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:
Tue May 28 21:20:58 2013 +0000
Revision:
4:d065642c32cc
Parent:
3:d6224049b3bf
Child:
6:fe661fa9d18a
Added parameter parsing from uri in http webrequest.
; Documentation updated.

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