Single instance HTTP Server using new Ethernet Interface.

Dependents:   EthHTTPServer if201410_section5 _PE2E_12-04_EthernetInterfaceServer MGAS_GR_Peach ... more

Fork of WiFlyHTTPServer by Henry Leinen

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(TCPSocketConnection& 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 }
00044 
00045 int HTTPConnection::poll()
00046 {
00047     static char buffer[256] = {};
00048 
00049     
00050     int rcvd= 0;
00051     INFO("Waiting for new data in connection");
00052     //  Try receiving request line
00053     rcvd = receiveLine(buffer, 255, 3000); 
00054     if (rcvd == -1) {
00055         //  there was an error, probably the connection was closed, so close this connection as well
00056         INFO("No more data available. Will close this connection now.");
00057         close();
00058         return -1;
00059     }
00060 
00061     //  The Request has not yet been received so try it
00062     rcvd = parse(buffer);
00063     if (rcvd == -1) {
00064         //  Invalid content received, so close the connection
00065         INFO("Invalid message received, so sending negative response and closing connection !");
00066         sprintf(buffer,"HTTP/1.1 400 BadRequest\n\rContent-Length: %d\n\rContent-Type: text\n\r\n\r\n\r",0);
00067         m_Tcp.set_blocking(true, 1500);
00068         m_Tcp.send(buffer,strlen(buffer));
00069         close();
00070         rcvd = -1;
00071         return -1;
00072     }
00073     //  The request has been received, try receive the body
00074     while(rcvd > 0) {
00075         rcvd = receiveLine((char*)buffer, 255, 3000); 
00076         //  First check if we received an empty line. This would indicate the end of the message or message body.
00077         if (rcvd < 0) {
00078             //  there was an empty line, so we can start with performing the request
00079             INFO("Request Header was received completely. Performing request.");
00080             rcvd = 0;
00081             break;
00082         }
00083         else {
00084             //  add message body
00085             if (parseHeader(buffer) == 0) {
00086             }
00087             else {
00088                 WARN("Invalid message header received !");
00089             }
00090         }
00091     }             
00092     INFO("Leaving poll function!");
00093     return rcvd;
00094 }
00095 
00096 int HTTPConnection::receiveLine(char* szLine, int nMaxLen, int nTimeout, char cLineTerm)
00097 {
00098     if ((szLine == NULL) || (nMaxLen == 0))
00099         return -1;
00100     
00101     szLine[0] = 0;
00102     m_Tcp.set_blocking(false);
00103     
00104     if (!m_Tcp.is_connected()) {
00105         error("NOT COnnected anymore");
00106         return -1;
00107     }
00108     Timer tm;
00109     int i;
00110     
00111     //  Try to receive up to the max number of characters
00112     for (i = 0 ; i < nMaxLen-1 ; i++) {
00113         int c;
00114         c = m_Tcp.receive( szLine + i, 1 );
00115         //  Check that - if no character was currently received - the timeout period is reached.
00116         if ((c == 0) || (c==-1)) {
00117             //  no character was read, so check if operation timed out
00118             if (tm.read_ms() > nTimeout) {
00119                 //  Operation timed out
00120                 INFO("Timeout occured in function 'receiveLine'.");
00121                 return -1;
00122             }
00123         }
00124         
00125         //  Check if line terminating character was received
00126         if (szLine[i] == cLineTerm)
00127         {   
00128             break;
00129         }
00130     }
00131     //  Terminate with \0
00132     szLine[i] = 0;
00133 
00134     //  Trim for '\r' linefeed at the end
00135     if( (i >0) && (szLine[i-1] == '\r')) {
00136         i--;
00137         szLine[i] = 0;
00138     }
00139     
00140     //  return number of characters received in the line or return -2 if an empty line was received
00141     if ((i == 0) || ((i==1) &&(szLine[0] == '\r')))
00142     {
00143         //  empty line received, so return -2
00144         return -2;
00145     }
00146     return i;    
00147 }
00148 
00149 int HTTPConnection::parse(char* buffer)
00150 {
00151     //  Check if buffer is invalid or its content not long enough.
00152     if ((buffer == NULL) || (strlen(buffer) < 4)) {
00153         ERR("Buffer content is invalid or too short.");
00154         return -1;
00155     }
00156     
00157     std::vector<std::string> args;
00158     args.clear();
00159     
00160     int argno = 0;
00161     //  decompose string into a list of arguments
00162     char s = 0; // current starting char
00163     int nLen = strlen(buffer)+1;
00164     for (int i = 0 ; i < nLen ; i++) {
00165         if ((buffer[i] == ' ') || (buffer[i] == '\n') || (buffer[i] == 0)) {
00166             // new arg found
00167             buffer[i] = 0;
00168             if (argno++ == 1) {
00169                 //  its the uri
00170                 // parse the uri args
00171                 parseUriArgs(&buffer[s], m_Msg.args);
00172             }
00173             INFO("Found argument \"%s\"", &buffer[s]);
00174             args.push_back(&buffer[s]);
00175             s = i+1;
00176         }
00177     }
00178     
00179     // store the uri and the HTTP version
00180     m_Msg.uri = args[1];
00181     m_Msg.version = args[2];    
00182     
00183     //  Find matching request type
00184     for (int i = 0 ; i < sizeof(g_requestConfig)/sizeof(struct HTTPRequestConfig) ; i++) {
00185         if (args.at(0) == g_requestConfig[i].request_string) {
00186             m_Msg.request = g_requestConfig[i].request_type;
00187         }
00188     }
00189     args.clear();
00190     
00191     return 1;
00192 }
00193 
00194 
00195 int HTTPConnection::parseHeader(char *buffer)
00196 {
00197     //  Check if the buffer is invalid or if the content is too short to be meaningful
00198     if ((strlen(buffer) <3) || (buffer == NULL))
00199         return -1;
00200         
00201     //  decompose string into a touple of <field name> : <field value>
00202     int value_start = 0;
00203     int buflen = strlen(buffer)+1;
00204     for (int i = 0 ; i < buflen ; i++) {
00205         if (buffer[i] == ':') {
00206             //  touple found
00207             buffer[i] = 0;
00208             value_start = i+1;    
00209             m_Msg.headers[buffer] = &buffer[value_start];
00210             
00211             INFO("Header name=\"%s\" : value=\"%s\".", buffer, &buffer[value_start]);            
00212             return 0;
00213         }
00214     }
00215     
00216     ERR("Did not recieve a valid header : \"%s\".", buffer);
00217     return -1;
00218 }
00219 
00220 int HTTPConnection::parseUriArgs(char *buffer, map<string,string>&args)
00221 {
00222     // Check if the buffer is invalid or if the content is too short to be meaningful
00223     if ((strlen(buffer) <3) || (buffer == NULL))
00224         return -1;
00225         
00226     int args_start = -1;
00227     int value_start = -1;
00228     int buflen = strlen(buffer) +1;
00229     const char* argname = NULL;
00230     const char* valuename = NULL;
00231     for (int i = 0; i < buflen ; i++) {
00232         if (args_start == -1) {  // args section not yet found
00233             if (buffer[i] == '?') {  // starts with a question mark, so got it
00234                 buffer[i] = 0;
00235                 args_start = i; //  set the start of the args section
00236                 INFO("Argument section found !");
00237             }
00238         }
00239         else {                  // search arg-value touples
00240             if (argname == NULL) {    //  arg-name found ?
00241                 if (buffer[i] == '=') {
00242                     //  yes, separate the arg-name
00243                     buffer[i] = 0;
00244                     argname = &buffer[args_start];
00245                     value_start = i+1;
00246                     INFO("Argument name %s", argname);
00247                 }
00248             }
00249             else { // search for end of value
00250                 if ((buffer[i] == '&') || (buffer[i] == 0) || (buffer[i] == '\r') || (buffer[i] == '\n')) {
00251                     buffer[i] = 0;
00252                     valuename = &buffer[value_start];
00253                     INFO("Argument value %s", valuename);
00254                     args[argname] = valuename;
00255                     //  reset all indicators
00256                     argname = NULL;
00257                     valuename = NULL;
00258                 }
00259             }
00260         }
00261     }
00262     
00263     return 0;
00264 }