Port of LwIP performed by Ralf in 2010. Not recommended for use with recent mbed libraries, but good demos of raw LwIP possible

Dependents:   LwIP_raw_API_serverExample tiny-dtls

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