Version of http://mbed.org/cookbook/NetServicesTribute with setting set the same for LPC2368

Dependents:   UDPSocketExample 24LCxx_I2CApp WeatherPlatform_pachube HvZServerLib ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers HTTPRequestHandler.cpp Source File

HTTPRequestHandler.cpp

00001 
00002 /*
00003 Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
00004  
00005 Permission is hereby granted, free of charge, to any person obtaining a copy
00006 of this software and associated documentation files (the "Software"), to deal
00007 in the Software without restriction, including without limitation the rights
00008 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00009 copies of the Software, and to permit persons to whom the Software is
00010 furnished to do so, subject to the following conditions:
00011  
00012 The above copyright notice and this permission notice shall be included in
00013 all copies or substantial portions of the Software.
00014  
00015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00017 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00018 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00019 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00020 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00021 THE SOFTWARE.
00022 */
00023 
00024 #include "core/netservice.h"
00025 #include "HTTPRequestHandler.h"
00026 
00027 #include <string.h>
00028 
00029 //#define __DEBUG
00030 #include "dbg/dbg.h"
00031 
00032 #define HTTP_REQUEST_TIMEOUT 5000
00033 
00034 HTTPRequestHandler::HTTPRequestHandler(const char* rootPath, const char* path, TCPSocket* pTCPSocket) : NetService(), 
00035 m_pTCPSocket(pTCPSocket), m_reqHeaders(), m_respHeaders(),
00036 m_rootPath(rootPath), m_path(path), m_errc(200),
00037 m_watchdog(), m_timeout(0), m_closed(false), m_headersSent(false) //OK
00038 {
00039   //Read & parse headers
00040   readHeaders();
00041   m_pTCPSocket->setOnEvent(this, &HTTPRequestHandler::onTCPSocketEvent);
00042   setTimeout(HTTP_REQUEST_TIMEOUT);
00043 }
00044 
00045 HTTPRequestHandler::~HTTPRequestHandler()
00046 {
00047   close();
00048 }
00049 
00050 void HTTPRequestHandler::onTimeout() //Connection has timed out
00051 {
00052   close();
00053 }
00054 
00055 void HTTPRequestHandler::close() //Close socket and destroy data
00056 {
00057   if(m_closed)
00058     return;
00059   m_closed = true; //Prevent recursive calling or calling on an object being destructed by someone else
00060   m_watchdog.detach();
00061   onClose();
00062   m_pTCPSocket->resetOnEvent();
00063   m_pTCPSocket->close();
00064   delete m_pTCPSocket; //Can safely destroy socket
00065   NetService::close();
00066 }
00067 
00068 map<string, string>& HTTPRequestHandler::reqHeaders() //const
00069 {
00070   return m_reqHeaders;
00071 }
00072 
00073 string& HTTPRequestHandler::path() //const
00074 {
00075   return m_path;
00076 }
00077 
00078 int HTTPRequestHandler::dataLen() const
00079 {
00080   map<string,string>::iterator it;
00081   it = m_reqHeaders.find("Content-Length");
00082   if( it == m_reqHeaders.end() )
00083   {
00084     return 0;
00085   }
00086   return atoi((*it).second.c_str()); //return 0 if parse fails, so that's fine
00087 }
00088 
00089 int HTTPRequestHandler::readData(char* buf, int len)
00090 {
00091   return m_pTCPSocket->recv(buf, len);
00092 }
00093 
00094 string& HTTPRequestHandler::rootPath() //const
00095 {
00096   return m_rootPath;
00097 }
00098 
00099 void HTTPRequestHandler::setErrCode(int errc)
00100 {
00101   m_errc = errc;
00102 }
00103 
00104 void HTTPRequestHandler::setContentLen(int len)
00105 {
00106   char len_str[6] = {0};
00107   sprintf(len_str, "%d", len);
00108   respHeaders()["Content-Length"] = len_str;
00109 }
00110   
00111 map<string, string>& HTTPRequestHandler::respHeaders()
00112 {
00113   return m_respHeaders;
00114 }
00115 
00116 int HTTPRequestHandler::writeData(const char* buf, int len)
00117 {
00118   if(!m_headersSent)
00119   {
00120     m_headersSent = true;
00121     writeHeaders();
00122   }
00123   
00124   return m_pTCPSocket->send(buf, len);
00125 }
00126 
00127 void HTTPRequestHandler::setTimeout(int ms)
00128 {
00129   m_timeout = 1000*ms;
00130   resetTimeout();
00131 }
00132 
00133 void HTTPRequestHandler::resetTimeout()
00134 {
00135   m_watchdog.detach();
00136   m_watchdog.attach_us<HTTPRequestHandler>(this, &HTTPRequestHandler::onTimeout, m_timeout);
00137 }
00138 
00139 
00140 void HTTPRequestHandler::readHeaders()
00141 {
00142   static char line[128];
00143   static char key[128];
00144   static char value[128];
00145   while( readLine(line, 128) > 0) //if == 0, it is an empty line = end of headers
00146   {
00147     int n = sscanf(line, "%[^:]: %[^\n]", key, value);
00148     if ( n == 2 )
00149     {
00150       DBG("\r\nRead header : %s : %s\r\n", key, value);
00151       m_reqHeaders[key] = value;
00152     }
00153     //TODO: Impl n==1 case (part 2 of previous header)
00154   }
00155 }
00156 
00157 void HTTPRequestHandler::writeHeaders() //Called at the first writeData call
00158 {
00159   static char line[128];
00160   
00161   //Response line
00162   sprintf(line, "HTTP/1.1 %d MbedInfo\r\n", m_errc); //Not a violation of the standard not to include the descriptive text
00163   m_pTCPSocket->send(line, strlen(line));
00164   
00165   map<string,string>::iterator it;
00166   while( !m_respHeaders.empty() )
00167   {
00168     it = m_respHeaders.begin();
00169     sprintf(line, "%s: %s\r\n", (*it).first.c_str(), (*it).second.c_str() );
00170     DBG("\r\n%s", line);
00171     m_pTCPSocket->send(line, strlen(line));
00172     m_respHeaders.erase(it);
00173   }
00174   m_pTCPSocket->send("\r\n",2); //End of head
00175 }
00176 
00177 int HTTPRequestHandler::readLine(char* str, int maxLen)
00178 {
00179   int ret;
00180   int len = 0;
00181   for(int i = 0; i < maxLen - 1; i++)
00182   {
00183     ret = m_pTCPSocket->recv(str, 1);
00184     if(!ret)
00185     {
00186       break;
00187     }
00188     if( (len > 1) && *(str-1)=='\r' && *str=='\n' )
00189     {
00190       str--;
00191       len-=2;
00192       break;
00193     }
00194     else if( *str=='\n' )
00195     {
00196       len--;
00197       break;    
00198     }
00199     str++;
00200     len++;
00201   }
00202   *str = 0;
00203   return len;
00204 }
00205 
00206 void HTTPRequestHandler::onTCPSocketEvent(TCPSocketEvent e)
00207 {
00208    
00209   DBG("\r\nEvent %d in HTTPRequestHandler\r\n", e);
00210 
00211   if(m_closed)
00212   {
00213     DBG("\r\nWARN: Discarded\r\n");
00214     return;
00215   }
00216 
00217   switch(e)
00218   {
00219   case TCPSOCKET_READABLE:
00220     resetTimeout();
00221     onReadable();
00222     break;
00223   case TCPSOCKET_WRITEABLE:
00224     resetTimeout();
00225     onWriteable();    
00226     break;
00227   case TCPSOCKET_CONTIMEOUT:
00228   case TCPSOCKET_CONRST:
00229   case TCPSOCKET_CONABRT:
00230   case TCPSOCKET_ERROR:
00231   case TCPSOCKET_DISCONNECTED:
00232     DBG("\r\nConnection error in handler\r\n");
00233     close();
00234     break;
00235   }
00236   
00237 }