Ilya I / Mbed 2 deprecated iva2k_NetHttpServerTcpSockets

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers HTTPClient.cpp Source File

HTTPClient.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 "HTTPClient.h"
00025 #include "../util/base64.h"
00026 #include "../util/url.h"
00027 
00028 //#define __DEBUG
00029 #include "dbg/dbg.h"
00030 
00031 #define HTTP_REQUEST_TIMEOUT 30000//15000
00032 #define HTTP_PORT 80
00033 
00034 #define CHUNK_SIZE 256
00035 
00036 HTTPClient::HTTPClient() : NetService(false) /*Not owned by the pool*/, m_meth(HTTP_GET), m_pCbItem(NULL), m_pCbMeth(NULL), m_pCb(NULL),
00037 m_watchdog(), m_timeout(0), m_pDnsReq(NULL), m_server(), m_path(), 
00038 m_closed(true), m_state(HTTP_CLOSED),
00039 m_pDataOut(NULL), m_pDataIn(NULL), m_dataChunked(false), m_dataPos(0), m_dataLen(0), m_httpResponseCode(0), m_blockingResult(HTTP_PROCESSING)
00040  
00041 {
00042   setTimeout(HTTP_REQUEST_TIMEOUT);
00043   m_buf = new char[CHUNK_SIZE];
00044   DBG("New HTTPClient %p\r\n",this);
00045 }
00046 
00047 HTTPClient::~HTTPClient()
00048 {
00049   close();
00050   delete[] m_buf;
00051 }
00052   
00053 void HTTPClient::basicAuth(const char* user, const char* password) //Basic Authentification
00054 {
00055   if(user==NULL)
00056   {
00057     m_reqHeaders.erase("Authorization"); //Remove auth str
00058     return;
00059   }
00060   string auth = "Basic ";
00061   string decStr = user;
00062   decStr += ":";
00063   decStr += password;
00064   auth.append( Base64::encode(decStr) );
00065   DBG("Auth str is %s\r\n", auth.c_str());
00066   m_reqHeaders["Authorization"] = auth; 
00067 }
00068 
00069 //High Level setup functions
00070 HTTPResult HTTPClient::get(const char* uri, HTTPData* pDataIn) //Blocking
00071 {
00072   doGet(uri, pDataIn);
00073   return blockingProcess();
00074 }
00075 
00076 HTTPResult HTTPClient::get(const char* uri, HTTPData* pDataIn, void (*pMethod)(HTTPResult)) //Non blocking
00077 {
00078   setOnResult(pMethod);
00079   doGet(uri, pDataIn);
00080   return HTTP_PROCESSING;
00081 }
00082 
00083 #ifdef __LINKER_BUG_SOLVED__
00084 template<class T> 
00085 HTTPResult HTTPClient::get(const char* uri, HTTPData* pDataIn, T* pItem, void (T::*pMethod)(HTTPResult)) //Non blocking
00086 {
00087   setOnResult(pItem, pMethod);
00088   doGet(uri, pDataIn);
00089   return HTTP_PROCESSING;
00090 }
00091 #endif
00092 
00093 HTTPResult HTTPClient::post(const char* uri, const HTTPData& dataOut, HTTPData* pDataIn) //Blocking
00094 {
00095   doPost(uri, dataOut, pDataIn);
00096   return blockingProcess();
00097 }
00098 
00099 HTTPResult HTTPClient::post(const char* uri, const HTTPData& dataOut, HTTPData* pDataIn, void (*pMethod)(HTTPResult)) //Non blocking
00100 {
00101   setOnResult(pMethod);
00102   doPost(uri, dataOut, pDataIn);
00103   return HTTP_PROCESSING;
00104 }
00105 
00106 #ifdef __LINKER_BUG_SOLVED__
00107 template<class T> 
00108 HTTPResult HTTPClient::post(const char* uri, const HTTPData& dataOut, HTTPData* pDataIn, T* pItem, void (T::*pMethod)(HTTPResult)) //Non blocking 
00109 {
00110   setOnResult(pItem, pMethod);
00111   doPost(uri, dataOut, pDataIn);
00112   return HTTP_PROCESSING;
00113 }
00114 #endif
00115 
00116 void HTTPClient::doGet(const char* uri, HTTPData* pDataIn)
00117 {
00118   m_meth = HTTP_GET;
00119   setup(uri, NULL, pDataIn);
00120 }
00121 
00122 void HTTPClient::doPost(const char* uri, const HTTPData& dataOut, HTTPData* pDataIn)
00123 {
00124   m_meth = HTTP_POST;
00125   setup(uri, (HTTPData*) &dataOut, pDataIn);
00126 }
00127 
00128 void HTTPClient::setOnResult( void (*pMethod)(HTTPResult) )
00129 {
00130   m_pCb = pMethod;
00131   m_pCbItem = NULL;
00132   m_pCbMeth = NULL;
00133 }
00134   
00135 #ifdef __LINKER_BUG_SOLVED__
00136 template<class T> 
00137 void HTTPClient::setOnResult( T* pItem, void (T::*pMethod)(NtpResult) )
00138 {
00139   m_pCb = NULL;
00140   m_pCbItem = (CDummy*) pItem;
00141   m_pCbMeth = (void (CDummy::*)(NtpResult)) pMethod;
00142 }
00143 #endif
00144   
00145 void HTTPClient::setTimeout(int ms)
00146 {
00147   m_timeout = 1000*ms;
00148   //resetTimeout();
00149 }
00150 
00151 void HTTPClient::poll() //Called by NetServices
00152 {
00153   if(m_closed)
00154   {
00155     return;
00156   }
00157   if(m_watchdog.read_us()>m_timeout)
00158   {
00159     onTimeout();
00160   }
00161   else if(m_state == HTTP_READ_DATA_INCOMPLETE)
00162   {
00163     readData(); //Try to read more data
00164     if( m_state == HTTP_DONE ) 
00165     {
00166       //All data has been read, close w/ success :)
00167       DBG("Done :)!\r\n");
00168       onResult(HTTP_OK);
00169       close();
00170     }
00171   }
00172   
00173 }
00174 
00175 int HTTPClient::getHTTPResponseCode()
00176 {
00177   return m_httpResponseCode;
00178 }
00179 
00180 void HTTPClient::setRequestHeader(const string& header, const string& value)
00181 {
00182   m_reqHeaders[header] = value;
00183 }
00184 
00185 string& HTTPClient::getResponseHeader(const string& header)
00186 {
00187   return m_respHeaders[header];
00188 }
00189 
00190 void HTTPClient::resetRequestHeaders()
00191 {
00192   m_reqHeaders.clear();
00193 }
00194   
00195 void HTTPClient::resetTimeout()
00196 {
00197   m_watchdog.reset();
00198   m_watchdog.start();
00199 }
00200 
00201 void HTTPClient::init() //Create and setup socket if needed
00202 {
00203   close(); //Remove previous elements
00204   if(!m_closed) //Already opened
00205     return;
00206   m_state = HTTP_WRITE_HEADERS;
00207   m_pTCPSocket = new TCPSocket;
00208   m_pTCPSocket->setOnEvent(this, &HTTPClient::onTCPSocketEvent);
00209   m_closed = false;
00210   m_httpResponseCode = 0;
00211 }
00212   
00213 void HTTPClient::close()
00214 {
00215   if(m_closed)
00216     return;
00217   m_state = HTTP_CLOSED;
00218   //Now Request headers are kept btw requests unless resetRequestHeaders() is called
00219   //m_reqHeaders.clear(); //Clear headers for next requests
00220   m_closed = true; //Prevent recursive calling or calling on an object being destructed by someone else
00221   m_watchdog.stop(); //Stop timeout
00222   m_watchdog.reset();
00223   m_pTCPSocket->resetOnEvent();
00224   m_pTCPSocket->close();
00225   delete m_pTCPSocket;
00226   m_pTCPSocket = NULL;
00227   if( m_pDnsReq )
00228   {
00229     m_pDnsReq->close();
00230     delete m_pDnsReq;
00231     m_pDnsReq = NULL;
00232   }
00233 }
00234 
00235 void HTTPClient::setup(const char* uri, HTTPData* pDataOut, HTTPData* pDataIn) //Setup request, make DNS Req if necessary
00236 {
00237   init(); //Initialize client in known state, create socket
00238   m_pDataOut = pDataOut;
00239   m_pDataIn = pDataIn;
00240   resetTimeout();
00241   
00242   //Erase previous headers
00243   //Do NOT clear m_reqHeaders as they might have already set before connecting
00244   m_respHeaders.clear();
00245   
00246   //Erase response buffer
00247   if(m_pDataIn)
00248     m_pDataIn->clear();
00249   
00250   //Assert that buffers are initialized properly
00251   m_dataLen = 0;
00252   m_bufRemainingLen = 0;
00253   
00254   Url url;
00255   url.fromString(uri);
00256   
00257   m_path = url.getPath();
00258   
00259   m_server.setName(url.getHost().c_str());
00260   
00261   if( url.getPort() > 0 )
00262   {
00263     m_server.setPort( url.getPort() );
00264   }
00265   else
00266   {
00267     m_server.setPort( HTTP_PORT );
00268   }
00269   
00270   DBG("URL parsed,\r\nHost: %s\r\nPort: %d\r\nPath: %s\r\n", url.getHost().c_str(), url.getPort(), url.getPath().c_str());
00271   
00272   IpAddr ip;
00273   if( url.getHostIp(&ip) )
00274   {
00275     m_server.setIp(ip);
00276     connect();
00277   }
00278   else
00279   {
00280     DBG("DNS Query...\r\n");
00281     m_pDnsReq = new DNSRequest();
00282     m_pDnsReq->setOnReply(this, &HTTPClient::onDNSReply);
00283     m_pDnsReq->resolve(&m_server);
00284     DBG("HTTPClient : DNSRequest %p\r\n", m_pDnsReq);
00285   }
00286   
00287 }
00288 
00289 void HTTPClient::connect() //Start Connection
00290 {
00291   resetTimeout();
00292   DBG("Connecting...\r\n");
00293   m_pTCPSocket->connect(m_server);
00294 }
00295 
00296 #define MIN(a,b) ((a)<(b)?(a):(b))
00297 #define ABS(a) (((a)>0)?(a):0)
00298 int HTTPClient::tryRead() //Try to read data from tcp packet and put in the HTTPData object
00299 {
00300   int len = 0;
00301   int readLen;
00302   do
00303   {
00304     if(m_state == HTTP_READ_DATA_INCOMPLETE) //First try to complete buffer copy
00305     {
00306       readLen = m_bufRemainingLen;
00307       if (readLen == 0)
00308       {
00309         m_state = HTTP_READ_DATA;
00310         continue;
00311       }
00312     }
00313     else
00314     {
00315       readLen = m_pTCPSocket->recv(m_buf, MIN(ABS(m_dataLen-m_dataPos),CHUNK_SIZE));
00316       if(readLen < 0) //Error
00317       {
00318         return readLen;
00319       }
00320       m_pBufRemaining = m_buf;
00321     }
00322   /*  if (readLen == 0)
00323     { 
00324       m_state = HTTP_READ_DATA;
00325       return len;
00326     }*/
00327   
00328     int writtenLen = m_pDataIn->write(m_pBufRemaining, readLen);
00329     m_dataPos += writtenLen;
00330      
00331     if(writtenLen<readLen) //Data was not completely written
00332     {
00333       m_pBufRemaining += writtenLen;
00334       m_bufRemainingLen = readLen - writtenLen;
00335       m_state = HTTP_READ_DATA_INCOMPLETE;
00336       return len + writtenLen;
00337     }
00338     else
00339     {
00340       m_state = HTTP_READ_DATA;
00341     }
00342     len += readLen;
00343   } while(readLen>0);
00344   
00345   return len;
00346 }
00347 
00348 void HTTPClient::readData() //Data has been read
00349 {
00350   if(m_pDataIn == NULL) //Nothing to read (in HEAD for instance, not supported now)
00351   {
00352     m_state = HTTP_DONE;
00353     return;
00354   }
00355   DBG("Reading response...\r\n");
00356   int len = 0;
00357   do
00358   {
00359     if(m_dataChunked && (m_state != HTTP_READ_DATA_INCOMPLETE))
00360     {
00361       if(m_dataLen==0)
00362       {
00363         DBG("Reading chunk length...\r\n");
00364         //New block
00365         static char chunkHeader[16];
00366         //We use m_dataPos to retain the read position in chunkHeader, it has been set to 0 before the first call of readData()
00367         m_dataPos += readLine(chunkHeader + m_dataPos, ABS(16 - m_dataPos));
00368         if( m_dataPos > 0 )
00369         {
00370           if( chunkHeader[strlen(chunkHeader)-1] == 0x0d )
00371           {
00372             sscanf(chunkHeader, "%x%*[^\r\n]", &m_dataLen);
00373             DBG("Chunk length is %d\r\n", m_dataLen);
00374             m_dataPos = 0;
00375           }
00376           else
00377           {
00378             //Wait for end of line
00379             DBG("Wait for CRLF\r\n");
00380             return;
00381           }
00382         }
00383         else
00384         {
00385           DBG("Wait for data\r\n");
00386           //Wait for data
00387           return;
00388         }
00389       }
00390     }  
00391       
00392     //Proper data recovery
00393     len = tryRead();
00394     if(len<0) //Error
00395     {
00396       onResult(HTTP_CONN);
00397       return;
00398     }
00399     
00400     if(m_state == HTTP_READ_DATA_INCOMPLETE)
00401       return;
00402       
00403     //Chunk Tail
00404     if(m_dataChunked)
00405     {  
00406       if(m_dataPos >= m_dataLen)
00407       {
00408         DBG("Chunk read, wait for CRLF\r\n");
00409         char chunkTail[3];
00410         m_dataPos += readLine(chunkTail, 3);
00411       }
00412       
00413       if(m_dataPos >= m_dataLen + 1) //1 == strlen("\n"),
00414       {
00415         DBG("End of chunk\r\n");
00416         if(m_dataLen==0)
00417         {
00418           DBG("End of file\r\n");
00419           //End of file
00420           m_state = HTTP_DONE; //Done
00421         }
00422         m_dataLen = 0;
00423         m_dataPos = 0;
00424       }
00425     }
00426   
00427   } while(len>0);
00428   
00429   
00430   if(!m_dataChunked && (m_dataPos >= m_dataLen)) //All Data has been received
00431   {
00432     DBG("End of file\r\n");
00433     m_state = HTTP_DONE; //Done
00434   }
00435 }
00436 
00437 void HTTPClient::writeData() //Data has been written & buf is free
00438 {
00439   if(m_pDataOut == NULL) //Nothing to write (in POST for instance)
00440   {
00441     m_dataLen = 0; //Reset Data Length
00442     m_state = HTTP_READ_HEADERS;
00443     return;
00444   }
00445   int len = m_pDataOut->read(m_buf, CHUNK_SIZE);
00446   if( m_dataChunked )
00447   {
00448     //Write chunk header
00449     char chunkHeader[16];
00450     sprintf(chunkHeader, "%d\r\n", len);
00451     int ret = m_pTCPSocket->send(chunkHeader, strlen(chunkHeader));
00452     if(ret < 0)//Error
00453     {
00454       onResult(HTTP_CONN);
00455       return;
00456     }
00457   }
00458   m_pTCPSocket->send(m_buf, len);
00459   m_dataPos+=len;
00460   if( m_dataChunked )
00461   {
00462     m_pTCPSocket->send("\r\n", 2); //Chunk terminating CRLF
00463   }
00464   if( ( !m_dataChunked && (m_dataPos >= m_dataLen) )
00465     || ( m_dataChunked && !len ) ) //All Data has been sent
00466   {
00467     m_dataLen = 0; //Reset Data Length
00468     m_state = HTTP_READ_HEADERS; //Wait for resp
00469   }
00470 }
00471   
00472 void HTTPClient::onTCPSocketEvent(TCPSocketEvent e)
00473 {
00474   DBG("Event %d in HTTPClient::onTCPSocketEvent()\r\n", e);
00475 
00476   if(m_closed)
00477   {
00478     DBG("WARN: Discarded\r\n");
00479     return;
00480   }
00481 
00482   switch(e)
00483   {
00484   case TCPSOCKET_READABLE: //Incoming data
00485     resetTimeout();
00486     switch(m_state)
00487     {
00488     case HTTP_READ_HEADERS:
00489       if( !readHeaders() ) 
00490       {
00491         return; //Connection has been closed or incomplete data
00492       }
00493       if( m_pDataIn )
00494       {
00495         //Data chunked?
00496         if(m_respHeaders["Transfer-Encoding"].find("chunked")!=string::npos)
00497         {
00498           m_dataChunked = true;
00499           m_dataPos = 0;
00500           m_dataLen = 0; 
00501           DBG("Encoding is chunked, Content-Type is %s\r\n", m_respHeaders["Content-Type"].c_str() );
00502         }
00503         else
00504         {    
00505           m_dataChunked = false;
00506           int len = 0;
00507           //DBG("Preparing read... len = %s\r\n", m_respHeaders["Content-Length"].c_str());
00508           sscanf(m_respHeaders["Content-Length"].c_str(), "%d", &len);
00509           m_pDataIn->setDataLen( len );
00510           m_dataPos = 0;
00511           m_dataLen = len; 
00512           DBG("Content-Length is %d, Content-Type is %s\r\n", len, m_respHeaders["Content-Type"].c_str() );
00513         }
00514         m_pDataIn->setDataType( m_respHeaders["Content-Type"] );
00515       }
00516     case HTTP_READ_DATA:
00517       readData();
00518       break;
00519     case HTTP_READ_DATA_INCOMPLETE:
00520       break; //We need to handle previously received data first
00521     default:
00522       //Should not receive data now, req is not complete
00523       onResult(HTTP_PRTCL);
00524     }
00525  //All data has been read, close w/ success :)
00526     if( m_state == HTTP_DONE ) 
00527     {
00528       DBG("Done :)!\r\n");
00529       onResult(HTTP_OK);
00530     }
00531     break;
00532   case TCPSOCKET_CONNECTED:
00533   case TCPSOCKET_WRITEABLE: //We can send data
00534     resetTimeout();
00535     switch(m_state)
00536     {
00537     case HTTP_WRITE_HEADERS:
00538       //Update headers fields according to m_pDataOut
00539       if( m_pDataOut )
00540       {
00541         //Data is chunked?
00542         if(m_pDataOut->getIsChunked())
00543         {
00544           m_dataChunked = true;
00545           m_reqHeaders.erase("Content-Length");
00546           m_reqHeaders["Transfer-Encoding"] = "chunked";
00547         }
00548         else
00549         {
00550           m_dataChunked = false;
00551           char c_len[16] = "0";
00552           int len = m_pDataOut->getDataLen();
00553           sprintf(c_len, "%d", len);
00554           m_dataPos = 0;
00555           m_dataLen = len;
00556           m_reqHeaders.erase("Transfer-Encoding");
00557           m_reqHeaders["Content-Length"] = string(c_len);
00558         } 
00559         string type = m_pDataOut->getDataType();
00560         if(!type.empty())
00561         {
00562           m_reqHeaders["Content-Type"] = type;
00563         }
00564         else
00565         {
00566           m_reqHeaders.erase("Content-Type");
00567         }
00568       }
00569       if( !writeHeaders() ) 
00570       {
00571         return; //Connection has been closed
00572       }
00573       break; //Wait for writeable event before sending payload
00574     case HTTP_WRITE_DATA:
00575       writeData();
00576       break;
00577     }
00578     //Otherwise request has been sent, now wait for resp
00579     break;
00580   case TCPSOCKET_CONTIMEOUT:
00581   case TCPSOCKET_CONRST:
00582   case TCPSOCKET_CONABRT:
00583   case TCPSOCKET_ERROR:
00584     DBG("Connection error.\r\n");
00585     onResult(HTTP_CONN);
00586   case TCPSOCKET_DISCONNECTED:
00587     //There might still be some data available for reading
00588     //So if we are in a reading state, do not close the socket yet
00589     if( (m_state != HTTP_READ_DATA_INCOMPLETE) && (m_state != HTTP_DONE) && (m_state != HTTP_CLOSED)  )
00590     {
00591       onResult(HTTP_CONN);
00592     }
00593     DBG("Connection closed by remote host.\r\n");
00594     break;
00595   }
00596 }
00597 
00598 void HTTPClient::onDNSReply(DNSReply r)
00599 {
00600   if(m_closed)
00601   {
00602     DBG("WARN: Discarded\r\n");
00603     return;
00604   }
00605   
00606   if( r != DNS_FOUND )
00607   {
00608     DBG("Could not resolve hostname.\r\n");
00609     onResult(HTTP_DNS);
00610     return;
00611   }
00612   
00613   DBG("DNS Resolved to %d.%d.%d.%d.\r\n",m_server.getIp()[0],m_server.getIp()[1],m_server.getIp()[2],m_server.getIp()[3]);
00614   //If no error, m_server has been updated by m_pDnsReq so we're set to go !
00615   m_pDnsReq->close();
00616   delete m_pDnsReq;
00617   m_pDnsReq = NULL;
00618   connect();
00619 }
00620 
00621 void HTTPClient::onResult(HTTPResult r) //Called when exchange completed or on failure
00622 {
00623   if(m_pCbItem && m_pCbMeth)
00624     (m_pCbItem->*m_pCbMeth)(r);
00625   else if(m_pCb)
00626     m_pCb(r);
00627   m_blockingResult = r; //Blocking mode
00628   close(); //FIXME:Remove suppl. close() calls
00629 }
00630 
00631 void HTTPClient::onTimeout() //Connection has timed out
00632 {
00633   DBG("Timed out.\n");
00634   onResult(HTTP_TIMEOUT);
00635   close();
00636 }
00637 
00638 //Headers
00639 
00640 //TODO: Factorize w/ HTTPRequestHandler in a single HTTPHeader class
00641 
00642 HTTPResult HTTPClient::blockingProcess() //Called in blocking mode, calls Net::poll() until return code is available
00643 {
00644   //Disable callbacks
00645   m_pCb = NULL;
00646   m_pCbItem = NULL;
00647   m_pCbMeth = NULL;
00648   m_blockingResult = HTTP_PROCESSING;
00649   do
00650   {
00651     Net::poll();
00652   } while(m_blockingResult == HTTP_PROCESSING);
00653   Net::poll(); //Necessary for cleanup
00654   return m_blockingResult;
00655 }
00656 
00657 bool HTTPClient::readHeaders()
00658 {
00659   static char* line = m_buf;
00660   static char key[128];
00661   static char value[128];
00662   if(!m_dataLen) //No incomplete header in buffer, this is the first time we read data
00663   {
00664     if( readLine(line, 128) > 0 )
00665     {
00666       //Check RC
00667       m_httpResponseCode = 0;
00668       if( sscanf(line, "HTTP/%*d.%*d %d %*[^\r\n]", &m_httpResponseCode) != 1 )
00669       {
00670         //Cannot match string, error
00671         DBG("Not a correct HTTP answer : %s\r\n", line);
00672         onResult(HTTP_PRTCL);
00673         close();
00674         return false;
00675       }
00676       
00677       if(m_httpResponseCode != 200)
00678       {
00679         DBG("Response: error code %d\r\n", m_httpResponseCode);
00680         HTTPResult res = HTTP_ERROR;
00681         switch(m_httpResponseCode)
00682         {
00683         case 404:
00684           res = HTTP_NOTFOUND;
00685           break;
00686         case 403:
00687           res = HTTP_REFUSED;
00688           break;
00689         default:
00690           res = HTTP_ERROR;
00691         }
00692         onResult(res);
00693         close();
00694         return false;
00695       }
00696       DBG("Response OK\r\n");
00697     }
00698     else
00699     {
00700       //Empty packet, weird!
00701       DBG("Empty packet!\r\n");
00702       onResult(HTTP_PRTCL);
00703       close();
00704       return false;
00705     }
00706   }
00707   bool incomplete = false;
00708   while( true )
00709   {
00710     int readLen = readLine(line + m_dataLen, 128 - m_dataLen, &incomplete);
00711     m_dataLen = 0;
00712     if( readLen <= 2 ) //if == 1 or 2, it is an empty line = end of headers
00713     {
00714       DBG("All headers read.\r\n");
00715       m_state = HTTP_READ_DATA;
00716       break;
00717     }
00718     else if( incomplete == true )
00719     {
00720       m_dataLen = readLen;//Sets data length available in buffer
00721       return false;
00722     }
00723     //DBG("Header : %s\r\n", line);
00724     int n = sscanf(line, "%[^:] : %[^\r\n]", key, value);
00725     if ( n == 2 )
00726     {
00727       DBG("Read header : %s: %s\r\n", key, value);
00728       m_respHeaders[key] = value;
00729     }
00730     //TODO: Impl n==1 case (part 2 of previous header)
00731   }
00732 
00733   return true;
00734 }
00735 
00736 bool HTTPClient::writeHeaders() //Called at the first writeData call
00737 {
00738   static char* line = m_buf;
00739   const char* HTTP_METH_STR[] = {"GET", "POST", "HEAD"};
00740   
00741   //Req
00742   sprintf(line, "%s %s HTTP/1.1\r\nHost: %s\r\n", HTTP_METH_STR[m_meth], m_path.c_str(), m_server.getName()); //Write request
00743   m_pTCPSocket->send(line, strlen(line));
00744   DBG("Request: %s\r\n", line);
00745   
00746   DBG("Writing headers:\r\n");
00747   map<string,string>::iterator it;
00748   for( it = m_reqHeaders.begin(); it != m_reqHeaders.end(); it++ )
00749   {
00750     sprintf(line, "%s: %s\r\n", (*it).first.c_str(), (*it).second.c_str() );
00751     DBG("%s", line);
00752     m_pTCPSocket->send(line, strlen(line));
00753   }
00754   m_pTCPSocket->send("\r\n",2); //End of head
00755   m_state = HTTP_WRITE_DATA;
00756   return true;
00757 }
00758 
00759 int HTTPClient::readLine(char* str, int maxLen, bool* pIncomplete /* = NULL*/)
00760 {
00761   int ret;
00762   int len = 0;
00763   if(pIncomplete)
00764     *pIncomplete = false;
00765   for(int i = 0; i < maxLen - 1; i++)
00766   {
00767     ret = m_pTCPSocket->recv(str, 1);
00768     if(ret != 1)
00769     {
00770       if(pIncomplete)
00771         *pIncomplete = true;
00772       break;
00773     }
00774     if( (len > 1) && *(str-1)=='\r' && *str=='\n' )
00775     {
00776       break;
00777     }
00778     else if( *str=='\n' )
00779     {
00780       break;    
00781     }
00782     str++;
00783     len++;
00784   }
00785   *str = 0;
00786   return len;
00787 }