TLS-enabled web server for the ESP32 using the Arduino core.
Switch branches/tags
Nothing to show
Clone or download

README.md

ESP32 HTTPS Server

This repository contains an HTTPS server library that can be used with the ESP32 Arduino Core. It supports HTTP as well.

Features

  • Make use of the built-in encryption of the ESP32 module
  • Handle multiple clients in parallel (max 3-4 SSL clients due to memory limits)
  • Usage of Connection: keep-alive and SSL Session reuse to reduce the overhead of SSL handshakes and speed up data transfer
  • Abstraction of handling the HTTP stuff and providing a simple API for it, eg. to access parameters, headers, HTTP Basic Auth etc.
  • Handling requests in callback functions that can be bound to URLs
  • Using middleware functions as proxy to every request to perform central tasks like authentication or logging
  • Providing support for HTTP, HTTPS or both at the same time

Dependencies

The library is self-contained and just needs the Arduino and ESP32 system libraries. Running the examples requires the WiFi library in addition to that.

Setup Instructions

Clone or download the content of this git repository into your Arduino/libraries folder and restart you IDE.

To run the examples, you need to execute the script extras/create_cert.sh first. This script will create a simple CA to sign certificates that are used with the examples. Some notes on the usage can be found in the extras/README.md file.

You then should be able to add the library to your project if you selected the ESP32 as architecture.

Examples

You will find several examples showing how you can use the library:

  • Static-Page: Short example showing how to serve some static resources with the server. You should start with this sketch and get familiar with it before having a look at the more complex examples.
  • Parameters: Shows how you can access request parameters (the part after the question mark in the URL) or parameters in dynamic URLs (like /led/1, /led/2, ...)
  • Put-Post-Echo: Implements a simple echo service for PUT and POST requests that returns the request body as response body. Also shows how to differentiate between multiple HTTP methods for the same URL.
  • HTTPS-and-HTTP: Shows how to serve resources via HTTP and HTTPS in parallel and how to check if the user is using a secure connection during request handling
  • Middleware: Shows how to use the middleware API for logging. Middleware functions are defined very similar to webservers like Express.
  • Authentication: Implements a chain of two middleware functions to handle authentication and authorization using HTTP Basic Auth.
  • Async-Server: Like the Static-Page example, but the server runs in a separate task on the ESP32, so you do not need to call the loop() function in your main sketch.
  • Websocket-Chat: Provides a browser-based chat built on top of websockets. Note: Websockets are still under development!
  • Parameter-Validation: Shows how you can integrate validator functions to do formal checks on parameters in your URL.

If you encounter error messages that cert.h or private_key.h are missing when running an example, make sure to run create_cert.sh first (see Setup Instructions).

Get Started

The following includes are required to be able to setup the server.

// Inlcudes for setting up the server
#include <HTTPSServer.hpp>

// Define the certificate data for the server (Certificate and private key)
#include <SSLCert.hpp>

// Includes to define request handler callbacks
#include <HTTPRequest.hpp>
#include <HTTPResponse.hpp>

// Required do define ResourceNodes
#include <ResourceNode.hpp>

// Easier access to the classes of the server
using namespace httpsserver

Create Server Instance

Then, you can create the server like this:

// Create certificate data (see extras/README.md on how to create it)
SSLCert cert = SSLCert(
    crt_DER,     // DER-formatted certificate data
    crt_DER_len, // length of the certificate data
    key_DER,     // private key for that certificate
    key_DER_len  // Length of the private key
);

// Setup the server with default configuration and the
// certificate that has been specified before
HTTPSServer myServer = HTTPSServer(cert);

By default, the server will listen on port 443. If you want to change that (or some other options), you can have a look at the optional parameters of the HTTPSServer constructor.

If you want to have just an HTTP server, you can skip the SSLCert part and replace HTTPSServer by HTTPServer. Everything else is the same for both protocols.

Add Resources to the Server

Every URL that should be accessible on the server has to be configured as a so-called ResourceNode. Such a node links a handler function to a specific URL and HTTP method. The handler function could look like this:

void handleRoot(HTTPRequest * req, HTTPResponse * res) {
	// We want to deliver an HTML page, so we set the content type
	res->setHeader("Content-Type", "text/html");
	// The response implements the Print interface, so you can use it just like
	// you would write to Serial etc.
	res->println("<!DOCTYPE html>");
	res->println("<html>");
	res->println("<head><title>Hello World!</title></head>");
	res->println("<body>");
	res->println("<h1>Hello World!</h1>");
	res->print("<p>... from your ESP32!</p>");
	res->println("</body>");
	res->println("</html>");
}

As you can see, the function gets references to the HTTP request and response. You can use the request to read headers, parameters, authentication information etc. The response can be used to send data to the client, set headers or HTTP status codes.

Now we need to tell the server which URL should be served by this function. This can be done by creating a ResourceNode (usually in your setup() function).

ResourceNode * nodeRoot = new ResourceNode("/", "GET", &handleRoot);

The first parameter defines the URL. It should always start with a slash, and using just a slash like here means that the function will be called for requests to the server's root (like https:/10.0.x.x/).

The second parameter is the HTTP method, "GET" in this case.

Finally, you pass a reference to the request handler function to link it to the URL and method.

Now you just need to register the created ResourceNode at your server:

myServer.registerNode(nodeRoot);

That's everything you need to do for a single web page on your server.

Note that you can define a single ResourceNode via HTTPServer::setDefaultNode(), which will be called if no other node on the server matches. Method and Path are ignored in this case. All examples use this to define a 404-handler, which might be a good idea for most scenarios.

Start the Server

A call to HTTPServer::start() will start the server so that it is listening on the port specified:

myServer.start();

This code usually goes into your setup() function. You can use HTTPServer::isRunning() to check whether the server started successfully.

By default, you need to pass control to the server explicitly. This is done by calling the HTTPServer::loop() function, which you usually will put into your Arduino sketch's loop() function. Once called, the server will first check for incoming connection (up to the maximum connection count that has been defined in the constructor), and then handle every open connection if it has new data on the socket. So your request handler functions will be called during the call to loop(). Note that if one of your handler functions is blocking, it will block all other connections as well.

Running the Server asynchronously

If you want to have the server running in the background (and not calling loop() by yourself every few milliseconds), you can make use of the ESP32's task feature and put the whole server in a separate task.

See the Async-Server example to see how this can be done.