A version of LWIP, provided for backwards compatibility.

Dependents:   AA_DemoBoard DemoBoard HelloServerDemo DemoBoard_RangeIndicator ... more

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     u8_t emptypolls;
00255 };
00256 
00257 /**
00258  * The HTTPServer class.
00259  * It representates the top class of an HTTPServer.
00260  */
00261 class HTTPServer : public TCPListener {
00262   public:
00263     /**
00264      * Create a new server instance by default on port 80.
00265      */
00266     HTTPServer(u16_t = 80);
00267     virtual ~HTTPServer() {
00268       fields.clear();
00269       _handler.clear();
00270     }
00271 
00272     /**
00273      * Add a new content handler to handle requests.
00274      * Content handler are URL prefix specific.
00275      * Have a look at HTTPRPC and HTTPFileSystemHandler for examples.
00276      */
00277     virtual void addHandler(HTTPHandler *handler) {
00278       _handler.push_back(handler);
00279       handler->reg(this);
00280     }
00281     
00282     /**
00283      * Register needed header fields to filter from a request header.
00284      * Should be called from HTTPHandler::reg()
00285      */
00286     virtual void registerField(char *name) {
00287       fields.insert(hash((unsigned char *)name));
00288     }
00289 
00290     /**
00291      * A short lookup if the headerfield is registerd.
00292      */
00293     virtual bool isField(unsigned long h) const {
00294       return fields.find(h) != fields.end();
00295     }
00296     
00297     /**
00298      * You have to call this method at least every 250ms to let the http server run.
00299      * But I would recomend to call this function as fast as possible.
00300      * This function is directly coupled to the answere time of your HTTPServer instance.
00301      */
00302     inline static void poll() {
00303       NetServer::poll();
00304     }
00305   private:
00306     /**
00307      * Pick up the right handler to deliver the response.
00308      */
00309     virtual HTTPHandler *handle(HTTPConnection *con) const {
00310       for(list<HTTPHandler *>::const_iterator iter = _handler.begin();
00311           iter != _handler.end(); iter++) {
00312         if(strncmp((*iter)->getPrefix(), con->getURL(), strlen((*iter)->getPrefix()))==0) {
00313           HTTPHandler *handler = *iter;
00314           if(handler->action(con)==HTTP_Deliver) {
00315             return *iter;
00316           }
00317         }
00318       }
00319       return NULL;
00320     }
00321 
00322     /**
00323      * Accept an incomming connection and fork a HTTPConnection if we have enought memory.
00324      */
00325     virtual err_t accept(struct tcp_pcb *pcb, err_t err) {
00326       LWIP_UNUSED_ARG(err);
00327       HTTPConnection *con = new HTTPConnection(this, pcb);
00328 //      printf("New Connection opend. Now are %u connections open\n", ++gconnections);
00329       if(con == NULL) {
00330         printf("http_accept: Out of memory\n");
00331         return ERR_MEM;
00332       }
00333       con->set_poll_interval(1);
00334       tcp_setprio(pcb, TCP_PRIO_MIN);
00335       return ERR_OK;
00336     }
00337 
00338     /** The registerd request header fields */
00339     set<unsigned int> fields;
00340     
00341     /** A List of all registered handler. */
00342     list<HTTPHandler *> _handler;
00343   friend HTTPConnection;
00344 };
00345 
00346 };
00347 
00348 #endif /* HTTP_H */