| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -36,6 +36,7 @@ You will find several examples showing how you can use the library: | |||
| 36 | 36 | - [Authentication](examples/Authentication/Authentication.ino): Implements a chain of two middleware functions to handle authentication and authorization using HTTP Basic Auth. | |
| 37 | 37 | - [Async-Server](examples/Async-Server/Async-Server.ino): 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. | |
| 38 | 38 | - [Websocket-Chat](examples/Websocket-Chat/Websocket-Chat.ino): Provides a browser-based chat built on top of websockets. **Note:** Websockets are still under development! | |
| 39 | + - [Parameter-Validation](examples/Parameter-Validation/Parameter-Validation.ino): Shows how you can integrate validator functions to do formal checks on parameters in your URL. | ||
| 39 | 40 | ||
| 40 | 41 | 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). | |
| 41 | 42 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,275 @@ | |||
| 1 | + #include <Arduino.h> | ||
| 2 | + /** | ||
| 3 | + * Example for the ESP32 HTTP(S) Webserver | ||
| 4 | + * | ||
| 5 | + * IMPORTANT NOTE: | ||
| 6 | + * To run this script, you need to | ||
| 7 | + * 1) Enter your WiFi SSID and PSK below this comment | ||
| 8 | + * 2) Make sure to have certificate data available. You will find a | ||
| 9 | + * shell script and instructions to do so in the library folder | ||
| 10 | + * under extras/ | ||
| 11 | + * | ||
| 12 | + * This script will install an HTTPS Server on your ESP32 with the following | ||
| 13 | + * functionalities: | ||
| 14 | + * - Shows you a page with some LEDs and allow you to turn them on or off | ||
| 15 | + * Parameters for the URLs are checked, so that you cannot address non-existing objects | ||
| 16 | + * - 404 for everything else | ||
| 17 | + * If you want to see the LEDs, connect them to GPIOs 33 (red), 25 (yellow), 26 (green) | ||
| 18 | + * and 27 (blue). | ||
| 19 | + */ | ||
| 20 | + | ||
| 21 | + // TODO: Configure your WiFi here | ||
| 22 | + #define WIFI_SSID "<your ssid goes here>" | ||
| 23 | + #define WIFI_PSK "<your pre-shared key goes here>" | ||
| 24 | + | ||
| 25 | + // Include certificate data (see note above) | ||
| 26 | + #include "cert.h" | ||
| 27 | + #include "private_key.h" | ||
| 28 | + | ||
| 29 | + // We will use wifi | ||
| 30 | + #include <WiFi.h> | ||
| 31 | + | ||
| 32 | + // We use strings | ||
| 33 | + #include <string> | ||
| 34 | + | ||
| 35 | + // Includes for the server | ||
| 36 | + #include <HTTPSServer.hpp> | ||
| 37 | + #include <SSLCert.hpp> | ||
| 38 | + #include <HTTPRequest.hpp> | ||
| 39 | + #include <HTTPResponse.hpp> | ||
| 40 | + #include <ValidatorFunctions.hpp> | ||
| 41 | + | ||
| 42 | + // The HTTPS Server comes in a separate namespace. For easier use, include it here. | ||
| 43 | + using namespace httpsserver; | ||
| 44 | + | ||
| 45 | + // Create an SSL certificate object from the files included above | ||
| 46 | + SSLCert cert = SSLCert( | ||
| 47 | + example_crt_DER, example_crt_DER_len, | ||
| 48 | + example_key_DER, example_key_DER_len | ||
| 49 | + ); | ||
| 50 | + | ||
| 51 | + // Create an SSL-enabled server that uses the certificate | ||
| 52 | + // The contstructor takes some more parameters, but we go for default values here. | ||
| 53 | + HTTPSServer secureServer = HTTPSServer(&cert); | ||
| 54 | + | ||
| 55 | + // Root node, will show the LEDs that are available | ||
| 56 | + void handleRoot(HTTPRequest * req, HTTPResponse * res); | ||
| 57 | + | ||
| 58 | + // Node to switch an LED on or off | ||
| 59 | + void handleSwitch(HTTPRequest * req, HTTPResponse * res); | ||
| 60 | + | ||
| 61 | + // Validation function for the LED ID and state, explanation follows below. | ||
| 62 | + bool validateLEDState(std::string s); | ||
| 63 | + bool validateLEDID(std::string s); | ||
| 64 | + | ||
| 65 | + // Default handler for resources that do not exist | ||
| 66 | + void handle404(HTTPRequest * req, HTTPResponse * res); | ||
| 67 | + | ||
| 68 | + // A class that defines an LED | ||
| 69 | + class LED { | ||
| 70 | + public: | ||
| 71 | + /** Name for the LED */ | ||
| 72 | + const std::string _name; | ||
| 73 | + /** Pin that it's connected to */ | ||
| 74 | + const uint8_t _pin; | ||
| 75 | + /** Current state */ | ||
| 76 | + bool _on; | ||
| 77 | + /** Constructor */ | ||
| 78 | + LED(const std::string name, uint8_t pin): _name(name), _pin(pin) { | ||
| 79 | + _on = false; | ||
| 80 | + pinMode(pin, OUTPUT); | ||
| 81 | + } | ||
| 82 | + /** Method to turn the led on or of */ | ||
| 83 | + void setOn(bool on) { | ||
| 84 | + digitalWrite(_pin,on?HIGH:LOW); | ||
| 85 | + _on=on; | ||
| 86 | + } | ||
| 87 | + }; | ||
| 88 | + | ||
| 89 | + // We create some LEDs: | ||
| 90 | + #define LEDCOUNT 4 | ||
| 91 | + LED myLEDs[LEDCOUNT] = { | ||
| 92 | + LED("Red LED", 33), | ||
| 93 | + LED("Yellow LED", 25), | ||
| 94 | + LED("Green LED", 26), | ||
| 95 | + LED("Blue LED", 27) | ||
| 96 | + }; | ||
| 97 | + | ||
| 98 | + void setup() { | ||
| 99 | + // For logging | ||
| 100 | + Serial.begin(115200); | ||
| 101 | + | ||
| 102 | + // Connect to WiFi | ||
| 103 | + Serial.println("Setting up WiFi"); | ||
| 104 | + WiFi.begin(WIFI_SSID, WIFI_PSK); | ||
| 105 | + while (WiFi.status() != WL_CONNECTED) { | ||
| 106 | + Serial.print("."); | ||
| 107 | + delay(500); | ||
| 108 | + } | ||
| 109 | + Serial.print("Connected. IP="); | ||
| 110 | + Serial.println(WiFi.localIP()); | ||
| 111 | + | ||
| 112 | + // We create a node for the main page of the server, available via get | ||
| 113 | + ResourceNode * nodeRoot = new ResourceNode("/", "GET", &handleRoot); | ||
| 114 | + | ||
| 115 | + // This node will turn an LED on or of. It has two parameters: | ||
| 116 | + // 1) The ID of the LED (0..LEDCOUNT) | ||
| 117 | + // 2) The new state (0..1) | ||
| 118 | + // For more information on URL parameters in general, see the Parameters example. | ||
| 119 | + ResourceNode * nodeSwitch = new ResourceNode("/led/*/*", "POST", &handleSwitch); | ||
| 120 | + | ||
| 121 | + // We want to use parameter validation. The ResourceNode class provides the method | ||
| 122 | + // addURLParamValidator() for that. This method takes two parameters: | ||
| 123 | + // 1) The index of the parameter that you want to validate, so for the first wildcard | ||
| 124 | + // in the URL pattern that has been specified above, it's 0, and for the second | ||
| 125 | + // parameter it's 1. | ||
| 126 | + // 2) A function pointer that takes an std::string as parameter and returns a bool. | ||
| 127 | + // That bool should be true if the parameter is considered valid. | ||
| 128 | + // All those functions are called in the order in that they have been added. So if | ||
| 129 | + // you want check if a parameter is an integer and then do some calculation with it, | ||
| 130 | + // make sure to add the integer-check first and the other function later. | ||
| 131 | + // | ||
| 132 | + // If any of the functions returns false, the URL is considered to be invalid completely. | ||
| 133 | + // In this case, the server will return with a static 400 Bad Request response. | ||
| 134 | + // | ||
| 135 | + // For convenience, the ValidatorFunctions.hpp include file already provides some useful | ||
| 136 | + // and common checks (integer, non-empty, ...). Have a look at it before you start | ||
| 137 | + // implementing your own checks to save time! | ||
| 138 | + | ||
| 139 | + // First we will take care of the LED ID. This ID should be... | ||
| 140 | + // ... an unsigned integer ... | ||
| 141 | + nodeSwitch->addURLParamValidator(0, &validateUnsignedInteger); | ||
| 142 | + // ... and within the range of known IDs. | ||
| 143 | + // We can treat the parameter safely as integer in this validator, as all validators | ||
| 144 | + // are executed in order and validateUnsignedInteger has been run before. | ||
| 145 | + nodeSwitch->addURLParamValidator(0, &validateLEDID); | ||
| 146 | + | ||
| 147 | + // The second parameter should either be 0 or 1. We use our custom validateLEDState() validator for this: | ||
| 148 | + nodeSwitch->addURLParamValidator(1, &validateLEDState); | ||
| 149 | + | ||
| 150 | + // Not found node | ||
| 151 | + ResourceNode * node404 = new ResourceNode("", "GET", &handle404); | ||
| 152 | + | ||
| 153 | + // Add the root node to the server | ||
| 154 | + secureServer.registerNode(nodeRoot); | ||
| 155 | + // And the switch node | ||
| 156 | + secureServer.registerNode(nodeSwitch); | ||
| 157 | + | ||
| 158 | + // Add the 404 not found node to the server. | ||
| 159 | + // The path is ignored for the default node. | ||
| 160 | + secureServer.setDefaultNode(node404); | ||
| 161 | + | ||
| 162 | + Serial.println("Starting server..."); | ||
| 163 | + secureServer.start(); | ||
| 164 | + if (secureServer.isRunning()) { | ||
| 165 | + Serial.println("Server ready."); | ||
| 166 | + } | ||
| 167 | + } | ||
| 168 | + | ||
| 169 | + void loop() { | ||
| 170 | + // This call will let the server do its work | ||
| 171 | + secureServer.loop(); | ||
| 172 | + | ||
| 173 | + // Other code would go here... | ||
| 174 | + delay(1); | ||
| 175 | + } | ||
| 176 | + | ||
| 177 | + void handleRoot(HTTPRequest * req, HTTPResponse * res) { | ||
| 178 | + // We will deliver an HTML page | ||
| 179 | + res->setHeader("Content-Type", "text/html"); | ||
| 180 | + | ||
| 181 | + // Write the response page | ||
| 182 | + res->println("<!DOCTYPE html>"); | ||
| 183 | + res->println("<html><head><style>"); | ||
| 184 | + res->println("* {font-family: sans-serif; font-size:12px}"); | ||
| 185 | + res->println("form.on {background: #ffffcc;color:black;}"); | ||
| 186 | + res->println("form.off {background: #404040;color:white;}"); | ||
| 187 | + res->println("</style><title>Parameter Validation Example</title></head>"); | ||
| 188 | + res->println("<body>"); | ||
| 189 | + | ||
| 190 | + // Iterate over the LEDs. | ||
| 191 | + for(int id = 0; id < LEDCOUNT; id++) { | ||
| 192 | + LED * led = &myLEDs[id]; | ||
| 193 | + res->print( | ||
| 194 | + "<form " | ||
| 195 | + "style=\"border:1px solid black;padding:10px;width:300px;margin:10px;float:left\" " | ||
| 196 | + "method=\"post\" " | ||
| 197 | + "class=\""); | ||
| 198 | + res->print(led->_on ? "on" : "off"); | ||
| 199 | + res->print( | ||
| 200 | + "\" " | ||
| 201 | + "action=\"/led/" | ||
| 202 | + ); | ||
| 203 | + res->print(id); | ||
| 204 | + res->print("/"); | ||
| 205 | + res->print(led->_on ? 0 : 1); | ||
| 206 | + res->print( | ||
| 207 | + "\">" | ||
| 208 | + "<p style=\"text-align:center;font-size:16px;\">" | ||
| 209 | + ); | ||
| 210 | + res->printStd(led->_name); | ||
| 211 | + res->print("</p><button type=\"submit\">Turn "); | ||
| 212 | + res->print(led->_on ? "off" : "on"); | ||
| 213 | + res->print("</button></form>"); | ||
| 214 | + } | ||
| 215 | + | ||
| 216 | + res->print( | ||
| 217 | + "<form method=\"post\" action=\"/led/foobar/1\" style=\"clear:both\">" | ||
| 218 | + "<p>To see that the validator functions are working as expected, you can e.g. call <button type=\"submit\">POST /led/foobar/1</button>.</p>" | ||
| 219 | + "</form>" | ||
| 220 | + "</body>" | ||
| 221 | + "</html>" | ||
| 222 | + ); | ||
| 223 | + } | ||
| 224 | + | ||
| 225 | + // This is the handler for our post callback. We can work with the parameters without further | ||
| 226 | + // validation, as the server assures this function only gets called if the validation succeeded. | ||
| 227 | + void handleSwitch(HTTPRequest * req, HTTPResponse * res) { | ||
| 228 | + // POST, so drain the input, if any | ||
| 229 | + req->discardRequestBody(); | ||
| 230 | + | ||
| 231 | + // Get access to the parameters | ||
| 232 | + ResourceParameters * params = req->getParams(); | ||
| 233 | + | ||
| 234 | + // Get the LED that is requested. | ||
| 235 | + // Note that we can use the parameter directly without further validation, as we | ||
| 236 | + // defined that is has to be an unsigned integer and must not be >LEDCOUNT-1 | ||
| 237 | + LED * led = &myLEDs[params->getUrlParameterInt(0)]; | ||
| 238 | + | ||
| 239 | + // Set the state of the LED. The value of the parameter can only be "0" or "1" here, | ||
| 240 | + // otherwise the server would not have called the handler. | ||
| 241 | + led->setOn(params->getUrlParameter(1)!="0"); | ||
| 242 | + | ||
| 243 | + // Redirect the user to the main page | ||
| 244 | + res->setStatusCode(303); | ||
| 245 | + // This should make the browser do a GET / | ||
| 246 | + res->setStatusText("See Other"); | ||
| 247 | + res->setHeader("Location", "/"); | ||
| 248 | + res->println("Redirecting..."); | ||
| 249 | + } | ||
| 250 | + | ||
| 251 | + // This function is the validator for the second parameter of the POST /led route. | ||
| 252 | + // It accepts only the strings "0" (off) and "1" (on) | ||
| 253 | + bool validateLEDState(std::string s) { | ||
| 254 | + return s == "0" || s == "1"; | ||
| 255 | + } | ||
| 256 | + | ||
| 257 | + // This function is a validator for the first parameter of the POST /led route. | ||
| 258 | + // We did check before that the parameter is an integer, now we check its range. | ||
| 259 | + bool validateLEDID(std::string s) { | ||
| 260 | + uint32_t id = parseUInt(s); | ||
| 261 | + return id < LEDCOUNT; | ||
| 262 | + } | ||
| 263 | + | ||
| 264 | + // For details to this function, see the Static-Page example | ||
| 265 | + void handle404(HTTPRequest * req, HTTPResponse * res) { | ||
| 266 | + req->discardRequestBody(); | ||
| 267 | + res->setStatusCode(404); | ||
| 268 | + res->setStatusText("Not Found"); | ||
| 269 | + res->setHeader("Content-Type", "text/html"); | ||
| 270 | + res->println("<!DOCTYPE html>"); | ||
| 271 | + res->println("<html>"); | ||
| 272 | + res->println("<head><title>Not Found</title></head>"); | ||
| 273 | + res->println("<body><h1>404 Not Found</h1><p>The requested resource was not found on this server.</p></body>"); | ||
| 274 | + res->println("</html>"); | ||
| 275 | + } | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments