1 // Copyright 2018 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <stdlib.h>
16 #include <stdbool.h>
17 #include <esp_system.h>
18 #include <esp_http_server.h>
19 
20 #include "unity.h"
21 #include "test_utils.h"
22 
23 int pre_start_mem, post_stop_mem, post_stop_min_mem;
24 bool basic_sanity = true;
25 
null_func(httpd_req_t * req)26 esp_err_t null_func(httpd_req_t *req)
27 {
28     return ESP_OK;
29 }
30 
handler_limit_uri(char * path)31 httpd_uri_t handler_limit_uri (char* path)
32 {
33     httpd_uri_t uri = {
34         .uri      = path,
35         .method   = HTTP_GET,
36         .handler  = null_func,
37         .user_ctx = NULL,
38     };
39     return uri;
40 };
41 
num_digits(unsigned x)42 static inline unsigned num_digits(unsigned x)
43 {
44     unsigned digits = 1;
45     while ((x = x/10) != 0) {
46         digits++;
47     }
48     return digits;
49 }
50 
51 #define HTTPD_TEST_MAX_URI_HANDLERS 8
52 
test_handler_limit(httpd_handle_t hd)53 void test_handler_limit(httpd_handle_t hd)
54 {
55     int i;
56     char x[HTTPD_TEST_MAX_URI_HANDLERS+1][num_digits(HTTPD_TEST_MAX_URI_HANDLERS)+1];
57     httpd_uri_t uris[HTTPD_TEST_MAX_URI_HANDLERS+1];
58 
59     for (i = 0; i < HTTPD_TEST_MAX_URI_HANDLERS + 1; i++) {
60         sprintf(x[i],"%d",i);
61         uris[i] = handler_limit_uri(x[i]);
62     }
63 
64     /* Register multiple instances of the same handler for MAX URI Handlers */
65     for (i = 0; i < HTTPD_TEST_MAX_URI_HANDLERS; i++) {
66         TEST_ASSERT(httpd_register_uri_handler(hd, &uris[i]) == ESP_OK);
67     }
68 
69     /* Register the MAX URI + 1 Handlers should fail */
70     TEST_ASSERT(httpd_register_uri_handler(hd, &uris[HTTPD_TEST_MAX_URI_HANDLERS]) != ESP_OK);
71 
72     /* Unregister the one of the Handler should pass */
73     TEST_ASSERT(httpd_unregister_uri_handler(hd, uris[0].uri, uris[0].method) == ESP_OK);
74 
75     /* Unregister non added Handler should fail */
76     TEST_ASSERT(httpd_unregister_uri_handler(hd, uris[0].uri, uris[0].method) != ESP_OK);
77 
78     /* Register the MAX URI Handler should pass */
79     TEST_ASSERT(httpd_register_uri_handler(hd, &uris[0]) == ESP_OK);
80 
81     /* Reregister same instance of handler should fail */
82     TEST_ASSERT(httpd_register_uri_handler(hd, &uris[0]) != ESP_OK);
83 
84     /* Register the MAX URI + 1 Handlers should fail */
85     TEST_ASSERT(httpd_register_uri_handler(hd, &uris[HTTPD_TEST_MAX_URI_HANDLERS]) != ESP_OK);
86 
87     /* Unregister the same handler for MAX URI Handlers */
88     for (i = 0; i < HTTPD_TEST_MAX_URI_HANDLERS; i++) {
89         TEST_ASSERT(httpd_unregister_uri_handler(hd, uris[i].uri, uris[i].method) == ESP_OK);
90     }
91     basic_sanity = false;
92 }
93 
94 /********************* Test Handler Limit End *******************/
95 
test_httpd_start(uint16_t id)96 httpd_handle_t test_httpd_start(uint16_t id)
97 {
98     httpd_handle_t hd;
99     httpd_config_t config = HTTPD_DEFAULT_CONFIG();
100     config.max_uri_handlers = HTTPD_TEST_MAX_URI_HANDLERS;
101     config.server_port += id;
102     config.ctrl_port += id;
103     TEST_ASSERT(httpd_start(&hd, &config) == ESP_OK)
104     return hd;
105 }
106 
107 #define SERVER_INSTANCES 2
108 
109 /* Currently this only tests for the number of tasks.
110  * Heap leakage is not tested as LWIP allocates memory
111  * which may not be freed immedietly causing erroneous
112  * evaluation. Another test to implement would be the
113  * monitoring of open sockets, but LWIP presently provides
114  * no such API for getting the number of open sockets.
115  */
116 TEST_CASE("Leak Test", "[HTTP SERVER]")
117 {
118     httpd_handle_t hd[SERVER_INSTANCES];
119     unsigned task_count;
120     bool res = true;
121 
122     test_case_uses_tcpip();
123 
124     task_count = uxTaskGetNumberOfTasks();
125     printf("Initial task count: %d\n", task_count);
126 
127     pre_start_mem = esp_get_free_heap_size();
128 
129     for (int i = 0; i < SERVER_INSTANCES; i++) {
130         hd[i] = test_httpd_start(i);
131         vTaskDelay(10);
132         unsigned num_tasks = uxTaskGetNumberOfTasks();
133         task_count++;
134         if (num_tasks != task_count) {
135             printf("Incorrect task count (starting): %d expected %d\n",
136                    num_tasks, task_count);
137             res = false;
138         }
139     }
140 
141     for (int i = 0; i < SERVER_INSTANCES; i++) {
142         if (httpd_stop(hd[i]) != ESP_OK) {
143             printf("Failed to stop httpd task %d\n", i);
144             res = false;
145         }
146         vTaskDelay(10);
147         unsigned num_tasks = uxTaskGetNumberOfTasks();
148         task_count--;
149         if (num_tasks != task_count) {
150             printf("Incorrect task count (stopping): %d expected %d\n",
151                    num_tasks, task_count);
152             res = false;
153         }
154     }
155     post_stop_mem = esp_get_free_heap_size();
156     TEST_ASSERT(res == true);
157 }
158 
159 TEST_CASE("Basic Functionality Tests", "[HTTP SERVER]")
160 {
161     httpd_handle_t hd;
162     httpd_config_t config = HTTPD_DEFAULT_CONFIG();
163 
164     test_case_uses_tcpip();
165 
166     TEST_ASSERT(httpd_start(&hd, &config) == ESP_OK);
167     test_handler_limit(hd);
168     TEST_ASSERT(httpd_stop(hd) == ESP_OK);
169 }
170 
171 TEST_CASE("URI Wildcard Matcher Tests", "[HTTP SERVER]")
172 {
173     struct uritest {
174         const char *template;
175         const char *uri;
176         bool matches;
177     };
178 
179     struct uritest uris[] = {
180         {"/", "/", true},
181         {"", "", true},
182         {"/", "", false},
183         {"/wrong", "/", false},
184         {"/", "/wrong", false},
185         {"/asdfghjkl/qwertrtyyuiuioo", "/asdfghjkl/qwertrtyyuiuioo", true},
186         {"/path", "/path", true},
187         {"/path", "/path/", false},
188         {"/path/", "/path", false},
189 
190         {"?", "", false}, // this is not valid, but should not crash
191         {"?", "sfsdf", false},
192 
193         {"/path/?", "/pa", false},
194         {"/path/?", "/path", true},
195         {"/path/?", "/path/", true},
196         {"/path/?", "/path/alalal", false},
197 
198         {"/path/*", "/path", false},
199         {"/path/*", "/", false},
200         {"/path/*", "/path/", true},
201         {"/path/*", "/path/blabla", true},
202 
203         {"*", "", true},
204         {"*", "/", true},
205         {"*", "/aaa", true},
206 
207         {"/path/?*", "/pat", false},
208         {"/path/?*", "/pathb", false},
209         {"/path/?*", "/pathxx", false},
210         {"/path/?*", "/pathblabla", false},
211         {"/path/?*", "/path", true},
212         {"/path/?*", "/path/", true},
213         {"/path/?*", "/path/blabla", true},
214 
215         {"/path/*?", "/pat", false},
216         {"/path/*?", "/pathb", false},
217         {"/path/*?", "/pathxx", false},
218         {"/path/*?", "/path", true},
219         {"/path/*?", "/path/", true},
220         {"/path/*?", "/path/blabla", true},
221 
222         {"/path/*/xxx", "/path/", false},
223         {"/path/*/xxx", "/path/*/xxx", true},
224         {}
225     };
226 
227     struct uritest *ut = &uris[0];
228 
229     while(ut->template != 0) {
230         bool match = httpd_uri_match_wildcard(ut->template, ut->uri, strlen(ut->uri));
231         TEST_ASSERT(match == ut->matches);
232         ut++;
233     }
234 }
235 
236 TEST_CASE("Max Allowed Sockets Test", "[HTTP SERVER]")
237 {
238     test_case_uses_tcpip();
239 
240     httpd_handle_t hd;
241     httpd_config_t config = HTTPD_DEFAULT_CONFIG();
242 
243     /* Starting server with default config options should pass */
244     TEST_ASSERT(httpd_start(&hd, &config) == ESP_OK);
245     TEST_ASSERT(httpd_stop(hd) == ESP_OK);
246 
247     /* Default value of max_open_sockets is already set as per
248      * maximum limit imposed by LWIP. Increasing this beyond the
249      * maximum allowed value, without increasing LWIP limit,
250      * should fail */
251     config.max_open_sockets += 1;
252     TEST_ASSERT(httpd_start(&hd, &config) != ESP_OK);
253 }
254