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:
- 58:5303e962f711
- Parent:
- 57:fb81057b4d77
- Child:
- 59:9a71ac02c782
--- a/SW_HTTPServer.cpp Tue Jul 10 23:13:55 2018 +0000 +++ b/SW_HTTPServer.cpp Sun Nov 18 04:04:16 2018 +0000 @@ -11,14 +11,15 @@ // author David Smart, Smartware Computing // #include "mbed.h" +#include "SW_String.h" // Secure methods and others that were missing -//#define DEBUG "HTTP" +#define DEBUG "HTTP" #include <cstdio> #if (defined(DEBUG) && !defined(TARGET_LPC11U24)) -#define DBG(x, ...) std::printf("[DBG %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); -#define WARN(x, ...) std::printf("[WRN %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); -#define ERR(x, ...) std::printf("[ERR %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); -#define INFO(x, ...) std::printf("[INF %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); +#define DBG(x, ...) std::printf("[DBG %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); +#define WARN(x, ...) std::printf("[WRN %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); +#define ERR(x, ...) std::printf("[ERR %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); +#define INFO(x, ...) std::printf("[INF %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); #else #define DBG(x, ...) #define WARN(x, ...) @@ -26,6 +27,7 @@ #define INFO(x, ...) #endif +extern void ShowSignOfLife(int which); #include "SW_HTTPServer.h" // define DEBUG before this @@ -112,6 +114,8 @@ #define myfree(x) free(x) #endif + + HTTPServer::HTTPServer( int port, const char * _webroot, @@ -124,8 +128,10 @@ int _allocforfile ) { - webroot = (char *)malloc(strlen(_webroot)+1); - strcpy(webroot, _webroot); + int wrSize = strlen(_webroot)+1; + + webroot = (char *)malloc(wrSize); + strcpy_s(webroot, wrSize, _webroot); if (strlen(webroot)>1 && webroot[strlen(webroot)-1] == '/') // remove trailing '/' webroot[strlen(webroot)-1] = '\0'; filenameAliasList = NULL; @@ -223,7 +229,7 @@ static state lastOp = Reset; if (lastOp != op) { const char *states[] = {"Idle", "ReceivingHeader", "ReceivingPayload", "Sending", "WaitingToClose", "Reset"}; - INFO("Poll: %s", states[op]); + INFO("Poll: %-30s ######## %8u us", states[op], (unsigned int)PerformanceTimer.read_us()-t_ref); lastOp = op; } #endif @@ -233,13 +239,15 @@ break; case Idle: + ShowSignOfLife(3); PerformanceTimer.reset(); t_ref = (unsigned int)PerformanceTimer.read_us(); bPtr = headerbuffer; if (0 == server->accept(client)) { op = ReceivingHeader; t_ref = RecordPerformanceData(&perfData.ConnectionAccepted, t_ref); - INFO("Accepted at %u", (unsigned int)PerformanceTimer.read_us()); + INFO("Accepted at %8u us", + (unsigned int)PerformanceTimer.read_us()-t_ref); } else { //INFO("Timeout waiting for accept()"); } @@ -247,12 +255,12 @@ case ReceivingHeader: n = client.receive(bPtr, headerbuffersize - (bPtr - headerbuffer)); + INFO("client.receive() returned %d, from %s", n, client.get_address()); if (n == -2) { - ; // timeout, so hang here waiting for traffic // was hang here waiting ... op = Sending; which causes misses + op = WaitingToClose; } else if (n < 0) { - // some error like a closed/crashed interface - INFO("%sclient.receive() returned %d, from %s", (n<0) ? "*** " : "", n, client.get_address()); + op = WaitingToClose; // bail out... } else if (n) { bPtr[n] = '\0'; switch (ParseHeader(headerbuffer)) { @@ -261,7 +269,8 @@ case ACCEPT_COMPLETE: op = Sending; t_ref = RecordPerformanceData(&perfData.HeaderParsed, t_ref); - INFO("Header Parsed at %u", (unsigned int)PerformanceTimer.read_us()); + INFO("Header Parsed at %8u us", + (unsigned int)PerformanceTimer.read_us()-t_ref); break; case ACCEPT_CONTINUE: op = ReceivingPayload; @@ -274,6 +283,8 @@ case ReceivingPayload: // After the header, there is a payload that will be handled #if 1 + INFO("ReceivingPayload %8u us", + (unsigned int)PerformanceTimer.read_us()-t_ref); n = client.receive(bPtr, headerbuffersize - (bPtr - headerbuffer)); if (n < 0) { op = Sending; @@ -288,17 +299,23 @@ break; case Sending: + INFO("SendResponse at %8u us", + (unsigned int)PerformanceTimer.read_us()-t_ref); SendResponse(); op = WaitingToClose; t_ref = RecordPerformanceData(&perfData.ResponseSent, t_ref); - INFO("Response Sent at %u", (unsigned int)PerformanceTimer.read_us()); + INFO("Response Sent at %8u us", + (unsigned int)PerformanceTimer.read_us()-t_ref); break; case WaitingToClose: + INFO("close_connection %8u us", + (unsigned int)PerformanceTimer.read_us()-t_ref); close_connection(); op = Idle; RecordPerformanceData(&perfData.ConnectionClosed, t_ref); - INFO("Connection closed exit: %u\r\n\r\n", (unsigned int)PerformanceTimer.read_us()); + INFO("Connection closed exit: %8u us\r\n\r\n", + (unsigned int)PerformanceTimer.read_us()-t_ref); break; } } @@ -326,7 +343,7 @@ bytes = strlen(msg); INFO("Sending %d bytes", bytes); //INFO("send:\r\n%s", msg); - int r = client.send((char *)msg, bytes); + int r = client.send_all((char *)msg, bytes); INFO("client.send returned: %d", r); return r; } @@ -368,22 +385,29 @@ char *fbuffer = (char *)mymalloc(FILESEND_BUF_SIZE); int bytes; - client.set_blocking(false, 450); - //server->set_blocking(true, 240); if (fbuffer) { char ContentLen[30]; snprintf(ContentLen, sizeof(ContentLen), "Content-Length: %u\r\n", FileSize(filename)); header(OK, "OK", filetype, ContentLen); header(""); - bytes = fread(fbuffer,sizeof(char),FILESEND_BUF_SIZE,fp); + bytes = fread(fbuffer,sizeof(char),FILESEND_BUF_SIZE-1,fp); INFO("Start with %d bytes", bytes); + int retryCount = 2; while (bytes > 0) { int r = send(fbuffer, bytes); - INFO("sent %d", r); if (r >= 0) { - bytes = fread(fbuffer,sizeof(char),FILESEND_BUF_SIZE,fp); + bytes = fread(fbuffer,sizeof(char),FILESEND_BUF_SIZE-1,fp); INFO(" Next %d bytes", bytes); //INFO("::%s", fbuffer); + } else if (r == -2) { + if (retryCount-- == 0) { + ERR("send failed with %d [retries] - terminating SendFile().", r); + break; + } + INFO("send failed with %d (timeout), hopefully it will recover.", r); + } else { + ERR("send failed with %d, but why? - terminating SendFile().", r); + break; } } myfree(fbuffer); @@ -542,10 +566,10 @@ send(optional_text); } else { if (strlen(hdr_age) + strlen(hdr_server) + strlen(hdr_close) + strlen(nl) < sizeof(http)) { - strcpy(http, hdr_age); - strcat(http, hdr_server); - strcat(http, hdr_close); - strcat(http, nl); + strcpy_s(http, 100, hdr_age); + strcat_s(http, 100, hdr_server); + strcat_s(http, 100, hdr_close); + strcat_s(http, 100, nl); send(http); } else { send(hdr_age); @@ -592,9 +616,10 @@ // /QueryString\0HTTP/1.1\0\0 if (*string) // recycle old string when working a new one myfree(*string); - container = (char *)mymalloc(strlen(qs)); + int ctSize = strlen(qs); + container = (char *)mymalloc(ctSize); if (container) { - strcpy(container, qs); + strcpy_s(container, ctSize, qs); eqs = strchr(container, ' '); if (eqs) *eqs = '\0'; @@ -611,12 +636,13 @@ char * HTTPServer::rewriteWithDefaultFile(char * queryString) { - char * temp = (char *)mymalloc(strlen(queryString) + strlen(DEFAULT_FILENAME) + 1); + int tSize = strlen(queryString) + strlen(DEFAULT_FILENAME) + 1; + char * temp = (char *)mymalloc(tSize); if (temp) { *temp = '\0'; - strcpy(temp, queryString); - strcat(temp, DEFAULT_FILENAME); + strcpy_s(temp, tSize, queryString); + strcat_s(temp, tSize, DEFAULT_FILENAME); myfree(queryString); return temp; } else { @@ -627,18 +653,19 @@ char * HTTPServer::rewritePrependWebroot(char * queryString) { - char * temp = (char *)mymalloc(strlen(webroot) + strlen(queryString) + 2); // save room for '/' + int tSize = strlen(webroot) + strlen(queryString) + 2; + char * temp = (char *)mymalloc(tSize); // save room for '/' if (temp) { char *lastC; *temp = '\0'; - strcpy(temp, webroot); + strcpy_s(temp, tSize, webroot); lastC = &temp[strlen(temp)-1]; if (*lastC == '/' && *queryString == '/') queryString++; // don't create two '/' else if (*lastC != '/' && *queryString != '/') - strcat(temp, "/"); - strcat(temp, queryString); + strcat_s(temp, tSize, "/"); + strcat_s(temp, tSize, queryString); myfree(queryString); return temp; } else { @@ -666,7 +693,8 @@ void HTTPServer::SendResponse() { - INFO("SendResponse(%s) at %u", queryType, (unsigned int)PerformanceTimer.read_us()); + INFO("SendResponse(%5s) at %8u us", + queryType, (unsigned int)PerformanceTimer.read_us()); if (strcmp(queryType, "GET ") == 0 || strcmp(queryType, "POST ") == 0) { if (!(queryString[0] == '.' && queryString[1] == '.')) { const char * fType; @@ -696,7 +724,8 @@ header(Bad_Request, "Bad Request", NULL, "Pragma: err - Unsupported query type\r\n"); header(""); } - INFO(" SendResponse complete at %u", (unsigned int)PerformanceTimer.read_us()); + INFO(" SendResponse complete at %8u us", + (unsigned int)PerformanceTimer.read_us()); if (queryType) { myfree(queryType); @@ -710,7 +739,8 @@ myfree(postQueryString); postQueryString = NULL; } - INFO(" SendResponse free at %u", (unsigned int)PerformanceTimer.read_us()); + INFO(" SendResponse free at %8u us", + (unsigned int)PerformanceTimer.read_us()); } @@ -746,8 +776,9 @@ if (strstr(soRec, qm->queryType) == soRec) { Extract(soRec, qm->queryType, &queryString); if (queryString) { - queryType = (char *)mymalloc(strlen(qm->queryType)+1); - strcpy(queryType, qm->queryType); + int qSize = strlen(qm->queryType)+1; + queryType = (char *)mymalloc(qSize); + strcpy_s(queryType, qSize, qm->queryType); } } qm++; @@ -758,14 +789,16 @@ if (strstr(soRec, "GET ") == soRec) { Extract(soRec, "GET", &queryString); if (queryString) { - queryType = (char *)mymalloc(strlen("GET")+1); - strcpy(queryType, "GET"); + int qSize = strlen("GET")+1; + queryType = (char *)mymalloc(qSize); + strcpy_s(queryType, qSize, "GET"); } } else if (strstr(soRec, "POST ") == soRec) { Extract(soRec, "POST", &queryString); if (queryString) { - queryType = (char *)mymalloc(strlen("POST")+1); - strcpy(queryType, "POST"); + int qSize = strlen("POST")+1; + queryType = (char *)mymalloc(qSize); + strcpy_s(queryType, qSize, "POST"); } } #endif @@ -856,7 +889,7 @@ escapePlan.start(); dblCR += 4; // There may be some after the double CR that we need ttlCount = strlen(dblCR); - strcpy(postQueryString, dblCR); + strcpy_s(postQueryString, CHUNK_SIZE, dblCR); //INFO(" {%s}", postQueryString); while ((!postBytes || ttlCount < postBytes) && !escape) { INFO("ttlCount: %d < postBytes: %d, of max chunk alloc %d", ttlCount, postBytes, CHUNK_SIZE);