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.
Fork of HTTPServer by
Diff: HTTPConnection.cpp
- Revision:
- 0:7a2421e63e74
- Child:
- 1:6b7472d5e9ee
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HTTPConnection.cpp Sun May 26 20:13:28 2013 +0000 @@ -0,0 +1,219 @@ +/* HTTPConnection.cpp */ + +#include "mbed.h" +#include "HTTPConnection.h" + +#include <vector> +using std::vector; + +using std::string; + +#if (1 && !defined(TARGET_LPC11U24)) +#define INFO(x, ...) std::printf("[HttpConnection : INFO]"x"\r\n", ##__VA_ARGS__); +#define WARN(x, ...) std::printf("[HttpConnection : WARN]"x"\r\n", ##__VA_ARGS__); +#define ERR(x, ...) std::printf("[HttpConnection : ERR]"x"\r\n", ##__VA_ARGS__); +#else +#define INFO(x, ...) +#define WARN(x, ...) +#define ERR(x, ...) +#endif + + + + +HTTPConnection::HTTPConnection() +{ +} + + +HTTPConnection::~HTTPConnection() +{ + close(); +} + +void HTTPConnection::close() +{ + m_Msg.headers.clear(); +} + +int HTTPConnection::poll() +{ + static char buffer[256] = {}; + static char echoHeader[256] = {}; + + + int rcvd= 0; + INFO("[HTTPConnection]Waiting for new data in connection"); + // Try receiving request line + rcvd = receiveLine(buffer, 255, 3000); + if (rcvd == -1) { + // there was an error, probably the connection was closed, so close this connection as well + INFO("No more data available. Will close this connection now."); + close(); + return -1; + } + + // The Request has not yet been received so try it + rcvd = parse(buffer); + if (rcvd == -1) { + // Invalid content received, so close the connection + INFO("Invalid message received, so sending negative response and closing connection !"); + sprintf(echoHeader,"HTTP/1.1 400 NOK\n\rContent-Length: %d\n\rContent-Type: text\n\rConnection: Close\n\r\n\r",strlen(buffer)); + m_Tcp.set_blocking(true, 1500); + m_Tcp.send(echoHeader,strlen(echoHeader)); + m_Tcp.send(buffer,strlen(buffer)); + close(); + rcvd = -1; + return -1; + } + // The request has been received, try receive the body + while(rcvd > 0) { + rcvd = receiveLine((char*)buffer, 255, 3000); + // First check if we received an empty line. This would indicate the end of the message or message body. + if (rcvd < 0) { + // there was an empty line, so we can start with performing the request + INFO("Request Header was received completely. Performing request."); + rcvd = 0; + break; + } + else { + // add message body + if (parseHeader(buffer) == 0) { + } + else { + WARN("Invalid message header received !"); + } + } + } + if (rcvd == 0) { + sprintf(echoHeader,"HTTP/1.1 200 OK\n\rContent-Length: %d\n\rContent-Type: text\n\rConnection: Close\n\r\n\r",strlen(buffer)); + m_Tcp.set_blocking(true); + m_Tcp.send_all(echoHeader,strlen(echoHeader)); + m_Tcp.send_all(buffer,strlen(buffer)); + + /// INSERT PRCESSING OF REQUESST HERE + /// END OF PROCESSING REQUEST + + // Do not close the connection, it may be reused + } + INFO("Leaving poll function!"); + return rcvd; +} + +int HTTPConnection::receiveLine(char* szLine, int nMaxLen, int nTimeout, char cLineTerm) +{ + if ((szLine == NULL) || (nMaxLen == 0)) + return -1; + + m_Tcp.set_blocking(false); + + Timer tm; + int i; + + // Try to receive up to the max number of characters + for (i = 0 ; i < nMaxLen-1 ; i++) { + int c; + c = m_Tcp.receive_all( szLine + i, 1 ); + // Check that - if no character was currently received - the timeout period is reached. + if ((c == 0) || (c==-1)) { + // no character was read, so check if operation timed out + if (tm.read_ms() > nTimeout) { + // Operation timed out + INFO("Timeout occured in function 'receiveLine'."); + return -1; + } + } + + // Check if line terminating character was received + if (szLine[i] == cLineTerm) + break; + } + // Terminate with \0 + szLine[i] = 0; + + // Trim for '\r' linefeed at the end + if( (i >0) && (szLine[i-1] == '\r')) { + i--; + szLine[i] = 0; + } + INFO("receiveLine : \"%s\".", szLine); + + // return number of characters received in the line or return -2 if an empty line was received + if ((i == 0) || ((i==1) &&(szLine[0] == '\r'))) + { + // empty line received, so return -2 + return -2; + } + return i; +} + +int HTTPConnection::parse(const char* buffer) +{ + if ((buffer == NULL) || (strlen(buffer) < 4)) { + ERR("Buffer content is invalid or too short."); + return -1; + } + + vector<std::string> args; + args.clear(); + + // decompose string into a list of arguments + char s = 0; // current starting char + static char buff[255] = {}; + for (int i = 0 ; i < strlen(buffer)+1 ; i++) { + if ((buffer[i] == ' ') || (buffer[i] == '\n') || (buffer[i] == 0)) { + // new arg found + strncpy(buff, &buffer[s], i-s); + buff[i-s] = 0; + INFO("Found argument \"%s\"", buff); + args.push_back(std::string(buff)); + s = i+1; + } + } + + if (args.at(0) == "GET") { + m_Msg.request = HTTP_RT_GET; + m_Msg.uri = args[1]; + m_Msg.version = args[2]; + } + else { + if (args.at(0) == "POST") { + m_Msg.request = HTTP_RT_GET; + m_Msg.uri = args[1]; + m_Msg.version = args[2]; + } + else { + INFO("unhandled message."); + } + } + args.clear(); + + return 1; +} + + +int HTTPConnection::parseHeader(const char *buffer) +{ + if ((strlen(buffer) <3) || (buffer == NULL)) + return -1; + + // decompose string into a touple of <field name> : <field value> + static char fieldname[256] = {}; + static char fieldvalue[256] = {}; + for (int i = 0 ; i < strlen(buffer)+1 ; i++) { + if (buffer[i] == ':') { + // touple found + strncpy(fieldname, buffer, i); + fieldname[i] = 0; + strcpy(fieldvalue, &buffer[i+1]); + +// m_Msg.headers[fieldname] = fieldvalue; + + INFO("Header name=\"%s\" : value=\"%s\".", fieldname, fieldvalue); + return 0; + } + } + + ERR("Did not recieve a valid header : \"%s\".", buffer); + return -1; +}