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