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