diff --git a/README.md b/README.md
index 8fda91e..4ee6bc3 100644
--- a/README.md
+++ b/README.md
@@ -1,38 +1,39 @@
-Simple HTTP server
-------------------
+# Simple HTTP/HTTPS server
-This is a very minimal HTTP server I use in some of the projects.
+This is a very minimal HTTP server. Optionally supports HTTPS server based on mbedTLS server example.
-Absolutely not ready for any kind of production use.
-
-How to use
-----------
-
-Really, please see above note.
+# How to use
This directory is an ESP-IDF component. Clone it (or add it as a submodule) into the component directory of the project.
+Enable TLS/SSL HTTPS server by uncommenting the `#define HTTPS_SERVER` line at `https_server.h`, otherwise it will implement unsecured http server. Server certificate and private key are loaded at `https_server.c` directly into flash code as in the [`open_ssl_server`](https://github.com/espressif/esp-idf/tree/master/examples/protocols/openssl_server) example from ESP-IDF repository. Don't forget to insert [`cacert.pem`](https://github.com/espressif/esp-idf/blob/master/examples/protocols/openssl_server/main/cacert.pem) and [`prvtkey.pem`](https://github.com/espressif/esp-idf/blob/master/examples/protocols/openssl_server/main/prvtkey.pem) at your main application directory if you want to run GET/POST examples.
-
-Documentation
--------------
+# Documentation
None yet, but I tried to make the comments in the header file helpful.
+# Examples
-Example
--------
+Examples functions at http server:
-None yet.
+## GET Method Example
+
+`simple_GET_method_example()` function:
+* Add http_server.c and http_server.h as a component into your project.
+* Server initialization added into the example function, simply call it and it should work!
+* Receiving a GET request at /, http server response is a "Hello World, from ESP32!" html.
-Debugging
----------
+## POST Method Example
+`simple_POST_method_example()` function:
+* As well as GET example, simply add http_server as a componente into your ESP-IDF project.
+* Server initialization added into the POST example function, simply call it and don't worry.
+* Post to / a pair of key-value where the key is 'key' and value some value you want to test. The example will show value content. If needed, increade log verbosity at `make menuconfig` to show all parsed key-value pairs.
-Increasing log level to "Verbose" should produce lots of output related to request handling.
+# Debugging
+Increasing log level to "Verbose" should produce lots of output related to request handling.
-License
--------
-GPL, see [LICENSE](LICENSE) file. Mostly because this is a very early version. Will be relicensed as something more reasonable later.
+# License
+GPL, see [LICENSE](LICENSE) file. Mostly because this is a very early version. Will be relicensed as something more reasonable later. mbedTLS are Apache 2.0 licensed.
diff --git a/http_server.c b/http_server.c
index 6f2f24c..0aa7349 100644
--- a/http_server.c
+++ b/http_server.c
@@ -15,7 +15,7 @@
* along with this program. If not, see .
*/
-
+#include
#include
#include
#include
@@ -24,6 +24,7 @@
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "rom/queue.h"
+#include "driver/gpio.h"
#include "esp_log.h"
@@ -32,10 +33,24 @@
#include "lwip/api.h"
#include "http_parser.h"
-#include "http_server.h"
+#include "mbedtls/platform.h"
+#include "mbedtls/net_sockets.h"
+#include "mbedtls/esp_debug.h"
+#include "mbedtls/ssl.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/error.h"
+#include "mbedtls/certs.h"
+#include "mbedtls/ssl_ticket.h"
+
+#if defined(MBEDTLS_SSL_CACHE_C)
+#include "mbedtls/ssl_cache.h"
+#endif
#define HTTP_PARSE_BUF_MAX_LEN 256
+#define MBEDTLS_EXAMPLE_RECV_BUF_LEN 1024
+
typedef enum {
HTTP_PARSING_URI, //!< HTTP_PARSING_URI
HTTP_PARSING_HEADER_NAME, //!< HTTP_PARSING_HEADER_NAME
@@ -77,7 +92,6 @@ struct http_context_ {
char* uri;
char parse_buffer[HTTP_PARSE_BUF_MAX_LEN];
char* request_header_tmp;
- struct netconn *conn;
http_parser parser;
http_header_list_t request_headers;
int response_code;
@@ -88,22 +102,51 @@ struct http_context_ {
const char* data_ptr;
size_t data_size;
http_header_list_t request_args;
+#ifdef HTTPS_SERVER
+ mbedtls_ssl_context *ssl_conn;
+ mbedtls_net_context *client_fd;
+#else
+ struct netconn *conn;
+#endif
};
-
struct http_server_context_ {
- int port;
- err_t server_task_err;
- struct netconn* server_conn;
+ int port;
TaskHandle_t task;
- EventGroupHandle_t start_done;
+ EventGroupHandle_t start_done;
+ err_t server_task_err;
SLIST_HEAD(, http_handler_t) handlers;
_lock_t handlers_lock;
struct http_context_ connection_context;
+#ifdef HTTPS_SERVER
+ mbedtls_net_context *listen_fd;
+ mbedtls_entropy_context *entropy;
+ mbedtls_ctr_drbg_context *ctr_drbg;
+ mbedtls_ssl_config *conf;
+ mbedtls_x509_crt *srvcert;
+ mbedtls_pk_context *pkey;
+ mbedtls_ssl_cache_context *cache;
+ mbedtls_ssl_ticket_context *ticket_ctx;
+#else
+ struct netconn* server_conn;
+#endif
};
-#define SERVER_STARTED_BIT BIT(0)
-#define SERVER_DONE_BIT BIT(1)
+/** Return true if \p ret is a status code indicating that there is an
+ * operation in progress on an SSL connection, and false if it indicates
+ * success or a fatal error.
+ *
+ * The possible operations in progress are:
+ *
+ * - A read, when the SSL input buffer does not contain a full message.
+ * - A write, when the SSL output buffer contains some data that has not
+ * been sent over the network yet.
+ * - An asynchronous callback that has not completed yet. */
+static int mbedtls_status_is_ssl_in_progress( int ret )
+{
+ return( ret == MBEDTLS_ERR_SSL_WANT_READ ||
+ ret == MBEDTLS_ERR_SSL_WANT_WRITE );
+}
static const char* http_response_code_to_str(int code);
@@ -111,6 +154,7 @@ static esp_err_t add_keyval_pair(http_header_list_t *list, const char* name, con
static const char* TAG = "http_server";
+
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)
@@ -177,7 +221,7 @@ static void header_value_done(http_context_t ctx)
{
const char* value = ctx->parse_buffer;
const char* name = ctx->request_header_tmp;
- ESP_LOGD(TAG, "Got header: '%s': '%s'", name, value);
+ ESP_LOGI(TAG, "Got header: '%s': '%s'", name, value);
add_keyval_pair(&ctx->request_headers, name, value);
free(ctx->request_header_tmp);
ctx->request_header_tmp = NULL;
@@ -186,6 +230,7 @@ static void header_value_done(http_context_t ctx)
static int http_url_cb(http_parser* parser, const char *at, size_t length)
{
+ ESP_LOGD(TAG, "Called %s", __func__);
http_context_t ctx = (http_context_t) parser->data;
return append_parse_buffer(ctx, at, length);
}
@@ -204,6 +249,7 @@ static bool invoke_handler(http_context_t ctx, int event)
static int http_headers_done_cb(http_parser* parser)
{
+ ESP_LOGD(TAG, "Called %s", __func__);
http_context_t ctx = (http_context_t) parser->data;
if (ctx->state == HTTP_PARSING_HEADER_VALUE) {
header_value_done(ctx);
@@ -274,7 +320,7 @@ static void parse_urlencoded_args(http_context_t ctx, const char* str, size_t le
value = urldecode(token_start, pos - token_start);
state = READING_KEY;
token_start = pos + 1;
- ESP_LOGD(TAG, "Got request argument, '%s': '%s'", key, value);
+ ESP_LOGI(TAG, "Got request argument, '%s': '%s'", key, value);
add_keyval_pair(&ctx->request_args, key, value);
free(key);
key = NULL;
@@ -284,7 +330,7 @@ static void parse_urlencoded_args(http_context_t ctx, const char* str, size_t le
}
if (state == READING_VAL) {
value = urldecode(token_start, end - token_start);
- ESP_LOGD(TAG, "Got request argument, '%s': '%s'", key, value);
+ ESP_LOGI(TAG, "Got request argument, '%s': '%s'", key, value);
add_keyval_pair(&ctx->request_args, key, value);
free(key);
key = NULL;
@@ -302,7 +348,7 @@ static void uri_done(http_context_t ctx)
++query_str;
}
ctx->uri = strdup(ctx->parse_buffer);
- ESP_LOGD(TAG, "Got URI: '%s'", ctx->uri);
+ ESP_LOGI(TAG, "Got URI: '%s'", ctx->uri);
if (query_str) {
parse_urlencoded_args(ctx, query_str, strlen(query_str));
}
@@ -315,7 +361,7 @@ static void uri_done(http_context_t ctx)
static int http_header_name_cb(http_parser* parser, const char *at, size_t length)
{
- ESP_LOGV(TAG, "%s", __func__);
+ ESP_LOGD(TAG, "Called %s", __func__);
http_context_t ctx = (http_context_t) parser->data;
if (ctx->state == HTTP_PARSING_URI) {
uri_done(ctx);
@@ -329,7 +375,7 @@ static int http_header_name_cb(http_parser* parser, const char *at, size_t lengt
static int http_header_value_cb(http_parser* parser, const char *at, size_t length)
{
- ESP_LOGV(TAG, "%s", __func__);
+ ESP_LOGD(TAG, "Called %s", __func__);
http_context_t ctx = (http_context_t) parser->data;
if (ctx->state == HTTP_PARSING_HEADER_NAME) {
header_name_done(ctx);
@@ -340,7 +386,7 @@ static int http_header_value_cb(http_parser* parser, const char *at, size_t leng
static int http_body_cb(http_parser* parser, const char *at, size_t length)
{
- ESP_LOGV(TAG, "%s", __func__);
+ ESP_LOGD(TAG, "Called %s", __func__);
http_context_t ctx = (http_context_t) parser->data;
ctx->data_ptr = at;
ctx->data_size = length;
@@ -352,7 +398,7 @@ static int http_body_cb(http_parser* parser, const char *at, size_t length)
static int http_message_done_cb(http_parser* parser)
{
- ESP_LOGV(TAG, "%s", __func__);
+ ESP_LOGD(TAG, "Called %s", __func__);
http_context_t ctx = (http_context_t) parser->data;
ctx->state = HTTP_REQUEST_DONE;
return 0;
@@ -388,6 +434,7 @@ const char* http_request_get_arg_value(http_context_t ctx, const char* name)
{
http_header_t* it;
SLIST_FOREACH(it, &ctx->request_args, list_entry) {
+ ESP_LOGI(TAG, "Key %s: %s", it->name, it->value);
if (strcasecmp(name, it->name) == 0) {
return it->value;
}
@@ -415,7 +462,7 @@ static void form_data_handler_cb(http_context_t http_ctx, void* ctx)
const char* str;
size_t len;
http_request_get_data(http_ctx, &str, &len);
- parse_urlencoded_args(ctx, str, len);
+ parse_urlencoded_args(http_ctx, str, len);
}
}
@@ -517,12 +564,49 @@ static esp_err_t http_send_response_headers(http_context_t http_ctx)
headers_list_clear(&http_ctx->response_headers);
+#ifdef HTTPS_SERVER
+ int ret;
+ int actual_len;
+ ESP_LOGI(TAG, "Writing response headers..." );
+
+ len = strlen(headers_buf);
+ actual_len = 0;
+ ret = 0;
+ do
+ {
+ len = len - ret;
+ ret = mbedtls_ssl_write( http_ctx->ssl_conn, ((const unsigned char *)headers_buf + ret), len);
+ if( ret == MBEDTLS_ERR_NET_CONN_RESET )
+ {
+ ESP_LOGE(TAG, "ERROR: peer closed the connection\n\n" );
+ //FIXME: reset connection
+ //goto reset;
+ }
+
+ if( ret < 0 && ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE )
+ {
+ ESP_LOGE(TAG, "ERROR: mbedtls_ssl_write returned %d\n\n", ret );
+ break;
+ //FIXME: close connection
+ //goto exit;
+ }
+ if (ret > 0)
+ actual_len += ret;
+ }while( ret < 0 || ret < len );
+
+ ESP_LOGI(TAG, "%d bytes written:\n%s", actual_len, (char *)headers_buf);
+ free(headers_buf);
+ http_ctx->state = HTTP_SENDING_RESPONSE_BODY;
+ //FIXME: check return code from mbedTLS
+ return ESP_OK;
+#else
err_t err = netconn_write(http_ctx->conn, headers_buf, strlen(headers_buf), NETCONN_COPY);
free(headers_buf);
http_ctx->state = HTTP_SENDING_RESPONSE_BODY;
return lwip_err_to_esp_err(err);
+#endif
}
/* Common function called by http_response_begin and http_response_begin_multipart */
@@ -554,21 +638,54 @@ esp_err_t http_response_begin(http_context_t http_ctx, int code, const char* con
esp_err_t http_response_write(http_context_t http_ctx, const http_buffer_t* buffer)
{
+ size_t len;
+ int ret;
+ esp_err_t err;
if (http_ctx->state == HTTP_COLLECTING_RESPONSE_HEADERS) {
- esp_err_t err = http_send_response_headers(http_ctx);
+ err = http_send_response_headers(http_ctx);
if (err != ESP_OK) {
+ ESP_LOGE(TAG, "ERROR: in http_send_response_headers function...");
return err;
}
}
- const int flag = buffer->data_is_persistent ? NETCONN_NOCOPY : NETCONN_COPY;
- size_t len = buffer->size ? buffer->size : strlen((const char*) buffer->data);
- err_t rc = netconn_write(http_ctx->conn, buffer->data, len, flag);
+ len = buffer->size ? buffer->size : strlen((const char*) buffer->data);
+#ifdef HTTPS_SERVER
+ ESP_LOGI(TAG, "Writing to client:" );
+ ret = 0;
+ do
+ {
+ len = len - ret;
+ ret = mbedtls_ssl_write( http_ctx->ssl_conn, (buffer->data + ret), len);
+ if( ret == MBEDTLS_ERR_NET_CONN_RESET )
+ {
+ ESP_LOGE(TAG, "ERROR: peer closed the connection\n\n" );
+ //FIXME: reset connection
+ //goto reset;
+ }
+
+ if( ret < 0 && ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE )
+ {
+ ESP_LOGE(TAG, "ERROR: mbedtls_ssl_write returned %d\n\n", ret );
+ break;
+ //FIXME: close connection
+ //goto exit;
+ }
+ if (ret > 0)
+ http_ctx->accumulated_response_size += ret;
+ }while( ret < 0 || ret < len );
+
+ ESP_LOGI(TAG, "%d bytes written:%s", http_ctx->accumulated_response_size, (char *)buffer->data);
+ return ret;
+#else
+ const int flag = buffer->data_is_persistent ? NETCONN_NOCOPY : NETCONN_COPY;
+ err_t rc = netconn_write(http_ctx->conn, buffer->data, len, flag);
if (rc != ESP_OK) {
ESP_LOGD(TAG, "netconn_write rc=%d", rc);
} else {
http_ctx->accumulated_response_size += len;
}
return lwip_err_to_esp_err(rc);
+#endif
}
@@ -636,12 +753,15 @@ esp_err_t http_response_set_header(http_context_t http_ctx, const char* name, co
static void http_send_not_found_response(http_context_t http_ctx)
{
- http_response_begin(http_ctx, 404, "text/plain", HTTP_RESPONSE_SIZE_UNKNOWN);
+ ESP_LOGD(TAG, "Called %s", __func__);
+ http_response_begin(http_ctx, 404, "text/plain", HTTP_RESPONSE_SIZE_UNKNOWN);
const http_buffer_t buf = {
.data = "Not found",
.data_is_persistent = true
};
+ ESP_LOGD(TAG, "Calling http_response_write function...");
http_response_write(http_ctx, &buf);
+ ESP_LOGD(TAG, "Calling http_response_end function...");
http_response_end(http_ctx);
}
@@ -662,19 +782,24 @@ static const char* http_response_code_to_str(int code)
}
-static void http_handle_connection(http_server_t server, struct netconn *conn)
+static void http_handle_connection(http_server_t server, void *arg_conn)
{
- struct netbuf *inbuf = NULL;
- char *buf;
- u16_t buflen;
- err_t err = ERR_OK;
+ unsigned char *buf;
+ unsigned char *larger_buf;
+ size_t len = 0;
/* Single threaded server, one context only */
http_context_t ctx = &server->connection_context;
/* Initialize context */
ctx->state = HTTP_PARSING_URI;
- ctx->conn = conn;
+#ifdef HTTPS_SERVER
+#else
+ struct netbuf *inbuf = NULL;
+ u16_t buflen;
+ err_t err = ERR_OK;
+ ctx->conn = (struct netconn *)arg_conn;
+#endif
http_parser_init(&ctx->parser, HTTP_REQUEST);
ctx->parser.data = ctx;
ctx->server = server;
@@ -688,87 +813,575 @@ static void http_handle_connection(http_server_t server, struct netconn *conn)
.on_message_complete = &http_message_done_cb
};
- while (ctx->state != HTTP_REQUEST_DONE) {
- err = netconn_recv(conn, &inbuf);
- if (err != ERR_OK) {
- break;
- }
-
- err = netbuf_data(inbuf, (void**) &buf, &buflen);
- if (err != ERR_OK) {
- break;
- }
-
- size_t parsed_bytes = http_parser_execute(&ctx->parser, &parser_settings, buf, buflen);
- if (parsed_bytes < buflen) {
- break;
- }
- }
+#ifdef HTTPS_SERVER
+ int ret;
+ size_t parsed_bytes = 0;
+ /*
+ * 6. Read the HTTP Request
+ */
+
+ ret = 0;
+ buf = malloc(sizeof(char)*MBEDTLS_EXAMPLE_RECV_BUF_LEN);
+
+ while (ctx->state != HTTP_REQUEST_DONE) {
+ ESP_LOGV(TAG, "Reading from client..." );
+/*
+ memset( buf, 0, sizeof(char)*MBEDTLS_EXAMPLE_RECV_BUF_LEN);
+ //FIXME: add support for buffer > MBEDTLS_EXAMPLE_RECV_BUF_LEN
+ ret = mbedtls_ssl_read( server->connection_context.ssl_conn, buf, MBEDTLS_EXAMPLE_RECV_BUF_LEN);
+
+ if( ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE )
+ continue;
+
+ if( ret <= 0 )
+ {
+ switch( ret )
+ {
+ case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
+ ESP_LOGW(TAG, "Error: connection was closed gracefully" );
+ break;
+
+ case MBEDTLS_ERR_NET_CONN_RESET:
+ ESP_LOGW(TAG, "Error: connection was reset by peer" );
+ break;
+
+ default:
+ ESP_LOGW(TAG, "Error: mbedtls_ssl_read returned -0x%x\n", -ret );
+ break;
+ }
+
+ break;
+ }
+*/
+ do
+ {
+ int terminated = 0;
+ len = sizeof(char)*MBEDTLS_EXAMPLE_RECV_BUF_LEN;
+ memset( buf, 0, sizeof(char)*MBEDTLS_EXAMPLE_RECV_BUF_LEN);
+ ret = mbedtls_ssl_read( server->connection_context.ssl_conn, buf, len );
+
+ if( mbedtls_status_is_ssl_in_progress( ret ) )
+ {
+ continue;
+ }
+
+ if( ret <= 0 )
+ {
+ switch( ret )
+ {
+ case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
+ ESP_LOGW(TAG, "Error: connection was closed gracefully" );
+ break;
+
+ case MBEDTLS_ERR_NET_CONN_RESET:
+ ESP_LOGW(TAG, "Error: connection was reset by peer" );
+ break;
+
+ default:
+ ESP_LOGW(TAG, "Error: mbedtls_ssl_read returned -0x%x\n", -ret );
+ break;
+ }
+ }
+
+ if( mbedtls_ssl_get_bytes_avail( server->connection_context.ssl_conn ) == 0 )
+ {
+ len = ret;
+ buf[len] = '\0';
+ ESP_LOGI(TAG, "%d bytes read: \n%s", len, (char *) buf );
+ /* End of message should be detected according to the syntax of the
+ * application protocol (eg HTTP), just use a dummy test here. */
+ if( buf[len - 1] == '\n' )
+ terminated = 1;
+ }
+ else
+ {
+ size_t extra_len, ori_len;
+
+ ori_len = ret;
+ extra_len = (size_t) mbedtls_ssl_get_bytes_avail( server->connection_context.ssl_conn );
+
+ larger_buf = mbedtls_calloc( 1, ori_len + extra_len + 1 );
+ if( larger_buf == NULL )
+ {
+ ESP_LOGE(TAG, "Failed to allocate larger_buf");
+ len = 0;
+ break;
+ }
+
+ memset( larger_buf, 0, ori_len + extra_len );
+ memcpy( larger_buf, buf, ori_len );
+
+ if(buf) //Free original buffer;
+ free(buf);
+
+ /* This read should never fail and get the whole cached data */
+ ret = mbedtls_ssl_read( server->connection_context.ssl_conn, larger_buf + ori_len, extra_len );
+ if( ret != extra_len ||
+ mbedtls_ssl_get_bytes_avail( server->connection_context.ssl_conn ) != 0 )
+ {
+ ESP_LOGE(TAG, "Failed on cached data");
+ len = 0;
+ break;
+ }
+
+ larger_buf[ori_len + extra_len] = '\0';
+
+ /* End of message should be detected according to the syntax of the
+ * application protocol (eg HTTP), just use a dummy test here. */
+ if( larger_buf[ori_len + extra_len - 1] == '\n' )
+ {
+ terminated = 1;
+ len = ori_len + extra_len;
+ buf = larger_buf;
+ }
+
+ ESP_LOGI(TAG, "%d bytes read (%d + %d): \n%s", len,
+ ori_len, extra_len, (char *) buf );
+ }
+
+ if( terminated )
+ {
+ break;
+ }
+ }
+ while( 1 );
+
+ if( len == 0 ) //If output buffer length is 0 (indicating a error), finishes processing of this request
+ break;
+
+ ESP_LOGI(TAG, "Calling http_parser_execute...");
+ parsed_bytes = http_parser_execute(&ctx->parser, &parser_settings, (char *)buf, len);
+ }
+ ESP_LOGD(TAG, "Read looping returned: %d", parsed_bytes);
+
+#else //HTPPS SERVER OFF
+ while (ctx->state != HTTP_REQUEST_DONE) {
+ err = netconn_recv(ctx->conn, &inbuf);
+ if (err != ERR_OK) {
+ break;
+ }
+
+ err = netbuf_data(inbuf, (void**) &buf, &buflen);
+ if (err != ERR_OK) {
+ break;
+ }
+
+ size_t parsed_bytes = http_parser_execute(&ctx->parser, &parser_settings, (char *)buf, buflen);
+ if (parsed_bytes < buflen) {
+ break;
+ }
+ }
+#endif
- if (err == ERR_OK) {
+#ifdef HTTPS_SERVER
+ if (len > 0) {
ctx->state = HTTP_COLLECTING_RESPONSE_HEADERS;
if (ctx->handler == NULL) {
- http_send_not_found_response(ctx);
+ ESP_LOGD(TAG, "No registered Handler!");
+ http_send_not_found_response(ctx);
+
} else {
- invoke_handler(ctx, HTTP_HANDLE_RESPONSE);
+ ESP_LOGD(TAG, "Registered Handler Found!");
+ invoke_handler(ctx, HTTP_HANDLE_RESPONSE);
}
}
+#else
+ if (err == ERR_OK) {
+ ctx->state = HTTP_COLLECTING_RESPONSE_HEADERS;
+ if (ctx->handler == NULL) {
+ ESP_LOGD(TAG, "No registered Handler!");
+ http_send_not_found_response(ctx);
+ } else {
+ ESP_LOGD(TAG, "Registered Handler Found!");
+ invoke_handler(ctx, HTTP_HANDLE_RESPONSE);
+ }
+ }
+#endif
headers_list_clear(&ctx->request_headers);
headers_list_clear(&ctx->request_args);
-
free(ctx->uri);
ctx->uri = NULL;
ctx->handler = NULL;
+
+#ifdef HTTPS_SERVER
+ ESP_LOGI(TAG, "Closing the connection..." );
+ while( ( ret = mbedtls_ssl_close_notify( server->connection_context.ssl_conn) ) < 0 )
+ {
+ if( ret != MBEDTLS_ERR_SSL_WANT_READ &&
+ ret != MBEDTLS_ERR_SSL_WANT_WRITE )
+ {
+ ESP_LOGI(TAG, "ERROR: mbedtls_ssl_close_notify returned %d\n\n", ret );
+ break;
+ //FIXME: Reset connection
+ //goto reset;
+ }
+ }
+ ESP_LOGI(TAG, "OK");
+ if(buf)
+ free(buf);
+#else
if (err != ERR_CLSD) {
- netconn_close(conn);
+ netconn_close(ctx->conn);
}
if (inbuf) {
netbuf_delete(inbuf);
}
+#endif
}
static void http_server(void *arg)
{
+ uint8_t bits;
http_server_t ctx = (http_server_t) arg;
- struct netconn *client_conn;
- err_t err;
- ctx->server_conn = netconn_new(NETCONN_TCP);
- if (ctx->server_conn == NULL) {
- err = ERR_MEM;
- goto out;
- }
-
- err = netconn_bind(ctx->server_conn, NULL, ctx->port);
- if (err != ERR_OK) {
- goto out;
- }
-
- err = netconn_listen(ctx->server_conn);
- if (err != ERR_OK) {
- goto out;
- }
- xEventGroupSetBits(ctx->start_done, SERVER_STARTED_BIT);
+ do{
+ ESP_LOGV(TAG, "Checking Server Status...");
+ bits = xEventGroupWaitBits(ctx->start_done, SERVER_STARTED_BIT | SERVER_DONE_BIT, 0, pdTRUE, 1000 / portTICK_PERIOD_MS);
+
+ //If server had already been successfully started but it has crashed,
+ if ((bits & SERVER_STARTED_BIT) && (bits & SERVER_DONE_BIT)) {
+ ESP_LOGE(TAG, "Server has closed. Restarting server...");
+ xEventGroupClearBits(ctx->start_done, SERVER_STARTED_BIT | SERVER_DONE_BIT);
+ memset(&(ctx->connection_context), 0, sizeof(*ctx) - (size_t)((int)&(ctx->connection_context) - (int)ctx) );
+ bits = pdFALSE;
+ }
+
+ //If server has not successfully been started yet,
+ if (!(bits & SERVER_STARTED_BIT)) {
+ #ifdef HTTPS_SERVER
+ char *error_buf;
+ ESP_LOGV(TAG, "Declaring local mbedTLS context on task...");
+ int ret;
+ mbedtls_net_context listen_fd;
+ mbedtls_net_context client_fd;
+ mbedtls_entropy_context entropy;
+ mbedtls_ctr_drbg_context ctr_drbg;
+ mbedtls_ssl_context ssl_conn;
+ mbedtls_ssl_config conf;
+ mbedtls_x509_crt srvcert;
+ mbedtls_pk_context pkey;
+ #if defined(MBEDTLS_SSL_CACHE_C)
+ mbedtls_ssl_cache_context cache;
+ (ctx->cache) = &cache;
+ #endif
+ #if defined(MBEDTLS_SSL_SESSION_TICKETS)
+ mbedtls_ssl_ticket_context ticket_ctx;
+ (ctx->ticket_ctx) = &ticket_ctx;
+ #endif
+ (ctx->listen_fd) = &listen_fd;
+ (ctx->connection_context.client_fd) = &client_fd;
+ (ctx->entropy) = &entropy;
+ (ctx->ctr_drbg) = &ctr_drbg;
+ (ctx->connection_context.ssl_conn) = &ssl_conn;
+ (ctx->conf) = &conf;
+ (ctx->srvcert) = &srvcert;
+ (ctx->pkey) = &pkey;
+
+ ESP_LOGV(TAG, "Reading Root CA certificate......");
+ extern const unsigned char rootcacert_pem_start[] asm("_binary_rootCertificate_pem_start");
+ extern const unsigned char rootcacert_pem_end[] asm("_binary_rootCertificate_pem_end");
+ const unsigned int rootcacert_pem_bytes = rootcacert_pem_end - rootcacert_pem_start;
+
+ /*
+ ESP_LOGV(TAG, "Reading Intermediate CA certificate......");
+ extern const unsigned char intermediatecacert_pem_start[] asm("_binary_intermediatecacert_pem_start");
+ extern const unsigned char intermediatecacert_pem_end[] asm("_binary_intermediatecacert_pem_end");
+ const unsigned int intermediatecacert_pem_bytes = intermediatecacert_pem_end - intermediatecacert_pem_start;
+ */
+
+ ESP_LOGV(TAG, "Reading Server certificate......");
+ extern const unsigned char servercert_pem_start[] asm("_binary_esp32Certificate_pem_start");
+ extern const unsigned char servercert_pem_end[] asm("_binary_esp32Certificate_pem_end");
+ const unsigned int servercert_pem_bytes = servercert_pem_end - servercert_pem_start;
+
+ ESP_LOGV(TAG, "Reading Server Private Key......");
+ extern const unsigned char serverprvtkey_pem_start[] asm("_binary_esp32_key_pem_start");
+ extern const unsigned char serverprvtkey_pem_end[] asm("_binary_esp32_key_pem_end");
+ const unsigned int serverprvtkey_pem_bytes = serverprvtkey_pem_end - serverprvtkey_pem_start;
+
+ ESP_LOGV(TAG, "Setting server_fd......");
+ mbedtls_net_init( ctx->listen_fd );
+ ESP_LOGV(TAG, "OK");
+
+ ESP_LOGV(TAG, "Setting client fd......");
+ mbedtls_net_init( ctx->connection_context.client_fd );
+ ESP_LOGV(TAG, "OK");
+
+ ESP_LOGV(TAG, "SSL server context create ......");
+ mbedtls_ssl_init( ctx->connection_context.ssl_conn );
+ ESP_LOGV(TAG, "OK");
+
+ ESP_LOGV(TAG, "SSL conf context create ......");
+ mbedtls_ssl_config_init( ctx->conf );
+ ESP_LOGV(TAG, "OK");
+
+#if defined(MBEDTLS_SSL_CACHE_C)
+ mbedtls_ssl_cache_init( ctx->cache );
+#endif
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+ mbedtls_ssl_ticket_init( ctx->ticket_ctx );
+#endif
+ mbedtls_x509_crt_init( ctx->srvcert );
+ mbedtls_pk_init( ctx->pkey );
+ mbedtls_entropy_init( ctx->entropy );
+ mbedtls_ctr_drbg_init( ctx->ctr_drbg );
+
+ /*
+ * 1. Load the certificates and private RSA key
+ */
+ ESP_LOGD(TAG, "Loading the server cert. and key..." );
+ /*
+ * This demonstration program uses embedded test certificates.
+ * Instead, you may want to use mbedtls_x509_crt_parse_file() to read the
+ * server and CA certificates, as well as mbedtls_pk_parse_keyfile().
+ */
+ ESP_LOGV(TAG, "SSL server context set own certification......");
+ ESP_LOGV(TAG, "Parsing test srv_crt......");
+ ret = mbedtls_x509_crt_parse( ctx->srvcert, (const unsigned char *) servercert_pem_start,
+ servercert_pem_bytes );
+ if( ret != ERR_OK )
+ {
+ ESP_LOGE(TAG, "ERROR: mbedtls_x509_crt_parse returned %d", ret );
+ goto exit;
+ }
+ ESP_LOGV(TAG, "OK");
+
+ /*
+ ESP_LOGV(TAG, "Parsing Intermediate CA crt......");
+ ret = mbedtls_x509_crt_parse( ctx->srvcert, (const unsigned char *) intermediatecacert_pem_start,
+ intermediatecacert_pem_bytes );
+ if( ret != ERR_OK )
+ {
+ ESP_LOGE(TAG, "ERROR: mbedtls_x509_crt_parse returned %d", ret );
+ goto exit;
+ }
+ ESP_LOGV(TAG, "OK");
+ */
+
+ ESP_LOGV(TAG, "Parsing Root CA crt......");
+ ret = mbedtls_x509_crt_parse( ctx->srvcert, (const unsigned char *) rootcacert_pem_start,
+ rootcacert_pem_bytes );
+ if( ret != ERR_OK )
+ {
+ ESP_LOGE(TAG, "ERROR: mbedtls_x509_crt_parse returned %d", ret );
+ goto exit;
+ }
+ ESP_LOGV(TAG, "OK");
+
+
+ ESP_LOGV(TAG, "SSL server context set private key......");
+ ret = mbedtls_pk_parse_key( ctx->pkey, (const unsigned char *) serverprvtkey_pem_start,
+ serverprvtkey_pem_bytes, NULL, 0 );
+ if( ret != ERR_OK )
+ {
+ ESP_LOGE(TAG, "ERROR: mbedtls_pk_parse_key returned %d", ret );
+ goto exit;
+ }
+ ESP_LOGV(TAG, "OK");
+
+ /*
+ * 3. Seed the RNG
+ */
+ ESP_LOGV(TAG, "Seeding the random number generator..." );
+ if( ( ret = mbedtls_ctr_drbg_seed( ctx->ctr_drbg, mbedtls_entropy_func, ctx->entropy,
+ (const unsigned char *) TAG,
+ strlen( TAG ) ) ) != 0 )
+ {
+ ESP_LOGE(TAG, "ERROR: mbedtls_ctr_drbg_seed returned %d", ret );
+ goto exit;
+ }
+ ESP_LOGV(TAG, "OK");
+
+ /*
+ * 2. Setup the listening TCP socket
+ */
+ char *port = malloc(sizeof(char) * 6);
+ ESP_LOGV(TAG, "SSL server socket bind at localhost: %s ......", itoa(ctx->port, port,10));
+ if( ( ret = mbedtls_net_bind( ctx->listen_fd, NULL, itoa(ctx->port, port,10), MBEDTLS_NET_PROTO_TCP ) ) != 0 )
+ {
+ ESP_LOGE(TAG, "ERROR: mbedtls_net_bind returned %d", ret );
+ goto exit;
+ }
+ free(port);
+ ESP_LOGV(TAG, "OK");
+
+
+ /*
+ * 4. Setup stuff
+ */
+ ESP_LOGV(TAG, "Setting up the SSL conf data...." );
+ #ifdef CONFIG_MBEDTLS_DEBUG
+ mbedtls_esp_enable_debug_log(ctx->conf, 4);
+ #endif
+ if( ( ret = mbedtls_ssl_config_defaults( ctx->conf,
+ MBEDTLS_SSL_IS_SERVER,
+ MBEDTLS_SSL_TRANSPORT_STREAM,
+ MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 )
+ {
+ ESP_LOGE(TAG, "ERROR: mbedtls_ssl_config_defaults returned %d", ret );
+ goto exit;
+ }
+
+ mbedtls_ssl_conf_rng( ctx->conf, mbedtls_ctr_drbg_random, ctx->ctr_drbg );
+
+#if defined(MBEDTLS_SSL_CACHE_C)
+ mbedtls_ssl_conf_session_cache( ctx->conf, ctx->cache,
+ mbedtls_ssl_cache_get,
+ mbedtls_ssl_cache_set );
+#endif
- do {
- err = netconn_accept(ctx->server_conn, &client_conn);
- if (err == ERR_OK) {
- http_handle_connection(ctx, client_conn);
- netconn_delete(client_conn);
- }
- } while (err == ERR_OK);
+ ESP_LOGV(TAG, "Setting up the SSL Session Tickets...." );
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+ if( ( ret = mbedtls_ssl_ticket_setup( ctx->ticket_ctx ,
+ mbedtls_ctr_drbg_random, &ctr_drbg,
+ MBEDTLS_CIPHER_AES_256_GCM,
+ 86400 ) ) != 0 )
+ {
+ ESP_LOGE(TAG, "ERROR: mbedtls_ssl_ticket_setup returned %d", ret );
+ goto exit;
+ }
+
+ mbedtls_ssl_conf_session_tickets_cb( &conf,
+ mbedtls_ssl_ticket_write,
+ mbedtls_ssl_ticket_parse,
+ ctx->ticket_ctx );
+#endif
-out:
- if (ctx->server_conn) {
- netconn_close(ctx->server_conn);
- netconn_delete(ctx->server_conn);
- }
- if (err != ERR_OK) {
- ctx->server_task_err = err;
- xEventGroupSetBits(ctx->start_done, SERVER_DONE_BIT);
- }
- vTaskDelete(NULL);
+ mbedtls_ssl_conf_ca_chain( ctx->conf, (*ctx->srvcert).next, NULL );
+ if( ( ret = mbedtls_ssl_conf_own_cert( ctx->conf, ctx->srvcert, ctx->pkey ) ) != 0 )
+ {
+ ESP_LOGE(TAG, "ERROR: mbedtls_ssl_conf_own_cert returned %d", ret );
+ goto exit;
+ }
+
+ if( ( ret = mbedtls_ssl_setup( ctx->connection_context.ssl_conn, ctx->conf ) ) != 0 )
+ {
+ ESP_LOGE(TAG, "ERROR: mbedtls_ssl_setup returned %d", ret );
+ goto exit;
+ }
+ ESP_LOGV(TAG, "OK");
+
+ xEventGroupSetBits(ctx->start_done, SERVER_STARTED_BIT);
+reset:
+ ESP_LOGI(TAG, "Clearing SERVER_PROCESSING_REQUEST bit...");
+ xEventGroupClearBits(ctx->start_done, SERVER_PROCESSING_REQUEST);
+ ESP_LOGI(TAG, "mbedTLS HTTPS server is running! Waiting for new connection...");
+ do {
+ mbedtls_net_free( ctx->connection_context.client_fd );
+
+ mbedtls_ssl_session_reset( ctx->connection_context.ssl_conn );
+ /*
+ * 3. Wait until a client connects
+ */
+ ESP_LOGV(TAG, "Wait until a client connects..." );
+ if( ( ret = mbedtls_net_accept( ctx->listen_fd, ctx->connection_context.client_fd,
+ NULL, 0, NULL ) ) != 0 )
+ {
+ ESP_LOGE(TAG, "ERROR: mbedtls_net_accept returned %d", ret );
+ goto exit;
+ }
+ ESP_LOGI(TAG, "Setting SERVER_PROCESSING_REQUEST bit...");
+ xEventGroupSetBits(ctx->start_done, SERVER_PROCESSING_REQUEST);
+ mbedtls_ssl_set_bio( ctx->connection_context.ssl_conn, ctx->connection_context.client_fd, mbedtls_net_send, mbedtls_net_recv, NULL );
+ ESP_LOGV(TAG, "OK");
+
+ /*
+ * 5. Handshake
+ */
+ ESP_LOGV(TAG, "Performing the SSL/TLS handshake..." );
+ while( ( ret = mbedtls_ssl_handshake( ctx->connection_context.ssl_conn ) ) != ERR_OK )
+ {
+ if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE )
+ {
+ ESP_LOGE(TAG, "ERROR: bedtls_ssl_handshake returned %d", ret );
+ goto reset;
+ }
+ }
+ ESP_LOGV(TAG, "OK");
+ ESP_LOGV(TAG, "Handling connection..." );
+ if (ret == ERR_OK) {
+ http_handle_connection(ctx, NULL);
+ }
+ ESP_LOGI(TAG, "Clearing SERVER_PROCESSING_REQUEST bit...");
+ xEventGroupClearBits(ctx->start_done, SERVER_PROCESSING_REQUEST);
+ ESP_LOGV(TAG, "OK");
+ } while (ret == ERR_OK);
+
+exit:
+ if (ret != ERR_OK) {
+ error_buf = malloc(sizeof(char)*ERROR_BUF_LENGTH);
+ mbedtls_strerror( ret, error_buf, sizeof(char)*ERROR_BUF_LENGTH );
+ ESP_LOGE(TAG, "Error %d: %s", ret, error_buf );
+ free(error_buf);
+
+ //Set SERVER_DONE_BIT and save error at http_server_t struct
+ ctx->server_task_err = ret;
+ xEventGroupSetBits(ctx->start_done, SERVER_DONE_BIT);
+ ESP_LOGI(TAG, "Clearing SERVER_PROCESSING_REQUEST bit...");
+ xEventGroupClearBits(ctx->start_done, SERVER_PROCESSING_REQUEST);
+ }
+
+ mbedtls_net_free( ctx->connection_context.client_fd );
+ mbedtls_net_free( ctx->listen_fd );
+ mbedtls_x509_crt_free( ctx->srvcert );
+ mbedtls_pk_free( ctx->pkey );
+ mbedtls_ssl_free( ctx->connection_context.ssl_conn );
+ mbedtls_ssl_config_free( ctx->conf );
+#if defined(MBEDTLS_SSL_CACHE_C)
+ mbedtls_ssl_cache_free( ctx->cache );
+#endif
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+ mbedtls_ssl_ticket_free( ctx->ticket_ctx );
+#endif
+ mbedtls_ctr_drbg_free( ctx->ctr_drbg );
+ mbedtls_entropy_free( ctx->entropy );
+#else
+ struct netconn *client_conn;
+ err_t err;
+ ctx->server_conn = netconn_new(NETCONN_TCP);
+ if (ctx->server_conn == NULL) {
+ err = ERR_MEM;
+ goto out;
+ }
+
+ err = netconn_bind(ctx->server_conn, NULL, ctx->port);
+ if (err != ERR_OK) {
+ goto out;
+ }
+
+ err = netconn_listen(ctx->server_conn);
+ if (err != ERR_OK) {
+ goto out;
+ }
+ xEventGroupSetBits(ctx->start_done, SERVER_STARTED_BIT);
+
+ do {
+ err = netconn_accept(ctx->server_conn, &client_conn);
+ if (err == ERR_OK) {
+ ESP_LOGI(TAG, "Setting SERVER_PROCESSING_REQUEST bit...");
+ xEventGroupSetBits(ctx->start_done, SERVER_PROCESSING_REQUEST);
+ http_handle_connection(ctx, client_conn);
+ netconn_delete(client_conn);
+ ESP_LOGI(TAG, "Clearing SERVER_PROCESSING_REQUEST bit...");
+ xEventGroupClearBits(ctx->start_done, SERVER_PROCESSING_REQUEST);
+ }
+ } while (err == ERR_OK);
+ out:
+ if (ctx->server_conn) {
+ netconn_close(ctx->server_conn);
+ netconn_delete(ctx->server_conn);
+ }
+ if (err != ERR_OK) {
+ ctx->server_task_err = err;
+ ESP_LOGI(TAG, "Clearing SERVER_PROCESSING_REQUEST bit...");
+ xEventGroupClearBits(ctx->start_done, SERVER_PROCESSING_REQUEST);
+ xEventGroupSetBits(ctx->start_done, SERVER_DONE_BIT);
+ }
+ vTaskDelete(NULL);
+ #endif
+ }
+ }while(1);
}
esp_err_t http_server_start(const http_server_options_t* options, http_server_t* out_server)
@@ -785,35 +1398,137 @@ esp_err_t http_server_start(const http_server_options_t* options, http_server_t*
return ESP_ERR_NO_MEM;
}
- int ret = xTaskCreatePinnedToCore(&http_server, "httpd",
- options->task_stack_size, ctx,
- options->task_priority,
- &ctx->task,
- options->task_affinity);
- if (ret != pdPASS) {
- vEventGroupDelete(ctx->start_done);
- free(ctx);
- return ESP_ERR_NO_MEM;
- }
-
- int bits = xEventGroupWaitBits(ctx->start_done, SERVER_STARTED_BIT | SERVER_DONE_BIT, 0, 0, portMAX_DELAY);
- if (bits & SERVER_DONE_BIT) {
- /* Error happened, task is deleted */
- esp_err_t err = lwip_err_to_esp_err(ctx->server_task_err);
- vEventGroupDelete(ctx->start_done);
- free(ctx);
- return err;
- }
-
- *out_server = ctx;
- return ESP_OK;
+ //Start http_server task if it had not been started before
+ ESP_LOGV(TAG, "Creating http_server task...");
+ int ret = xTaskCreatePinnedToCore(&http_server, "http_server",
+ options->task_stack_size, ctx,
+ options->task_priority,
+ &ctx->task,
+ options->task_affinity);
+ if (ret != pdPASS) {
+ vEventGroupDelete(ctx->start_done);
+ free(ctx);
+ return ESP_ERR_NO_MEM;
+ }
+ ESP_LOGI(TAG, "http_server task has been created!");
+
+ //Check server status by checking SERVER_STARTED_BIT (it server has been succesfully started) or SERVER_DONE_BIT (if it has crashed)
+ ESP_LOGV(TAG, "Checking server status...");
+ xEventGroupWaitBits(ctx->start_done, SERVER_STARTED_BIT, 0, 0, portMAX_DELAY);
+ ESP_LOGI(TAG, "Server started!");
+ *out_server = ctx;
+ return ESP_OK;
}
esp_err_t http_server_stop(http_server_t server)
{
/* FIXME: figure out a thread safe way to do this */
- netconn_close(server->server_conn);
+#ifdef HTTPS_SERVER
+ /* FIXME: Add function to stop HTTPS */
+#else
+ netconn_close(server->server_conn);
+#endif
xEventGroupWaitBits(server->start_done, SERVER_DONE_BIT, 0, 0, portMAX_DELAY);
free(server);
return ESP_OK;
}
+
+static void cb_GET_method(http_context_t http_ctx, void* ctx)
+{
+ size_t response_size = strlen(index_html);
+ http_response_begin(http_ctx, 200, "text/html", response_size);
+ http_buffer_t http_index_html = { .data = index_html };
+ http_response_write(http_ctx, &http_index_html);
+ http_response_end(http_ctx);
+}
+
+esp_err_t simple_GET_method_example(void)
+{
+ http_server_t server;
+#ifdef HTTPS_SERVER
+ http_server_options_t http_options = HTTPS_SERVER_OPTIONS_DEFAULT();
+#else
+ http_server_options_t http_options = HTTP_SERVER_OPTIONS_DEFAULT();
+#endif
+ esp_err_t res;
+
+ ESP_LOGI(TAG, "Creating Example Server!");
+ ESP_ERROR_CHECK( res = http_server_start(&http_options, &server) );
+ if (res != ESP_OK) {
+ return res;
+ }
+ ESP_LOGV(TAG, "OK");
+
+ ESP_LOGI(TAG, "Registering Handler!");
+ ESP_ERROR_CHECK( res = http_register_handler(server, "/", HTTP_GET, HTTP_HANDLE_RESPONSE, &cb_GET_method, NULL) );
+ if (res != ESP_OK) {
+ return res;
+ }
+ ESP_LOGV(TAG, "OK");
+
+ return res;
+}
+
+static void cb_POST_method(http_context_t http_ctx, void* ctx)
+{
+ const char* post_data;
+
+ ESP_LOGI(TAG, "Received data from POST method...");
+
+ /*Receiving key from POST*/
+ post_data = http_request_get_arg_value(http_ctx, "key");
+ if(post_data!=NULL){
+ ESP_LOGI(TAG, "Received %d bytes corresponding to the 'key': %s", strlen(post_data), post_data);
+ }else{
+ ESP_LOGI(TAG, "Received NULL from POST method");
+ }
+
+ size_t response_size = strlen(response_OK);
+ http_response_begin(http_ctx, 201, "text/plain", response_size);
+ http_buffer_t http_response_OK = { .data = response_OK };
+ http_response_write(http_ctx, &http_response_OK);
+ http_response_end(http_ctx);
+}
+
+esp_err_t simple_POST_method_example(void)
+{
+ http_server_t server;
+#ifdef HTTPS_SERVER
+ http_server_options_t http_options = HTTPS_SERVER_OPTIONS_DEFAULT();
+#else
+ http_server_options_t http_options = HTTP_SERVER_OPTIONS_DEFAULT();
+#endif
+ esp_err_t res;
+
+ ESP_ERROR_CHECK( res = http_server_start(&http_options, &server) );
+ if (res != ESP_OK) {
+ return res;
+ }
+
+ ESP_ERROR_CHECK( res = http_register_form_handler(server, "/", HTTP_POST, HTTP_HANDLE_RESPONSE, &cb_POST_method, NULL) );
+ if (res != ESP_OK) {
+ return res;
+ }
+
+ return res;
+}
+
+/**
+ * @brief Check if a request is being attended and returns it
+ *
+ * @param Current HTTP(S) server context
+ *
+ * @return a uint8_t variable indicating if server is processing any request
+ */
+uint8_t check_processing_request(http_server_t server)
+{
+ if(xEventGroupWaitBits(server->start_done, SERVER_PROCESSING_REQUEST, 0, 0, 0) & SERVER_PROCESSING_REQUEST) //If a request was not finished properly, returns an error
+ {
+ ESP_LOGI(TAG, "Processing Server Request");
+ return true;
+ }else
+ {
+ ESP_LOGI(TAG, "No Server Request");
+ return false;
+ }
+}
diff --git a/http_server.h b/http_server.h
index 9c109d8..6061f18 100644
--- a/http_server.h
+++ b/http_server.h
@@ -27,6 +27,9 @@ extern "C" {
* @brief Simple HTTP server
*/
+#include "sdkconfig.h"
+#include "esp_system.h"
+
/* Pull in the definitions of HTTP methods */
#include "http_parser.h"
@@ -38,6 +41,20 @@ extern "C" {
#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 */
+/**
+ * Bit masks for server event handler
+ */
+#define SERVER_STARTED_BIT BIT(0)
+#define SERVER_DONE_BIT BIT(1)
+#define SERVER_ERR_NO_MEM BIT(2)
+#define SERVER_PROCESSING_REQUEST BIT(3)
+
+/** Error buffer length */
+#define ERROR_BUF_LENGTH 100
+
+/** Uncomment to enable secure server */
+#define HTTPS_SERVER
+
/** Opaque type representing single HTTP connection */
typedef struct http_context_* http_context_t;
@@ -65,6 +82,32 @@ typedef struct {
.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
@@ -285,6 +328,33 @@ esp_err_t http_response_write(http_context_t http_ctx, const http_buffer_t* buff
*/
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);
+
+/**
+ * @brief Check if a request is being attended and returns it
+ *
+ * @param Current HTTP(S) server context
+ *
+ * @return a uint8_t variable indicating if server is processing any request
+ */
+uint8_t check_processing_request(http_server_t server);
+
#ifdef __cplusplus
}
#endif