/* Simple HTTP server for ESP32. * Copyright Ivan Grokhotkov, 2017. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #ifdef __cplusplus extern "C" { #endif /** * @file http_server.h * @brief Simple HTTP server */ #include "sdkconfig.h" /* Pull in the definitions of HTTP methods */ #include "http_parser.h" /** * Bit masks for events to be passed to a handler */ #define HTTP_HANDLE_URI BIT(0) /*!< Called when URI is received */ #define HTTP_HANDLE_HEADERS BIT(1) /*!< Called when all headers are received */ #define HTTP_HANDLE_DATA BIT(2) /*!< Called each time a fragment of request body is received */ #define HTTP_HANDLE_RESPONSE BIT(3) /*!< Called at the end of the request to produce the response */ /** Error buffer length */ #define ERROR_BUF_LENGTH 100 #define HTTPS_SERVER CONFIG_HTTPS_SERVER #define HTTPD_EXAMPLE CONFIG_HTTPD_EXAMPLE /** Opaque type representing single HTTP connection */ typedef struct http_context_* http_context_t; /** Opaque type representing HTTP server */ typedef struct http_server_context_* http_server_t; /** Callback type of HTTP request handler */ typedef void (* http_handler_fn_t)(http_context_t http_ctx, void* ctx); /** * @brief Configuration of the HTTP server */ typedef struct { int port; /*!< TCP Port to listen on */ int task_affinity; /*!< Server task affinity (CPU number of tskNO_AFFINITY */ int task_stack_size; /*!< Server task stack size, in bytes */ int task_priority; /*!< Server task priority */ } http_server_options_t; /** Default initializer for http_server_options_t */ #define HTTP_SERVER_OPTIONS_DEFAULT() {\ .port = 80, \ .task_affinity = tskNO_AFFINITY, \ .task_stack_size = 4096, \ .task_priority = 1, \ } /** Default initializer for http_server_options_t */ #define HTTPS_SERVER_OPTIONS_DEFAULT() {\ .port = 443, \ .task_affinity = tskNO_AFFINITY, \ .task_stack_size = 10240, \ .task_priority = 8, \ } const static char index_html[] = "" "\n" "\n" " \n" " \n" "HELLO ESP32\n" "\n" "\n" "

Hello World, from ESP32!

\n" "\n" "\n"; const static char response_OK[] = "OK!\n"; /** * @brief initialize HTTP server, start listening * @param options pointer to http server options, can point to a temporary * @param[out] output, handle of the server; pass it to http_server_stop do * delete the server. * @return * - ESP_OK on success * - ESP_ERR_NO_MEM if out of RAM * - ESP_FAIL if some other error */ esp_err_t http_server_start(const http_server_options_t* options, http_server_t* out_server); /** * @brief Stop the previously started server * @param server handle obtained from http_server_start * @return * - ESP_OK on success */ esp_err_t http_server_stop(http_server_t server); /** * @brief Register a handler for certain URI * * The handler will be called when a client makes a request with matching URI * and HTTP method. * * @note Currently only matches full URIs, doesn't support regex * * @param server Server handle to register the handler for * @param uri_pattern URI pattern to match * @param method one of HTTP_GET, HTTP_POST, HTTP_PUT, etc * @param events a bit mask of HTTP_HANDLE_X events for which the handler * should be called * @param callback function to call * @param callback_arg application context to pass to the callback * @return * - ESP_OK on success * - ESP_ERR_NO_MEM if out of memory */ esp_err_t http_register_handler(http_server_t server, const char* uri_pattern, int method, int events, http_handler_fn_t callback, void* callback_arg); /** * @brief Register a handler for application/x-www-form-urlencoded requests * * Unlike http_register_handler, handlers registered using this function will * not receive HTTP_HANDLE_DATA events. Instead, request body will be parsed * into key-value pairs, which can be retrieved while handling * HTTP_HANDLE_RESPONSE event using http_request_get_form_value. * * @param server Server handle to register the handler for * @param uri_pattern URI pattern to match * @param method one of HTTP_GET, HTTP_POST, HTTP_PUT, etc * @param events a bit mask of HTTP_HANDLE_X events for which the handler * should be called. HTTP_HANDLE_DATA will not be passed to * the callback. * @param callback function to call * @param callback_arg application context to pass to the callback * @return * - ESP_OK on success * - ESP_ERR_NO_MEM if out of memory */ esp_err_t http_register_form_handler(http_server_t server, const char* uri_pattern, int method, int events, http_handler_fn_t callback, void* callback_arg); /** * @brief Get value for given URL argument of form argument * @param http_ctx context passed to the handler * @param name name of URL or form argument * @return pointer to the value, valid until the end of request */ const char* http_request_get_arg_value(http_context_t http_ctx, const char* name); /** * @brief Get request method * @param http_ctx context passed to the handler * @return one of HTTP_GET, HTTP_POST, etc */ int http_request_get_method(http_context_t http_ctx); /** * @brief Get URI present in the request * @param http_ctx context passed to the handler * @return pointer to the URI, valid until the end of request */ const char* http_request_get_uri(http_context_t http_ctx); /** * @brief Get request header * @param http_ctx context passed to the handler * @param name header name * @return * - If the header with given name is present in the request, returns * pointer to the value; valid until request callback returns. * - Otherwise, returns NULL */ const char* http_request_get_header(http_context_t ctx, const char* name); /** * @brief Get the event which caused a call to the handler * @param ctx context passed to the handler * @return one of HTTP_HANDLE_X values */ int http_request_get_event(http_context_t ctx); /** * @brief Get the request body fragment * To be used when handling HTTP_HANDLE_DATA event. * * @param ctx context passed to the handler * @param[out] out_data_ptr output, receives pointer to the body fragment * @param[out] out_size output, receives the size of the body fragment * @return * - ESP_OK on success * - ESP_ERR_INVALID_STATE if called for events other than HTTP_HANDLE_DATA */ esp_err_t http_request_get_data(http_context_t ctx, const char** out_data_ptr, size_t* out_size); /** * @brief structure describing a part of the response to be sent */ typedef struct { const void* data; /*!< pointer to data to be sent */ size_t size; /*!< size of data to send; if data is a 0-terminated string, size can be left 0 */ bool data_is_persistent; /*!< set to true if data is in constant RAM */ } http_buffer_t; #define HTTP_RESPONSE_SIZE_UNKNOWN SIZE_MAX /** * @brief Begin writing HTTP response * @param http_ctx context passed to the handler * @param code HTTP response code * @param content_type string to send as a value in content-type header * @param response_size either the size of the response body, or HTTP_RESPONSE_SIZE_UNKNOWN * @return * - ESP_OK on success * - ESP_ERR_NO_MEM if can't allocate temporary buffer * - other errors from LwIP */ esp_err_t http_response_begin(http_context_t http_ctx, int code, const char* content_type, size_t response_size); /** * @brief Add HTTP header to the response * * This function may be called between http_response_begin and http_response_write. * * For multipart responses, calling it between http_response_begin and * http_response_begin_multipart adds header to the list of headers in the original * response (which is sent first). Calling it after http_response_begin_multipart * adds the header to the list of headers sent for the current response part. * * 'name' and 'val' can point to temporary values. This function copies the * both strings into internal storage. * * @param http_ctx context passed to the handler * @param name Header name * @param val Header value * @return * - ESP_OK on success * - ESP_ERR_NO_MEM if can't allocate memory for the header */ esp_err_t http_response_set_header(http_context_t http_ctx, const char* name, const char* val); /** * @brief Start one part of a multipart response * * For multipart responses, the sequence of calls is as follows: * * 1. http_response_begin (with size == HTTP_RESPONSE_SIZE_UNKNOWN) * 2. (optional) http_response_set_header — for the overall response * 3. http_response_begin_multipart (if part size is known, pass it in response_size argument) * 4. (optional) http_repponse_set_header — for the current part * 5. (optional) http_response_write — write response data * 6. http_response_end_multipart — when done with the part * 7. repeat from 3 as needed * * @param http_ctx context passed to the handler * @param content_type value to be set in part's content-type header * @param response_size either the size of part body, or HTTP_RESPONSE_SIZE_UNKNOWN * @return * - ESP_OK * - ESP_ERR_NO_MEM if can't allocate memory * - other errors from LwIP */ esp_err_t http_response_begin_multipart(http_context_t http_ctx, const char* content_type, size_t response_size); /** * @brief Indicate that one part of the multipart response is finished * @param http_ctx context passed to the handler * @param boundary part boundary. Has to be the same as given in the content-type of the first response. * @return * - ESP_OK * - other errors from LwIP */ esp_err_t http_response_end_multipart(http_context_t http_ctx, const char* boundary); /** * @brief Send a piece of HTTP response to the client * @param http_ctx context passed to the handler * @param buffer data to send, see \ref http_buffer_t * @return * - ESP_OK on success * - other errors from LwIP */ esp_err_t http_response_write(http_context_t http_ctx, const http_buffer_t* buffer); /** * @brief Indicate that response is complete * @param http_ctx context passed to the handler * @return * - ESP_OK on success * - other errors in the future? */ esp_err_t http_response_end(http_context_t http_ctx); /** * @brief Example of GET method. Responding a simple "Hello World" html. All initializations included. * @param none * @return * - ESP_OK on success * - other errors in the future? */ esp_err_t simple_GET_method_example(void); /** * @brief Example of POST method. Send a application/x-www-form-urlencoded pair key-value where the key is 'key' and some value for it. The value is printed and the server responds a 201 code and a OK message. * @param none * @return * - ESP_OK on success * - other errors in the future? */ esp_err_t simple_POST_method_example(void); #ifdef __cplusplus } #endif