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

Dependents:   Smart-WiFly-WebServer WattEye X10Svr SSDP_Server

Revision:
8:262583f054f6
Parent:
7:99ad7a67f05e
Child:
9:2ea342765c9d
--- a/SW_HTTPServer.cpp	Thu Jun 27 17:08:25 2013 +0000
+++ b/SW_HTTPServer.cpp	Mon Jul 01 04:36:54 2013 +0000
@@ -14,17 +14,17 @@
 #include "SW_HTTPServer.h"
 #include "Utility.h"
 
-#define DEBUG
+//#define DEBUG
 
 const char * DEFAULT_FILENAME = "index.htm";
 
-// Header information to always send
-const char hdr_httpver[] = "HTTP/1.1";              // typically HTTP/1.0 or HTTP/1.1
-const char hdr_age[] = "Max-age: 0\r\n";            // expires right away (must be \r\n terminated)
-const char hdr_server[] = "Server: Smart_Server v0.1\r\n"; // Server (must be \r\n terminated)
-const char hdr_dnt[] = "DNT: 1\r\n";                // Do Not Track
-const char hdr_close[] = "Connection: close\r\n";       // tell the client to close the connection (must be \r\n terminated)
-const char nl[] = "\r\n";                           // final \r\n for the termination of the header
+// Header information to always send (must be \r\n terminated)
+const char hdr_httpver[] = "HTTP/1.0";                  // typically HTTP/1.0 or HTTP/1.1
+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_dnt[]     = "DNT: 1\r\n";                // Do Not Track
+const char hdr_close[]   = "Connection: close\r\n";     // tell the client to close the connection
+const char nl[]          = "\r\n";                      // final \r\n for the termination of the header
 
 static const struct {
     char *ext;
@@ -45,6 +45,21 @@
     {0,0}
 };
 
+#ifdef DEBUG
+static void * MyMalloc(int x, int y)
+{
+    std::printf("[%04d] malloc(%d)\r\n", y, x);
+    return malloc(x);
+}
+#define mymalloc(x) MyMalloc(x, __LINE__)
+#define myfree(x) \
+    pc->printf("[%04d] free(%02x %02x %02x %02x ...\r\n", __LINE__, *x, *(x+1), *(x+2), *(x+3)); \
+    free(x);
+#else
+#define mymalloc(x) malloc(x)
+#define myfree(x) free(x)
+#endif
+
 HTTPServer::HTTPServer(
     Wifly * _wf,
     int port,
@@ -77,16 +92,23 @@
     server = new TCPSocketServer();
     server->bind(port);
     server->listen();
-    server->set_blocking(false, 0);
-    client.set_blocking(false, 0);
-    server->accept(client);
+//    server->set_blocking(false, 0);
+//    client.set_blocking(false, 0);
+//    server->accept(client);
     ResetPerformanceData();
     timer.start();
 }
 
 HTTPServer::~HTTPServer()
 {
-    free(webroot);
+    int i;
+
+    for (i=0; i<handlercount; i++)
+        myfree(handlers[i].path);
+    myfree(headerbuffer);
+    myfree(handlers);
+    myfree(params);
+    myfree(webroot);
     webroot = NULL;
 }
 
@@ -98,7 +120,7 @@
 bool HTTPServer::RegisterHandler(const char * path, Handler callback)
 {
     if (handlercount < maxdynamicpages && path && callback) {
-        handlers[handlercount].path = (char *)malloc(strlen(path)+1);
+        handlers[handlercount].path = (char *)mymalloc(strlen(path)+1);
         memcpy(handlers[handlercount].path, path, strlen(path)+1);
         handlers[handlercount].callback = callback;
         handlercount++;
@@ -128,33 +150,39 @@
         Reset
     } state;
     static state op = Idle;
-    static state lastOp = Reset;
     static char * bPtr = headerbuffer;
     int n;
     static int t_ref;       // reference point for the timer
 
-    #ifdef DEBUG
+#ifdef DEBUG
+    static state lastOp = Reset;
     if (lastOp != op) {
-        pc->printf("%d", op);
+        char *states[] = {"Idle", "Receiving", "Sending", "WaitingToClose", "Reset"};
+        pc->printf("Poll: %s\r\n", states[op]);
         lastOp = op;
     }
-    #endif
+#endif
     switch(op) {
         default:                    // not expected to arrive here
             op = Idle;
             break;
+
         case Idle:
             timer.reset();
             bPtr = headerbuffer;
-            if (0 == client.receive(bPtr, 0)) {  // server->accept(client) == 0) {
+            if (0 == server->accept(client)) { // client.receive(bPtr, 0)) {  // server->accept(client) == 0) {
                 op = Receiving;
                 t_ref = timer.read_us();
+#ifdef DEBUG
+                pc->printf("Accept at %d\r\n", t_ref);
+#endif
             }
             break;
+
         case Receiving:
             n = client.receive(bPtr, headerbuffersize - (bPtr - headerbuffer));
             if (n < 0) {
-                ; // pc->printf("*** client.receive error: %d\r\n", n);
+                pc->printf("*** client.receive() => %d\r\n", n);
             } else if (n) {
                 bPtr[n] = '\0';
                 if (ParseHeader(headerbuffer)) {
@@ -164,6 +192,7 @@
                 bPtr += n;
             }
             break;
+
         case Sending:
             SendResponse();
             op = WaitingToClose;
@@ -207,7 +236,7 @@
 
     fp  = fopen(filename,"rb");
     if (fp) { // can open it
-        char *fbuffer = (char *)malloc(FILESEND_BUF_SIZE);
+        char *fbuffer = (char *)mymalloc(FILESEND_BUF_SIZE);
         int bytes;
 
         if (fbuffer) {
@@ -217,7 +246,7 @@
                 send(fbuffer, bytes);
                 bytes = fread(fbuffer,sizeof(char),FILESEND_BUF_SIZE,fp);
             }
-            free(fbuffer);
+            myfree(fbuffer);
         } else {
             header(500, "Server Error", "Pragma: err - insufficient memory\r\n");
         }
@@ -383,19 +412,23 @@
     char * get = strstr(haystack, needle);    // what if not at the front?
     if (get) {
         // Seems to be a valid "...GET /QueryString HTTP/1.1"
+        // or "...<needle>param..."
         qs = get + strlen(needle);  // in case the needle didn't have space delimiters
         while (*qs == ' ')
             qs++;
         // /QueryString\0HTTP/1.1\0\0
         if (*string)            // recycle old string when working a new one
-            free(*string);
-        container = (char *)malloc(strlen(qs));
+            myfree(*string);
+        container = (char *)mymalloc(strlen(qs));
         if (container) {
             strcpy(container, qs);
             eqs = strchr(container, ' ');
             if (eqs)
                 *eqs = '\0';
             *string = container;
+#ifdef DEBUG
+            pc->printf("Extract(%s) = %s\r\n", needle, container);
+#endif
             ret = true;
         } else {
             *string = NULL;     // something bad happened... no memory
@@ -406,13 +439,13 @@
 
 char * HTTPServer::rewriteWithDefaultFile(char * queryString)
 {
-    char * temp = (char *)malloc(strlen(queryString) + strlen(DEFAULT_FILENAME) + 1);
+    char * temp = (char *)mymalloc(strlen(queryString) + strlen(DEFAULT_FILENAME) + 1);
 
     if (temp) {
         *temp = '\0';
         strcpy(temp, queryString);
         strcat(temp, DEFAULT_FILENAME);
-        free(queryString);
+        myfree(queryString);
         return temp;
     } else {
         return queryString;
@@ -421,7 +454,7 @@
 
 char * HTTPServer::rewritePrependWebroot(char * queryString)
 {
-    char * temp = (char *)malloc(strlen(webroot) + strlen(queryString) + 1);
+    char * temp = (char *)mymalloc(strlen(webroot) + strlen(queryString) + 1);
 
     if (temp) {
         *temp = '\0';
@@ -429,7 +462,7 @@
         if (temp[strlen(temp)-1] == '/' && *queryString == '/')
             temp[strlen(temp)-1] = '\0';
         strcat(temp, queryString);
-        free(queryString);
+        myfree(queryString);
         return temp;
     } else {
         return queryString;
@@ -453,10 +486,16 @@
 
 void HTTPServer::SendResponse()
 {
+#ifdef DEBUG
+    pc->printf("SendResponse(%s) [%d]\r\n", queryType, __LINE__);
+#endif
     if (strcmp(queryType, "GET") == 0 ||  strcmp(queryType, "POST") == 0) {
         if (!(queryString[0] == '.' && queryString[1] == '.')) {
             const char * fType;
 
+#ifdef DEBUG
+            pc->printf("  SendResponse() [%d]\r\n", __LINE__);
+#endif
             if (!CheckDynamicHandlers()) {
                 // Otherwise, this queryString must be trying to reference a static file
                 if (queryString[strlen(queryString)-1] == '/') {
@@ -481,27 +520,27 @@
         header(400, "Bad Request", "Pragma: err - Unsupported query type\r\n");
     }
     if (queryType) {
-        free(queryType);
+        myfree(queryType);
         queryType = NULL;
     }
     if (queryString) {
-        free(queryString);
+        myfree(queryString);
         queryString = NULL;
     }
     if (hostString) {
-        free(hostString);
+        myfree(hostString);
         hostString = NULL;
     }
     if (contentLength) {
-        free(contentLength);
+        myfree(contentLength);
         contentLength = NULL;
     }
     if (contentType) {
-        free(contentType);
+        myfree(contentType);
         contentType = NULL;
     }
     if (postQueryString) {
-        free(postQueryString);
+        myfree(postQueryString);
         postQueryString = NULL;
     }
 }
@@ -517,15 +556,13 @@
     // when it is done.
     wifly->setConnectionState(true);
     // Buffer could have partial, but the double \r\n is the key
-    //      *OPEN*QueryType QueryString HTTP/1.1....
-    //          QueryType:= GET
-    //      *OPEN*GET /QueryString HTTP/1.1\r\n
-    //      *OPEN*GET /QueryString HTTP/1.1\r\nHeader stuf
-    //      *OPEN*GET /QueryString HTTP/1.1\r\nHeader stuff...\r\n\r\n
+    //      GET /QueryString 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");
     if (dblCR) {  // Have to scan from the beginning in case split on \r
-#if 0
-        pc->printf("\r\n\r\nThe Header:\r\n%s\r\n\r\n", buffer);
+#ifdef DEBUG
+        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
@@ -537,10 +574,24 @@
             *eoRec = '\0';
             if (*(eoRec-1) == '\r')
                 *(eoRec-1) = '\0';
-            if (!Extract(soRec, "*OPEN*", &queryType))
-                Extract(soRec, "*CLOS*", &queryType);
-            if (queryType)
-                Extract(soRec, queryType, &queryString);
+            #ifdef DEBUG
+            pc->printf("rec {%s}\r\n", soRec);
+            #endif
+            // Inspect the supported query types (GET, POST) and ignore (HEAD, PUT, OPTION, DELETE, TRACE, CONNECT]
+            // This is very clumsy
+            if (strstr(soRec, "GET ") == soRec) {
+                Extract(soRec, "GET", &queryString);
+                if (queryString) {
+                    queryType = (char *)mymalloc(strlen("GET")+1);
+                    strcpy(queryType, "GET");
+                }
+            } else if (strstr(soRec, "POST ") == soRec) {
+                Extract(soRec, "POST", &queryString);
+                if (queryString) {
+                    queryType = (char *)mymalloc(strlen("POST")+1);
+                    strcpy(queryType, "POST");
+                }
+            }            
             Extract(soRec, "Host: ", &hostString);
             Extract(soRec, "Content-Length: ", &contentLength);
             Extract(soRec, "Content-Type: ", &contentType);
@@ -549,7 +600,9 @@
         }
         if (queryString) {
             // We have enough to try to reply
-            //pc->printf("create reply queryType{%s}, queryString{%s}\r\n", queryType, queryString);
+            #ifdef DEBUG
+            pc->printf("create reply queryType{%s}, queryString{%s}\r\n", "GET", queryString);
+            #endif
             // parse params - if any
             // /file.htm?name1=value1&name2=value2...
             // /file.htm?name1&name2=value2...
@@ -563,7 +616,7 @@
             //for (int i=0; i<paramcount; i++)
             //    pc->printf("param %d '%s'='%s'\r\n", i, params[i].name, params[i].value);
         } else {
-            pc->printf("not found\r\n");
+            pc->printf("ERROR: queryString not found\r\n");
         }
         advanceState = true;
         buffer[0] = 0;
@@ -593,7 +646,7 @@
 
                 if (regHandled && acceptIt) {
                     // If so, we'll make space for it
-                    postQueryString = (char *)malloc(postBytes + 1);
+                    postQueryString = (char *)mymalloc(postBytes + 1);
                     if (postQueryString) {
                         char * offset;
                         int len;
@@ -618,7 +671,7 @@
                 } else {
                     // Simply copy it to the bitbucket
                     int bytesToDump = postBytes;
-                    char * bitbucket = (char *)malloc(201);
+                    char * bitbucket = (char *)mymalloc(201);
                     dblCR += 4;
                     while (*dblCR && *dblCR <= ' ')
                         dblCR++;
@@ -628,7 +681,7 @@
                         n = client.receive(bitbucket, n);
                         bytesToDump -= n;
                     }
-                    free(bitbucket);
+                    myfree(bitbucket);
                 }
             }
         }