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:
- 13:8975d7928678
- Parent:
- 12:109bf1558300
- Child:
- 14:19c5f6151319
diff -r 109bf1558300 -r 8975d7928678 SW_HTTPServer.cpp --- a/SW_HTTPServer.cpp Sun Aug 11 15:49:51 2013 +0000 +++ b/SW_HTTPServer.cpp Mon Aug 12 11:26:59 2013 +0000 @@ -77,7 +77,8 @@ Wifly * _wf, int port, const char * _webroot, - int _maxparams, + int maxheaderParams, + int _maxqueryParams, int _maxdynamicpages, PC * _pc, int _allocforheader, @@ -86,21 +87,22 @@ wifly = _wf; webroot = (char *)malloc(strlen(_webroot)+1); strcpy(webroot, _webroot); - maxparams = _maxparams; + maxqueryParams = _maxqueryParams; maxdynamicpages = _maxdynamicpages; - params = (namevalue *)malloc(maxparams * sizeof(namevalue)); + headerParams = (namevalue *)malloc(maxheaderParams * sizeof(namevalue)); + queryParams = (namevalue *)malloc(maxqueryParams * sizeof(namevalue)); handlers = (handler *)malloc(maxdynamicpages * sizeof(handler)); headerbuffersize = _allocforheader; headerbuffer = (char *)malloc(headerbuffersize); pc = _pc; queryType = NULL; queryString = NULL; - hostString = NULL; - contentLength = NULL; - contentType = NULL; - authorization = NULL; +// hostString = NULL; +// contentLength = NULL; +// contentType = NULL; +// authorization = NULL; postQueryString = NULL; - paramcount = 0; + queryParamCount = 0; handlercount = 0; maxheaderbytes = 0; server = new TCPSocketServer(); @@ -121,7 +123,7 @@ myfree(handlers[i].path); myfree(headerbuffer); myfree(handlers); - myfree(params); + myfree(queryParams); myfree(webroot); webroot = NULL; } @@ -322,9 +324,9 @@ const char * HTTPServer::GetParameter(const char * name) { - for (int i=0; i<paramcount; i++) { - if (strcmp(params[i].name, name) == 0) { - return params[i].value; + for (int i=0; i<queryParamCount; i++) { + if (strcmp(queryParams[i].name, name) == 0) { + return queryParams[i].value; } } return NULL; @@ -337,32 +339,32 @@ char * pVal; char * pNextName; - // Parse params + // Parse queryParams pVal = strchr(pName, '#'); // If there is a '#fragment_id', we can ignore it if (pVal) *pVal = '\0'; do { //pc->printf("Parse(%s)\r\n", pName); //*pName++ = '\0'; // already '\0' on the first entry - params[paramcount].name = pName; + queryParams[queryParamCount].name = pName; pVal = strchr(pName, '='); pNextName = strchr(pName,'&'); if (pVal) { if (pNextName == NULL || (pNextName && pNextName > pVal)) { *pVal++ = '\0'; - params[paramcount].value = pVal; + queryParams[queryParamCount].value = pVal; pName = pVal; } } - //pc->printf(" [%s]=[%s]\r\n", params[paramcount].name, params[paramcount].value); - paramcount++; + //pc->printf(" [%s]=[%s]\r\n", queryParams[queryParamCount].name, queryParams[queryParamCount].value); + queryParamCount++; if (pNextName) { pName = pNextName; *pName++ = '\0'; } else { pName = NULL; } - } while (pName && paramcount < maxparams); + } while (pName && queryParamCount < maxqueryParams); } @@ -493,7 +495,7 @@ // If this queryString is in the list of registered handlers, call that for (int i=0; i<handlercount; i++) { if (strcmp(handlers[i].path, queryString) == 0) { - (*handlers[i].callback)(this, SEND_PAGE, queryString, params, paramcount); + (*handlers[i].callback)(this, SEND_PAGE, queryString, queryParams, queryParamCount); regHandled = true; break; // we only execute the first one } @@ -544,22 +546,22 @@ myfree(queryString); queryString = NULL; } - if (hostString) { - myfree(hostString); - hostString = NULL; - } - if (contentLength) { - myfree(contentLength); - contentLength = NULL; - } - if (contentType) { - myfree(contentType); - contentType = NULL; - } - if (authorization) { - myfree(authorization); - authorization = NULL; - } +// if (hostString) { +// myfree(hostString); +// hostString = NULL; +// } +// if (contentLength) { +// myfree(contentLength); +// contentLength = NULL; +// } +// if (contentType) { +// myfree(contentType); +// contentType = NULL; +// } +// if (authorization) { +// myfree(authorization); +// authorization = NULL; +// } if (postQueryString) { myfree(postQueryString); postQueryString = NULL; @@ -573,7 +575,7 @@ int bytecount; // Buffer could have partial, but the double \r\n is the key - // GET /QueryString HTTP/1.1\r\n + // GET /QueryString?this=that&sky=blue HTTP/1.1\r\n // GET /QueryString HTTP/1.1\r\nHost: 192.168.1.140\r\nCache-Con // 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"); @@ -582,8 +584,9 @@ pc->printf("==\r\n%s==\r\n", buffer); #endif char * soRec = buffer; // start of the next record of text - char * eoRec = strchr(soRec, '\n'); // search for end of a record + char * eoRec = strchr(soRec, '\n'); // search for end of the current record + headerParamCount = 0; bytecount = strlen(buffer); if (bytecount > maxheaderbytes) maxheaderbytes = bytecount; @@ -611,10 +614,28 @@ } //printf("POST: %s\r\n", queryString); } - Extract(soRec, "Host: ", &hostString); - Extract(soRec, "Content-Length: ", &contentLength); - Extract(soRec, "Content-Type: ", &contentType); - Extract(soRec, "Authorization: ", &authorization); + + // if there is a ": " delimiter, we have a header item to parse into name,value pair + // "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) { + *delim++ = '\0'; + *delim++ = '\0'; + headerParams[headerParamCount].name = soRec; + headerParams[headerParamCount].value = delim; +#ifdef DEBUG + pc->printf("%d: headerParams[%s] = {%s}\r\n", headerParamCount, + headerParams[headerParamCount].name, headerParams[headerParamCount].value); +#endif + headerParamCount++; + } +// Extract(soRec, "Host: ", &hostString); +// Extract(soRec, "Content-Length: ", &contentLength); +// Extract(soRec, "Content-Type: ", &contentType); +// Extract(soRec, "Authorization: ", &authorization); soRec = eoRec + 1; eoRec = strchr(soRec, '\n'); } @@ -623,18 +644,18 @@ #ifdef DEBUG pc->printf("create reply queryType{%s}, queryString{%s}\r\n", "GET", queryString); #endif - // parse params - if any + // parse queryParams - if any // /file.htm?name1=value1&name2=value2... // /file.htm?name1&name2=value2... - paramcount = 0; + queryParamCount = 0; char * paramDelim = strchr(queryString, '?'); if (paramDelim) { *paramDelim++ = '\0'; UnescapeString(paramDelim); // everything after the '?' - ParseParameters(paramDelim); // pointing at the NULL, but there are params beyond + ParseParameters(paramDelim); // pointing at the NULL, but there are queryParams beyond } - //for (int i=0; i<paramcount; i++) - // pc->printf("param %d '%s'='%s'\r\n", i, params[i].name, params[i].value); + //for (int i=0; i<queryParamCount; i++) + // pc->printf("param %d '%s'='%s'\r\n", i, queryParams[i].name, queryParams[i].value); } else { pc->printf("ERROR: queryString not found in (%s)\r\n", soRec); } @@ -648,7 +669,7 @@ // 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(contentLength); + int postBytes = atoi(GetHeaderValue("Content-Length")); bool acceptIt = false; //pc->printf("Content-Length = %d\r\n", postBytes); if (strcmp(queryType, "POST") == 0 && postBytes > 0 ) { @@ -658,7 +679,7 @@ // Callback and ask if they want to accept this data for (int i=0; i<handlercount; i++) { if (strcmp(handlers[i].path, queryString) == 0) { - acceptIt = (*handlers[i].callback)(this, CONTENT_LENGTH_REQUEST, queryString, params, paramcount); + acceptIt = (*handlers[i].callback)(this, CONTENT_LENGTH_REQUEST, queryString, queryParams, queryParamCount); regHandled = true; break; // we only execute the first one } @@ -709,6 +730,18 @@ return advanceState; } +const char * HTTPServer::GetHeaderValue(const char * hdr) +{ + int i; + + for (i=0; i<headerParamCount; i++) + { + if (strcmp(hdr, headerParams[i].name) == 0) + return headerParams[i].value; + } + return NULL; +} + void HTTPServer::GetPerformanceData(SW_PerformanceData * p) {