HTTP Server upon new mbed Ethernet Interface. Based on original code by Henry Leinen.
Dependencies: EthernetInterface mbed-rtos mbed
Fork of HTTP_server by
HTTPServer.cpp@4:2a34139c7246, 2013-08-05 (annotated)
- Committer:
- pabloxid
- Date:
- Mon Aug 05 05:51:16 2013 +0000
- Revision:
- 4:2a34139c7246
- Parent:
- 3:27b3a889b327
Some minor changes
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
pabloxid | 0:fcceff3299be | 1 | #include "mbed.h" |
pabloxid | 0:fcceff3299be | 2 | #include "HTTPServer.h" |
pabloxid | 0:fcceff3299be | 3 | |
pabloxid | 0:fcceff3299be | 4 | RequestConfig rq_conf[] = { |
pabloxid | 0:fcceff3299be | 5 | { "GET", HTTP_RT_GET }, |
pabloxid | 0:fcceff3299be | 6 | { "POST", HTTP_RT_POST} |
pabloxid | 0:fcceff3299be | 7 | }; |
pabloxid | 0:fcceff3299be | 8 | |
pabloxid | 0:fcceff3299be | 9 | HTTPServer::HTTPServer (int port, const char* _path) { |
pabloxid | 0:fcceff3299be | 10 | |
pabloxid | 0:fcceff3299be | 11 | INFO("Binding to port %d...", port); |
pabloxid | 0:fcceff3299be | 12 | if (socketServer.bind (port) < 0) { |
pabloxid | 0:fcceff3299be | 13 | ERR("Failed to bind to port !\n"); |
pabloxid | 0:fcceff3299be | 14 | error("Binding"); |
pabloxid | 0:fcceff3299be | 15 | } |
pabloxid | 0:fcceff3299be | 16 | |
pabloxid | 0:fcceff3299be | 17 | INFO("Listening ..."); |
pabloxid | 0:fcceff3299be | 18 | if (socketServer.listen(1) < 0) { |
pabloxid | 0:fcceff3299be | 19 | ERR("Failed to listen !\n"); |
pabloxid | 0:fcceff3299be | 20 | error("Listening"); |
pabloxid | 0:fcceff3299be | 21 | } |
pabloxid | 0:fcceff3299be | 22 | |
pabloxid | 0:fcceff3299be | 23 | INFO("Connected !"); |
pabloxid | 3:27b3a889b327 | 24 | // set into blocking operation |
pabloxid | 2:dc9184e97328 | 25 | socketServer.set_blocking (true); |
pabloxid | 0:fcceff3299be | 26 | |
pabloxid | 0:fcceff3299be | 27 | path = _path; |
pabloxid | 4:2a34139c7246 | 28 | msg = NULL; |
pabloxid | 4:2a34139c7246 | 29 | cliente = NULL; |
pabloxid | 0:fcceff3299be | 30 | |
pabloxid | 0:fcceff3299be | 31 | } |
pabloxid | 0:fcceff3299be | 32 | |
pabloxid | 0:fcceff3299be | 33 | HTTPServer::~HTTPServer() { }; |
pabloxid | 0:fcceff3299be | 34 | |
pabloxid | 0:fcceff3299be | 35 | int HTTPServer::poll () { |
pabloxid | 0:fcceff3299be | 36 | |
pabloxid | 0:fcceff3299be | 37 | cliente = new TCPSocketConnection; |
pabloxid | 0:fcceff3299be | 38 | cliente->set_blocking (false, TIMEOUT); |
pabloxid | 0:fcceff3299be | 39 | |
pabloxid | 4:2a34139c7246 | 40 | int retvalue = socketServer.accept (*cliente); |
pabloxid | 3:27b3a889b327 | 41 | |
pabloxid | 3:27b3a889b327 | 42 | if (retvalue == OK) { |
pabloxid | 3:27b3a889b327 | 43 | // a new connection was received |
pabloxid | 3:27b3a889b327 | 44 | INFO("Client (IP=%s) is connected !", cliente->get_address()); |
pabloxid | 3:27b3a889b327 | 45 | msg = new HTTPMsg; // estructura para decodificar y alojar el mensaje |
pabloxid | 3:27b3a889b327 | 46 | |
pabloxid | 3:27b3a889b327 | 47 | retvalue = pollConnection (); // esto parsea y llena las cosas contenidas en msg |
pabloxid | 3:27b3a889b327 | 48 | |
pabloxid | 3:27b3a889b327 | 49 | if (retvalue == OK) { |
pabloxid | 3:27b3a889b327 | 50 | // Handle the request |
pabloxid | 3:27b3a889b327 | 51 | INFO("Handling request !"); |
pabloxid | 4:2a34139c7246 | 52 | |
pabloxid | 4:2a34139c7246 | 53 | handleRequest (); // handling request |
pabloxid | 4:2a34139c7246 | 54 | |
pabloxid | 3:27b3a889b327 | 55 | } |
pabloxid | 3:27b3a889b327 | 56 | delete msg; |
pabloxid | 3:27b3a889b327 | 57 | } else { // retvalue == ERROR |
pabloxid | 4:2a34139c7246 | 58 | ERR("Error accepting client"); |
pabloxid | 0:fcceff3299be | 59 | } |
pabloxid | 0:fcceff3299be | 60 | |
pabloxid | 0:fcceff3299be | 61 | delete cliente; |
pabloxid | 0:fcceff3299be | 62 | |
pabloxid | 2:dc9184e97328 | 63 | INFO("Leaving polling thread\n"); |
pabloxid | 3:27b3a889b327 | 64 | return retvalue; |
pabloxid | 3:27b3a889b327 | 65 | |
pabloxid | 0:fcceff3299be | 66 | } |
pabloxid | 0:fcceff3299be | 67 | |
pabloxid | 0:fcceff3299be | 68 | int HTTPServer::pollConnection () { |
pabloxid | 0:fcceff3299be | 69 | |
pabloxid | 0:fcceff3299be | 70 | INFO("Waiting for new data in connection"); |
pabloxid | 3:27b3a889b327 | 71 | |
pabloxid | 3:27b3a889b327 | 72 | // Try receiving request line |
pabloxid | 4:2a34139c7246 | 73 | int received = receiveLine (); |
pabloxid | 0:fcceff3299be | 74 | |
pabloxid | 0:fcceff3299be | 75 | if (received == ERROR) { |
pabloxid | 3:27b3a889b327 | 76 | // there was an error, probably the connection was closed, so close this connection as well |
pabloxid | 0:fcceff3299be | 77 | INFO("No more data available. Will close this connection now."); |
pabloxid | 0:fcceff3299be | 78 | return ERROR; |
pabloxid | 0:fcceff3299be | 79 | } |
pabloxid | 0:fcceff3299be | 80 | |
pabloxid | 3:27b3a889b327 | 81 | // Request has not yet been received, so try it |
pabloxid | 3:27b3a889b327 | 82 | received = parseRequest (); |
pabloxid | 0:fcceff3299be | 83 | |
pabloxid | 4:2a34139c7246 | 84 | /*alternative (fast) parse request method: |
pabloxid | 4:2a34139c7246 | 85 | * ret = sscanf(buffer, "%s %s HTTP/%*d.%*d", request, uri); |
pabloxid | 4:2a34139c7246 | 86 | */ |
pabloxid | 4:2a34139c7246 | 87 | |
pabloxid | 0:fcceff3299be | 88 | if (received == ERROR) { |
pabloxid | 3:27b3a889b327 | 89 | // Invalid content received, so close the connection |
pabloxid | 0:fcceff3299be | 90 | INFO("Invalid message received, so sending negative response and closing connection !"); |
pabloxid | 2:dc9184e97328 | 91 | tcpsend ("HTTP/1.1 400 BadRequest\n\rContent-Length: %d\n\rContent-Type: text\n\r\n\r\n\r", 0); |
pabloxid | 0:fcceff3299be | 92 | return ERROR; |
pabloxid | 0:fcceff3299be | 93 | } |
pabloxid | 0:fcceff3299be | 94 | |
pabloxid | 3:27b3a889b327 | 95 | // Request has been received, try receive the headers section |
pabloxid | 0:fcceff3299be | 96 | do { |
pabloxid | 0:fcceff3299be | 97 | received = receiveLine (); |
pabloxid | 0:fcceff3299be | 98 | if (received == ERROR) {return ERROR;} |
pabloxid | 3:27b3a889b327 | 99 | // First check if we received an empty line; |
pabloxid | 3:27b3a889b327 | 100 | // This would indicate the end of headers section. |
pabloxid | 0:fcceff3299be | 101 | if (received == EMPTY) { |
pabloxid | 3:27b3a889b327 | 102 | // there was an empty line, so the headers section is complete |
pabloxid | 0:fcceff3299be | 103 | INFO("Request Header was received completely. Performing request."); |
pabloxid | 4:2a34139c7246 | 104 | received = OK; |
pabloxid | 0:fcceff3299be | 105 | break; |
pabloxid | 0:fcceff3299be | 106 | } else { |
pabloxid | 3:27b3a889b327 | 107 | // parse header field |
pabloxid | 3:27b3a889b327 | 108 | if (parseHeader() != OK) { |
pabloxid | 0:fcceff3299be | 109 | WARN("Invalid message header received !"); |
pabloxid | 3:27b3a889b327 | 110 | } |
pabloxid | 0:fcceff3299be | 111 | } |
pabloxid | 3:27b3a889b327 | 112 | } while (received > 0); |
pabloxid | 0:fcceff3299be | 113 | |
pabloxid | 0:fcceff3299be | 114 | INFO("Leaving poll function!"); |
pabloxid | 0:fcceff3299be | 115 | return received; |
pabloxid | 0:fcceff3299be | 116 | } |
pabloxid | 0:fcceff3299be | 117 | |
pabloxid | 0:fcceff3299be | 118 | int HTTPServer::receiveLine () { |
pabloxid | 0:fcceff3299be | 119 | |
pabloxid | 0:fcceff3299be | 120 | buffer[0] = 0; |
pabloxid | 0:fcceff3299be | 121 | |
pabloxid | 0:fcceff3299be | 122 | int i; |
pabloxid | 0:fcceff3299be | 123 | |
pabloxid | 0:fcceff3299be | 124 | // Try to receive up to the max number of characters |
pabloxid | 0:fcceff3299be | 125 | for (i=0; i<BUFFER_SIZE-1; i++) { |
pabloxid | 0:fcceff3299be | 126 | int c = cliente->receive (buffer+i, 1); |
pabloxid | 0:fcceff3299be | 127 | // Check that - if no character was currently received - the timeout period is reached. |
pabloxid | 0:fcceff3299be | 128 | if (c == 0 || c == -1) { |
pabloxid | 0:fcceff3299be | 129 | // no character was read, so check if operation timed out |
pabloxid | 4:2a34139c7246 | 130 | ERR("Timeout occured in function 'receiveLine'."); |
pabloxid | 4:2a34139c7246 | 131 | return ERROR; |
pabloxid | 0:fcceff3299be | 132 | } |
pabloxid | 0:fcceff3299be | 133 | // Check if line terminating character was received |
pabloxid | 0:fcceff3299be | 134 | if (buffer[i] == '\n') {break;} |
pabloxid | 0:fcceff3299be | 135 | } |
pabloxid | 0:fcceff3299be | 136 | // Terminate with \0 |
pabloxid | 0:fcceff3299be | 137 | buffer[i] = 0; |
pabloxid | 0:fcceff3299be | 138 | |
pabloxid | 0:fcceff3299be | 139 | // Trim for '\r' linefeed at the end |
pabloxid | 0:fcceff3299be | 140 | if (i>0 && buffer[i-1] == '\r') { |
pabloxid | 0:fcceff3299be | 141 | i--; |
pabloxid | 0:fcceff3299be | 142 | buffer[i] = 0; |
pabloxid | 0:fcceff3299be | 143 | } |
pabloxid | 0:fcceff3299be | 144 | |
pabloxid | 0:fcceff3299be | 145 | // return number of characters received in the line or return -2 if an empty line was received |
pabloxid | 0:fcceff3299be | 146 | if (i==0 || (i==1 && buffer[0]=='\r')) { |
pabloxid | 0:fcceff3299be | 147 | // empty line received, so return -2 |
pabloxid | 0:fcceff3299be | 148 | return EMPTY; |
pabloxid | 0:fcceff3299be | 149 | } |
pabloxid | 0:fcceff3299be | 150 | // retorna número de caracteres leidos |
pabloxid | 0:fcceff3299be | 151 | return i; |
pabloxid | 0:fcceff3299be | 152 | } |
pabloxid | 0:fcceff3299be | 153 | |
pabloxid | 3:27b3a889b327 | 154 | int HTTPServer::parseRequest () { |
pabloxid | 0:fcceff3299be | 155 | |
pabloxid | 0:fcceff3299be | 156 | // Check if buffer content is not long enough. |
pabloxid | 0:fcceff3299be | 157 | if (strlen(buffer) < MIN_LONG) { |
pabloxid | 0:fcceff3299be | 158 | ERR("Buffer content is invalid or too short."); |
pabloxid | 0:fcceff3299be | 159 | return ERROR; |
pabloxid | 0:fcceff3299be | 160 | } |
pabloxid | 0:fcceff3299be | 161 | |
pabloxid | 0:fcceff3299be | 162 | std::vector<std::string> args; |
pabloxid | 0:fcceff3299be | 163 | |
pabloxid | 0:fcceff3299be | 164 | int argno = 0; |
pabloxid | 0:fcceff3299be | 165 | // decompose string into a list of arguments |
pabloxid | 0:fcceff3299be | 166 | int start = 0; // current starting char |
pabloxid | 0:fcceff3299be | 167 | int nLen = strlen(buffer)+1; |
pabloxid | 0:fcceff3299be | 168 | for (int i=0; i<nLen; i++) { |
pabloxid | 0:fcceff3299be | 169 | if ((buffer[i] == ' ') || (buffer[i] == '\n') || (buffer[i] == 0)) { |
pabloxid | 0:fcceff3299be | 170 | // new arg found |
pabloxid | 0:fcceff3299be | 171 | buffer[i] = 0; |
pabloxid | 0:fcceff3299be | 172 | if (argno++ == 1) { |
pabloxid | 0:fcceff3299be | 173 | // it's the uri |
pabloxid | 0:fcceff3299be | 174 | // parse the uri args |
pabloxid | 0:fcceff3299be | 175 | parseUriArgs (&buffer[start]); |
pabloxid | 0:fcceff3299be | 176 | } |
pabloxid | 0:fcceff3299be | 177 | INFO("Found argument \"%s\"", &buffer[start]); |
pabloxid | 0:fcceff3299be | 178 | args.push_back(&buffer[start]); |
pabloxid | 0:fcceff3299be | 179 | start = i+1; |
pabloxid | 0:fcceff3299be | 180 | } |
pabloxid | 0:fcceff3299be | 181 | } |
pabloxid | 0:fcceff3299be | 182 | |
pabloxid | 0:fcceff3299be | 183 | // store the uri and the HTTP version |
pabloxid | 0:fcceff3299be | 184 | msg->uri = args[1]; |
pabloxid | 0:fcceff3299be | 185 | msg->version = args[2]; |
pabloxid | 0:fcceff3299be | 186 | |
pabloxid | 0:fcceff3299be | 187 | // Find matching request type |
pabloxid | 0:fcceff3299be | 188 | for (int i=0; i<sizeof(rq_conf)/sizeof(RequestConfig) ; i++) { |
pabloxid | 0:fcceff3299be | 189 | if (args.at(0) == rq_conf[i].request_string) { |
pabloxid | 0:fcceff3299be | 190 | msg->request = rq_conf[i].request_type; |
pabloxid | 0:fcceff3299be | 191 | } |
pabloxid | 0:fcceff3299be | 192 | } |
pabloxid | 0:fcceff3299be | 193 | |
pabloxid | 3:27b3a889b327 | 194 | // init body section length |
pabloxid | 3:27b3a889b327 | 195 | msg->body_length = 0; |
pabloxid | 3:27b3a889b327 | 196 | |
pabloxid | 0:fcceff3299be | 197 | return OK; |
pabloxid | 0:fcceff3299be | 198 | } |
pabloxid | 0:fcceff3299be | 199 | |
pabloxid | 0:fcceff3299be | 200 | int HTTPServer::parseHeader () { |
pabloxid | 0:fcceff3299be | 201 | |
pabloxid | 0:fcceff3299be | 202 | // Check if the buffer content is too short to be meaningful |
pabloxid | 0:fcceff3299be | 203 | if (strlen(buffer) < MIN_LONG) {return ERROR;} |
pabloxid | 0:fcceff3299be | 204 | |
pabloxid | 0:fcceff3299be | 205 | // decompose string into a touple of <field name> : <field value> |
pabloxid | 0:fcceff3299be | 206 | int value_start = 0; |
pabloxid | 0:fcceff3299be | 207 | int buflen = strlen(buffer)+1; |
pabloxid | 0:fcceff3299be | 208 | for (int i=0; i<buflen; i++) { |
pabloxid | 0:fcceff3299be | 209 | if (buffer[i] == ':') { |
pabloxid | 0:fcceff3299be | 210 | // touple found |
pabloxid | 0:fcceff3299be | 211 | buffer[i] = 0; |
pabloxid | 0:fcceff3299be | 212 | value_start = i+1; |
pabloxid | 3:27b3a889b327 | 213 | // headers storage is disabled; uncomment next line to enable |
pabloxid | 3:27b3a889b327 | 214 | // msg->headers[buffer] = &buffer[value_start]; |
pabloxid | 0:fcceff3299be | 215 | INFO("Header name=\"%s\" : value=\"%s\".", buffer, &buffer[value_start]); |
pabloxid | 3:27b3a889b327 | 216 | // Look for "Content-Length" header |
pabloxid | 3:27b3a889b327 | 217 | if (strcmp (buffer, "Content-Length") == 0) { |
pabloxid | 3:27b3a889b327 | 218 | msg->body_length = atoi(&buffer[value_start]); |
pabloxid | 3:27b3a889b327 | 219 | INFO ("Body section found. Length: %i", msg->body_length); |
pabloxid | 3:27b3a889b327 | 220 | } |
pabloxid | 0:fcceff3299be | 221 | return OK; |
pabloxid | 0:fcceff3299be | 222 | } |
pabloxid | 0:fcceff3299be | 223 | } |
pabloxid | 0:fcceff3299be | 224 | |
pabloxid | 3:27b3a889b327 | 225 | ERR("Did not receive a valid header : \"%s\".", buffer); |
pabloxid | 0:fcceff3299be | 226 | return ERROR; |
pabloxid | 0:fcceff3299be | 227 | } |
pabloxid | 0:fcceff3299be | 228 | |
pabloxid | 0:fcceff3299be | 229 | int HTTPServer::parseUriArgs (char *uri_buffer) { |
pabloxid | 0:fcceff3299be | 230 | |
pabloxid | 0:fcceff3299be | 231 | // Check if the buffer content is too short to be meaningful |
pabloxid | 0:fcceff3299be | 232 | if (strlen(uri_buffer) < MIN_LONG) {return ERROR;} |
pabloxid | 0:fcceff3299be | 233 | |
pabloxid | 0:fcceff3299be | 234 | int args_start = -1; |
pabloxid | 0:fcceff3299be | 235 | int value_start = -1; |
pabloxid | 0:fcceff3299be | 236 | int buflen = strlen(uri_buffer) + 1; |
pabloxid | 0:fcceff3299be | 237 | char* argname = NULL; |
pabloxid | 0:fcceff3299be | 238 | char* valuename = NULL; |
pabloxid | 0:fcceff3299be | 239 | for (int i=0; i<buflen; i++) { |
pabloxid | 4:2a34139c7246 | 240 | if (args_start == -1) { // args section not yet found |
pabloxid | 0:fcceff3299be | 241 | if (uri_buffer[i] == '?') { // starts with a question mark, so got it |
pabloxid | 0:fcceff3299be | 242 | uri_buffer[i] = 0; |
pabloxid | 4:2a34139c7246 | 243 | args_start = i; // set the start of the args section |
pabloxid | 0:fcceff3299be | 244 | INFO("Argument section found !"); |
pabloxid | 0:fcceff3299be | 245 | } |
pabloxid | 4:2a34139c7246 | 246 | } else { // search arg-value touples |
pabloxid | 4:2a34139c7246 | 247 | if (argname == NULL) { // arg-name found ? |
pabloxid | 0:fcceff3299be | 248 | if (uri_buffer[i] == '=') { |
pabloxid | 3:27b3a889b327 | 249 | // yes, separate the arg-name |
pabloxid | 0:fcceff3299be | 250 | uri_buffer[i] = 0; |
pabloxid | 0:fcceff3299be | 251 | argname = &uri_buffer[args_start]; |
pabloxid | 0:fcceff3299be | 252 | value_start = i+1; |
pabloxid | 0:fcceff3299be | 253 | INFO("Argument name %s", argname); |
pabloxid | 0:fcceff3299be | 254 | } |
pabloxid | 0:fcceff3299be | 255 | } else { // search for end of value |
pabloxid | 0:fcceff3299be | 256 | if ((uri_buffer[i] == '&') || (uri_buffer[i] == 0) || (uri_buffer[i] == '\r') || (uri_buffer[i] == '\n')) { |
pabloxid | 0:fcceff3299be | 257 | buffer[i] = 0; |
pabloxid | 0:fcceff3299be | 258 | valuename = &uri_buffer[value_start]; |
pabloxid | 0:fcceff3299be | 259 | INFO("Argument value %s", valuename); |
pabloxid | 3:27b3a889b327 | 260 | msg->uri_args[argname] = valuename; |
pabloxid | 3:27b3a889b327 | 261 | // reset all indicators |
pabloxid | 0:fcceff3299be | 262 | argname = NULL; |
pabloxid | 0:fcceff3299be | 263 | valuename = NULL; |
pabloxid | 0:fcceff3299be | 264 | } |
pabloxid | 0:fcceff3299be | 265 | } |
pabloxid | 0:fcceff3299be | 266 | } |
pabloxid | 0:fcceff3299be | 267 | } |
pabloxid | 0:fcceff3299be | 268 | return OK; |
pabloxid | 0:fcceff3299be | 269 | } |
pabloxid | 0:fcceff3299be | 270 | |
pabloxid | 0:fcceff3299be | 271 | void HTTPServer::handleRequest () { |
pabloxid | 0:fcceff3299be | 272 | |
pabloxid | 0:fcceff3299be | 273 | int err_; |
pabloxid | 0:fcceff3299be | 274 | |
pabloxid | 0:fcceff3299be | 275 | switch (msg->request) { |
pabloxid | 0:fcceff3299be | 276 | case HTTP_RT_GET: |
pabloxid | 0:fcceff3299be | 277 | INFO("Dispatching GET Request."); |
pabloxid | 0:fcceff3299be | 278 | err_ = handleGetRequest(); |
pabloxid | 0:fcceff3299be | 279 | break; |
pabloxid | 0:fcceff3299be | 280 | case HTTP_RT_POST: |
pabloxid | 0:fcceff3299be | 281 | INFO("Dispatching POST request."); |
pabloxid | 0:fcceff3299be | 282 | err_ = handlePostRequest(); |
pabloxid | 0:fcceff3299be | 283 | break; |
pabloxid | 0:fcceff3299be | 284 | default: |
pabloxid | 0:fcceff3299be | 285 | INFO("Error in handleRequest, unhandled request type."); |
pabloxid | 0:fcceff3299be | 286 | err_ = 501; // HTTP_NotImplemented |
pabloxid | 0:fcceff3299be | 287 | break; |
pabloxid | 0:fcceff3299be | 288 | } |
pabloxid | 0:fcceff3299be | 289 | |
pabloxid | 0:fcceff3299be | 290 | // if any of these functions returns a negative number, call the error handler |
pabloxid | 0:fcceff3299be | 291 | if (err_ > 0) { |
pabloxid | 0:fcceff3299be | 292 | handleError (err_); |
pabloxid | 0:fcceff3299be | 293 | } |
pabloxid | 0:fcceff3299be | 294 | |
pabloxid | 0:fcceff3299be | 295 | } |
pabloxid | 0:fcceff3299be | 296 | |
pabloxid | 0:fcceff3299be | 297 | int HTTPServer::handleGetRequest() { |
pabloxid | 0:fcceff3299be | 298 | |
pabloxid | 2:dc9184e97328 | 299 | int retval = OK; //success |
pabloxid | 0:fcceff3299be | 300 | |
pabloxid | 2:dc9184e97328 | 301 | INFO("Handling Get Request."); |
pabloxid | 0:fcceff3299be | 302 | |
pabloxid | 0:fcceff3299be | 303 | // maping to root path |
pabloxid | 0:fcceff3299be | 304 | std::string reqPath = path + msg->uri.substr(1); |
pabloxid | 0:fcceff3299be | 305 | |
pabloxid | 0:fcceff3299be | 306 | // Check if we received a directory with the local path |
pabloxid | 0:fcceff3299be | 307 | if (reqPath.substr(reqPath.length()-1, 1) == "/") { |
pabloxid | 0:fcceff3299be | 308 | // yes, we shall append the default page name |
pabloxid | 0:fcceff3299be | 309 | reqPath += "index.htm"; |
pabloxid | 0:fcceff3299be | 310 | } |
pabloxid | 0:fcceff3299be | 311 | |
pabloxid | 0:fcceff3299be | 312 | INFO("Mapping \"%s\" to \"%s\"", msg->uri.c_str(), reqPath.c_str()); |
pabloxid | 0:fcceff3299be | 313 | |
pabloxid | 2:dc9184e97328 | 314 | FILE *file = fopen(reqPath.c_str(), "r"); |
pabloxid | 2:dc9184e97328 | 315 | if (file != NULL) { |
pabloxid | 0:fcceff3299be | 316 | |
pabloxid | 2:dc9184e97328 | 317 | // File was found and can be returned; first determine the size |
pabloxid | 2:dc9184e97328 | 318 | fseek (file, 0, SEEK_END); |
pabloxid | 2:dc9184e97328 | 319 | int size = ftell (file); |
pabloxid | 2:dc9184e97328 | 320 | fseek (file, 0, SEEK_SET); |
pabloxid | 0:fcceff3299be | 321 | |
pabloxid | 2:dc9184e97328 | 322 | startResponse (200, size); // response: 200 = HTTP_Ok |
pabloxid | 2:dc9184e97328 | 323 | while (!feof(file) && !ferror(file)) { |
pabloxid | 4:2a34139c7246 | 324 | // TODO: handle filesystem errors too |
pabloxid | 3:27b3a889b327 | 325 | int count = fread (buffer, 1, CHUNK_SIZE, file); |
pabloxid | 2:dc9184e97328 | 326 | INFO("Processing Response (%d bytes)!", count); |
pabloxid | 4:2a34139c7246 | 327 | tcpsend (buffer, count); |
pabloxid | 0:fcceff3299be | 328 | } |
pabloxid | 0:fcceff3299be | 329 | INFO("Ending Response !"); |
pabloxid | 0:fcceff3299be | 330 | |
pabloxid | 2:dc9184e97328 | 331 | fclose (file); |
pabloxid | 0:fcceff3299be | 332 | |
pabloxid | 0:fcceff3299be | 333 | } else { |
pabloxid | 0:fcceff3299be | 334 | retval = 404; |
pabloxid | 0:fcceff3299be | 335 | ERR("Requested file was not found !"); |
pabloxid | 0:fcceff3299be | 336 | } |
pabloxid | 0:fcceff3299be | 337 | |
pabloxid | 0:fcceff3299be | 338 | return retval; |
pabloxid | 0:fcceff3299be | 339 | |
pabloxid | 0:fcceff3299be | 340 | } |
pabloxid | 0:fcceff3299be | 341 | |
pabloxid | 0:fcceff3299be | 342 | int HTTPServer::handlePostRequest() { |
pabloxid | 0:fcceff3299be | 343 | |
pabloxid | 3:27b3a889b327 | 344 | // Try receive the body data, if there is any |
pabloxid | 3:27b3a889b327 | 345 | if (msg->body_length > 0) { |
pabloxid | 3:27b3a889b327 | 346 | |
pabloxid | 4:2a34139c7246 | 347 | char post_buffer [msg->body_length]; |
pabloxid | 4:2a34139c7246 | 348 | |
pabloxid | 4:2a34139c7246 | 349 | INFO("Receiving body data. (%i bytes)", msg->body_length); |
pabloxid | 3:27b3a889b327 | 350 | |
pabloxid | 3:27b3a889b327 | 351 | int bytes_read = 0; |
pabloxid | 3:27b3a889b327 | 352 | while (bytes_read < msg->body_length) { |
pabloxid | 4:2a34139c7246 | 353 | int result = cliente->receive_all(post_buffer+bytes_read, msg->body_length-bytes_read); |
pabloxid | 3:27b3a889b327 | 354 | if (result == ERROR) { |
pabloxid | 3:27b3a889b327 | 355 | WARN("Error receiving body data."); |
pabloxid | 3:27b3a889b327 | 356 | break; |
pabloxid | 3:27b3a889b327 | 357 | } |
pabloxid | 3:27b3a889b327 | 358 | bytes_read += result; |
pabloxid | 3:27b3a889b327 | 359 | } |
pabloxid | 3:27b3a889b327 | 360 | |
pabloxid | 3:27b3a889b327 | 361 | INFO("Body data received."); |
pabloxid | 4:2a34139c7246 | 362 | |
pabloxid | 3:27b3a889b327 | 363 | // do something |
pabloxid | 4:2a34139c7246 | 364 | // use the url_decode function :) |
pabloxid | 4:2a34139c7246 | 365 | |
pabloxid | 3:27b3a889b327 | 366 | INFO("Done !\n"); |
pabloxid | 4:2a34139c7246 | 367 | |
pabloxid | 3:27b3a889b327 | 368 | return handleGetRequest(); |
pabloxid | 4:2a34139c7246 | 369 | |
pabloxid | 3:27b3a889b327 | 370 | } else { |
pabloxid | 3:27b3a889b327 | 371 | ERR("POST data not found !"); |
pabloxid | 3:27b3a889b327 | 372 | } |
pabloxid | 3:27b3a889b327 | 373 | |
pabloxid | 0:fcceff3299be | 374 | return 404; |
pabloxid | 0:fcceff3299be | 375 | } |
pabloxid | 0:fcceff3299be | 376 | |
pabloxid | 0:fcceff3299be | 377 | static const char hdrStandard[] = "DNT: 1\r\n" |
pabloxid | 0:fcceff3299be | 378 | "MaxAge: 0\r\n" |
pabloxid | 0:fcceff3299be | 379 | "Connection: Keep-Alive\r\n" |
pabloxid | 2:dc9184e97328 | 380 | "Content-Type: text/html\r\n" // TODO: handle file types |
pabloxid | 0:fcceff3299be | 381 | "Server: mbed embedded\r\n" |
pabloxid | 0:fcceff3299be | 382 | "Accessible: 1\r\n" |
pabloxid | 3:27b3a889b327 | 383 | "Pragma: no-cache\r\n" |
pabloxid | 3:27b3a889b327 | 384 | "Cache-control: no-cache;no-store\r\n" |
pabloxid | 3:27b3a889b327 | 385 | "Expires: 0\r\n" |
pabloxid | 0:fcceff3299be | 386 | "\r\n"; |
pabloxid | 0:fcceff3299be | 387 | |
pabloxid | 2:dc9184e97328 | 388 | void HTTPServer::startResponse (int returnCode, int nLen) { |
pabloxid | 0:fcceff3299be | 389 | |
pabloxid | 2:dc9184e97328 | 390 | INFO("Starting response (%d bytes in total)!", nLen); |
pabloxid | 2:dc9184e97328 | 391 | |
pabloxid | 2:dc9184e97328 | 392 | tcpsend ("HTTP/1.1 %d OK\r\n", returnCode); |
pabloxid | 2:dc9184e97328 | 393 | tcpsend ("Content-Length: %d\r\n", nLen); // Add 2 chars for the terminating CR+LF |
pabloxid | 0:fcceff3299be | 394 | INFO("Sending standard headers !"); |
pabloxid | 2:dc9184e97328 | 395 | tcpsend (hdrStandard); |
pabloxid | 0:fcceff3299be | 396 | |
pabloxid | 2:dc9184e97328 | 397 | INFO("Done !"); |
pabloxid | 0:fcceff3299be | 398 | |
pabloxid | 0:fcceff3299be | 399 | } |
pabloxid | 0:fcceff3299be | 400 | |
pabloxid | 0:fcceff3299be | 401 | static const char* errorPage = "<HTML><HEAD><META content=\"text/html\" http-equiv=Content-Type></HEAD><BODY><h1>Error</h1><P>HTTPServer Error<P></BODY></HTML>\r\n\r\n"; |
pabloxid | 0:fcceff3299be | 402 | |
pabloxid | 0:fcceff3299be | 403 | void HTTPServer::handleError (int errorCode) { |
pabloxid | 0:fcceff3299be | 404 | |
pabloxid | 0:fcceff3299be | 405 | INFO("Handling error !"); |
pabloxid | 0:fcceff3299be | 406 | |
pabloxid | 2:dc9184e97328 | 407 | tcpsend ("HTTP/1.1 %d Error\r\n", errorCode); |
pabloxid | 2:dc9184e97328 | 408 | tcpsend ("Content-Length: %d\r\n", strlen(errorPage)); |
pabloxid | 2:dc9184e97328 | 409 | tcpsend ("Content-Type: text/html\r\nServer: mbed embedded\r\n\r\n"); |
pabloxid | 2:dc9184e97328 | 410 | tcpsend (errorPage); // TODO: better error page (handle error type) |
pabloxid | 0:fcceff3299be | 411 | |
pabloxid | 0:fcceff3299be | 412 | INFO("Done !"); |
pabloxid | 0:fcceff3299be | 413 | |
pabloxid | 0:fcceff3299be | 414 | } |
pabloxid | 3:27b3a889b327 | 415 | |
pabloxid | 3:27b3a889b327 | 416 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
pabloxid | 3:27b3a889b327 | 417 | // UTILS // |
pabloxid | 3:27b3a889b327 | 418 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
pabloxid | 3:27b3a889b327 | 419 | |
pabloxid | 3:27b3a889b327 | 420 | #include <ctype.h> |
pabloxid | 3:27b3a889b327 | 421 | |
pabloxid | 3:27b3a889b327 | 422 | /* Converts a hex character to its integer value */ |
pabloxid | 3:27b3a889b327 | 423 | char from_hex (char ch) { |
pabloxid | 3:27b3a889b327 | 424 | return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10; |
pabloxid | 3:27b3a889b327 | 425 | } |
pabloxid | 3:27b3a889b327 | 426 | |
pabloxid | 3:27b3a889b327 | 427 | /* Returns a url-decoded version of str */ |
pabloxid | 3:27b3a889b327 | 428 | void url_decode (char *str) { |
pabloxid | 3:27b3a889b327 | 429 | char *lee = str, *escribe = str; |
pabloxid | 3:27b3a889b327 | 430 | while (*lee) { |
pabloxid | 3:27b3a889b327 | 431 | if (*lee == '%') { |
pabloxid | 3:27b3a889b327 | 432 | if (lee[1] && lee[2]) { |
pabloxid | 3:27b3a889b327 | 433 | *escribe++ = from_hex(lee[1])<<4 | from_hex(lee[2]); |
pabloxid | 3:27b3a889b327 | 434 | lee += 2; |
pabloxid | 3:27b3a889b327 | 435 | } |
pabloxid | 3:27b3a889b327 | 436 | } else if (*lee == '+') { |
pabloxid | 3:27b3a889b327 | 437 | *escribe++ = ' '; |
pabloxid | 3:27b3a889b327 | 438 | } else { |
pabloxid | 3:27b3a889b327 | 439 | *escribe++ = *lee; |
pabloxid | 3:27b3a889b327 | 440 | } |
pabloxid | 3:27b3a889b327 | 441 | lee++; |
pabloxid | 3:27b3a889b327 | 442 | } |
pabloxid | 3:27b3a889b327 | 443 | *escribe = 0; |
pabloxid | 3:27b3a889b327 | 444 | } |