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:
cabledev
Date:
Thu May 15 16:09:51 2014 +0000
Revision:
17:d7186c696729
Parent:
16:cc3f5c53d0d5
- converted to blocking mode & removed polling; greatly improving stability, but HTTP server must be started from a separate thread (not the main app thread); - moved ethernet interface and port assignment out of start() method; - updated log messages

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