aa
Dependents: Internet-Piano_WIZwiki-W7500
Fork of httpServer by
Diff: HTTPConnection.cpp
- Revision:
- 0:e59cc54df17c
diff -r 000000000000 -r e59cc54df17c HTTPConnection.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HTTPConnection.cpp Mon Jun 29 09:03:40 2015 +0000 @@ -0,0 +1,287 @@ +/* HTTPConnection.cpp */ + +#include "mbed.h" +#include "HTTPConnection.h" +//#define DEBUG +#include "hl_debug.h" + +#include <vector> +using std::vector; + +using std::string; + + + +const struct HTTPRequestConfig { + const char* request_string; + HTTPRequestType request_type; +} g_requestConfig[] = { + { "GET", HTTP_RT_GET }, + { "POST", HTTP_RT_POST}, + { "PUT", HTTP_RT_PUT}, + { "OPTIONS",HTTP_RT_OPTIONS}, + { "HEAD", HTTP_RT_HEAD}, + { "DELETE", HTTP_RT_DELETE}, + { "TRACE", HTTP_RT_TRACE}, + { "CONNECT",HTTP_RT_CONNECT} +}; + + +HTTPConnection::HTTPConnection(TCPSocketConnection& clnt) : m_Tcp(clnt) +{ +} + + +HTTPConnection::~HTTPConnection() +{ + close(); +} + +void HTTPConnection::close() +{ + m_Msg.headers.clear(); +} + +int HTTPConnection::poll() +{ + static char buffer[256] = {}; + int rcvd= 0; + int ret = 0; + int attri_len = 0; + + INFO("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(buffer,"HTTP/1.1 400 BadRequest\n\rContent-Length: %d\n\rContent-Type: text\n\r\n\r\n\r",0); + m_Tcp.set_blocking(true, 1500); + //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 + ret = parseHeader(buffer); + if (ret == 0) { + + } + else { + attri_len = ret; + } + } + } + + //Receive attribute data + if( attri_len != 0 ) + { + m_Tcp.receive( m_Msg.attri, attri_len ); + } + + INFO("Leaving poll function!"); + return rcvd; +} + +int HTTPConnection::receiveLine(char* szLine, int nMaxLen, int nTimeout, char cLineTerm) +{ + if ((szLine == NULL) || (nMaxLen == 0)) + return -1; + + szLine[0] = 0; + m_Tcp.set_blocking(false); + + if (!m_Tcp.is_connected()) { + error("NOT COnnected anymore"); + return -1; + } + 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( 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; + } + + // 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(char* buffer) +{ + // Check if buffer is invalid or its content not long enough. + if ((buffer == NULL) || (strlen(buffer) < 4)) { + ERR("Buffer content is invalid or too short."); + return -1; + } + + std::vector<std::string> args; + args.clear(); + + int argno = 0; + // decompose string into a list of arguments + char s = 0; // current starting char + int nLen = strlen(buffer)+1; + + + //for(int i = 0; i < nLen; i++) + //printf("%d : %c\r\n", i, buffer[i]); + + + for (int i = 0 ; i < nLen ; i++) { + if ((buffer[i] == ' ') || (buffer[i] == '\n') || (buffer[i] == 0)) { + // new arg found + buffer[i] = 0; + if (argno++ == 1) { + // its the uri + // parse the uri args + parseUriArgs(&buffer[s], m_Msg.args); + } + INFO("Found argument \"%s\"", &buffer[s]); + args.push_back(&buffer[s]); + s = i+1; + } + } + + // store the uri and the HTTP version + m_Msg.uri = args[1]; + m_Msg.version = args[2]; + + // Find matching request type + for (int i = 0 ; i < sizeof(g_requestConfig)/sizeof(struct HTTPRequestConfig) ; i++) { + if (args.at(0) == g_requestConfig[i].request_string) { + m_Msg.request = g_requestConfig[i].request_type; + } + } + args.clear(); + + return 1; +} + + +int HTTPConnection::parseHeader(char *buffer) +{ + // Check if the buffer is invalid or if the content is too short to be meaningful + if ((strlen(buffer) <3) || (buffer == NULL)) + return -1; + + //Find Content length + if(strncmp(buffer, "Content-Length", 14) == 0) + { + m_Msg.attri_len = atoi(&buffer[16]); + return m_Msg.attri_len; + } + /* + for (int i = 0 ; i < buflen ; i++) { + if (buffer[i] == ':') { + // touple found + buffer[i] = 0; + value_start = i+1; + m_Msg.headers[buffer] = &buffer[value_start]; + + INFO("Header name=\"%s\" : value=\"%s\".", buffer, &buffer[value_start]); + return 0; + } + } + */ + return 0; + //ERR("Did not recieve a valid header : \"%s\".", buffer); + //return -1; +} + +int HTTPConnection::parseUriArgs(char *buffer, map<string,string>&args) +{ + // Check if the buffer is invalid or if the content is too short to be meaningful + if ((strlen(buffer) <3) || (buffer == NULL)) + return -1; + + int args_start = -1; + int value_start = -1; + int buflen = strlen(buffer) +1; + const char* argname = NULL; + const char* valuename = NULL; + for (int i = 0; i < buflen ; i++) { + if (args_start == -1) { // args section not yet found + if (buffer[i] == '?') { // starts with a question mark, so got it + buffer[i] = 0; + args_start = i; // set the start of the args section + INFO("Argument section found !"); + } + } + else { // search arg-value touples + if (argname == NULL) { // arg-name found ? + if (buffer[i] == '=') { + // yes, separate the arg-name + buffer[i] = 0; + argname = &buffer[args_start]; + value_start = i+1; + INFO("Argument name %s", argname); + } + } + else { // search for end of value + if ((buffer[i] == '&') || (buffer[i] == 0) || (buffer[i] == '\r') || (buffer[i] == '\n')) { + buffer[i] = 0; + valuename = &buffer[value_start]; + INFO("Argument value %s", valuename); + args[argname] = valuename; + // reset all indicators + argname = NULL; + valuename = NULL; + } + } + } + } + + + return 0; +}