Single instance HTTP Server using WiFly Interface.

Dependents:   WiFlyHTTPServerSample MultiThreadingHTTPServer

This is my implementation for a HTTP Server using the WiFly Interface. Please note that this is still under development.

It may still contain several bugs. I have tested it using a 1768 on an application board plus RN-XV board.

Currently there is only a FileSystem implemented. Also it is limited to GET request.

I try to extend it further so it will be more useful.

Btw, it does NOT work with RTOS, which seems not to be the Problem of my library.

Do not Forget to Import the WiFly Interface into your Project when using this library.

Change History:

REV5: - added support for basic RPC GET request functionality.

REV4: - added argument parsing from the request uri. - documentation extended and updated.

HttpServer.h

Committer:
leihen
Date:
2013-06-26
Revision:
14:7f9fbfc18623

File content as of revision 14:7f9fbfc18623:

#ifndef __HTTPSERVER_H__
#define __HTTPSERVER_H__

#include "Wifly.h"
#include "rtos.h"
#include "HTTPConnection.h"
#include "HTTPRequestHandler.h"

#include <string>
#include <map>

typedef enum {
    msg_get,
    msg_post,
    msg_head,
    msg_put,
    msg_delete,
    msg_trace,
    msg_options,
    msg_connect
} msg_t;


typedef struct {
    msg_t                       requestType;
    char                        requestUri[256];
//    map<string, string>         messageHeaders;
} request_msg_t;

/** Typedefinition for a handler function
*/
typedef void (*HTTPRequestHandlerFunction)(HTTPConnection::HTTPMessage&);


/** This is the non-blocking HTTP Server class. The idea behind this class is as follows:
  * the user may instantiate the class and initialize it. Once the server is setup and 
  * listening, the server will stay in an endless loop and keep on listening for new 
  * connections and for new HTTP requests. Once a request is received it will be placed 
  * in a queue. The queue itself will be handled in a separate task.
  */
class HttpServer : public Wifly
{
        Thread      *m_listener;
        Thread      *m_worker;

        request_msg_t*  checkMessageReceived(char *);
        void            processMessageHeader(char* headerLine, char **fieldname, char **fieldvalue);        
        
    public:
        HttpServer(PinName tx, PinName rx, PinName reset, PinName tcp_status, const char * ssid, const char * phrase, Security sec, Wifly::WiflyBaudrate_t baud = Wifly::Wifly_115200);
        ~HttpServer();
        
        bool start(int port);
        
        virtual void handler_rx(void);
        virtual void attach_rx(bool);
        
        virtual bool join();
        virtual int send(const char * str, int len, const char * ACK = NULL, char * res = NULL, int timeout = DEFAULT_WAIT_RESP_TIMEOUT);
        
    public:
        
        
        /**
        * Structure which will allow to order the stored handlers according to their associated path.
        */
        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));
            }
        };
        /** The standard error handler function.
        * @param msg : Request message data.
        * @param tcp : Socket to be used for responding.
        */
        static void StdErrorHandler(HTTPConnection::HTTPMessage& msg);


        /** Internal function which processes a request and which will try to find the matching handler function
        * for the given request. Please note that the function will search through the list of handlers, iterating
        * from longest to shortest \c paths. If the registered \c path is a subset of the request the associated
        * handler is considered as being a match.
        * @param msg : Request message data. Contains the requested logical \c uri. 
        * @param tcp : Socket to be used for communication with the client.
        */
        void HandleRequest(HTTPConnection::HTTPMessage* msg);
    
        /** Map of handler objects. Can be any object derived from \ref HTTPRequestHeader. Use the \ref addHandler function
        * to register new handler objects.
        */
        static map<string, HTTPRequestHandler* (*)(const char*, const char*, HTTPConnection::HTTPMessage&), handlersComp>   m_lpHandlers;

        /**
        * Adds a request handler to the handlers list. You will have to use one of the existing implementations.
        * With each handler a \c uri or \c path is associated. Whenever a request is received the server will
        * walk through all registered handlers and check which \c path is matching.
        * @param T : class which will be instanciated to serve these requests for the associated \b path.
        * @param path : request uri starting with this \c path will be served using this handler.
        */
        template<typename T>
        void addHandler(const char* path)
        { m_lpHandlers[path] = &T::create; }
    
        /**
        * Replaces the standard error Handler. The error Handler will be called everytime a request is not
        * matching any of the registered \c paths or \c uris.
        * @param hdlFunc: User specified handler function which will be used in error conditions.
        */
        void addErrorHandler(HTTPRequestHandlerFunction hdlFunc)
        { m_pErrorHandler = hdlFunc!=NULL ?hdlFunc : StdErrorHandler; }    
        HTTPRequestHandlerFunction m_pErrorHandler;

    protected:
        bool bind(int port);
        void listenForRequests();
        void serveRequests();
        
        bool parseRequest(char *request);
        
        static void listen_thread(const void * parms);
        static void worker_thread(const void * parms);
};

#endif //   __HTTPSERVER_H__