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

Dependents:   Smart-WiFly-WebServer WattEye X10Svr SSDP_Server

Revision:
27:90a1f5a5392f
Parent:
26:38102ef2b132
Child:
28:f93ef41b78e1
--- a/SW_HTTPServer.cpp	Thu Oct 10 18:46:55 2013 +0000
+++ b/SW_HTTPServer.cpp	Thu Oct 10 20:38:12 2013 +0000
@@ -14,7 +14,20 @@
 #include "SW_HTTPServer.h"
 #include "Utility.h"
 
-#define DEBUG
+#define DEBUG "HTTP"
+
+#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__);
+#else
+#define DBG(x, ...)
+#define WARN(x, ...)
+#define ERR(x, ...)
+#define INFO(x, ...)
+#endif
+
 
 const char * DEFAULT_FILENAME = "index.htm";
 
@@ -87,6 +100,8 @@
     wifly = _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));
@@ -168,7 +183,7 @@
     static state lastOp = Reset;
     if (lastOp != op) {
         const char *states[] = {"Idle", "Receiving", "Sending", "WaitingToClose", "Reset"};
-        pc->printf("Poll: %s\r\n", states[op]);
+        INFO("Poll: %s", states[op]);
         lastOp = op;
     }
 #endif
@@ -184,26 +199,20 @@
             if (0 == server->accept(client)) {
                 op = Receiving;
                 t_ref = RecordPerformanceData(&perfData.ConnectionAccepted, t_ref);
-#ifdef DEBUG
-                pc->printf("Accepted at %u\r\n", (unsigned int)PerformanceTimer.read_us());
-#endif
+                INFO("Accepted at %u", (unsigned int)PerformanceTimer.read_us());
             }
             break;
 
         case Receiving:
             n = client.receive(bPtr, headerbuffersize - (bPtr - headerbuffer));
             if (n < 0) {
-#ifdef DEBUG
-                pc->printf("*** client.receive() => %d\r\n", n);
-#endif
+                INFO("*** client.receive() => %d", n);
             } else if (n) {
                 bPtr[n] = '\0';
                 if (ParseHeader(headerbuffer)) {
                     op = Sending;
                     t_ref = RecordPerformanceData(&perfData.HeaderParsed, t_ref);
-#ifdef DEBUG
-                    pc->printf("Header Parsed at %u\r\n", (unsigned int)PerformanceTimer.read_us());
-#endif
+                    INFO("Header Parsed at %u", (unsigned int)PerformanceTimer.read_us());
                 }
                 bPtr += n;
             }
@@ -213,21 +222,15 @@
             SendResponse();
             op = WaitingToClose;
             t_ref = RecordPerformanceData(&perfData.ResponseSent, t_ref);
-#ifdef DEBUG
-            pc->printf("Response Sent at %u\r\n", (unsigned int)PerformanceTimer.read_us());
-#endif
+            INFO("Response Sent at %u", (unsigned int)PerformanceTimer.read_us());
             break;
 
         case WaitingToClose:
-#ifdef DEBUG
-            pc->printf("Connection closed entry %u\r\n", (unsigned int)PerformanceTimer.read_us());
-#endif
+            INFO("Connection closed entry %u", (unsigned int)PerformanceTimer.read_us());
             close_connection();
             op = Idle;
             RecordPerformanceData(&perfData.ConnectionClosed, t_ref);
-#ifdef DEBUG
-            pc->printf("Connection closed exit  %u\r\n", (unsigned int)PerformanceTimer.read_us());
-#endif
+            INFO("Connection closed exit  %u", (unsigned int)PerformanceTimer.read_us());
             break;
     }
 }
@@ -397,9 +400,7 @@
     bool res;
 
     res = server->close();
-#ifdef DEBUG
-    pc->printf("close connection returned %d\r\n", res);
-#endif
+    INFO("close connection returned %d", res);
     return res;
 }
 
@@ -427,9 +428,7 @@
             if (eqs)
                 *eqs = '\0';
             *string = container;
-#ifdef DEBUG
-            pc->printf("Extract(%s) = %s\r\n", needle, container);
-#endif
+            INFO("Extract(%s) = %s", needle, container);
             ret = true;
         } else {
             *string = NULL;     // something bad happened... no memory
@@ -495,9 +494,7 @@
 
 void HTTPServer::SendResponse()
 {
-#ifdef DEBUG
-    pc->printf("SendResponse(%s) at %u\r\n", queryType, (unsigned int)PerformanceTimer.read_us());
-#endif
+    INFO("SendResponse(%s) at %u", queryType, (unsigned int)PerformanceTimer.read_us());
     if (strcmp(queryType, "GET") == 0 ||  strcmp(queryType, "POST") == 0) {
         if (!(queryString[0] == '.' && queryString[1] == '.')) {
             const char * fType;
@@ -522,9 +519,7 @@
     } else {
         header(400, "Bad Request", "Pragma: err - Unsupported query type\r\n");
     }
-#ifdef DEBUG
-    pc->printf("  SendResponse complete at %u\r\n", (unsigned int)PerformanceTimer.read_us());
-#endif
+    INFO("  SendResponse complete at %u", (unsigned int)PerformanceTimer.read_us());
 
     if (queryType) {
         myfree(queryType);
@@ -538,9 +533,7 @@
         myfree(postQueryString);
         postQueryString = NULL;
     }
-#ifdef DEBUG
-    pc->printf("  SendResponse free at %u\r\n", (unsigned int)PerformanceTimer.read_us());
-#endif
+    INFO("  SendResponse free at %u", (unsigned int)PerformanceTimer.read_us());
 }
 
 
@@ -556,9 +549,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
-#ifdef DEBUG
-        pc->printf("==\r\n%s==\r\n", buffer);
-#endif
+        INFO("==\r\n%s==\r\n", buffer);
         char * soRec = buffer;                  // start of the next record of text
         char * eoRec = strchr(soRec, '\n');     // search for end of the current record
 
@@ -597,10 +588,8 @@
                 *delim++ = '\0';
                 headerParams[headerParamCount].name = soRec;
                 headerParams[headerParamCount].value = delim;
-#ifdef DEBUG
-                pc->printf("%d: headerParams[%s] = {%s}\r\n", headerParamCount,
+                INFO("%d: headerParams[%s] = {%s}", headerParamCount,
                            headerParams[headerParamCount].name, headerParams[headerParamCount].value);
-#endif
                 headerParamCount++;
             }
             soRec = eoRec + 1;
@@ -608,9 +597,7 @@
         }
         if (queryString) {
             // We have enough to try to reply
-#ifdef DEBUG
-            pc->printf("create reply queryType{%s}, queryString{%s}\r\n", "GET", queryString);
-#endif
+            INFO("create reply queryType{%s}, queryString{%s}", "GET", queryString);
             // parse queryParams - if any
             // /file.htm?name1=value1&name2=value2...
             // /file.htm?name1&name2=value2...
@@ -622,7 +609,7 @@
                 ParseParameters(paramDelim);    // pointing at the NULL, but there are queryParams beyond
             }
         } else {
-            pc->printf("ERROR: queryString not found in (%s)\r\n", soRec);
+            ERR("queryString not found in (%s)", soRec);
         }
         advanceState = true;
         buffer[0] = 0;
@@ -638,18 +625,26 @@
         bool acceptIt = false;
         if (strcmp(queryType, "POST") == 0 && postBytes > 0 ) {
             if (postBytes) {
+                int ndxHandler = 0;
                 bool regHandled = false;
                 // Registered Dynamic Handler
                 // 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, queryParams, queryParamCount);
+                for (ndxHandler=0; ndxHandler<handlercount; ndxHandler++) {
+                    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
                     }
                 }
 
                 if (regHandled && acceptIt) {
+                    // @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.
+                    //
                     // If so, we'll make space for it
                     postQueryString = (char *)mymalloc(postBytes + 1);
                     if (postQueryString) {
@@ -666,12 +661,22 @@
                             n = client.receive(offset, postBytes - len);
                             if (n >=0) {
                                 offset[n] = '\0';
+                                //printf("HTTPd: %d of %d: [%s]\r\n", len, postBytes, offset);
+                            } else if (n < 0) {
+                                //printf("HTTPd: n=%d\r\n", n);
+                                break;      // no more data, before the plan
                             }
                         }
                         if (len >= 0) {
-                            UnescapeString(postQueryString);
-                            ParseParameters(postQueryString);
+//                            UnescapeString(postQueryString);
+//                            ParseParameters(postQueryString);
+                            // use the same handler as for the length check
+                            acceptIt = (*handlers[ndxHandler].callback)(this, DATA_TRANSFER, postQueryString, NULL, 0);
+                        } else {
+                            ERR("HTTPd: len error.");
                         }
+                    } else {
+                        ERR("HTTPd: attempt to allocate %d failed.", postBytes+1);
                     }
                 } else {
                     // Simply copy it to the bitbucket
@@ -695,6 +700,7 @@
 }
 
 
+
 const char * HTTPServer::GetHeaderValue(const char * hdr)
 {
     int i;