John Lowe / Mbed 2 deprecated WebSockets2

Dependencies:   mbed MD5

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers HTTPServer.h Source File

HTTPServer.h

00001 #ifndef HTTPSERVER_H
00002 #define HTTPSERVER_H
00003 
00004 #include "TCPConnection.h"
00005 #include "TCPListener.h"
00006 #include "NetServer.h"
00007 
00008 #include <map>
00009 #include <set>
00010 #include <list>
00011 
00012 #define HTTP_MAX_EMPTYPOLLS 100
00013 #define GET 4
00014 #define POST 5
00015 
00016 //extern unsigned int gconnections;
00017 
00018 using namespace std;
00019 
00020 namespace mbed {
00021 
00022 class HTTPServer;
00023 class HTTPHandler;
00024 class HTTPConnection;
00025 
00026 /**
00027  * A simple HASH function to reduce the size of stored Header Fields
00028  * TODO: Make the Hash case insensetive.
00029  */
00030 unsigned int hash(unsigned char *str);
00031 
00032 /**
00033  * The Status of an HTTP Request
00034  * Nedded for HTTPHandler subclasses to define there reults in the HTTPHandler:init Method.
00035  */
00036 enum HTTPStatus {
00037   HTTP_SwitchProtocols             = 101,
00038   HTTP_OK                          = 200,
00039   HTTP_BadRequest                  = 400,
00040   HTTP_Unauthorized                = 401,
00041   HTTP_Forbidden                   = 403,
00042   HTTP_NotFound                    = 404,
00043   HTTP_MethodNotAllowed            = 405,
00044   HTTP_InternalServerError         = 500,
00045   HTTP_NotImplemented              = 501,
00046 };
00047 
00048 /**
00049  * The result of a chunk of data used for the HTTPHandler Methodes data and send
00050  */
00051 enum HTTPHandle {
00052   /** Execution Succeeded but more data expected. */
00053   HTTP_Success                     = 600,
00054   
00055   /** Running out of memory waiting for memory */
00056   HTTP_SenderMemory                = 601,
00057 
00058   
00059   /** Execution Succeeded and no more data expected. */
00060   HTTP_SuccessEnded                = 700,
00061   
00062   /** Execution failed. Close conection*/
00063   HTTP_Failed                      = 701,
00064   
00065   /** This module will deliver the data. */
00066   HTTP_Deliver                     = 800,
00067   
00068   /** This module has add header fields to the request. */
00069   HTTP_AddFields                   = 801,
00070 };
00071 
00072 /**
00073  * A parent object for a data storage container for all HTTPHandler objects.
00074  */
00075 class HTTPData {
00076   public:
00077     HTTPData() {}
00078     virtual ~HTTPData() {}
00079 };
00080 
00081 /**
00082  * A HTTPHandler will serve the requested data if there is an object of a 
00083  * child class from HTTPHandler which is registert to an matching prefix.
00084  * To see how to implement your own HTTPHandler classes have a look at 
00085  * HTTPRPC HTTPStaticPage and HTTPFileSystemHandler.
00086  */
00087 class HTTPHandler {
00088   public:
00089     HTTPHandler(const char *prefix) : _prefix(prefix) {};
00090     virtual ~HTTPHandler() {
00091       delete _prefix;
00092     };
00093 
00094   protected:
00095     /**
00096      * Register needed header fields by the HTTPServer.
00097      * Because of memory size the server will throw away all request header fields which are not registert.
00098      * Register the fields you need in your implementation of this method.
00099      */
00100     virtual void reg(HTTPServer *) {};
00101     
00102     /**
00103      * This Method returns if you will deliver the requested page or not.
00104      * It will only executed if the prefix is matched by the URL. 
00105      * If you want to add something to the headerfiles use this method and return HTTP_AddFields. See HTTPFields
00106      * This would be the right method to implement an Auth Handler.
00107      */
00108     virtual HTTPHandle action(HTTPConnection *) const                    {return HTTP_Deliver;}
00109     
00110     /**
00111      * If action returned HTTP_Deliver. 
00112      * This function will be executed and it means your handler will be deliver the requested data.
00113      * In this method is the right place to allocate the needed space for your request data and to prepare the sended Header.
00114      */
00115     virtual HTTPStatus init(HTTPConnection *) const                      {return HTTP_NotFound;}
00116     
00117     /**
00118      * If data from a post request is arrived for an request you accepted this function will be executed with the data.
00119      * @param data A pointer to the received data.
00120      * @param len The length of the received data.
00121      * @return Return an HTTPHandle. For example HTTP_SuccessEnded if you received all your needed data and want to close the conection (normally not the case).
00122      */
00123     virtual HTTPHandle data(HTTPConnection *, void *data, int len) const {return HTTP_SuccessEnded;}
00124     
00125     /**
00126      * If tere is new space in the sendbuffer this function is executed. You can send maximal Bytes of data.
00127      * @return Return an HTTPHandle. For example HTTP_SuccessEnded if you send out all your data and you want to close the connection.
00128      */
00129     virtual HTTPHandle send(HTTPConnection *, int) const                 {return HTTP_SuccessEnded;}
00130     
00131     /**
00132      * returns the Prefix from the HTTPHandler
00133      */
00134     const char *getPrefix() const                                        {return _prefix;}
00135 
00136     const char *_prefix;
00137     
00138   friend HTTPServer;
00139   friend HTTPConnection;
00140 };
00141 
00142 /**
00143  * For every incomming connection we have a HTTPConnection object which will handle the requests of this connection.
00144  */
00145 class HTTPConnection : public TCPConnection {
00146   public:
00147     /**
00148      * Constructs a new connection object from a server.
00149      * It just need the server object to contact the handlers
00150      * and the tcp connection pcb.
00151      * @param parent The server which created the connection.
00152      * @param pcb The pcb object NetServers internal representation of an TCP Connection
00153      */
00154     HTTPConnection(HTTPServer *parent, struct tcp_pcb *pcb);
00155     /**
00156      * Default destructor. Simple cleanup.
00157      */
00158     virtual ~HTTPConnection();
00159 
00160     /**
00161      * Get the requested url.
00162      * Only set if a request ist received.
00163      */
00164     char *getURL() const                  { return _request_url; }
00165     
00166     /**
00167      * Gets a string of set fields to send with the answere header.
00168      */
00169     const char *getHeaderFields() const   { return (_request_headerfields)?_request_headerfields:""; }
00170     
00171     /**
00172      * Gets the length of the anwere in bytes. This is requiered for the HTTP Header.
00173      * It should be set over setLength by an HTTPHandler in the init() method.
00174      */
00175     const int  &getLength() const         { return _request_length; }
00176     
00177     /**
00178      * Gets POST or GET or 0 depends on wether ther is a request and what type is requested.
00179      */
00180     const char &getType() const           { return _request_type; }
00181     
00182     /**
00183      * Gets a value from a header field of the request header.
00184      * But you must have registerd this headerfield by the HTTPServer before.
00185      * Use the HTTPHandler::reg() method for the registration of important header fields for your Handler.
00186      */
00187     const char *getField(char *key) const;
00188     
00189     /**
00190      * For internal usage. Adds an header field value to its hash.
00191      * If it was registered You can see the Value with the getField method
00192      */
00193     void addField(char *key, char *value);
00194     
00195     /**
00196      * Sets the result length for an request shoud be set in an HTTPHandler.init() call.
00197      * This Value will be send with the response header before the first chunk of data is send.
00198      */
00199     void setLength(const int &value)      { _request_length = value; }
00200     
00201     /**
00202      * Set the response header field to a value.
00203      * Should be used in the HTTPHandler::init() method.
00204      * For example if you want to set caching methods.
00205      */
00206     void setHeaderFields(char *value)     { _request_headerfields = value; }
00207     
00208     /** Indicates that if a request is received the header is incomplete until now. */
00209     bool request_incomplete;
00210     
00211     /** If an request is complete HTTPHandler:init will be called and can store here its connection data. */
00212     HTTPData *data;
00213     
00214     /** The handler which handles the current request. Depends on the prefix of the URL. */
00215     HTTPHandler *request_handler;
00216     
00217     /** The status of the request. Will be set as result of HTTPHandler::init. */
00218     HTTPStatus request_status;
00219 
00220     /** The HTTTPServer which created this connection. */
00221     HTTPServer *parent;
00222   private:
00223     virtual void err(err_t err);
00224     virtual err_t poll();
00225     virtual err_t sent(u16_t len);
00226     virtual err_t recv(struct pbuf *q, err_t err);
00227 
00228     /** We will not make any DNS requests. */
00229     virtual void dnsreply(const char *, struct ip_addr *) {}
00230     
00231     /** If a request is finished it will be deleted with this method. Simple cleanup. */
00232     void deleteRequest();
00233 
00234     /** Call the handler to send the next chunk of data. */
00235     void send();
00236     
00237     /** Call the handler if we received new data. */
00238     void store(void *d, struct pbuf *p);
00239     
00240     /** 
00241      * If a request header is not complete we can colect needed header fields. 
00242      * This happens in here.
00243      */
00244     void getFields(struct pbuf **q, char **d);
00245 
00246     char *_request_url;
00247     char  _request_type;
00248     char *_request_headerfields;
00249     map<unsigned int, char *> _request_fields;
00250     int _request_length;
00251     char *_request_arg_key;
00252     char *_request_arg_value;
00253     char  _request_arg_state;
00254     
00255     unsigned int emptypolls; // Last time for timeout
00256     unsigned int _timeout_max;
00257     
00258     bool webSocket; // JDL
00259 
00260 };
00261 
00262 /* Class HTTPServer
00263  *  An object of this class is an HTTPServer instance and will anwere requests on a given port.
00264  *  It will deliver HTTP pages
00265  */
00266 class HTTPServer : public TCPListener {
00267   public:
00268 
00269     /* Constructor: HTTPServer
00270      *  Creates an HTTPServer object. You might want to initialise the network server befor.
00271      *  If you dont do it it will be happen by the first post or get request you make.
00272      *
00273      *  To initialize the network server on creation of the HTTPServer object it's possible to parse some arguments:
00274      * Variables:
00275      *  hostname - A host name for the device. Might take a while to appear in the network, 
00276      *             depends on the network infrastructure. Furthermore in most cases you have 
00277      *             to add your domainname after the host name to address the device.
00278      *             Default is NULL.
00279      *  ip  - The device ipaddress or ip_addr_any for dhcp. Default is ip_addr_any
00280      *  nm  - The device netmask or ip_addr_any for dhcp. Default is ip_addr_any.
00281      *  gw  - The device gateway or ip_addr_any for dhcp. Default is ip_addr_any.
00282      *  dns - The device first dns server ip or ip_addr_any for dhcp. Default is ip_addr_any.
00283      *
00284      * Example:
00285      *  > HTTPServer http;         // Simple DHCP, brings up the TCP/IP stack on bind(). Default prot is port 80.
00286      *  > HTTPServer http(8080);   // Port is here 8080.
00287      *  
00288      *  > HTTPServer http("worf"); // Brings up the device with DHCP and sets the host name "worf"
00289      *  >                          // The device will be available under worf.<your local domain> 
00290      *  >                          // for example worf.1-2-3-4.dynamic.sky.com
00291      *
00292      *  > HTTPServer http("wolf",              // Brings up the device with static IP address and domain name.
00293      *  >                 IPv4(192,168,0,44),  // IPv4 is a helper function which allows to rtype ipaddresses direct
00294      *  >                 IPv4(255,255,255,0), // as numbers in C++.
00295      *  >                 IPv4(192,168,0,1),   // the device address is set to 192.168.0.44, netmask 255.255.255.0
00296      *  >                 IPv4(192,168,0,1)    // default gateway is 192.168.0.1 and dns to 192.168.0.1 as well.
00297      *  >                 8080);               // And port is on 8080. Default port is 80.
00298      */
00299 
00300     HTTPServer(const char *hostname, struct ip_addr ip = ip_addr_any, struct ip_addr nm = ip_addr_any, struct ip_addr gw = ip_addr_any, struct ip_addr dns = ip_addr_any, unsigned short port = 80);
00301     HTTPServer(unsigned short port = 80);
00302 
00303     /* Destructor: ~HTTPServer
00304      *  Destroys the HTTPServer and all open connections.
00305      */
00306     virtual ~HTTPServer() {
00307       fields.clear();
00308       _handler.clear();
00309     }
00310 
00311     /* Function: addHandler
00312      *  Add a new content handler to handle requests.
00313      *  Content handler are URL prefix specific.
00314      *  Have a look at HTTPRPC and HTTPFileSystemHandler for examples.
00315      */
00316     virtual void addHandler(HTTPHandler *handler) {
00317       _handler.push_back(handler);
00318       handler->reg(this);
00319     }
00320     
00321     /* Function registerField
00322      *  Register needed header fields to filter from a request header.
00323      *  Should be called from HTTPHandler::reg()
00324      */
00325     virtual void registerField(char *name) {
00326       fields.insert(hash((unsigned char *)name));
00327     }
00328 
00329     /* Function isField
00330      *  A short lookup if the headerfield is registerd.
00331      */
00332     virtual bool isField(unsigned long h) const {
00333       return fields.find(h) != fields.end();
00334     }
00335     
00336     /* Function: poll 
00337      *   You have to call this method at least every 250ms to let the http server run.
00338      *   But I would recomend to call this function as fast as possible.
00339      *   This function is directly coupled to the answere time of your HTTPServer instance.
00340      */
00341     inline static void poll() {
00342       NetServer::poll();
00343     }
00344 
00345     /* Function: timeout
00346      *  Sets the timout for a HTTP request. 
00347      *  The timout is the time wich is allowed to spent between two incomming TCP packets. 
00348      *  If the time is passed the connection will be closed.
00349      */
00350     void timeout(int value) {
00351       _timeout_max = value;
00352     }
00353 
00354     /* Function timeout
00355      *  Returns the timout to use it in HTTPHandlers and HTTPConnections
00356      */
00357     int timeout() {
00358       return _timeout_max;
00359     }
00360   private:
00361     /**
00362      * Pick up the right handler to deliver the response.
00363      */
00364     virtual HTTPHandler *handle(HTTPConnection *con) const {
00365       for(list<HTTPHandler *>::const_iterator iter = _handler.begin(); iter != _handler.end(); iter++) {      
00366         if(strncmp((*iter)->getPrefix(), con->getURL(), strlen((*iter)->getPrefix()))==0) {
00367           HTTPHandler *handler = *iter;
00368           if(handler->action(con)==HTTP_Deliver) {
00369             return *iter;
00370           }
00371         }
00372       }
00373       return NULL;
00374     }
00375 
00376     /**
00377      * Accept an incomming connection and fork a HTTPConnection if we have enought memory.
00378      */
00379     virtual err_t accept(struct tcp_pcb *pcb, err_t err) {
00380       LWIP_UNUSED_ARG(err);
00381       HTTPConnection *con = new HTTPConnection(this, pcb);
00382 //      printf("New Connection opend. Now are %u connections open\n", ++gconnections);
00383       if(con == NULL) {
00384         printf("http_accept: Out of memory\n");
00385         return ERR_MEM;
00386       }
00387       con->set_poll_interval(1);
00388       tcp_setprio(pcb, TCP_PRIO_MIN);
00389       return ERR_OK;
00390     }
00391 
00392     /** The registerd request header fields */
00393     set<unsigned int> fields;
00394     
00395     /** A List of all registered handler. */
00396     list<HTTPHandler *> _handler;
00397 
00398     int _timeout_max;
00399     
00400   friend HTTPConnection;
00401 };
00402 
00403 };
00404 
00405 #include "HTTPRPC.h"
00406 #include "HTTPFS.h"
00407 #include "HTTPFields.h"
00408 
00409 #endif /* HTTP_H */