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

HTTPServer.cpp

Committer:
leihen
Date:
2013-06-02
Revision:
11:3943841e1798
Parent:
9:c2a1462b9b71
Child:
12:ba81cc117fb6

File content as of revision 11:3943841e1798:

#include "mbed.h"
#include "HTTPServer.h"

#define _DEBUG      0

#ifdef _DEBUG
DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);
#endif

#if (_DEBUG && !defined(TARGET_LPC11U24))
#define INFO(x, ...) std::printf("[HttpServer : DBG]"x"\r\n", ##__VA_ARGS__);
#define WARN(x, ...) std::printf("[HttpServer : DBG]"x"\r\n", ##__VA_ARGS__);
#define ERR(x, ...) std::printf("[HttpServer : DBG]"x"\r\n", ##__VA_ARGS__);
#else
#define INFO(x, ...)
#define WARN(x, ...)
#define ERR(x, ...)
#endif


/* Constructor */
/* initialize all members and set the standard error handler. */
HTTPServer::HTTPServer(PinName tx, PinName rx, PinName reset, PinName tcp_status, const char * ssid, const char * phrase, Security sec)
    : m_wifly(tx, rx, reset, tcp_status, ssid, phrase, sec)
{
    m_pErrorHandler = StdErrorHandler;
    m_pSvr = NULL;
}

HTTPServer::~HTTPServer()
{
    if (m_pSvr) {
        delete m_pSvr;
        m_pSvr = NULL;
    }
}


static const char* szStdErrorPage = "<HTML><HEAD><META content=\"text/html\" http-equiv=Content-Type></HEAD><BODY><h1>Error 404</h1><P>This resource is not available<P></BODY></HTML>\r\n\r\n";

void HTTPServer::StdErrorHandler(HTTPConnection::HTTPMessage& msg, TCPSocketConnection& tcp)
{
    char echoHeader[256];
    tcp.set_blocking(true, 1500);
    sprintf(echoHeader,"HTTP/1.0 404 Fail\r\nConnection: close\r\nContent-Length: %d\r\nContent-Type: text/html\r\nServer: mbed embedded\r\n\n\r",strlen(szStdErrorPage));
    tcp.send(echoHeader, strlen(echoHeader));
    tcp.send((char*)szStdErrorPage, strlen(szStdErrorPage));
}


int HTTPServer::start(int port)
{
    // check if the start member was called already once
    if (m_pSvr != NULL) {
        ERR("start function was already called, server is already in listening state.");
        return -1;
    }
    INFO("Initializing wifly\n");    
    //  Initialize the wifly wlan device
    m_wifly.init();

    INFO("Connecting to network...");
    //  Try join the network
    while(!m_wifly.connect()) {
        INFO("Failed to connect. Trying again\n");
        m_wifly.reset();
    }
    INFO("connected\n");

    // check if the start member was called already once
    if (m_pSvr != NULL) {
        ERR("start function was already called, server is already in listening state.");
        return -1;
    }
    
    //  Create a new server object
    m_pSvr = new TCPSocketServer();
    
    //  Bind the local server to the given port
    if (m_pSvr->bind(port) < 0) {
        ERR("Failed to bind to port %d\n", port);
        return -1;
    }
    else {
        INFO("Binding succeeded !\n");
    }

    //  Listen to a maximum of 10 concurrent connections
    if (m_pSvr->listen(1) < 0) {
        ERR("Faild to listen !\n");
        delete m_pSvr;
        m_pSvr = NULL;
        return -1;
    }
    else {
        INFO("Listening\n");
    }

    //  set into non blocking operation
    m_pSvr->set_blocking(false, 100);
    
    return 0;
}


int HTTPServer::poll(bool blocking)
{    
    int retval = -1;
    INFO("Listening for new connection requests.");

    //  This thread basically checks if there is a new incoming connection.
    //  If so , a new HTTPConnection is created and the connection thread is started.
    TCPSocketConnection Clnt;

#ifdef _DEBUG
    led4 = 1;   //  Indicate we are waiting for a new connection 
#endif
    m_pSvr->set_blocking(blocking); 
    retval = m_pSvr->accept(Clnt);
    if (retval > 0) {
        // no connection availale yet, so just return
#ifdef _DEBUG
led4 = 0;
led3 = 0;
led2 = 0;
#endif
        return retval;
    }
    if ( retval < 0) {
        //  an error occured 
        ERR("There was an error, Accept returned with an error. Probably the connection to the router was lost. Shutting down server");
#ifdef _DEBUG
        led2 = 0;
#endif 
        m_pSvr->close();
        delete m_pSvr;
        m_pSvr = NULL;
#ifdef _DEBUG
        led4 = 0;
        led3 = 1;   //  ERROR
        led2 = 0;
        led1 = 0;
#endif
        return -1;
    }
    else {
#ifdef _DEBUG
        led4 = 0;
#endif 
        //   a new connection was received
        INFO("Client (IP=%s) is connected !\n", Clnt.get_address());
        //  Start the main connection thread
//        while(1) {
            
    #ifdef _DEBUG
            led3 = 1;
            led2 = 1;
    #endif
            HTTPConnection con;
            int c = con.poll();
            if (c == 0) {
                //  Handle the request
                HandleRequest(con.m_Msg, Clnt);
                INFO("Closing connection.\n");
//                if (!m_wifly.close()) {
//                    ERR("Failed to close connection !\n");
//                }
            }
            if (c == -1) {
                // No more data available or error
 //               break;
            }
    #ifdef _DEBUG
            led2 = 0;
            led3 = 0;
    #endif
//        }
    }
    
    INFO("Leaving polling thread");
    return 0;
}

void HTTPServer::HandleRequest(HTTPConnection::HTTPMessage& msg, TCPSocketConnection& tcp)
{
    std::string localPath;
    std::map<std::string, HTTPRequestHandler*(*)(const char*, const char*, HTTPConnection::HTTPMessage&, TCPSocketConnection&), handlersComp>::const_iterator it;

    //  Iterate through registered handlers and check if the handler's path is a subset of the requested uri.
    for (it = m_lpHandlers.begin() ; it != m_lpHandlers.end() ; it++) {
        //  check if this entries' path is fully contained at the beginning of the requested path
        std::string curpth = it->first;

        if (msg.uri.find(curpth) == 0) {
            // firts matching handler found, we just take it and we'll be happy
            localPath = msg.uri.substr(curpth.length());
            break;
        }
    }
    
    if (it == m_lpHandlers.end()) {
        //  There is no such handler, so return invalid

        m_pErrorHandler(msg, tcp);        
        INFO("Webrequest left unhandled.");
    }
    else {
        //  Valid handler was found
        INFO("Routing webrequest !");
        //  Instantiate the handler object (handling will be done from withing the object's constructor
        HTTPRequestHandler *phdl = (*it->second)(it->first.c_str(), localPath.c_str(), msg, tcp);
        //  now we can delete the object, because handling is completed.
        if (phdl != NULL)
            delete phdl;
    }
}