--- /dev/null
+set(COMPONENT_ADD_INCLUDEDIRS include)
+set(COMPONENT_SRCS "src/https_server.c")
+
+set(COMPONENT_REQUIRES esp_http_server openssl)
+set(COMPONENT_PRIV_REQUIRES lwip)
+
+register_component()
--- /dev/null
+# HTTPS server
+
+This component is built on top of `esp_http_server`. The HTTPS server takes advantage of hooks and
+function overrides in the regular HTTP server to provide encryption using OpenSSL.
+
+All documentation for `esp_http_server` applies also to a server you create this way.
+
+## Used APIs
+
+The following API of `esp_http_server` should not be used with `esp_https_server`, as they are
+used internally to handle secure sessions and to maintain internal state:
+
+- "send", "receive" and "pending" function overrides - secure socket handling
+ - `httpd_set_sess_send_override()`
+ - `httpd_set_sess_recv_override()`
+ - `httpd_set_sess_pending_override()`
+ - `httpd_set_send_override()`
+ - `httpd_set_recv_override()`
+ - `httpd_set_pending_override()`
+- "transport context" - both global and session
+ - `httpd_sess_get_transport_ctx()` - returns SSL used for the session
+ - `httpd_sess_set_transport_ctx()`
+ - `httpd_get_global_transport_ctx()` - returns the shared SSL context
+ - `httpd_config_t.global_transport_ctx`
+ - `httpd_config_t.global_transport_ctx_free_fn`
+ - `httpd_config_t.open_fn` - used to set up secure sockets
+
+Everything else can be used without limitations.
+
+## Usage
+
+Please see the example `protocols/https_server` to learn how to set up a secure server.
+
+Basically all you need is to generate a certificate, embed it in the firmware, and provide
+its pointers and lengths to the start function via the init struct.
+
+The server can be started with or without SSL by changing a flag in the init struct.
+This could be used e.g. for testing or in trusted environments where you prefer speed over security.
+
+## Performance
+
+The initial session setup can take about two seconds, or more with slower clock speeds or more
+verbose logging. Subsequent requests through the open secure socket are much faster (down to under
+100 ms).
--- /dev/null
+COMPONENT_SRCDIRS := src
+COMPONENT_ADD_INCLUDEDIRS := include
--- /dev/null
+// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef _ESP_HTTPS_SERVER_H_
+#define _ESP_HTTPS_SERVER_H_
+
+#include <stdbool.h>
+#include "esp_err.h"
+#include "esp_http_server.h"
+
+/**
+ * HTTPS server config struct
+ *
+ * Please use HTTPD_SSL_CONFIG_DEFAULT() to initialize it.
+ */
+struct httpd_ssl_config {
+ /**
+ * Underlying HTTPD server config
+ *
+ * Parameters like task stack size and priority can be adjusted here.
+ */
+ httpd_config_t httpd;
+
+ /** CA certificate */
+ const uint8_t *cacert_pem;
+
+ /** CA certificate byte length */
+ size_t cacert_len;
+
+ /** Private key */
+ const uint8_t *prvtkey_pem;
+
+ /** Private key byte length */
+ size_t prvtkey_len;
+
+ /** Enable SSL (default true) */
+ bool secure_enable;
+
+ /** Port used when SSL is enabled (default 443) */
+ uint16_t port_secure;
+
+ /** Port used when SSL is disabled (default 80) */
+ uint16_t port_insecure;
+};
+
+typedef struct httpd_ssl_config httpd_ssl_config_t;
+
+/**
+ * Default config struct init
+ *
+ * (http_server default config had to be copied for customization)
+ *
+ * Notes:
+ * - port is set when starting the server, according to 'secure_enable'
+ * - one socket uses ~ 40kB RAM with SSL, we reduce the default socket count to 4
+ * - SSL sockets are usually long-lived, closing LRU prevents pool exhaustion DOS
+ * - Stack size may need adjustments depending on the user application
+ */
+#define HTTPD_SSL_CONFIG_DEFAULT() { \
+ .httpd = { \
+ .task_priority = tskIDLE_PRIORITY+5, \
+ .stack_size = 10240, \
+ .server_port = 0, \
+ .ctrl_port = 32768, \
+ .max_open_sockets = 4, \
+ .max_uri_handlers = 8, \
+ .max_resp_headers = 8, \
+ .backlog_conn = 5, \
+ .lru_purge_enable = true, \
+ .recv_wait_timeout = 5, \
+ .send_wait_timeout = 5, \
+ .global_user_ctx = NULL, \
+ .global_user_ctx_free_fn = NULL, \
+ .global_transport_ctx = NULL, \
+ .global_transport_ctx_free_fn = NULL, \
+ .open_fn = NULL, \
+ .close_fn = NULL, \
+ }, \
+ .secure_enable = true, \
+ .port_secure = 443, \
+ .port_insecure = 80, \
+}
+
+/**
+ * Create a SSL capable HTTP server (secure mode may be disabled in config)
+ *
+ * @param[in,out] config - server config, must not be const. Does not have to stay valid after
+ * calling this function.
+ * @param[out] handle - storage for the server handle, must be a valid pointer
+ * @return success
+ */
+esp_err_t httpd_ssl_start(httpd_handle_t *handle, httpd_ssl_config_t *config);
+
+/**
+ * Stop the server. Blocks until the server is shut down.
+ *
+ * @param[in] handle
+ */
+void httpd_ssl_stop(httpd_handle_t handle);
+
+#endif // _ESP_HTTPS_SERVER_H_
--- /dev/null
+// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <string.h>
+#include "esp_https_server.h"
+#include "openssl/ssl.h"
+#include "esp_log.h"
+#include "sdkconfig.h"
+
+const static char *TAG = "esp_https_server";
+
+/**
+ * SSL socket close handler
+ *
+ * @param[in] ctx - session transport context (SSL context we stored there)
+ */
+static void httpd_ssl_close(void *ctx)
+{
+ assert(ctx != NULL);
+ SSL_shutdown(ctx);
+ SSL_free(ctx);
+ ESP_LOGD(TAG, "Secure socket closed");
+}
+
+/**
+ * SSL socket pending-check function
+ *
+ * @param server
+ * @param sockfd
+ * @return number of pending bytes, negative on error
+ */
+static int httpd_ssl_pending(httpd_handle_t server, int sockfd)
+{
+ SSL *ssl = httpd_sess_get_transport_ctx(server, sockfd);
+ assert(ssl != NULL);
+ return SSL_pending(ssl);
+}
+
+/**
+ * Receive from a SSL socket
+ *
+ * @param server
+ * @param sockfd
+ * @param buf
+ * @param buf_len
+ * @param flags
+ * @return bytes read, negative on error
+ */
+static int httpd_ssl_recv(httpd_handle_t server, int sockfd, char *buf, size_t buf_len, int flags)
+{
+ SSL *ssl = httpd_sess_get_transport_ctx(server, sockfd);
+ assert(ssl != NULL);
+ return SSL_read(ssl, buf, buf_len);
+}
+
+/**
+ * Send to a SSL socket
+ *
+ * @param server
+ * @param sockfd
+ * @param buf
+ * @param buf_len
+ * @param flags
+ * @return bytes sent, negative on error
+ */
+static int httpd_ssl_send(httpd_handle_t server, int sockfd, const char *buf, size_t buf_len, int flags)
+{
+ SSL *ssl = httpd_sess_get_transport_ctx(server, sockfd);
+ assert(ssl != NULL);
+ return SSL_write(ssl, buf, buf_len);
+}
+
+/**
+ * Open a SSL socket for the server.
+ * The fd is already open and ready to read / write raw data.
+ *
+ * @param server
+ * @param sockfd - raw socket fd
+ * @return success
+ */
+static esp_err_t httpd_ssl_open(httpd_handle_t server, int sockfd)
+{
+ assert(server != NULL);
+
+ // Retrieve the SSL context from the global context field (set in config)
+ SSL_CTX *global_ctx = httpd_get_global_transport_ctx(server);
+ assert(global_ctx != NULL);
+
+ SSL *ssl = SSL_new(global_ctx);
+ if (NULL == ssl) {
+ ESP_LOGE(TAG, "SSL_new ret NULL (out of memory)");
+ return ESP_ERR_NO_MEM;
+ }
+
+ if (1 != SSL_set_fd(ssl, sockfd)) {
+ ESP_LOGE(TAG, "fail to set SSL fd");
+ goto teardown;
+ }
+
+ ESP_LOGD(TAG, "SSL accept");
+ if (1 != SSL_accept(ssl)) {
+ ESP_LOGW(TAG, "fail to SSL_accept - handshake error");
+ goto teardown;
+ }
+
+ // Store the SSL session into the context field of the HTTPD session object
+ httpd_sess_set_transport_ctx(server, sockfd, ssl, httpd_ssl_close);
+
+ // Set rx/tx/pending override functions
+ httpd_set_sess_send_override(server, sockfd, httpd_ssl_send);
+ httpd_set_sess_recv_override(server, sockfd, httpd_ssl_recv);
+ httpd_set_sess_pending_override(server, sockfd, httpd_ssl_pending);
+
+ // all access should now go through SSL
+
+ ESP_LOGD(TAG, "Secure socket open");
+
+ return ESP_OK;
+
+teardown:
+ SSL_free(ssl);
+ return ESP_FAIL;
+}
+
+/**
+ * Tear down the HTTPD global transport context
+ *
+ * @param ctx
+ */
+static void free_secure_context(void *ctx)
+{
+ assert(ctx != NULL);
+
+ ESP_LOGI(TAG, "Server shuts down, releasing SSL context");
+ SSL_CTX_free(ctx);
+}
+
+/**
+* Create and perform basic init of a SSL_CTX, or return NULL on failure
+*
+* @return ctx or null
+*/
+static SSL_CTX *create_secure_context(const struct httpd_ssl_config *config)
+{
+ SSL_CTX *ctx = NULL;
+
+ ESP_LOGD(TAG, "SSL server context create");
+ ctx = SSL_CTX_new(TLS_server_method());
+ if (NULL != ctx) {
+ //region SSL ctx alloc'd
+ ESP_LOGD(TAG, "SSL ctx set own cert");
+ if (SSL_CTX_use_certificate_ASN1(ctx, config->cacert_len, config->cacert_pem)
+ && SSL_CTX_use_PrivateKey_ASN1(0, ctx, config->prvtkey_pem, (long) config->prvtkey_len)) {
+ return ctx;
+ }
+ else {
+ ESP_LOGE(TAG, "Failed to set certificate");
+ SSL_CTX_free(ctx);
+ ctx = NULL;
+ }
+ } else {
+ ESP_LOGE(TAG, "Failed to create SSL context");
+ }
+ return NULL;
+}
+
+/** Start the server */
+esp_err_t httpd_ssl_start(httpd_handle_t *pHandle, struct httpd_ssl_config *config)
+{
+ assert(config != NULL);
+ assert(pHandle != NULL);
+
+ ESP_LOGI(TAG, "Starting server");
+
+ if (config->secure_enable) {
+ SSL_CTX *ctx = create_secure_context(config);
+ if (!ctx) {
+ return ESP_FAIL;
+ }
+
+ ESP_LOGD(TAG, "SSL context ready");
+
+ // set SSL specific config
+ config->httpd.global_transport_ctx = ctx;
+ config->httpd.global_transport_ctx_free_fn = free_secure_context;
+ config->httpd.open_fn = httpd_ssl_open; // the open function configures the created SSL sessions
+
+ config->httpd.server_port = config->port_secure;
+ } else {
+ ESP_LOGD(TAG, "SSL disabled, using plain HTTP");
+ config->httpd.server_port = config->port_insecure;
+ }
+
+ httpd_handle_t handle = NULL;
+
+ esp_err_t ret = httpd_start(&handle, &config->httpd);
+ if (ret != ESP_OK) return ret;
+
+ *pHandle = handle;
+
+ ESP_LOGI(TAG, "Server listening on port %d", config->httpd.server_port);
+ return ESP_OK;
+}
+
+/** Stop the server */
+void httpd_ssl_stop(httpd_handle_t handle)
+{
+ httpd_stop(handle);
+}
--- /dev/null
+# The following lines of boilerplate have to be in your project's CMakeLists
+# in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.5)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+project(https_server)
--- /dev/null
+#
+# This is a project Makefile. It is assumed the directory this Makefile resides in is a
+# project subdirectory.
+#
+
+PROJECT_NAME := https_server
+
+include $(IDF_PATH)/make/project.mk
+
--- /dev/null
+# HTTP server with SSL support using OpenSSL
+
+This example creates a SSL server that returns a simple HTML page when you visit its root URL.
+
+See the `esp_https_server` component documentation for details.
+
+## Certificates
+
+You will need to approve a security exception in your browser. This is because of a self signed
+certificate; this will be always the case, unless you preload the CA root into your browser/system
+as trusted.
+
+You can generate a new certificate using the OpenSSL command line tool as shown in the script
+`main/certs/gencert.sh`. It is **strongly recommended** to not reuse the example certificate in
+your application; it is included only for demonstration.
--- /dev/null
+set(COMPONENT_SRCS "main.c")
+set(COMPONENT_ADD_INCLUDEDIRS ".")
+
+set(COMPONENT_EMBED_TXTFILES
+ "certs/cacert.pem"
+ "certs/prvtkey.pem")
+
+register_component()
--- /dev/null
+menu "Example Configuration"
+
+config WIFI_SSID
+ string "WiFi SSID"
+ default "myssid"
+ help
+ SSID (network name) for the example to connect to.
+
+config WIFI_PASSWORD
+ string "WiFi Password"
+ default "mypassword"
+ help
+ WiFi password (WPA or WPA2) for the example to use.
+ Can be left blank if the network has no security set.
+
+endmenu
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIDKzCCAhOgAwIBAgIUBxM3WJf2bP12kAfqhmhhjZWv0ukwDQYJKoZIhvcNAQEL
+BQAwJTEjMCEGA1UEAwwaRVNQMzIgSFRUUFMgc2VydmVyIGV4YW1wbGUwHhcNMTgx
+MDE3MTEzMjU3WhcNMjgxMDE0MTEzMjU3WjAlMSMwIQYDVQQDDBpFU1AzMiBIVFRQ
+UyBzZXJ2ZXIgZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+ALBint6nP77RCQcmKgwPtTsGK0uClxg+LwKJ3WXuye3oqnnjqJCwMEneXzGdG09T
+sA0SyNPwrEgebLCH80an3gWU4pHDdqGHfJQa2jBL290e/5L5MB+6PTs2NKcojK/k
+qcZkn58MWXhDW1NpAnJtjVniK2Ksvr/YIYSbyD+JiEs0MGxEx+kOl9d7hRHJaIzd
+GF/vO2pl295v1qXekAlkgNMtYIVAjUy9CMpqaQBCQRL+BmPSJRkXBsYk8GPnieS4
+sUsp53DsNvCCtWDT6fd9D1v+BB6nDk/FCPKhtjYOwOAZlX4wWNSZpRNr5dfrxKsb
+jAn4PCuR2akdF4G8WLUeDWECAwEAAaNTMFEwHQYDVR0OBBYEFMnmdJKOEepXrHI/
+ivM6mVqJgAX8MB8GA1UdIwQYMBaAFMnmdJKOEepXrHI/ivM6mVqJgAX8MA8GA1Ud
+EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADiXIGEkSsN0SLSfCF1VNWO3
+emBurfOcDq4EGEaxRKAU0814VEmU87btIDx80+z5Dbf+GGHCPrY7odIkxGNn0DJY
+W1WcF+DOcbiWoUN6DTkAML0SMnp8aGj9ffx3x+qoggT+vGdWVVA4pgwqZT7Ybntx
+bkzcNFW0sqmCv4IN1t4w6L0A87ZwsNwVpre/j6uyBw7s8YoJHDLRFT6g7qgn0tcN
+ZufhNISvgWCVJQy/SZjNBHSpnIdCUSJAeTY2mkM4sGxY0Widk8LnjydxZUSxC3Nl
+hb6pnMh3jRq4h0+5CZielA4/a+TdrNPv/qok67ot/XJdY3qHCCd8O2b14OVq9jo=
+-----END CERTIFICATE-----
--- /dev/null
+#!/bin/bash
+
+# Example command to generate a new certificate in the correct format.
+# Expiry time and metadata fields can be adjusted in the invocation.
+
+# Please see the openssl man pages (man openssl-req) for more details
+
+openssl req -newkey rsa:2048 -nodes -keyout prvtkey.pem -x509 -days 3650 -out cacert.pem -subj "/CN=ESP32 HTTPS server example"
--- /dev/null
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCwYp7epz++0QkH
+JioMD7U7BitLgpcYPi8Cid1l7snt6Kp546iQsDBJ3l8xnRtPU7ANEsjT8KxIHmyw
+h/NGp94FlOKRw3ahh3yUGtowS9vdHv+S+TAfuj07NjSnKIyv5KnGZJ+fDFl4Q1tT
+aQJybY1Z4itirL6/2CGEm8g/iYhLNDBsRMfpDpfXe4URyWiM3Rhf7ztqZdveb9al
+3pAJZIDTLWCFQI1MvQjKamkAQkES/gZj0iUZFwbGJPBj54nkuLFLKedw7DbwgrVg
+0+n3fQ9b/gQepw5PxQjyobY2DsDgGZV+MFjUmaUTa+XX68SrG4wJ+DwrkdmpHReB
+vFi1Hg1hAgMBAAECggEAaTCnZkl/7qBjLexIryC/CBBJyaJ70W1kQ7NMYfniWwui
+f0aRxJgOdD81rjTvkINsPp+xPRQO6oOadjzdjImYEuQTqrJTEUnntbu924eh+2D9
+Mf2CAanj0mglRnscS9mmljZ0KzoGMX6Z/EhnuS40WiJTlWlH6MlQU/FDnwC6U34y
+JKy6/jGryfsx+kGU/NRvKSru6JYJWt5v7sOrymHWD62IT59h3blOiP8GMtYKeQlX
+49om9Mo1VTIFASY3lrxmexbY+6FG8YO+tfIe0tTAiGrkb9Pz6tYbaj9FjEWOv4Vc
++3VMBUVdGJjgqvE8fx+/+mHo4Rg69BUPfPSrpEg7sQKBgQDlL85G04VZgrNZgOx6
+pTlCCl/NkfNb1OYa0BELqWINoWaWQHnm6lX8YjrUjwRpBF5s7mFhguFjUjp/NW6D
+0EEg5BmO0ePJ3dLKSeOA7gMo7y7kAcD/YGToqAaGljkBI+IAWK5Su5yldrECTQKG
+YnMKyQ1MWUfCYEwHtPvFvE5aPwKBgQDFBWXekpxHIvt/B41Cl/TftAzE7/f58JjV
+MFo/JCh9TDcH6N5TMTRS1/iQrv5M6kJSSrHnq8pqDXOwfHLwxetpk9tr937VRzoL
+CuG1Ar7c1AO6ujNnAEmUVC2DppL/ck5mRPWK/kgLwZSaNcZf8sydRgphsW1ogJin
+7g0nGbFwXwKBgQCPoZY07Pr1TeP4g8OwWTu5F6dSvdU2CAbtZthH5q98u1n/cAj1
+noak1Srpa3foGMTUn9CHu+5kwHPIpUPNeAZZBpq91uxa5pnkDMp3UrLIRJ2uZyr8
+4PxcknEEh8DR5hsM/IbDcrCJQglM19ZtQeW3LKkY4BsIxjDf45ymH407IQKBgE/g
+Ul6cPfOxQRlNLH4VMVgInSyyxWx1mODFy7DRrgCuh5kTVh+QUVBM8x9lcwAn8V9/
+nQT55wR8E603pznqY/jX0xvAqZE6YVPcw4kpZcwNwL1RhEl8GliikBlRzUL3SsW3
+q30AfqEViHPE3XpE66PPo6Hb1ymJCVr77iUuC3wtAoGBAIBrOGunv1qZMfqmwAY2
+lxlzRgxgSiaev0lTNxDzZkmU/u3dgdTwJ5DDANqPwJc6b8SGYTp9rQ0mbgVHnhIB
+jcJQBQkTfq6Z0H6OoTVi7dPs3ibQJFrtkoyvYAbyk36quBmNRjVh6rc8468bhXYr
+v/t+MeGJP/0Zw8v/X2CFll96
+-----END PRIVATE KEY-----
--- /dev/null
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
+
+COMPONENT_EMBED_TXTFILES := certs/cacert.pem
+COMPONENT_EMBED_TXTFILES += certs/prvtkey.pem
--- /dev/null
+/* Simple HTTP + SSL Server Example
+
+ This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+ Unless required by applicable law or agreed to in writing, this
+ software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#include <esp_wifi.h>
+#include <esp_event_loop.h>
+#include <esp_log.h>
+#include <esp_system.h>
+#include <nvs_flash.h>
+#include <sys/param.h>
+
+#include <esp_https_server.h>
+
+/* A simple example that demonstrates how to create GET and POST
+ * handlers for the web server.
+ * The examples use simple WiFi configuration that you can set via
+ * 'make menuconfig'.
+ * If you'd rather not, just change the below entries to strings
+ * with the config you want -
+ * ie. #define EXAMPLE_WIFI_SSID "mywifissid"
+*/
+#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID
+#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD
+
+static const char *TAG="APP";
+
+
+/* An HTTP GET handler */
+esp_err_t root_get_handler(httpd_req_t *req)
+{
+ httpd_resp_set_type(req, "text/html");
+ httpd_resp_send(req, "<h1>Hello Secure World!</h1>", -1); // -1 = use strlen()
+
+ return ESP_OK;
+}
+
+const httpd_uri_t root = {
+ .uri = "/",
+ .method = HTTP_GET,
+ .handler = root_get_handler
+};
+
+
+httpd_handle_t start_webserver(void)
+{
+ httpd_handle_t server = NULL;
+
+ // Start the httpd server
+ ESP_LOGI(TAG, "Starting server");
+
+ httpd_ssl_config_t conf = HTTPD_SSL_CONFIG_DEFAULT();
+
+ extern const unsigned char cacert_pem_start[] asm("_binary_cacert_pem_start");
+ extern const unsigned char cacert_pem_end[] asm("_binary_cacert_pem_end");
+ conf.cacert_pem = cacert_pem_start;
+ conf.cacert_len = cacert_pem_end - cacert_pem_start;
+
+ extern const unsigned char prvtkey_pem_start[] asm("_binary_prvtkey_pem_start");
+ extern const unsigned char prvtkey_pem_end[] asm("_binary_prvtkey_pem_end");
+ conf.prvtkey_pem = prvtkey_pem_start;
+ conf.prvtkey_len = prvtkey_pem_end - prvtkey_pem_start;
+
+ esp_err_t ret = httpd_ssl_start(&server, &conf);
+ if (ESP_OK != ret) {
+ ESP_LOGI(TAG, "Error starting server!");
+ return NULL;
+ }
+
+ // Set URI handlers
+ ESP_LOGI(TAG, "Registering URI handlers");
+ httpd_register_uri_handler(server, &root);
+ return server;
+}
+
+void stop_webserver(httpd_handle_t server)
+{
+ // Stop the httpd server
+ httpd_ssl_stop(server);
+}
+
+
+
+
+// ------------------------- application boilerplate ------------------------
+
+static esp_err_t event_handler(void *ctx, system_event_t *event)
+{
+ httpd_handle_t *server = (httpd_handle_t *) ctx;
+
+ switch(event->event_id) {
+ case SYSTEM_EVENT_STA_START:
+ ESP_LOGI(TAG, "SYSTEM_EVENT_STA_START");
+ ESP_ERROR_CHECK(esp_wifi_connect());
+ break;
+ case SYSTEM_EVENT_STA_GOT_IP:
+ ESP_LOGI(TAG, "SYSTEM_EVENT_STA_GOT_IP");
+ ESP_LOGI(TAG, "Got IP: '%s'",
+ ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip));
+
+ /* Start the web server */
+ if (*server == NULL) {
+ *server = start_webserver();
+ }
+ break;
+ case SYSTEM_EVENT_STA_DISCONNECTED:
+ ESP_LOGI(TAG, "SYSTEM_EVENT_STA_DISCONNECTED");
+ ESP_ERROR_CHECK(esp_wifi_connect());
+
+ /* Stop the web server */
+ if (*server) {
+ stop_webserver(*server);
+ *server = NULL;
+ }
+ break;
+ default:
+ break;
+ }
+ return ESP_OK;
+}
+
+static void initialise_wifi(void *arg)
+{
+ tcpip_adapter_init();
+ ESP_ERROR_CHECK(esp_event_loop_init(event_handler, arg));
+ wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
+ ESP_ERROR_CHECK(esp_wifi_init(&cfg));
+ ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
+ wifi_config_t wifi_config = {
+ .sta = {
+ .ssid = EXAMPLE_WIFI_SSID,
+ .password = EXAMPLE_WIFI_PASS,
+ },
+ };
+ ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
+ ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
+ ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
+ ESP_ERROR_CHECK(esp_wifi_start());
+}
+
+void app_main()
+{
+ static httpd_handle_t server = NULL;
+ ESP_ERROR_CHECK(nvs_flash_init());
+ initialise_wifi(&server);
+}