tests.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. #include <stdlib.h>
  2. #include <stdbool.h>
  3. #include <esp_log.h>
  4. #include <esp_system.h>
  5. #include <esp_http_server.h>
  6. #include "tests.h"
  7. static const char *TAG = "TESTS";
  8. static int pre_start_mem, post_stop_mem;
  9. struct async_resp_arg {
  10. httpd_handle_t hd;
  11. int fd;
  12. };
  13. /********************* Basic Handlers Start *******************/
  14. static esp_err_t hello_get_handler(httpd_req_t *req)
  15. {
  16. #define STR "Hello World!"
  17. ESP_LOGI(TAG, "Free Stack for server task: '%d'", uxTaskGetStackHighWaterMark(NULL));
  18. httpd_resp_send(req, STR, HTTPD_RESP_USE_STRLEN);
  19. return ESP_OK;
  20. #undef STR
  21. }
  22. /* This handler is intended to check what happens in case of empty values of headers.
  23. * Here `Header2` is an empty header and `Header1` and `Header3` will have `Value1`
  24. * and `Value3` in them. */
  25. static esp_err_t test_header_get_handler(httpd_req_t *req)
  26. {
  27. httpd_resp_set_type(req, HTTPD_TYPE_TEXT);
  28. int buf_len;
  29. char *buf;
  30. buf_len = httpd_req_get_hdr_value_len(req, "Header1");
  31. if (buf_len > 0) {
  32. buf = malloc(++buf_len);
  33. if (!buf) {
  34. ESP_LOGE(TAG, "Failed to allocate memory of %d bytes!", buf_len);
  35. httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Memory allocation failed");
  36. return ESP_ERR_NO_MEM;
  37. }
  38. /* Copy null terminated value string into buffer */
  39. if (httpd_req_get_hdr_value_str(req, "Header1", buf, buf_len) == ESP_OK) {
  40. ESP_LOGI(TAG, "Header1 content: %s", buf);
  41. if (strcmp("Value1", buf) != 0) {
  42. httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Wrong value of Header1 received");
  43. free(buf);
  44. return ESP_ERR_INVALID_ARG;
  45. } else {
  46. ESP_LOGI(TAG, "Expected value and received value matched for Header1");
  47. }
  48. } else {
  49. ESP_LOGE(TAG, "Error in getting value of Header1");
  50. httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Error in getting value of Header1");
  51. free(buf);
  52. return ESP_FAIL;
  53. }
  54. free(buf);
  55. } else {
  56. ESP_LOGE(TAG, "Header1 not found");
  57. httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Header1 not found");
  58. return ESP_ERR_NOT_FOUND;
  59. }
  60. buf_len = httpd_req_get_hdr_value_len(req, "Header3");
  61. if (buf_len > 0) {
  62. buf = malloc(++buf_len);
  63. if (!buf) {
  64. ESP_LOGE(TAG, "Failed to allocate memory of %d bytes!", buf_len);
  65. httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Memory allocation failed");
  66. return ESP_ERR_NO_MEM;
  67. }
  68. /* Copy null terminated value string into buffer */
  69. if (httpd_req_get_hdr_value_str(req, "Header3", buf, buf_len) == ESP_OK) {
  70. ESP_LOGI(TAG, "Header3 content: %s", buf);
  71. if (strcmp("Value3", buf) != 0) {
  72. httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Wrong value of Header3 received");
  73. free(buf);
  74. return ESP_ERR_INVALID_ARG;
  75. } else {
  76. ESP_LOGI(TAG, "Expected value and received value matched for Header3");
  77. }
  78. } else {
  79. ESP_LOGE(TAG, "Error in getting value of Header3");
  80. httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Error in getting value of Header3");
  81. free(buf);
  82. return ESP_FAIL;
  83. }
  84. free(buf);
  85. } else {
  86. ESP_LOGE(TAG, "Header3 not found");
  87. httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Header3 not found");
  88. return ESP_ERR_NOT_FOUND;
  89. }
  90. buf_len = httpd_req_get_hdr_value_len(req, "Header2");
  91. buf = malloc(++buf_len);
  92. if (!buf) {
  93. ESP_LOGE(TAG, "Failed to allocate memory of %d bytes!", buf_len);
  94. httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Memory allocation failed");
  95. return ESP_ERR_NO_MEM;
  96. }
  97. if (httpd_req_get_hdr_value_str(req, "Header2", buf, buf_len) == ESP_OK) {
  98. ESP_LOGI(TAG, "Header2 content: %s", buf);
  99. httpd_resp_send(req, buf, HTTPD_RESP_USE_STRLEN);
  100. } else {
  101. ESP_LOGE(TAG, "Header2 not found");
  102. httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Header2 not found");
  103. return ESP_FAIL;
  104. }
  105. return ESP_OK;
  106. }
  107. static esp_err_t hello_type_get_handler(httpd_req_t *req)
  108. {
  109. #define STR "Hello World!"
  110. httpd_resp_set_type(req, HTTPD_TYPE_TEXT);
  111. httpd_resp_send(req, STR, HTTPD_RESP_USE_STRLEN);
  112. return ESP_OK;
  113. #undef STR
  114. }
  115. static esp_err_t hello_status_get_handler(httpd_req_t *req)
  116. {
  117. #define STR "Hello World!"
  118. httpd_resp_set_status(req, HTTPD_500);
  119. httpd_resp_send(req, STR, HTTPD_RESP_USE_STRLEN);
  120. return ESP_OK;
  121. #undef STR
  122. }
  123. static esp_err_t echo_post_handler(httpd_req_t *req)
  124. {
  125. ESP_LOGI(TAG, "/echo handler read content length %d", req->content_len);
  126. char* buf = malloc(req->content_len + 1);
  127. size_t off = 0;
  128. int ret;
  129. if (!buf) {
  130. ESP_LOGE(TAG, "Failed to allocate memory of %d bytes!", req->content_len + 1);
  131. httpd_resp_send_500(req);
  132. return ESP_FAIL;
  133. }
  134. while (off < req->content_len) {
  135. /* Read data received in the request */
  136. ret = httpd_req_recv(req, buf + off, req->content_len - off);
  137. if (ret <= 0) {
  138. if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
  139. httpd_resp_send_408(req);
  140. }
  141. free (buf);
  142. return ESP_FAIL;
  143. }
  144. off += ret;
  145. ESP_LOGI(TAG, "/echo handler recv length %d", ret);
  146. }
  147. buf[off] = '\0';
  148. if (req->content_len < 128) {
  149. ESP_LOGI(TAG, "/echo handler read %s", buf);
  150. }
  151. /* Search for Custom header field */
  152. char* req_hdr = 0;
  153. size_t hdr_len = httpd_req_get_hdr_value_len(req, "Custom");
  154. if (hdr_len) {
  155. /* Read Custom header value */
  156. req_hdr = malloc(hdr_len + 1);
  157. if (!req_hdr) {
  158. ESP_LOGE(TAG, "Failed to allocate memory of %d bytes!", hdr_len + 1);
  159. httpd_resp_send_500(req);
  160. return ESP_FAIL;
  161. }
  162. httpd_req_get_hdr_value_str(req, "Custom", req_hdr, hdr_len + 1);
  163. /* Set as additional header for response packet */
  164. httpd_resp_set_hdr(req, "Custom", req_hdr);
  165. }
  166. httpd_resp_send(req, buf, req->content_len);
  167. free (req_hdr);
  168. free (buf);
  169. return ESP_OK;
  170. }
  171. static void adder_free_func(void *ctx)
  172. {
  173. ESP_LOGI(TAG, "Custom Free Context function called");
  174. free(ctx);
  175. }
  176. /* Create a context, keep incrementing value in the context, by whatever was
  177. * received. Return the result
  178. */
  179. static esp_err_t adder_post_handler(httpd_req_t *req)
  180. {
  181. char buf[10];
  182. char outbuf[50];
  183. int ret;
  184. /* Read data received in the request */
  185. ret = httpd_req_recv(req, buf, sizeof(buf));
  186. if (ret <= 0) {
  187. if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
  188. httpd_resp_send_408(req);
  189. }
  190. return ESP_FAIL;
  191. }
  192. buf[ret] = '\0';
  193. int val = atoi(buf);
  194. ESP_LOGI(TAG, "/adder handler read %d", val);
  195. if (! req->sess_ctx) {
  196. ESP_LOGI(TAG, "/adder allocating new session");
  197. req->sess_ctx = malloc(sizeof(int));
  198. req->free_ctx = adder_free_func;
  199. *(int *)req->sess_ctx = 0;
  200. }
  201. int *adder = (int *)req->sess_ctx;
  202. *adder += val;
  203. snprintf(outbuf, sizeof(outbuf),"%d", *adder);
  204. httpd_resp_send(req, outbuf, HTTPD_RESP_USE_STRLEN);
  205. return ESP_OK;
  206. }
  207. static esp_err_t leftover_data_post_handler(httpd_req_t *req)
  208. {
  209. /* Only echo the first 10 bytes of the request, leaving the rest of the
  210. * request data as is.
  211. */
  212. char buf[11];
  213. int ret;
  214. /* Read data received in the request */
  215. ret = httpd_req_recv(req, buf, sizeof(buf) - 1);
  216. if (ret <= 0) {
  217. if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
  218. httpd_resp_send_408(req);
  219. }
  220. return ESP_FAIL;
  221. }
  222. buf[ret] = '\0';
  223. ESP_LOGI(TAG, "leftover data handler read %s", buf);
  224. httpd_resp_send(req, buf, HTTPD_RESP_USE_STRLEN);
  225. return ESP_OK;
  226. }
  227. static void generate_async_resp(void *arg)
  228. {
  229. char buf[250];
  230. struct async_resp_arg *resp_arg = (struct async_resp_arg *)arg;
  231. httpd_handle_t hd = resp_arg->hd;
  232. int fd = resp_arg->fd;
  233. #define HTTPD_HDR_STR "HTTP/1.1 200 OK\r\n" \
  234. "Content-Type: text/html\r\n" \
  235. "Content-Length: %d\r\n"
  236. #define STR "Hello Double World!"
  237. ESP_LOGI(TAG, "Executing queued work fd : %d", fd);
  238. snprintf(buf, sizeof(buf), HTTPD_HDR_STR,
  239. strlen(STR));
  240. httpd_socket_send(hd, fd, buf, strlen(buf), 0);
  241. /* Space for sending additional headers based on set_header */
  242. httpd_socket_send(hd, fd, "\r\n", strlen("\r\n"), 0);
  243. httpd_socket_send(hd, fd, STR, strlen(STR), 0);
  244. #undef STR
  245. free(arg);
  246. }
  247. static esp_err_t async_get_handler(httpd_req_t *req)
  248. {
  249. #define STR "Hello World!"
  250. httpd_resp_send(req, STR, HTTPD_RESP_USE_STRLEN);
  251. /* Also register a HTTPD Work which sends the same data on the same
  252. * socket again
  253. */
  254. struct async_resp_arg *resp_arg = malloc(sizeof(struct async_resp_arg));
  255. resp_arg->hd = req->handle;
  256. resp_arg->fd = httpd_req_to_sockfd(req);
  257. if (resp_arg->fd < 0) {
  258. return ESP_FAIL;
  259. }
  260. ESP_LOGI(TAG, "Queuing work fd : %d", resp_arg->fd);
  261. httpd_queue_work(req->handle, generate_async_resp, resp_arg);
  262. return ESP_OK;
  263. #undef STR
  264. }
  265. static const httpd_uri_t basic_handlers[] = {
  266. { .uri = "/hello/type_html",
  267. .method = HTTP_GET,
  268. .handler = hello_type_get_handler,
  269. .user_ctx = NULL,
  270. },
  271. { .uri = "/test_header",
  272. .method = HTTP_GET,
  273. .handler = test_header_get_handler,
  274. .user_ctx = NULL,
  275. },
  276. { .uri = "/hello",
  277. .method = HTTP_GET,
  278. .handler = hello_get_handler,
  279. .user_ctx = NULL,
  280. },
  281. { .uri = "/hello/status_500",
  282. .method = HTTP_GET,
  283. .handler = hello_status_get_handler,
  284. .user_ctx = NULL,
  285. },
  286. { .uri = "/echo",
  287. .method = HTTP_POST,
  288. .handler = echo_post_handler,
  289. .user_ctx = NULL,
  290. },
  291. { .uri = "/echo",
  292. .method = HTTP_PUT,
  293. .handler = echo_post_handler,
  294. .user_ctx = NULL,
  295. },
  296. { .uri = "/leftover_data",
  297. .method = HTTP_POST,
  298. .handler = leftover_data_post_handler,
  299. .user_ctx = NULL,
  300. },
  301. { .uri = "/adder",
  302. .method = HTTP_POST,
  303. .handler = adder_post_handler,
  304. .user_ctx = NULL,
  305. },
  306. { .uri = "/async_data",
  307. .method = HTTP_GET,
  308. .handler = async_get_handler,
  309. .user_ctx = NULL,
  310. }
  311. };
  312. static const int basic_handlers_no = sizeof(basic_handlers)/sizeof(httpd_uri_t);
  313. static void register_basic_handlers(httpd_handle_t hd)
  314. {
  315. int i;
  316. ESP_LOGI(TAG, "Registering basic handlers");
  317. ESP_LOGI(TAG, "No of handlers = %d", basic_handlers_no);
  318. for (i = 0; i < basic_handlers_no; i++) {
  319. if (httpd_register_uri_handler(hd, &basic_handlers[i]) != ESP_OK) {
  320. ESP_LOGW(TAG, "register uri failed for %d", i);
  321. return;
  322. }
  323. }
  324. ESP_LOGI(TAG, "Success");
  325. }
  326. static httpd_handle_t test_httpd_start(void)
  327. {
  328. pre_start_mem = esp_get_free_heap_size();
  329. httpd_handle_t hd;
  330. httpd_config_t config = HTTPD_DEFAULT_CONFIG();
  331. /* Modify this setting to match the number of test URI handlers */
  332. config.max_uri_handlers = 9;
  333. config.server_port = 1234;
  334. /* This check should be a part of http_server */
  335. config.max_open_sockets = (CONFIG_LWIP_MAX_SOCKETS - 3);
  336. if (httpd_start(&hd, &config) == ESP_OK) {
  337. ESP_LOGI(TAG, "Started HTTP server on port: '%d'", config.server_port);
  338. ESP_LOGI(TAG, "Max URI handlers: '%d'", config.max_uri_handlers);
  339. ESP_LOGI(TAG, "Max Open Sessions: '%d'", config.max_open_sockets);
  340. ESP_LOGI(TAG, "Max Header Length: '%d'", HTTPD_MAX_REQ_HDR_LEN);
  341. ESP_LOGI(TAG, "Max URI Length: '%d'", HTTPD_MAX_URI_LEN);
  342. ESP_LOGI(TAG, "Max Stack Size: '%d'", config.stack_size);
  343. return hd;
  344. }
  345. return NULL;
  346. }
  347. static void test_httpd_stop(httpd_handle_t hd)
  348. {
  349. httpd_stop(hd);
  350. post_stop_mem = esp_get_free_heap_size();
  351. ESP_LOGI(TAG, "HTTPD Stop: Current free memory: %d", post_stop_mem);
  352. }
  353. httpd_handle_t start_tests(void)
  354. {
  355. httpd_handle_t hd = test_httpd_start();
  356. if (hd) {
  357. register_basic_handlers(hd);
  358. }
  359. return hd;
  360. }
  361. void stop_tests(httpd_handle_t hd)
  362. {
  363. ESP_LOGI(TAG, "Stopping httpd");
  364. test_httpd_stop(hd);
  365. }