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.cpp@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 | #include "mbed.h" |
| leihen | 0:9c6ebc97c758 | 2 | #include "HttpServer.h" |
| leihen | 0:9c6ebc97c758 | 3 | |
| leihen | 0:9c6ebc97c758 | 4 | #define DEBUG |
| leihen | 0:9c6ebc97c758 | 5 | #include "debug.h" |
| leihen | 0:9c6ebc97c758 | 6 | |
| leihen | 0:9c6ebc97c758 | 7 | |
| leihen | 0:9c6ebc97c758 | 8 | #define EVENT_DATA_READY 0x05 |
| leihen | 0:9c6ebc97c758 | 9 | |
| leihen | 0:9c6ebc97c758 | 10 | DigitalOut ledRX(LED4); |
| leihen | 0:9c6ebc97c758 | 11 | |
| leihen | 0:9c6ebc97c758 | 12 | |
| leihen | 0:9c6ebc97c758 | 13 | typedef struct { |
| leihen | 0:9c6ebc97c758 | 14 | char c; |
| leihen | 0:9c6ebc97c758 | 15 | } message_t; |
| leihen | 0:9c6ebc97c758 | 16 | |
| leihen | 0:9c6ebc97c758 | 17 | Queue<char, 256> m_queue; |
| leihen | 0:9c6ebc97c758 | 18 | |
| leihen | 0:9c6ebc97c758 | 19 | typedef struct { |
| leihen | 0:9c6ebc97c758 | 20 | const char* method; |
| leihen | 0:9c6ebc97c758 | 21 | msg_t type; |
| leihen | 0:9c6ebc97c758 | 22 | } methodType_t; |
| leihen | 0:9c6ebc97c758 | 23 | |
| leihen | 0:9c6ebc97c758 | 24 | const methodType_t supportedOps[] = { |
| leihen | 0:9c6ebc97c758 | 25 | { "GET", msg_get }, |
| leihen | 0:9c6ebc97c758 | 26 | { "POST", msg_post }, |
| leihen | 0:9c6ebc97c758 | 27 | { "PUT", msg_put }, |
| leihen | 0:9c6ebc97c758 | 28 | { "HEAD", msg_head}, |
| leihen | 0:9c6ebc97c758 | 29 | { "CONNECT", msg_connect}, |
| leihen | 0:9c6ebc97c758 | 30 | { "DELETE", msg_delete}, |
| leihen | 0:9c6ebc97c758 | 31 | { "TRACE", msg_trace}, |
| leihen | 0:9c6ebc97c758 | 32 | { "OPTIONS", msg_options} |
| leihen | 0:9c6ebc97c758 | 33 | }; |
| leihen | 0:9c6ebc97c758 | 34 | |
| leihen | 0:9c6ebc97c758 | 35 | |
| leihen | 0:9c6ebc97c758 | 36 | Queue<request_msg_t, 5> m_requestQueue; // Do not allow more than 5 concurrent requests |
| leihen | 0:9c6ebc97c758 | 37 | MemoryPool<request_msg_t, 5> m_requestPool; |
| leihen | 0:9c6ebc97c758 | 38 | |
| leihen | 0:9c6ebc97c758 | 39 | map<string, string> messageHeaders; |
| leihen | 0:9c6ebc97c758 | 40 | |
| leihen | 0:9c6ebc97c758 | 41 | map<string, HTTPRequestHandler* (*)(const char*, const char*, HTTPConnection::HTTPMessage&), HttpServer::handlersComp> HttpServer::m_lpHandlers; |
| leihen | 0:9c6ebc97c758 | 42 | |
| leihen | 0:9c6ebc97c758 | 43 | |
| leihen | 0:9c6ebc97c758 | 44 | |
| leihen | 0:9c6ebc97c758 | 45 | /* Constructor will create and initialize all objects excep the threads */ |
| leihen | 0:9c6ebc97c758 | 46 | HttpServer::HttpServer(PinName tx, PinName rx, PinName rst, PinName tcp_status, const char * ssid, const char * phrase, Security sec, Wifly::WiflyBaudrate_t baud) |
| leihen | 0:9c6ebc97c758 | 47 | : Wifly(tx, rx, rst, tcp_status, ssid, phrase, sec, baud), m_listener(NULL), m_worker(NULL) |
| leihen | 0:9c6ebc97c758 | 48 | { |
| leihen | 0:9c6ebc97c758 | 49 | INFO("Initializing wifly\n"); |
| leihen | 0:9c6ebc97c758 | 50 | // Initialize the wifly wlan device |
| leihen | 0:9c6ebc97c758 | 51 | reset(); |
| leihen | 0:9c6ebc97c758 | 52 | |
| leihen | 0:9c6ebc97c758 | 53 | state.dhcp = true; |
| leihen | 0:9c6ebc97c758 | 54 | INFO("Connecting to network..."); |
| leihen | 0:9c6ebc97c758 | 55 | // Try join the network |
| leihen | 0:9c6ebc97c758 | 56 | while(!join()) { |
| leihen | 0:9c6ebc97c758 | 57 | INFO("Failed to connect. Trying again\n"); |
| leihen | 0:9c6ebc97c758 | 58 | reset(); |
| leihen | 0:9c6ebc97c758 | 59 | } |
| leihen | 0:9c6ebc97c758 | 60 | INFO("connected\n"); |
| leihen | 0:9c6ebc97c758 | 61 | } |
| leihen | 0:9c6ebc97c758 | 62 | |
| leihen | 0:9c6ebc97c758 | 63 | HttpServer::~HttpServer() |
| leihen | 0:9c6ebc97c758 | 64 | { |
| leihen | 0:9c6ebc97c758 | 65 | if (m_listener) { |
| leihen | 0:9c6ebc97c758 | 66 | m_listener->terminate(); |
| leihen | 0:9c6ebc97c758 | 67 | delete m_listener; |
| leihen | 0:9c6ebc97c758 | 68 | } |
| leihen | 0:9c6ebc97c758 | 69 | if (m_worker) { |
| leihen | 0:9c6ebc97c758 | 70 | m_worker->terminate(); |
| leihen | 0:9c6ebc97c758 | 71 | delete m_worker; |
| leihen | 0:9c6ebc97c758 | 72 | } |
| leihen | 0:9c6ebc97c758 | 73 | } |
| leihen | 0:9c6ebc97c758 | 74 | |
| leihen | 0:9c6ebc97c758 | 75 | |
| leihen | 0:9c6ebc97c758 | 76 | bool HttpServer::start(int port) |
| leihen | 0:9c6ebc97c758 | 77 | { |
| leihen | 0:9c6ebc97c758 | 78 | // Bind to that port |
| leihen | 0:9c6ebc97c758 | 79 | if (!bind(port)) { |
| leihen | 0:9c6ebc97c758 | 80 | ERR("Failed to bind to port %d\n", port); |
| leihen | 0:9c6ebc97c758 | 81 | return false; |
| leihen | 0:9c6ebc97c758 | 82 | } |
| leihen | 0:9c6ebc97c758 | 83 | |
| leihen | 0:9c6ebc97c758 | 84 | // Start the child threads |
| leihen | 0:9c6ebc97c758 | 85 | m_worker = new Thread(HttpServer::worker_thread, NULL, osPriorityAboveNormal, DEFAULT_STACK_SIZE*4); |
| leihen | 0:9c6ebc97c758 | 86 | if (m_worker == NULL) { |
| leihen | 0:9c6ebc97c758 | 87 | ERR("Failed to start server thread !\n"); |
| leihen | 0:9c6ebc97c758 | 88 | return false; |
| leihen | 0:9c6ebc97c758 | 89 | } |
| leihen | 0:9c6ebc97c758 | 90 | |
| leihen | 0:9c6ebc97c758 | 91 | m_listener = new Thread(&HttpServer::listen_thread, NULL, osPriorityAboveNormal, DEFAULT_STACK_SIZE*2); |
| leihen | 0:9c6ebc97c758 | 92 | if (m_listener == NULL) { |
| leihen | 0:9c6ebc97c758 | 93 | ERR("Failed to start listener thread !\n"); |
| leihen | 0:9c6ebc97c758 | 94 | m_worker->terminate(); |
| leihen | 0:9c6ebc97c758 | 95 | delete m_worker; |
| leihen | 0:9c6ebc97c758 | 96 | m_worker = NULL; |
| leihen | 0:9c6ebc97c758 | 97 | return false; |
| leihen | 0:9c6ebc97c758 | 98 | } |
| leihen | 0:9c6ebc97c758 | 99 | |
| leihen | 0:9c6ebc97c758 | 100 | return true; |
| leihen | 0:9c6ebc97c758 | 101 | } |
| leihen | 0:9c6ebc97c758 | 102 | |
| leihen | 0:9c6ebc97c758 | 103 | |
| leihen | 0:9c6ebc97c758 | 104 | |
| leihen | 0:9c6ebc97c758 | 105 | |
| leihen | 0:9c6ebc97c758 | 106 | |
| leihen | 0:9c6ebc97c758 | 107 | bool HttpServer::bind(int port) |
| leihen | 0:9c6ebc97c758 | 108 | { |
| leihen | 0:9c6ebc97c758 | 109 | char cmd[20]; |
| leihen | 0:9c6ebc97c758 | 110 | |
| leihen | 0:9c6ebc97c758 | 111 | // set TCP protocol |
| leihen | 0:9c6ebc97c758 | 112 | setProtocol(TCP); |
| leihen | 0:9c6ebc97c758 | 113 | |
| leihen | 0:9c6ebc97c758 | 114 | // set local port |
| leihen | 0:9c6ebc97c758 | 115 | sprintf(cmd, "set i l %d\r", port); |
| leihen | 0:9c6ebc97c758 | 116 | if (!sendCommand(cmd, "AOK")) |
| leihen | 0:9c6ebc97c758 | 117 | return false; |
| leihen | 0:9c6ebc97c758 | 118 | |
| leihen | 0:9c6ebc97c758 | 119 | // save |
| leihen | 0:9c6ebc97c758 | 120 | if (!sendCommand("save\r", "Stor")) |
| leihen | 0:9c6ebc97c758 | 121 | return false; |
| leihen | 0:9c6ebc97c758 | 122 | |
| leihen | 0:9c6ebc97c758 | 123 | // reboot |
| leihen | 0:9c6ebc97c758 | 124 | reboot(); |
| leihen | 0:9c6ebc97c758 | 125 | |
| leihen | 0:9c6ebc97c758 | 126 | // connect the network |
| leihen | 0:9c6ebc97c758 | 127 | if (isDHCP()) { |
| leihen | 0:9c6ebc97c758 | 128 | if (!sendCommand("join\r", "DHCP=ON", NULL, 10000)) |
| leihen | 0:9c6ebc97c758 | 129 | return false; |
| leihen | 0:9c6ebc97c758 | 130 | } else { |
| leihen | 0:9c6ebc97c758 | 131 | if (!sendCommand("join\r", "Associated", NULL, 10000)) |
| leihen | 0:9c6ebc97c758 | 132 | return false; |
| leihen | 0:9c6ebc97c758 | 133 | } |
| leihen | 0:9c6ebc97c758 | 134 | |
| leihen | 0:9c6ebc97c758 | 135 | // exit |
| leihen | 0:9c6ebc97c758 | 136 | exit(); |
| leihen | 0:9c6ebc97c758 | 137 | |
| leihen | 0:9c6ebc97c758 | 138 | Thread::wait(200); |
| leihen | 0:9c6ebc97c758 | 139 | flush(); |
| leihen | 0:9c6ebc97c758 | 140 | |
| leihen | 0:9c6ebc97c758 | 141 | return true; |
| leihen | 0:9c6ebc97c758 | 142 | } |
| leihen | 0:9c6ebc97c758 | 143 | |
| leihen | 0:9c6ebc97c758 | 144 | DigitalOut Led2(LED2); |
| leihen | 0:9c6ebc97c758 | 145 | |
| leihen | 0:9c6ebc97c758 | 146 | void HttpServer::handler_rx(void) |
| leihen | 0:9c6ebc97c758 | 147 | { |
| leihen | 0:9c6ebc97c758 | 148 | static char sequence = 0; |
| leihen | 0:9c6ebc97c758 | 149 | //read characters |
| leihen | 0:9c6ebc97c758 | 150 | while (wifi.readable()) { |
| leihen | 0:9c6ebc97c758 | 151 | char c = LPC_UART3->RBR; |
| leihen | 0:9c6ebc97c758 | 152 | ledRX = !ledRX; |
| leihen | 0:9c6ebc97c758 | 153 | switch(sequence) { |
| leihen | 0:9c6ebc97c758 | 154 | case 0 : if (c == 'G') sequence = 1; break; |
| leihen | 0:9c6ebc97c758 | 155 | case 1 : if (c == 'E') sequence = 2; break; |
| leihen | 0:9c6ebc97c758 | 156 | case 2 : if (c == 'T') sequence = 0; Led2 = !Led2;break; |
| leihen | 0:9c6ebc97c758 | 157 | default: break; |
| leihen | 0:9c6ebc97c758 | 158 | } |
| leihen | 0:9c6ebc97c758 | 159 | m_queue.put((char*)(int)c); |
| leihen | 0:9c6ebc97c758 | 160 | } |
| leihen | 0:9c6ebc97c758 | 161 | } |
| leihen | 0:9c6ebc97c758 | 162 | |
| leihen | 0:9c6ebc97c758 | 163 | |
| leihen | 0:9c6ebc97c758 | 164 | void HttpServer::attach_rx(bool callback) |
| leihen | 0:9c6ebc97c758 | 165 | { |
| leihen | 0:9c6ebc97c758 | 166 | if (!callback) |
| leihen | 0:9c6ebc97c758 | 167 | wifi.attach(NULL); |
| leihen | 0:9c6ebc97c758 | 168 | else |
| leihen | 0:9c6ebc97c758 | 169 | wifi.attach(this, &HttpServer::handler_rx); |
| leihen | 0:9c6ebc97c758 | 170 | } |
| leihen | 0:9c6ebc97c758 | 171 | |
| leihen | 0:9c6ebc97c758 | 172 | |
| leihen | 0:9c6ebc97c758 | 173 | bool HttpServer::join() |
| leihen | 0:9c6ebc97c758 | 174 | { |
| leihen | 0:9c6ebc97c758 | 175 | return Wifly::join(); |
| leihen | 0:9c6ebc97c758 | 176 | } |
| leihen | 0:9c6ebc97c758 | 177 | |
| leihen | 0:9c6ebc97c758 | 178 | int HttpServer::send(const char * str, int len, const char * ACK, char * res, int timeout) |
| leihen | 0:9c6ebc97c758 | 179 | { |
| leihen | 0:9c6ebc97c758 | 180 | return Wifly::send(str, len, ACK, res, timeout); |
| leihen | 0:9c6ebc97c758 | 181 | } |
| leihen | 0:9c6ebc97c758 | 182 | |
| leihen | 0:9c6ebc97c758 | 183 | request_msg_t* HttpServer::checkMessageReceived(char *data) |
| leihen | 0:9c6ebc97c758 | 184 | { |
| leihen | 0:9c6ebc97c758 | 185 | INFO("Checking for new HTTP request !\n"); |
| leihen | 0:9c6ebc97c758 | 186 | char *req = data; |
| leihen | 0:9c6ebc97c758 | 187 | char *uri = NULL; |
| leihen | 0:9c6ebc97c758 | 188 | char *ver = NULL; |
| leihen | 0:9c6ebc97c758 | 189 | while( *data ) { |
| leihen | 0:9c6ebc97c758 | 190 | if (*data == ' ') { |
| leihen | 0:9c6ebc97c758 | 191 | *data = 0; |
| leihen | 0:9c6ebc97c758 | 192 | if (uri == NULL) { |
| leihen | 0:9c6ebc97c758 | 193 | uri = data+1; |
| leihen | 0:9c6ebc97c758 | 194 | } else { |
| leihen | 0:9c6ebc97c758 | 195 | ver = data+1; |
| leihen | 0:9c6ebc97c758 | 196 | break; |
| leihen | 0:9c6ebc97c758 | 197 | } |
| leihen | 0:9c6ebc97c758 | 198 | } |
| leihen | 0:9c6ebc97c758 | 199 | data++; |
| leihen | 0:9c6ebc97c758 | 200 | } |
| leihen | 0:9c6ebc97c758 | 201 | |
| leihen | 0:9c6ebc97c758 | 202 | INFO("Detected : %s, %s, %s\n", req, uri, ver); |
| leihen | 0:9c6ebc97c758 | 203 | |
| leihen | 0:9c6ebc97c758 | 204 | if ((req != NULL) && (uri != NULL) && (ver != NULL) ) { |
| leihen | 0:9c6ebc97c758 | 205 | for (int i = 0 ; i < sizeof(supportedOps) / sizeof(methodType_t) ; i++) { |
| leihen | 0:9c6ebc97c758 | 206 | if (strcmp(supportedOps[i].method, req) == 0) { |
| leihen | 0:9c6ebc97c758 | 207 | // found the request |
| leihen | 0:9c6ebc97c758 | 208 | INFO("Request valid !!!\n"); |
| leihen | 0:9c6ebc97c758 | 209 | request_msg_t* pmsg = m_requestPool.alloc(); |
| leihen | 0:9c6ebc97c758 | 210 | pmsg->requestType = supportedOps[i].type; |
| leihen | 0:9c6ebc97c758 | 211 | strncpy(pmsg->requestUri, uri, 255); |
| leihen | 0:9c6ebc97c758 | 212 | return pmsg; |
| leihen | 0:9c6ebc97c758 | 213 | } |
| leihen | 0:9c6ebc97c758 | 214 | } |
| leihen | 0:9c6ebc97c758 | 215 | } |
| leihen | 0:9c6ebc97c758 | 216 | |
| leihen | 0:9c6ebc97c758 | 217 | INFO("Invalid request \"%s\"\n", req); |
| leihen | 0:9c6ebc97c758 | 218 | return NULL; |
| leihen | 0:9c6ebc97c758 | 219 | } |
| leihen | 0:9c6ebc97c758 | 220 | |
| leihen | 0:9c6ebc97c758 | 221 | void HttpServer::processMessageHeader(char* headerLine, char **fieldname, char **fieldvalue) |
| leihen | 0:9c6ebc97c758 | 222 | { |
| leihen | 0:9c6ebc97c758 | 223 | *fieldname = headerLine; |
| leihen | 0:9c6ebc97c758 | 224 | *fieldvalue = NULL; |
| leihen | 0:9c6ebc97c758 | 225 | |
| leihen | 0:9c6ebc97c758 | 226 | while( *headerLine ) { |
| leihen | 0:9c6ebc97c758 | 227 | if (*headerLine == ':') { |
| leihen | 0:9c6ebc97c758 | 228 | *headerLine++ = 0; |
| leihen | 0:9c6ebc97c758 | 229 | while(*headerLine == ' ') headerLine++; |
| leihen | 0:9c6ebc97c758 | 230 | *fieldvalue = headerLine; |
| leihen | 0:9c6ebc97c758 | 231 | return; |
| leihen | 0:9c6ebc97c758 | 232 | } |
| leihen | 0:9c6ebc97c758 | 233 | headerLine++; |
| leihen | 0:9c6ebc97c758 | 234 | } |
| leihen | 0:9c6ebc97c758 | 235 | return ; |
| leihen | 0:9c6ebc97c758 | 236 | } |
| leihen | 0:9c6ebc97c758 | 237 | |
| leihen | 0:9c6ebc97c758 | 238 | |
| leihen | 0:9c6ebc97c758 | 239 | void HttpServer::listenForRequests() |
| leihen | 0:9c6ebc97c758 | 240 | { |
| leihen | 0:9c6ebc97c758 | 241 | static char data[256]; |
| leihen | 0:9c6ebc97c758 | 242 | static int curPos = 0; |
| leihen | 0:9c6ebc97c758 | 243 | int CRLF = 0; |
| leihen | 0:9c6ebc97c758 | 244 | int m_openConnections = 0; |
| leihen | 0:9c6ebc97c758 | 245 | |
| leihen | 0:9c6ebc97c758 | 246 | request_msg_t *pMsg = NULL; |
| leihen | 0:9c6ebc97c758 | 247 | INFO("Listener running\n"); |
| leihen | 0:9c6ebc97c758 | 248 | bool asteriskReceivedOnce = false; |
| leihen | 0:9c6ebc97c758 | 249 | while(1) { |
| leihen | 0:9c6ebc97c758 | 250 | osEvent evt = m_queue.get(); |
| leihen | 0:9c6ebc97c758 | 251 | if (evt.status == osEventMessage) { |
| leihen | 0:9c6ebc97c758 | 252 | char c; |
| leihen | 0:9c6ebc97c758 | 253 | c = (char)(int)evt.value.p; |
| leihen | 0:9c6ebc97c758 | 254 | if ((c!='\n') && (c!='\r')) { |
| leihen | 0:9c6ebc97c758 | 255 | data[curPos++] = c; |
| leihen | 0:9c6ebc97c758 | 256 | data[curPos] = 0; |
| leihen | 0:9c6ebc97c758 | 257 | } |
| leihen | 0:9c6ebc97c758 | 258 | if (pMsg != NULL) { // request was detected and will further be processed completely |
| leihen | 0:9c6ebc97c758 | 259 | // check for CRLF |
| leihen | 0:9c6ebc97c758 | 260 | if (c == '\n') { |
| leihen | 0:9c6ebc97c758 | 261 | CRLF++; |
| leihen | 0:9c6ebc97c758 | 262 | INFO("<CR>(%d)", CRLF); |
| leihen | 0:9c6ebc97c758 | 263 | if (CRLF == 2) { // all message headers received, so send message and be ready for new one |
| leihen | 0:9c6ebc97c758 | 264 | CRLF = 0; |
| leihen | 0:9c6ebc97c758 | 265 | // SPAWN MESSAGE |
| leihen | 0:9c6ebc97c758 | 266 | INFO("REQUEST COMPLETE --> Handing over to worker thread !\n\n\n\n"); |
| leihen | 0:9c6ebc97c758 | 267 | m_requestQueue.put(pMsg); |
| leihen | 0:9c6ebc97c758 | 268 | data[0] = 0; |
| leihen | 0:9c6ebc97c758 | 269 | curPos = 0; |
| leihen | 0:9c6ebc97c758 | 270 | asteriskReceivedOnce = false; |
| leihen | 0:9c6ebc97c758 | 271 | pMsg = NULL; |
| leihen | 0:9c6ebc97c758 | 272 | } else { // must be a new header |
| leihen | 0:9c6ebc97c758 | 273 | // char *name, *value; |
| leihen | 0:9c6ebc97c758 | 274 | // INFO("Processing Header !\"%s\"", data); |
| leihen | 0:9c6ebc97c758 | 275 | /* processMessageHeader(data, &name, &value); |
| leihen | 0:9c6ebc97c758 | 276 | if (strncmp(name, "Content-Length", 14 ) == 0) { |
| leihen | 0:9c6ebc97c758 | 277 | // Data will be sent, be ready to receive |
| leihen | 0:9c6ebc97c758 | 278 | } else { |
| leihen | 0:9c6ebc97c758 | 279 | INFO("HEADER: Name=\"%s\", Value=\"%s\"", name, value); |
| leihen | 0:9c6ebc97c758 | 280 | } |
| leihen | 0:9c6ebc97c758 | 281 | */ data[0] = 0; |
| leihen | 0:9c6ebc97c758 | 282 | curPos = 0; |
| leihen | 0:9c6ebc97c758 | 283 | } |
| leihen | 0:9c6ebc97c758 | 284 | } else { |
| leihen | 0:9c6ebc97c758 | 285 | if (c != '\r') |
| leihen | 0:9c6ebc97c758 | 286 | CRLF = 0; |
| leihen | 0:9c6ebc97c758 | 287 | else |
| leihen | 0:9c6ebc97c758 | 288 | INFO("<LF>"); |
| leihen | 0:9c6ebc97c758 | 289 | } |
| leihen | 0:9c6ebc97c758 | 290 | } else if (c == '*') { |
| leihen | 0:9c6ebc97c758 | 291 | CRLF = 0; |
| leihen | 0:9c6ebc97c758 | 292 | if (asteriskReceivedOnce) { |
| leihen | 0:9c6ebc97c758 | 293 | // could be an open, close or read command |
| leihen | 0:9c6ebc97c758 | 294 | if (curPos >= 6) { // only need to process if data is large enough |
| leihen | 0:9c6ebc97c758 | 295 | if ( (data[curPos-6] == '*') && (data[curPos-5] == 'O') && (data[curPos-4] == 'P') && (data[curPos-3] == 'E') && (data[curPos-2] == 'N') && (data[curPos-1] == '*')) { |
| leihen | 0:9c6ebc97c758 | 296 | // Add a connection |
| leihen | 0:9c6ebc97c758 | 297 | INFO("New connection opened (%d)...\n", ++m_openConnections); |
| leihen | 0:9c6ebc97c758 | 298 | data[0] = 0; |
| leihen | 0:9c6ebc97c758 | 299 | curPos = 0; |
| leihen | 0:9c6ebc97c758 | 300 | } else if ( (data[curPos-6] == '*') && (data[curPos-5] == 'C') && (data[curPos-4] == 'L') && (data[curPos-3] == 'O') && (data[curPos-2] == 'S') && (data[curPos-1] == '*')) { |
| leihen | 0:9c6ebc97c758 | 301 | // close a connection |
| leihen | 0:9c6ebc97c758 | 302 | INFO("Connection was closed ...(%d)\n", --m_openConnections); |
| leihen | 0:9c6ebc97c758 | 303 | data[0] = 0; |
| leihen | 0:9c6ebc97c758 | 304 | curPos = 0; |
| leihen | 0:9c6ebc97c758 | 305 | } |
| leihen | 0:9c6ebc97c758 | 306 | } |
| leihen | 0:9c6ebc97c758 | 307 | asteriskReceivedOnce = false; |
| leihen | 0:9c6ebc97c758 | 308 | } else { // set the indicator so that next time we'll check for valid connection commands |
| leihen | 0:9c6ebc97c758 | 309 | asteriskReceivedOnce = true; |
| leihen | 0:9c6ebc97c758 | 310 | } |
| leihen | 0:9c6ebc97c758 | 311 | } else { // first make sure that when no asterisk is received the asteriskReceivedOnce flag will be reset on each newline |
| leihen | 0:9c6ebc97c758 | 312 | if (c == '\n') { |
| leihen | 0:9c6ebc97c758 | 313 | if (m_openConnections > 0) { |
| leihen | 0:9c6ebc97c758 | 314 | // Check to see if we received a valid request |
| leihen | 0:9c6ebc97c758 | 315 | pMsg = checkMessageReceived(data); |
| leihen | 0:9c6ebc97c758 | 316 | if (pMsg == NULL) { |
| leihen | 0:9c6ebc97c758 | 317 | // not received valid stuff, so discard |
| leihen | 0:9c6ebc97c758 | 318 | INFO("Unrecognised data received : \"%s\"\n", data); |
| leihen | 0:9c6ebc97c758 | 319 | } else { |
| leihen | 0:9c6ebc97c758 | 320 | INFO("New request detected ! : \"%s\"\n", data); |
| leihen | 0:9c6ebc97c758 | 321 | } |
| leihen | 0:9c6ebc97c758 | 322 | } else { |
| leihen | 0:9c6ebc97c758 | 323 | INFO("Unrecognised data detected : \"%s\"\n", data); |
| leihen | 0:9c6ebc97c758 | 324 | } |
| leihen | 0:9c6ebc97c758 | 325 | asteriskReceivedOnce = false; |
| leihen | 0:9c6ebc97c758 | 326 | data[0] = 0; |
| leihen | 0:9c6ebc97c758 | 327 | curPos = 0; |
| leihen | 0:9c6ebc97c758 | 328 | CRLF = 1; |
| leihen | 0:9c6ebc97c758 | 329 | } |
| leihen | 0:9c6ebc97c758 | 330 | } |
| leihen | 0:9c6ebc97c758 | 331 | } |
| leihen | 0:9c6ebc97c758 | 332 | // else { |
| leihen | 0:9c6ebc97c758 | 333 | Thread::yield(); |
| leihen | 0:9c6ebc97c758 | 334 | // } |
| leihen | 0:9c6ebc97c758 | 335 | } |
| leihen | 0:9c6ebc97c758 | 336 | } |
| leihen | 0:9c6ebc97c758 | 337 | |
| leihen | 0:9c6ebc97c758 | 338 | void HttpServer::serveRequests() |
| leihen | 0:9c6ebc97c758 | 339 | { |
| leihen | 0:9c6ebc97c758 | 340 | HTTPConnection::HTTPMessage *myMessage = new HTTPConnection::HTTPMessage; |
| leihen | 0:9c6ebc97c758 | 341 | |
| leihen | 0:9c6ebc97c758 | 342 | INFO("Server running\n"); |
| leihen | 0:9c6ebc97c758 | 343 | |
| leihen | 0:9c6ebc97c758 | 344 | while(1) { |
| leihen | 0:9c6ebc97c758 | 345 | INFO("Listening for new request !"); |
| leihen | 0:9c6ebc97c758 | 346 | osEvent evt = m_requestQueue.get(); |
| leihen | 0:9c6ebc97c758 | 347 | if (evt.status == osEventMessage) { |
| leihen | 0:9c6ebc97c758 | 348 | request_msg_t* pMsg = (request_msg_t*)evt.value.p; |
| leihen | 0:9c6ebc97c758 | 349 | m_worker->set_priority(osPriorityBelowNormal); |
| leihen | 0:9c6ebc97c758 | 350 | Thread::yield(); |
| leihen | 0:9c6ebc97c758 | 351 | switch(pMsg->requestType) { |
| leihen | 0:9c6ebc97c758 | 352 | case msg_get: |
| leihen | 0:9c6ebc97c758 | 353 | INFO("Server received GET message !"); |
| leihen | 0:9c6ebc97c758 | 354 | myMessage->request = HTTP_RT_GET; |
| leihen | 0:9c6ebc97c758 | 355 | myMessage->uri = pMsg->requestUri; |
| leihen | 0:9c6ebc97c758 | 356 | HandleRequest(myMessage); |
| leihen | 0:9c6ebc97c758 | 357 | Thread::yield(); |
| leihen | 0:9c6ebc97c758 | 358 | break; |
| leihen | 0:9c6ebc97c758 | 359 | |
| leihen | 0:9c6ebc97c758 | 360 | case msg_post: |
| leihen | 0:9c6ebc97c758 | 361 | case msg_put: |
| leihen | 0:9c6ebc97c758 | 362 | case msg_head: |
| leihen | 0:9c6ebc97c758 | 363 | case msg_delete: |
| leihen | 0:9c6ebc97c758 | 364 | case msg_trace: |
| leihen | 0:9c6ebc97c758 | 365 | case msg_options: |
| leihen | 0:9c6ebc97c758 | 366 | case msg_connect: |
| leihen | 0:9c6ebc97c758 | 367 | default: |
| leihen | 0:9c6ebc97c758 | 368 | break; |
| leihen | 0:9c6ebc97c758 | 369 | } |
| leihen | 0:9c6ebc97c758 | 370 | m_worker->set_priority(osPriorityNormal); |
| leihen | 0:9c6ebc97c758 | 371 | m_requestPool.free(pMsg); |
| leihen | 0:9c6ebc97c758 | 372 | } |
| leihen | 0:9c6ebc97c758 | 373 | Thread::yield(); |
| leihen | 0:9c6ebc97c758 | 374 | } |
| leihen | 0:9c6ebc97c758 | 375 | } |
| leihen | 0:9c6ebc97c758 | 376 | |
| leihen | 0:9c6ebc97c758 | 377 | bool HttpServer::parseRequest(char *request) |
| leihen | 0:9c6ebc97c758 | 378 | { |
| leihen | 0:9c6ebc97c758 | 379 | // dissect into : path, file[, [arg, value]1..N ] as "/path/file?arg1=val1&arg2=val2... |
| leihen | 0:9c6ebc97c758 | 380 | // first check for questionmark sign to separate the file and path from any arguments |
| leihen | 0:9c6ebc97c758 | 381 | char* path = request; |
| leihen | 0:9c6ebc97c758 | 382 | char* file = NULL; |
| leihen | 0:9c6ebc97c758 | 383 | char* arglist = NULL; |
| leihen | 0:9c6ebc97c758 | 384 | |
| leihen | 0:9c6ebc97c758 | 385 | char* lastPathSep = NULL; |
| leihen | 0:9c6ebc97c758 | 386 | while(*request) { |
| leihen | 0:9c6ebc97c758 | 387 | if (*request == '/' ) |
| leihen | 0:9c6ebc97c758 | 388 | lastPathSep = request; |
| leihen | 0:9c6ebc97c758 | 389 | if (*request == '?') { |
| leihen | 0:9c6ebc97c758 | 390 | *request++ = 0; |
| leihen | 0:9c6ebc97c758 | 391 | arglist = request; |
| leihen | 0:9c6ebc97c758 | 392 | } |
| leihen | 0:9c6ebc97c758 | 393 | } |
| leihen | 0:9c6ebc97c758 | 394 | |
| leihen | 0:9c6ebc97c758 | 395 | if (arglist == NULL) { |
| leihen | 0:9c6ebc97c758 | 396 | INFO("Request does not have parameters !"); |
| leihen | 0:9c6ebc97c758 | 397 | } |
| leihen | 0:9c6ebc97c758 | 398 | |
| leihen | 0:9c6ebc97c758 | 399 | if (lastPathSep == NULL) |
| leihen | 0:9c6ebc97c758 | 400 | return false; // no path provided !!!! |
| leihen | 0:9c6ebc97c758 | 401 | |
| leihen | 0:9c6ebc97c758 | 402 | // now, whatever is provided to the left including the slash is the 'path', the part to the right is the file. caution: the file may be left blank ! |
| leihen | 0:9c6ebc97c758 | 403 | if (lastPathSep != 0) { |
| leihen | 0:9c6ebc97c758 | 404 | // 2 cases to handle : |
| leihen | 0:9c6ebc97c758 | 405 | // 1. : "/blah/" or "/blah/blub/" --> path = "/blah/", file = "index.html" |
| leihen | 0:9c6ebc97c758 | 406 | // 2. : "/blah/blub" or "/blah/blub/blubber" --> path = "/blah/", file = "blub" |
| leihen | 0:9c6ebc97c758 | 407 | } else { |
| leihen | 0:9c6ebc97c758 | 408 | // 2 cases to handle : |
| leihen | 0:9c6ebc97c758 | 409 | // 1. : "/" --> path = "/", file = "index.html" |
| leihen | 0:9c6ebc97c758 | 410 | // 2. : "/blah" --> path = "/", file = "blah" |
| leihen | 0:9c6ebc97c758 | 411 | } |
| leihen | 0:9c6ebc97c758 | 412 | return true; |
| leihen | 0:9c6ebc97c758 | 413 | } |
| leihen | 0:9c6ebc97c758 | 414 | |
| leihen | 0:9c6ebc97c758 | 415 | |
| leihen | 0:9c6ebc97c758 | 416 | void HttpServer::listen_thread(const void *params) |
| leihen | 0:9c6ebc97c758 | 417 | { |
| leihen | 0:9c6ebc97c758 | 418 | HttpServer* pSvr = (HttpServer*)params; |
| leihen | 0:9c6ebc97c758 | 419 | |
| leihen | 0:9c6ebc97c758 | 420 | pSvr->listenForRequests(); |
| leihen | 0:9c6ebc97c758 | 421 | } |
| leihen | 0:9c6ebc97c758 | 422 | |
| leihen | 0:9c6ebc97c758 | 423 | void HttpServer::worker_thread(const void * params) |
| leihen | 0:9c6ebc97c758 | 424 | { |
| leihen | 0:9c6ebc97c758 | 425 | HttpServer* pSvr = (HttpServer*)params; |
| leihen | 0:9c6ebc97c758 | 426 | |
| leihen | 0:9c6ebc97c758 | 427 | pSvr->serveRequests(); |
| leihen | 0:9c6ebc97c758 | 428 | } |
| leihen | 0:9c6ebc97c758 | 429 | |
| leihen | 0:9c6ebc97c758 | 430 | |
| leihen | 0:9c6ebc97c758 | 431 | |
| leihen | 0:9c6ebc97c758 | 432 | |
| leihen | 0:9c6ebc97c758 | 433 | 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 | 0:9c6ebc97c758 | 434 | |
| leihen | 0:9c6ebc97c758 | 435 | void HttpServer::StdErrorHandler(HTTPConnection::HTTPMessage& msg) |
| leihen | 0:9c6ebc97c758 | 436 | { |
| leihen | 0:9c6ebc97c758 | 437 | char echoHeader[256]; |
| leihen | 0:9c6ebc97c758 | 438 | 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 | 0:9c6ebc97c758 | 439 | |
| leihen | 0:9c6ebc97c758 | 440 | Wifly::getInstance()->sendData(echoHeader, strlen(echoHeader)); |
| leihen | 0:9c6ebc97c758 | 441 | Wifly::getInstance()->sendData((char*)szStdErrorPage, strlen(szStdErrorPage)); |
| leihen | 0:9c6ebc97c758 | 442 | } |
| leihen | 0:9c6ebc97c758 | 443 | |
| leihen | 0:9c6ebc97c758 | 444 | void HttpServer::HandleRequest(HTTPConnection::HTTPMessage* pmsg) |
| leihen | 0:9c6ebc97c758 | 445 | { |
| leihen | 0:9c6ebc97c758 | 446 | static std::string localPath; |
| leihen | 0:9c6ebc97c758 | 447 | static std::map<std::string, HTTPRequestHandler*(*)(const char*, const char*, HTTPConnection::HTTPMessage&), handlersComp>::const_iterator it; |
| leihen | 0:9c6ebc97c758 | 448 | |
| leihen | 0:9c6ebc97c758 | 449 | INFO("Trying to handle request"); |
| leihen | 0:9c6ebc97c758 | 450 | // Iterate through registered handlers and check if the handler's path is a subset of the requested uri. |
| leihen | 0:9c6ebc97c758 | 451 | for (it = m_lpHandlers.begin() ; it != m_lpHandlers.end() ; it++) { |
| leihen | 0:9c6ebc97c758 | 452 | // check if this entries' path is fully contained at the beginning of the requested path |
| leihen | 0:9c6ebc97c758 | 453 | std::string curpth = it->first; |
| leihen | 0:9c6ebc97c758 | 454 | |
| leihen | 0:9c6ebc97c758 | 455 | if (pmsg->uri.find(curpth) == 0) { |
| leihen | 0:9c6ebc97c758 | 456 | // firts matching handler found, we just take it and we'll be happy |
| leihen | 0:9c6ebc97c758 | 457 | localPath = pmsg->uri.substr(curpth.length()); |
| leihen | 0:9c6ebc97c758 | 458 | break; |
| leihen | 0:9c6ebc97c758 | 459 | } |
| leihen | 0:9c6ebc97c758 | 460 | } |
| leihen | 0:9c6ebc97c758 | 461 | |
| leihen | 0:9c6ebc97c758 | 462 | if (it == m_lpHandlers.end()) { |
| leihen | 0:9c6ebc97c758 | 463 | // There is no such handler, so return invalid |
| leihen | 0:9c6ebc97c758 | 464 | INFO("Webrequest left unhandled."); |
| leihen | 0:9c6ebc97c758 | 465 | |
| leihen | 0:9c6ebc97c758 | 466 | m_pErrorHandler(*pmsg); |
| leihen | 0:9c6ebc97c758 | 467 | } else { |
| leihen | 0:9c6ebc97c758 | 468 | // Valid handler was found |
| leihen | 0:9c6ebc97c758 | 469 | INFO("Routing webrequest !"); |
| leihen | 0:9c6ebc97c758 | 470 | // Instantiate the handler object (handling will be done from withing the object's constructor |
| leihen | 0:9c6ebc97c758 | 471 | HTTPRequestHandler *phdl = (*it->second)(it->first.c_str(), localPath.c_str(), *pmsg); |
| leihen | 0:9c6ebc97c758 | 472 | // now we can delete the object, because handling is completed. |
| leihen | 0:9c6ebc97c758 | 473 | if (phdl != NULL) |
| leihen | 0:9c6ebc97c758 | 474 | delete phdl; |
| leihen | 0:9c6ebc97c758 | 475 | } |
| leihen | 0:9c6ebc97c758 | 476 | } |
| leihen | 0:9c6ebc97c758 | 477 |