A simple web server that can be bound to either the EthernetInterface or the WiflyInterface.

Dependents:   Smart-WiFly-WebServer WattEye X10Svr SSDP_Server

Committer:
Sissors
Date:
Wed Sep 03 10:42:33 2014 +0000
Revision:
42:0d5b682bb17a
Parent:
41:6f2f1fb96742
Child:
43:3fc773c2986e
Fixed some bugs regarding processing of post stuff (it checked if received was smaller or equal to what it should receive instead of smaller, and a debug statement caused a lock up in some situations).
;
; Also by default disabled send info statement

Who changed what in which revision?

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