A simple web server that can be bound to either the EthernetInterface or the WiflyInterface.
Dependents: Smart-WiFly-WebServer WattEye X10Svr SSDP_Server
Diff: SW_HTTPServer.cpp
- Revision:
- 33:ef165a67ab22
- Parent:
- 32:7ded9bacb546
- Child:
- 34:019212c05980
diff -r 7ded9bacb546 -r ef165a67ab22 SW_HTTPServer.cpp --- a/SW_HTTPServer.cpp Mon Dec 30 23:03:37 2013 +0000 +++ b/SW_HTTPServer.cpp Fri Jan 03 19:12:22 2014 +0000 @@ -12,12 +12,27 @@ // #include "mbed.h" +#define DEBUG "HTTP" +#include "Utility.h" + #include "SW_HTTPServer.h" // define DEBUG before this -#define DEBUG "httpd" -#include "Utility.h" +#if 0 +#if (defined(DEBUG) && !defined(TARGET_LPC11U24)) +#define DBG(x, ...) pc->printf("[DBG %s%4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); +#define WARN(x, ...) pc->printf("[WRN %s%4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); +#define ERR(x, ...) pc->printf("[ERR %s%4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); +#define INFO(x, ...) pc->printf("[INF %s%4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); +#else +#define DBG(x, ...) +#define WARN(x, ...) +#define ERR(x, ...) +#define INFO(x, ...) +#endif +#endif -#define CHUNKSIZE 1600 // When receiving and handing partial to the app, this is the chunk size +#define CHUNK_SIZE 1500 // max size of a single chunk (probably limited by Ethernet to 1500) +#define HANG_TIMEOUT_MS 250 // If we're waiting on the host, which may never respond, this is the timeout const char * DEFAULT_FILENAME = "index.htm"; @@ -37,6 +52,7 @@ {".jpg", "Content-Type: image/jpeg\r\n" }, {".jpeg","Content-Type: image/jpeg\r\n" }, {".ico", "Content-Type: image/x-icon\r\n" }, + {".bmp", "Content-Type: image/bmp\r\n" }, {".png", "Content-Type: image/png\r\n" }, {".zip", "Content-Type: image/zip\r\n" }, {".gz", "Content-Type: image/gz\r\n" }, @@ -107,10 +123,12 @@ queryParamCount = 0; handlercount = 0; maxheaderbytes = 0; + INFO("HTTPServer::HTTPServer"); server = new TCPSocketServer(); server->bind(port); server->listen(); server->set_blocking(false, 10); + client.set_blocking(false, 100); //@TODO client is separate from server. any way to combine? ResetPerformanceData(); PerformanceTimer.start(); } @@ -220,7 +238,18 @@ case ReceivingPayload: // After the header, there is a payload that will be handled +#if 1 + n = client.receive(bPtr, headerbuffersize - (bPtr - headerbuffer)); + if (n < 0) { + op = Sending; + INFO("*** client.receive() => %d", n); + } else if (n) { + bPtr[n] = '\0'; + INFO("*** payload size %d", n); + } +#else op = Sending; +#endif break; case Sending: @@ -645,38 +674,45 @@ // @todo need to refactor - if the thing is bigger than the buffer, // then we can receive it a chunk at a time, and hand off // the chunks to the callback. May need callbacks that - // are: START: extract the filename/object name, - // NEXT: a chunk of data, - // END: signals that all chunks were delivered. + // are: DATA_TRANSFER: self-detect to extract the filename/object name, + // DATA_TRANSFER: subsequent chunk of data, + // DATA_TRANSFER_END: signals that last chunk is enclosed. // // If so, we'll make space for it - postQueryString = (char *)mymalloc(CHUNKSIZE); + postQueryString = (char *)mymalloc(CHUNK_SIZE); INFO("Free space %d", Free()); if (postQueryString) { - int ttlReceived = 0; - - INFO("Processing"); - dblCR += 4; // If we slurped up any of the POST, - while (*dblCR && *dblCR <= ' ') - dblCR++; - strcpy(postQueryString, dblCR); // copy that in and then get the rest - while (ttlReceived < postBytes) { - int len; - wait_ms(4); - len = client.receive(postQueryString, CHUNKSIZE); - if (len >=0) { - INFO("Passing %d bytes (%d of %d) in [%s]", len, ttlReceived, postBytes, postQueryString); - ttlReceived += len; + int len; + int ttlCount = 4; // includes the doubleCR in the total count from Content-Length + Timer escapePlan; + bool escape = false; + + escapePlan.start(); + //INFO("Processing"); + while (ttlCount < postBytes && !escape) { + len = client.receive_all(postQueryString, CHUNK_SIZE); + if (len > 0) { + ttlCount += len; + postQueryString[len] = '\0'; // Whether binary or ASCII, this is ok as it's after the data + //INFO("%d bytes is %d of %d: [%s]", len, ttlCount, postBytes, postQueryString); acceptIt = (*handlers[ndxHandler].callback)(this, DATA_TRANSFER, postQueryString, NULL, len); + escapePlan.reset(); } else if (len < 0) { - INFO("*** receive returned %d ***", len); - break; // no more data + INFO("*** connection closed ***"); + break; // no more data, before the plan + } else { // n == 0 + ; + } + if (escapePlan.read_ms() > HANG_TIMEOUT_MS) { + escape = true; + WARN("Escape plan activated."); } } + //INFO("..processing exit"); + acceptIt = (*handlers[ndxHandler].callback)(this, DATA_TRANSFER_END, NULL, NULL, 0); myfree(postQueryString); - INFO("done."); } else { - ERR("HTTPd: attempt to allocate %d bytes failed.", CHUNKSIZE); + ERR("attempt to allocate %d failed.", CHUNK_SIZE); } } else { // Simply copy it to the bitbucket