Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: HTTPServer/HTTPServer.h
- Revision:
- 0:7a64fbb4069d
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/HTTPServer/HTTPServer.h Mon Aug 06 09:23:14 2012 +0000
@@ -0,0 +1,348 @@
+#ifndef HTTPSERVER_H
+#define HTTPSERVER_H
+
+#include "TCPConnection.h"
+#include "TCPListener.h"
+#include "NetServer.h"
+
+#include <map>
+#include <set>
+#include <list>
+
+#define HTTP_MAX_EMPTYPOLLS 100
+#define GET 4
+#define POST 5
+
+//extern unsigned int gconnections;
+
+using namespace std;
+
+namespace mbed {
+
+class HTTPServer;
+class HTTPHandler;
+class HTTPConnection;
+
+/**
+ * A simple HASH function to reduce the size of stored Header Fields
+ * TODO: Make the Hash case insensetive.
+ */
+unsigned int hash(unsigned char *str);
+
+/**
+ * The Status of an HTTP Request
+ * Nedded for HTTPHandler subclasses to define there reults in the HTTPHandler:init Method.
+ */
+enum HTTPStatus {
+ HTTP_OK = 200,
+ HTTP_BadRequest = 400,
+ HTTP_Unauthorized = 401,
+ HTTP_Forbidden = 403,
+ HTTP_NotFound = 404,
+ HTTP_MethodNotAllowed = 405,
+ HTTP_InternalServerError = 500,
+ HTTP_NotImplemented = 501,
+};
+
+/**
+ * The result of a chunk of data used for the HTTPHandler Methodes data and send
+ */
+enum HTTPHandle {
+ /** Execution Succeeded but more data expected. */
+ HTTP_Success = 600,
+
+ /** Running out of memory waiting for memory */
+ HTTP_SenderMemory = 601,
+
+
+ /** Execution Succeeded and no more data expected. */
+ HTTP_SuccessEnded = 700,
+
+ /** Execution failed. Close conection*/
+ HTTP_Failed = 701,
+
+ /** This module will deliver the data. */
+ HTTP_Deliver = 800,
+
+ /** This module has add header fields to the request. */
+ HTTP_AddFields = 801,
+};
+
+/**
+ * A parent object for a data storage container for all HTTPHandler objects.
+ */
+class HTTPData {
+ public:
+ HTTPData() {}
+ virtual ~HTTPData() {}
+};
+
+/**
+ * A HTTPHandler will serve the requested data if there is an object of a
+ * child class from HTTPHandler which is registert to an matching prefix.
+ * To see how to implement your own HTTPHandler classes have a look at
+ * HTTPRPC HTTPStaticPage and HTTPFileSystemHandler.
+ */
+class HTTPHandler {
+ public:
+ HTTPHandler(const char *prefix) : _prefix(prefix) {};
+ virtual ~HTTPHandler() {
+ delete _prefix;
+ };
+
+ protected:
+ /**
+ * Register needed header fields by the HTTPServer.
+ * Because of memory size the server will throw away all request header fields which are not registert.
+ * Register the fields you need in your implementation of this method.
+ */
+ virtual void reg(HTTPServer *) {};
+
+ /**
+ * This Method returns if you will deliver the requested page or not.
+ * It will only executed if the prefix is matched by the URL.
+ * If you want to add something to the headerfiles use this method and return HTTP_AddFields. See HTTPFields
+ * This would be the right method to implement an Auth Handler.
+ */
+ virtual HTTPHandle action(HTTPConnection *) const {return HTTP_Deliver;}
+
+ /**
+ * If action returned HTTP_Deliver.
+ * This function will be executed and it means your handler will be deliver the requested data.
+ * In this method is the right place to allocate the needed space for your request data and to prepare the sended Header.
+ */
+ virtual HTTPStatus init(HTTPConnection *) const {return HTTP_NotFound;}
+
+ /**
+ * If data from a post request is arrived for an request you accepted this function will be executed with the data.
+ * @param data A pointer to the received data.
+ * @param len The length of the received data.
+ * @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).
+ */
+ virtual HTTPHandle data(HTTPConnection *, void *data, int len) const {return HTTP_SuccessEnded;}
+
+ /**
+ * If tere is new space in the sendbuffer this function is executed. You can send maximal Bytes of data.
+ * @return Return an HTTPHandle. For example HTTP_SuccessEnded if you send out all your data and you want to close the connection.
+ */
+ virtual HTTPHandle send(HTTPConnection *, int) const {return HTTP_SuccessEnded;}
+
+ /**
+ * returns the Prefix from the HTTPHandler
+ */
+ const char *getPrefix() const {return _prefix;}
+
+ const char *_prefix;
+
+ friend HTTPServer;
+ friend HTTPConnection;
+};
+
+/**
+ * For every incomming connection we have a HTTPConnection object which will handle the requests of this connection.
+ */
+class HTTPConnection : public TCPConnection {
+ public:
+ /**
+ * Constructs a new connection object from a server.
+ * It just need the server object to contact the handlers
+ * and the tcp connection pcb.
+ * @param parent The server which created the connection.
+ * @param pcb The pcb object NetServers internal representation of an TCP Connection
+ */
+ HTTPConnection(HTTPServer *parent, struct tcp_pcb *pcb);
+ /**
+ * Default destructor. Simple cleanup.
+ */
+ virtual ~HTTPConnection();
+
+ /**
+ * Get the requested url.
+ * Only set if a request ist received.
+ */
+ char *getURL() const { return _request_url; }
+
+ /**
+ * Gets a string of set fields to send with the answere header.
+ */
+ const char *getHeaderFields() const { return (_request_headerfields)?_request_headerfields:""; }
+
+ /**
+ * Gets the length of the anwere in bytes. This is requiered for the HTTP Header.
+ * It should be set over setLength by an HTTPHandler in the init() method.
+ */
+ const int &getLength() const { return _request_length; }
+
+ /**
+ * Gets POST or GET or 0 depends on wether ther is a request and what type is requested.
+ */
+ const char &getType() const { return _request_type; }
+
+ /**
+ * Gets a value from a header field of the request header.
+ * But you must have registerd this headerfield by the HTTPServer before.
+ * Use the HTTPHandler::reg() method for the registration of important header fields for your Handler.
+ */
+ const char *getField(char *key) const;
+
+ /**
+ * For internal usage. Adds an header field value to its hash.
+ * If it was registered You can see the Value with the getField method
+ */
+ void addField(char *key, char *value);
+
+ /**
+ * Sets the result length for an request shoud be set in an HTTPHandler.init() call.
+ * This Value will be send with the response header before the first chunk of data is send.
+ */
+ void setLength(const int &value) { _request_length = value; }
+
+ /**
+ * Set the response header field to a value.
+ * Should be used in the HTTPHandler::init() method.
+ * For example if you want to set caching methods.
+ */
+ void setHeaderFields(char *value) { _request_headerfields = value; }
+
+ /** Indicates that if a request is received the header is incomplete until now. */
+ bool request_incomplete;
+
+ /** If an request is complete HTTPHandler:init will be called and can store here its connection data. */
+ HTTPData *data;
+
+ /** The handler which handles the current request. Depends on the prefix of the URL. */
+ HTTPHandler *request_handler;
+
+ /** The status of the request. Will be set as result of HTTPHandler::init. */
+ HTTPStatus request_status;
+
+ /** The HTTTPServer which created this connection. */
+ HTTPServer *parent;
+ private:
+ virtual void err(err_t err);
+ virtual err_t poll();
+ virtual err_t sent(u16_t len);
+ virtual err_t recv(struct pbuf *q, err_t err);
+
+ /** We will not make any DNS requests. */
+ virtual void dnsreply(const char *, struct ip_addr *) {}
+
+ /** If a request is finished it will be deleted with this method. Simple cleanup. */
+ void deleteRequest();
+
+ /** Call the handler to send the next chunk of data. */
+ void send();
+
+ /** Call the handler if we received new data. */
+ void store(void *d, struct pbuf *p);
+
+ /**
+ * If a request header is not complete we can colect needed header fields.
+ * This happens in here.
+ */
+ void getFields(struct pbuf **q, char **d);
+
+ char *_request_url;
+ char _request_type;
+ char *_request_headerfields;
+ map<unsigned int, char *> _request_fields;
+ int _request_length;
+ char *_request_arg_key;
+ char *_request_arg_value;
+ char _request_arg_state;
+
+ u8_t emptypolls;
+};
+
+/**
+ * The HTTPServer class.
+ * It representates the top class of an HTTPServer.
+ */
+class HTTPServer : public TCPListener {
+ public:
+ /**
+ * Create a new server instance by default on port 80.
+ */
+ HTTPServer(u16_t = 80);
+ virtual ~HTTPServer() {
+ fields.clear();
+ _handler.clear();
+ }
+
+ /**
+ * Add a new content handler to handle requests.
+ * Content handler are URL prefix specific.
+ * Have a look at HTTPRPC and HTTPFileSystemHandler for examples.
+ */
+ virtual void addHandler(HTTPHandler *handler) {
+ _handler.push_back(handler);
+ handler->reg(this);
+ }
+
+ /**
+ * Register needed header fields to filter from a request header.
+ * Should be called from HTTPHandler::reg()
+ */
+ virtual void registerField(char *name) {
+ fields.insert(hash((unsigned char *)name));
+ }
+
+ /**
+ * A short lookup if the headerfield is registerd.
+ */
+ virtual bool isField(unsigned long h) const {
+ return fields.find(h) != fields.end();
+ }
+
+ /**
+ * You have to call this method at least every 250ms to let the http server run.
+ * But I would recomend to call this function as fast as possible.
+ * This function is directly coupled to the answere time of your HTTPServer instance.
+ */
+ inline static void poll() {
+ NetServer::poll();
+ }
+ private:
+ /**
+ * Pick up the right handler to deliver the response.
+ */
+ virtual HTTPHandler *handle(HTTPConnection *con) const {
+ for(list<HTTPHandler *>::const_iterator iter = _handler.begin();
+ iter != _handler.end(); iter++) {
+ if(strncmp((*iter)->getPrefix(), con->getURL(), strlen((*iter)->getPrefix()))==0) {
+ HTTPHandler *handler = *iter;
+ if(handler->action(con)==HTTP_Deliver) {
+ return *iter;
+ }
+ }
+ }
+ return NULL;
+ }
+
+ /**
+ * Accept an incomming connection and fork a HTTPConnection if we have enought memory.
+ */
+ virtual err_t accept(struct tcp_pcb *pcb, err_t err) {
+ LWIP_UNUSED_ARG(err);
+ HTTPConnection *con = new HTTPConnection(this, pcb);
+// printf("New Connection opend. Now are %u connections open\n", ++gconnections);
+ if(con == NULL) {
+ printf("http_accept: Out of memory\n");
+ return ERR_MEM;
+ }
+ con->set_poll_interval(1);
+ tcp_setprio(pcb, TCP_PRIO_MIN);
+ return ERR_OK;
+ }
+
+ /** The registerd request header fields */
+ set<unsigned int> fields;
+
+ /** A List of all registered handler. */
+ list<HTTPHandler *> _handler;
+ friend HTTPConnection;
+};
+
+};
+
+#endif /* HTTP_H */