Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of SW_HTTPServer by
Diff: SW_HTTPServer.cpp
- Revision:
- 29:00116fc9da74
- Parent:
- 28:f93ef41b78e1
- Child:
- 30:864843965b40
--- a/SW_HTTPServer.cpp Fri Oct 11 02:33:46 2013 +0000 +++ b/SW_HTTPServer.cpp Fri Oct 11 23:47:31 2013 +0000 @@ -11,16 +11,17 @@ // author David Smart, Smartware Computing // #include "mbed.h" -#include "SW_HTTPServer.h" + #include "Utility.h" #define DEBUG "HTTP" +#include "SW_HTTPServer.h" #if (defined(DEBUG) && !defined(TARGET_LPC11U24)) -#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__); +#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, ...) @@ -62,12 +63,12 @@ // This uses standard library dynamic memory management, but for an // embedded system there are alternates that may make better sense - // search the web for embedded system malloc alternates. -static void * MyMalloc(int x, int y) +void * HTTPServer::MyMalloc(int x, int y) { - std::printf("[INF HTTP%4d] malloc(%d)\r\n", y, x); + pc->printf("[INF HTTP%4d] malloc(%d)\r\n", y, x); return malloc(x); } -static char toP(void * x) +char HTTPServer::toP(void * x) { char * c = (char *) x; if (*c >= ' ' && *c < 0x7F) @@ -169,7 +170,8 @@ { typedef enum { Idle, // waiting for a connection - Receiving, // receiving data + ReceivingHeader, // receiving header + ReceivingPayload, // receiving a section after the Header Sending, // send the response WaitingToClose, // small timeout to close Reset @@ -182,7 +184,7 @@ #if defined(DEBUG) static state lastOp = Reset; if (lastOp != op) { - const char *states[] = {"Idle", "Receiving", "Sending", "WaitingToClose", "Reset"}; + const char *states[] = {"Idle", "ReceivingHeader", "ReceivingPayload", "Sending", "WaitingToClose", "Reset"}; INFO("Poll: %s", states[op]); lastOp = op; } @@ -197,27 +199,40 @@ t_ref = (unsigned int)PerformanceTimer.read_us(); bPtr = headerbuffer; if (0 == server->accept(client)) { - op = Receiving; + op = ReceivingHeader; t_ref = RecordPerformanceData(&perfData.ConnectionAccepted, t_ref); INFO("Accepted at %u", (unsigned int)PerformanceTimer.read_us()); } break; - case Receiving: + case ReceivingHeader: n = client.receive(bPtr, headerbuffersize - (bPtr - headerbuffer)); if (n < 0) { + op = Sending; INFO("*** client.receive() => %d", n); } else if (n) { bPtr[n] = '\0'; - if (ParseHeader(headerbuffer)) { - op = Sending; - t_ref = RecordPerformanceData(&perfData.HeaderParsed, t_ref); - INFO("Header Parsed at %u", (unsigned int)PerformanceTimer.read_us()); + switch (ParseHeader(headerbuffer)) { + case ACCEPT_ERROR: + break; + case ACCEPT_COMPLETE: + op = Sending; + t_ref = RecordPerformanceData(&perfData.HeaderParsed, t_ref); + INFO("Header Parsed at %u", (unsigned int)PerformanceTimer.read_us()); + break; + case ACCEPT_CONTINUE: + op = ReceivingPayload; + break; } bPtr += n; } break; + case ReceivingPayload: + // After the header, there is a payload that will be handled + op = Sending; + break; + case Sending: SendResponse(); op = WaitingToClose; @@ -537,10 +552,10 @@ } -bool HTTPServer::ParseHeader(char * buffer) +HTTPServer::CallBackResults HTTPServer::ParseHeader(char * buffer) { char * dblCR; - bool advanceState = false; + CallBackResults advanceState = ACCEPT_ERROR; int bytecount; // Buffer could have partial, but the double \r\n is the key @@ -549,7 +564,7 @@ // GET /QueryString HTTP/1.1\r\nHost: 192.168.1.140\r\nCache-Control: max-age=0\r\n\r\n dblCR = strstr(buffer,"\r\n\r\n"); if (dblCR) { // Have to scan from the beginning in case split on \r - INFO("==\r\n%s==\r\n", buffer); + INFO("\r\n==\r\n%s==", buffer); char * soRec = buffer; // start of the next record of text char * eoRec = strchr(soRec, '\n'); // search for end of the current record @@ -581,20 +596,21 @@ // "Connection: keep-alive" becomes "Connection" "keep-alive" char *delim = strstr(soRec, ": "); char *chkSpace = strchr(soRec, ' '); // a field-name has no space ahead of the ":" - if (delim - && (!chkSpace || (chkSpace && delim < chkSpace)) - && headerParamCount < maxheaderParams) { + if (delim + && (!chkSpace || (chkSpace && delim < chkSpace)) + && headerParamCount < maxheaderParams) { *delim++ = '\0'; // replace ": " with null *delim++ = '\0'; headerParams[headerParamCount].name = soRec; headerParams[headerParamCount].value = delim; INFO("%d: headerParams[%s] = {%s}", headerParamCount, - headerParams[headerParamCount].name, headerParams[headerParamCount].value); + headerParams[headerParamCount].name, headerParams[headerParamCount].value); headerParamCount++; } soRec = eoRec + 1; eoRec = strchr(soRec, '\n'); } + if (queryString) { // We have enough to try to reply INFO("create reply queryType{%s}, queryString{%s}", "GET", queryString); @@ -606,12 +622,12 @@ if (paramDelim) { *paramDelim++ = '\0'; UnescapeString(paramDelim); // everything after the '?' - ParseParameters(paramDelim); // pointing at the NULL, but there are queryParams beyond + ParseParameters(paramDelim); // pointing at the NULL, but there are queryParams beyond } } else { - ERR("queryString not found in (%s)", soRec); + ERR("queryString not found in (%s) [this should never happen]", soRec); } - advanceState = true; + advanceState = ACCEPT_COMPLETE; buffer[0] = 0; // This part parses the extra data on a POST method. @@ -619,8 +635,6 @@ // it would make sense to move some of this responsibility to // that handler. It could then choose if it wanted to allocate // the requested 'Content-Length' amount of memory. - // Should we check the 'Content-Type' to see if it is - // 'application/x-www-form-urlencoded'? int postBytes = atoi(GetHeaderValue("Content-Length")); CallBackResults acceptIt = ACCEPT_ERROR; if (strcmp(queryType, "POST") == 0 && postBytes > 0 ) { @@ -633,7 +647,7 @@ if (strcmp(handlers[ndxHandler].path, queryString) == 0) { acceptIt = (*handlers[ndxHandler].callback)(this, CONTENT_LENGTH_REQUEST, queryString, queryParams, queryParamCount); regHandled = true; - break; // we only execute the first one + break; // only one callback per path allowed } } @@ -665,7 +679,7 @@ offset[n] = '\0'; INFO("HTTPd: %d of %d: [%s]", len, postBytes, offset); } else if (n < 0) { - INFO("HTTPd; n=%d", n); + INFO("*** receive returned %d ***", n); break; // no more data, before the plan } } @@ -685,6 +699,7 @@ // Simply copy it to the bitbucket int bytesToDump = postBytes; char * bitbucket = (char *)mymalloc(201); + dblCR += 4; while (*dblCR && *dblCR <= ' ') dblCR++; @@ -692,6 +707,10 @@ while (bytesToDump > 0) { int n = (bytesToDump > 200) ? 200 : bytesToDump; n = client.receive(bitbucket, n); + if (n < 0) { + ERR("to the bitbucket."); + break; + } bytesToDump -= n; } myfree(bitbucket); @@ -707,12 +726,11 @@ const char * HTTPServer::GetHeaderValue(const char * hdr) { int i; - - for (i=0; i<headerParamCount; i++) - { + + for (i=0; i<headerParamCount; i++) { if (strcmp(hdr, headerParams[i].name) == 0) return headerParams[i].value; - } + } return NULL; }