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:
Sun Jun 02 18:32:05 2013 +0000
Revision:
2:a29c32190037
Parent:
0:729320f63c5c
Child:
3:17928786bdb5
turned off debug

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