My fork of the HTTPServer (working)

Dependents:   DGWWebServer LAN2

Committer:
screamer
Date:
Tue Nov 20 12:18:53 2012 +0000
Revision:
1:284f2df30cf9
Parent:
0:7a64fbb4069d
local changes

Who changed what in which revision?

UserRevisionLine numberNew contents of line
screamer 0:7a64fbb4069d 1 #ifndef HTTPSERVER_H
screamer 0:7a64fbb4069d 2 #define HTTPSERVER_H
screamer 0:7a64fbb4069d 3
screamer 0:7a64fbb4069d 4 #include "TCPConnection.h"
screamer 0:7a64fbb4069d 5 #include "TCPListener.h"
screamer 0:7a64fbb4069d 6 #include "NetServer.h"
screamer 0:7a64fbb4069d 7
screamer 0:7a64fbb4069d 8 #include <map>
screamer 0:7a64fbb4069d 9 #include <set>
screamer 0:7a64fbb4069d 10 #include <list>
screamer 0:7a64fbb4069d 11
screamer 0:7a64fbb4069d 12 #define HTTP_MAX_EMPTYPOLLS 100
screamer 0:7a64fbb4069d 13 #define GET 4
screamer 0:7a64fbb4069d 14 #define POST 5
screamer 0:7a64fbb4069d 15
screamer 0:7a64fbb4069d 16 //extern unsigned int gconnections;
screamer 0:7a64fbb4069d 17
screamer 0:7a64fbb4069d 18 using namespace std;
screamer 0:7a64fbb4069d 19
screamer 0:7a64fbb4069d 20 namespace mbed {
screamer 0:7a64fbb4069d 21
screamer 0:7a64fbb4069d 22 class HTTPServer;
screamer 0:7a64fbb4069d 23 class HTTPHandler;
screamer 0:7a64fbb4069d 24 class HTTPConnection;
screamer 0:7a64fbb4069d 25
screamer 0:7a64fbb4069d 26 /**
screamer 0:7a64fbb4069d 27 * A simple HASH function to reduce the size of stored Header Fields
screamer 0:7a64fbb4069d 28 * TODO: Make the Hash case insensetive.
screamer 0:7a64fbb4069d 29 */
screamer 0:7a64fbb4069d 30 unsigned int hash(unsigned char *str);
screamer 0:7a64fbb4069d 31
screamer 0:7a64fbb4069d 32 /**
screamer 0:7a64fbb4069d 33 * The Status of an HTTP Request
screamer 0:7a64fbb4069d 34 * Nedded for HTTPHandler subclasses to define there reults in the HTTPHandler:init Method.
screamer 0:7a64fbb4069d 35 */
screamer 0:7a64fbb4069d 36 enum HTTPStatus {
screamer 0:7a64fbb4069d 37 HTTP_OK = 200,
screamer 0:7a64fbb4069d 38 HTTP_BadRequest = 400,
screamer 0:7a64fbb4069d 39 HTTP_Unauthorized = 401,
screamer 0:7a64fbb4069d 40 HTTP_Forbidden = 403,
screamer 0:7a64fbb4069d 41 HTTP_NotFound = 404,
screamer 0:7a64fbb4069d 42 HTTP_MethodNotAllowed = 405,
screamer 0:7a64fbb4069d 43 HTTP_InternalServerError = 500,
screamer 0:7a64fbb4069d 44 HTTP_NotImplemented = 501,
screamer 0:7a64fbb4069d 45 };
screamer 0:7a64fbb4069d 46
screamer 0:7a64fbb4069d 47 /**
screamer 0:7a64fbb4069d 48 * The result of a chunk of data used for the HTTPHandler Methodes data and send
screamer 0:7a64fbb4069d 49 */
screamer 0:7a64fbb4069d 50 enum HTTPHandle {
screamer 0:7a64fbb4069d 51 /** Execution Succeeded but more data expected. */
screamer 0:7a64fbb4069d 52 HTTP_Success = 600,
screamer 0:7a64fbb4069d 53
screamer 0:7a64fbb4069d 54 /** Running out of memory waiting for memory */
screamer 0:7a64fbb4069d 55 HTTP_SenderMemory = 601,
screamer 0:7a64fbb4069d 56
screamer 0:7a64fbb4069d 57
screamer 0:7a64fbb4069d 58 /** Execution Succeeded and no more data expected. */
screamer 0:7a64fbb4069d 59 HTTP_SuccessEnded = 700,
screamer 0:7a64fbb4069d 60
screamer 0:7a64fbb4069d 61 /** Execution failed. Close conection*/
screamer 0:7a64fbb4069d 62 HTTP_Failed = 701,
screamer 0:7a64fbb4069d 63
screamer 0:7a64fbb4069d 64 /** This module will deliver the data. */
screamer 0:7a64fbb4069d 65 HTTP_Deliver = 800,
screamer 0:7a64fbb4069d 66
screamer 0:7a64fbb4069d 67 /** This module has add header fields to the request. */
screamer 0:7a64fbb4069d 68 HTTP_AddFields = 801,
screamer 0:7a64fbb4069d 69 };
screamer 0:7a64fbb4069d 70
screamer 0:7a64fbb4069d 71 /**
screamer 0:7a64fbb4069d 72 * A parent object for a data storage container for all HTTPHandler objects.
screamer 0:7a64fbb4069d 73 */
screamer 0:7a64fbb4069d 74 class HTTPData {
screamer 0:7a64fbb4069d 75 public:
screamer 0:7a64fbb4069d 76 HTTPData() {}
screamer 0:7a64fbb4069d 77 virtual ~HTTPData() {}
screamer 0:7a64fbb4069d 78 };
screamer 0:7a64fbb4069d 79
screamer 0:7a64fbb4069d 80 /**
screamer 0:7a64fbb4069d 81 * A HTTPHandler will serve the requested data if there is an object of a
screamer 0:7a64fbb4069d 82 * child class from HTTPHandler which is registert to an matching prefix.
screamer 0:7a64fbb4069d 83 * To see how to implement your own HTTPHandler classes have a look at
screamer 0:7a64fbb4069d 84 * HTTPRPC HTTPStaticPage and HTTPFileSystemHandler.
screamer 0:7a64fbb4069d 85 */
screamer 0:7a64fbb4069d 86 class HTTPHandler {
screamer 0:7a64fbb4069d 87 public:
screamer 0:7a64fbb4069d 88 HTTPHandler(const char *prefix) : _prefix(prefix) {};
screamer 0:7a64fbb4069d 89 virtual ~HTTPHandler() {
screamer 0:7a64fbb4069d 90 delete _prefix;
screamer 0:7a64fbb4069d 91 };
screamer 0:7a64fbb4069d 92
screamer 0:7a64fbb4069d 93 protected:
screamer 0:7a64fbb4069d 94 /**
screamer 0:7a64fbb4069d 95 * Register needed header fields by the HTTPServer.
screamer 0:7a64fbb4069d 96 * Because of memory size the server will throw away all request header fields which are not registert.
screamer 0:7a64fbb4069d 97 * Register the fields you need in your implementation of this method.
screamer 0:7a64fbb4069d 98 */
screamer 0:7a64fbb4069d 99 virtual void reg(HTTPServer *) {};
screamer 0:7a64fbb4069d 100
screamer 0:7a64fbb4069d 101 /**
screamer 0:7a64fbb4069d 102 * This Method returns if you will deliver the requested page or not.
screamer 0:7a64fbb4069d 103 * It will only executed if the prefix is matched by the URL.
screamer 0:7a64fbb4069d 104 * If you want to add something to the headerfiles use this method and return HTTP_AddFields. See HTTPFields
screamer 0:7a64fbb4069d 105 * This would be the right method to implement an Auth Handler.
screamer 0:7a64fbb4069d 106 */
screamer 0:7a64fbb4069d 107 virtual HTTPHandle action(HTTPConnection *) const {return HTTP_Deliver;}
screamer 0:7a64fbb4069d 108
screamer 0:7a64fbb4069d 109 /**
screamer 0:7a64fbb4069d 110 * If action returned HTTP_Deliver.
screamer 0:7a64fbb4069d 111 * This function will be executed and it means your handler will be deliver the requested data.
screamer 0:7a64fbb4069d 112 * In this method is the right place to allocate the needed space for your request data and to prepare the sended Header.
screamer 0:7a64fbb4069d 113 */
screamer 0:7a64fbb4069d 114 virtual HTTPStatus init(HTTPConnection *) const {return HTTP_NotFound;}
screamer 0:7a64fbb4069d 115
screamer 0:7a64fbb4069d 116 /**
screamer 0:7a64fbb4069d 117 * If data from a post request is arrived for an request you accepted this function will be executed with the data.
screamer 0:7a64fbb4069d 118 * @param data A pointer to the received data.
screamer 0:7a64fbb4069d 119 * @param len The length of the received data.
screamer 0:7a64fbb4069d 120 * @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).
screamer 0:7a64fbb4069d 121 */
screamer 0:7a64fbb4069d 122 virtual HTTPHandle data(HTTPConnection *, void *data, int len) const {return HTTP_SuccessEnded;}
screamer 0:7a64fbb4069d 123
screamer 0:7a64fbb4069d 124 /**
screamer 0:7a64fbb4069d 125 * If tere is new space in the sendbuffer this function is executed. You can send maximal Bytes of data.
screamer 0:7a64fbb4069d 126 * @return Return an HTTPHandle. For example HTTP_SuccessEnded if you send out all your data and you want to close the connection.
screamer 0:7a64fbb4069d 127 */
screamer 0:7a64fbb4069d 128 virtual HTTPHandle send(HTTPConnection *, int) const {return HTTP_SuccessEnded;}
screamer 0:7a64fbb4069d 129
screamer 0:7a64fbb4069d 130 /**
screamer 0:7a64fbb4069d 131 * returns the Prefix from the HTTPHandler
screamer 0:7a64fbb4069d 132 */
screamer 0:7a64fbb4069d 133 const char *getPrefix() const {return _prefix;}
screamer 0:7a64fbb4069d 134
screamer 0:7a64fbb4069d 135 const char *_prefix;
screamer 0:7a64fbb4069d 136
screamer 0:7a64fbb4069d 137 friend HTTPServer;
screamer 0:7a64fbb4069d 138 friend HTTPConnection;
screamer 0:7a64fbb4069d 139 };
screamer 0:7a64fbb4069d 140
screamer 0:7a64fbb4069d 141 /**
screamer 0:7a64fbb4069d 142 * For every incomming connection we have a HTTPConnection object which will handle the requests of this connection.
screamer 0:7a64fbb4069d 143 */
screamer 0:7a64fbb4069d 144 class HTTPConnection : public TCPConnection {
screamer 0:7a64fbb4069d 145 public:
screamer 0:7a64fbb4069d 146 /**
screamer 0:7a64fbb4069d 147 * Constructs a new connection object from a server.
screamer 0:7a64fbb4069d 148 * It just need the server object to contact the handlers
screamer 0:7a64fbb4069d 149 * and the tcp connection pcb.
screamer 0:7a64fbb4069d 150 * @param parent The server which created the connection.
screamer 0:7a64fbb4069d 151 * @param pcb The pcb object NetServers internal representation of an TCP Connection
screamer 0:7a64fbb4069d 152 */
screamer 0:7a64fbb4069d 153 HTTPConnection(HTTPServer *parent, struct tcp_pcb *pcb);
screamer 0:7a64fbb4069d 154 /**
screamer 0:7a64fbb4069d 155 * Default destructor. Simple cleanup.
screamer 0:7a64fbb4069d 156 */
screamer 0:7a64fbb4069d 157 virtual ~HTTPConnection();
screamer 0:7a64fbb4069d 158
screamer 0:7a64fbb4069d 159 /**
screamer 0:7a64fbb4069d 160 * Get the requested url.
screamer 0:7a64fbb4069d 161 * Only set if a request ist received.
screamer 0:7a64fbb4069d 162 */
screamer 0:7a64fbb4069d 163 char *getURL() const { return _request_url; }
screamer 0:7a64fbb4069d 164
screamer 0:7a64fbb4069d 165 /**
screamer 0:7a64fbb4069d 166 * Gets a string of set fields to send with the answere header.
screamer 0:7a64fbb4069d 167 */
screamer 0:7a64fbb4069d 168 const char *getHeaderFields() const { return (_request_headerfields)?_request_headerfields:""; }
screamer 0:7a64fbb4069d 169
screamer 0:7a64fbb4069d 170 /**
screamer 0:7a64fbb4069d 171 * Gets the length of the anwere in bytes. This is requiered for the HTTP Header.
screamer 0:7a64fbb4069d 172 * It should be set over setLength by an HTTPHandler in the init() method.
screamer 0:7a64fbb4069d 173 */
screamer 0:7a64fbb4069d 174 const int &getLength() const { return _request_length; }
screamer 0:7a64fbb4069d 175
screamer 0:7a64fbb4069d 176 /**
screamer 0:7a64fbb4069d 177 * Gets POST or GET or 0 depends on wether ther is a request and what type is requested.
screamer 0:7a64fbb4069d 178 */
screamer 0:7a64fbb4069d 179 const char &getType() const { return _request_type; }
screamer 0:7a64fbb4069d 180
screamer 0:7a64fbb4069d 181 /**
screamer 0:7a64fbb4069d 182 * Gets a value from a header field of the request header.
screamer 0:7a64fbb4069d 183 * But you must have registerd this headerfield by the HTTPServer before.
screamer 0:7a64fbb4069d 184 * Use the HTTPHandler::reg() method for the registration of important header fields for your Handler.
screamer 0:7a64fbb4069d 185 */
screamer 0:7a64fbb4069d 186 const char *getField(char *key) const;
screamer 0:7a64fbb4069d 187
screamer 0:7a64fbb4069d 188 /**
screamer 0:7a64fbb4069d 189 * For internal usage. Adds an header field value to its hash.
screamer 0:7a64fbb4069d 190 * If it was registered You can see the Value with the getField method
screamer 0:7a64fbb4069d 191 */
screamer 0:7a64fbb4069d 192 void addField(char *key, char *value);
screamer 0:7a64fbb4069d 193
screamer 0:7a64fbb4069d 194 /**
screamer 0:7a64fbb4069d 195 * Sets the result length for an request shoud be set in an HTTPHandler.init() call.
screamer 0:7a64fbb4069d 196 * This Value will be send with the response header before the first chunk of data is send.
screamer 0:7a64fbb4069d 197 */
screamer 0:7a64fbb4069d 198 void setLength(const int &value) { _request_length = value; }
screamer 0:7a64fbb4069d 199
screamer 0:7a64fbb4069d 200 /**
screamer 0:7a64fbb4069d 201 * Set the response header field to a value.
screamer 0:7a64fbb4069d 202 * Should be used in the HTTPHandler::init() method.
screamer 0:7a64fbb4069d 203 * For example if you want to set caching methods.
screamer 0:7a64fbb4069d 204 */
screamer 0:7a64fbb4069d 205 void setHeaderFields(char *value) { _request_headerfields = value; }
screamer 0:7a64fbb4069d 206
screamer 0:7a64fbb4069d 207 /** Indicates that if a request is received the header is incomplete until now. */
screamer 0:7a64fbb4069d 208 bool request_incomplete;
screamer 0:7a64fbb4069d 209
screamer 0:7a64fbb4069d 210 /** If an request is complete HTTPHandler:init will be called and can store here its connection data. */
screamer 0:7a64fbb4069d 211 HTTPData *data;
screamer 0:7a64fbb4069d 212
screamer 0:7a64fbb4069d 213 /** The handler which handles the current request. Depends on the prefix of the URL. */
screamer 0:7a64fbb4069d 214 HTTPHandler *request_handler;
screamer 0:7a64fbb4069d 215
screamer 0:7a64fbb4069d 216 /** The status of the request. Will be set as result of HTTPHandler::init. */
screamer 0:7a64fbb4069d 217 HTTPStatus request_status;
screamer 0:7a64fbb4069d 218
screamer 0:7a64fbb4069d 219 /** The HTTTPServer which created this connection. */
screamer 0:7a64fbb4069d 220 HTTPServer *parent;
screamer 0:7a64fbb4069d 221 private:
screamer 0:7a64fbb4069d 222 virtual void err(err_t err);
screamer 0:7a64fbb4069d 223 virtual err_t poll();
screamer 0:7a64fbb4069d 224 virtual err_t sent(u16_t len);
screamer 0:7a64fbb4069d 225 virtual err_t recv(struct pbuf *q, err_t err);
screamer 0:7a64fbb4069d 226
screamer 0:7a64fbb4069d 227 /** We will not make any DNS requests. */
screamer 0:7a64fbb4069d 228 virtual void dnsreply(const char *, struct ip_addr *) {}
screamer 0:7a64fbb4069d 229
screamer 0:7a64fbb4069d 230 /** If a request is finished it will be deleted with this method. Simple cleanup. */
screamer 0:7a64fbb4069d 231 void deleteRequest();
screamer 0:7a64fbb4069d 232
screamer 0:7a64fbb4069d 233 /** Call the handler to send the next chunk of data. */
screamer 0:7a64fbb4069d 234 void send();
screamer 0:7a64fbb4069d 235
screamer 0:7a64fbb4069d 236 /** Call the handler if we received new data. */
screamer 0:7a64fbb4069d 237 void store(void *d, struct pbuf *p);
screamer 0:7a64fbb4069d 238
screamer 0:7a64fbb4069d 239 /**
screamer 0:7a64fbb4069d 240 * If a request header is not complete we can colect needed header fields.
screamer 0:7a64fbb4069d 241 * This happens in here.
screamer 0:7a64fbb4069d 242 */
screamer 0:7a64fbb4069d 243 void getFields(struct pbuf **q, char **d);
screamer 0:7a64fbb4069d 244
screamer 0:7a64fbb4069d 245 char *_request_url;
screamer 0:7a64fbb4069d 246 char _request_type;
screamer 0:7a64fbb4069d 247 char *_request_headerfields;
screamer 0:7a64fbb4069d 248 map<unsigned int, char *> _request_fields;
screamer 0:7a64fbb4069d 249 int _request_length;
screamer 0:7a64fbb4069d 250 char *_request_arg_key;
screamer 0:7a64fbb4069d 251 char *_request_arg_value;
screamer 0:7a64fbb4069d 252 char _request_arg_state;
screamer 0:7a64fbb4069d 253
screamer 0:7a64fbb4069d 254 u8_t emptypolls;
screamer 0:7a64fbb4069d 255 };
screamer 0:7a64fbb4069d 256
screamer 0:7a64fbb4069d 257 /**
screamer 0:7a64fbb4069d 258 * The HTTPServer class.
screamer 0:7a64fbb4069d 259 * It representates the top class of an HTTPServer.
screamer 0:7a64fbb4069d 260 */
screamer 0:7a64fbb4069d 261 class HTTPServer : public TCPListener {
screamer 0:7a64fbb4069d 262 public:
screamer 0:7a64fbb4069d 263 /**
screamer 0:7a64fbb4069d 264 * Create a new server instance by default on port 80.
screamer 0:7a64fbb4069d 265 */
screamer 0:7a64fbb4069d 266 HTTPServer(u16_t = 80);
screamer 0:7a64fbb4069d 267 virtual ~HTTPServer() {
screamer 0:7a64fbb4069d 268 fields.clear();
screamer 0:7a64fbb4069d 269 _handler.clear();
screamer 0:7a64fbb4069d 270 }
screamer 0:7a64fbb4069d 271
screamer 0:7a64fbb4069d 272 /**
screamer 0:7a64fbb4069d 273 * Add a new content handler to handle requests.
screamer 0:7a64fbb4069d 274 * Content handler are URL prefix specific.
screamer 0:7a64fbb4069d 275 * Have a look at HTTPRPC and HTTPFileSystemHandler for examples.
screamer 0:7a64fbb4069d 276 */
screamer 0:7a64fbb4069d 277 virtual void addHandler(HTTPHandler *handler) {
screamer 0:7a64fbb4069d 278 _handler.push_back(handler);
screamer 0:7a64fbb4069d 279 handler->reg(this);
screamer 0:7a64fbb4069d 280 }
screamer 0:7a64fbb4069d 281
screamer 0:7a64fbb4069d 282 /**
screamer 0:7a64fbb4069d 283 * Register needed header fields to filter from a request header.
screamer 0:7a64fbb4069d 284 * Should be called from HTTPHandler::reg()
screamer 0:7a64fbb4069d 285 */
screamer 0:7a64fbb4069d 286 virtual void registerField(char *name) {
screamer 0:7a64fbb4069d 287 fields.insert(hash((unsigned char *)name));
screamer 0:7a64fbb4069d 288 }
screamer 0:7a64fbb4069d 289
screamer 0:7a64fbb4069d 290 /**
screamer 0:7a64fbb4069d 291 * A short lookup if the headerfield is registerd.
screamer 0:7a64fbb4069d 292 */
screamer 0:7a64fbb4069d 293 virtual bool isField(unsigned long h) const {
screamer 0:7a64fbb4069d 294 return fields.find(h) != fields.end();
screamer 0:7a64fbb4069d 295 }
screamer 0:7a64fbb4069d 296
screamer 0:7a64fbb4069d 297 /**
screamer 0:7a64fbb4069d 298 * You have to call this method at least every 250ms to let the http server run.
screamer 0:7a64fbb4069d 299 * But I would recomend to call this function as fast as possible.
screamer 0:7a64fbb4069d 300 * This function is directly coupled to the answere time of your HTTPServer instance.
screamer 0:7a64fbb4069d 301 */
screamer 0:7a64fbb4069d 302 inline static void poll() {
screamer 0:7a64fbb4069d 303 NetServer::poll();
screamer 0:7a64fbb4069d 304 }
screamer 0:7a64fbb4069d 305 private:
screamer 0:7a64fbb4069d 306 /**
screamer 0:7a64fbb4069d 307 * Pick up the right handler to deliver the response.
screamer 0:7a64fbb4069d 308 */
screamer 0:7a64fbb4069d 309 virtual HTTPHandler *handle(HTTPConnection *con) const {
screamer 0:7a64fbb4069d 310 for(list<HTTPHandler *>::const_iterator iter = _handler.begin();
screamer 0:7a64fbb4069d 311 iter != _handler.end(); iter++) {
screamer 0:7a64fbb4069d 312 if(strncmp((*iter)->getPrefix(), con->getURL(), strlen((*iter)->getPrefix()))==0) {
screamer 0:7a64fbb4069d 313 HTTPHandler *handler = *iter;
screamer 0:7a64fbb4069d 314 if(handler->action(con)==HTTP_Deliver) {
screamer 0:7a64fbb4069d 315 return *iter;
screamer 0:7a64fbb4069d 316 }
screamer 0:7a64fbb4069d 317 }
screamer 0:7a64fbb4069d 318 }
screamer 0:7a64fbb4069d 319 return NULL;
screamer 0:7a64fbb4069d 320 }
screamer 0:7a64fbb4069d 321
screamer 0:7a64fbb4069d 322 /**
screamer 0:7a64fbb4069d 323 * Accept an incomming connection and fork a HTTPConnection if we have enought memory.
screamer 0:7a64fbb4069d 324 */
screamer 0:7a64fbb4069d 325 virtual err_t accept(struct tcp_pcb *pcb, err_t err) {
screamer 0:7a64fbb4069d 326 LWIP_UNUSED_ARG(err);
screamer 0:7a64fbb4069d 327 HTTPConnection *con = new HTTPConnection(this, pcb);
screamer 0:7a64fbb4069d 328 // printf("New Connection opend. Now are %u connections open\n", ++gconnections);
screamer 0:7a64fbb4069d 329 if(con == NULL) {
screamer 0:7a64fbb4069d 330 printf("http_accept: Out of memory\n");
screamer 0:7a64fbb4069d 331 return ERR_MEM;
screamer 0:7a64fbb4069d 332 }
screamer 0:7a64fbb4069d 333 con->set_poll_interval(1);
screamer 0:7a64fbb4069d 334 tcp_setprio(pcb, TCP_PRIO_MIN);
screamer 0:7a64fbb4069d 335 return ERR_OK;
screamer 0:7a64fbb4069d 336 }
screamer 0:7a64fbb4069d 337
screamer 0:7a64fbb4069d 338 /** The registerd request header fields */
screamer 0:7a64fbb4069d 339 set<unsigned int> fields;
screamer 0:7a64fbb4069d 340
screamer 0:7a64fbb4069d 341 /** A List of all registered handler. */
screamer 0:7a64fbb4069d 342 list<HTTPHandler *> _handler;
screamer 0:7a64fbb4069d 343 friend HTTPConnection;
screamer 0:7a64fbb4069d 344 };
screamer 0:7a64fbb4069d 345
screamer 0:7a64fbb4069d 346 };
screamer 0:7a64fbb4069d 347
screamer 0:7a64fbb4069d 348 #endif /* HTTP_H */