HTTPServer

Committer:
jphuc96
Date:
Sat Sep 16 02:39:55 2017 +0000
Revision:
0:caf5feddac47
v1

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jphuc96 0:caf5feddac47 1 /* HTTPServer.cpp */
jphuc96 0:caf5feddac47 2 /*
jphuc96 0:caf5feddac47 3 Copyright (c) 2013 Henry Leinen (henry[dot]leinen [at] online [dot] de)
jphuc96 0:caf5feddac47 4
jphuc96 0:caf5feddac47 5 Permission is hereby granted, free of charge, to any person obtaining a copy
jphuc96 0:caf5feddac47 6 of this software and associated documentation files (the "Software"), to deal
jphuc96 0:caf5feddac47 7 in the Software without restriction, including without limitation the rights
jphuc96 0:caf5feddac47 8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
jphuc96 0:caf5feddac47 9 copies of the Software, and to permit persons to whom the Software is
jphuc96 0:caf5feddac47 10 furnished to do so, subject to the following conditions:
jphuc96 0:caf5feddac47 11
jphuc96 0:caf5feddac47 12 The above copyright notice and this permission notice shall be included in
jphuc96 0:caf5feddac47 13 all copies or substantial portions of the Software.
jphuc96 0:caf5feddac47 14
jphuc96 0:caf5feddac47 15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
jphuc96 0:caf5feddac47 16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
jphuc96 0:caf5feddac47 17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
jphuc96 0:caf5feddac47 18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
jphuc96 0:caf5feddac47 19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
jphuc96 0:caf5feddac47 20 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
jphuc96 0:caf5feddac47 21 THE SOFTWARE.
jphuc96 0:caf5feddac47 22 */
jphuc96 0:caf5feddac47 23 #ifndef __HTTPSERVER_H__
jphuc96 0:caf5feddac47 24 #define __HTTPSERVER_H__
jphuc96 0:caf5feddac47 25 #include "mbed.h"
jphuc96 0:caf5feddac47 26 #include "EthernetInterface.h"
jphuc96 0:caf5feddac47 27 #include "HTTPConnection.h"
jphuc96 0:caf5feddac47 28 #include "HTTPRequestHandler.h"
jphuc96 0:caf5feddac47 29 #include "RpcHandler.h"
jphuc96 0:caf5feddac47 30
jphuc96 0:caf5feddac47 31 #include <map>
jphuc96 0:caf5feddac47 32 using std::map;
jphuc96 0:caf5feddac47 33 #include <string>
jphuc96 0:caf5feddac47 34 using std::string;
jphuc96 0:caf5feddac47 35
jphuc96 0:caf5feddac47 36 #include <TCPSocketConnection.h>
jphuc96 0:caf5feddac47 37 #include <TCPSocketServer.h>
jphuc96 0:caf5feddac47 38
jphuc96 0:caf5feddac47 39 /** Typedefinition for a handler function
jphuc96 0:caf5feddac47 40 */
jphuc96 0:caf5feddac47 41 typedef void (*HTTPRequestHandlerFunction)(HTTPConnection::HTTPMessage&, TCPSocketConnection&);
jphuc96 0:caf5feddac47 42
jphuc96 0:caf5feddac47 43
jphuc96 0:caf5feddac47 44 /** Class HTTPServer for use with <a href="http://mbed.org/users/samux/code/WiflyInterface/">WiflyInterface</a>.
jphuc96 0:caf5feddac47 45 * This class is a simple implementation of an HTTP Server for use with the WiFly interface.
jphuc96 0:caf5feddac47 46 * The class will listen for incoming connections on the (configurable) HTTP port. For each
jphuc96 0:caf5feddac47 47 * incoming connection, one request will be processed.
jphuc96 0:caf5feddac47 48 * After instantiating this class, add all required handlers using the \c addHandler function,
jphuc96 0:caf5feddac47 49 * replace the default error handler using \c addErrorHandler if needed and call the \c start
jphuc96 0:caf5feddac47 50 * method to initialize the class.
jphuc96 0:caf5feddac47 51 * You need to continuously poll for any new incoming connections after one request has been
jphuc96 0:caf5feddac47 52 * served using the \c poll member function.
jphuc96 0:caf5feddac47 53 *
jphuc96 0:caf5feddac47 54 * \b Example:
jphuc96 0:caf5feddac47 55 * @code
jphuc96 0:caf5feddac47 56 * #include "mbed.h"
jphuc96 0:caf5feddac47 57 * #include "HTTPServer.h"
jphuc96 0:caf5feddac47 58 * #include "LocalFileSystem.h"
jphuc96 0:caf5feddac47 59 *
jphuc96 0:caf5feddac47 60 * LocalFileSystem local("local");
jphuc96 0:caf5feddac47 61 *
jphuc96 0:caf5feddac47 62 * void main(void)
jphuc96 0:caf5feddac47 63 * {
jphuc96 0:caf5feddac47 64 * HTTPServer svr;
jphuc96 0:caf5feddac47 65 * svr.mount("/local/", "/");
jphuc96 0:caf5feddac47 66 * svr.addHandler<HTTPFsRequestHandler>( "/" );
jphuc96 0:caf5feddac47 67 * svr.start();
jphuc96 0:caf5feddac47 68 * while(1)
jphuc96 0:caf5feddac47 69 * {
jphuc96 0:caf5feddac47 70 * if (svr.poll() < 0)
jphuc96 0:caf5feddac47 71 * exit(0);
jphuc96 0:caf5feddac47 72 * }
jphuc96 0:caf5feddac47 73 * }
jphuc96 0:caf5feddac47 74 * @endcode
jphuc96 0:caf5feddac47 75 *
jphuc96 0:caf5feddac47 76 * An alternate approach e.g. if you need to perform additional tasks using the EthernetInterface
jphuc96 0:caf5feddac47 77 * there is the possibility to provide the EthernetInterface object in an initialized and connected
jphuc96 0:caf5feddac47 78 * state. __NOTE: You should choose this scenario for compatibility reasons.___
jphuc96 0:caf5feddac47 79 *
jphuc96 0:caf5feddac47 80 * \b Example2:
jphuc96 0:caf5feddac47 81 * @code
jphuc96 0:caf5feddac47 82 * #include "mbed.h"
jphuc96 0:caf5feddac47 83 * #include "HTTPServer.h"
jphuc96 0:caf5feddac47 84 * #include "EthernetInterface.h"
jphuc96 0:caf5feddac47 85 * #include "LocalFileSystem.h"
jphuc96 0:caf5feddac47 86 *
jphuc96 0:caf5feddac47 87 * LocalFileSystem local("local");
jphuc96 0:caf5feddac47 88 * EthernetInterface eth;
jphuc96 0:caf5feddac47 89 *
jphuc96 0:caf5feddac47 90 * void main(void)
jphuc96 0:caf5feddac47 91 * {
jphuc96 0:caf5feddac47 92 * HTTPServer svr;
jphuc96 0:caf5feddac47 93 * // Initialize the ethernet interface
jphuc96 0:caf5feddac47 94 * if (eth.init() != 0) {
jphuc96 0:caf5feddac47 95 * printf("Initialization of EthernetInterface failed !");
jphuc96 0:caf5feddac47 96 * exit(0);
jphuc96 0:caf5feddac47 97 * }
jphuc96 0:caf5feddac47 98 * // Connect using DHCP
jphuc96 0:caf5feddac47 99 * if (eth.connect() !=0) {
jphuc96 0:caf5feddac47 100 * printf("Failed to connect using DHCP !");
jphuc96 0:caf5feddac47 101 * exit(0);
jphuc96 0:caf5feddac47 102 * }
jphuc96 0:caf5feddac47 103 *
jphuc96 0:caf5feddac47 104 * // Moint the local file system and provide a handler for 'root'.
jphuc96 0:caf5feddac47 105 * svr.mount("/local/", "/");
jphuc96 0:caf5feddac47 106 * svr.addHandler<HTTPFsRequestHandler>( "/" );
jphuc96 0:caf5feddac47 107 * // Start the server on port 80, providing our own ethernet interface object.
jphuc96 0:caf5feddac47 108 * svr.start(80, &eth);
jphuc96 0:caf5feddac47 109 * while(1)
jphuc96 0:caf5feddac47 110 * {
jphuc96 0:caf5feddac47 111 * if (svr.poll() < 0)
jphuc96 0:caf5feddac47 112 * exit(0);
jphuc96 0:caf5feddac47 113 * }
jphuc96 0:caf5feddac47 114 * }
jphuc96 0:caf5feddac47 115 * @endcode
jphuc96 0:caf5feddac47 116 *
jphuc96 0:caf5feddac47 117 */
jphuc96 0:caf5feddac47 118 class HTTPServer
jphuc96 0:caf5feddac47 119 {
jphuc96 0:caf5feddac47 120 TCPSocketServer m_Svr;
jphuc96 0:caf5feddac47 121 bool m_bServerListening;
jphuc96 0:caf5feddac47 122 EthernetInterface* m_pEthernet;
jphuc96 0:caf5feddac47 123
jphuc96 0:caf5feddac47 124 public:
jphuc96 0:caf5feddac47 125 /** Constructor for HTTPServer objects.
jphuc96 0:caf5feddac47 126 */
jphuc96 0:caf5feddac47 127 HTTPServer();
jphuc96 0:caf5feddac47 128
jphuc96 0:caf5feddac47 129 /** Destructor for HTTPServer objects.
jphuc96 0:caf5feddac47 130 */
jphuc96 0:caf5feddac47 131 ~HTTPServer();
jphuc96 0:caf5feddac47 132
jphuc96 0:caf5feddac47 133 /**
jphuc96 0:caf5feddac47 134 * Structure which will allow to order the stored handlers according to their associated path.
jphuc96 0:caf5feddac47 135 */
jphuc96 0:caf5feddac47 136 struct handlersComp //Used to order handlers in the right way
jphuc96 0:caf5feddac47 137 {
jphuc96 0:caf5feddac47 138 bool operator() (const string& handler1, const string& handler2) const
jphuc96 0:caf5feddac47 139 {
jphuc96 0:caf5feddac47 140 //The first handler is longer than the second one
jphuc96 0:caf5feddac47 141 if (handler1.length() > handler2.length())
jphuc96 0:caf5feddac47 142 return true; //Returns true if handler1 is to appear before handler2
jphuc96 0:caf5feddac47 143 else if (handler1.length() < handler2.length())
jphuc96 0:caf5feddac47 144 return false;
jphuc96 0:caf5feddac47 145 else //To avoid the == case, sort now by address
jphuc96 0:caf5feddac47 146 return ((&handler1)>(&handler2));
jphuc96 0:caf5feddac47 147 }
jphuc96 0:caf5feddac47 148 };
jphuc96 0:caf5feddac47 149
jphuc96 0:caf5feddac47 150 /**
jphuc96 0:caf5feddac47 151 * Adds a request handler to the handlers list. You will have to use one of the existing implementations.
jphuc96 0:caf5feddac47 152 * With each handler a \c uri or \c path is associated. Whenever a request is received the server will
jphuc96 0:caf5feddac47 153 * walk through all registered handlers and check which \c path is matching.
jphuc96 0:caf5feddac47 154 * @param T : class which will be instanciated to serve these requests for the associated \b path.
jphuc96 0:caf5feddac47 155 * @param path : request uri starting with this \c path will be served using this handler.
jphuc96 0:caf5feddac47 156 */
jphuc96 0:caf5feddac47 157 template<typename T>
jphuc96 0:caf5feddac47 158 void addHandler(const char* path)
jphuc96 0:caf5feddac47 159 { m_lpHandlers[path] = &T::create; }
jphuc96 0:caf5feddac47 160
jphuc96 0:caf5feddac47 161 /**
jphuc96 0:caf5feddac47 162 * Replaces the standard error Handler. The error Handler will be called everytime a request is not
jphuc96 0:caf5feddac47 163 * matching any of the registered \c paths or \c uris.
jphuc96 0:caf5feddac47 164 * @param hdlFunc: User specified handler function which will be used in error conditions.
jphuc96 0:caf5feddac47 165 */
jphuc96 0:caf5feddac47 166 void addErrorHandler(HTTPRequestHandlerFunction hdlFunc)
jphuc96 0:caf5feddac47 167 { m_pErrorHandler = hdlFunc!=NULL ?hdlFunc : StdErrorHandler; }
jphuc96 0:caf5feddac47 168
jphuc96 0:caf5feddac47 169 /** Binds server to a specific port and starts listening. This member prepares the internal variables and the server socket
jphuc96 0:caf5feddac47 170 * and terminates after successfull initialization
jphuc96 0:caf5feddac47 171 * @param port : port on which to listen for incoming connections
jphuc96 0:caf5feddac47 172 * @param pEthernet : a pointer to an existing EthernetInterface object or NULL if the HTTPServer shall allocate the object. _Please note that for compatibility reasons
jphuc96 0:caf5feddac47 173 * your should consider to create the EthernetInterface as a static variable. Otherwise the the object will be created on the heap._
jphuc96 0:caf5feddac47 174 * @returns : false if an unrecoverable error occured or if the ethernet interface was not set or not initialized correctly, or true if everything was ok.
jphuc96 0:caf5feddac47 175 */
jphuc96 0:caf5feddac47 176 bool start(int port = 80, EthernetInterface* pEthernet = NULL);
jphuc96 0:caf5feddac47 177
jphuc96 0:caf5feddac47 178 /** Performs the regular polling of the server component. Needs to be called cyclically.
jphuc96 0:caf5feddac47 179 * The function will internally check whether new connections are requested by a client and will also poll all existing client connections.
jphuc96 0:caf5feddac47 180 * @param blocking : if true,
jphuc96 0:caf5feddac47 181 * @returns -1 if there was a problem. If 0 is returned, the latest request was served successfully and the server is
jphuc96 0:caf5feddac47 182 * ready for processing the next request. Simply call \c poll as long as you want to serve new incoming requests.
jphuc96 0:caf5feddac47 183 */
jphuc96 0:caf5feddac47 184 int poll(bool blocking = true);
jphuc96 0:caf5feddac47 185
jphuc96 0:caf5feddac47 186 private:
jphuc96 0:caf5feddac47 187
jphuc96 0:caf5feddac47 188 /** The standard error handler function.
jphuc96 0:caf5feddac47 189 * @param msg : Request message data.
jphuc96 0:caf5feddac47 190 * @param tcp : Socket to be used for responding.
jphuc96 0:caf5feddac47 191 */
jphuc96 0:caf5feddac47 192 static void StdErrorHandler(HTTPConnection::HTTPMessage& msg, TCPSocketConnection& tcp);
jphuc96 0:caf5feddac47 193
jphuc96 0:caf5feddac47 194 /** Internal function which processes a request and which will try to find the matching handler function
jphuc96 0:caf5feddac47 195 * for the given request. Please note that the function will search through the list of handlers, iterating
jphuc96 0:caf5feddac47 196 * from longest to shortest \c paths. If the registered \c path is a subset of the request the associated
jphuc96 0:caf5feddac47 197 * handler is considered as being a match.
jphuc96 0:caf5feddac47 198 * @param msg : Request message data. Contains the requested logical \c uri.
jphuc96 0:caf5feddac47 199 * @param tcp : Socket to be used for communication with the client.
jphuc96 0:caf5feddac47 200 */
jphuc96 0:caf5feddac47 201 void HandleRequest(HTTPConnection::HTTPMessage& msg, TCPSocketConnection& tcp);
jphuc96 0:caf5feddac47 202
jphuc96 0:caf5feddac47 203 /** Map of handler objects. Can be any object derived from \ref HTTPRequestHeader. Use the \ref addHandler function
jphuc96 0:caf5feddac47 204 * to register new handler objects.
jphuc96 0:caf5feddac47 205 */
jphuc96 0:caf5feddac47 206 map<string, HTTPRequestHandler* (*)(const char*, const char*, HTTPConnection::HTTPMessage&, TCPSocketConnection&), handlersComp> m_lpHandlers;
jphuc96 0:caf5feddac47 207 HTTPRequestHandlerFunction m_pErrorHandler;
jphuc96 0:caf5feddac47 208
jphuc96 0:caf5feddac47 209 };
jphuc96 0:caf5feddac47 210
jphuc96 0:caf5feddac47 211 #endif //__HTTPSERVER_H__
jphuc96 0:caf5feddac47 212