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

Dependents:   SmartLight

Fork of HTTPServer by Henry Leinen

Committer:
leihen
Date:
Sat Aug 17 16:17:55 2013 +0000
Revision:
16:cc3f5c53d0d5
Parent:
13:aa5338a5e452
Child:
17:d7186c696729
- Removed old Debug message helper macros and replaced them with new hl_debug.h macros.
; - Renamed debug.h file to hl_debug.h to avoid conflict with EthernetInterface.
; - Fixed incorrectly used debug macro where an ERR was used instead of an INFO

Who changed what in which revision?

UserRevisionLine numberNew contents of line
leihen 0:7a2421e63e74 1 /* HTTPConnection.cpp */
leihen 0:7a2421e63e74 2
leihen 0:7a2421e63e74 3 #include "mbed.h"
leihen 0:7a2421e63e74 4 #include "HTTPConnection.h"
leihen 13:aa5338a5e452 5 #define DEBUG
leihen 16:cc3f5c53d0d5 6 #include "hl_debug.h"
leihen 6:fe661fa9d18a 7
leihen 0:7a2421e63e74 8 #include <vector>
leihen 0:7a2421e63e74 9 using std::vector;
leihen 0:7a2421e63e74 10
leihen 0:7a2421e63e74 11 using std::string;
leihen 0:7a2421e63e74 12
leihen 0:7a2421e63e74 13
leihen 0:7a2421e63e74 14
leihen 4:d065642c32cc 15 const struct HTTPRequestConfig {
leihen 4:d065642c32cc 16 const char* request_string;
leihen 4:d065642c32cc 17 HTTPRequestType request_type;
leihen 4:d065642c32cc 18 } g_requestConfig[] = {
leihen 4:d065642c32cc 19 { "GET", HTTP_RT_GET },
leihen 4:d065642c32cc 20 { "POST", HTTP_RT_POST},
leihen 4:d065642c32cc 21 { "PUT", HTTP_RT_PUT},
leihen 4:d065642c32cc 22 { "OPTIONS",HTTP_RT_OPTIONS},
leihen 4:d065642c32cc 23 { "HEAD", HTTP_RT_HEAD},
leihen 4:d065642c32cc 24 { "DELETE", HTTP_RT_DELETE},
leihen 4:d065642c32cc 25 { "TRACE", HTTP_RT_TRACE},
leihen 4:d065642c32cc 26 { "CONNECT",HTTP_RT_CONNECT}
leihen 4:d065642c32cc 27 };
leihen 4:d065642c32cc 28
leihen 0:7a2421e63e74 29
leihen 13:aa5338a5e452 30 HTTPConnection::HTTPConnection(TCPSocketConnection& clnt) : m_Tcp(clnt)
leihen 0:7a2421e63e74 31 {
leihen 0:7a2421e63e74 32 }
leihen 0:7a2421e63e74 33
leihen 0:7a2421e63e74 34
leihen 0:7a2421e63e74 35 HTTPConnection::~HTTPConnection()
leihen 0:7a2421e63e74 36 {
leihen 0:7a2421e63e74 37 close();
leihen 0:7a2421e63e74 38 }
leihen 0:7a2421e63e74 39
leihen 0:7a2421e63e74 40 void HTTPConnection::close()
leihen 0:7a2421e63e74 41 {
leihen 0:7a2421e63e74 42 m_Msg.headers.clear();
leihen 0:7a2421e63e74 43 }
leihen 0:7a2421e63e74 44
leihen 0:7a2421e63e74 45 int HTTPConnection::poll()
leihen 0:7a2421e63e74 46 {
leihen 0:7a2421e63e74 47 static char buffer[256] = {};
leihen 0:7a2421e63e74 48
leihen 0:7a2421e63e74 49
leihen 0:7a2421e63e74 50 int rcvd= 0;
leihen 9:c2a1462b9b71 51 INFO("Waiting for new data in connection");
leihen 0:7a2421e63e74 52 // Try receiving request line
leihen 0:7a2421e63e74 53 rcvd = receiveLine(buffer, 255, 3000);
leihen 0:7a2421e63e74 54 if (rcvd == -1) {
leihen 0:7a2421e63e74 55 // there was an error, probably the connection was closed, so close this connection as well
leihen 0:7a2421e63e74 56 INFO("No more data available. Will close this connection now.");
leihen 0:7a2421e63e74 57 close();
leihen 0:7a2421e63e74 58 return -1;
leihen 0:7a2421e63e74 59 }
leihen 0:7a2421e63e74 60
leihen 0:7a2421e63e74 61 // The Request has not yet been received so try it
leihen 0:7a2421e63e74 62 rcvd = parse(buffer);
leihen 0:7a2421e63e74 63 if (rcvd == -1) {
leihen 0:7a2421e63e74 64 // Invalid content received, so close the connection
leihen 0:7a2421e63e74 65 INFO("Invalid message received, so sending negative response and closing connection !");
leihen 11:3943841e1798 66 sprintf(buffer,"HTTP/1.1 400 BadRequest\n\rContent-Length: %d\n\rContent-Type: text\n\r\n\r\n\r",0);
leihen 0:7a2421e63e74 67 m_Tcp.set_blocking(true, 1500);
leihen 0:7a2421e63e74 68 m_Tcp.send(buffer,strlen(buffer));
leihen 0:7a2421e63e74 69 close();
leihen 0:7a2421e63e74 70 rcvd = -1;
leihen 0:7a2421e63e74 71 return -1;
leihen 0:7a2421e63e74 72 }
leihen 0:7a2421e63e74 73 // The request has been received, try receive the body
leihen 0:7a2421e63e74 74 while(rcvd > 0) {
leihen 0:7a2421e63e74 75 rcvd = receiveLine((char*)buffer, 255, 3000);
leihen 0:7a2421e63e74 76 // First check if we received an empty line. This would indicate the end of the message or message body.
leihen 0:7a2421e63e74 77 if (rcvd < 0) {
leihen 0:7a2421e63e74 78 // there was an empty line, so we can start with performing the request
leihen 0:7a2421e63e74 79 INFO("Request Header was received completely. Performing request.");
leihen 0:7a2421e63e74 80 rcvd = 0;
leihen 0:7a2421e63e74 81 break;
leihen 0:7a2421e63e74 82 }
leihen 0:7a2421e63e74 83 else {
leihen 0:7a2421e63e74 84 // add message body
leihen 0:7a2421e63e74 85 if (parseHeader(buffer) == 0) {
leihen 0:7a2421e63e74 86 }
leihen 0:7a2421e63e74 87 else {
leihen 0:7a2421e63e74 88 WARN("Invalid message header received !");
leihen 0:7a2421e63e74 89 }
leihen 0:7a2421e63e74 90 }
leihen 0:7a2421e63e74 91 }
leihen 0:7a2421e63e74 92 INFO("Leaving poll function!");
leihen 0:7a2421e63e74 93 return rcvd;
leihen 0:7a2421e63e74 94 }
leihen 0:7a2421e63e74 95
leihen 0:7a2421e63e74 96 int HTTPConnection::receiveLine(char* szLine, int nMaxLen, int nTimeout, char cLineTerm)
leihen 0:7a2421e63e74 97 {
leihen 0:7a2421e63e74 98 if ((szLine == NULL) || (nMaxLen == 0))
leihen 0:7a2421e63e74 99 return -1;
leihen 0:7a2421e63e74 100
leihen 13:aa5338a5e452 101 szLine[0] = 0;
leihen 0:7a2421e63e74 102 m_Tcp.set_blocking(false);
leihen 0:7a2421e63e74 103
leihen 13:aa5338a5e452 104 if (!m_Tcp.is_connected()) {
leihen 13:aa5338a5e452 105 error("NOT COnnected anymore");
leihen 13:aa5338a5e452 106 return -1;
leihen 13:aa5338a5e452 107 }
leihen 0:7a2421e63e74 108 Timer tm;
leihen 0:7a2421e63e74 109 int i;
leihen 0:7a2421e63e74 110
leihen 0:7a2421e63e74 111 // Try to receive up to the max number of characters
leihen 0:7a2421e63e74 112 for (i = 0 ; i < nMaxLen-1 ; i++) {
leihen 0:7a2421e63e74 113 int c;
leihen 11:3943841e1798 114 c = m_Tcp.receive( szLine + i, 1 );
leihen 0:7a2421e63e74 115 // Check that - if no character was currently received - the timeout period is reached.
leihen 0:7a2421e63e74 116 if ((c == 0) || (c==-1)) {
leihen 0:7a2421e63e74 117 // no character was read, so check if operation timed out
leihen 0:7a2421e63e74 118 if (tm.read_ms() > nTimeout) {
leihen 0:7a2421e63e74 119 // Operation timed out
leihen 0:7a2421e63e74 120 INFO("Timeout occured in function 'receiveLine'.");
leihen 0:7a2421e63e74 121 return -1;
leihen 0:7a2421e63e74 122 }
leihen 0:7a2421e63e74 123 }
leihen 0:7a2421e63e74 124
leihen 0:7a2421e63e74 125 // Check if line terminating character was received
leihen 0:7a2421e63e74 126 if (szLine[i] == cLineTerm)
leihen 13:aa5338a5e452 127 {
leihen 0:7a2421e63e74 128 break;
leihen 13:aa5338a5e452 129 }
leihen 0:7a2421e63e74 130 }
leihen 0:7a2421e63e74 131 // Terminate with \0
leihen 0:7a2421e63e74 132 szLine[i] = 0;
leihen 0:7a2421e63e74 133
leihen 0:7a2421e63e74 134 // Trim for '\r' linefeed at the end
leihen 0:7a2421e63e74 135 if( (i >0) && (szLine[i-1] == '\r')) {
leihen 0:7a2421e63e74 136 i--;
leihen 0:7a2421e63e74 137 szLine[i] = 0;
leihen 0:7a2421e63e74 138 }
leihen 0:7a2421e63e74 139
leihen 0:7a2421e63e74 140 // return number of characters received in the line or return -2 if an empty line was received
leihen 0:7a2421e63e74 141 if ((i == 0) || ((i==1) &&(szLine[0] == '\r')))
leihen 0:7a2421e63e74 142 {
leihen 0:7a2421e63e74 143 // empty line received, so return -2
leihen 0:7a2421e63e74 144 return -2;
leihen 0:7a2421e63e74 145 }
leihen 0:7a2421e63e74 146 return i;
leihen 0:7a2421e63e74 147 }
leihen 0:7a2421e63e74 148
leihen 2:8653bbcf7e58 149 int HTTPConnection::parse(char* buffer)
leihen 0:7a2421e63e74 150 {
leihen 4:d065642c32cc 151 // Check if buffer is invalid or its content not long enough.
leihen 0:7a2421e63e74 152 if ((buffer == NULL) || (strlen(buffer) < 4)) {
leihen 0:7a2421e63e74 153 ERR("Buffer content is invalid or too short.");
leihen 0:7a2421e63e74 154 return -1;
leihen 0:7a2421e63e74 155 }
leihen 0:7a2421e63e74 156
leihen 4:d065642c32cc 157 std::vector<std::string> args;
leihen 0:7a2421e63e74 158 args.clear();
leihen 0:7a2421e63e74 159
leihen 4:d065642c32cc 160 int argno = 0;
leihen 0:7a2421e63e74 161 // decompose string into a list of arguments
leihen 0:7a2421e63e74 162 char s = 0; // current starting char
leihen 2:8653bbcf7e58 163 int nLen = strlen(buffer)+1;
leihen 2:8653bbcf7e58 164 for (int i = 0 ; i < nLen ; i++) {
leihen 0:7a2421e63e74 165 if ((buffer[i] == ' ') || (buffer[i] == '\n') || (buffer[i] == 0)) {
leihen 0:7a2421e63e74 166 // new arg found
leihen 2:8653bbcf7e58 167 buffer[i] = 0;
leihen 4:d065642c32cc 168 if (argno++ == 1) {
leihen 4:d065642c32cc 169 // its the uri
leihen 4:d065642c32cc 170 // parse the uri args
leihen 4:d065642c32cc 171 parseUriArgs(&buffer[s], m_Msg.args);
leihen 4:d065642c32cc 172 }
leihen 2:8653bbcf7e58 173 INFO("Found argument \"%s\"", &buffer[s]);
leihen 2:8653bbcf7e58 174 args.push_back(&buffer[s]);
leihen 0:7a2421e63e74 175 s = i+1;
leihen 0:7a2421e63e74 176 }
leihen 0:7a2421e63e74 177 }
leihen 4:d065642c32cc 178
leihen 4:d065642c32cc 179 // store the uri and the HTTP version
leihen 4:d065642c32cc 180 m_Msg.uri = args[1];
leihen 4:d065642c32cc 181 m_Msg.version = args[2];
leihen 4:d065642c32cc 182
leihen 4:d065642c32cc 183 // Find matching request type
leihen 4:d065642c32cc 184 for (int i = 0 ; i < sizeof(g_requestConfig)/sizeof(struct HTTPRequestConfig) ; i++) {
leihen 4:d065642c32cc 185 if (args.at(0) == g_requestConfig[i].request_string) {
leihen 4:d065642c32cc 186 m_Msg.request = g_requestConfig[i].request_type;
leihen 0:7a2421e63e74 187 }
leihen 0:7a2421e63e74 188 }
leihen 0:7a2421e63e74 189 args.clear();
leihen 0:7a2421e63e74 190
leihen 0:7a2421e63e74 191 return 1;
leihen 0:7a2421e63e74 192 }
leihen 0:7a2421e63e74 193
leihen 0:7a2421e63e74 194
leihen 3:d6224049b3bf 195 int HTTPConnection::parseHeader(char *buffer)
leihen 0:7a2421e63e74 196 {
leihen 4:d065642c32cc 197 // Check if the buffer is invalid or if the content is too short to be meaningful
leihen 0:7a2421e63e74 198 if ((strlen(buffer) <3) || (buffer == NULL))
leihen 0:7a2421e63e74 199 return -1;
leihen 0:7a2421e63e74 200
leihen 0:7a2421e63e74 201 // decompose string into a touple of <field name> : <field value>
leihen 3:d6224049b3bf 202 int value_start = 0;
leihen 3:d6224049b3bf 203 int buflen = strlen(buffer)+1;
leihen 3:d6224049b3bf 204 for (int i = 0 ; i < buflen ; i++) {
leihen 0:7a2421e63e74 205 if (buffer[i] == ':') {
leihen 0:7a2421e63e74 206 // touple found
leihen 3:d6224049b3bf 207 buffer[i] = 0;
leihen 3:d6224049b3bf 208 value_start = i+1;
leihen 3:d6224049b3bf 209 m_Msg.headers[buffer] = &buffer[value_start];
leihen 0:7a2421e63e74 210
leihen 3:d6224049b3bf 211 INFO("Header name=\"%s\" : value=\"%s\".", buffer, &buffer[value_start]);
leihen 0:7a2421e63e74 212 return 0;
leihen 0:7a2421e63e74 213 }
leihen 0:7a2421e63e74 214 }
leihen 0:7a2421e63e74 215
leihen 0:7a2421e63e74 216 ERR("Did not recieve a valid header : \"%s\".", buffer);
leihen 0:7a2421e63e74 217 return -1;
leihen 0:7a2421e63e74 218 }
leihen 4:d065642c32cc 219
leihen 4:d065642c32cc 220 int HTTPConnection::parseUriArgs(char *buffer, map<string,string>&args)
leihen 4:d065642c32cc 221 {
leihen 4:d065642c32cc 222 // Check if the buffer is invalid or if the content is too short to be meaningful
leihen 4:d065642c32cc 223 if ((strlen(buffer) <3) || (buffer == NULL))
leihen 4:d065642c32cc 224 return -1;
leihen 4:d065642c32cc 225
leihen 4:d065642c32cc 226 int args_start = -1;
leihen 4:d065642c32cc 227 int value_start = -1;
leihen 4:d065642c32cc 228 int buflen = strlen(buffer) +1;
leihen 4:d065642c32cc 229 const char* argname = NULL;
leihen 4:d065642c32cc 230 const char* valuename = NULL;
leihen 4:d065642c32cc 231 for (int i = 0; i < buflen ; i++) {
leihen 4:d065642c32cc 232 if (args_start == -1) { // args section not yet found
leihen 4:d065642c32cc 233 if (buffer[i] == '?') { // starts with a question mark, so got it
leihen 4:d065642c32cc 234 buffer[i] = 0;
leihen 4:d065642c32cc 235 args_start = i; // set the start of the args section
leihen 4:d065642c32cc 236 INFO("Argument section found !");
leihen 4:d065642c32cc 237 }
leihen 4:d065642c32cc 238 }
leihen 4:d065642c32cc 239 else { // search arg-value touples
leihen 4:d065642c32cc 240 if (argname == NULL) { // arg-name found ?
leihen 4:d065642c32cc 241 if (buffer[i] == '=') {
leihen 4:d065642c32cc 242 // yes, separate the arg-name
leihen 4:d065642c32cc 243 buffer[i] = 0;
leihen 4:d065642c32cc 244 argname = &buffer[args_start];
leihen 4:d065642c32cc 245 value_start = i+1;
leihen 4:d065642c32cc 246 INFO("Argument name %s", argname);
leihen 4:d065642c32cc 247 }
leihen 4:d065642c32cc 248 }
leihen 4:d065642c32cc 249 else { // search for end of value
leihen 4:d065642c32cc 250 if ((buffer[i] == '&') || (buffer[i] == 0) || (buffer[i] == '\r') || (buffer[i] == '\n')) {
leihen 4:d065642c32cc 251 buffer[i] = 0;
leihen 4:d065642c32cc 252 valuename = &buffer[value_start];
leihen 4:d065642c32cc 253 INFO("Argument value %s", valuename);
leihen 4:d065642c32cc 254 args[argname] = valuename;
leihen 4:d065642c32cc 255 // reset all indicators
leihen 4:d065642c32cc 256 argname = NULL;
leihen 4:d065642c32cc 257 valuename = NULL;
leihen 4:d065642c32cc 258 }
leihen 4:d065642c32cc 259 }
leihen 4:d065642c32cc 260 }
leihen 4:d065642c32cc 261 }
leihen 4:d065642c32cc 262
leihen 4:d065642c32cc 263 return 0;
leihen 4:d065642c32cc 264 }