-
Notifications
You must be signed in to change notification settings - Fork 125
/
Parameters.ino
354 lines (302 loc) · 14.3 KB
/
Parameters.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
/**
* Example for the ESP32 HTTP(S) Webserver
*
* IMPORTANT NOTE:
* To run this script, your need to
* 1) Enter your WiFi SSID and PSK below this comment
* 2) Make sure to have certificate data available. You will find a
* shell script and instructions to do so in the library folder
* under extras/
*
* This script will install an HTTPS Server on your ESP32 with the following
* functionalities:
* - Show page on web server root that will display some SVG smileys.
* Using a simple HTML form and GET parameters, you can change the colors
* of those images.
* - Provide the svg image with an optional GET parameter that allows to
* modify the background color, URL: /images/awesome.svg
* - Provide an example that shows how wildcard URL parameters get parsed
* URL: /urlparam/some/thing
* - 404 for everything else
*/
// TODO: Configure your WiFi here
#define WIFI_SSID "<your ssid goes here>"
#define WIFI_PSK "<your pre-shared key goes here>"
// Include certificate data (see note above)
#include "cert.h"
#include "private_key.h"
// We will use wifi
#include <WiFi.h>
// Includes for the server
#include <HTTPSServer.hpp>
#include <SSLCert.hpp>
#include <HTTPRequest.hpp>
#include <HTTPResponse.hpp>
// The HTTPS Server comes in a separate namespace. For easier use, include it here.
using namespace httpsserver;
// Create an SSL certificate object from the files included above
SSLCert cert = SSLCert(
example_crt_DER, example_crt_DER_len,
example_key_DER, example_key_DER_len
);
// Create an SSL-enabled server that uses the certificate
// The contstructor takes some more parameters, but we go for default values here.
HTTPSServer secureServer = HTTPSServer(&cert);
// We declare some handler functions (definition at the end of the file)
void handleRoot(HTTPRequest * req, HTTPResponse * res);
void handleSVG(HTTPRequest * req, HTTPResponse * res);
void handleQueryDemo(HTTPRequest * req, HTTPResponse * res);
void handlePathParam(HTTPRequest * req, HTTPResponse * res);
void handle404(HTTPRequest * req, HTTPResponse * res);
void setup() {
// For logging
Serial.begin(115200);
// Connect to WiFi
Serial.println("Setting up WiFi");
WiFi.begin(WIFI_SSID, WIFI_PSK);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.print("Connected. IP=");
Serial.println(WiFi.localIP());
// For every resource available on the server, we need to create a ResourceNode
// The ResourceNode links URL and HTTP method to a handler function
ResourceNode * nodeRoot = new ResourceNode("/", "GET", &handleRoot);
ResourceNode * nodeSVG = new ResourceNode("/images/awesome.svg", "GET", &handleSVG);
ResourceNode * nodeQueryDemo = new ResourceNode("/queryparams", "GET", &handleQueryDemo);
ResourceNode * node404 = new ResourceNode("", "GET", &handle404);
// Path parameters
// If you want (for example) to return a specific instance of an object type by its ID
// you can use URLs like /led/1, led/2, ... - And you do not need to register one Resource
// Node per ID, but you can use wildcards in the route definition. The following route
// has two wildcards, and will match for example to /urlparam/foo/bar, where "foo" and "bar"
// are accessible parameters in the handler function.
// Note: The wildcards can only be used between slashes at the moment (so /urlparam* would
// not work).
ResourceNode * nodeURLParam = new ResourceNode("/urlparam/*/*", "GET", &handlePathParam);
// Add the root node to the server
secureServer.registerNode(nodeRoot);
// Add the SVG image
secureServer.registerNode(nodeSVG);
// Query parameter demo
secureServer.registerNode(nodeQueryDemo);
// Add the path parameter
// Note: The order of nodes may become important here. If you have one node for "/led" (e.g. list of LEDs)
// and one node for /led/* (LED details), you should register the non-parameterized version first. The server
// follows a first-match policy. If you would register the details node first, a call to /led/ will be targetted
// at the details handler function with an empty parameter, which is probably not what you want.
secureServer.registerNode(nodeURLParam);
// Add the 404 not found node to the server.
// The path is ignored for the default node.
secureServer.setDefaultNode(node404);
Serial.println("Starting server...");
secureServer.start();
if (secureServer.isRunning()) {
Serial.println("Server ready.");
}
}
void loop() {
// This call will let the server do its work
secureServer.loop();
// Other code would go here...
delay(1);
}
void handleRoot(HTTPRequest * req, HTTPResponse * res) {
// We will deliver an HTML page
res->setHeader("Content-Type", "text/html");
// Write the response page
res->println("<!DOCTYPE html>");
res->println("<html>");
res->println("<head><title>Hello World!</title></head>");
res->println("<style>.info{font-style:italic}</style>");
res->println("<body>");
res->println("<h1>Query Parameters</h1>");
res->println("<p class=\"info\">The parameters after the question mark in your URL.</p>");
// Show a form to select a color to colorize the faces
// We pass the selection as get parameter "shades" to this very same page,
// so we can evaluate it below
res->println("<form method=\"GET\" action=\"/\">Show me faces in shades of ");
res->println("<select name=\"shades\">");
res->println("<option value=\"red\">red</option>");
res->println("<option value=\"green\">green</option>");
res->println("<option value=\"blue\">blue</option>");
res->println("<option value=\"yellow\">yellow</option>");
res->println("<option value=\"cyan\">cyan</option>");
res->println("<option value=\"magenta\">magenta</option>");
res->println("<option value=\"rainbow\">rainbow</option>");
res->println("</select>");
res->println("<button type=\"submit\">Go!</button>");
res->println("</form>");
// Get the params to check if the user did select something
ResourceParameters * params = req->getParams();
std::string paramName = "shades";
// Print 6 faces
for(int i = 0; i < 6; i++) {
// Include the image of the handleSVG function with a specific color code
res->print("<img style=\"height:100px;width:100px\" src=\"images/awesome.svg?color=");
// Depending on the selection we show the images in a specific color shade
// Default is dark gray.
int r = 63, g = 63, b = 63;
std::string paramVal;
if (params->getQueryParameter(paramName, paramVal)) {
if (paramVal == "red" || paramVal == "magenta" || paramVal == "yellow" || paramVal == "rainbow") {
r = 128 + random(0, 128);
}
if (paramVal == "green" || paramVal == "cyan" || paramVal == "yellow" || paramVal == "rainbow") {
g = 128 + random(0, 128);
}
if (paramVal == "blue" || paramVal == "magenta" || paramVal == "cyan" || paramVal == "rainbow") {
b = 128 + random(0, 128);
}
}
// Print the random color. As the HTTPResponse extends the Print interface, we can make use of that.
res->print(r, HEX);
res->print(g, HEX);
res->print(b, HEX);
res->print("\" alt=\"Awesome!\" />");
}
res->println("<p>You'll find another demo <a href=\"/queryparams?a=42&b&c=13&a=hello\">here</a>.</p>");
// Link to the path parameter demo
res->println("<h1>Path Parameters</h1>");
res->println("<p class=\"info\">The parameters derived from placeholders in your path, like /foo/bar.</p>");
res->println("<p>You'll find the demo <a href=\"/urlparam/foo/bar\">here</a>.</p>");
res->println("</body>");
res->println("</html>");
}
// This callback responds with an SVG image to a GET request. The icon is the "awesome face".
// (borrowed from https://commons.wikimedia.org/wiki/File:718smiley.svg)
//
// If the color query parameter is set (so the URL is like awesome.svg?color=fede58), the
// background of our awesome face is changed.
void handleSVG(HTTPRequest * req, HTTPResponse * res) {
// Get access to the parameters
ResourceParameters * params = req->getParams();
// Set SVG content type
res->setHeader("Content-Type", "image/svg+xml");
// Set a default color
std::string fillColor = "fede58";
// Get request parameter (like awesome.svg?color=ff0000) and validate it
std::string colorParamName = "color";
// Check that the parameter is set and retrieve it.
// The getQueryParameter function will modify the second parameter, but only if the query
// parameter is set.
std::string requestColor;
if (params->getQueryParameter(colorParamName, requestColor)) {
// Check for correct length
if (requestColor.length()==6) {
bool colorOk = true;
// Check that we only have characters within [0-9a-fA-F]
for(int i = 1; i < 6 && colorOk; i++) {
if (!(
(requestColor[i]>='0' && requestColor[i]<='9' ) ||
(requestColor[i]>='a' && requestColor[i]<='f' ) ||
(requestColor[i]>='A' && requestColor[i]<='F' )
)) {
colorOk = false;
}
}
// If validation was successful, replace the default color
if (colorOk) {
fillColor = requestColor;
}
}
}
// Print the SVG to the response:
res->print("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>");
res->print("<svg id=\"svg1923\" width=\"733\" xmlns=\"http://www.w3.org/2000/svg\" height=\"733\">");
res->print("<circle cy=\"366.5\" cx=\"366.5\" r=\"366.5\"/>");
res->print("<circle cy=\"366.5\" cx=\"366.5\" r=\"336.5\" fill=\"#");
// We insert the color from the parameter here
res->printStd(fillColor);
res->print("\"/>");
res->print("<path d=\"m325 665c-121-21-194-115-212-233v-8l-25-1-1-18h481c6 13 10 27 13 41 13 94-38 146-114 193-45 23-93 29-142 26z\"/>");
res->print("<path d=\"m372 647c52-6 98-28 138-62 28-25 46-56 51-87 4-20 1-57-5-70l-423-1c-2 56 39 118 74 157 31 34 72 54 116 63 11 2 38 2 49 0z\" fill=\"#871945\"/>");
res->print("<path d=\"m76 342c-13-26-13-57-9-85 6-27 18-52 35-68 21-20 50-23 77-18 15 4 28 12 39 23 18 17 30 40 36 67 4 20 4 41 0 60l-6 21z\"/>");
res->print("<path d=\"m234 323c5-6 6-40 2-58-3-16-4-16-10-10-14 14-38 14-52 0-15-18-12-41 6-55 3-3 5-5 5-6-1-4-22-8-34-7-42 4-57.6 40-66.2 77-3 17-1 53 4 59h145.2z\" fill=\"#fff\"/>");
res->print("<path d=\"m378 343c-2-3-6-20-7-29-5-28-1-57 11-83 15-30 41-52 72-60 29-7 57 0 82 15 26 17 45 49 50 82 2 12 2 33 0 45-1 10-5 26-8 30z\"/>");
res->print("<path d=\"m565 324c4-5 5-34 4-50-2-14-6-24-8-24-1 0-3 2-6 5-17 17-47 13-58-9-7-16-4-31 8-43 4-4 7-8 7-9 0 0-4-2-8-3-51-17-105 20-115 80-3 15 0 43 3 53z\" fill=\"#fff\"/>");
res->print("<path d=\"m504 590s-46 40-105 53c-66 15-114-7-114-7s14-76 93-95c76-18 126 49 126 49z\" fill=\"#f9bedd\"/>");
res->print("</svg>");
}
// This is a more generic demo for the query parameters. It makes use of the iterator
// interface to access them, which is useful if you do not know the paramter names in
// adavance.
void handleQueryDemo(HTTPRequest * req, HTTPResponse * res) {
// A word of warning: In this example, we use the query parameters and directly print
// them into the HTML output. We do this to simplify the demo. NEVER do this in a
// real application, as it allows cross-site-scripting.
res->setHeader("Content-Type", "text/html");
res->println("<!DOCTYPE html>");
res->println("<html>");
res->println("<head>");
res->println("<title>Query Parameter Demo</title>");
res->println("</head>");
res->println("<body>");
res->println("<p>The following query paramters have been set:</p>");
// Start a table to display the parameters
res->println("<table style=\"border:1px solid black collapse;\">");
res->println("<tr><th>Key</th><th>Value</th></tr>");
// Iterate over the parameters. For more information, read about the C++ standard template library,
// especially about vectors and iterators.
ResourceParameters *params = req->getParams();
for(auto it = params->beginQueryParameters(); it != params->endQueryParameters(); ++it) {
res->print("<tr><td>");
// The iterator yields std::pairs of std::strings. The first value contains the parameter key
res->printStd((*it).first);
res->print("</td><td>");
// and the second value contains the parameter value
res->printStd((*it).second);
res->println("</td></tr>");
}
res->println("</table>");
// You can retrieve the total parameter count from the parameters instance:
res->print("<p>There are a total of ");
res->print(params->getQueryParameterCount());
res->print(" parameters, with ");
res->print(params->getQueryParameterCount(true));
res->println(" unique keys.</p>");
res->println("<p>Go <a href=\"/\">back to main page</a>.</p>");
res->println("</body>");
res->println("</html>");
}
// This is a simple handler function that will show the content of URL parameters.
// If you call for example /urlparam/foo/bar, you will get the parameter values
// "foo" and "bar" provided by the ResourceParameters.
void handlePathParam(HTTPRequest * req, HTTPResponse * res) {
// Get access to the parameters
ResourceParameters * params = req->getParams();
// Set a simple content type
res->setHeader("Content-Type", "text/plain");
// The url pattern is: /urlparam/*/*
// This will make the content for the first parameter available on index 0,
// and the second wildcard as index 1.
// getPathParameter will - like getQueryParameter - write the value to the second parameter,
// and return true, if the index is valid. Otherwise it returns false and leaves the second
// parameter as it is.
std::string parameter1, parameter2;
// Print the first parameter value
if (params->getPathParameter(0, parameter1)) {
res->print("Parameter 1: ");
res->printStd(parameter1);
}
res->println();
// Print the second parameter value
if (params->getPathParameter(1, parameter2)) {
res->print("Parameter 2: ");
res->printStd(parameter2);
}
res->println("\n\nChange the parameters in the URL to see how they get parsed!");
}
// For details to this function, see the Static-Page example
void handle404(HTTPRequest * req, HTTPResponse * res) {
req->discardRequestBody();
res->setStatusCode(404);
res->setStatusText("Not Found");
res->setHeader("Content-Type", "text/html");
res->println("<!DOCTYPE html>");
res->println("<html>");
res->println("<head><title>Not Found</title></head>");
res->println("<body><h1>404 Not Found</h1><p>The requested resource was not found on this server.</p></body>");
res->println("</html>");
}