ESP32 HTTPS server: Handling multiple routes

In this tutorial we will check how to handle multiple routes in a HTTPS server, using the ESP32 and the Arduino core. The tests shown on this tutorial were performed using an ESP32 board from DFRobot.

Introduction

In this tutorial we will check how to handle multiple routes in a HTTPS server, using the ESP32 and the Arduino core.

We are going to use this library, which you can install in your Arduino environment by following these instructions.

We have already covered the basics about how to setup a HTTPS server with the mentioned library on this previous post. Nonetheless, in that introductory example, we have just setup a single route. In this post we are going to check a slightly more complex use case, where our server will have 3 routes.

Like we did on the mentioned previous post, we are going to use a self signed certificate, generated on the fly by the ESP32. Naturally, this should only be used for testing purposes.

The tests shown on this tutorial were performed using an ESP32 board from DFRobot.

The code

As usual, we start our code by including all the needed libraries. We will need the WiFi.h library, for connecting the ESP32 to a WiFi network, and 4 additional includes for setting up the HTTPS server. You can check here in more detail the header and implementation files for the HTTPS related functionalities.

#include <WiFi.h>
#include <HTTPSServer.hpp>
#include <SSLCert.hpp>
#include <HTTPRequest.hpp>
#include <HTTPResponse.hpp>

Additionally, we will declare the use of the httpsserver namespace.

using namespace httpsserver;

Since we are going to connect the ESP32 to a WiFi network, we will also need to declare the credentials of that network. More precisely, we will need the network name and password. You should replace the placeholders below with the actual credentials of your network.

const char* ssid = "yourNetworkName";
const char* password =  "yourNetworkPassword";

Then, we will need a pointer to an object of class SSLCert. This object will store the information of our server certificate.

SSLCert * cert;

We will also need a pointer to an object of class HTTPSServer, which we will use to configure the routes of our HTTPS server.

HTTPSServer * secureServer;

Moving on to the Arduino setup function, we will start by opening a serial connection, so we can output some information from our program.

Serial.begin(115200);

After that, we will generate the self signed certificate that we will use in our server. Naturally, when we later test the code, the browser that will contact the server will complain about security issues since the certificate is self signed and not issued by a trusted certification authority.

You can read more details about the certificate generation procedure on the previous tutorial.

cert = new SSLCert();
 
int createCertResult = createSelfSignedCert(
    *cert,
    KEYSIZE_2048,
    "CN=myesp.local,O=acme,C=US");
   
if (createCertResult != 0) {
    Serial.printf("Error generating certificate");
    return; 
}

After the certificate generation, we will handle the connection of the ESP32 to the WiFi network. Recall that we have previously declared the network’s credentials (name and password) as global variables.

Note that we are printing the local IP assigned to the ESP32 after the connection is established, since it needs to be known by the client that will contact the server.

WiFi.begin(ssid, password);
  
while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
}  
  
Serial.println(WiFi.localIP());

Next we will create an instance of the HTTPSServer class. As input, the constructor will receive the SSLCert object pointer. Recall that this SSLCert object holds the information about our self signed certificate.

secureServer = new HTTPSServer(cert);

Now we will take care of configuring the server routes. Recall from the previous tutorial that, on this library, each route should be specified as a ResourceNode.

The constructor of this class receives as first input the name of the route, as second input the HTTP method allowed on that route, and as third input the route handling function.

The route handling function should follow a pre-defined signature: it returns void and receives as input a pointer to an object of class HTTPRequest and a pointer to an object of class HTTPResponse.

To keep the code shorter we will make use of the C++ lambda function syntax to specify the route handling functions.

So, as stated in the introductory section, we will have 3 route handling functions. They will have the following names:

  • /route1
  • /route2
  • /route3

The 3 routes will only listen to HTTP GET requests and they will return as output a simple message indicating their index.

ResourceNode * nodeRoute1 = new ResourceNode("/route1", "GET", [](HTTPRequest * req, HTTPResponse * res){
    res->println("Route 1");
});

ResourceNode * nodeRoute2 = new ResourceNode("/route2", "GET", [](HTTPRequest * req, HTTPResponse * res){
    res->println("Route 2");
});

ResourceNode * nodeRoute3 = new ResourceNode("/route3", "GET", [](HTTPRequest * req, HTTPResponse * res){
    res->println("Route 3");
});

After creating the resource nodes for each route, we still need to register them. To do it, we simply need to call the registerNode method on the server object, passing as input the pointers to the ResourceNode objects we have just created.

secureServer->registerNode(nodeRoute1);
secureServer->registerNode(nodeRoute2);
secureServer->registerNode(nodeRoute3);

To start the server, we need to call the start method on our server object. After that, we will call the isRunning method to confirm the server was indeed started.

secureServer->start();
   
if (secureServer->isRunning()) {
    Serial.println("Server ready.");
}else{
    Serial.println("Server could not be started.");
}

To finalize the code, we need to periodically call the loop method on our server object, to handle incoming client connections.

void loop() {
  
  secureServer->loop();  
  delay(10);
}

The final source code can be seen below.

#include <WiFi.h>
#include <HTTPSServer.hpp>
#include <SSLCert.hpp>
#include <HTTPRequest.hpp>
#include <HTTPResponse.hpp>
 
using namespace httpsserver;
 
const char* ssid = "yourNetworkName";
const char* password =  "yourNetworkPassword";

SSLCert * cert;
HTTPSServer * secureServer;
 
void setup() {
 
  Serial.begin(115200);


  //----Generating the certificate----
  Serial.println("Creating certificate...");
   
  cert = new SSLCert();
 
  int createCertResult = createSelfSignedCert(
    *cert,
    KEYSIZE_2048,
    "CN=myesp.local,O=acme,C=US");
   
  if (createCertResult != 0) {
    Serial.printf("Error generating certificate");
    return; 
  }
 
  Serial.println("Certificate created with success");


  //----Connect to WiFi----
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }  
  
  Serial.println(WiFi.localIP());


  //----Configure server----
  secureServer = new HTTPSServer(cert);
 
  ResourceNode * nodeRoute1 = new ResourceNode("/route1", "GET", [](HTTPRequest * req, HTTPResponse * res){
    res->println("Route 1");
  });

  ResourceNode * nodeRoute2 = new ResourceNode("/route2", "GET", [](HTTPRequest * req, HTTPResponse * res){
    res->println("Route 2");
  });

  ResourceNode * nodeRoute3 = new ResourceNode("/route3", "GET", [](HTTPRequest * req, HTTPResponse * res){
    res->println("Route 3");
  });
 
  secureServer->registerNode(nodeRoute1);
  secureServer->registerNode(nodeRoute2);
  secureServer->registerNode(nodeRoute3);
 
 
  secureServer->start();
   
  if (secureServer->isRunning()) {
    Serial.println("Server ready.");
  }else{
    Serial.println("Server could not be started.");
  }
}
 
void loop() {
  
  secureServer->loop();  
  delay(10);
}

Testing the code

To test the previous code, simply compile it and upload it to your ESP32, using the Arduino IDE. Once the procedure finishes, open the IDE serial monitor.

The self signed certificate generation will take a while. After that, the WiFi connection procedure should start. When it finishes, it should print an IP address. Copy it.

Then, open a web browser of your choice and type the following, changing #yourDeviceIp# by the IP you have just copied, and #route# by one of the route names we have defined in the Arduino code:

https://#yourDeviceIp#/#route#

Note that, as already mentioned, your browser should complain about some security issues, due to the fact that we are using a self signed certificate. You should choose to proceed.

Figure 1 shows the expected result for the route named “/route3“. The others will have a similar result, except for the message returned.

Note that even though the connection is marked as insecure due to the certificate not being issues by a trusted Certificate Authority, it is also indicated that the connection is encrypted and the resources are being served securely, as expected when using HTTPS.

Making HTTPS request to a server hosted by the ESP32, using Google Chrome.
Figure 1 – Accessing route 3 of the HTTPS server hosted by the ESP32.

Related Posts

Leave a Reply