Adaptation of the HttpServer by user yueee_yt. This version has improved handling of the HTTP headers (**NOTE**: There are limitations with this implementation and it is not fully functional. Use it only as a starting point.)

Dependents:   DMSupport DMSupport DMSupport DMSupport

Fork of DM_HttpServer by EmbeddedArtists AB

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers HTTPRequestHandler.cpp Source File

HTTPRequestHandler.cpp

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