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:
Sun May 26 22:49:42 2013 +0000
Revision:
1:6b7472d5e9ee
Parent:
0:7a2421e63e74
Child:
2:8653bbcf7e58
Basic functionality demonstrated. One issue exists with error pages, which does not work 100%
;

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 1:6b7472d5e9ee 11 #if (0 && !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 0:7a2421e63e74 23
leihen 0:7a2421e63e74 24 HTTPConnection::HTTPConnection()
leihen 0:7a2421e63e74 25 {
leihen 0:7a2421e63e74 26 }
leihen 0:7a2421e63e74 27
leihen 0:7a2421e63e74 28
leihen 0:7a2421e63e74 29 HTTPConnection::~HTTPConnection()
leihen 0:7a2421e63e74 30 {
leihen 0:7a2421e63e74 31 close();
leihen 0:7a2421e63e74 32 }
leihen 0:7a2421e63e74 33
leihen 0:7a2421e63e74 34 void HTTPConnection::close()
leihen 0:7a2421e63e74 35 {
leihen 0:7a2421e63e74 36 m_Msg.headers.clear();
leihen 0:7a2421e63e74 37 }
leihen 0:7a2421e63e74 38
leihen 0:7a2421e63e74 39 int HTTPConnection::poll()
leihen 0:7a2421e63e74 40 {
leihen 0:7a2421e63e74 41 static char buffer[256] = {};
leihen 0:7a2421e63e74 42 static char echoHeader[256] = {};
leihen 0:7a2421e63e74 43
leihen 0:7a2421e63e74 44
leihen 0:7a2421e63e74 45 int rcvd= 0;
leihen 0:7a2421e63e74 46 INFO("[HTTPConnection]Waiting for new data in connection");
leihen 0:7a2421e63e74 47 // Try receiving request line
leihen 0:7a2421e63e74 48 rcvd = receiveLine(buffer, 255, 3000);
leihen 0:7a2421e63e74 49 if (rcvd == -1) {
leihen 0:7a2421e63e74 50 // there was an error, probably the connection was closed, so close this connection as well
leihen 0:7a2421e63e74 51 INFO("No more data available. Will close this connection now.");
leihen 0:7a2421e63e74 52 close();
leihen 0:7a2421e63e74 53 return -1;
leihen 0:7a2421e63e74 54 }
leihen 0:7a2421e63e74 55
leihen 0:7a2421e63e74 56 // The Request has not yet been received so try it
leihen 0:7a2421e63e74 57 rcvd = parse(buffer);
leihen 0:7a2421e63e74 58 if (rcvd == -1) {
leihen 0:7a2421e63e74 59 // Invalid content received, so close the connection
leihen 0:7a2421e63e74 60 INFO("Invalid message received, so sending negative response and closing connection !");
leihen 0:7a2421e63e74 61 sprintf(echoHeader,"HTTP/1.1 400 NOK\n\rContent-Length: %d\n\rContent-Type: text\n\rConnection: Close\n\r\n\r",strlen(buffer));
leihen 0:7a2421e63e74 62 m_Tcp.set_blocking(true, 1500);
leihen 0:7a2421e63e74 63 m_Tcp.send(echoHeader,strlen(echoHeader));
leihen 0:7a2421e63e74 64 m_Tcp.send(buffer,strlen(buffer));
leihen 0:7a2421e63e74 65 close();
leihen 0:7a2421e63e74 66 rcvd = -1;
leihen 0:7a2421e63e74 67 return -1;
leihen 0:7a2421e63e74 68 }
leihen 0:7a2421e63e74 69 // The request has been received, try receive the body
leihen 0:7a2421e63e74 70 while(rcvd > 0) {
leihen 0:7a2421e63e74 71 rcvd = receiveLine((char*)buffer, 255, 3000);
leihen 0:7a2421e63e74 72 // First check if we received an empty line. This would indicate the end of the message or message body.
leihen 0:7a2421e63e74 73 if (rcvd < 0) {
leihen 0:7a2421e63e74 74 // there was an empty line, so we can start with performing the request
leihen 0:7a2421e63e74 75 INFO("Request Header was received completely. Performing request.");
leihen 0:7a2421e63e74 76 rcvd = 0;
leihen 0:7a2421e63e74 77 break;
leihen 0:7a2421e63e74 78 }
leihen 0:7a2421e63e74 79 else {
leihen 0:7a2421e63e74 80 // add message body
leihen 0:7a2421e63e74 81 if (parseHeader(buffer) == 0) {
leihen 0:7a2421e63e74 82 }
leihen 0:7a2421e63e74 83 else {
leihen 0:7a2421e63e74 84 WARN("Invalid message header received !");
leihen 0:7a2421e63e74 85 }
leihen 0:7a2421e63e74 86 }
leihen 0:7a2421e63e74 87 }
leihen 0:7a2421e63e74 88 if (rcvd == 0) {
leihen 1:6b7472d5e9ee 89 // sprintf(echoHeader,"HTTP/1.1 200 OK\n\rContent-Length: %d\n\rContent-Type: text\n\rConnection: Close\n\r\n\r",strlen(buffer));
leihen 1:6b7472d5e9ee 90 // m_Tcp.set_blocking(true);
leihen 1:6b7472d5e9ee 91 // m_Tcp.send_all(echoHeader,strlen(echoHeader));
leihen 1:6b7472d5e9ee 92 // m_Tcp.send_all(buffer,strlen(buffer));
leihen 0:7a2421e63e74 93
leihen 0:7a2421e63e74 94 /// INSERT PRCESSING OF REQUESST HERE
leihen 0:7a2421e63e74 95 /// END OF PROCESSING REQUEST
leihen 0:7a2421e63e74 96
leihen 0:7a2421e63e74 97 // Do not close the connection, it may be reused
leihen 0:7a2421e63e74 98 }
leihen 0:7a2421e63e74 99 INFO("Leaving poll function!");
leihen 0:7a2421e63e74 100 return rcvd;
leihen 0:7a2421e63e74 101 }
leihen 0:7a2421e63e74 102
leihen 0:7a2421e63e74 103 int HTTPConnection::receiveLine(char* szLine, int nMaxLen, int nTimeout, char cLineTerm)
leihen 0:7a2421e63e74 104 {
leihen 0:7a2421e63e74 105 if ((szLine == NULL) || (nMaxLen == 0))
leihen 0:7a2421e63e74 106 return -1;
leihen 0:7a2421e63e74 107
leihen 0:7a2421e63e74 108 m_Tcp.set_blocking(false);
leihen 0:7a2421e63e74 109
leihen 0:7a2421e63e74 110 Timer tm;
leihen 0:7a2421e63e74 111 int i;
leihen 0:7a2421e63e74 112
leihen 0:7a2421e63e74 113 // Try to receive up to the max number of characters
leihen 0:7a2421e63e74 114 for (i = 0 ; i < nMaxLen-1 ; i++) {
leihen 0:7a2421e63e74 115 int c;
leihen 0:7a2421e63e74 116 c = m_Tcp.receive_all( szLine + i, 1 );
leihen 0:7a2421e63e74 117 // Check that - if no character was currently received - the timeout period is reached.
leihen 0:7a2421e63e74 118 if ((c == 0) || (c==-1)) {
leihen 0:7a2421e63e74 119 // no character was read, so check if operation timed out
leihen 0:7a2421e63e74 120 if (tm.read_ms() > nTimeout) {
leihen 0:7a2421e63e74 121 // Operation timed out
leihen 0:7a2421e63e74 122 INFO("Timeout occured in function 'receiveLine'.");
leihen 0:7a2421e63e74 123 return -1;
leihen 0:7a2421e63e74 124 }
leihen 0:7a2421e63e74 125 }
leihen 0:7a2421e63e74 126
leihen 0:7a2421e63e74 127 // Check if line terminating character was received
leihen 0:7a2421e63e74 128 if (szLine[i] == cLineTerm)
leihen 0:7a2421e63e74 129 break;
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 INFO("receiveLine : \"%s\".", szLine);
leihen 0:7a2421e63e74 140
leihen 0:7a2421e63e74 141 // return number of characters received in the line or return -2 if an empty line was received
leihen 0:7a2421e63e74 142 if ((i == 0) || ((i==1) &&(szLine[0] == '\r')))
leihen 0:7a2421e63e74 143 {
leihen 0:7a2421e63e74 144 // empty line received, so return -2
leihen 0:7a2421e63e74 145 return -2;
leihen 0:7a2421e63e74 146 }
leihen 0:7a2421e63e74 147 return i;
leihen 0:7a2421e63e74 148 }
leihen 0:7a2421e63e74 149
leihen 0:7a2421e63e74 150 int HTTPConnection::parse(const char* buffer)
leihen 0:7a2421e63e74 151 {
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 0:7a2421e63e74 157 vector<std::string> args;
leihen 0:7a2421e63e74 158 args.clear();
leihen 0:7a2421e63e74 159
leihen 0:7a2421e63e74 160 // decompose string into a list of arguments
leihen 0:7a2421e63e74 161 char s = 0; // current starting char
leihen 0:7a2421e63e74 162 static char buff[255] = {};
leihen 0:7a2421e63e74 163 for (int i = 0 ; i < strlen(buffer)+1 ; i++) {
leihen 0:7a2421e63e74 164 if ((buffer[i] == ' ') || (buffer[i] == '\n') || (buffer[i] == 0)) {
leihen 0:7a2421e63e74 165 // new arg found
leihen 0:7a2421e63e74 166 strncpy(buff, &buffer[s], i-s);
leihen 0:7a2421e63e74 167 buff[i-s] = 0;
leihen 0:7a2421e63e74 168 INFO("Found argument \"%s\"", buff);
leihen 0:7a2421e63e74 169 args.push_back(std::string(buff));
leihen 0:7a2421e63e74 170 s = i+1;
leihen 0:7a2421e63e74 171 }
leihen 0:7a2421e63e74 172 }
leihen 0:7a2421e63e74 173
leihen 0:7a2421e63e74 174 if (args.at(0) == "GET") {
leihen 0:7a2421e63e74 175 m_Msg.request = HTTP_RT_GET;
leihen 0:7a2421e63e74 176 m_Msg.uri = args[1];
leihen 0:7a2421e63e74 177 m_Msg.version = args[2];
leihen 0:7a2421e63e74 178 }
leihen 0:7a2421e63e74 179 else {
leihen 0:7a2421e63e74 180 if (args.at(0) == "POST") {
leihen 0:7a2421e63e74 181 m_Msg.request = HTTP_RT_GET;
leihen 0:7a2421e63e74 182 m_Msg.uri = args[1];
leihen 0:7a2421e63e74 183 m_Msg.version = args[2];
leihen 0:7a2421e63e74 184 }
leihen 0:7a2421e63e74 185 else {
leihen 0:7a2421e63e74 186 INFO("unhandled message.");
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 0:7a2421e63e74 195 int HTTPConnection::parseHeader(const char *buffer)
leihen 0:7a2421e63e74 196 {
leihen 0:7a2421e63e74 197 if ((strlen(buffer) <3) || (buffer == NULL))
leihen 0:7a2421e63e74 198 return -1;
leihen 0:7a2421e63e74 199
leihen 0:7a2421e63e74 200 // decompose string into a touple of <field name> : <field value>
leihen 0:7a2421e63e74 201 static char fieldname[256] = {};
leihen 0:7a2421e63e74 202 static char fieldvalue[256] = {};
leihen 0:7a2421e63e74 203 for (int i = 0 ; i < strlen(buffer)+1 ; i++) {
leihen 0:7a2421e63e74 204 if (buffer[i] == ':') {
leihen 0:7a2421e63e74 205 // touple found
leihen 0:7a2421e63e74 206 strncpy(fieldname, buffer, i);
leihen 0:7a2421e63e74 207 fieldname[i] = 0;
leihen 0:7a2421e63e74 208 strcpy(fieldvalue, &buffer[i+1]);
leihen 0:7a2421e63e74 209
leihen 0:7a2421e63e74 210 // m_Msg.headers[fieldname] = fieldvalue;
leihen 0:7a2421e63e74 211
leihen 0:7a2421e63e74 212 INFO("Header name=\"%s\" : value=\"%s\".", fieldname, fieldvalue);
leihen 0:7a2421e63e74 213 return 0;
leihen 0:7a2421e63e74 214 }
leihen 0:7a2421e63e74 215 }
leihen 0:7a2421e63e74 216
leihen 0:7a2421e63e74 217 ERR("Did not recieve a valid header : \"%s\".", buffer);
leihen 0:7a2421e63e74 218 return -1;
leihen 0:7a2421e63e74 219 }