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.
Dependencies: WiFlyHTTPServer WiflyInterface mbed-rpc mbed-rtos mbed
HttpServer.h@0:9c6ebc97c758, 2013-06-26 (annotated)
- Committer:
- leihen
- Date:
- Wed Jun 26 21:13:55 2013 +0000
- Revision:
- 0:9c6ebc97c758
Working Multithreaded HTTP Server
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| leihen | 0:9c6ebc97c758 | 1 | #ifndef __HTTPSERVER_H__ |
| leihen | 0:9c6ebc97c758 | 2 | #define __HTTPSERVER_H__ |
| leihen | 0:9c6ebc97c758 | 3 | |
| leihen | 0:9c6ebc97c758 | 4 | #include "Wifly.h" |
| leihen | 0:9c6ebc97c758 | 5 | #include "rtos.h" |
| leihen | 0:9c6ebc97c758 | 6 | #include "HTTPConnection.h" |
| leihen | 0:9c6ebc97c758 | 7 | #include "HTTPRequestHandler.h" |
| leihen | 0:9c6ebc97c758 | 8 | |
| leihen | 0:9c6ebc97c758 | 9 | #include <string> |
| leihen | 0:9c6ebc97c758 | 10 | #include <map> |
| leihen | 0:9c6ebc97c758 | 11 | |
| leihen | 0:9c6ebc97c758 | 12 | typedef enum { |
| leihen | 0:9c6ebc97c758 | 13 | msg_get, |
| leihen | 0:9c6ebc97c758 | 14 | msg_post, |
| leihen | 0:9c6ebc97c758 | 15 | msg_head, |
| leihen | 0:9c6ebc97c758 | 16 | msg_put, |
| leihen | 0:9c6ebc97c758 | 17 | msg_delete, |
| leihen | 0:9c6ebc97c758 | 18 | msg_trace, |
| leihen | 0:9c6ebc97c758 | 19 | msg_options, |
| leihen | 0:9c6ebc97c758 | 20 | msg_connect |
| leihen | 0:9c6ebc97c758 | 21 | } msg_t; |
| leihen | 0:9c6ebc97c758 | 22 | |
| leihen | 0:9c6ebc97c758 | 23 | |
| leihen | 0:9c6ebc97c758 | 24 | typedef struct { |
| leihen | 0:9c6ebc97c758 | 25 | msg_t requestType; |
| leihen | 0:9c6ebc97c758 | 26 | char requestUri[256]; |
| leihen | 0:9c6ebc97c758 | 27 | // map<string, string> messageHeaders; |
| leihen | 0:9c6ebc97c758 | 28 | } request_msg_t; |
| leihen | 0:9c6ebc97c758 | 29 | |
| leihen | 0:9c6ebc97c758 | 30 | /** Typedefinition for a handler function |
| leihen | 0:9c6ebc97c758 | 31 | */ |
| leihen | 0:9c6ebc97c758 | 32 | typedef void (*HTTPRequestHandlerFunction)(HTTPConnection::HTTPMessage&); |
| leihen | 0:9c6ebc97c758 | 33 | |
| leihen | 0:9c6ebc97c758 | 34 | |
| leihen | 0:9c6ebc97c758 | 35 | /** This is the non-blocking HTTP Server class. The idea behind this class is as follows: |
| leihen | 0:9c6ebc97c758 | 36 | * the user may instantiate the class and initialize it. Once the server is setup and |
| leihen | 0:9c6ebc97c758 | 37 | * listening, the server will stay in an endless loop and keep on listening for new |
| leihen | 0:9c6ebc97c758 | 38 | * connections and for new HTTP requests. Once a request is received it will be placed |
| leihen | 0:9c6ebc97c758 | 39 | * in a queue. The queue itself will be handled in a separate task. |
| leihen | 0:9c6ebc97c758 | 40 | */ |
| leihen | 0:9c6ebc97c758 | 41 | class HttpServer : public Wifly |
| leihen | 0:9c6ebc97c758 | 42 | { |
| leihen | 0:9c6ebc97c758 | 43 | Thread *m_listener; |
| leihen | 0:9c6ebc97c758 | 44 | Thread *m_worker; |
| leihen | 0:9c6ebc97c758 | 45 | |
| leihen | 0:9c6ebc97c758 | 46 | request_msg_t* checkMessageReceived(char *); |
| leihen | 0:9c6ebc97c758 | 47 | void processMessageHeader(char* headerLine, char **fieldname, char **fieldvalue); |
| leihen | 0:9c6ebc97c758 | 48 | |
| leihen | 0:9c6ebc97c758 | 49 | public: |
| leihen | 0:9c6ebc97c758 | 50 | HttpServer(PinName tx, PinName rx, PinName reset, PinName tcp_status, const char * ssid, const char * phrase, Security sec, Wifly::WiflyBaudrate_t baud = Wifly::Wifly_115200); |
| leihen | 0:9c6ebc97c758 | 51 | ~HttpServer(); |
| leihen | 0:9c6ebc97c758 | 52 | |
| leihen | 0:9c6ebc97c758 | 53 | bool start(int port); |
| leihen | 0:9c6ebc97c758 | 54 | |
| leihen | 0:9c6ebc97c758 | 55 | virtual void handler_rx(void); |
| leihen | 0:9c6ebc97c758 | 56 | virtual void attach_rx(bool); |
| leihen | 0:9c6ebc97c758 | 57 | |
| leihen | 0:9c6ebc97c758 | 58 | virtual bool join(); |
| leihen | 0:9c6ebc97c758 | 59 | virtual int send(const char * str, int len, const char * ACK = NULL, char * res = NULL, int timeout = DEFAULT_WAIT_RESP_TIMEOUT); |
| leihen | 0:9c6ebc97c758 | 60 | |
| leihen | 0:9c6ebc97c758 | 61 | public: |
| leihen | 0:9c6ebc97c758 | 62 | |
| leihen | 0:9c6ebc97c758 | 63 | |
| leihen | 0:9c6ebc97c758 | 64 | /** |
| leihen | 0:9c6ebc97c758 | 65 | * Structure which will allow to order the stored handlers according to their associated path. |
| leihen | 0:9c6ebc97c758 | 66 | */ |
| leihen | 0:9c6ebc97c758 | 67 | struct handlersComp //Used to order handlers in the right way |
| leihen | 0:9c6ebc97c758 | 68 | { |
| leihen | 0:9c6ebc97c758 | 69 | bool operator() (const string& handler1, const string& handler2) const |
| leihen | 0:9c6ebc97c758 | 70 | { |
| leihen | 0:9c6ebc97c758 | 71 | //The first handler is longer than the second one |
| leihen | 0:9c6ebc97c758 | 72 | if (handler1.length() > handler2.length()) |
| leihen | 0:9c6ebc97c758 | 73 | return true; //Returns true if handler1 is to appear before handler2 |
| leihen | 0:9c6ebc97c758 | 74 | else if (handler1.length() < handler2.length()) |
| leihen | 0:9c6ebc97c758 | 75 | return false; |
| leihen | 0:9c6ebc97c758 | 76 | else //To avoid the == case, sort now by address |
| leihen | 0:9c6ebc97c758 | 77 | return ((&handler1)>(&handler2)); |
| leihen | 0:9c6ebc97c758 | 78 | } |
| leihen | 0:9c6ebc97c758 | 79 | }; |
| leihen | 0:9c6ebc97c758 | 80 | /** The standard error handler function. |
| leihen | 0:9c6ebc97c758 | 81 | * @param msg : Request message data. |
| leihen | 0:9c6ebc97c758 | 82 | * @param tcp : Socket to be used for responding. |
| leihen | 0:9c6ebc97c758 | 83 | */ |
| leihen | 0:9c6ebc97c758 | 84 | static void StdErrorHandler(HTTPConnection::HTTPMessage& msg); |
| leihen | 0:9c6ebc97c758 | 85 | |
| leihen | 0:9c6ebc97c758 | 86 | |
| leihen | 0:9c6ebc97c758 | 87 | /** Internal function which processes a request and which will try to find the matching handler function |
| leihen | 0:9c6ebc97c758 | 88 | * for the given request. Please note that the function will search through the list of handlers, iterating |
| leihen | 0:9c6ebc97c758 | 89 | * from longest to shortest \c paths. If the registered \c path is a subset of the request the associated |
| leihen | 0:9c6ebc97c758 | 90 | * handler is considered as being a match. |
| leihen | 0:9c6ebc97c758 | 91 | * @param msg : Request message data. Contains the requested logical \c uri. |
| leihen | 0:9c6ebc97c758 | 92 | * @param tcp : Socket to be used for communication with the client. |
| leihen | 0:9c6ebc97c758 | 93 | */ |
| leihen | 0:9c6ebc97c758 | 94 | void HandleRequest(HTTPConnection::HTTPMessage* msg); |
| leihen | 0:9c6ebc97c758 | 95 | |
| leihen | 0:9c6ebc97c758 | 96 | /** Map of handler objects. Can be any object derived from \ref HTTPRequestHeader. Use the \ref addHandler function |
| leihen | 0:9c6ebc97c758 | 97 | * to register new handler objects. |
| leihen | 0:9c6ebc97c758 | 98 | */ |
| leihen | 0:9c6ebc97c758 | 99 | static map<string, HTTPRequestHandler* (*)(const char*, const char*, HTTPConnection::HTTPMessage&), handlersComp> m_lpHandlers; |
| leihen | 0:9c6ebc97c758 | 100 | |
| leihen | 0:9c6ebc97c758 | 101 | /** |
| leihen | 0:9c6ebc97c758 | 102 | * Adds a request handler to the handlers list. You will have to use one of the existing implementations. |
| leihen | 0:9c6ebc97c758 | 103 | * With each handler a \c uri or \c path is associated. Whenever a request is received the server will |
| leihen | 0:9c6ebc97c758 | 104 | * walk through all registered handlers and check which \c path is matching. |
| leihen | 0:9c6ebc97c758 | 105 | * @param T : class which will be instanciated to serve these requests for the associated \b path. |
| leihen | 0:9c6ebc97c758 | 106 | * @param path : request uri starting with this \c path will be served using this handler. |
| leihen | 0:9c6ebc97c758 | 107 | */ |
| leihen | 0:9c6ebc97c758 | 108 | template<typename T> |
| leihen | 0:9c6ebc97c758 | 109 | void addHandler(const char* path) |
| leihen | 0:9c6ebc97c758 | 110 | { m_lpHandlers[path] = &T::create; } |
| leihen | 0:9c6ebc97c758 | 111 | |
| leihen | 0:9c6ebc97c758 | 112 | /** |
| leihen | 0:9c6ebc97c758 | 113 | * Replaces the standard error Handler. The error Handler will be called everytime a request is not |
| leihen | 0:9c6ebc97c758 | 114 | * matching any of the registered \c paths or \c uris. |
| leihen | 0:9c6ebc97c758 | 115 | * @param hdlFunc: User specified handler function which will be used in error conditions. |
| leihen | 0:9c6ebc97c758 | 116 | */ |
| leihen | 0:9c6ebc97c758 | 117 | void addErrorHandler(HTTPRequestHandlerFunction hdlFunc) |
| leihen | 0:9c6ebc97c758 | 118 | { m_pErrorHandler = hdlFunc!=NULL ?hdlFunc : StdErrorHandler; } |
| leihen | 0:9c6ebc97c758 | 119 | HTTPRequestHandlerFunction m_pErrorHandler; |
| leihen | 0:9c6ebc97c758 | 120 | |
| leihen | 0:9c6ebc97c758 | 121 | protected: |
| leihen | 0:9c6ebc97c758 | 122 | bool bind(int port); |
| leihen | 0:9c6ebc97c758 | 123 | void listenForRequests(); |
| leihen | 0:9c6ebc97c758 | 124 | void serveRequests(); |
| leihen | 0:9c6ebc97c758 | 125 | |
| leihen | 0:9c6ebc97c758 | 126 | bool parseRequest(char *request); |
| leihen | 0:9c6ebc97c758 | 127 | |
| leihen | 0:9c6ebc97c758 | 128 | static void listen_thread(const void * parms); |
| leihen | 0:9c6ebc97c758 | 129 | static void worker_thread(const void * parms); |
| leihen | 0:9c6ebc97c758 | 130 | }; |
| leihen | 0:9c6ebc97c758 | 131 | |
| leihen | 0:9c6ebc97c758 | 132 | #endif // __HTTPSERVER_H__ |