Bonjour/Zerconf library

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("\r\nNew 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("\r\nAuth 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 = 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_ms()>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("\r\nDone :)!\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("\r\nURL 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("\r\nDNS Query...\r\n");
00281     m_pDnsReq = new DNSRequest();
00282     m_pDnsReq->setOnReply(this, &HTTPClient::onDNSReply);
00283     m_pDnsReq->resolve(&m_server);
00284     DBG("\r\nHTTPClient : DNSRequest %p\r\n", m_pDnsReq);
00285   }
00286   
00287 }
00288 
00289 void HTTPClient::connect() //Start Connection
00290 {
00291   resetTimeout();
00292   DBG("\r\nConnecting...\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("\r\nReading 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("\r\nReading 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("\r\nChunk length is %d\r\n", m_dataLen);
00374             m_dataPos = 0;
00375           }
00376           else
00377           {
00378             //Wait for end of line
00379             DBG("\r\nWait for CRLF\r\n");
00380             return;
00381           }
00382         }
00383         else
00384         {
00385           DBG("\r\nWait 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(len>0)
00401       resetTimeout();
00402     
00403     if(m_state == HTTP_READ_DATA_INCOMPLETE)
00404       return;
00405       
00406     //Chunk Tail
00407     if(m_dataChunked)
00408     {  
00409       if(m_dataPos >= m_dataLen)
00410       {
00411         DBG("\r\nChunk read, wait for CRLF\r\n");
00412         char chunkTail[3];
00413         m_dataPos += readLine(chunkTail, 3);
00414       }
00415       
00416       if(m_dataPos >= m_dataLen + 1) //1 == strlen("\n"),
00417       {
00418         DBG("\r\nEnd of chunk\r\n");
00419         if(m_dataLen==0)
00420         {
00421           DBG("\r\nEnd of file\r\n");
00422           //End of file
00423           m_state = HTTP_DONE; //Done
00424         }
00425         m_dataLen = 0;
00426         m_dataPos = 0;
00427       }
00428     }
00429   
00430   } while(len>0);
00431   
00432   
00433   if(!m_dataChunked && (m_dataPos >= m_dataLen)) //All Data has been received
00434   {
00435     DBG("\r\nEnd of file\r\n");
00436     m_state = HTTP_DONE; //Done
00437   }
00438 }
00439 
00440 void HTTPClient::writeData() //Data has been written & buf is free
00441 {
00442   if(m_pDataOut == NULL) //Nothing to write (in POST for instance)
00443   {
00444     m_dataLen = 0; //Reset Data Length
00445     m_state = HTTP_READ_HEADERS;
00446     return;
00447   }
00448   int len = m_pDataOut->read(m_buf, CHUNK_SIZE);
00449   if( m_dataChunked )
00450   {
00451     //Write chunk header
00452     char chunkHeader[16];
00453     sprintf(chunkHeader, "%d\r\n", len);
00454     int ret = m_pTCPSocket->send(chunkHeader, strlen(chunkHeader));
00455     if(ret < 0)//Error
00456     {
00457       onResult(HTTP_CONN);
00458       return;
00459     }
00460   }
00461   m_pTCPSocket->send(m_buf, len);
00462   m_dataPos+=len;
00463   if( m_dataChunked )
00464   {
00465     m_pTCPSocket->send("\r\n", 2); //Chunk terminating CRLF
00466   }
00467   if( ( !m_dataChunked && (m_dataPos >= m_dataLen) )
00468     || ( m_dataChunked && !len ) ) //All Data has been sent
00469   {
00470     m_dataLen = 0; //Reset Data Length
00471     m_state = HTTP_READ_HEADERS; //Wait for resp
00472   }
00473 }
00474   
00475 void HTTPClient::onTCPSocketEvent(TCPSocketEvent e)
00476 {
00477   DBG("\r\nEvent %d in HTTPClient::onTCPSocketEvent()\r\n", e);
00478 
00479   if(m_closed)
00480   {
00481     DBG("\r\nWARN: Discarded\r\n");
00482     return;
00483   }
00484 
00485   switch(e)
00486   {
00487   case TCPSOCKET_READABLE: //Incoming data
00488     resetTimeout();
00489     switch(m_state)
00490     {
00491     case HTTP_READ_HEADERS:
00492       if( !readHeaders() ) 
00493       {
00494         return; //Connection has been closed or incomplete data
00495       }
00496       if( m_pDataIn )
00497       {
00498         //Data chunked?
00499         if(m_respHeaders["Transfer-Encoding"].find("chunked")!=string::npos)
00500         {
00501           m_dataChunked = true;
00502           m_dataPos = 0;
00503           m_dataLen = 0; 
00504           DBG("\r\nEncoding is chunked, Content-Type is %s\r\n", m_respHeaders["Content-Type"].c_str() );
00505         }
00506         else
00507         {    
00508           m_dataChunked = false;
00509           int len = 0;
00510           //DBG("\r\nPreparing read... len = %s\r\n", m_respHeaders["Content-Length"].c_str());
00511           sscanf(m_respHeaders["Content-Length"].c_str(), "%d", &len);
00512           m_pDataIn->setDataLen( len );
00513           m_dataPos = 0;
00514           m_dataLen = len; 
00515           DBG("\r\nContent-Length is %d, Content-Type is %s\r\n", len, m_respHeaders["Content-Type"].c_str() );
00516         }
00517         m_pDataIn->setDataType( m_respHeaders["Content-Type"] );
00518       }
00519     case HTTP_READ_DATA:
00520       readData();
00521       break;
00522     case HTTP_READ_DATA_INCOMPLETE:
00523       break; //We need to handle previously received data first
00524     default:
00525       //Should not receive data now, req is not complete
00526       onResult(HTTP_PRTCL);
00527     }
00528  //All data has been read, close w/ success :)
00529     if( m_state == HTTP_DONE ) 
00530     {
00531       DBG("\r\nDone :)!\r\n");
00532       onResult(HTTP_OK);
00533     }
00534     break;
00535   case TCPSOCKET_CONNECTED:
00536   case TCPSOCKET_WRITEABLE: //We can send data
00537     resetTimeout();
00538     switch(m_state)
00539     {
00540     case HTTP_WRITE_HEADERS:
00541       //Update headers fields according to m_pDataOut
00542       if( m_pDataOut )
00543       {
00544         //Data is chunked?
00545         if(m_pDataOut->getIsChunked())
00546         {
00547           m_dataChunked = true;
00548           m_reqHeaders.erase("Content-Length");
00549           m_reqHeaders["Transfer-Encoding"] = "chunked";
00550         }
00551         else
00552         {
00553           m_dataChunked = false;
00554           char c_len[16] = "0";
00555           int len = m_pDataOut->getDataLen();
00556           sprintf(c_len, "%d", len);
00557           m_dataPos = 0;
00558           m_dataLen = len;
00559           m_reqHeaders.erase("Transfer-Encoding");
00560           m_reqHeaders["Content-Length"] = string(c_len);
00561         } 
00562         string type = m_pDataOut->getDataType();
00563         if(!type.empty())
00564         {
00565           m_reqHeaders["Content-Type"] = type;
00566         }
00567         else
00568         {
00569           m_reqHeaders.erase("Content-Type");
00570         }
00571       }
00572       if( !writeHeaders() ) 
00573       {
00574         return; //Connection has been closed
00575       }
00576       break; //Wait for writeable event before sending payload
00577     case HTTP_WRITE_DATA:
00578       writeData();
00579       break;
00580     }
00581     //Otherwise request has been sent, now wait for resp
00582     break;
00583   case TCPSOCKET_CONTIMEOUT:
00584   case TCPSOCKET_CONRST:
00585   case TCPSOCKET_CONABRT:
00586   case TCPSOCKET_ERROR:
00587     DBG("\r\nConnection error.\r\n");
00588     onResult(HTTP_CONN);
00589   case TCPSOCKET_DISCONNECTED:
00590     //There might still be some data available for reading
00591     //So if we are in a reading state, do not close the socket yet
00592     if( (m_state != HTTP_READ_DATA_INCOMPLETE) && (m_state != HTTP_DONE) && (m_state != HTTP_CLOSED)  )
00593     {
00594       onResult(HTTP_CONN);
00595     }
00596     DBG("\r\nConnection closed by remote host.\r\n");
00597     break;
00598   }
00599 }
00600 
00601 void HTTPClient::onDNSReply(DNSReply r)
00602 {
00603   if(m_closed)
00604   {
00605     DBG("\r\nWARN: Discarded\r\n");
00606     return;
00607   }
00608   
00609   if( r != DNS_FOUND )
00610   {
00611     DBG("\r\nCould not resolve hostname.\r\n");
00612     onResult(HTTP_DNS);
00613     return;
00614   }
00615   
00616   DBG("\r\nDNS Resolved to %d.%d.%d.%d.\r\n",m_server.getIp()[0],m_server.getIp()[1],m_server.getIp()[2],m_server.getIp()[3]);
00617   //If no error, m_server has been updated by m_pDnsReq so we're set to go !
00618   m_pDnsReq->close();
00619   delete m_pDnsReq;
00620   m_pDnsReq = NULL;
00621   connect();
00622 }
00623 
00624 void HTTPClient::onResult(HTTPResult r) //Called when exchange completed or on failure
00625 {
00626   if(m_pCbItem && m_pCbMeth)
00627     (m_pCbItem->*m_pCbMeth)(r);
00628   else if(m_pCb)
00629     m_pCb(r);
00630   m_blockingResult = r; //Blocking mode
00631   close(); //FIXME:Remove suppl. close() calls
00632 }
00633 
00634 void HTTPClient::onTimeout() //Connection has timed out
00635 {
00636   DBG("\r\nTimed out.\n");
00637   onResult(HTTP_TIMEOUT);
00638   close();
00639 }
00640 
00641 //Headers
00642 
00643 //TODO: Factorize w/ HTTPRequestHandler in a single HTTPHeader class
00644 
00645 HTTPResult HTTPClient::blockingProcess() //Called in blocking mode, calls Net::poll() until return code is available
00646 {
00647   //Disable callbacks
00648   m_pCb = NULL;
00649   m_pCbItem = NULL;
00650   m_pCbMeth = NULL;
00651   m_blockingResult = HTTP_PROCESSING;
00652   do
00653   {
00654     Net::poll();
00655   } while(m_blockingResult == HTTP_PROCESSING);
00656   Net::poll(); //Necessary for cleanup
00657   return m_blockingResult;
00658 }
00659 
00660 bool HTTPClient::readHeaders()
00661 {
00662   static char* line = m_buf;
00663   static char key[128];
00664   static char value[128];
00665   if(!m_dataLen) //No incomplete header in buffer, this is the first time we read data
00666   {
00667     if( readLine(line, 128) > 0 )
00668     {
00669       //Check RC
00670       m_httpResponseCode = 0;
00671       if( sscanf(line, "HTTP/%*d.%*d %d %*[^\r\n]", &m_httpResponseCode) != 1 )
00672       {
00673         //Cannot match string, error
00674         DBG("\r\nNot a correct HTTP answer : %s\r\n", line);
00675         onResult(HTTP_PRTCL);
00676         close();
00677         return false;
00678       }
00679       
00680       if(m_httpResponseCode != 200)
00681       {
00682         DBG("\r\nResponse: error code %d\r\n", m_httpResponseCode);
00683         HTTPResult res = HTTP_ERROR;
00684         switch(m_httpResponseCode)
00685         {
00686         case 404:
00687           res = HTTP_NOTFOUND;
00688           break;
00689         case 403:
00690           res = HTTP_REFUSED;
00691           break;
00692         default:
00693           res = HTTP_ERROR;
00694         }
00695         onResult(res);
00696         close();
00697         return false;
00698       }
00699       DBG("\r\nResponse OK\r\n");
00700     }
00701     else
00702     {
00703       //Empty packet, weird!
00704       DBG("\r\nEmpty packet!\r\n");
00705       onResult(HTTP_PRTCL);
00706       close();
00707       return false;
00708     }
00709   }
00710   bool incomplete = false;
00711   while( true )
00712   {
00713     int readLen = readLine(line + m_dataLen, 128 - m_dataLen, &incomplete);
00714     m_dataLen = 0;
00715     if( readLen <= 2 ) //if == 1 or 2, it is an empty line = end of headers
00716     {
00717       DBG("\r\nAll headers read.\r\n");
00718       m_state = HTTP_READ_DATA;
00719       break;
00720     }
00721     else if( incomplete == true )
00722     {
00723       m_dataLen = readLen;//Sets data length available in buffer
00724       return false;
00725     }
00726     //DBG("\r\nHeader : %s\r\n", line);
00727     int n = sscanf(line, "%[^:] : %[^\r\n]", key, value);
00728     if ( n == 2 )
00729     {
00730       DBG("\r\nRead header : %s: %s\r\n", key, value);
00731       m_respHeaders[key] = value;
00732     }
00733     //TODO: Impl n==1 case (part 2 of previous header)
00734   }
00735 
00736   return true;
00737 }
00738 
00739 bool HTTPClient::writeHeaders() //Called at the first writeData call
00740 {
00741   static char* line = m_buf;
00742   const char* HTTP_METH_STR[] = {"GET", "POST", "HEAD"};
00743   
00744   //Req
00745   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
00746   m_pTCPSocket->send(line, strlen(line));
00747   DBG("\r\nRequest: %s\r\n", line);
00748   
00749   DBG("\r\nWriting headers:\r\n");
00750   map<string,string>::iterator it;
00751   for( it = m_reqHeaders.begin(); it != m_reqHeaders.end(); it++ )
00752   {
00753     sprintf(line, "%s: %s\r\n", (*it).first.c_str(), (*it).second.c_str() );
00754     DBG("\r\n%s", line);
00755     m_pTCPSocket->send(line, strlen(line));
00756   }
00757   m_pTCPSocket->send("\r\n",2); //End of head
00758   m_state = HTTP_WRITE_DATA;
00759   return true;
00760 }
00761 
00762 int HTTPClient::readLine(char* str, int maxLen, bool* pIncomplete /* = NULL*/)
00763 {
00764   int ret;
00765   int len = 0;
00766   if(pIncomplete)
00767     *pIncomplete = false;
00768   for(int i = 0; i < maxLen - 1; i++)
00769   {
00770     ret = m_pTCPSocket->recv(str, 1);
00771     if(ret != 1)
00772     {
00773       if(pIncomplete)
00774         *pIncomplete = true;
00775       break;
00776     }
00777     if( (len > 1) && *(str-1)=='\r' && *str=='\n' )
00778     {
00779       break;
00780     }
00781     else if( *str=='\n' )
00782     {
00783       break;    
00784     }
00785     str++;
00786     len++;
00787   }
00788   *str = 0;
00789   return len;
00790 }