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 Jun 01 16:49:17 2013 +0000
Revision:
6:fe661fa9d18a
Parent:
4:d065642c32cc
Child:
9:c2a1462b9b71
Added DEBUG preprocessor constant to each file.
; Added non-blocking polling function.

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