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

HTTPConnection.cpp

Committer:
leihen
Date:
2013-05-26
Revision:
1:6b7472d5e9ee
Parent:
0:7a2421e63e74
Child:
2:8653bbcf7e58

File content as of revision 1:6b7472d5e9ee:

/* HTTPConnection.cpp */

#include "mbed.h"
#include "HTTPConnection.h"

#include <vector>
using std::vector;

using std::string;

#if (0 && !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;
}