HTTP Server upon new mbed Ethernet Interface. Based on original code by Henry Leinen.

Dependencies:   EthernetInterface mbed-rtos mbed

Fork of HTTP_server by pablo gindel

Files at this revision

API Documentation at this revision

Comitter:
pabloxid
Date:
Sun Jul 28 07:53:35 2013 +0000
Parent:
1:f0c641cd9bad
Child:
3:27b3a889b327
Commit message:
Many fixes: It works now

Changed in this revision

HTTPServer.cpp Show annotated file Show diff for this revision Revisions of this file
HTTPServer.h Show annotated file Show diff for this revision Revisions of this file
debug.h Show annotated file Show diff for this revision Revisions of this file
--- a/HTTPServer.cpp	Fri Jul 26 22:33:47 2013 +0000
+++ b/HTTPServer.cpp	Sun Jul 28 07:53:35 2013 +0000
@@ -1,16 +1,6 @@
 #include "mbed.h"
 #include "HTTPServer.h"
 
-#define DEBUG
-#include "debug.h"
-
-#define TIMEOUT      500
-#define OK           0
-#define ERROR        -1
-#define EMPTY        -2
-#define MIN_LONG     3
-
-
 RequestConfig rq_conf[] = {
     { "GET",    HTTP_RT_GET },
     { "POST",   HTTP_RT_POST}
@@ -32,7 +22,7 @@
 
     INFO("Connected !");
     //  set into blocking operation
-    socketServer.set_blocking (true, TIMEOUT);
+    socketServer.set_blocking (true);
 
     path = _path;
 
@@ -50,24 +40,24 @@
         return ERROR;
     }
 
-    //   a new connection was received
-    INFO("Client (IP=%s) is connected !\n", cliente->get_address());
+    // a new connection was received
+    INFO("Client (IP=%s) is connected !", cliente->get_address());
 
     msg = new HTTPMsg;  // estructura para decodificar y alojar el mensaje
 
-    int c = pollConnection (); // esto parsea y llena las cosas contenidas en msg
+    int c = pollConnection ();  // esto parsea y llena las cosas contenidas en msg
 
     if (c == OK) {
-        //  Handle the request
+        // Handle the request
+        // cliente->set_blocking (true);
         INFO("Handling request !");
-        //cliente->set_blocking (true, TIMEOUT);
         handleRequest ();
     }
 
     delete msg;
     delete cliente;
 
-    INFO("Leaving polling thread");
+    INFO("Leaving polling thread\n");
     return c;
 }
 
@@ -90,14 +80,11 @@
     if (received == ERROR) {
         //  Invalid content received, so close the connection
         INFO("Invalid message received, so sending negative response and closing connection !");
-        sprintf (buffer,"HTTP/1.1 400 BadRequest\n\rContent-Length: %d\n\rContent-Type: text\n\r\n\r\n\r",0);
-
-        cliente->send (buffer, strlen (buffer));
-
+        tcpsend ("HTTP/1.1 400 BadRequest\n\rContent-Length: %d\n\rContent-Type: text\n\r\n\r\n\r", 0);
         return ERROR;
     }
 
-    /*  The request has been received, try receive the body
+    //  The request has been received, try receive the body
     do {
         received = receiveLine ();
         if (received == ERROR) {return ERROR;}
@@ -108,12 +95,12 @@
             received = 0;
             break;
         } else {
-            //  add message body
+            /*  add message body
             if (parseHeader () != 0) {
                 WARN("Invalid message header received !");
-            }
+            }*/
         }
-    } while (received > 0);   */
+    } while (received > 0);   //
 
     INFO("Leaving poll function!");
     return received;
@@ -137,7 +124,7 @@
         //  Check that - if no character was currently received - the timeout period is reached.
         if (c == 0 || c == -1) {
             //  no character was read, so check if operation timed out
-            if (tm.read_ms() > TIMEOUT) {
+            if (tm.read_ms() > 2*TIMEOUT) {
                 //  Operation timed out
                 INFO("Timeout occured in function 'receiveLine'.");
                 return ERROR;
@@ -306,9 +293,9 @@
 
 int HTTPServer::handleGetRequest() {
 
-    INFO("Handling Get Request.");
+    int retval = OK;     //success
 
-    int retval = OK;     //success
+    INFO("Handling Get Request.");
 
     // maping to root path
     std::string reqPath = path + msg->uri.substr(1);
@@ -321,37 +308,38 @@
 
     INFO("Mapping \"%s\" to \"%s\"", msg->uri.c_str(), reqPath.c_str());
 
-    FILE *fp = fopen(reqPath.c_str(), "r");
-    if (fp != NULL) {
+    FILE *file = fopen(reqPath.c_str(), "r");
+    if (file != NULL) {
 
-        char * pBuffer = NULL;
-        int sz = 8192;                         // fixme harcode
-        while( pBuffer == NULL) {
-            sz /= 2;
-            pBuffer = (char*)malloc(sz);
-            if (sz < 128)                      // fixme harcode
+        // asigna toda la memoria dinámica disponible para 'chunk'
+        char * chunk = NULL;
+        int chunk_sz = MAX_CHUNK_SIZE;
+        while(chunk == NULL) {
+            chunk_sz /= 2;
+            chunk = (char*) malloc (chunk_sz);
+            if (chunk_sz < MIN_CHUNK_SIZE) {
                 error ("OutOfMemory");
+            }
         }
 
-        //  File was found and can be returned
-
-        //  first determine the size
-        fseek(fp, 0, SEEK_END);
-        long size = ftell(fp);
-        fseek(fp, 0, SEEK_SET);
+        // File was found and can be returned; first determine the size
+        fseek (file, 0, SEEK_END);
+        int size = ftell (file);
+        fseek (file, 0, SEEK_SET);
 
-        startResponse (200, size);                  // response: 200
-        while (!feof(fp) && !ferror(fp)) {
-            int cnt = fread (pBuffer, 1, sz , fp);
-            if (cnt < 0)
-                cnt = 0;
-            processResponse (cnt, pBuffer);
+        startResponse (200, size);                  // response: 200 = HTTP_Ok
+        while (!feof(file) && !ferror(file)) {
+            int count = fread (chunk, 1, chunk_sz , file);
+            INFO("Processing Response (%d bytes)!", count);
+            if (cliente->send_all (chunk, count) != count) {
+                WARN ("Unsent bytes left !");                  // TODO: handle filesystem errors
+            }
         }
 
         INFO("Ending Response !");
 
-        free (pBuffer);
-        fclose (fp);
+        free (chunk);
+        fclose (file);
 
     } else {
         retval = 404;
@@ -370,30 +358,21 @@
 static const char hdrStandard[] = "DNT: 1\r\n"
                             "MaxAge: 0\r\n"
                             "Connection: Keep-Alive\r\n"
-                            "Content-Type: text/html\r\n"
+                            "Content-Type: text/html\r\n"       // TODO: handle file types
                             "Server: mbed embedded\r\n"
                             "Accessible: 1\r\n"
                             "\r\n";
 
-void HTTPServer::startResponse (int returnCode, long nLen) {
-
-    INFO("Starting response (%ld bytes in total)!", nLen);
+void HTTPServer::startResponse (int returnCode, int nLen) {
 
-    sprintf (buffer, "HTTP/1.1 %d OK\r\n", returnCode);
-    cliente->send(buffer, strlen(buffer));
-    sprintf (buffer, "Content-Length: %ld\r\n", nLen);    //  Add 2 chars for the terminating CR+LF
-    cliente->send(buffer, strlen(buffer));
+    INFO("Starting response (%d bytes in total)!", nLen);
+
+    tcpsend ("HTTP/1.1 %d OK\r\n", returnCode);
+    tcpsend ("Content-Length: %d\r\n", nLen);    // Add 2 chars for the terminating CR+LF
     INFO("Sending standard headers !");
-    cliente->send_all((char*)hdrStandard, strlen(hdrStandard));
+    tcpsend (hdrStandard);
 
-    INFO("Proceeding !");
-    //  other content must be sent using the 'processResponse' function
-}
-
-void HTTPServer::processResponse (int nLen, char* body) {
-
-    INFO("Processing Response (%d bytes)!\n", nLen);
-    cliente->send_all (body, nLen);
+    INFO("Done !");
 
 }
 
@@ -403,14 +382,10 @@
 
     INFO("Handling error !");
 
-    sprintf (buffer,"HTTP/1.1 %d Error\r\n", errorCode);
-    cliente->send (buffer, strlen(buffer));
-    sprintf (buffer, "Content-Length: %ld\r\n", strlen(errorPage));
-    cliente->send (buffer, strlen(buffer));
-    sprintf(buffer, "Content-Type: text/html\r\nServer: mbed embedded\r\n\r\n");
-    cliente->send(buffer, strlen(buffer));
-    cliente->send_all((char*)errorPage, strlen(errorPage));
-    cliente->send("\r\n", 3);
+    tcpsend ("HTTP/1.1 %d Error\r\n", errorCode);
+    tcpsend ("Content-Length: %d\r\n", strlen(errorPage));
+    tcpsend ("Content-Type: text/html\r\nServer: mbed embedded\r\n\r\n");
+    tcpsend (errorPage);                                                  // TODO: better error page (handle error type)
 
     INFO("Done !");
 
--- a/HTTPServer.h	Fri Jul 26 22:33:47 2013 +0000
+++ b/HTTPServer.h	Sun Jul 28 07:53:35 2013 +0000
@@ -31,6 +31,18 @@
 #include <string>
 #include <map>
 
+#define BUFFER_SIZE     256
+#define TIMEOUT         800
+#define OK              0
+#define ERROR           -1
+#define EMPTY           -2
+#define MIN_LONG        3
+#define MAX_CHUNK_SIZE  512
+#define MIN_CHUNK_SIZE  128
+
+#define DEBUG 0
+#include "debug.h"
+
 enum RequestType {
      HTTP_RT_GET,        /*!< GET request */
      HTTP_RT_POST,       /*!< POST request */
@@ -55,8 +67,6 @@
      RequestType request_type;
 };
 
-#define BUFFER_SIZE  256
-
 class HTTPServer {
 
 private:
@@ -73,10 +83,32 @@
     void handleRequest ();
     int handleGetRequest();
     int handlePostRequest();
-    void startResponse (int returnCode, long nLen);
-    void processResponse (int nLen, char* body);
+    void startResponse (int returnCode, int nLen);
     void handleError (int errorCode);
 
+    int tcpsend (const char* text, int param) {
+        //if (cliente == NULL) {return ERROR;}
+        sprintf (buffer, text, param);
+        int len = strlen (buffer);
+        if (cliente->send_all (buffer, len) == len) {
+            return OK;
+        } else {
+            WARN("Unsent bytes left !");
+            return ERROR;
+        }
+    }
+
+    int tcpsend (const char* text) {
+        //if (cliente == NULL) {return ERROR;}
+        int len = strlen (text);
+        if (cliente->send_all ((char*)text, len) == len) {
+            return OK;
+        } else {
+            WARN("Unsent bytes left !");
+            return ERROR;
+        }
+    }
+
 public:
         /** Constructor for HTTPServer objects.  */
         HTTPServer (int port, const char* _path);
--- a/debug.h	Fri Jul 26 22:33:47 2013 +0000
+++ b/debug.h	Sun Jul 28 07:53:35 2013 +0000
@@ -1,16 +1,31 @@
-
 #ifndef __DEBUG_H__
 #define __DEBUG_H__
 
 
-#ifdef DEBUG
+#if (DEBUG == 3)
+
 #define INFO(x, ...) std::printf("[INFO: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
 #define WARN(x, ...) std::printf("[WARN: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
 #define ERR(x, ...) std::printf("[ERR: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+
+#elif (DEBUG == 2)
+
+#define INFO(x, ...)
+#define WARN(x, ...) std::printf("[WARN: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#define ERR(x, ...) std::printf("[ERR: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+
+#elif (DEBUG == 1)
+
+#define INFO(x, ...)
+#define WARN(x, ...)
+#define ERR(x, ...) std::printf("[ERR: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+
 #else
+
 #define INFO(x, ...)
 #define WARN(x, ...)
 #define ERR(x, ...)
+
 #endif