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-28
Revision:
3:d6224049b3bf
Parent:
2:8653bbcf7e58
Child:
4:d065642c32cc

File content as of revision 3:d6224049b3bf:

/* 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] = {};

    
    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(buffer,"HTTP/1.1 400 NOK\n\rContent-Length: %d\n\rContent-Type: text\n\rConnection: Close\n\r\n\r",0);
        m_Tcp.set_blocking(true, 1500);
        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 !");
            }
        }
    }             
    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(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
    int nLen = strlen(buffer)+1;
    for (int i = 0 ; i < nLen ; i++) {
        if ((buffer[i] == ' ') || (buffer[i] == '\n') || (buffer[i] == 0)) {
            // new arg found
            buffer[i] = 0;
            INFO("Found argument \"%s\"", &buffer[s]);
            args.push_back(&buffer[s]);
            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(char *buffer)
{
    if ((strlen(buffer) <3) || (buffer == NULL))
        return -1;
        
    //  decompose string into a touple of <field name> : <field value>
    int value_start = 0;
    int buflen = strlen(buffer)+1;
    for (int i = 0 ; i < buflen ; i++) {
        if (buffer[i] == ':') {
            //  touple found
            buffer[i] = 0;
            value_start = i+1;    
            m_Msg.headers[buffer] = &buffer[value_start];
            
            INFO("Header name=\"%s\" : value=\"%s\".", buffer, &buffer[value_start]);            
            return 0;
        }
    }
    
    ERR("Did not recieve a valid header : \"%s\".", buffer);
    return -1;
}