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:
Sat Oct 12 23:35:51 2013 +0000
Revision:
30:864843965b40
Parent:
29:00116fc9da74
Child:
31:8f72be717a3c
Removed a bit of debugging that hasn't brought value in a while - malloc and free.

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