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:
Mon Jun 24 20:02:01 2013 +0000
Revision:
3:17928786bdb5
Parent:
2:a29c32190037
Child:
4:f34642902056
Revise so buffer allocations are alterable
; Refactor Poll() for maintenance
; Diagnostics:
; GetMaxHeaderSize() to size the buffer
; GetPerformanceData() Get Metrics
; ResetPerformanceData()

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 0:729320f63c5c 315 void HTTPServer::GetRemoteAddr(char * str, int size)
WiredHome 0:729320f63c5c 316 {
WiredHome 0:729320f63c5c 317 bool res = false;
WiredHome 0:729320f63c5c 318 char *p;
WiredHome 0:729320f63c5c 319
WiredHome 3:17928786bdb5 320 if (size < 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 3:17928786bdb5 324 res = wifly->sendCommand("show z\r", "NO", str, 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