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