Zoltan Hudak / HTTPServer

Dependents:   STM32F407VET6_HTTPServer

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers HTTPConnection.cpp Source File

HTTPConnection.cpp

00001 /* HTTPConnection.cpp */
00002 
00003 #include "mbed.h"
00004 #include "HTTPConnection.h"
00005 #define DEBUG
00006 #include "hl_debug.h"
00007 
00008 #include <vector>
00009 using std::vector;
00010 
00011 using std::string;
00012 
00013 
00014 
00015 const struct HTTPRequestConfig {
00016     const char* request_string;
00017     HTTPRequestType request_type;
00018 } g_requestConfig[] = {
00019     { "GET",    HTTP_RT_GET },
00020     { "POST",   HTTP_RT_POST},
00021     { "PUT",    HTTP_RT_PUT},
00022     { "OPTIONS",HTTP_RT_OPTIONS},
00023     { "HEAD",   HTTP_RT_HEAD},
00024     { "DELETE", HTTP_RT_DELETE},
00025     { "TRACE",  HTTP_RT_TRACE},
00026     { "CONNECT",HTTP_RT_CONNECT}
00027 };
00028 
00029 
00030 HTTPConnection::HTTPConnection(TCPSocket* clnt) : m_Tcp(clnt)
00031 {
00032 }
00033 
00034 
00035 HTTPConnection::~HTTPConnection()
00036 {
00037     close();
00038 }
00039 
00040 void HTTPConnection::close()
00041 {
00042     m_Msg.headers.clear();
00043     m_Tcp->close();
00044 }
00045 
00046 int HTTPConnection::poll()
00047 {
00048     static char buffer[256] = {};
00049     int rcvd= 0;
00050     int ret = 0;
00051     int attri_len = 0;
00052     
00053     INFO("Waiting for new data in connection");
00054     //  Try receiving request line
00055     rcvd = receiveLine(buffer, 255, 3000); 
00056     if (rcvd == -1) {
00057         //  there was an error, probably the connection was closed, so close this connection as well
00058         INFO("No more data available. Will close this connection now.");
00059         close();
00060         return -1;
00061     }
00062 
00063     //  The Request has not yet been received so try it
00064     rcvd = parse(buffer);
00065     if (rcvd == -1) {
00066         //  Invalid content received, so close the connection
00067         INFO("Invalid message received, so sending negative response and closing connection !");
00068         //sprintf(buffer,"HTTP/1.1 400 BadRequest\n\rContent-Length: %d\n\rContent-Type: text\n\r\n\r\n\r",0);
00069         m_Tcp->set_timeout(1500);
00070         //m_Tcp->send(buffer,strlen(buffer));
00071         close();
00072         rcvd = -1;
00073         return -1;
00074     }
00075     //  The request has been received, try receive the body
00076     while(rcvd > 0) {
00077         rcvd = receiveLine((char*)buffer, 255, 3000); 
00078         //  First check if we received an empty line. This would indicate the end of the message or message body.
00079         if (rcvd < 0) {
00080             //  there was an empty line, so we can start with performing the request
00081             INFO("Request Header was received completely. Performing request.");
00082             rcvd = 0;
00083             break;
00084         }
00085         else {
00086             //  add message body
00087             ret = parseHeader(buffer);
00088             if (ret == 0) {
00089                 
00090             }
00091             else {
00092                 attri_len = ret;
00093             }
00094         }
00095     }
00096     
00097     //Receive attribute data
00098     if( attri_len != 0 )
00099     {
00100         m_Tcp->recv(m_Msg.attri, attri_len);
00101     }
00102       
00103     INFO("Leaving poll function!");
00104     return rcvd;
00105 }
00106 
00107 int HTTPConnection::receiveLine(char* szLine, int nMaxLen, int nTimeout, char cLineTerm)
00108 {
00109     if ((szLine == NULL) || (nMaxLen == 0))
00110         return -1;
00111     
00112     szLine[0] = 0;
00113     m_Tcp->set_blocking(false);
00114     
00115 //    if (!m_Tcp->is_connected()) {
00116 //        error("NOT COnnected anymore");
00117 //        return -1;
00118 //    }
00119 
00120     Timer tm;
00121     int i;
00122     
00123     //  Try to receive up to the max number of characters
00124     for (i = 0 ; i < nMaxLen-1 ; i++) {
00125         int c;
00126         c = m_Tcp->recv( szLine + i, 1 );
00127         //  Check that - if no character was currently received - the timeout period is reached.
00128         if ((c == 0) || (c==-1)) {
00129             //  no character was read, so check if operation timed out
00130             //if (tm.read_ms() > nTimeout) {
00131                 //  Operation timed out
00132                 //INFO("Timeout occured in function 'receiveLine'.");
00133                 return -1;
00134             //}
00135         }
00136         
00137         //  Check if line terminating character was received
00138         if (szLine[i] == cLineTerm)
00139         {   
00140             break;
00141         }
00142     }
00143     
00144     //  Terminate with \0
00145     szLine[i] = 0;
00146 
00147     //  Trim for '\r' linefeed at the end
00148     if( (i >0) && (szLine[i-1] == '\r')) {
00149         i--;
00150         szLine[i] = 0;
00151     }
00152     
00153     //  return number of characters received in the line or return -2 if an empty line was received
00154     if ((i == 0) || ((i==1) &&(szLine[0] == '\r')))
00155     {
00156         //  empty line received, so return -2
00157         return -2;
00158     }
00159     return i;    
00160 }
00161 
00162 int HTTPConnection::parse(char* buffer)
00163 {
00164     //  Check if buffer is invalid or its content not long enough.
00165     if ((buffer == NULL) || (strlen(buffer) < 4)) {
00166         ERR("Buffer content is invalid or too short.");
00167         return -1;
00168     }
00169     
00170     std::vector<std::string> args;
00171     args.clear();
00172     
00173     int argno = 0;
00174     //  decompose string into a list of arguments
00175     char s = 0; // current starting char
00176     int nLen = strlen(buffer)+1;
00177     
00178     
00179     //for(int i = 0; i < nLen; i++)
00180         //printf("%d : %c\r\n", i, buffer[i]);
00181     
00182     
00183     for (int i = 0 ; i < nLen ; i++) {
00184         if ((buffer[i] == ' ') || (buffer[i] == '\n') || (buffer[i] == 0)) {
00185             // new arg found
00186             buffer[i] = 0;
00187             if (argno++ == 1) {
00188                 //  its the uri
00189                 // parse the uri args
00190                 parseUriArgs(&buffer[s], m_Msg.args);
00191             }
00192             INFO("Found argument \"%s\"", &buffer[s]);
00193             args.push_back(&buffer[s]);
00194             s = i+1;
00195         }
00196     }
00197     
00198     // store the uri and the HTTP version
00199     m_Msg.uri = args[1];
00200     m_Msg.version = args[2];    
00201     
00202     //  Find matching request type
00203     for (int i = 0 ; i < sizeof(g_requestConfig)/sizeof(struct HTTPRequestConfig) ; i++) {
00204         if (args.at(0) == g_requestConfig[i].request_string) {
00205             m_Msg.request = g_requestConfig[i].request_type;
00206         }
00207     }
00208     args.clear();
00209     
00210     return 1;
00211 }
00212 
00213 
00214 int HTTPConnection::parseHeader(char *buffer)
00215 {
00216     //  Check if the buffer is invalid or if the content is too short to be meaningful
00217     if ((strlen(buffer) <3) || (buffer == NULL))
00218         return -1;
00219         
00220     //Find Content length
00221     if(strncmp(buffer, "Content-Length", 14) == 0)
00222     {
00223         m_Msg.attri_len = atoi(&buffer[16]);
00224         return m_Msg.attri_len;
00225     }
00226     /*
00227     for (int i = 0 ; i < buflen ; i++) {
00228         if (buffer[i] == ':') {
00229             //  touple found
00230             buffer[i] = 0;
00231             value_start = i+1;    
00232             m_Msg.headers[buffer] = &buffer[value_start];
00233             
00234             INFO("Header name=\"%s\" : value=\"%s\".", buffer, &buffer[value_start]);            
00235             return 0;
00236         }
00237     }
00238     */
00239     return 0;
00240     //ERR("Did not recieve a valid header : \"%s\".", buffer);
00241     //return -1;
00242 }
00243 
00244 int HTTPConnection::parseUriArgs(char *buffer, map<string,string>&args)
00245 {
00246     // Check if the buffer is invalid or if the content is too short to be meaningful
00247     if ((strlen(buffer) <3) || (buffer == NULL))
00248         return -1;
00249         
00250     int args_start = -1;
00251     int value_start = -1;
00252     int buflen = strlen(buffer) +1;
00253     const char* argname = NULL;
00254     const char* valuename = NULL;
00255     for (int i = 0; i < buflen ; i++) {
00256         if (args_start == -1) {  // args section not yet found
00257             if (buffer[i] == '?') {  // starts with a question mark, so got it
00258                 buffer[i] = 0;
00259                 args_start = i; //  set the start of the args section
00260                 INFO("Argument section found !");
00261             }
00262         }
00263         else {                  // search arg-value touples
00264             if (argname == NULL) {    //  arg-name found ?
00265                 if (buffer[i] == '=') {
00266                     //  yes, separate the arg-name
00267                     buffer[i] = 0;
00268                     argname = &buffer[args_start];
00269                     value_start = i+1;
00270                     INFO("Argument name %s", argname);
00271                 }
00272             }
00273             else { // search for end of value
00274                 if ((buffer[i] == '&') || (buffer[i] == 0) || (buffer[i] == '\r') || (buffer[i] == '\n')) {
00275                     buffer[i] = 0;
00276                     valuename = &buffer[value_start];
00277                     INFO("Argument value %s", valuename);
00278                     args[argname] = valuename;
00279                     //  reset all indicators
00280                     argname = NULL;
00281                     valuename = NULL;
00282                 }
00283             }
00284         }
00285     }
00286     
00287     
00288     return 0;
00289 }