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:
Fri May 31 03:13:39 2013 +0000
Revision:
0:729320f63c5c
Child:
2:a29c32190037
First viable version of the Smartware HTTP Server. It handles static and dynamic pages, GET and POST methods.

Who changed what in which revision?

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