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

Dependents:   Smart-WiFly-WebServer WattEye X10Svr SSDP_Server

Revision:
39:0427544a5c08
Parent:
38:c8fa31e6fe02
Child:
40:02c49fadbb94
--- a/SW_HTTPServer.cpp	Sat Jul 26 19:49:13 2014 +0000
+++ b/SW_HTTPServer.cpp	Mon Sep 01 20:53:19 2014 +0000
@@ -35,7 +35,7 @@
 const char * DEFAULT_FILENAME = "index.htm";
 
 // Header information to always send (must be \r\n terminated)
-const char hdr_httpver[] = "HTTP/1.0";                  // Wifly may not be able to support HTTP/1.1 protocol
+const char hdr_httpver[] = "HTTP/1.0";                  // supported HTTP/1.1 protocol
 const char hdr_age[]     = "Max-age: 0\r\n";            // expires right away
 const char hdr_server[]  = "Server: Smart_Server v0.1\r\n"; // Server
 const char hdr_close[]   = "Connection: close\r\n";     // tell the client the server closes the connection immediately
@@ -92,7 +92,6 @@
 #endif
 
 HTTPServer::HTTPServer(
-    void * _wf,
     int port,
     const char * _webroot,
     int maxheaderParams,
@@ -102,15 +101,21 @@
     int _allocforheader,
     int _allocforfile)
 {
-    (void)_wf;
     webroot = (char *)malloc(strlen(_webroot)+1);
     strcpy(webroot, _webroot);
     if (strlen(webroot)>1 && webroot[strlen(webroot)-1] == '/') // remove trailing '/'
         webroot[strlen(webroot)-1] = '\0';
-    maxqueryParams = _maxqueryParams;
     maxdynamicpages = _maxdynamicpages;
     headerParams = (namevalue *)malloc(maxheaderParams * sizeof(namevalue));
+
+    maxqueryParams = _maxqueryParams;
     queryParams = (namevalue *)malloc(maxqueryParams * sizeof(namevalue));
+    queryParamCount = 0;
+    
+    maxPostParams = _maxqueryParams;   // Same as Query params, but for post method
+    postParams = (namevalue *)malloc(maxPostParams * sizeof(namevalue));
+    postParamCount = 0;
+    
     handlers = (handler *)malloc(maxdynamicpages * sizeof(handler));
     headerbuffersize = _allocforheader;
     headerbuffer = (char *)malloc(headerbuffersize);
@@ -118,7 +123,6 @@
     queryType = NULL;
     queryString = NULL;
     postQueryString = NULL;
-    queryParamCount = 0;
     handlercount = 0;
     maxheaderbytes = 0;
     server = new TCPSocketServer();
@@ -336,6 +340,7 @@
     return 16 * HexCharToInt(*p) + HexCharToInt(*(p+1));
 }
 
+// modifies in-place
 void HTTPServer::UnescapeString(char * encoded)
 {
     char *p;
@@ -377,10 +382,38 @@
     return NULL;
 }
 
+HTTPServer::namevalue * HTTPServer::GetParameter(int index)
+{
+    if (index < queryParamCount)
+        return &queryParams[index];
+    else
+        return NULL;
+}
+
+const char * HTTPServer::GetPostParameter(const char * name)
+{
+    INFO("GetPostParameter(%s)", name);
+    for (int i=0; i<postParamCount; i++) {
+        INFO("  %d: %s = %s", i, postParams[i].name, postParams[i].value);
+        if (strcmp(postParams[i].name, name) == 0) {
+            INFO("  value {%s}", postParams[i].value);
+            return postParams[i].value;
+        }
+    }
+    return NULL;
+}
+
+HTTPServer::namevalue * HTTPServer::GetPostParameter(int index)
+{
+    if (index < postParamCount)
+        return &postParams[index];
+    else
+        return NULL;
+}
 
 // this=that&who=what&more=stuff...
 // ^   ^    ^
-int HTTPServer::ParseParameters(char * pName)
+int HTTPServer::ParseParameters(namevalue * qP, int * qpCount, int maxP, char * pName)
 {
     char * pVal;
     char * pNextName;
@@ -390,14 +423,14 @@
     if (pVal)
         *pVal = '\0';
     do {
-        INFO("ParseParameters(%s)", pName);
-        queryParams[queryParamCount].name = pName;
+        INFO("ParseParameters(%s), qP:{%s}, qpCount: %d", pName, qP->name, *qpCount);
+        qP->name = pName;
         pVal = strchr(pName, '=');
         pNextName = strchr(pName,'&');
         if (pVal) {
             if (pNextName == NULL || (pNextName && pNextName > pVal)) {
                 *pVal++ = '\0';
-                queryParams[queryParamCount].value = pVal;
+                qP->value = pVal;
                 pName = pVal;
             }
         }
@@ -407,11 +440,12 @@
         } else {
             pName = NULL;
         }
-        INFO("  param{%s}={%s}", queryParams[queryParamCount].name, queryParams[queryParamCount].value);
-        queryParamCount++;
-    } while (pName && queryParamCount < maxqueryParams);
-    INFO("  count %d", queryParamCount);
-    return queryParamCount;
+        INFO("  param{%s}={%s}", qP->name, qP->value);
+        *qpCount += 1;
+        qP++;
+    } while (pName && *qpCount < maxP);
+    INFO("  count %d", *qpCount);
+    return *qpCount;
 }
 
 
@@ -522,6 +556,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) {
+            INFO("CheckDynamicHandlers - SEND_PAGE");
             (*handlers[i].callback)(this, SEND_PAGE, queryString, queryParams, queryParamCount);
             regHandled = true;
             break;      // we only execute the first one
@@ -586,7 +621,7 @@
     //      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
-    //      POST /dyn2 HTTP/1.2\r\nAccept: text/html, application/xhtml+xml, */*\r\n\r\nle
+    //      POST /dyn2 HTTP/1.2\r\nAccept: text/html, application/xhtml+xml, */*\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==\r\n%s==", buffer);
@@ -611,7 +646,7 @@
                     strcpy(queryType, "GET");
                 }
             } else if (strstr(soRec, "POST ") == soRec) {
-               Extract(soRec, "POST", &queryString);
+                Extract(soRec, "POST", &queryString);
                 if (queryString) {
                     queryType = (char *)mymalloc(strlen("POST")+1);
                     strcpy(queryType, "POST");
@@ -648,7 +683,7 @@
             if (paramDelim) {
                 *paramDelim++ = '\0';
                 UnescapeString(paramDelim);   // everything after the '?'
-                ParseParameters(paramDelim);  // pointing past the NULL, and there are queryParams here
+                ParseParameters(queryParams, &queryParamCount, maxqueryParams, paramDelim);  // pointing past the NULL, and there are queryParams here
             }
         } else {
             ERR("queryString not found in (%s) [this should never happen]", soRec);
@@ -704,12 +739,12 @@
                         strcpy(postQueryString, dblCR);
                         INFO("  {%s}", postQueryString);
                         while (ttlCount <= postBytes && !escape) {
-                            INFO("ttlCount: %d < postBytes: %d, of chunk %d", ttlCount, postBytes, CHUNK_SIZE);
+                            INFO("ttlCount: %d <= postBytes: %d, of chunk %d", ttlCount, postBytes, CHUNK_SIZE);
                             len = client.receive_all(postQueryString + ttlCount, CHUNK_SIZE - ttlCount);
                             if (len > 0) {
-                                INFO("  len: %d, ttlCount: %d < postBytes %d, {%s}", len, ttlCount, postBytes, postQueryString);
+                                INFO("  len: %d, ttlCount: %d < postBytes %d, {%s}", len, ttlCount, postBytes, postQueryString + ttlCount);
                                 ttlCount += len;
-                                postQueryString[len] = '\0';    // Whether binary or ASCII, this is ok as it's after the data
+                                postQueryString[ttlCount] = '\0';    // Whether binary or ASCII, this is ok as it's after the data
                                 INFO("  postBytes %d: [%s], [%d]", postBytes, postQueryString, ndxHandler);
                                 escapePlan.reset();
                             } else if (len < 0) {
@@ -723,10 +758,12 @@
                                 WARN("Escape plan activated.");
                             }
                         }
-                        acceptIt = (*handlers[ndxHandler].callback)(this, DATA_TRANSFER, postQueryString, NULL, 0);
+                        postParamCount = 0;
+                        INFO("post: %s", postQueryString);
+                        ParseParameters(postParams, &postParamCount, maxPostParams, postQueryString);
+                        acceptIt = (*handlers[ndxHandler].callback)(this, DATA_TRANSFER, queryString, queryParams, queryParamCount);
                         INFO("..processing exit");
                         acceptIt = (*handlers[ndxHandler].callback)(this, DATA_TRANSFER_END, NULL, NULL, 0);
-                        myfree(postQueryString);
                     } else {
                         ERR("attempt to allocate %d failed.", CHUNK_SIZE);
                     }