A simple web server that can be bound to either the EthernetInterface or the WiflyInterface.

Dependents:   Smart-WiFly-WebServer WattEye X10Svr SSDP_Server

Committer:
WiredHome
Date:
Tue Jun 25 16:37:06 2013 +0000
Revision:
4:f34642902056
Parent:
3:17928786bdb5
Child:
5:c9b27e718054
When a pointer to a buffer is passed in to the Wifly APIs that can modify that buffer, it will also pass the size of that buffer to avoid buffer overrun.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
WiredHome 0:729320f63c5c 1 //
WiredHome 2:a29c32190037 2 // @note Copyright © 2013 by Smartware Computing, all rights reserved.
WiredHome 0:729320f63c5c 3 // Individuals may use this application for evaluation or non-commercial
WiredHome 0:729320f63c5c 4 // purposes. Within this restriction, changes may be made to this application
WiredHome 0:729320f63c5c 5 // as long as this copyright notice is retained. The user shall make
WiredHome 0:729320f63c5c 6 // clear that their work is a derived work, and not the original.
WiredHome 0:729320f63c5c 7 // Users of this application and sources accept this application "as is" and
WiredHome 0:729320f63c5c 8 // shall hold harmless Smartware Computing, for any undesired results while
WiredHome 0:729320f63c5c 9 // using this application - whether real or imagined.
WiredHome 0:729320f63c5c 10 //
WiredHome 0:729320f63c5c 11 // author David Smart, Smartware Computing
WiredHome 0:729320f63c5c 12 //
WiredHome 0:729320f63c5c 13 #include "mbed.h"
WiredHome 0:729320f63c5c 14 #include "SW_HTTPServer.h"
WiredHome 0:729320f63c5c 15 #include "Utility.h"
WiredHome 0:729320f63c5c 16
WiredHome 0:729320f63c5c 17 //#define DEBUG
WiredHome 0:729320f63c5c 18
WiredHome 0:729320f63c5c 19 const char * DEFAULT_FILENAME = "index.htm";
WiredHome 0:729320f63c5c 20
WiredHome 0:729320f63c5c 21 // Header information to always send
WiredHome 0:729320f63c5c 22 const char hdr_httpver[] = "HTTP/1.1"; // typically HTTP/1.0 or HTTP/1.1
WiredHome 0:729320f63c5c 23 const char hdr_age[] = "Max-age: 0\r\n"; // expires right away (must be \r\n terminated)
WiredHome 0:729320f63c5c 24 const char hdr_server[] = "Server: Smart_Server v0.1\r\n"; // Server (must be \r\n terminated)
WiredHome 2:a29c32190037 25 const char hdr_dnt[] = "DNT: 1\r\n"; // Do Not Track
WiredHome 0:729320f63c5c 26 const char hdr_close[] = "Connection: close\r\n"; // tell the client to close the connection (must be \r\n terminated)
WiredHome 0:729320f63c5c 27 const char nl[] = "\r\n"; // final \r\n for the termination of the header
WiredHome 0:729320f63c5c 28
WiredHome 0:729320f63c5c 29 static const struct {
WiredHome 0:729320f63c5c 30 char *ext;
WiredHome 0:729320f63c5c 31 char *filetype;
WiredHome 0:729320f63c5c 32 } extensions [] = {
WiredHome 3:17928786bdb5 33 {".gif", "Content-Type: image/gif\r\n" },
WiredHome 3:17928786bdb5 34 {".jpg", "Content-Type: image/jpeg\r\n" },
WiredHome 3:17928786bdb5 35 {".jpeg","Content-Type: image/jpeg\r\n" },
WiredHome 3:17928786bdb5 36 {".ico", "Content-Type: image/x-icon\r\n" },
WiredHome 3:17928786bdb5 37 {".png", "Content-Type: image/png\r\n" },
WiredHome 3:17928786bdb5 38 {".zip", "Content-Type: image/zip\r\n" },
WiredHome 3:17928786bdb5 39 {".gz", "Content-Type: image/gz\r\n" },
WiredHome 3:17928786bdb5 40 {".tar", "Content-Type: image/tar\r\n" },
WiredHome 3:17928786bdb5 41 {".txt", "Content-Type: plain/text\r\n" },
WiredHome 3:17928786bdb5 42 {".pdf", "Content-Type: application/pdf\r\n" },
WiredHome 3:17928786bdb5 43 {".htm", "Content-Type: text/html\r\n" },
WiredHome 3:17928786bdb5 44 {".html","Content-Type: text/html\r\n" },
WiredHome 0:729320f63c5c 45 {0,0}
WiredHome 0:729320f63c5c 46 };
WiredHome 0:729320f63c5c 47
WiredHome 3:17928786bdb5 48 HTTPServer::HTTPServer(
WiredHome 3:17928786bdb5 49 Wifly * _wf,
WiredHome 3:17928786bdb5 50 int port,
WiredHome 3:17928786bdb5 51 const char * _webroot,
WiredHome 3:17928786bdb5 52 int _maxparams,
WiredHome 3:17928786bdb5 53 int _maxdynamicpages,
WiredHome 3:17928786bdb5 54 PC * _pc,
WiredHome 3:17928786bdb5 55 int _allocforheader,
WiredHome 3:17928786bdb5 56 int _allocforfile)
WiredHome 0:729320f63c5c 57 {
WiredHome 0:729320f63c5c 58 wifly = _wf;
WiredHome 0:729320f63c5c 59 webroot = (char *)malloc(strlen(_webroot)+1);
WiredHome 0:729320f63c5c 60 strcpy(webroot, _webroot);
WiredHome 0:729320f63c5c 61 maxparams = _maxparams;
WiredHome 0:729320f63c5c 62 maxdynamicpages = _maxdynamicpages;
WiredHome 0:729320f63c5c 63 params = (namevalue *)malloc(maxparams * sizeof(namevalue));
WiredHome 0:729320f63c5c 64 handlers = (handler *)malloc(maxdynamicpages * sizeof(handler));
WiredHome 3:17928786bdb5 65 headerbuffersize = _allocforheader;
WiredHome 3:17928786bdb5 66 headerbuffer = (char *)malloc(headerbuffersize);
WiredHome 0:729320f63c5c 67 pc = _pc;
WiredHome 3:17928786bdb5 68 queryType = NULL;
WiredHome 3:17928786bdb5 69 queryString = NULL;
WiredHome 3:17928786bdb5 70 hostString = NULL;
WiredHome 3:17928786bdb5 71 contentLength = NULL;
WiredHome 3:17928786bdb5 72 contentType = NULL;
WiredHome 3:17928786bdb5 73 postQueryString = NULL;
WiredHome 0:729320f63c5c 74 paramcount = 0;
WiredHome 0:729320f63c5c 75 handlercount = 0;
WiredHome 3:17928786bdb5 76 maxheaderbytes = 0;
WiredHome 0:729320f63c5c 77 server = new TCPSocketServer();
WiredHome 0:729320f63c5c 78 server->bind(port);
WiredHome 0:729320f63c5c 79 server->listen();
WiredHome 3:17928786bdb5 80 server->set_blocking(false, 0);
WiredHome 3:17928786bdb5 81 client.set_blocking(false, 0);
WiredHome 0:729320f63c5c 82 server->accept(client);
WiredHome 3:17928786bdb5 83 ResetPerformanceData();
WiredHome 3:17928786bdb5 84 timer.start();
WiredHome 0:729320f63c5c 85 }
WiredHome 0:729320f63c5c 86
WiredHome 0:729320f63c5c 87 HTTPServer::~HTTPServer()
WiredHome 0:729320f63c5c 88 {
WiredHome 0:729320f63c5c 89 free(webroot);
WiredHome 0:729320f63c5c 90 webroot = NULL;
WiredHome 0:729320f63c5c 91 }
WiredHome 0:729320f63c5c 92
WiredHome 3:17928786bdb5 93 int HTTPServer::GetMaxHeaderSize()
WiredHome 3:17928786bdb5 94 {
WiredHome 3:17928786bdb5 95 return maxheaderbytes;
WiredHome 3:17928786bdb5 96 }
WiredHome 3:17928786bdb5 97
WiredHome 0:729320f63c5c 98 bool HTTPServer::RegisterHandler(const char * path, Handler callback)
WiredHome 0:729320f63c5c 99 {
WiredHome 0:729320f63c5c 100 if (handlercount < maxdynamicpages && path && callback) {
WiredHome 0:729320f63c5c 101 handlers[handlercount].path = (char *)malloc(strlen(path)+1);
WiredHome 0:729320f63c5c 102 memcpy(handlers[handlercount].path, path, strlen(path)+1);
WiredHome 0:729320f63c5c 103 handlers[handlercount].callback = callback;
WiredHome 0:729320f63c5c 104 handlercount++;
WiredHome 0:729320f63c5c 105 return true;
WiredHome 0:729320f63c5c 106 } else {
WiredHome 0:729320f63c5c 107 return false;
WiredHome 0:729320f63c5c 108 }
WiredHome 0:729320f63c5c 109 }
WiredHome 0:729320f63c5c 110
WiredHome 2:a29c32190037 111 // Poll()
WiredHome 0:729320f63c5c 112 //
WiredHome 0:729320f63c5c 113 // *OPEN*GET /x=1 HTTP/1.1
WiredHome 0:729320f63c5c 114 // Host: 192.168.1.140
WiredHome 0:729320f63c5c 115 // Connection: keep-alive
WiredHome 0:729320f63c5c 116 // Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
WiredHome 0:729320f63c5c 117 // User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36
WiredHome 0:729320f63c5c 118 // Accept-Encoding: gzip,deflate,sdch
WiredHome 0:729320f63c5c 119 // Accept-Language: en-US,en;q=0.8
WiredHome 0:729320f63c5c 120 //
WiredHome 2:a29c32190037 121 void HTTPServer::Poll()
WiredHome 0:729320f63c5c 122 {
WiredHome 3:17928786bdb5 123 typedef enum {
WiredHome 3:17928786bdb5 124 Idle, // waiting for a connection
WiredHome 3:17928786bdb5 125 Receiving, // receiving data
WiredHome 3:17928786bdb5 126 Sending, // send the response
WiredHome 3:17928786bdb5 127 WaitingToClose // small timeout to close
WiredHome 3:17928786bdb5 128 } state;
WiredHome 0:729320f63c5c 129 static state op = Idle;
WiredHome 3:17928786bdb5 130 static char * bPtr = headerbuffer;
WiredHome 0:729320f63c5c 131 int n;
WiredHome 3:17928786bdb5 132 static int t_ref; // reference point for the timer
WiredHome 0:729320f63c5c 133
WiredHome 0:729320f63c5c 134 switch(op) {
WiredHome 3:17928786bdb5 135 default: // not expected to arrive here
WiredHome 3:17928786bdb5 136 op = Idle;
WiredHome 3:17928786bdb5 137 break;
WiredHome 3:17928786bdb5 138 case Idle:
WiredHome 3:17928786bdb5 139 timer.reset();
WiredHome 3:17928786bdb5 140 bPtr = headerbuffer;
WiredHome 3:17928786bdb5 141 if (0 == client.receive(bPtr, 0)) { // server->accept(client) == 0) {
WiredHome 3:17928786bdb5 142 op = Receiving;
WiredHome 3:17928786bdb5 143 t_ref = timer.read_us();
WiredHome 3:17928786bdb5 144 }
WiredHome 0:729320f63c5c 145 break;
WiredHome 3:17928786bdb5 146 case Receiving:
WiredHome 3:17928786bdb5 147 n = client.receive(bPtr, headerbuffersize - (bPtr - headerbuffer));
WiredHome 3:17928786bdb5 148 if (n < 0) {
WiredHome 3:17928786bdb5 149 ; // pc->printf("*** client.receive error: %d\r\n", n);
WiredHome 3:17928786bdb5 150 } else if (n) {
WiredHome 3:17928786bdb5 151 bPtr[n] = '\0';
WiredHome 3:17928786bdb5 152 if (ParseHeader(headerbuffer)) {
WiredHome 3:17928786bdb5 153 op = Sending;
WiredHome 3:17928786bdb5 154 t_ref = RecordPerformanceData(&perfData.Header, t_ref);
WiredHome 3:17928786bdb5 155 }
WiredHome 3:17928786bdb5 156 bPtr += n;
WiredHome 0:729320f63c5c 157 }
WiredHome 0:729320f63c5c 158 break;
WiredHome 0:729320f63c5c 159 case Sending:
WiredHome 3:17928786bdb5 160 SendResponse();
WiredHome 0:729320f63c5c 161 op = WaitingToClose;
WiredHome 3:17928786bdb5 162 RecordPerformanceData(&perfData.SendData, t_ref);
WiredHome 0:729320f63c5c 163 break;
WiredHome 0:729320f63c5c 164 case WaitingToClose:
WiredHome 3:17928786bdb5 165 close_connection();
WiredHome 0:729320f63c5c 166 op = Idle;
WiredHome 0:729320f63c5c 167 break;
WiredHome 0:729320f63c5c 168 }
WiredHome 0:729320f63c5c 169 }
WiredHome 0:729320f63c5c 170
WiredHome 0:729320f63c5c 171
WiredHome 0:729320f63c5c 172 const char * HTTPServer::GetSupportedType(const char * filename)
WiredHome 0:729320f63c5c 173 {
WiredHome 0:729320f63c5c 174 int i;
WiredHome 0:729320f63c5c 175 int buflen = strlen(filename);
WiredHome 0:729320f63c5c 176 int extlen;
WiredHome 0:729320f63c5c 177
WiredHome 0:729320f63c5c 178 for (i=0; extensions[i].ext != 0; i++) {
WiredHome 0:729320f63c5c 179 extlen = strlen(extensions[i].ext);
WiredHome 0:729320f63c5c 180 if ( !strncmp(&filename[buflen-extlen], extensions[i].ext, extlen)) {
WiredHome 0:729320f63c5c 181 return extensions[i].filetype;
WiredHome 0:729320f63c5c 182 }
WiredHome 0:729320f63c5c 183 }
WiredHome 0:729320f63c5c 184 return NULL;
WiredHome 0:729320f63c5c 185 }
WiredHome 0:729320f63c5c 186
WiredHome 3:17928786bdb5 187
WiredHome 0:729320f63c5c 188 void HTTPServer::send(const char * msg, int bytes)
WiredHome 0:729320f63c5c 189 {
WiredHome 0:729320f63c5c 190 if (bytes == -1)
WiredHome 0:729320f63c5c 191 bytes = strlen(msg);
WiredHome 0:729320f63c5c 192 wifly->send(msg, bytes);
WiredHome 0:729320f63c5c 193 }
WiredHome 0:729320f63c5c 194
WiredHome 3:17928786bdb5 195
WiredHome 0:729320f63c5c 196 bool HTTPServer::SendFile(const char * filename, const char * filetype)
WiredHome 0:729320f63c5c 197 {
WiredHome 0:729320f63c5c 198 FILE * fp;
WiredHome 3:17928786bdb5 199
WiredHome 0:729320f63c5c 200 fp = fopen(filename,"rb");
WiredHome 0:729320f63c5c 201 if (fp) { // can open it
WiredHome 0:729320f63c5c 202 char *fbuffer = (char *)malloc(FILESEND_BUF_SIZE);
WiredHome 0:729320f63c5c 203 int bytes;
WiredHome 0:729320f63c5c 204
WiredHome 3:17928786bdb5 205 if (fbuffer) {
WiredHome 3:17928786bdb5 206 header(200, "OK", filetype);
WiredHome 0:729320f63c5c 207 bytes = fread(fbuffer,sizeof(char),FILESEND_BUF_SIZE,fp);
WiredHome 3:17928786bdb5 208 while (bytes > 0) {
WiredHome 3:17928786bdb5 209 send(fbuffer, bytes);
WiredHome 3:17928786bdb5 210 bytes = fread(fbuffer,sizeof(char),FILESEND_BUF_SIZE,fp);
WiredHome 3:17928786bdb5 211 }
WiredHome 3:17928786bdb5 212 free(fbuffer);
WiredHome 3:17928786bdb5 213 } else {
WiredHome 3:17928786bdb5 214 header(500, "Server Error", "Pragma: err - insufficient memory\r\n");
WiredHome 0:729320f63c5c 215 }
WiredHome 0:729320f63c5c 216 fclose(fp);
WiredHome 0:729320f63c5c 217 return true;
WiredHome 0:729320f63c5c 218 } else {
WiredHome 3:17928786bdb5 219 header(404, "Not Found", "Pragma: err - Can't open file\r\n");
WiredHome 0:729320f63c5c 220 return false;
WiredHome 0:729320f63c5c 221 }
WiredHome 0:729320f63c5c 222 }
WiredHome 0:729320f63c5c 223
WiredHome 0:729320f63c5c 224 int HTTPServer::HexCharToInt(char c)
WiredHome 0:729320f63c5c 225 {
WiredHome 0:729320f63c5c 226 if (c >= 'a' && c <= 'f')
WiredHome 0:729320f63c5c 227 return (c - 'a' + 10);
WiredHome 0:729320f63c5c 228 else if (c >= 'A' && c <= 'F')
WiredHome 0:729320f63c5c 229 return (c - 'A' + 10);
WiredHome 0:729320f63c5c 230 else if (c >= '0' && c <= '9')
WiredHome 0:729320f63c5c 231 return c - '0';
WiredHome 0:729320f63c5c 232 else
WiredHome 0:729320f63c5c 233 return 0;
WiredHome 0:729320f63c5c 234 }
WiredHome 0:729320f63c5c 235
WiredHome 0:729320f63c5c 236 char HTTPServer::HexPairToChar(char * p)
WiredHome 0:729320f63c5c 237 {
WiredHome 0:729320f63c5c 238 return 16 * HexCharToInt(*p) + HexCharToInt(*(p+1));
WiredHome 0:729320f63c5c 239 }
WiredHome 0:729320f63c5c 240
WiredHome 0:729320f63c5c 241 void HTTPServer::UnescapeString(char * encoded)
WiredHome 0:729320f63c5c 242 {
WiredHome 0:729320f63c5c 243 char *p;
WiredHome 0:729320f63c5c 244
WiredHome 0:729320f63c5c 245 // first convert '+' to ' '
WiredHome 0:729320f63c5c 246 p = strchr(encoded, '+');
WiredHome 0:729320f63c5c 247 while (p) {
WiredHome 0:729320f63c5c 248 *p = ' ';
WiredHome 0:729320f63c5c 249 p = strchr(encoded, '+');
WiredHome 0:729320f63c5c 250 }
WiredHome 0:729320f63c5c 251 // then convert hex '%xx' to char 'x'
WiredHome 0:729320f63c5c 252 p = strchr(encoded, '%');
WiredHome 0:729320f63c5c 253 while (p) {
WiredHome 0:729320f63c5c 254 if (strchr("0123456789ABCDEFabcdef", *(p+1))
WiredHome 0:729320f63c5c 255 && strchr("0123456789ABCDEFabcdef", *(p+2)) ) {
WiredHome 0:729320f63c5c 256 *p = HexPairToChar(p+1);
WiredHome 0:729320f63c5c 257 p++; // advance past the %
WiredHome 0:729320f63c5c 258 char * a = p;
WiredHome 0:729320f63c5c 259 char * b = p + 2;
WiredHome 0:729320f63c5c 260 do {
WiredHome 0:729320f63c5c 261 *a++ = *b++;
WiredHome 0:729320f63c5c 262 } while (*b);
WiredHome 0:729320f63c5c 263 *a = '\0';
WiredHome 0:729320f63c5c 264 }
WiredHome 0:729320f63c5c 265 p = strchr(p, '%');
WiredHome 0:729320f63c5c 266 }
WiredHome 0:729320f63c5c 267 }
WiredHome 0:729320f63c5c 268
WiredHome 0:729320f63c5c 269 const char * HTTPServer::GetParameter(const char * name)
WiredHome 0:729320f63c5c 270 {
WiredHome 0:729320f63c5c 271 for (int i=0; i<paramcount; i++) {
WiredHome 0:729320f63c5c 272 if (strcmp(params[i].name, name) == 0) {
WiredHome 0:729320f63c5c 273 return params[i].value;
WiredHome 0:729320f63c5c 274 }
WiredHome 0:729320f63c5c 275 }
WiredHome 0:729320f63c5c 276 return NULL;
WiredHome 0:729320f63c5c 277 }
WiredHome 0:729320f63c5c 278
WiredHome 0:729320f63c5c 279 // this=that&who=what&more=stuff...
WiredHome 0:729320f63c5c 280 // ^ ^ ^
WiredHome 3:17928786bdb5 281 void HTTPServer::ParseParameters(char * pName)
WiredHome 0:729320f63c5c 282 {
WiredHome 0:729320f63c5c 283 char * pVal;
WiredHome 0:729320f63c5c 284 char * pNextName;
WiredHome 0:729320f63c5c 285
WiredHome 0:729320f63c5c 286 // Parse params
WiredHome 0:729320f63c5c 287 pVal = strchr(pName, '#'); // If there is a '#fragment_id', we can ignore it
WiredHome 0:729320f63c5c 288 if (pVal)
WiredHome 3:17928786bdb5 289 *pVal = '\0';
WiredHome 0:729320f63c5c 290 do {
WiredHome 0:729320f63c5c 291 //pc->printf("Parse(%s)\r\n", pName);
WiredHome 0:729320f63c5c 292 //*pName++ = '\0'; // already '\0' on the first entry
WiredHome 0:729320f63c5c 293 params[paramcount].name = pName;
WiredHome 0:729320f63c5c 294 pVal = strchr(pName, '=');
WiredHome 0:729320f63c5c 295 pNextName = strchr(pName,'&');
WiredHome 0:729320f63c5c 296 if (pVal) {
WiredHome 0:729320f63c5c 297 if (pNextName == NULL || (pNextName && pNextName > pVal)) {
WiredHome 0:729320f63c5c 298 *pVal++ = '\0';
WiredHome 0:729320f63c5c 299 params[paramcount].value = pVal;
WiredHome 0:729320f63c5c 300 pName = pVal;
WiredHome 0:729320f63c5c 301 }
WiredHome 0:729320f63c5c 302 }
WiredHome 0:729320f63c5c 303 //pc->printf(" [%s]=[%s]\r\n", params[paramcount].name, params[paramcount].value);
WiredHome 0:729320f63c5c 304 paramcount++;
WiredHome 0:729320f63c5c 305 if (pNextName) {
WiredHome 0:729320f63c5c 306 pName = pNextName;
WiredHome 0:729320f63c5c 307 *pName++ = '\0';
WiredHome 0:729320f63c5c 308 } else {
WiredHome 0:729320f63c5c 309 pName = NULL;
WiredHome 0:729320f63c5c 310 }
WiredHome 0:729320f63c5c 311 } while (pName && paramcount < maxparams);
WiredHome 0:729320f63c5c 312 }
WiredHome 0:729320f63c5c 313
WiredHome 0:729320f63c5c 314
WiredHome 4:f34642902056 315 void HTTPServer::GetRemoteAddr(char * str, int strSize)
WiredHome 0:729320f63c5c 316 {
WiredHome 0:729320f63c5c 317 bool res = false;
WiredHome 0:729320f63c5c 318 char *p;
WiredHome 0:729320f63c5c 319
WiredHome 4:f34642902056 320 if (strSize < 16) { // Can only guard it here w/o modifying Wifly class
WiredHome 3:17928786bdb5 321 *str = '\0';
WiredHome 3:17928786bdb5 322 return;
WiredHome 3:17928786bdb5 323 }
WiredHome 4:f34642902056 324 res = wifly->sendCommand("show z\r", "NO", str, strSize, 500);
WiredHome 0:729320f63c5c 325 wait(0.2); // how long to wait is fragile, but need the rest of the chars to come in...
WiredHome 0:729320f63c5c 326 if (res) {
WiredHome 0:729320f63c5c 327 p = strchr(str, '\n'); // truncate after the octets.
WiredHome 0:729320f63c5c 328 if (p) *p = '\0';
WiredHome 0:729320f63c5c 329 p = strchr(str, ' '); // or a space
WiredHome 0:729320f63c5c 330 if (p) *p = '\0';
WiredHome 0:729320f63c5c 331 p = strchr(str, '<'); // or a <
WiredHome 0:729320f63c5c 332 if (p) *p = '\0';
WiredHome 0:729320f63c5c 333 }
WiredHome 0:729320f63c5c 334 wifly->exit();
WiredHome 0:729320f63c5c 335 }
WiredHome 0:729320f63c5c 336
WiredHome 0:729320f63c5c 337
WiredHome 0:729320f63c5c 338 void HTTPServer::header(int code, const char * code_text, const char * content_type, const char * optional_text)
WiredHome 0:729320f63c5c 339 {
WiredHome 0:729320f63c5c 340 char http[100];
WiredHome 0:729320f63c5c 341
WiredHome 0:729320f63c5c 342 sprintf(http, "%s %i %s\r\n", hdr_httpver, code, code_text);
WiredHome 0:729320f63c5c 343 send(http);
WiredHome 0:729320f63c5c 344 send(hdr_age);
WiredHome 0:729320f63c5c 345 send(hdr_server);
WiredHome 0:729320f63c5c 346 if (content_type) {
WiredHome 0:729320f63c5c 347 send(content_type);
WiredHome 0:729320f63c5c 348 }
WiredHome 0:729320f63c5c 349 if (optional_text) {
WiredHome 0:729320f63c5c 350 send(optional_text);
WiredHome 0:729320f63c5c 351 }
WiredHome 2:a29c32190037 352 send(hdr_dnt);
WiredHome 0:729320f63c5c 353 send(hdr_close);
WiredHome 0:729320f63c5c 354 send(nl);
WiredHome 0:729320f63c5c 355 }
WiredHome 0:729320f63c5c 356
WiredHome 0:729320f63c5c 357 void HTTPServer::close_connection( )
WiredHome 0:729320f63c5c 358 {
WiredHome 0:729320f63c5c 359 #ifndef DEBUG
WiredHome 0:729320f63c5c 360 wifly->close();
WiredHome 0:729320f63c5c 361 #else // DEBUG
WiredHome 0:729320f63c5c 362 if (!wifly->close())
WiredHome 0:729320f63c5c 363 pc->printf("Couldn't close connection\r\n");
WiredHome 0:729320f63c5c 364 #endif
WiredHome 0:729320f63c5c 365 }
WiredHome 0:729320f63c5c 366
WiredHome 0:729320f63c5c 367 bool HTTPServer::Extract(char * haystack, char * needle, char ** string)
WiredHome 0:729320f63c5c 368 {
WiredHome 0:729320f63c5c 369 bool ret = false; // assume failure until proven otherwise
WiredHome 0:729320f63c5c 370 char * qs = NULL;
WiredHome 0:729320f63c5c 371 char * eqs = NULL;
WiredHome 0:729320f63c5c 372 char * container = NULL;
WiredHome 0:729320f63c5c 373 char * get = strstr(haystack, needle); // what if not at the front?
WiredHome 0:729320f63c5c 374 if (get) {
WiredHome 0:729320f63c5c 375 // Seems to be a valid "...GET /QueryString HTTP/1.1"
WiredHome 0:729320f63c5c 376 qs = get + strlen(needle); // in case the needle didn't have space delimiters
WiredHome 0:729320f63c5c 377 while (*qs == ' ')
WiredHome 0:729320f63c5c 378 qs++;
WiredHome 0:729320f63c5c 379 // /QueryString\0HTTP/1.1\0\0
WiredHome 0:729320f63c5c 380 if (*string) // recycle old string when working a new one
WiredHome 0:729320f63c5c 381 free(*string);
WiredHome 0:729320f63c5c 382 container = (char *)malloc(strlen(qs));
WiredHome 0:729320f63c5c 383 if (container) {
WiredHome 0:729320f63c5c 384 strcpy(container, qs);
WiredHome 0:729320f63c5c 385 eqs = strchr(container, ' ');
WiredHome 0:729320f63c5c 386 if (eqs)
WiredHome 0:729320f63c5c 387 *eqs = '\0';
WiredHome 0:729320f63c5c 388 *string = container;
WiredHome 0:729320f63c5c 389 ret = true;
WiredHome 0:729320f63c5c 390 } else {
WiredHome 0:729320f63c5c 391 *string = NULL; // something bad happened... no memory
WiredHome 0:729320f63c5c 392 }
WiredHome 0:729320f63c5c 393 }
WiredHome 0:729320f63c5c 394 return ret;
WiredHome 0:729320f63c5c 395 }
WiredHome 0:729320f63c5c 396
WiredHome 0:729320f63c5c 397 char * HTTPServer::rewriteWithDefaultFile(char * queryString)
WiredHome 0:729320f63c5c 398 {
WiredHome 0:729320f63c5c 399 char * temp = (char *)malloc(strlen(queryString) + strlen(DEFAULT_FILENAME) + 1);
WiredHome 0:729320f63c5c 400
WiredHome 0:729320f63c5c 401 if (temp) {
WiredHome 0:729320f63c5c 402 *temp = '\0';
WiredHome 0:729320f63c5c 403 strcpy(temp, queryString);
WiredHome 0:729320f63c5c 404 strcat(temp, DEFAULT_FILENAME);
WiredHome 0:729320f63c5c 405 free(queryString);
WiredHome 0:729320f63c5c 406 return temp;
WiredHome 0:729320f63c5c 407 } else {
WiredHome 0:729320f63c5c 408 return queryString;
WiredHome 0:729320f63c5c 409 }
WiredHome 0:729320f63c5c 410 }
WiredHome 0:729320f63c5c 411
WiredHome 0:729320f63c5c 412 char * HTTPServer::rewritePrependWebroot(char * queryString)
WiredHome 0:729320f63c5c 413 {
WiredHome 0:729320f63c5c 414 char * temp = (char *)malloc(strlen(webroot) + strlen(queryString) + 1);
WiredHome 0:729320f63c5c 415
WiredHome 0:729320f63c5c 416 if (temp) {
WiredHome 0:729320f63c5c 417 *temp = '\0';
WiredHome 0:729320f63c5c 418 strcpy(temp, webroot);
WiredHome 0:729320f63c5c 419 if (temp[strlen(temp)-1] == '/' && *queryString == '/')
WiredHome 0:729320f63c5c 420 temp[strlen(temp)-1] = '\0';
WiredHome 0:729320f63c5c 421 strcat(temp, queryString);
WiredHome 0:729320f63c5c 422 free(queryString);
WiredHome 0:729320f63c5c 423 return temp;
WiredHome 0:729320f63c5c 424 } else {
WiredHome 0:729320f63c5c 425 return queryString;
WiredHome 0:729320f63c5c 426 }
WiredHome 0:729320f63c5c 427 }
WiredHome 0:729320f63c5c 428
WiredHome 3:17928786bdb5 429 bool HTTPServer::CheckDynamicHandlers()
WiredHome 3:17928786bdb5 430 {
WiredHome 3:17928786bdb5 431 bool regHandled = false;
WiredHome 0:729320f63c5c 432
WiredHome 3:17928786bdb5 433 // If this queryString is in the list of registered handlers, call that
WiredHome 3:17928786bdb5 434 for (int i=0; i<handlercount; i++) {
WiredHome 3:17928786bdb5 435 if (strcmp(handlers[i].path, queryString) == 0) {
WiredHome 3:17928786bdb5 436 (*handlers[i].callback)(this, SEND_PAGE, queryString, params, paramcount);
WiredHome 3:17928786bdb5 437 regHandled = true;
WiredHome 3:17928786bdb5 438 break; // we only execute the first one
WiredHome 3:17928786bdb5 439 }
WiredHome 3:17928786bdb5 440 }
WiredHome 3:17928786bdb5 441 return regHandled;
WiredHome 3:17928786bdb5 442 }
WiredHome 3:17928786bdb5 443
WiredHome 3:17928786bdb5 444 void HTTPServer::SendResponse()
WiredHome 3:17928786bdb5 445 {
WiredHome 3:17928786bdb5 446 if (strcmp(queryType, "GET") == 0 || strcmp(queryType, "POST") == 0) {
WiredHome 3:17928786bdb5 447 if (!(queryString[0] == '.' && queryString[1] == '.')) {
WiredHome 3:17928786bdb5 448 const char * fType;
WiredHome 3:17928786bdb5 449
WiredHome 3:17928786bdb5 450 if (!CheckDynamicHandlers()) {
WiredHome 3:17928786bdb5 451 // Otherwise, this queryString must be trying to reference a static file
WiredHome 3:17928786bdb5 452 if (queryString[strlen(queryString)-1] == '/') {
WiredHome 3:17928786bdb5 453 queryString = rewriteWithDefaultFile(queryString);
WiredHome 3:17928786bdb5 454 }
WiredHome 3:17928786bdb5 455 // see if we support this file type
WiredHome 3:17928786bdb5 456 fType = GetSupportedType(queryString);
WiredHome 3:17928786bdb5 457 if (fType) {
WiredHome 3:17928786bdb5 458 queryString = rewritePrependWebroot(queryString);
WiredHome 3:17928786bdb5 459 SendFile(queryString, fType);
WiredHome 3:17928786bdb5 460 } else {
WiredHome 3:17928786bdb5 461 //pc->printf("Unsupported file type %s\r\n", queryString);
WiredHome 3:17928786bdb5 462 header(404, "Not Found", "Pragma: err - Unsupported type\r\n");
WiredHome 3:17928786bdb5 463 }
WiredHome 3:17928786bdb5 464 }
WiredHome 3:17928786bdb5 465 } else {
WiredHome 3:17928786bdb5 466 //pc->printf("Unsupported path %s\r\n", queryString);
WiredHome 3:17928786bdb5 467 header(400, "Bad Request", "Pragma: err - Unsupported path\r\n");
WiredHome 3:17928786bdb5 468 }
WiredHome 3:17928786bdb5 469 } else {
WiredHome 3:17928786bdb5 470 //pc->printf("Unsupported query type %s\r\n", queryType);
WiredHome 3:17928786bdb5 471 header(400, "Bad Request", "Pragma: err - Unsupported query type\r\n");
WiredHome 3:17928786bdb5 472 }
WiredHome 3:17928786bdb5 473 if (queryType) {
WiredHome 3:17928786bdb5 474 free(queryType);
WiredHome 3:17928786bdb5 475 queryType = NULL;
WiredHome 3:17928786bdb5 476 }
WiredHome 3:17928786bdb5 477 if (queryString) {
WiredHome 3:17928786bdb5 478 free(queryString);
WiredHome 3:17928786bdb5 479 queryString = NULL;
WiredHome 3:17928786bdb5 480 }
WiredHome 3:17928786bdb5 481 if (hostString) {
WiredHome 3:17928786bdb5 482 free(hostString);
WiredHome 3:17928786bdb5 483 hostString = NULL;
WiredHome 3:17928786bdb5 484 }
WiredHome 3:17928786bdb5 485 if (contentLength) {
WiredHome 3:17928786bdb5 486 free(contentLength);
WiredHome 3:17928786bdb5 487 contentLength = NULL;
WiredHome 3:17928786bdb5 488 }
WiredHome 3:17928786bdb5 489 if (contentType) {
WiredHome 3:17928786bdb5 490 free(contentType);
WiredHome 3:17928786bdb5 491 contentType = NULL;
WiredHome 3:17928786bdb5 492 }
WiredHome 3:17928786bdb5 493 if (postQueryString) {
WiredHome 3:17928786bdb5 494 free(postQueryString);
WiredHome 3:17928786bdb5 495 postQueryString = NULL;
WiredHome 3:17928786bdb5 496 }
WiredHome 3:17928786bdb5 497 }
WiredHome 3:17928786bdb5 498
WiredHome 3:17928786bdb5 499 bool HTTPServer::ParseHeader(char * buffer)
WiredHome 3:17928786bdb5 500 {
WiredHome 3:17928786bdb5 501 char * dblCR;
WiredHome 3:17928786bdb5 502 bool advanceState = false;
WiredHome 3:17928786bdb5 503 int bytecount;
WiredHome 3:17928786bdb5 504
WiredHome 3:17928786bdb5 505 // Bad hack to have to do this here, but it isn't being set in the
WiredHome 3:17928786bdb5 506 // underlying layer, and this is what allows it to properly "close"
WiredHome 3:17928786bdb5 507 // when it is done.
WiredHome 3:17928786bdb5 508 wifly->setConnectionState(true);
WiredHome 3:17928786bdb5 509 // Buffer could have partial, but the double \r\n is the key
WiredHome 3:17928786bdb5 510 // *OPEN*QueryType QueryString HTTP/1.1....
WiredHome 3:17928786bdb5 511 // QueryType:= GET
WiredHome 3:17928786bdb5 512 // *OPEN*GET /QueryString HTTP/1.1\r\n
WiredHome 3:17928786bdb5 513 // *OPEN*GET /QueryString HTTP/1.1\r\nHeader stuf
WiredHome 3:17928786bdb5 514 // *OPEN*GET /QueryString HTTP/1.1\r\nHeader stuff...\r\n\r\n
WiredHome 3:17928786bdb5 515 dblCR = strstr(buffer,"\r\n\r\n");
WiredHome 3:17928786bdb5 516 if (dblCR) { // Have to scan from the beginning in case split on \r
WiredHome 3:17928786bdb5 517 #if 0
WiredHome 3:17928786bdb5 518 pc->printf("\r\n\r\nThe Header:\r\n%s\r\n\r\n", buffer);
WiredHome 3:17928786bdb5 519 #endif
WiredHome 3:17928786bdb5 520 char * soRec = buffer; // start of the next record of text
WiredHome 3:17928786bdb5 521 char * eoRec = strchr(soRec, '\n'); // search for end of a record
WiredHome 3:17928786bdb5 522
WiredHome 3:17928786bdb5 523 bytecount = strlen(buffer);
WiredHome 3:17928786bdb5 524 if (bytecount > maxheaderbytes)
WiredHome 3:17928786bdb5 525 maxheaderbytes = bytecount;
WiredHome 3:17928786bdb5 526 while (eoRec) {
WiredHome 3:17928786bdb5 527 *eoRec = '\0';
WiredHome 3:17928786bdb5 528 if (*(eoRec-1) == '\r')
WiredHome 3:17928786bdb5 529 *(eoRec-1) = '\0';
WiredHome 3:17928786bdb5 530 if (!Extract(soRec, "*OPEN*", &queryType))
WiredHome 3:17928786bdb5 531 Extract(soRec, "*CLOS*", &queryType);
WiredHome 3:17928786bdb5 532 if (queryType)
WiredHome 3:17928786bdb5 533 Extract(soRec, queryType, &queryString);
WiredHome 3:17928786bdb5 534 Extract(soRec, "Host: ", &hostString);
WiredHome 3:17928786bdb5 535 Extract(soRec, "Content-Length: ", &contentLength);
WiredHome 3:17928786bdb5 536 Extract(soRec, "Content-Type: ", &contentType);
WiredHome 3:17928786bdb5 537 soRec = eoRec + 1;
WiredHome 3:17928786bdb5 538 eoRec = strchr(soRec, '\n');
WiredHome 3:17928786bdb5 539 }
WiredHome 3:17928786bdb5 540 if (queryString) {
WiredHome 3:17928786bdb5 541 // We have enough to try to reply
WiredHome 3:17928786bdb5 542 //pc->printf("create reply queryType{%s}, queryString{%s}\r\n", queryType, queryString);
WiredHome 3:17928786bdb5 543 // parse params - if any
WiredHome 3:17928786bdb5 544 // /file.htm?name1=value1&name2=value2...
WiredHome 3:17928786bdb5 545 // /file.htm?name1&name2=value2...
WiredHome 3:17928786bdb5 546 paramcount = 0;
WiredHome 3:17928786bdb5 547 char * paramDelim = strchr(queryString, '?');
WiredHome 3:17928786bdb5 548 if (paramDelim) {
WiredHome 3:17928786bdb5 549 *paramDelim++ = '\0';
WiredHome 3:17928786bdb5 550 UnescapeString(paramDelim); // everything after the '?'
WiredHome 3:17928786bdb5 551 ParseParameters(paramDelim); // pointing at the NULL, but there are params beyond
WiredHome 3:17928786bdb5 552 }
WiredHome 3:17928786bdb5 553 //for (int i=0; i<paramcount; i++)
WiredHome 3:17928786bdb5 554 // pc->printf("param %d '%s'='%s'\r\n", i, params[i].name, params[i].value);
WiredHome 3:17928786bdb5 555 } else {
WiredHome 3:17928786bdb5 556 pc->printf("not found\r\n");
WiredHome 3:17928786bdb5 557 }
WiredHome 3:17928786bdb5 558 advanceState = true;
WiredHome 3:17928786bdb5 559 buffer[0] = 0;
WiredHome 3:17928786bdb5 560 // bPtr = buffer;
WiredHome 3:17928786bdb5 561
WiredHome 3:17928786bdb5 562 // This part parses the extra data on a POST method.
WiredHome 3:17928786bdb5 563 // Since there has to be a dynamic handler registered for this
WiredHome 3:17928786bdb5 564 // it would make sense to move some of this responsibility to
WiredHome 3:17928786bdb5 565 // that handler. It could then choose if it wanted to allocate
WiredHome 3:17928786bdb5 566 // the requested 'Content-Length' amount of memory.
WiredHome 3:17928786bdb5 567 // Should we check the 'Content-Type' to see if it is
WiredHome 3:17928786bdb5 568 // 'application/x-www-form-urlencoded'?
WiredHome 3:17928786bdb5 569 int postBytes = atoi(contentLength);
WiredHome 3:17928786bdb5 570 bool acceptIt = false;
WiredHome 3:17928786bdb5 571 //pc->printf("Content-Length = %d\r\n", postBytes);
WiredHome 3:17928786bdb5 572 if (strcmp(queryType, "POST") == 0 && postBytes > 0 ) {
WiredHome 3:17928786bdb5 573 if (postBytes) {
WiredHome 3:17928786bdb5 574 bool regHandled = false;
WiredHome 3:17928786bdb5 575 // Registered Dynamic Handler
WiredHome 3:17928786bdb5 576 // Callback and ask if they want to accept this data
WiredHome 3:17928786bdb5 577 for (int i=0; i<handlercount; i++) {
WiredHome 3:17928786bdb5 578 if (strcmp(handlers[i].path, queryString) == 0) {
WiredHome 3:17928786bdb5 579 acceptIt = (*handlers[i].callback)(this, CONTENT_LENGTH_REQUEST, queryString, params, paramcount);
WiredHome 3:17928786bdb5 580 regHandled = true;
WiredHome 3:17928786bdb5 581 break; // we only execute the first one
WiredHome 3:17928786bdb5 582 }
WiredHome 3:17928786bdb5 583 }
WiredHome 3:17928786bdb5 584
WiredHome 3:17928786bdb5 585 if (regHandled && acceptIt) {
WiredHome 3:17928786bdb5 586 // If so, we'll make space for it
WiredHome 3:17928786bdb5 587 postQueryString = (char *)malloc(postBytes + 1);
WiredHome 3:17928786bdb5 588 if (postQueryString) {
WiredHome 3:17928786bdb5 589 char * offset;
WiredHome 3:17928786bdb5 590 int len;
WiredHome 3:17928786bdb5 591
WiredHome 3:17928786bdb5 592 dblCR += 4; // If we slurped up any of the POST,
WiredHome 3:17928786bdb5 593 while (*dblCR && *dblCR <= ' ')
WiredHome 3:17928786bdb5 594 dblCR++;
WiredHome 3:17928786bdb5 595 strcpy(postQueryString, dblCR); // copy that in and then get the rest
WiredHome 3:17928786bdb5 596 while ((len = strlen(postQueryString)) < postBytes) {
WiredHome 3:17928786bdb5 597 int n;
WiredHome 3:17928786bdb5 598 offset = postQueryString + len;
WiredHome 3:17928786bdb5 599 n = client.receive(offset, postBytes - len);
WiredHome 3:17928786bdb5 600 if (n >=0) {
WiredHome 3:17928786bdb5 601 offset[n] = '\0';
WiredHome 3:17928786bdb5 602 }
WiredHome 3:17928786bdb5 603 }
WiredHome 3:17928786bdb5 604 if (len >= 0) {
WiredHome 3:17928786bdb5 605 UnescapeString(postQueryString);
WiredHome 3:17928786bdb5 606 ParseParameters(postQueryString);
WiredHome 3:17928786bdb5 607 }
WiredHome 3:17928786bdb5 608 }
WiredHome 3:17928786bdb5 609 } else {
WiredHome 3:17928786bdb5 610 // Simply copy it to the bitbucket
WiredHome 3:17928786bdb5 611 int bytesToDump = postBytes;
WiredHome 3:17928786bdb5 612 char * bitbucket = (char *)malloc(201);
WiredHome 3:17928786bdb5 613 dblCR += 4;
WiredHome 3:17928786bdb5 614 while (*dblCR && *dblCR <= ' ')
WiredHome 3:17928786bdb5 615 dblCR++;
WiredHome 3:17928786bdb5 616 bytesToDump -= strlen(dblCR);
WiredHome 3:17928786bdb5 617 while (bytesToDump > 0) {
WiredHome 3:17928786bdb5 618 int n = (bytesToDump > 200) ? 200 : bytesToDump;
WiredHome 3:17928786bdb5 619 n = client.receive(bitbucket, n);
WiredHome 3:17928786bdb5 620 bytesToDump -= n;
WiredHome 3:17928786bdb5 621 }
WiredHome 3:17928786bdb5 622 free(bitbucket);
WiredHome 3:17928786bdb5 623 }
WiredHome 3:17928786bdb5 624 }
WiredHome 3:17928786bdb5 625 }
WiredHome 3:17928786bdb5 626 }
WiredHome 3:17928786bdb5 627 return advanceState;
WiredHome 3:17928786bdb5 628 }
WiredHome 3:17928786bdb5 629
WiredHome 3:17928786bdb5 630 void HTTPServer::GetPerformanceData(SW_PerformanceData * p) {
WiredHome 3:17928786bdb5 631 memcpy(p, &perfData, sizeof(perfData));
WiredHome 3:17928786bdb5 632 }
WiredHome 3:17928786bdb5 633
WiredHome 3:17928786bdb5 634 int HTTPServer::RecordPerformanceData(SW_PerformanceParam * param, int refTime) {
WiredHome 3:17928786bdb5 635 int t_now = timer.read_us();
WiredHome 3:17928786bdb5 636 param->TotalTime_us += (t_now - refTime);
WiredHome 3:17928786bdb5 637 param->Samples++;
WiredHome 3:17928786bdb5 638 if ((t_now - refTime) > param->MaxTime_us)
WiredHome 3:17928786bdb5 639 param->MaxTime_us = (t_now - refTime);
WiredHome 3:17928786bdb5 640 return t_now;
WiredHome 3:17928786bdb5 641 }
WiredHome 3:17928786bdb5 642
WiredHome 3:17928786bdb5 643 void HTTPServer::ResetPerformanceData() {
WiredHome 3:17928786bdb5 644 memset(&perfData, 0, sizeof(perfData));
WiredHome 3:17928786bdb5 645 }
WiredHome 3:17928786bdb5 646
WiredHome 4:f34642902056 647