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 02 00:26:06 2014 +0000
Revision:
36:1bb5fa6b109c
Parent:
35:2d756262d095
Child:
37:0cb2774e2410
Small update to disable DEBUG output and to swap from modserial to RawSerial.

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