An example HTTP Server library using new Ethernet Interface

Dependents:   HTMLServer_Sample

HTTPServer.h

Committer:
mkilivan
Date:
2014-12-23
Revision:
0:8e1971a883be

File content as of revision 0:8e1971a883be:

//#define _DEBUG_HTTP_SERVER_H

#ifndef HTTP_SERVER_H
#define HTTP_SERVER_H

#define HELLO_PAGE "/hello"
#define RPC_PAGE "/rpc"
//#define IEEE1888WSDL_PAGE "/IEEE1888?wsdl"
//#define IEEE1888_PAGE "/IEEE1888"
#define FS_PAGE "/"

#include <string>
using std::string;

#include <map>
using std::map;

#include "HTTPRequestHandler.h"
#include "rtos.h"
#include "mbed.h"
#include "EthernetInterface.h"

#include "Handler/RPCHandler.h"
#include "Handler/FSHandler.h"
#include "Handler/SimpleHandler.h"

#define THREAD_MAX 3
Thread *threads[THREAD_MAX];
Thread *xthread;

/*
struct handlersComp { //Used to order handlers in the right way
    bool operator() (const string& handler1, const string& handler2) const {
        //The first handler is longer than the second one
        if (handler1.length() > handler2.length())
            return true; //Returns true if handler1 is to appear before handler2
        else if (handler1.length() < handler2.length())
            return false;
        else //To avoid the == case, sort now by address
            return ((&handler1)>(&handler2));
    }
};

map< string, HTTPRequestHandler*(*)(const char*, const char* , TCPSocketConnection* ), handlersComp > m_lpHandlers;
template<typename T>
void HTTPServerAddHandler(const char* path)  //Template decl in header
{
    m_lpHandlers[path] = &T::inst;
}
*/

void ListenThread(void const *args);
enum HTTP_METH {
    HTTP_GET,
    HTTP_POST,
    HTTP_HEAD
};

bool getRequest(TCPSocketConnection* client,string* path, string* meth)
{
    char req[128];
    char c_path[128];
    char c_meth[128];
    const int maxLen = 128;
    char* p = req;
    //Read Line
    int ret;
    int len = 0;
    for(int i = 0; i < maxLen - 1; i++) {
        ret = client->receive(p, 1);
        if(!ret) {
            break;
        }
        if( (len > 1) && *(p-1)=='\r' && *p=='\n' ) {
            p--;
            len-=2;
            break;
        } else if( *p=='\n' ) {
            len--;
            break;
        }
        p++;
        len++;
    }
    *p = 0;
#ifdef _DEBUG_HTTP_SERVER_H
    printf("Parsing request : %s\r\n", req);
#endif
    ret = sscanf(req, "%s %s HTTP/%*d.%*d", c_meth, c_path);
    if(ret !=2)        return false;
    *meth = string(c_meth);
    *path = string(c_path);
    return true;
}

void dispatchRequest(TCPSocketConnection* client)
{
    string path;
    string meth;
    HTTP_METH methCode;
#ifdef _DEBUG_HTTP_SERVER_H
    printf("Dispatching req\r\n");
#endif
    if( !getRequest(client,&path, &meth ) ) {
#ifdef _DEBUG_HTTP_SERVER_H
        printf("dispatchRequest Invalid request\r\n");
#endif
        //close();
        return; //Invalid request
    }
    if( !meth.compare("GET") ) {
#ifdef _DEBUG_HTTP_SERVER_H
        printf("dispatchRequest HTTP_GET\r\n");
#endif
        methCode = HTTP_GET;
    } else if( !meth.compare("POST") ) {
#ifdef _DEBUG_HTTP_SERVER_H
        printf("dispatchRequest HTTP_POST\r\n");
#endif
        methCode = HTTP_POST;
    } else if( !meth.compare("HEAD") ) {
#ifdef _DEBUG_HTTP_SERVER_H
        printf("dispatchRequest HTTP_HEAD\r\n");
#endif
        methCode = HTTP_HEAD;
    } else {
#ifdef _DEBUG_HTTP_SERVER_H
        printf("dispatchRequest() Parse error\r\n");
#endif
        //close(); //Parse error
        return;
    }
#ifdef _DEBUG_HTTP_SERVER_H
    printf("Looking for a handler\r\n");
#endif
    /*
        map< string, HTTPRequestHandler*(*)(const char*, const char*, TCPSocketConnection*) >::iterator it;
        int root_len = 0;
        for (it = m_lpHandlers.begin(); it != m_lpHandlers.end(); it++) {
    #ifdef _DEBUG_HTTP_SERVER_H
            printf("Checking %s...\r\n", (*it).first.c_str());
    #endif
            root_len = (*it).first.length();
            if ( root_len &&
                    !path.compare( 0, root_len, (*it).first ) &&
                    (path[root_len] == '/' || path[root_len] == '\0')) {
    #ifdef _DEBUG_HTTP_SERVER_H
                printf("Found (%s)\r\n", (*it).first.c_str());
    #endif
                // Found!
                break;  // for
            }
        }
        if((it == m_lpHandlers.end()) && !(m_lpHandlers.empty())) {
    #ifdef _DEBUG_HTTP_SERVER_H
            printf("Using default handler\r\n");
    #endif
            it = m_lpHandlers.end();
            it--; //Get the last element
            if( ! (((*it).first.length() == 0) || !(*it).first.compare("/")) ) //This is not the default handler
                it = m_lpHandlers.end();
            root_len = 0;
        }
        if(it == m_lpHandlers.end()) {
    #ifdef _DEBUG_HTTP_SERVER_H
            printf("No handler found\r\n");
    #endif
            return;
        }
    #ifdef _DEBUG_HTTP_SERVER_H
        printf("Handler found.\r\n");
    #endif
        HTTPRequestHandler* pHdlr = (*it).second((*it).first.c_str(), path.c_str() + root_len, client);
    */
    HTTPRequestHandler* pHdlr;
    if (!path.compare(0,strlen(HELLO_PAGE),HELLO_PAGE)) {
#ifdef _DEBUG_HTTP_SERVER_H
        printf("HELLO PAGE CREATE. PATH %s: %s \r\n",HELLO_PAGE, path.c_str() + strlen(HELLO_PAGE));
#endif
        pHdlr = new SimpleHandler(HELLO_PAGE, path.c_str() + strlen(HELLO_PAGE), client);
    }
    
#ifdef RPC_PAGE
    else if (!path.compare(0,strlen(RPC_PAGE),RPC_PAGE)) {
#ifdef _DEBUG_HTTP_SERVER_H
        printf("RPC PAGE CREATE. PATH %s: %s \r\n",RPC_PAGE, path.c_str() + strlen(RPC_PAGE));
#endif
        pHdlr = new RPCHandler(RPC_PAGE, path.c_str() + strlen(RPC_PAGE), client);
    }
#endif

#ifdef IEEE1888WSDL_PAGE
    else if (!path.compare(0,strlen(IEEE1888WSDL_PAGE),IEEE1888WSDL_PAGE)) {
#ifdef _DEBUG_HTTP_SERVER_H
        printf("IEEE1888WSDL_PAGE CREATE. PATH %s: %s \r\n",IEEE1888WSDL_PAGE, path.c_str() + strlen(IEEE1888WSDL_PAGE));
#endif
        pHdlr = new IEEE1888WSDLHandler(IEEE1888WSDL_PAGE, path.c_str() + strlen(IEEE1888WSDL_PAGE)-1, client);
    }
#endif

#ifdef IEEE1888_PAGE
    else if (!path.compare(0,strlen(IEEE1888_PAGE),IEEE1888_PAGE)) {
#ifdef _DEBUG_HTTP_SERVER_H
        printf("IEEE1888_PAGE CREATE. PATH %s: %s \r\n",IEEE1888_PAGE, path.c_str() + strlen(IEEE1888_PAGE));
#endif
        pHdlr = new IEEE1888Handler(IEEE1888_PAGE, path.c_str() + strlen(IEEE1888_PAGE)-1, client);
    }
#endif

#ifdef FS_PAGE
    else if (!path.compare(0,strlen(FS_PAGE),FS_PAGE)) {
#ifdef _DEBUG_HTTP_SERVER_H
        printf("FS_PAGE CREATE. PATH %s: %s \r\n",FS_PAGE, path.c_str() + strlen(FS_PAGE));
#endif
        pHdlr = new FSHandler(FS_PAGE, path.c_str() + strlen(FS_PAGE)-1, client);
    }
#endif

    else {
#ifdef _DEBUG_HTTP_SERVER_H
        printf("No handler found\r\n");
#endif
        pHdlr = new SimpleHandler(HELLO_PAGE, path.c_str() + strlen(HELLO_PAGE), client);
        return;
    }
    //****  client = NULL; //We don't own it anymore
#ifdef _DEBUG_HTTP_SERVER_H
    printf("Handler Created.\r\n");
#endif
    switch(methCode) {
        case HTTP_GET:
            pHdlr->doGet();
            break;
        case HTTP_POST:
            pHdlr->doPost();
            break;
        case HTTP_HEAD:
            pHdlr->doHead();
            break;
    }
#ifdef _DEBUG_HTTP_SERVER_H
    printf("Handler Delete.\r\n");
#endif
    delete pHdlr;
    // delete client;
    //delete pTCPSocketConnection;
#ifdef _DEBUG_HTTP_SERVER_H
    printf("(dispatcherRequest)return\r\n");
#endif
    return ;
}

void HTTPServerChild (void const *arg)
{
#ifdef _DEBUG_HTTP_SERVER_H
    printf("HTTPServerChiled Start......\r\n");
#endif
    TCPSocketConnection* client = (TCPSocketConnection*)arg;

    for (;;) {
#ifdef _DEBUG_HTTP_SERVER_H
        printf("(HTTPServer.h<HTTPServerChild>)Connection from %s\r\n", client->get_address());
#endif
        dispatchRequest(client);
#ifdef _DEBUG_HTTP_SERVER_H
        printf("(HTTPServer.h<HTTPServerChild>)Client->Close %s\r\n", client->get_address());
#endif
        client->close();
#ifdef _DEBUG_HTTP_SERVER_H
 //       printf("(HTTPServer.h<HTTPServerChild>)Client->reset\r\n");
#endif
 //       client->reset_address();
#ifdef _DEBUG_HTTP_SERVER_H
        printf("(HTTPServer.h<HTTPServerChild>)Thread::signal_wait(1)\r\n");
#endif        //delete client;
        Thread::signal_wait(1);
#ifdef _DEBUG_HTTP_SERVER_H
        printf("(HTTPServer.h<HTTPServerChild>)Return \r\n");
#endif
    }
}

void HTTPServerCloser (void const *arg)
{
    TCPSocketConnection *client = (TCPSocketConnection*)arg;
#ifdef _DEBUG_HTTP_SERVER_H
        printf("HTTPCloser start%s\r\n", client->get_address());
#endif

    for (;;) {
        client->close();
#ifdef _DEBUG_HTTP_SERVER_H
        printf("Close %s\r\n", client->get_address());
#endif
        Thread::signal_wait(1);
    }
}

void HTTPServerStart(int port = 80)
{
    int i, t = 0;
    TCPSocketConnection clients[THREAD_MAX];
    TCPSocketConnection xclient;

    for (i = 0; i < THREAD_MAX; i ++) {
        threads[i] = NULL;
    }
    xthread = NULL;

    TCPSocketServer server;
    server.bind(port);
    server.listen();
    // server.set_blocking(false);
#ifdef _DEBUG_HTTP_SERVER_H
    printf("Wait for new connection...\r\n");
#endif
    for (;;) {
#ifdef _DEBUG_HTTP_SERVER_H
        printf("**Start Loop** \r\n");
#endif
        if (t >= 0) {
            if(server.accept(clients[t])==0) {
                // fork child process
                if (threads[t]) {
                    threads[t]->signal_set(1);
                } else {
                    threads[t] = new Thread(HTTPServerChild, (void*)&clients[t]);
                }
#ifdef _DEBUG_HTTP_SERVER_H
                printf("Forked %d\r\n", t);
#endif
            }
        } else {
            if(server.accept(xclient)==0) {
                // closer process
                if (xthread) {
                    xthread->signal_set(1);
                } else {
                    xthread = new Thread(HTTPServerCloser, (void*)&xclient);
                }
#ifdef _DEBUG_HTTP_SERVER_H
                printf("Connection full\r\n");
#endif
            }
        }

        t = -1;
        for (i = 0; i < THREAD_MAX; i ++) {
            if (threads[i] == NULL || threads[i]->get_state() == Thread::WaitingAnd) {
                if (t < 0) t = i; // next empty thread
            }
        }
        // Thread::wait(100);
    }
}


#endif