#include #include #include #include #include #include "tests.h" static const char *TAG="TESTS"; int pre_start_mem, post_stop_mem, post_stop_min_mem; bool basic_sanity = true; struct async_resp_arg { httpd_handle_t hd; int fd; }; /********************* Basic Handlers Start *******************/ esp_err_t hello_get_handler(httpd_req_t *req) { #define STR "Hello World!" ESP_LOGI(TAG, "Free Stack for server task: '%d'", uxTaskGetStackHighWaterMark(NULL)); httpd_resp_send(req, STR, strlen(STR)); return ESP_OK; #undef STR } esp_err_t hello_type_get_handler(httpd_req_t *req) { #define STR "Hello World!" httpd_resp_set_type(req, HTTPD_TYPE_TEXT); httpd_resp_send(req, STR, strlen(STR)); return ESP_OK; #undef STR } esp_err_t hello_status_get_handler(httpd_req_t *req) { #define STR "Hello World!" httpd_resp_set_status(req, HTTPD_500); httpd_resp_send(req, STR, strlen(STR)); return ESP_OK; #undef STR } esp_err_t echo_post_handler(httpd_req_t *req) { ESP_LOGI(TAG, "/echo handler read content length %d", req->content_len); char* buf = malloc(req->content_len + 1); size_t off = 0; int ret; if (!buf) { httpd_resp_send_500(req); return ESP_FAIL; } while (off < req->content_len) { /* Read data received in the request */ ret = httpd_req_recv(req, buf + off, req->content_len - off); if (ret <= 0) { if (ret == HTTPD_SOCK_ERR_TIMEOUT) { httpd_resp_send_408(req); } free (buf); return ESP_FAIL; } off += ret; ESP_LOGI(TAG, "/echo handler recv length %d", ret); } buf[off] = '\0'; if (req->content_len < 128) { ESP_LOGI(TAG, "/echo handler read %s", buf); } /* Search for Custom header field */ char* req_hdr = 0; size_t hdr_len = httpd_req_get_hdr_value_len(req, "Custom"); if (hdr_len) { /* Read Custom header value */ req_hdr = malloc(hdr_len + 1); if (req_hdr) { httpd_req_get_hdr_value_str(req, "Custom", req_hdr, hdr_len + 1); /* Set as additional header for response packet */ httpd_resp_set_hdr(req, "Custom", req_hdr); } } httpd_resp_send(req, buf, req->content_len); free (req_hdr); free (buf); return ESP_OK; } void adder_free_func(void *ctx) { ESP_LOGI(TAG, "Custom Free Context function called"); free(ctx); } /* Create a context, keep incrementing value in the context, by whatever was * received. Return the result */ esp_err_t adder_post_handler(httpd_req_t *req) { char buf[10]; char outbuf[50]; int ret; /* Read data received in the request */ ret = httpd_req_recv(req, buf, sizeof(buf)); if (ret <= 0) { if (ret == HTTPD_SOCK_ERR_TIMEOUT) { httpd_resp_send_408(req); } return ESP_FAIL; } buf[ret] = '\0'; int val = atoi(buf); ESP_LOGI(TAG, "/adder handler read %d", val); if (! req->sess_ctx) { ESP_LOGI(TAG, "/adder allocating new session"); req->sess_ctx = malloc(sizeof(int)); req->free_ctx = adder_free_func; *(int *)req->sess_ctx = 0; } int *adder = (int *)req->sess_ctx; *adder += val; snprintf(outbuf, sizeof(outbuf),"%d", *adder); httpd_resp_send(req, outbuf, strlen(outbuf)); return ESP_OK; } esp_err_t leftover_data_post_handler(httpd_req_t *req) { /* Only echo the first 10 bytes of the request, leaving the rest of the * request data as is. */ char buf[11]; int ret; /* Read data received in the request */ ret = httpd_req_recv(req, buf, sizeof(buf) - 1); if (ret <= 0) { if (ret == HTTPD_SOCK_ERR_TIMEOUT) { httpd_resp_send_408(req); } return ESP_FAIL; } buf[ret] = '\0'; ESP_LOGI(TAG, "leftover data handler read %s", buf); httpd_resp_send(req, buf, strlen(buf)); return ESP_OK; } int httpd_default_send(httpd_handle_t hd, int sockfd, const char *buf, unsigned buf_len, int flags); void generate_async_resp(void *arg) { char buf[250]; struct async_resp_arg *resp_arg = (struct async_resp_arg *)arg; httpd_handle_t hd = resp_arg->hd; int fd = resp_arg->fd; #define HTTPD_HDR_STR "HTTP/1.1 200 OK\r\n" \ "Content-Type: text/html\r\n" \ "Content-Length: %d\r\n" #define STR "Hello Double World!" ESP_LOGI(TAG, "Executing queued work fd : %d", fd); snprintf(buf, sizeof(buf), HTTPD_HDR_STR, strlen(STR)); httpd_default_send(hd, fd, buf, strlen(buf), 0); /* Space for sending additional headers based on set_header */ httpd_default_send(hd, fd, "\r\n", strlen("\r\n"), 0); httpd_default_send(hd, fd, STR, strlen(STR), 0); #undef STR free(arg); } esp_err_t async_get_handler(httpd_req_t *req) { #define STR "Hello World!" httpd_resp_send(req, STR, strlen(STR)); /* Also register a HTTPD Work which sends the same data on the same * socket again */ struct async_resp_arg *resp_arg = malloc(sizeof(struct async_resp_arg)); resp_arg->hd = req->handle; resp_arg->fd = httpd_req_to_sockfd(req); if (resp_arg->fd < 0) { return ESP_FAIL; } ESP_LOGI(TAG, "Queuing work fd : %d", resp_arg->fd); httpd_queue_work(req->handle, generate_async_resp, resp_arg); return ESP_OK; #undef STR } httpd_uri_t basic_handlers[] = { { .uri = "/hello/type_html", .method = HTTP_GET, .handler = hello_type_get_handler, .user_ctx = NULL, }, { .uri = "/hello", .method = HTTP_GET, .handler = hello_get_handler, .user_ctx = NULL, }, { .uri = "/hello/status_500", .method = HTTP_GET, .handler = hello_status_get_handler, .user_ctx = NULL, }, { .uri = "/echo", .method = HTTP_POST, .handler = echo_post_handler, .user_ctx = NULL, }, { .uri = "/echo", .method = HTTP_PUT, .handler = echo_post_handler, .user_ctx = NULL, }, { .uri = "/leftover_data", .method = HTTP_POST, .handler = leftover_data_post_handler, .user_ctx = NULL, }, { .uri = "/adder", .method = HTTP_POST, .handler = adder_post_handler, .user_ctx = NULL, }, { .uri = "/async_data", .method = HTTP_GET, .handler = async_get_handler, .user_ctx = NULL, } }; int basic_handlers_no = sizeof(basic_handlers)/sizeof(httpd_uri_t); void register_basic_handlers(httpd_handle_t hd) { int i; ESP_LOGI(TAG, "Registering basic handlers"); ESP_LOGI(TAG, "No of handlers = %d", basic_handlers_no); for (i = 0; i < basic_handlers_no; i++) { if (httpd_register_uri_handler(hd, &basic_handlers[i]) != ESP_OK) { ESP_LOGW(TAG, "register uri failed for %d", i); return; } } ESP_LOGI(TAG, "Success"); } httpd_handle_t test_httpd_start() { pre_start_mem = esp_get_free_heap_size(); httpd_handle_t hd; httpd_config_t config = HTTPD_DEFAULT_CONFIG(); config.server_port = 1234; /* This check should be a part of http_server */ config.max_open_sockets = (CONFIG_LWIP_MAX_SOCKETS - 3); if (httpd_start(&hd, &config) == ESP_OK) { ESP_LOGI(TAG, "Started HTTP server on port: '%d'", config.server_port); ESP_LOGI(TAG, "Max URI handlers: '%d'", config.max_uri_handlers); ESP_LOGI(TAG, "Max Open Sessions: '%d'", config.max_open_sockets); ESP_LOGI(TAG, "Max Header Length: '%d'", HTTPD_MAX_REQ_HDR_LEN); ESP_LOGI(TAG, "Max URI Length: '%d'", HTTPD_MAX_URI_LEN); ESP_LOGI(TAG, "Max Stack Size: '%d'", config.stack_size); return hd; } return NULL; } void test_httpd_stop(httpd_handle_t hd) { httpd_stop(hd); post_stop_mem = esp_get_free_heap_size(); ESP_LOGI(TAG, "HTTPD Stop: Current free memory: %d", post_stop_mem); } httpd_handle_t start_tests() { httpd_handle_t hd = test_httpd_start(); if (hd) { register_basic_handlers(hd); } return hd; } void stop_tests(httpd_handle_t hd) { ESP_LOGI(TAG, "Stopping httpd"); test_httpd_stop(hd); }