Single instance HTTP Server using new Ethernet Interface. Blocking mode only; this improved stability, but the HTTP server must be started from a separate thread.

Dependents:   SmartLight

Fork of HTTPServer by Henry Leinen

Revision:
0:7a2421e63e74
Child:
1:6b7472d5e9ee
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HTTPConnection.cpp	Sun May 26 20:13:28 2013 +0000
@@ -0,0 +1,219 @@
+/* HTTPConnection.cpp */
+
+#include "mbed.h"
+#include "HTTPConnection.h"
+
+#include <vector>
+using std::vector;
+
+using std::string;
+
+#if (1 && !defined(TARGET_LPC11U24))
+#define INFO(x, ...) std::printf("[HttpConnection : INFO]"x"\r\n", ##__VA_ARGS__);
+#define WARN(x, ...) std::printf("[HttpConnection : WARN]"x"\r\n", ##__VA_ARGS__);
+#define ERR(x, ...) std::printf("[HttpConnection : ERR]"x"\r\n", ##__VA_ARGS__);
+#else
+#define INFO(x, ...)
+#define WARN(x, ...)
+#define ERR(x, ...)
+#endif
+
+
+
+
+HTTPConnection::HTTPConnection()
+{
+}
+
+
+HTTPConnection::~HTTPConnection()
+{
+    close();
+}
+
+void HTTPConnection::close()
+{
+    m_Msg.headers.clear();
+}
+
+int HTTPConnection::poll()
+{
+    static char buffer[256] = {};
+    static char echoHeader[256] = {};
+
+    
+    int rcvd= 0;
+    INFO("[HTTPConnection]Waiting for new data in connection");
+    //  Try receiving request line
+    rcvd = receiveLine(buffer, 255, 3000); 
+    if (rcvd == -1) {
+        //  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.");
+        close();
+        return -1;
+    }
+
+    //  The Request has not yet been received so try it
+    rcvd = parse(buffer);
+    if (rcvd == -1) {
+        //  Invalid content received, so close the connection
+        INFO("Invalid message received, so sending negative response and closing connection !");
+        sprintf(echoHeader,"HTTP/1.1 400 NOK\n\rContent-Length: %d\n\rContent-Type: text\n\rConnection: Close\n\r\n\r",strlen(buffer));
+        m_Tcp.set_blocking(true, 1500);
+        m_Tcp.send(echoHeader,strlen(echoHeader));
+        m_Tcp.send(buffer,strlen(buffer));
+        close();
+        rcvd = -1;
+        return -1;
+    }
+    //  The request has been received, try receive the body
+    while(rcvd > 0) {
+        rcvd = receiveLine((char*)buffer, 255, 3000); 
+        //  First check if we received an empty line. This would indicate the end of the message or message body.
+        if (rcvd < 0) {
+            //  there was an empty line, so we can start with performing the request
+            INFO("Request Header was received completely. Performing request.");
+            rcvd = 0;
+            break;
+        }
+        else {
+            //  add message body
+            if (parseHeader(buffer) == 0) {
+            }
+            else {
+                WARN("Invalid message header received !");
+            }
+        }
+    }             
+    if (rcvd == 0) {
+        sprintf(echoHeader,"HTTP/1.1 200 OK\n\rContent-Length: %d\n\rContent-Type: text\n\rConnection: Close\n\r\n\r",strlen(buffer));
+        m_Tcp.set_blocking(true);
+        m_Tcp.send_all(echoHeader,strlen(echoHeader));
+        m_Tcp.send_all(buffer,strlen(buffer));
+        
+        /// INSERT PRCESSING OF REQUESST HERE
+        /// END OF PROCESSING REQUEST
+        
+        //  Do not close the connection, it may be reused
+    }
+    INFO("Leaving poll function!");
+    return rcvd;
+}
+
+int HTTPConnection::receiveLine(char* szLine, int nMaxLen, int nTimeout, char cLineTerm)
+{
+    if ((szLine == NULL) || (nMaxLen == 0))
+        return -1;
+    
+    m_Tcp.set_blocking(false);
+    
+    Timer tm;
+    int i;
+    
+    //  Try to receive up to the max number of characters
+    for (i = 0 ; i < nMaxLen-1 ; i++) {
+        int c;
+        c = m_Tcp.receive_all( szLine + i, 1 );
+        //  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() > nTimeout) {
+                //  Operation timed out
+                INFO("Timeout occured in function 'receiveLine'.");
+                return -1;
+            }
+        }
+        
+        //  Check if line terminating character was received
+        if (szLine[i] == cLineTerm)
+            break;
+    }
+    //  Terminate with \0
+    szLine[i] = 0;
+
+    //  Trim for '\r' linefeed at the end
+    if( (i >0) && (szLine[i-1] == '\r')) {
+        i--;
+        szLine[i] = 0;
+    }
+    INFO("receiveLine : \"%s\".", szLine);
+    
+    //  return number of characters received in the line or return -2 if an empty line was received
+    if ((i == 0) || ((i==1) &&(szLine[0] == '\r')))
+    {
+        //  empty line received, so return -2
+        return -2;
+    }
+    return i;    
+}
+
+int HTTPConnection::parse(const char* buffer)
+{
+    if ((buffer == NULL) || (strlen(buffer) < 4)) {
+        ERR("Buffer content is invalid or too short.");
+        return -1;
+    }
+    
+    vector<std::string> args;
+    args.clear();
+    
+    //  decompose string into a list of arguments
+    char s = 0; // current starting char
+    static char buff[255] = {};
+    for (int i = 0 ; i < strlen(buffer)+1 ; i++) {
+        if ((buffer[i] == ' ') || (buffer[i] == '\n') || (buffer[i] == 0)) {
+            // new arg found
+            strncpy(buff, &buffer[s], i-s);
+            buff[i-s] = 0;
+            INFO("Found argument \"%s\"", buff);
+            args.push_back(std::string(buff));
+            s = i+1;
+        }
+    }
+        
+    if (args.at(0) == "GET") {
+        m_Msg.request = HTTP_RT_GET;
+        m_Msg.uri = args[1];
+        m_Msg.version = args[2];    
+    }
+    else {
+        if (args.at(0) == "POST") {
+            m_Msg.request = HTTP_RT_GET;
+            m_Msg.uri = args[1];
+            m_Msg.version = args[2];    
+        }
+        else {
+            INFO("unhandled message.");
+        }
+    }
+    args.clear();
+    
+    return 1;
+}
+
+
+int HTTPConnection::parseHeader(const char *buffer)
+{
+    if ((strlen(buffer) <3) || (buffer == NULL))
+        return -1;
+        
+    //  decompose string into a touple of <field name> : <field value>
+    static char fieldname[256] = {};
+    static char fieldvalue[256] = {};
+    for (int i = 0 ; i < strlen(buffer)+1 ; i++) {
+        if (buffer[i] == ':') {
+            //  touple found
+            strncpy(fieldname, buffer, i);
+            fieldname[i] = 0;
+            strcpy(fieldvalue, &buffer[i+1]);
+    
+//            m_Msg.headers[fieldname] = fieldvalue;
+            
+            INFO("Header name=\"%s\" : value=\"%s\".", fieldname, fieldvalue);            
+            return 0;
+        }
+    }
+    
+    ERR("Did not recieve a valid header : \"%s\".", buffer);
+    return -1;
+}