Webserver controller with url trimming for value controls

Dependencies:   LCD_DISCO_F746NG BSP_DISCO_F746NG

Committer:
hudakz
Date:
Mon Jul 01 17:23:49 2019 +0000
Revision:
9:161bed13b17e
Parent:
8:47b0cb4b5b7d
Child:
10:f941e0750773
Tiny web server controlling a DigitalOut.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
hudakz 0:e455fdb56bc8 1 #include "mbed.h"
hudakz 0:e455fdb56bc8 2 #include "EthernetInterface.h"
hudakz 0:e455fdb56bc8 3 #include "TCPSocket.h"
hudakz 0:e455fdb56bc8 4 #include <stdio.h>
hudakz 0:e455fdb56bc8 5 #include <string>
hudakz 9:161bed13b17e 6
hudakz 9:161bed13b17e 7 using namespace std;
hudakz 9:161bed13b17e 8
hudakz 9:161bed13b17e 9 #define IP "192.168.1.181"
hudakz 9:161bed13b17e 10 #define GATEWAY "192.168.1.1"
hudakz 9:161bed13b17e 11 #define NETMASK "255.255.255.0"
hudakz 9:161bed13b17e 12 #define PORT 80
hudakz 9:161bed13b17e 13
hudakz 9:161bed13b17e 14 Serial pc(USBTX, USBRX);
hudakz 8:47b0cb4b5b7d 15 EthernetInterface* net;
hudakz 9:161bed13b17e 16 TCPSocket server;
hudakz 9:161bed13b17e 17 TCPSocket* clientSocket;
hudakz 0:e455fdb56bc8 18 SocketAddress clientAddress;
hudakz 9:161bed13b17e 19 char receiveBuf[1024];
hudakz 0:e455fdb56bc8 20 const int OFF = 0;
hudakz 0:e455fdb56bc8 21 const int ON = 1;
hudakz 9:161bed13b17e 22 DigitalOut sw(LED1); // A digital output to be switched on/off
hudakz 9:161bed13b17e 23 float roomTemp = 21.8; // A temperature sensor output
hudakz 9:161bed13b17e 24 const string PASSWORD = "secret"; // Change as you like
hudakz 9:161bed13b17e 25 const string HTTP_OK = "HTTP/1.0 200 OK";
hudakz 9:161bed13b17e 26 const string MOVED_PERM = "HTTP/1.0 301 Moved Permanently\r\nLocation: ";
hudakz 0:e455fdb56bc8 27 const string UNAUTHORIZED = "HTTP/1.0 401 Unauthorized";
hudakz 9:161bed13b17e 28 string httpHeader; // HTTP header
hudakz 9:161bed13b17e 29 string httpContent; // HTTP content
hudakz 9:161bed13b17e 30
hudakz 2:33e8bb5615a6 31 /**
hudakz 2:33e8bb5615a6 32 * @brief Analyses the received URL
hudakz 2:33e8bb5615a6 33 * @note The string passed to this function will look like this:
hudakz 9:161bed13b17e 34 * GET /HTTP/1.....
hudakz 2:33e8bb5615a6 35 * GET /password HTTP/1.....
hudakz 2:33e8bb5615a6 36 * GET /password/ HTTP/1.....
hudakz 2:33e8bb5615a6 37 * GET /password/?sw=1 HTTP/1.....
hudakz 2:33e8bb5615a6 38 * GET /password/?sw=0 HTTP/1.....
hudakz 2:33e8bb5615a6 39 * @param url URL string
hudakz 9:161bed13b17e 40 * @retval -3 just refresh page
hudakz 2:33e8bb5615a6 41 * -2 no command given but password valid
hudakz 9:161bed13b17e 42 * -1 invalid password
hudakz 2:33e8bb5615a6 43 * 0 switch off
hudakz 2:33e8bb5615a6 44 * 1 switch on
hudakz 2:33e8bb5615a6 45 */
hudakz 9:161bed13b17e 46 int8_t analyseURL(string& url)
hudakz 9:161bed13b17e 47 {
hudakz 9:161bed13b17e 48 if (url.length() < 5 + PASSWORD.size() + 1)
hudakz 9:161bed13b17e 49 return(-1);
hudakz 9:161bed13b17e 50
hudakz 9:161bed13b17e 51 if (url.substr(5, PASSWORD.size()) != PASSWORD)
hudakz 0:e455fdb56bc8 52 return(-1);
hudakz 9:161bed13b17e 53
hudakz 0:e455fdb56bc8 54 uint8_t pos = 5 + PASSWORD.size();
hudakz 9:161bed13b17e 55
hudakz 9:161bed13b17e 56 if (url.substr(pos, 1) != "/")
hudakz 9:161bed13b17e 57 return(-1);
hudakz 9:161bed13b17e 58
hudakz 9:161bed13b17e 59 if (url.substr(pos++, 1) == " ")
hudakz 0:e455fdb56bc8 60 return(-2);
hudakz 9:161bed13b17e 61
hudakz 2:33e8bb5615a6 62 string cmd(url.substr(pos, 5));
hudakz 9:161bed13b17e 63
hudakz 9:161bed13b17e 64 if (cmd == "?sw=0")
hudakz 2:33e8bb5615a6 65 return(0);
hudakz 9:161bed13b17e 66
hudakz 9:161bed13b17e 67 if (cmd == "?sw=1")
hudakz 2:33e8bb5615a6 68 return(1);
hudakz 9:161bed13b17e 69
hudakz 0:e455fdb56bc8 70 return(-3);
hudakz 0:e455fdb56bc8 71 }
hudakz 9:161bed13b17e 72
hudakz 0:e455fdb56bc8 73 /**
hudakz 0:e455fdb56bc8 74 * @brief
hudakz 0:e455fdb56bc8 75 * @note
hudakz 0:e455fdb56bc8 76 * @param
hudakz 0:e455fdb56bc8 77 * @retval
hudakz 0:e455fdb56bc8 78 */
hudakz 9:161bed13b17e 79 string& movedPermanently(uint8_t flag)
hudakz 9:161bed13b17e 80 {
hudakz 9:161bed13b17e 81 if (flag == 1)
hudakz 0:e455fdb56bc8 82 httpContent = "/" + PASSWORD + "/";
hudakz 0:e455fdb56bc8 83 else
hudakz 0:e455fdb56bc8 84 httpContent = "";
hudakz 9:161bed13b17e 85
hudakz 0:e455fdb56bc8 86 httpContent += "<h1>301 Moved Permanently</h1>\r\n";
hudakz 9:161bed13b17e 87
hudakz 0:e455fdb56bc8 88 return(httpContent);
hudakz 0:e455fdb56bc8 89 }
hudakz 9:161bed13b17e 90
hudakz 0:e455fdb56bc8 91 /**
hudakz 0:e455fdb56bc8 92 * @brief
hudakz 0:e455fdb56bc8 93 * @note
hudakz 0:e455fdb56bc8 94 * @param
hudakz 0:e455fdb56bc8 95 * @retval
hudakz 0:e455fdb56bc8 96 */
hudakz 9:161bed13b17e 97 string& showWebPage(int status)
hudakz 9:161bed13b17e 98 {
hudakz 9:161bed13b17e 99 char roomTempStr[5];
hudakz 9:161bed13b17e 100
hudakz 2:33e8bb5615a6 101 //roomTemp = ds1820.read();
hudakz 2:33e8bb5615a6 102 sprintf(roomTempStr, "%3.1f", roomTemp);
hudakz 9:161bed13b17e 103
hudakz 9:161bed13b17e 104 /*$off*/
hudakz 9:161bed13b17e 105 httpContent =
hudakz 9:161bed13b17e 106 "<head>"
hudakz 9:161bed13b17e 107 "<meta charset=\"utf-8\">"
hudakz 9:161bed13b17e 108 "<meta name=\"viewport\" content=\" initial-scale=1.0; maximum-scale=1.0; minimum-scale=1.0; user-scalable=0;\"/>"
hudakz 9:161bed13b17e 109 "<title>Smart Home</title>"
hudakz 9:161bed13b17e 110 "<link href='http://fonts.googleapis.com/css?family=Droid+Sans&v1' rel='stylesheet' type='text/css'>"
hudakz 9:161bed13b17e 111 "<style>"
hudakz 9:161bed13b17e 112 ".switch {"
hudakz 9:161bed13b17e 113 "position: relative;"
hudakz 9:161bed13b17e 114 "display: inline-block;"
hudakz 9:161bed13b17e 115 "width: 60px;"
hudakz 9:161bed13b17e 116 "height: 34px;"
hudakz 9:161bed13b17e 117 "}"
hudakz 9:161bed13b17e 118 ".switch input {display:none;}"
hudakz 9:161bed13b17e 119 ".slider {"
hudakz 9:161bed13b17e 120 "position: absolute;"
hudakz 9:161bed13b17e 121 "cursor: pointer;"
hudakz 9:161bed13b17e 122 "top: 0;"
hudakz 9:161bed13b17e 123 "left: 0;"
hudakz 9:161bed13b17e 124 "right: 0;"
hudakz 9:161bed13b17e 125 "bottom: 0;"
hudakz 9:161bed13b17e 126 "border-radius: 34px;"
hudakz 9:161bed13b17e 127 "background-color: #ccc;"
hudakz 9:161bed13b17e 128 "-webkit-transition: .4s;"
hudakz 9:161bed13b17e 129 "transition: .4s;"
hudakz 9:161bed13b17e 130 "}"
hudakz 9:161bed13b17e 131 ".slider:before {"
hudakz 9:161bed13b17e 132 "position: absolute;"
hudakz 9:161bed13b17e 133 "content: \"\";"
hudakz 9:161bed13b17e 134 "height: 26px;"
hudakz 9:161bed13b17e 135 "width: 26px;"
hudakz 9:161bed13b17e 136 "left: 4px;"
hudakz 9:161bed13b17e 137 "bottom: 4px;"
hudakz 9:161bed13b17e 138 "border-radius: 50%;"
hudakz 9:161bed13b17e 139 "background-color: white;"
hudakz 9:161bed13b17e 140 "-webkit-transition: .4s;"
hudakz 9:161bed13b17e 141 "transition: .4s;"
hudakz 9:161bed13b17e 142 "}"
hudakz 9:161bed13b17e 143 "input:checked + .slider {"
hudakz 9:161bed13b17e 144 "background-color: #8ce196;"
hudakz 9:161bed13b17e 145 "}"
hudakz 9:161bed13b17e 146 "input:focus + .slider {"
hudakz 9:161bed13b17e 147 "box-shadow: 0 0 1px #8ce196;"
hudakz 9:161bed13b17e 148 "}"
hudakz 9:161bed13b17e 149 "input:checked + .slider:before {"
hudakz 9:161bed13b17e 150 "-webkit-transform: translateX(26px);"
hudakz 9:161bed13b17e 151 "-ms-transform: translateX(26px);"
hudakz 9:161bed13b17e 152 "transform: translateX(26px);"
hudakz 9:161bed13b17e 153 "}"
hudakz 9:161bed13b17e 154 "</style>"
hudakz 9:161bed13b17e 155 "</head>"
hudakz 9:161bed13b17e 156
hudakz 9:161bed13b17e 157 "<body>"
hudakz 9:161bed13b17e 158 "<h2><a href=\".\" title=\"Click to refresh the page\">Smart Home</a></h2>"
hudakz 9:161bed13b17e 159 "<pre>Temperature:\t" + string(roomTempStr) + "&deg;C</pre>"
hudakz 9:161bed13b17e 160 "<pre>Heating:\t";
hudakz 9:161bed13b17e 161
hudakz 0:e455fdb56bc8 162 if(status == ON) {
hudakz 9:161bed13b17e 163 httpContent +=
hudakz 9:161bed13b17e 164 "<a href=\"./?sw=0\" class=\"switch\"> "
hudakz 9:161bed13b17e 165 "<input type=\"checkbox\" checked>";
hudakz 0:e455fdb56bc8 166 }
hudakz 0:e455fdb56bc8 167 else {
hudakz 9:161bed13b17e 168 httpContent +=
hudakz 9:161bed13b17e 169 "<a href=\"./?sw=1\" class=\"switch\"> "
hudakz 9:161bed13b17e 170 "<input type=\"checkbox\">";
hudakz 9:161bed13b17e 171 }
hudakz 9:161bed13b17e 172
hudakz 9:161bed13b17e 173 httpContent +=
hudakz 9:161bed13b17e 174 "<div class=\"slider\"></div>"
hudakz 9:161bed13b17e 175 "</a>"
hudakz 9:161bed13b17e 176 "</pre>"
hudakz 9:161bed13b17e 177 "<hr>"
hudakz 9:161bed13b17e 178 "<pre>2017 ARMmbed</pre>"
hudakz 9:161bed13b17e 179 "</body>";
hudakz 9:161bed13b17e 180
hudakz 0:e455fdb56bc8 181 return httpContent;
hudakz 9:161bed13b17e 182 /*$on*/
hudakz 0:e455fdb56bc8 183 }
hudakz 9:161bed13b17e 184
hudakz 0:e455fdb56bc8 185 /**
hudakz 0:e455fdb56bc8 186 * @brief
hudakz 0:e455fdb56bc8 187 * @note
hudakz 0:e455fdb56bc8 188 * @param
hudakz 0:e455fdb56bc8 189 * @retval
hudakz 0:e455fdb56bc8 190 */
hudakz 9:161bed13b17e 191 void sendHTTP(TCPSocket& client, string& header, string& content)
hudakz 9:161bed13b17e 192 {
hudakz 9:161bed13b17e 193 /*$off*/
hudakz 0:e455fdb56bc8 194 char content_length[5] = { };
hudakz 9:161bed13b17e 195
hudakz 9:161bed13b17e 196 header +=
hudakz 9:161bed13b17e 197 "\r\nContent-Type: text/html\r\n"
hudakz 9:161bed13b17e 198 "Content-Length: ";
hudakz 0:e455fdb56bc8 199 sprintf(content_length, "%d", content.length());
hudakz 9:161bed13b17e 200 header +=
hudakz 9:161bed13b17e 201 string(content_length) + "\r\n"
hudakz 9:161bed13b17e 202 "Pragma: no-cache\r\n"
hudakz 9:161bed13b17e 203 "Connection: About to close\r\n\r\n";
hudakz 9:161bed13b17e 204
hudakz 0:e455fdb56bc8 205 string webpage = header + content;
hudakz 0:e455fdb56bc8 206 client.send((char*)webpage.c_str(), webpage.length());
hudakz 9:161bed13b17e 207 pc.printf("HTTP message sent to client.\n\r");
hudakz 9:161bed13b17e 208 /*$on*/
hudakz 0:e455fdb56bc8 209 }
hudakz 9:161bed13b17e 210
hudakz 0:e455fdb56bc8 211 /**
hudakz 0:e455fdb56bc8 212 * @brief
hudakz 0:e455fdb56bc8 213 * @note
hudakz 0:e455fdb56bc8 214 * @param
hudakz 0:e455fdb56bc8 215 * @retval
hudakz 0:e455fdb56bc8 216 */
hudakz 9:161bed13b17e 217 int main(void)
hudakz 9:161bed13b17e 218 {
hudakz 9:161bed13b17e 219 pc.printf("Starting.. \r\n\r\n");
hudakz 9:161bed13b17e 220
hudakz 8:47b0cb4b5b7d 221 net = new EthernetInterface();
hudakz 8:47b0cb4b5b7d 222
hudakz 8:47b0cb4b5b7d 223 if (!net) {
hudakz 9:161bed13b17e 224 pc.printf("Error! No network inteface found.\n");
hudakz 8:47b0cb4b5b7d 225 return 0;
hudakz 8:47b0cb4b5b7d 226 }
hudakz 0:e455fdb56bc8 227
hudakz 8:47b0cb4b5b7d 228 //net->set_network (IP, NETMASK, GATEWAY); // include this for using static IP address
hudakz 9:161bed13b17e 229 nsapi_size_or_error_t r = net->connect();
hudakz 9:161bed13b17e 230
hudakz 8:47b0cb4b5b7d 231 if (r != 0) {
hudakz 9:161bed13b17e 232 pc.printf("Error! net->connect() returned: %d\n", r);
hudakz 8:47b0cb4b5b7d 233 return r;
hudakz 8:47b0cb4b5b7d 234 }
hudakz 7:02a0635aeeac 235
hudakz 9:161bed13b17e 236 // Show the network address
hudakz 9:161bed13b17e 237 const char* ip = net->get_ip_address();
hudakz 9:161bed13b17e 238 const char* netmask = net->get_netmask();
hudakz 9:161bed13b17e 239 const char* gateway = net->get_gateway();
hudakz 9:161bed13b17e 240
hudakz 9:161bed13b17e 241 pc.printf("IP address: %s\r\n", ip ? ip : "None");
hudakz 9:161bed13b17e 242 pc.printf("Netmask: %s\r\n", netmask ? netmask : "None");
hudakz 9:161bed13b17e 243 pc.printf("Gateway: %s\r\n\r\n", gateway ? gateway : "None");
hudakz 9:161bed13b17e 244 pc.printf("Usage: Type %s/%s/ into your web browser and hit ENTER\r\n\r\n", ip, PASSWORD.c_str());
hudakz 9:161bed13b17e 245
hudakz 8:47b0cb4b5b7d 246 /* Open the server on ethernet stack */
hudakz 8:47b0cb4b5b7d 247 server.open(net);
hudakz 9:161bed13b17e 248
hudakz 0:e455fdb56bc8 249 /* Bind the HTTP port (TCP 80) to the server */
hudakz 9:161bed13b17e 250 server.bind(ip, PORT);
hudakz 9:161bed13b17e 251
hudakz 0:e455fdb56bc8 252 /* Can handle 5 simultaneous connections */
hudakz 0:e455fdb56bc8 253 server.listen(5);
hudakz 9:161bed13b17e 254
hudakz 0:e455fdb56bc8 255 //listening for http GET request
hudakz 9:161bed13b17e 256 while (true) {
hudakz 9:161bed13b17e 257 pc.printf("=========================================\r\n");
hudakz 9:161bed13b17e 258
hudakz 9:161bed13b17e 259 nsapi_error_t error;
hudakz 9:161bed13b17e 260
hudakz 9:161bed13b17e 261 clientSocket = server.accept(&error);
hudakz 9:161bed13b17e 262 if (error != 0) {
hudakz 9:161bed13b17e 263 pc.printf("Connection failed!\r\n");
hudakz 9:161bed13b17e 264 clientSocket->close();
hudakz 9:161bed13b17e 265 continue;
hudakz 9:161bed13b17e 266 }
hudakz 9:161bed13b17e 267
hudakz 9:161bed13b17e 268 clientSocket->getpeername(&clientAddress);
hudakz 9:161bed13b17e 269 pc.printf("Client with IP address %s connected.\r\n\r\n", clientAddress.get_ip_address());
hudakz 9:161bed13b17e 270 clientSocket->recv(receiveBuf, 1023);
hudakz 9:161bed13b17e 271 pc.printf("Data received:\r\n%s\n\r", receiveBuf);
hudakz 9:161bed13b17e 272
hudakz 0:e455fdb56bc8 273 string received(receiveBuf);
hudakz 9:161bed13b17e 274
hudakz 9:161bed13b17e 275 if (received.substr(0, 3) != "GET") {
hudakz 0:e455fdb56bc8 276 httpHeader = HTTP_OK;
hudakz 0:e455fdb56bc8 277 httpContent = "<h1>200 OK</h1>";
hudakz 9:161bed13b17e 278 sendHTTP(*clientSocket, httpHeader, httpContent);
hudakz 9:161bed13b17e 279 clientSocket->close();
hudakz 0:e455fdb56bc8 280 continue;
hudakz 0:e455fdb56bc8 281 }
hudakz 9:161bed13b17e 282
hudakz 9:161bed13b17e 283 if (received.substr(0, 6) == "GET / ") {
hudakz 0:e455fdb56bc8 284 httpHeader = HTTP_OK;
hudakz 0:e455fdb56bc8 285 httpContent = "<p>Usage: Type http://ip_address/password/ into your web browser and hit ENTER</p>\r\n";
hudakz 9:161bed13b17e 286 sendHTTP(*clientSocket, httpHeader, httpContent);
hudakz 9:161bed13b17e 287 clientSocket->close();
hudakz 0:e455fdb56bc8 288 continue;
hudakz 0:e455fdb56bc8 289 }
hudakz 9:161bed13b17e 290
hudakz 9:161bed13b17e 291 int cmd = analyseURL(received);
hudakz 9:161bed13b17e 292
hudakz 9:161bed13b17e 293 switch (cmd) {
hudakz 9:161bed13b17e 294 case -3:
hudakz 9:161bed13b17e 295 // update webpage
hudakz 9:161bed13b17e 296 httpHeader = HTTP_OK;
hudakz 9:161bed13b17e 297 sendHTTP(*clientSocket, httpHeader, showWebPage(sw));
hudakz 9:161bed13b17e 298 break;
hudakz 9:161bed13b17e 299
hudakz 9:161bed13b17e 300 case -2:
hudakz 9:161bed13b17e 301 // redirect to the right base url
hudakz 9:161bed13b17e 302 httpHeader = MOVED_PERM;
hudakz 9:161bed13b17e 303 sendHTTP(*clientSocket, httpHeader, movedPermanently(1));
hudakz 9:161bed13b17e 304 break;
hudakz 9:161bed13b17e 305
hudakz 9:161bed13b17e 306 case -1:
hudakz 9:161bed13b17e 307 httpHeader = UNAUTHORIZED;
hudakz 9:161bed13b17e 308 httpContent = "<h1>401 Unauthorized</h1>";
hudakz 9:161bed13b17e 309 sendHTTP(*clientSocket, httpHeader, httpContent);
hudakz 9:161bed13b17e 310 break;
hudakz 9:161bed13b17e 311
hudakz 9:161bed13b17e 312 case 0:
hudakz 9:161bed13b17e 313 sw = OFF; // turn the switch off
hudakz 9:161bed13b17e 314 httpHeader = HTTP_OK;
hudakz 9:161bed13b17e 315 sendHTTP(*clientSocket, httpHeader, showWebPage(sw));
hudakz 9:161bed13b17e 316 break;
hudakz 9:161bed13b17e 317
hudakz 9:161bed13b17e 318 case 1:
hudakz 9:161bed13b17e 319 sw = ON; // turn the switch on
hudakz 9:161bed13b17e 320 httpHeader = HTTP_OK;
hudakz 9:161bed13b17e 321 sendHTTP(*clientSocket, httpHeader, showWebPage(sw));
hudakz 9:161bed13b17e 322 break;
hudakz 0:e455fdb56bc8 323 }
hudakz 9:161bed13b17e 324
hudakz 9:161bed13b17e 325 clientSocket->close();
hudakz 0:e455fdb56bc8 326 }
hudakz 9:161bed13b17e 327 }