Single instance HTTP Server using new Ethernet Interface. Blocking mode only; this improved stability, but the HTTP server must be started from a separate thread.

Dependents:   SmartLight

Fork of HTTPServer by Henry Leinen

Committer:
leihen
Date:
Sat Aug 17 12:12:13 2013 +0000
Revision:
14:011edcd33e86
Parent:
13:aa5338a5e452
Child:
16:cc3f5c53d0d5
Changed behaviour, so that now an EthernetInterface can be provided by user of the library as an alternative to having the HTTPServer being the owner.
; Example documentation Extended.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
leihen 0:7a2421e63e74 1 #include "mbed.h"
leihen 0:7a2421e63e74 2 #include "HTTPServer.h"
leihen 13:aa5338a5e452 3 #define DEBUG
leihen 13:aa5338a5e452 4 #include "debug.h"
leihen 0:7a2421e63e74 5
leihen 13:aa5338a5e452 6 #define _DEBUG 1
leihen 4:d065642c32cc 7
leihen 4:d065642c32cc 8 #ifdef _DEBUG
leihen 0:7a2421e63e74 9 DigitalOut led1(LED1);
leihen 0:7a2421e63e74 10 DigitalOut led2(LED2);
leihen 0:7a2421e63e74 11 DigitalOut led3(LED3);
leihen 0:7a2421e63e74 12 DigitalOut led4(LED4);
leihen 4:d065642c32cc 13 #endif
leihen 0:7a2421e63e74 14
leihen 4:d065642c32cc 15
leihen 4:d065642c32cc 16 /* Constructor */
leihen 4:d065642c32cc 17 /* initialize all members and set the standard error handler. */
leihen 13:aa5338a5e452 18 HTTPServer::HTTPServer()
leihen 14:011edcd33e86 19 : m_pEthernet(NULL)
leihen 0:7a2421e63e74 20 {
leihen 9:c2a1462b9b71 21 m_pErrorHandler = StdErrorHandler;
leihen 0:7a2421e63e74 22 }
leihen 0:7a2421e63e74 23
leihen 0:7a2421e63e74 24 HTTPServer::~HTTPServer()
leihen 0:7a2421e63e74 25 {
leihen 14:011edcd33e86 26 if (m_pEthernet == NULL) {
leihen 14:011edcd33e86 27 INFO("Deleting EthernetInterface Object.\n");
leihen 14:011edcd33e86 28 delete m_pEthernet;
leihen 14:011edcd33e86 29 }
leihen 0:7a2421e63e74 30 }
leihen 0:7a2421e63e74 31
leihen 4:d065642c32cc 32 static const char* szStdErrorPage = "<HTML><HEAD><META content=\"text/html\" http-equiv=Content-Type></HEAD><BODY><h1>Error 404</h1><P>This resource is not available<P></BODY></HTML>\r\n\r\n";
leihen 2:8653bbcf7e58 33
leihen 3:d6224049b3bf 34 void HTTPServer::StdErrorHandler(HTTPConnection::HTTPMessage& msg, TCPSocketConnection& tcp)
leihen 2:8653bbcf7e58 35 {
leihen 4:d065642c32cc 36 char echoHeader[256];
leihen 2:8653bbcf7e58 37 tcp.set_blocking(true, 1500);
leihen 11:3943841e1798 38 sprintf(echoHeader,"HTTP/1.0 404 Fail\r\nConnection: close\r\nContent-Length: %d\r\nContent-Type: text/html\r\nServer: mbed embedded\r\n\n\r",strlen(szStdErrorPage));
leihen 2:8653bbcf7e58 39 tcp.send(echoHeader, strlen(echoHeader));
leihen 2:8653bbcf7e58 40 tcp.send((char*)szStdErrorPage, strlen(szStdErrorPage));
leihen 2:8653bbcf7e58 41 }
leihen 2:8653bbcf7e58 42
leihen 2:8653bbcf7e58 43
leihen 14:011edcd33e86 44 bool HTTPServer::start(int port, EthernetInterface* pEthernet)
leihen 0:7a2421e63e74 45 {
leihen 14:011edcd33e86 46 // If no ethernet interface is provided, instantiate own on the heap. This has to be deleted later in the destructor.
leihen 14:011edcd33e86 47 // If a valid pointer to an thernet interface is proveded, we can simply use it.
leihen 14:011edcd33e86 48 if (pEthernet == NULL) {
leihen 14:011edcd33e86 49 INFO("Creating EthernetInterface object\n");
leihen 14:011edcd33e86 50 m_pEthernet = new EthernetInterface();
leihen 14:011edcd33e86 51
leihen 14:011edcd33e86 52 if (m_pEthernet == NULL) {
leihen 14:011edcd33e86 53 ERR("Out of memory, unable to instantiate an EthernetInterface object.");
leihen 14:011edcd33e86 54 return false;
leihen 14:011edcd33e86 55 }
leihen 9:c2a1462b9b71 56
leihen 14:011edcd33e86 57 // Initiaize the network
leihen 14:011edcd33e86 58 INFO("Initializing network\n");
leihen 14:011edcd33e86 59 if (m_pEthernet->init() != 0) {
leihen 14:011edcd33e86 60 ERR("Failed to initialize the ethernet interface !");
leihen 14:011edcd33e86 61 delete m_pEthernet;
leihen 14:011edcd33e86 62 m_pEthernet = NULL;
leihen 14:011edcd33e86 63 return false;
leihen 14:011edcd33e86 64 }
leihen 14:011edcd33e86 65
leihen 14:011edcd33e86 66 // Connect to the network using DHCP
leihen 14:011edcd33e86 67 INFO("Connecting to the network using DHCP...");
leihen 14:011edcd33e86 68 if (m_pEthernet->connect() != 0) {
leihen 14:011edcd33e86 69 ERR("Failed to connect to the ethernet !");
leihen 14:011edcd33e86 70 delete m_pEthernet;
leihen 14:011edcd33e86 71 m_pEthernet = NULL;
leihen 14:011edcd33e86 72 return false;
leihen 14:011edcd33e86 73 }
leihen 14:011edcd33e86 74
leihen 14:011edcd33e86 75 INFO("Connected IP %s", m_pEthernet->getIPAddress());
leihen 14:011edcd33e86 76
leihen 14:011edcd33e86 77 } else {
leihen 14:011edcd33e86 78 // In the case that the ethernet interface is provided, it is assumed that a connection has already been created.
leihen 14:011edcd33e86 79 INFO("Using connection IP %s", pEthernet->getIPAddress());
leihen 14:011edcd33e86 80 }
leihen 14:011edcd33e86 81
leihen 13:aa5338a5e452 82 INFO("Binding to port %d...", port);
leihen 13:aa5338a5e452 83 if (m_Svr.bind(port) < 0) {
leihen 13:aa5338a5e452 84 ERR("Failed to bind to port !\n");
leihen 13:aa5338a5e452 85 error("Binding");
leihen 13:aa5338a5e452 86 return false;
leihen 0:7a2421e63e74 87 }
leihen 0:7a2421e63e74 88
leihen 13:aa5338a5e452 89 INFO("Listening ...");
leihen 13:aa5338a5e452 90 if (m_Svr.listen(1) < 0) {
leihen 13:aa5338a5e452 91 ERR("Failed to listen !\n");
leihen 13:aa5338a5e452 92 error("Listening");
leihen 13:aa5338a5e452 93 return false;
leihen 0:7a2421e63e74 94 }
leihen 0:7a2421e63e74 95
leihen 13:aa5338a5e452 96 ERR("Connected !");
leihen 0:7a2421e63e74 97 // set into non blocking operation
leihen 13:aa5338a5e452 98 m_Svr.set_blocking(false, 100);
leihen 13:aa5338a5e452 99
leihen 13:aa5338a5e452 100 return true;
leihen 0:7a2421e63e74 101 }
leihen 0:7a2421e63e74 102
leihen 0:7a2421e63e74 103
leihen 6:fe661fa9d18a 104 int HTTPServer::poll(bool blocking)
leihen 13:aa5338a5e452 105 {
leihen 13:aa5338a5e452 106 #ifdef _DEBUG
leihen 13:aa5338a5e452 107 led4 = 1; // Indicate we are waiting for a new connection
leihen 13:aa5338a5e452 108 #endif
leihen 0:7a2421e63e74 109 // This thread basically checks if there is a new incoming connection.
leihen 0:7a2421e63e74 110 // If so , a new HTTPConnection is created and the connection thread is started.
leihen 0:7a2421e63e74 111 TCPSocketConnection Clnt;
leihen 13:aa5338a5e452 112 if (m_Svr.accept(Clnt) < 0) {
leihen 4:d065642c32cc 113 #ifdef _DEBUG
leihen 0:7a2421e63e74 114 led4 = 0;
leihen 0:7a2421e63e74 115 led3 = 1; // ERROR
leihen 0:7a2421e63e74 116 led2 = 0;
leihen 0:7a2421e63e74 117 led1 = 0;
leihen 4:d065642c32cc 118 #endif
leihen 0:7a2421e63e74 119 return -1;
leihen 0:7a2421e63e74 120 }
leihen 13:aa5338a5e452 121
leihen 13:aa5338a5e452 122 // a new connection was received
leihen 13:aa5338a5e452 123 INFO("Client (IP=%s) is connected !\n", Clnt.get_address());
leihen 13:aa5338a5e452 124 #ifdef _DEBUG
leihen 13:aa5338a5e452 125 led4 = 0;
leihen 13:aa5338a5e452 126 led3 = 0;
leihen 13:aa5338a5e452 127 led2 = 0;
leihen 13:aa5338a5e452 128 #endif
leihen 13:aa5338a5e452 129
leihen 4:d065642c32cc 130 #ifdef _DEBUG
leihen 13:aa5338a5e452 131 led3 = 1;
leihen 13:aa5338a5e452 132 led2 = 1;
leihen 13:aa5338a5e452 133 #endif
leihen 13:aa5338a5e452 134 HTTPConnection con(Clnt);
leihen 13:aa5338a5e452 135 int c = con.poll();
leihen 13:aa5338a5e452 136 if (c == 0) {
leihen 13:aa5338a5e452 137 // Handle the request
leihen 13:aa5338a5e452 138 INFO("Handling request !");
leihen 13:aa5338a5e452 139 HandleRequest(con.m_Msg, Clnt);
leihen 0:7a2421e63e74 140 }
leihen 13:aa5338a5e452 141 if (c == -1) {
leihen 13:aa5338a5e452 142 // break;
leihen 13:aa5338a5e452 143 }
leihen 13:aa5338a5e452 144 #ifdef _DEBUG
leihen 13:aa5338a5e452 145 led2 = 0;
leihen 13:aa5338a5e452 146 led3 = 0;
leihen 13:aa5338a5e452 147 #endif
leihen 13:aa5338a5e452 148
leihen 13:aa5338a5e452 149
leihen 0:7a2421e63e74 150 INFO("Leaving polling thread");
leihen 0:7a2421e63e74 151 return 0;
leihen 1:6b7472d5e9ee 152 }
leihen 1:6b7472d5e9ee 153
leihen 3:d6224049b3bf 154 void HTTPServer::HandleRequest(HTTPConnection::HTTPMessage& msg, TCPSocketConnection& tcp)
leihen 3:d6224049b3bf 155 {
leihen 3:d6224049b3bf 156 std::string localPath;
leihen 3:d6224049b3bf 157 std::map<std::string, HTTPRequestHandler*(*)(const char*, const char*, HTTPConnection::HTTPMessage&, TCPSocketConnection&), handlersComp>::const_iterator it;
leihen 3:d6224049b3bf 158
leihen 4:d065642c32cc 159 // Iterate through registered handlers and check if the handler's path is a subset of the requested uri.
leihen 3:d6224049b3bf 160 for (it = m_lpHandlers.begin() ; it != m_lpHandlers.end() ; it++) {
leihen 3:d6224049b3bf 161 // check if this entries' path is fully contained at the beginning of the requested path
leihen 3:d6224049b3bf 162 std::string curpth = it->first;
leihen 3:d6224049b3bf 163
leihen 3:d6224049b3bf 164 if (msg.uri.find(curpth) == 0) {
leihen 4:d065642c32cc 165 // firts matching handler found, we just take it and we'll be happy
leihen 3:d6224049b3bf 166 localPath = msg.uri.substr(curpth.length());
leihen 3:d6224049b3bf 167 break;
leihen 3:d6224049b3bf 168 }
leihen 3:d6224049b3bf 169 }
leihen 13:aa5338a5e452 170
leihen 3:d6224049b3bf 171 if (it == m_lpHandlers.end()) {
leihen 3:d6224049b3bf 172 // There is no such handler, so return invalid
leihen 3:d6224049b3bf 173
leihen 13:aa5338a5e452 174 m_pErrorHandler(msg, tcp);
leihen 3:d6224049b3bf 175 INFO("Webrequest left unhandled.");
leihen 13:aa5338a5e452 176 } else {
leihen 4:d065642c32cc 177 // Valid handler was found
leihen 3:d6224049b3bf 178 INFO("Routing webrequest !");
leihen 4:d065642c32cc 179 // Instantiate the handler object (handling will be done from withing the object's constructor
leihen 3:d6224049b3bf 180 HTTPRequestHandler *phdl = (*it->second)(it->first.c_str(), localPath.c_str(), msg, tcp);
leihen 4:d065642c32cc 181 // now we can delete the object, because handling is completed.
leihen 3:d6224049b3bf 182 if (phdl != NULL)
leihen 3:d6224049b3bf 183 delete phdl;
leihen 3:d6224049b3bf 184 }
leihen 3:d6224049b3bf 185 }