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 May 11 21:16:42 2014 +0000
Revision:
37:0cb2774e2410
Parent:
36:1bb5fa6b109c
Child:
38:c8fa31e6fe02
Enhanced to support POST as well as GET methods.

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 29:00116fc9da74 14
WiredHome 36:1bb5fa6b109c 15 //#define DEBUG "HTTP"
WiredHome 33:ef165a67ab22 16 #include "Utility.h"
WiredHome 33:ef165a67ab22 17
WiredHome 31:8f72be717a3c 18 #include "SW_HTTPServer.h" // define DEBUG before this
WiredHome 27:90a1f5a5392f 19
WiredHome 33:ef165a67ab22 20 #define CHUNK_SIZE 1500 // max size of a single chunk (probably limited by Ethernet to 1500)
WiredHome 33:ef165a67ab22 21 #define HANG_TIMEOUT_MS 250 // If we're waiting on the host, which may never respond, this is the timeout
WiredHome 0:729320f63c5c 22
WiredHome 0:729320f63c5c 23 const char * DEFAULT_FILENAME = "index.htm";
WiredHome 0:729320f63c5c 24
WiredHome 8:262583f054f6 25 // Header information to always send (must be \r\n terminated)
WiredHome 17:69ff00ce39f4 26 const char hdr_httpver[] = "HTTP/1.0"; // Wifly may not be able to support HTTP/1.1 protocol
WiredHome 8:262583f054f6 27 const char hdr_age[] = "Max-age: 0\r\n"; // expires right away
WiredHome 8:262583f054f6 28 const char hdr_server[] = "Server: Smart_Server v0.1\r\n"; // Server
WiredHome 17:69ff00ce39f4 29 const char hdr_close[] = "Connection: close\r\n"; // tell the client the server closes the connection immediately
WiredHome 8:262583f054f6 30 const char nl[] = "\r\n"; // final \r\n for the termination of the header
WiredHome 0:729320f63c5c 31
WiredHome 14:19c5f6151319 32
WiredHome 0:729320f63c5c 33 static const struct {
WiredHome 0:729320f63c5c 34 char *ext;
WiredHome 0:729320f63c5c 35 char *filetype;
WiredHome 0:729320f63c5c 36 } extensions [] = {
WiredHome 3:17928786bdb5 37 {".gif", "Content-Type: image/gif\r\n" },
WiredHome 3:17928786bdb5 38 {".jpg", "Content-Type: image/jpeg\r\n" },
WiredHome 3:17928786bdb5 39 {".jpeg","Content-Type: image/jpeg\r\n" },
WiredHome 3:17928786bdb5 40 {".ico", "Content-Type: image/x-icon\r\n" },
WiredHome 33:ef165a67ab22 41 {".bmp", "Content-Type: image/bmp\r\n" },
WiredHome 3:17928786bdb5 42 {".png", "Content-Type: image/png\r\n" },
WiredHome 3:17928786bdb5 43 {".zip", "Content-Type: image/zip\r\n" },
WiredHome 3:17928786bdb5 44 {".gz", "Content-Type: image/gz\r\n" },
WiredHome 3:17928786bdb5 45 {".tar", "Content-Type: image/tar\r\n" },
WiredHome 3:17928786bdb5 46 {".txt", "Content-Type: plain/text\r\n" },
WiredHome 3:17928786bdb5 47 {".pdf", "Content-Type: application/pdf\r\n" },
WiredHome 3:17928786bdb5 48 {".htm", "Content-Type: text/html\r\n" },
WiredHome 3:17928786bdb5 49 {".html","Content-Type: text/html\r\n" },
WiredHome 0:729320f63c5c 50 {0,0}
WiredHome 0:729320f63c5c 51 };
WiredHome 0:729320f63c5c 52
WiredHome 30:864843965b40 53 #if 0 && defined(DEBUG)
WiredHome 30:864843965b40 54 // Haven't learned anything from this in a long time, so disabled.
WiredHome 12:109bf1558300 55 // This uses standard library dynamic memory management, but for an
WiredHome 9:2ea342765c9d 56 // embedded system there are alternates that may make better sense -
WiredHome 9:2ea342765c9d 57 // search the web for embedded system malloc alternates.
WiredHome 29:00116fc9da74 58 void * HTTPServer::MyMalloc(int x, int y)
WiredHome 8:262583f054f6 59 {
WiredHome 29:00116fc9da74 60 pc->printf("[INF HTTP%4d] malloc(%d)\r\n", y, x);
WiredHome 8:262583f054f6 61 return malloc(x);
WiredHome 8:262583f054f6 62 }
WiredHome 29:00116fc9da74 63 char HTTPServer::toP(void * x)
WiredHome 11:17d84c41a7b3 64 {
WiredHome 11:17d84c41a7b3 65 char * c = (char *) x;
WiredHome 30:864843965b40 66 if (*c >= ' ' && *c < 0x7F) // isprint()
WiredHome 11:17d84c41a7b3 67 return *c;
WiredHome 11:17d84c41a7b3 68 else
WiredHome 11:17d84c41a7b3 69 return '.';
WiredHome 11:17d84c41a7b3 70 }
WiredHome 8:262583f054f6 71 #define mymalloc(x) MyMalloc(x, __LINE__)
WiredHome 8:262583f054f6 72 #define myfree(x) \
WiredHome 25:f7d6df7a700a 73 pc->printf("[INF HTTP%4d] free(%02x %02x %02x %02x %02x ... %c%c%c%c%c)\r\n", __LINE__, \
WiredHome 11:17d84c41a7b3 74 *x, *(x+1), *(x+2), *(x+3), *(x+4), \
WiredHome 11:17d84c41a7b3 75 toP(x), toP(x+1), toP(x+2), toP(x+3), toP(x+4) ); \
WiredHome 8:262583f054f6 76 free(x);
WiredHome 8:262583f054f6 77 #else
WiredHome 8:262583f054f6 78 #define mymalloc(x) malloc(x)
WiredHome 8:262583f054f6 79 #define myfree(x) free(x)
WiredHome 8:262583f054f6 80 #endif
WiredHome 8:262583f054f6 81
WiredHome 3:17928786bdb5 82 HTTPServer::HTTPServer(
WiredHome 7:99ad7a67f05e 83 Wifly * _wf,
WiredHome 7:99ad7a67f05e 84 int port,
WiredHome 7:99ad7a67f05e 85 const char * _webroot,
WiredHome 13:8975d7928678 86 int maxheaderParams,
WiredHome 13:8975d7928678 87 int _maxqueryParams,
WiredHome 7:99ad7a67f05e 88 int _maxdynamicpages,
WiredHome 7:99ad7a67f05e 89 PC * _pc,
WiredHome 7:99ad7a67f05e 90 int _allocforheader,
WiredHome 3:17928786bdb5 91 int _allocforfile)
WiredHome 0:729320f63c5c 92 {
WiredHome 0:729320f63c5c 93 wifly = _wf;
WiredHome 0:729320f63c5c 94 webroot = (char *)malloc(strlen(_webroot)+1);
WiredHome 0:729320f63c5c 95 strcpy(webroot, _webroot);
WiredHome 27:90a1f5a5392f 96 if (strlen(webroot)>1 && webroot[strlen(webroot)-1] == '/') // remove trailing '/'
WiredHome 27:90a1f5a5392f 97 webroot[strlen(webroot)-1] = '\0';
WiredHome 13:8975d7928678 98 maxqueryParams = _maxqueryParams;
WiredHome 0:729320f63c5c 99 maxdynamicpages = _maxdynamicpages;
WiredHome 13:8975d7928678 100 headerParams = (namevalue *)malloc(maxheaderParams * sizeof(namevalue));
WiredHome 13:8975d7928678 101 queryParams = (namevalue *)malloc(maxqueryParams * sizeof(namevalue));
WiredHome 0:729320f63c5c 102 handlers = (handler *)malloc(maxdynamicpages * sizeof(handler));
WiredHome 3:17928786bdb5 103 headerbuffersize = _allocforheader;
WiredHome 3:17928786bdb5 104 headerbuffer = (char *)malloc(headerbuffersize);
WiredHome 0:729320f63c5c 105 pc = _pc;
WiredHome 3:17928786bdb5 106 queryType = NULL;
WiredHome 3:17928786bdb5 107 queryString = NULL;
WiredHome 3:17928786bdb5 108 postQueryString = NULL;
WiredHome 13:8975d7928678 109 queryParamCount = 0;
WiredHome 0:729320f63c5c 110 handlercount = 0;
WiredHome 3:17928786bdb5 111 maxheaderbytes = 0;
WiredHome 0:729320f63c5c 112 server = new TCPSocketServer();
WiredHome 0:729320f63c5c 113 server->bind(port);
WiredHome 0:729320f63c5c 114 server->listen();
WiredHome 16:6ebacf2946d8 115 server->set_blocking(false, 10);
WiredHome 33:ef165a67ab22 116 client.set_blocking(false, 100); //@TODO client is separate from server. any way to combine?
WiredHome 3:17928786bdb5 117 ResetPerformanceData();
WiredHome 10:9c8d2c6a3469 118 PerformanceTimer.start();
WiredHome 0:729320f63c5c 119 }
WiredHome 0:729320f63c5c 120
WiredHome 0:729320f63c5c 121 HTTPServer::~HTTPServer()
WiredHome 0:729320f63c5c 122 {
WiredHome 8:262583f054f6 123 int i;
WiredHome 8:262583f054f6 124
WiredHome 8:262583f054f6 125 for (i=0; i<handlercount; i++)
WiredHome 8:262583f054f6 126 myfree(handlers[i].path);
WiredHome 8:262583f054f6 127 myfree(headerbuffer);
WiredHome 8:262583f054f6 128 myfree(handlers);
WiredHome 13:8975d7928678 129 myfree(queryParams);
WiredHome 8:262583f054f6 130 myfree(webroot);
WiredHome 0:729320f63c5c 131 webroot = NULL;
WiredHome 0:729320f63c5c 132 }
WiredHome 0:729320f63c5c 133
WiredHome 3:17928786bdb5 134 int HTTPServer::GetMaxHeaderSize()
WiredHome 3:17928786bdb5 135 {
WiredHome 3:17928786bdb5 136 return maxheaderbytes;
WiredHome 3:17928786bdb5 137 }
WiredHome 3:17928786bdb5 138
WiredHome 0:729320f63c5c 139 bool HTTPServer::RegisterHandler(const char * path, Handler callback)
WiredHome 0:729320f63c5c 140 {
WiredHome 0:729320f63c5c 141 if (handlercount < maxdynamicpages && path && callback) {
WiredHome 8:262583f054f6 142 handlers[handlercount].path = (char *)mymalloc(strlen(path)+1);
WiredHome 0:729320f63c5c 143 memcpy(handlers[handlercount].path, path, strlen(path)+1);
WiredHome 0:729320f63c5c 144 handlers[handlercount].callback = callback;
WiredHome 0:729320f63c5c 145 handlercount++;
WiredHome 0:729320f63c5c 146 return true;
WiredHome 0:729320f63c5c 147 } else {
WiredHome 0:729320f63c5c 148 return false;
WiredHome 0:729320f63c5c 149 }
WiredHome 0:729320f63c5c 150 }
WiredHome 0:729320f63c5c 151
WiredHome 2:a29c32190037 152 // Poll()
WiredHome 0:729320f63c5c 153 //
WiredHome 0:729320f63c5c 154 // *OPEN*GET /x=1 HTTP/1.1
WiredHome 0:729320f63c5c 155 // Host: 192.168.1.140
WiredHome 0:729320f63c5c 156 // Connection: keep-alive
WiredHome 0:729320f63c5c 157 // Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
WiredHome 0:729320f63c5c 158 // 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 159 // Accept-Encoding: gzip,deflate,sdch
WiredHome 0:729320f63c5c 160 // Accept-Language: en-US,en;q=0.8
WiredHome 0:729320f63c5c 161 //
WiredHome 2:a29c32190037 162 void HTTPServer::Poll()
WiredHome 0:729320f63c5c 163 {
WiredHome 3:17928786bdb5 164 typedef enum {
WiredHome 3:17928786bdb5 165 Idle, // waiting for a connection
WiredHome 29:00116fc9da74 166 ReceivingHeader, // receiving header
WiredHome 29:00116fc9da74 167 ReceivingPayload, // receiving a section after the Header
WiredHome 3:17928786bdb5 168 Sending, // send the response
WiredHome 7:99ad7a67f05e 169 WaitingToClose, // small timeout to close
WiredHome 7:99ad7a67f05e 170 Reset
WiredHome 3:17928786bdb5 171 } state;
WiredHome 0:729320f63c5c 172 static state op = Idle;
WiredHome 3:17928786bdb5 173 static char * bPtr = headerbuffer;
WiredHome 0:729320f63c5c 174 int n;
WiredHome 16:6ebacf2946d8 175 static unsigned int t_ref; // reference point for the PerformanceTimer
WiredHome 0:729320f63c5c 176
WiredHome 20:786aa5749007 177 #if defined(DEBUG)
WiredHome 8:262583f054f6 178 static state lastOp = Reset;
WiredHome 7:99ad7a67f05e 179 if (lastOp != op) {
WiredHome 29:00116fc9da74 180 const char *states[] = {"Idle", "ReceivingHeader", "ReceivingPayload", "Sending", "WaitingToClose", "Reset"};
WiredHome 27:90a1f5a5392f 181 INFO("Poll: %s", states[op]);
WiredHome 7:99ad7a67f05e 182 lastOp = op;
WiredHome 7:99ad7a67f05e 183 }
WiredHome 8:262583f054f6 184 #endif
WiredHome 0:729320f63c5c 185 switch(op) {
WiredHome 3:17928786bdb5 186 default: // not expected to arrive here
WiredHome 3:17928786bdb5 187 op = Idle;
WiredHome 3:17928786bdb5 188 break;
WiredHome 8:262583f054f6 189
WiredHome 3:17928786bdb5 190 case Idle:
WiredHome 10:9c8d2c6a3469 191 PerformanceTimer.reset();
WiredHome 17:69ff00ce39f4 192 t_ref = (unsigned int)PerformanceTimer.read_us();
WiredHome 3:17928786bdb5 193 bPtr = headerbuffer;
WiredHome 11:17d84c41a7b3 194 if (0 == server->accept(client)) {
WiredHome 29:00116fc9da74 195 op = ReceivingHeader;
WiredHome 17:69ff00ce39f4 196 t_ref = RecordPerformanceData(&perfData.ConnectionAccepted, t_ref);
WiredHome 27:90a1f5a5392f 197 INFO("Accepted at %u", (unsigned int)PerformanceTimer.read_us());
WiredHome 3:17928786bdb5 198 }
WiredHome 0:729320f63c5c 199 break;
WiredHome 8:262583f054f6 200
WiredHome 29:00116fc9da74 201 case ReceivingHeader:
WiredHome 3:17928786bdb5 202 n = client.receive(bPtr, headerbuffersize - (bPtr - headerbuffer));
WiredHome 3:17928786bdb5 203 if (n < 0) {
WiredHome 29:00116fc9da74 204 op = Sending;
WiredHome 27:90a1f5a5392f 205 INFO("*** client.receive() => %d", n);
WiredHome 3:17928786bdb5 206 } else if (n) {
WiredHome 3:17928786bdb5 207 bPtr[n] = '\0';
WiredHome 29:00116fc9da74 208 switch (ParseHeader(headerbuffer)) {
WiredHome 29:00116fc9da74 209 case ACCEPT_ERROR:
WiredHome 29:00116fc9da74 210 break;
WiredHome 29:00116fc9da74 211 case ACCEPT_COMPLETE:
WiredHome 29:00116fc9da74 212 op = Sending;
WiredHome 29:00116fc9da74 213 t_ref = RecordPerformanceData(&perfData.HeaderParsed, t_ref);
WiredHome 29:00116fc9da74 214 INFO("Header Parsed at %u", (unsigned int)PerformanceTimer.read_us());
WiredHome 29:00116fc9da74 215 break;
WiredHome 29:00116fc9da74 216 case ACCEPT_CONTINUE:
WiredHome 29:00116fc9da74 217 op = ReceivingPayload;
WiredHome 29:00116fc9da74 218 break;
WiredHome 3:17928786bdb5 219 }
WiredHome 3:17928786bdb5 220 bPtr += n;
WiredHome 0:729320f63c5c 221 }
WiredHome 0:729320f63c5c 222 break;
WiredHome 8:262583f054f6 223
WiredHome 29:00116fc9da74 224 case ReceivingPayload:
WiredHome 29:00116fc9da74 225 // After the header, there is a payload that will be handled
WiredHome 33:ef165a67ab22 226 #if 1
WiredHome 33:ef165a67ab22 227 n = client.receive(bPtr, headerbuffersize - (bPtr - headerbuffer));
WiredHome 33:ef165a67ab22 228 if (n < 0) {
WiredHome 33:ef165a67ab22 229 op = Sending;
WiredHome 33:ef165a67ab22 230 INFO("*** client.receive() => %d", n);
WiredHome 33:ef165a67ab22 231 } else if (n) {
WiredHome 33:ef165a67ab22 232 bPtr[n] = '\0';
WiredHome 33:ef165a67ab22 233 INFO("*** payload size %d", n);
WiredHome 33:ef165a67ab22 234 }
WiredHome 33:ef165a67ab22 235 #else
WiredHome 29:00116fc9da74 236 op = Sending;
WiredHome 33:ef165a67ab22 237 #endif
WiredHome 29:00116fc9da74 238 break;
WiredHome 29:00116fc9da74 239
WiredHome 0:729320f63c5c 240 case Sending:
WiredHome 3:17928786bdb5 241 SendResponse();
WiredHome 0:729320f63c5c 242 op = WaitingToClose;
WiredHome 17:69ff00ce39f4 243 t_ref = RecordPerformanceData(&perfData.ResponseSent, t_ref);
WiredHome 27:90a1f5a5392f 244 INFO("Response Sent at %u", (unsigned int)PerformanceTimer.read_us());
WiredHome 0:729320f63c5c 245 break;
WiredHome 9:2ea342765c9d 246
WiredHome 0:729320f63c5c 247 case WaitingToClose:
WiredHome 27:90a1f5a5392f 248 INFO("Connection closed entry %u", (unsigned int)PerformanceTimer.read_us());
WiredHome 3:17928786bdb5 249 close_connection();
WiredHome 0:729320f63c5c 250 op = Idle;
WiredHome 17:69ff00ce39f4 251 RecordPerformanceData(&perfData.ConnectionClosed, t_ref);
WiredHome 27:90a1f5a5392f 252 INFO("Connection closed exit %u", (unsigned int)PerformanceTimer.read_us());
WiredHome 0:729320f63c5c 253 break;
WiredHome 0:729320f63c5c 254 }
WiredHome 0:729320f63c5c 255 }
WiredHome 0:729320f63c5c 256
WiredHome 0:729320f63c5c 257
WiredHome 0:729320f63c5c 258 const char * HTTPServer::GetSupportedType(const char * filename)
WiredHome 0:729320f63c5c 259 {
WiredHome 0:729320f63c5c 260 int i;
WiredHome 0:729320f63c5c 261 int buflen = strlen(filename);
WiredHome 0:729320f63c5c 262 int extlen;
WiredHome 0:729320f63c5c 263
WiredHome 0:729320f63c5c 264 for (i=0; extensions[i].ext != 0; i++) {
WiredHome 0:729320f63c5c 265 extlen = strlen(extensions[i].ext);
WiredHome 0:729320f63c5c 266 if ( !strncmp(&filename[buflen-extlen], extensions[i].ext, extlen)) {
WiredHome 0:729320f63c5c 267 return extensions[i].filetype;
WiredHome 0:729320f63c5c 268 }
WiredHome 0:729320f63c5c 269 }
WiredHome 0:729320f63c5c 270 return NULL;
WiredHome 0:729320f63c5c 271 }
WiredHome 0:729320f63c5c 272
WiredHome 3:17928786bdb5 273
WiredHome 0:729320f63c5c 274 void HTTPServer::send(const char * msg, int bytes)
WiredHome 0:729320f63c5c 275 {
WiredHome 0:729320f63c5c 276 if (bytes == -1)
WiredHome 0:729320f63c5c 277 bytes = strlen(msg);
WiredHome 20:786aa5749007 278 client.send((char *)msg, bytes);
WiredHome 0:729320f63c5c 279 }
WiredHome 0:729320f63c5c 280
WiredHome 3:17928786bdb5 281
WiredHome 0:729320f63c5c 282 bool HTTPServer::SendFile(const char * filename, const char * filetype)
WiredHome 0:729320f63c5c 283 {
WiredHome 0:729320f63c5c 284 FILE * fp;
WiredHome 3:17928786bdb5 285
WiredHome 0:729320f63c5c 286 fp = fopen(filename,"rb");
WiredHome 0:729320f63c5c 287 if (fp) { // can open it
WiredHome 8:262583f054f6 288 char *fbuffer = (char *)mymalloc(FILESEND_BUF_SIZE);
WiredHome 0:729320f63c5c 289 int bytes;
WiredHome 0:729320f63c5c 290
WiredHome 3:17928786bdb5 291 if (fbuffer) {
WiredHome 3:17928786bdb5 292 header(200, "OK", filetype);
WiredHome 0:729320f63c5c 293 bytes = fread(fbuffer,sizeof(char),FILESEND_BUF_SIZE,fp);
WiredHome 3:17928786bdb5 294 while (bytes > 0) {
WiredHome 3:17928786bdb5 295 send(fbuffer, bytes);
WiredHome 3:17928786bdb5 296 bytes = fread(fbuffer,sizeof(char),FILESEND_BUF_SIZE,fp);
WiredHome 3:17928786bdb5 297 }
WiredHome 8:262583f054f6 298 myfree(fbuffer);
WiredHome 3:17928786bdb5 299 } else {
WiredHome 3:17928786bdb5 300 header(500, "Server Error", "Pragma: err - insufficient memory\r\n");
WiredHome 0:729320f63c5c 301 }
WiredHome 0:729320f63c5c 302 fclose(fp);
WiredHome 0:729320f63c5c 303 return true;
WiredHome 0:729320f63c5c 304 } else {
WiredHome 3:17928786bdb5 305 header(404, "Not Found", "Pragma: err - Can't open file\r\n");
WiredHome 0:729320f63c5c 306 return false;
WiredHome 0:729320f63c5c 307 }
WiredHome 0:729320f63c5c 308 }
WiredHome 0:729320f63c5c 309
WiredHome 0:729320f63c5c 310 int HTTPServer::HexCharToInt(char c)
WiredHome 0:729320f63c5c 311 {
WiredHome 0:729320f63c5c 312 if (c >= 'a' && c <= 'f')
WiredHome 0:729320f63c5c 313 return (c - 'a' + 10);
WiredHome 0:729320f63c5c 314 else if (c >= 'A' && c <= 'F')
WiredHome 0:729320f63c5c 315 return (c - 'A' + 10);
WiredHome 0:729320f63c5c 316 else if (c >= '0' && c <= '9')
WiredHome 0:729320f63c5c 317 return c - '0';
WiredHome 0:729320f63c5c 318 else
WiredHome 0:729320f63c5c 319 return 0;
WiredHome 0:729320f63c5c 320 }
WiredHome 0:729320f63c5c 321
WiredHome 0:729320f63c5c 322 char HTTPServer::HexPairToChar(char * p)
WiredHome 0:729320f63c5c 323 {
WiredHome 0:729320f63c5c 324 return 16 * HexCharToInt(*p) + HexCharToInt(*(p+1));
WiredHome 0:729320f63c5c 325 }
WiredHome 0:729320f63c5c 326
WiredHome 0:729320f63c5c 327 void HTTPServer::UnescapeString(char * encoded)
WiredHome 0:729320f63c5c 328 {
WiredHome 0:729320f63c5c 329 char *p;
WiredHome 0:729320f63c5c 330
WiredHome 0:729320f63c5c 331 // first convert '+' to ' '
WiredHome 0:729320f63c5c 332 p = strchr(encoded, '+');
WiredHome 0:729320f63c5c 333 while (p) {
WiredHome 0:729320f63c5c 334 *p = ' ';
WiredHome 0:729320f63c5c 335 p = strchr(encoded, '+');
WiredHome 0:729320f63c5c 336 }
WiredHome 0:729320f63c5c 337 // then convert hex '%xx' to char 'x'
WiredHome 0:729320f63c5c 338 p = strchr(encoded, '%');
WiredHome 0:729320f63c5c 339 while (p) {
WiredHome 0:729320f63c5c 340 if (strchr("0123456789ABCDEFabcdef", *(p+1))
WiredHome 0:729320f63c5c 341 && strchr("0123456789ABCDEFabcdef", *(p+2)) ) {
WiredHome 0:729320f63c5c 342 *p = HexPairToChar(p+1);
WiredHome 0:729320f63c5c 343 p++; // advance past the %
WiredHome 0:729320f63c5c 344 char * a = p;
WiredHome 0:729320f63c5c 345 char * b = p + 2;
WiredHome 0:729320f63c5c 346 do {
WiredHome 0:729320f63c5c 347 *a++ = *b++;
WiredHome 0:729320f63c5c 348 } while (*b);
WiredHome 0:729320f63c5c 349 *a = '\0';
WiredHome 0:729320f63c5c 350 }
WiredHome 0:729320f63c5c 351 p = strchr(p, '%');
WiredHome 0:729320f63c5c 352 }
WiredHome 0:729320f63c5c 353 }
WiredHome 0:729320f63c5c 354
WiredHome 0:729320f63c5c 355 const char * HTTPServer::GetParameter(const char * name)
WiredHome 0:729320f63c5c 356 {
WiredHome 37:0cb2774e2410 357 INFO("GetParameter(%s)", name);
WiredHome 13:8975d7928678 358 for (int i=0; i<queryParamCount; i++) {
WiredHome 37:0cb2774e2410 359 INFO(" %d: %s = %s", i, queryParams[i].name, queryParams[i].value);
WiredHome 13:8975d7928678 360 if (strcmp(queryParams[i].name, name) == 0) {
WiredHome 37:0cb2774e2410 361 INFO(" value {%s}", queryParams[i].value);
WiredHome 13:8975d7928678 362 return queryParams[i].value;
WiredHome 0:729320f63c5c 363 }
WiredHome 0:729320f63c5c 364 }
WiredHome 0:729320f63c5c 365 return NULL;
WiredHome 0:729320f63c5c 366 }
WiredHome 0:729320f63c5c 367
WiredHome 37:0cb2774e2410 368
WiredHome 0:729320f63c5c 369 // this=that&who=what&more=stuff...
WiredHome 0:729320f63c5c 370 // ^ ^ ^
WiredHome 37:0cb2774e2410 371 int HTTPServer::ParseParameters(char * pName)
WiredHome 0:729320f63c5c 372 {
WiredHome 0:729320f63c5c 373 char * pVal;
WiredHome 0:729320f63c5c 374 char * pNextName;
WiredHome 0:729320f63c5c 375
WiredHome 13:8975d7928678 376 // Parse queryParams
WiredHome 0:729320f63c5c 377 pVal = strchr(pName, '#'); // If there is a '#fragment_id', we can ignore it
WiredHome 0:729320f63c5c 378 if (pVal)
WiredHome 3:17928786bdb5 379 *pVal = '\0';
WiredHome 0:729320f63c5c 380 do {
WiredHome 37:0cb2774e2410 381 INFO("ParseParameters(%s)", pName);
WiredHome 13:8975d7928678 382 queryParams[queryParamCount].name = pName;
WiredHome 0:729320f63c5c 383 pVal = strchr(pName, '=');
WiredHome 0:729320f63c5c 384 pNextName = strchr(pName,'&');
WiredHome 0:729320f63c5c 385 if (pVal) {
WiredHome 0:729320f63c5c 386 if (pNextName == NULL || (pNextName && pNextName > pVal)) {
WiredHome 0:729320f63c5c 387 *pVal++ = '\0';
WiredHome 13:8975d7928678 388 queryParams[queryParamCount].value = pVal;
WiredHome 0:729320f63c5c 389 pName = pVal;
WiredHome 0:729320f63c5c 390 }
WiredHome 0:729320f63c5c 391 }
WiredHome 0:729320f63c5c 392 if (pNextName) {
WiredHome 0:729320f63c5c 393 pName = pNextName;
WiredHome 0:729320f63c5c 394 *pName++ = '\0';
WiredHome 0:729320f63c5c 395 } else {
WiredHome 0:729320f63c5c 396 pName = NULL;
WiredHome 0:729320f63c5c 397 }
WiredHome 37:0cb2774e2410 398 INFO(" param{%s}={%s}", queryParams[queryParamCount].name, queryParams[queryParamCount].value);
WiredHome 37:0cb2774e2410 399 queryParamCount++;
WiredHome 13:8975d7928678 400 } while (pName && queryParamCount < maxqueryParams);
WiredHome 37:0cb2774e2410 401 INFO(" count %d", queryParamCount);
WiredHome 37:0cb2774e2410 402 return queryParamCount;
WiredHome 0:729320f63c5c 403 }
WiredHome 0:729320f63c5c 404
WiredHome 0:729320f63c5c 405
WiredHome 0:729320f63c5c 406 void HTTPServer::header(int code, const char * code_text, const char * content_type, const char * optional_text)
WiredHome 0:729320f63c5c 407 {
WiredHome 0:729320f63c5c 408 char http[100];
WiredHome 0:729320f63c5c 409
WiredHome 0:729320f63c5c 410 sprintf(http, "%s %i %s\r\n", hdr_httpver, code, code_text);
WiredHome 0:729320f63c5c 411 send(http);
WiredHome 0:729320f63c5c 412 send(hdr_age);
WiredHome 0:729320f63c5c 413 send(hdr_server);
WiredHome 0:729320f63c5c 414 if (content_type) {
WiredHome 0:729320f63c5c 415 send(content_type);
WiredHome 0:729320f63c5c 416 }
WiredHome 0:729320f63c5c 417 if (optional_text) {
WiredHome 0:729320f63c5c 418 send(optional_text);
WiredHome 0:729320f63c5c 419 }
WiredHome 0:729320f63c5c 420 send(hdr_close);
WiredHome 0:729320f63c5c 421 send(nl);
WiredHome 0:729320f63c5c 422 }
WiredHome 0:729320f63c5c 423
WiredHome 14:19c5f6151319 424
WiredHome 7:99ad7a67f05e 425 bool HTTPServer::close_connection()
WiredHome 0:729320f63c5c 426 {
WiredHome 7:99ad7a67f05e 427 bool res;
WiredHome 7:99ad7a67f05e 428
WiredHome 14:19c5f6151319 429 res = server->close();
WiredHome 27:90a1f5a5392f 430 INFO("close connection returned %d", res);
WiredHome 7:99ad7a67f05e 431 return res;
WiredHome 0:729320f63c5c 432 }
WiredHome 0:729320f63c5c 433
WiredHome 14:19c5f6151319 434
WiredHome 0:729320f63c5c 435 bool HTTPServer::Extract(char * haystack, char * needle, char ** string)
WiredHome 0:729320f63c5c 436 {
WiredHome 0:729320f63c5c 437 bool ret = false; // assume failure until proven otherwise
WiredHome 0:729320f63c5c 438 char * qs = NULL;
WiredHome 0:729320f63c5c 439 char * eqs = NULL;
WiredHome 0:729320f63c5c 440 char * container = NULL;
WiredHome 0:729320f63c5c 441 char * get = strstr(haystack, needle); // what if not at the front?
WiredHome 0:729320f63c5c 442 if (get) {
WiredHome 0:729320f63c5c 443 // Seems to be a valid "...GET /QueryString HTTP/1.1"
WiredHome 8:262583f054f6 444 // or "...<needle>param..."
WiredHome 0:729320f63c5c 445 qs = get + strlen(needle); // in case the needle didn't have space delimiters
WiredHome 0:729320f63c5c 446 while (*qs == ' ')
WiredHome 0:729320f63c5c 447 qs++;
WiredHome 0:729320f63c5c 448 // /QueryString\0HTTP/1.1\0\0
WiredHome 0:729320f63c5c 449 if (*string) // recycle old string when working a new one
WiredHome 8:262583f054f6 450 myfree(*string);
WiredHome 8:262583f054f6 451 container = (char *)mymalloc(strlen(qs));
WiredHome 0:729320f63c5c 452 if (container) {
WiredHome 0:729320f63c5c 453 strcpy(container, qs);
WiredHome 0:729320f63c5c 454 eqs = strchr(container, ' ');
WiredHome 0:729320f63c5c 455 if (eqs)
WiredHome 0:729320f63c5c 456 *eqs = '\0';
WiredHome 0:729320f63c5c 457 *string = container;
WiredHome 27:90a1f5a5392f 458 INFO("Extract(%s) = %s", needle, container);
WiredHome 0:729320f63c5c 459 ret = true;
WiredHome 0:729320f63c5c 460 } else {
WiredHome 0:729320f63c5c 461 *string = NULL; // something bad happened... no memory
WiredHome 0:729320f63c5c 462 }
WiredHome 0:729320f63c5c 463 }
WiredHome 0:729320f63c5c 464 return ret;
WiredHome 0:729320f63c5c 465 }
WiredHome 0:729320f63c5c 466
WiredHome 14:19c5f6151319 467
WiredHome 0:729320f63c5c 468 char * HTTPServer::rewriteWithDefaultFile(char * queryString)
WiredHome 0:729320f63c5c 469 {
WiredHome 8:262583f054f6 470 char * temp = (char *)mymalloc(strlen(queryString) + strlen(DEFAULT_FILENAME) + 1);
WiredHome 0:729320f63c5c 471
WiredHome 0:729320f63c5c 472 if (temp) {
WiredHome 0:729320f63c5c 473 *temp = '\0';
WiredHome 0:729320f63c5c 474 strcpy(temp, queryString);
WiredHome 0:729320f63c5c 475 strcat(temp, DEFAULT_FILENAME);
WiredHome 8:262583f054f6 476 myfree(queryString);
WiredHome 0:729320f63c5c 477 return temp;
WiredHome 0:729320f63c5c 478 } else {
WiredHome 0:729320f63c5c 479 return queryString;
WiredHome 0:729320f63c5c 480 }
WiredHome 0:729320f63c5c 481 }
WiredHome 0:729320f63c5c 482
WiredHome 14:19c5f6151319 483
WiredHome 0:729320f63c5c 484 char * HTTPServer::rewritePrependWebroot(char * queryString)
WiredHome 0:729320f63c5c 485 {
WiredHome 24:062431453abb 486 char * temp = (char *)mymalloc(strlen(webroot) + strlen(queryString) + 2); // save room for '/'
WiredHome 0:729320f63c5c 487
WiredHome 0:729320f63c5c 488 if (temp) {
WiredHome 24:062431453abb 489 char *lastC;
WiredHome 0:729320f63c5c 490 *temp = '\0';
WiredHome 0:729320f63c5c 491 strcpy(temp, webroot);
WiredHome 24:062431453abb 492 lastC = &temp[strlen(temp)-1];
WiredHome 24:062431453abb 493 if (*lastC == '/' && *queryString == '/')
WiredHome 24:062431453abb 494 queryString++; // don't create two '/'
WiredHome 24:062431453abb 495 else if (*lastC != '/' && *queryString != '/')
WiredHome 24:062431453abb 496 strcat(temp, "/");
WiredHome 0:729320f63c5c 497 strcat(temp, queryString);
WiredHome 8:262583f054f6 498 myfree(queryString);
WiredHome 0:729320f63c5c 499 return temp;
WiredHome 0:729320f63c5c 500 } else {
WiredHome 0:729320f63c5c 501 return queryString;
WiredHome 0:729320f63c5c 502 }
WiredHome 0:729320f63c5c 503 }
WiredHome 0:729320f63c5c 504
WiredHome 14:19c5f6151319 505
WiredHome 3:17928786bdb5 506 bool HTTPServer::CheckDynamicHandlers()
WiredHome 3:17928786bdb5 507 {
WiredHome 3:17928786bdb5 508 bool regHandled = false;
WiredHome 0:729320f63c5c 509
WiredHome 3:17928786bdb5 510 // If this queryString is in the list of registered handlers, call that
WiredHome 3:17928786bdb5 511 for (int i=0; i<handlercount; i++) {
WiredHome 3:17928786bdb5 512 if (strcmp(handlers[i].path, queryString) == 0) {
WiredHome 13:8975d7928678 513 (*handlers[i].callback)(this, SEND_PAGE, queryString, queryParams, queryParamCount);
WiredHome 3:17928786bdb5 514 regHandled = true;
WiredHome 3:17928786bdb5 515 break; // we only execute the first one
WiredHome 3:17928786bdb5 516 }
WiredHome 3:17928786bdb5 517 }
WiredHome 3:17928786bdb5 518 return regHandled;
WiredHome 3:17928786bdb5 519 }
WiredHome 3:17928786bdb5 520
WiredHome 14:19c5f6151319 521
WiredHome 3:17928786bdb5 522 void HTTPServer::SendResponse()
WiredHome 3:17928786bdb5 523 {
WiredHome 27:90a1f5a5392f 524 INFO("SendResponse(%s) at %u", queryType, (unsigned int)PerformanceTimer.read_us());
WiredHome 3:17928786bdb5 525 if (strcmp(queryType, "GET") == 0 || strcmp(queryType, "POST") == 0) {
WiredHome 3:17928786bdb5 526 if (!(queryString[0] == '.' && queryString[1] == '.')) {
WiredHome 3:17928786bdb5 527 const char * fType;
WiredHome 3:17928786bdb5 528
WiredHome 3:17928786bdb5 529 if (!CheckDynamicHandlers()) {
WiredHome 3:17928786bdb5 530 // Otherwise, this queryString must be trying to reference a static file
WiredHome 3:17928786bdb5 531 if (queryString[strlen(queryString)-1] == '/') {
WiredHome 3:17928786bdb5 532 queryString = rewriteWithDefaultFile(queryString);
WiredHome 3:17928786bdb5 533 }
WiredHome 3:17928786bdb5 534 // see if we support this file type
WiredHome 3:17928786bdb5 535 fType = GetSupportedType(queryString);
WiredHome 3:17928786bdb5 536 if (fType) {
WiredHome 3:17928786bdb5 537 queryString = rewritePrependWebroot(queryString);
WiredHome 3:17928786bdb5 538 SendFile(queryString, fType);
WiredHome 3:17928786bdb5 539 } else {
WiredHome 3:17928786bdb5 540 header(404, "Not Found", "Pragma: err - Unsupported type\r\n");
WiredHome 3:17928786bdb5 541 }
WiredHome 3:17928786bdb5 542 }
WiredHome 3:17928786bdb5 543 } else {
WiredHome 3:17928786bdb5 544 header(400, "Bad Request", "Pragma: err - Unsupported path\r\n");
WiredHome 3:17928786bdb5 545 }
WiredHome 3:17928786bdb5 546 } else {
WiredHome 3:17928786bdb5 547 header(400, "Bad Request", "Pragma: err - Unsupported query type\r\n");
WiredHome 3:17928786bdb5 548 }
WiredHome 27:90a1f5a5392f 549 INFO(" SendResponse complete at %u", (unsigned int)PerformanceTimer.read_us());
WiredHome 17:69ff00ce39f4 550
WiredHome 3:17928786bdb5 551 if (queryType) {
WiredHome 8:262583f054f6 552 myfree(queryType);
WiredHome 3:17928786bdb5 553 queryType = NULL;
WiredHome 3:17928786bdb5 554 }
WiredHome 3:17928786bdb5 555 if (queryString) {
WiredHome 8:262583f054f6 556 myfree(queryString);
WiredHome 3:17928786bdb5 557 queryString = NULL;
WiredHome 3:17928786bdb5 558 }
WiredHome 3:17928786bdb5 559 if (postQueryString) {
WiredHome 8:262583f054f6 560 myfree(postQueryString);
WiredHome 3:17928786bdb5 561 postQueryString = NULL;
WiredHome 3:17928786bdb5 562 }
WiredHome 27:90a1f5a5392f 563 INFO(" SendResponse free at %u", (unsigned int)PerformanceTimer.read_us());
WiredHome 3:17928786bdb5 564 }
WiredHome 3:17928786bdb5 565
WiredHome 14:19c5f6151319 566
WiredHome 29:00116fc9da74 567 HTTPServer::CallBackResults HTTPServer::ParseHeader(char * buffer)
WiredHome 3:17928786bdb5 568 {
WiredHome 3:17928786bdb5 569 char * dblCR;
WiredHome 29:00116fc9da74 570 CallBackResults advanceState = ACCEPT_ERROR;
WiredHome 3:17928786bdb5 571 int bytecount;
WiredHome 7:99ad7a67f05e 572
WiredHome 3:17928786bdb5 573 // Buffer could have partial, but the double \r\n is the key
WiredHome 13:8975d7928678 574 // GET /QueryString?this=that&sky=blue HTTP/1.1\r\n
WiredHome 8:262583f054f6 575 // GET /QueryString HTTP/1.1\r\nHost: 192.168.1.140\r\nCache-Con
WiredHome 8:262583f054f6 576 // GET /QueryString HTTP/1.1\r\nHost: 192.168.1.140\r\nCache-Control: max-age=0\r\n\r\n
WiredHome 37:0cb2774e2410 577 // POST /dyn2 HTTP/1.2\r\nAccept: text/html, application/xhtml+xml, */*\r\n\r\nle
WiredHome 3:17928786bdb5 578 dblCR = strstr(buffer,"\r\n\r\n");
WiredHome 3:17928786bdb5 579 if (dblCR) { // Have to scan from the beginning in case split on \r
WiredHome 29:00116fc9da74 580 INFO("\r\n==\r\n%s==", buffer);
WiredHome 3:17928786bdb5 581 char * soRec = buffer; // start of the next record of text
WiredHome 13:8975d7928678 582 char * eoRec = strchr(soRec, '\n'); // search for end of the current record
WiredHome 7:99ad7a67f05e 583
WiredHome 13:8975d7928678 584 headerParamCount = 0;
WiredHome 3:17928786bdb5 585 bytecount = strlen(buffer);
WiredHome 3:17928786bdb5 586 if (bytecount > maxheaderbytes)
WiredHome 3:17928786bdb5 587 maxheaderbytes = bytecount;
WiredHome 3:17928786bdb5 588 while (eoRec) {
WiredHome 3:17928786bdb5 589 *eoRec = '\0';
WiredHome 3:17928786bdb5 590 if (*(eoRec-1) == '\r')
WiredHome 3:17928786bdb5 591 *(eoRec-1) = '\0';
WiredHome 8:262583f054f6 592 // Inspect the supported query types (GET, POST) and ignore (HEAD, PUT, OPTION, DELETE, TRACE, CONNECT]
WiredHome 8:262583f054f6 593 // This is very clumsy
WiredHome 37:0cb2774e2410 594 INFO("method: %s", soRec);
WiredHome 37:0cb2774e2410 595 if (strstr(soRec, "GET ") == soRec) {
WiredHome 8:262583f054f6 596 Extract(soRec, "GET", &queryString);
WiredHome 8:262583f054f6 597 if (queryString) {
WiredHome 8:262583f054f6 598 queryType = (char *)mymalloc(strlen("GET")+1);
WiredHome 8:262583f054f6 599 strcpy(queryType, "GET");
WiredHome 8:262583f054f6 600 }
WiredHome 8:262583f054f6 601 } else if (strstr(soRec, "POST ") == soRec) {
WiredHome 37:0cb2774e2410 602 Extract(soRec, "POST", &queryString);
WiredHome 8:262583f054f6 603 if (queryString) {
WiredHome 8:262583f054f6 604 queryType = (char *)mymalloc(strlen("POST")+1);
WiredHome 8:262583f054f6 605 strcpy(queryType, "POST");
WiredHome 8:262583f054f6 606 }
WiredHome 10:9c8d2c6a3469 607 }
WiredHome 13:8975d7928678 608
WiredHome 13:8975d7928678 609 // if there is a ": " delimiter, we have a header item to parse into name,value pair
WiredHome 13:8975d7928678 610 // "Connection: keep-alive" becomes "Connection" "keep-alive"
WiredHome 13:8975d7928678 611 char *delim = strstr(soRec, ": ");
WiredHome 13:8975d7928678 612 char *chkSpace = strchr(soRec, ' '); // a field-name has no space ahead of the ":"
WiredHome 29:00116fc9da74 613 if (delim
WiredHome 29:00116fc9da74 614 && (!chkSpace || (chkSpace && delim < chkSpace))
WiredHome 29:00116fc9da74 615 && headerParamCount < maxheaderParams) {
WiredHome 14:19c5f6151319 616 *delim++ = '\0'; // replace ": " with null
WiredHome 13:8975d7928678 617 *delim++ = '\0';
WiredHome 13:8975d7928678 618 headerParams[headerParamCount].name = soRec;
WiredHome 13:8975d7928678 619 headerParams[headerParamCount].value = delim;
WiredHome 37:0cb2774e2410 620 INFO("%d: headerParams[%s] = {%s}", headerParamCount,
WiredHome 37:0cb2774e2410 621 headerParams[headerParamCount].name, headerParams[headerParamCount].value);
WiredHome 13:8975d7928678 622 headerParamCount++;
WiredHome 13:8975d7928678 623 }
WiredHome 3:17928786bdb5 624 soRec = eoRec + 1;
WiredHome 3:17928786bdb5 625 eoRec = strchr(soRec, '\n');
WiredHome 3:17928786bdb5 626 }
WiredHome 29:00116fc9da74 627
WiredHome 3:17928786bdb5 628 if (queryString) {
WiredHome 3:17928786bdb5 629 // We have enough to try to reply
WiredHome 37:0cb2774e2410 630 INFO("create reply queryType{%s}, queryString{%s}", queryType, queryString);
WiredHome 13:8975d7928678 631 // parse queryParams - if any
WiredHome 3:17928786bdb5 632 // /file.htm?name1=value1&name2=value2...
WiredHome 3:17928786bdb5 633 // /file.htm?name1&name2=value2...
WiredHome 13:8975d7928678 634 queryParamCount = 0;
WiredHome 3:17928786bdb5 635 char * paramDelim = strchr(queryString, '?');
WiredHome 3:17928786bdb5 636 if (paramDelim) {
WiredHome 3:17928786bdb5 637 *paramDelim++ = '\0';
WiredHome 3:17928786bdb5 638 UnescapeString(paramDelim); // everything after the '?'
WiredHome 37:0cb2774e2410 639 ParseParameters(paramDelim); // pointing past the NULL, and there are queryParams here
WiredHome 3:17928786bdb5 640 }
WiredHome 3:17928786bdb5 641 } else {
WiredHome 29:00116fc9da74 642 ERR("queryString not found in (%s) [this should never happen]", soRec);
WiredHome 3:17928786bdb5 643 }
WiredHome 29:00116fc9da74 644 advanceState = ACCEPT_COMPLETE;
WiredHome 3:17928786bdb5 645 buffer[0] = 0;
WiredHome 3:17928786bdb5 646
WiredHome 3:17928786bdb5 647 // This part parses the extra data on a POST method.
WiredHome 3:17928786bdb5 648 // Since there has to be a dynamic handler registered for this
WiredHome 3:17928786bdb5 649 // it would make sense to move some of this responsibility to
WiredHome 3:17928786bdb5 650 // that handler. It could then choose if it wanted to allocate
WiredHome 3:17928786bdb5 651 // the requested 'Content-Length' amount of memory.
WiredHome 13:8975d7928678 652 int postBytes = atoi(GetHeaderValue("Content-Length"));
WiredHome 28:f93ef41b78e1 653 CallBackResults acceptIt = ACCEPT_ERROR;
WiredHome 3:17928786bdb5 654 if (strcmp(queryType, "POST") == 0 && postBytes > 0 ) {
WiredHome 37:0cb2774e2410 655 INFO("parse POST data %d bytes", postBytes);
WiredHome 3:17928786bdb5 656 if (postBytes) {
WiredHome 27:90a1f5a5392f 657 int ndxHandler = 0;
WiredHome 3:17928786bdb5 658 bool regHandled = false;
WiredHome 3:17928786bdb5 659 // Registered Dynamic Handler
WiredHome 3:17928786bdb5 660 // Callback and ask if they want to accept this data
WiredHome 27:90a1f5a5392f 661 for (ndxHandler=0; ndxHandler<handlercount; ndxHandler++) {
WiredHome 37:0cb2774e2410 662 INFO("is '%s' a handler for '%s' ?", handlers[ndxHandler].path, queryString);
WiredHome 27:90a1f5a5392f 663 if (strcmp(handlers[ndxHandler].path, queryString) == 0) {
WiredHome 27:90a1f5a5392f 664 acceptIt = (*handlers[ndxHandler].callback)(this, CONTENT_LENGTH_REQUEST, queryString, queryParams, queryParamCount);
WiredHome 3:17928786bdb5 665 regHandled = true;
WiredHome 29:00116fc9da74 666 break; // only one callback per path allowed
WiredHome 3:17928786bdb5 667 }
WiredHome 3:17928786bdb5 668 }
WiredHome 37:0cb2774e2410 669 INFO("reghandled: %d, acceptIt: %d", regHandled, acceptIt);
WiredHome 28:f93ef41b78e1 670 if (regHandled && acceptIt != ACCEPT_ERROR) {
WiredHome 27:90a1f5a5392f 671 // @todo need to refactor - if the thing is bigger than the buffer,
WiredHome 27:90a1f5a5392f 672 // then we can receive it a chunk at a time, and hand off
WiredHome 27:90a1f5a5392f 673 // the chunks to the callback. May need callbacks that
WiredHome 33:ef165a67ab22 674 // are: DATA_TRANSFER: self-detect to extract the filename/object name,
WiredHome 33:ef165a67ab22 675 // DATA_TRANSFER: subsequent chunk of data,
WiredHome 33:ef165a67ab22 676 // DATA_TRANSFER_END: signals that last chunk is enclosed.
WiredHome 27:90a1f5a5392f 677 //
WiredHome 3:17928786bdb5 678 // If so, we'll make space for it
WiredHome 33:ef165a67ab22 679 postQueryString = (char *)mymalloc(CHUNK_SIZE);
WiredHome 37:0cb2774e2410 680 //INFO("Free space %d", Free());
WiredHome 37:0cb2774e2410 681 INFO("postQueryString %p", postQueryString);
WiredHome 3:17928786bdb5 682 if (postQueryString) {
WiredHome 37:0cb2774e2410 683 int len = 0;
WiredHome 37:0cb2774e2410 684 int ttlCount;
WiredHome 33:ef165a67ab22 685 Timer escapePlan;
WiredHome 33:ef165a67ab22 686 bool escape = false;
WiredHome 33:ef165a67ab22 687
WiredHome 37:0cb2774e2410 688 INFO("Processing tail...");
WiredHome 33:ef165a67ab22 689 escapePlan.start();
WiredHome 37:0cb2774e2410 690 dblCR += 4; // There may be some after the double CR that we need
WiredHome 37:0cb2774e2410 691 ttlCount = strlen(dblCR);
WiredHome 37:0cb2774e2410 692 strcpy(postQueryString, dblCR);
WiredHome 37:0cb2774e2410 693 INFO(" {%s}", postQueryString);
WiredHome 37:0cb2774e2410 694 while (ttlCount <= postBytes && !escape) {
WiredHome 37:0cb2774e2410 695 INFO("ttlCount: %d < postBytes: %d, of chunk %d", ttlCount, postBytes, CHUNK_SIZE);
WiredHome 37:0cb2774e2410 696 len = client.receive_all(postQueryString + ttlCount, CHUNK_SIZE - ttlCount);
WiredHome 33:ef165a67ab22 697 if (len > 0) {
WiredHome 37:0cb2774e2410 698 INFO(" len: %d, ttlCount: %d < postBytes %d, {%s}", len, ttlCount, postBytes, postQueryString);
WiredHome 33:ef165a67ab22 699 ttlCount += len;
WiredHome 33:ef165a67ab22 700 postQueryString[len] = '\0'; // Whether binary or ASCII, this is ok as it's after the data
WiredHome 37:0cb2774e2410 701 INFO(" postBytes %d: [%s], [%d]", postBytes, postQueryString, ndxHandler);
WiredHome 33:ef165a67ab22 702 escapePlan.reset();
WiredHome 32:7ded9bacb546 703 } else if (len < 0) {
WiredHome 33:ef165a67ab22 704 INFO("*** connection closed ***");
WiredHome 33:ef165a67ab22 705 break; // no more data, before the plan
WiredHome 33:ef165a67ab22 706 } else { // n == 0
WiredHome 33:ef165a67ab22 707 ;
WiredHome 33:ef165a67ab22 708 }
WiredHome 33:ef165a67ab22 709 if (escapePlan.read_ms() > HANG_TIMEOUT_MS) {
WiredHome 33:ef165a67ab22 710 escape = true;
WiredHome 33:ef165a67ab22 711 WARN("Escape plan activated.");
WiredHome 3:17928786bdb5 712 }
WiredHome 3:17928786bdb5 713 }
WiredHome 37:0cb2774e2410 714 acceptIt = (*handlers[ndxHandler].callback)(this, DATA_TRANSFER, postQueryString, NULL, 0);
WiredHome 37:0cb2774e2410 715 INFO("..processing exit");
WiredHome 33:ef165a67ab22 716 acceptIt = (*handlers[ndxHandler].callback)(this, DATA_TRANSFER_END, NULL, NULL, 0);
WiredHome 32:7ded9bacb546 717 myfree(postQueryString);
WiredHome 27:90a1f5a5392f 718 } else {
WiredHome 33:ef165a67ab22 719 ERR("attempt to allocate %d failed.", CHUNK_SIZE);
WiredHome 3:17928786bdb5 720 }
WiredHome 3:17928786bdb5 721 } else {
WiredHome 3:17928786bdb5 722 // Simply copy it to the bitbucket
WiredHome 37:0cb2774e2410 723 WARN("to the bit bucket...");
WiredHome 3:17928786bdb5 724 int bytesToDump = postBytes;
WiredHome 8:262583f054f6 725 char * bitbucket = (char *)mymalloc(201);
WiredHome 29:00116fc9da74 726
WiredHome 3:17928786bdb5 727 dblCR += 4;
WiredHome 3:17928786bdb5 728 while (*dblCR && *dblCR <= ' ')
WiredHome 3:17928786bdb5 729 dblCR++;
WiredHome 3:17928786bdb5 730 bytesToDump -= strlen(dblCR);
WiredHome 3:17928786bdb5 731 while (bytesToDump > 0) {
WiredHome 3:17928786bdb5 732 int n = (bytesToDump > 200) ? 200 : bytesToDump;
WiredHome 3:17928786bdb5 733 n = client.receive(bitbucket, n);
WiredHome 29:00116fc9da74 734 if (n < 0) {
WiredHome 29:00116fc9da74 735 ERR("to the bitbucket.");
WiredHome 29:00116fc9da74 736 break;
WiredHome 29:00116fc9da74 737 }
WiredHome 3:17928786bdb5 738 bytesToDump -= n;
WiredHome 3:17928786bdb5 739 }
WiredHome 8:262583f054f6 740 myfree(bitbucket);
WiredHome 3:17928786bdb5 741 }
WiredHome 3:17928786bdb5 742 }
WiredHome 3:17928786bdb5 743 }
WiredHome 3:17928786bdb5 744 }
WiredHome 3:17928786bdb5 745 return advanceState;
WiredHome 3:17928786bdb5 746 }
WiredHome 3:17928786bdb5 747
WiredHome 14:19c5f6151319 748
WiredHome 27:90a1f5a5392f 749
WiredHome 13:8975d7928678 750 const char * HTTPServer::GetHeaderValue(const char * hdr)
WiredHome 13:8975d7928678 751 {
WiredHome 13:8975d7928678 752 int i;
WiredHome 29:00116fc9da74 753
WiredHome 29:00116fc9da74 754 for (i=0; i<headerParamCount; i++) {
WiredHome 13:8975d7928678 755 if (strcmp(hdr, headerParams[i].name) == 0)
WiredHome 13:8975d7928678 756 return headerParams[i].value;
WiredHome 29:00116fc9da74 757 }
WiredHome 13:8975d7928678 758 return NULL;
WiredHome 13:8975d7928678 759 }
WiredHome 13:8975d7928678 760
WiredHome 12:109bf1558300 761
WiredHome 7:99ad7a67f05e 762 void HTTPServer::GetPerformanceData(SW_PerformanceData * p)
WiredHome 7:99ad7a67f05e 763 {
WiredHome 3:17928786bdb5 764 memcpy(p, &perfData, sizeof(perfData));
WiredHome 3:17928786bdb5 765 }
WiredHome 3:17928786bdb5 766
WiredHome 17:69ff00ce39f4 767 unsigned int HTTPServer::GetPerformanceClock()
WiredHome 17:69ff00ce39f4 768 {
WiredHome 17:69ff00ce39f4 769 return (unsigned int)PerformanceTimer.read_us();
WiredHome 17:69ff00ce39f4 770 }
WiredHome 14:19c5f6151319 771
WiredHome 16:6ebacf2946d8 772 unsigned int HTTPServer::RecordPerformanceData(SW_PerformanceParam * param, unsigned int refTime)
WiredHome 7:99ad7a67f05e 773 {
WiredHome 16:6ebacf2946d8 774 unsigned int t_now = (unsigned int)PerformanceTimer.read_us();
WiredHome 3:17928786bdb5 775 param->TotalTime_us += (t_now - refTime);
WiredHome 3:17928786bdb5 776 param->Samples++;
WiredHome 3:17928786bdb5 777 if ((t_now - refTime) > param->MaxTime_us)
WiredHome 3:17928786bdb5 778 param->MaxTime_us = (t_now - refTime);
WiredHome 3:17928786bdb5 779 return t_now;
WiredHome 3:17928786bdb5 780 }
WiredHome 3:17928786bdb5 781
WiredHome 14:19c5f6151319 782
WiredHome 7:99ad7a67f05e 783 void HTTPServer::ResetPerformanceData()
WiredHome 7:99ad7a67f05e 784 {
WiredHome 3:17928786bdb5 785 memset(&perfData, 0, sizeof(perfData));
WiredHome 3:17928786bdb5 786 }
WiredHome 3:17928786bdb5 787
WiredHome 4:f34642902056 788
WiredHome 21:660143f20b04 789 #ifdef INCLUDE_GETREMOTE
WiredHome 21:660143f20b04 790 bool HTTPServer::GetRemoteAddr(char * str, int strSize)
WiredHome 21:660143f20b04 791 {
WiredHome 21:660143f20b04 792 bool res = false;
WiredHome 21:660143f20b04 793 char *p;
WiredHome 21:660143f20b04 794
WiredHome 21:660143f20b04 795 if (strSize < 16) { // Can only guard it here w/o modifying Wifly class
WiredHome 21:660143f20b04 796 *str = '\0';
WiredHome 21:660143f20b04 797 return res;
WiredHome 21:660143f20b04 798 }
WiredHome 21:660143f20b04 799 res = wifly->sendCommand("show z\r", NULL, str, strSize);
WiredHome 21:660143f20b04 800 if (res) {
WiredHome 21:660143f20b04 801 p = strchr(str, '\n'); // truncate after the octets.
WiredHome 21:660143f20b04 802 if (p) *p = '\0';
WiredHome 21:660143f20b04 803 p = strchr(str, ' '); // or a space
WiredHome 21:660143f20b04 804 if (p) *p = '\0';
WiredHome 21:660143f20b04 805 p = strchr(str, '<'); // or a <
WiredHome 21:660143f20b04 806 if (p) *p = '\0';
WiredHome 21:660143f20b04 807 res = true;
WiredHome 21:660143f20b04 808 }
WiredHome 21:660143f20b04 809 wifly->exit();
WiredHome 21:660143f20b04 810 return res;
WiredHome 21:660143f20b04 811 }
WiredHome 21:660143f20b04 812 #endif