pablo gindel / Mbed 2 deprecated HTTP_server

Dependencies:   EthernetInterface mbed-rtos mbed

Fork of HTTP_server by pablo gindel

Revision:
3:27b3a889b327
Parent:
2:dc9184e97328
Child:
4:2a34139c7246
--- a/HTTPServer.cpp	Sun Jul 28 07:53:35 2013 +0000
+++ b/HTTPServer.cpp	Tue Jul 30 04:37:09 2013 +0000
@@ -21,7 +21,7 @@
     }
 
     INFO("Connected !");
-    //  set into blocking operation
+    // set into blocking operation
     socketServer.set_blocking (true);
 
     path = _path;
@@ -32,75 +32,83 @@
 
 int HTTPServer::poll () {
 
+    int retvalue;
+
     cliente = new TCPSocketConnection;
     cliente->set_blocking (false, TIMEOUT);
 
-    if (socketServer.accept(*cliente) < 0) {
+    retvalue = socketServer.accept (*cliente);
+
+    if (retvalue == OK) {
+
+        // a new connection was received
+        INFO("Client (IP=%s) is connected !", cliente->get_address());
+
+        msg = new HTTPMsg;     // estructura para decodificar y alojar el mensaje
+
+        retvalue = pollConnection (); // esto parsea y llena las cosas contenidas en msg
+
+        if (retvalue == OK) {
+            // Handle the request
+            INFO("Handling request !");
+            handleRequest ();
+        }
+
+        delete msg;
+
+    } else {  // retvalue == ERROR
         INFO("No connection\n");
-        return ERROR;
     }
 
-    // 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
-
-    if (c == OK) {
-        // Handle the request
-        // cliente->set_blocking (true);
-        INFO("Handling request !");
-        handleRequest ();
-    }
-
-    delete msg;
     delete cliente;
 
     INFO("Leaving polling thread\n");
-    return c;
+    return retvalue;
+
 }
 
 int HTTPServer::pollConnection () {
 
     int received = 0;
     INFO("Waiting for new data in connection");
-    //  Try receiving request line
+
+    // Try receiving request line
     received = receiveLine ();
 
     if (received == ERROR) {
-        //  there was an error, probably the connection was closed, so close this connection as well
+        // there was an error, probably the connection was closed, so close this connection as well
         INFO("No more data available. Will close this connection now.");
         return ERROR;
     }
 
-    //  The Request has not yet been received so try it
-    received = parse ();
+    // Request has not yet been received, so try it
+    received = parseRequest ();
 
     if (received == ERROR) {
-        //  Invalid content received, so close the connection
+        // Invalid content received, so close the connection
         INFO("Invalid message received, so sending negative response and closing connection !");
         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
+    // Request has been received, try receive the headers section
     do {
         received = receiveLine ();
         if (received == ERROR) {return ERROR;}
-        //  First check if we received an empty line. This would indicate the end of the message or message body.
+        // First check if we received an empty line;
+        // This would indicate the end of headers section.
         if (received == EMPTY) {
-            //  there was an empty line, so we can start with performing the request
+            // there was an empty line, so the headers section is complete
             INFO("Request Header was received completely. Performing request.");
             received = 0;
             break;
         } else {
-            /*  add message body
-            if (parseHeader () != 0) {
+            // parse header field
+            if (parseHeader() != OK) {
                 WARN("Invalid message header received !");
-            }*/
+            }
         }
-    } while (received > 0);   //
+    } while (received > 0);
 
     INFO("Leaving poll function!");
     return received;
@@ -151,7 +159,7 @@
     return i;
 }
 
-int HTTPServer::parse () {
+int HTTPServer::parseRequest () {
 
     //  Check if buffer content is not long enough.
     if (strlen(buffer) < MIN_LONG) {
@@ -191,11 +199,12 @@
         }
     }
 
+    // init body section length
+    msg->body_length = 0;
+
     return OK;
 }
 
-/* esta rutina no se usa */
-
 int HTTPServer::parseHeader () {
 
     //  Check if the buffer content is too short to be meaningful
@@ -209,13 +218,19 @@
             //  touple found
             buffer[i] = 0;
             value_start = i+1;
-            msg->headers[buffer] = &buffer[value_start];
+            // headers storage is disabled; uncomment next line to enable
+            // msg->headers[buffer] = &buffer[value_start];
             INFO("Header name=\"%s\" : value=\"%s\".", buffer, &buffer[value_start]);
+            // Look for "Content-Length" header
+            if (strcmp (buffer, "Content-Length") == 0) {
+                msg->body_length = atoi(&buffer[value_start]);
+                INFO ("Body section found. Length: %i", msg->body_length);
+            }
             return OK;
         }
     }
 
-    ERR("Did not recieve a valid header : \"%s\".", buffer);
+    ERR("Did not receive a valid header : \"%s\".", buffer);
     return ERROR;
 }
 
@@ -230,16 +245,16 @@
     char* argname = NULL;
     char* valuename = NULL;
     for (int i=0; i<buflen; i++) {
-        if (args_start == -1) {  // args section not yet found
+        if (args_start == -1) { // args section not yet found
             if (uri_buffer[i] == '?') {  // starts with a question mark, so got it
                 uri_buffer[i] = 0;
                 args_start = i; //  set the start of the args section
                 INFO("Argument section found !");
             }
-        } else {                  // search arg-value touples
-            if (argname == NULL) {    //  arg-name found ?
+        } else { // search arg-value touples
+            if (argname == NULL) {    // arg-name found ?
                 if (uri_buffer[i] == '=') {
-                    //  yes, separate the arg-name
+                    // yes, separate the arg-name
                     uri_buffer[i] = 0;
                     argname = &uri_buffer[args_start];
                     value_start = i+1;
@@ -250,21 +265,17 @@
                     buffer[i] = 0;
                     valuename = &uri_buffer[value_start];
                     INFO("Argument value %s", valuename);
-                    msg->args[argname] = valuename;
-                    //  reset all indicators
+                    msg->uri_args[argname] = valuename;
+                    // reset all indicators
                     argname = NULL;
                     valuename = NULL;
                 }
             }
         }
     }
-
     return OK;
 }
 
-/* verificar qué parte de msg realmente se usa,
-   eliminar el resto, incluyendo los procesos asociados */
-
 void HTTPServer::handleRequest () {
 
     int err_;
@@ -311,17 +322,6 @@
     FILE *file = fopen(reqPath.c_str(), "r");
     if (file != NULL) {
 
-        // 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 (file, 0, SEEK_END);
         int size = ftell (file);
@@ -329,16 +329,14 @@
 
         startResponse (200, size);                  // response: 200 = HTTP_Ok
         while (!feof(file) && !ferror(file)) {
-            int count = fread (chunk, 1, chunk_sz , file);
+            int count = fread (buffer, 1, CHUNK_SIZE, file);
             INFO("Processing Response (%d bytes)!", count);
-            if (cliente->send_all (chunk, count) != count) {
+            if (cliente->send_all (buffer, count) != count) {
                 WARN ("Unsent bytes left !");                  // TODO: handle filesystem errors
             }
         }
-
         INFO("Ending Response !");
 
-        free (chunk);
         fclose (file);
 
     } else {
@@ -352,6 +350,36 @@
 
 int HTTPServer::handlePostRequest() {
 
+    // Try receive the body data, if there is any
+    if (msg->body_length > 0) {
+
+        INFO("Receiving body data.");
+        if (msg->body_length > BUFFER_SIZE) {error ("OutOfMemory");}
+
+        int bytes_read = 0;
+        while (bytes_read < msg->body_length) {
+            int result = cliente->receive_all(buffer+bytes_read, msg->body_length-bytes_read);
+            if (result == ERROR) {
+                WARN("Error receiving body data.");
+                break;
+            }
+            bytes_read += result;
+        }
+
+        INFO("Body data received.");
+
+        // do something
+        // use the url_decode routine :)
+
+        INFO("Done !\n");
+        return handleGetRequest();
+            
+    } else {
+        
+        ERR("POST data not found !");
+    
+    }
+
     return 404;
 }
 
@@ -361,6 +389,9 @@
                             "Content-Type: text/html\r\n"       // TODO: handle file types
                             "Server: mbed embedded\r\n"
                             "Accessible: 1\r\n"
+                            "Pragma: no-cache\r\n"
+                            "Cache-control: no-cache;no-store\r\n"
+                            "Expires: 0\r\n"
                             "\r\n";
 
 void HTTPServer::startResponse (int returnCode, int nLen) {
@@ -390,3 +421,33 @@
     INFO("Done !");
 
 }
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                            UTILS                                               //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#include <ctype.h>
+
+/* Converts a hex character to its integer value */
+char from_hex (char ch) {
+  return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
+}
+
+/* Returns a url-decoded version of str */
+void url_decode (char *str) {
+  char *lee = str, *escribe = str;
+  while (*lee) {
+    if (*lee == '%') {
+      if (lee[1] && lee[2]) {
+        *escribe++ = from_hex(lee[1])<<4 | from_hex(lee[2]);
+        lee += 2;
+      }
+    } else if (*lee == '+') {
+      *escribe++ = ' ';
+    } else {
+      *escribe++ = *lee;
+    }
+    lee++;
+  }
+  *escribe = 0;
+}