HTTPClient for IEEE1888 (FIAP) Gateway

Dependents:   Fetch_IEEE1888_Storage IEEE1888_MULTI_SENSOR_GW

Fork of HTTPClient by Donatien Garnier

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers HTTPClient.cpp Source File

HTTPClient.cpp

00001 /* HTTPClient.cpp */
00002 /* Copyright (C) 2012 mbed.org, MIT License
00003  *
00004  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
00005  * and associated documentation files (the "Software"), to deal in the Software without restriction,
00006  * including without limitation the rights to use, copy, modify, merge, publish, distribute,
00007  * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
00008  * furnished to do so, subject to the following conditions:
00009  *
00010  * The above copyright notice and this permission notice shall be included in all copies or
00011  * substantial portions of the Software.
00012  *
00013  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
00014  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00015  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
00016  * DAMAGES OR OTHER 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 THE SOFTWARE.
00018  */
00019 
00020 //Debug is disabled by default
00021 #if 0
00022 //Enable debug
00023 #include <cstdio>
00024 #define DBG(x, ...) std::printf("[HTTPClient : DBG]"x"\r\n", ##__VA_ARGS__); 
00025 #define WARN(x, ...) std::printf("[HTTPClient : WARN]"x"\r\n", ##__VA_ARGS__); 
00026 #define ERR(x, ...) std::printf("[HTTPClient : ERR]"x"\r\n", ##__VA_ARGS__); 
00027 
00028 #else
00029 //Disable debug
00030 #define DBG(x, ...) 
00031 #define WARN(x, ...)
00032 #define ERR(x, ...) 
00033 
00034 #endif
00035 
00036 #define HTTP_PORT 80
00037 
00038 #define OK 0
00039 
00040 #define MIN(x,y) (((x)<(y))?(x):(y))
00041 #define MAX(x,y) (((x)>(y))?(x):(y))
00042 
00043 #define CHUNK_SIZE 256
00044 
00045 #include <cstring>
00046 
00047 #include "HTTPClient.h"
00048 
00049 HTTPClient::HTTPClient() :
00050 m_sock(), m_basicAuthUser(NULL), m_basicAuthPassword(NULL), m_httpResponseCode(0)
00051 {
00052 
00053 }
00054 
00055 HTTPClient::~HTTPClient()
00056 {
00057 
00058 }
00059 
00060 #if 0
00061 void HTTPClient::basicAuth(const char* user, const char* password) //Basic Authentification
00062 {
00063   m_basicAuthUser = user;
00064   m_basicAuthPassword = password;
00065 }
00066 #endif
00067 
00068 HTTPResult HTTPClient::get(const char* url, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
00069 {
00070   return connect(url, HTTP_GET, NULL, pDataIn, timeout);
00071 }
00072 
00073 HTTPResult HTTPClient::get(const char* url, char* result, size_t maxResultLen, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
00074 {
00075   HTTPText str(result, maxResultLen);
00076   return get(url, &str, timeout);
00077 }
00078 
00079 HTTPResult HTTPClient::post(const char* url, const IHTTPDataOut& dataOut, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
00080 {
00081   return connect(url, HTTP_POST, (IHTTPDataOut*)&dataOut, pDataIn, timeout);
00082 }
00083 
00084 //strysd add start
00085 HTTPResult HTTPClient::postXML(const char* url,const char* SOAPAction, const IHTTPDataOut& dataOut, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
00086 {
00087   return connectExt(url, HTTP_POST, SOAPAction, (IHTTPDataOut*)&dataOut, pDataIn, timeout);
00088 }
00089 //strysd add end
00090 
00091 HTTPResult HTTPClient::put(const char* url, const IHTTPDataOut& dataOut, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
00092 {
00093   return connect(url, HTTP_PUT, (IHTTPDataOut*)&dataOut, pDataIn, timeout);
00094 }
00095 
00096 HTTPResult HTTPClient::del(const char* url, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
00097 {
00098   return connect(url, HTTP_DELETE, NULL, pDataIn, timeout);
00099 }
00100 
00101 
00102 int HTTPClient::getHTTPResponseCode()
00103 {
00104   return m_httpResponseCode;
00105 }
00106 
00107 #define CHECK_CONN_ERR(ret) \
00108   do{ \
00109     if(ret) { \
00110       m_sock.close(); \
00111       ERR("Connection error (%d)", ret); \
00112       return HTTP_CONN; \
00113     } \
00114   } while(0)
00115 
00116 #define PRTCL_ERR() \
00117   do{ \
00118     m_sock.close(); \
00119     ERR("Protocol error"); \
00120     return HTTP_PRTCL; \
00121   } while(0)
00122 
00123 HTTPResult HTTPClient::connect(const char* url, HTTP_METH method, IHTTPDataOut* pDataOut, IHTTPDataIn* pDataIn, int timeout) //Execute request
00124 { 
00125   m_httpResponseCode = 0; //Invalidate code
00126   m_timeout = timeout;
00127   
00128   pDataIn->writeReset();
00129   if( pDataOut )
00130   {
00131     pDataOut->readReset();
00132   }
00133 
00134   char scheme[8];
00135   uint16_t port;
00136   char host[64];//strysd change from 32 
00137   char path[64];
00138   //First we need to parse the url (http[s]://host[:port][/[path]]) -- HTTPS not supported (yet?)
00139   HTTPResult res = parseURL(url, scheme, sizeof(scheme), host, sizeof(host), &port, path, sizeof(path));
00140   if(res != HTTP_OK)
00141   {
00142     ERR("parseURL returned %d", res);
00143     return res;
00144   }
00145 
00146   if(port == 0) //TODO do handle HTTPS->443
00147   {
00148     port = 80;
00149   }
00150 
00151   DBG("Scheme: %s", scheme);
00152   DBG("Host: %s", host);
00153   DBG("Port: %d", port);
00154   DBG("Path: %s", path);
00155 
00156   //Connect
00157   DBG("Connecting socket to server");
00158   int ret = m_sock.connect(host, port);
00159   if (ret < 0)
00160   {
00161     m_sock.close();
00162     ERR("Could not connect");
00163     return HTTP_CONN;
00164   }
00165 
00166   //Send request
00167   DBG("Sending request");
00168   char buf[CHUNK_SIZE];
00169   const char* meth = (method==HTTP_GET)?"GET":(method==HTTP_POST)?"POST":(method==HTTP_PUT)?"PUT":(method==HTTP_DELETE)?"DELETE":"";
00170   snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\nHost: %s\r\n", meth, path, host); //Write request
00171   ret = send(buf);
00172   if(ret)
00173   {
00174     m_sock.close();
00175     ERR("Could not write request");
00176     return HTTP_CONN;
00177   }
00178 
00179   //Send all headers
00180 
00181   //Send default headers
00182   DBG("Sending headers");
00183   if( pDataOut != NULL )
00184   {
00185     if( pDataOut->getIsChunked() )
00186     {
00187       ret = send("Transfer-Encoding: chunked\r\n");
00188       CHECK_CONN_ERR(ret);
00189     }
00190     else
00191     {
00192       snprintf(buf, sizeof(buf), "Content-Length: %d\r\n", pDataOut->getDataLen());
00193       ret = send(buf);
00194       CHECK_CONN_ERR(ret);
00195     }
00196     char type[48];
00197     if( pDataOut->getDataType(type, 48) == HTTP_OK )
00198     {
00199       snprintf(buf, sizeof(buf), "Content-Type: %s\r\n", type);
00200       ret = send(buf);
00201       CHECK_CONN_ERR(ret);
00202     }
00203   }
00204   
00205   //Close headers
00206   DBG("Headers sent");
00207   ret = send("\r\n");
00208   CHECK_CONN_ERR(ret);
00209 
00210   size_t trfLen;
00211   
00212   //Send data (if available)
00213   if( pDataOut != NULL )
00214   {
00215     DBG("Sending data");
00216     while(true)
00217     {
00218       size_t writtenLen = 0;
00219       pDataOut->read(buf, CHUNK_SIZE, &trfLen);
00220       if( pDataOut->getIsChunked() )
00221       {
00222         //Write chunk header
00223         char chunkHeader[16];
00224         snprintf(chunkHeader, sizeof(chunkHeader), "%X\r\n", trfLen); //In hex encoding
00225         ret = send(chunkHeader);
00226         CHECK_CONN_ERR(ret);
00227       }
00228       else if( trfLen == 0 )
00229       {
00230         break;
00231       }
00232       if( trfLen != 0 )
00233       {
00234         ret = send(buf, trfLen);
00235         CHECK_CONN_ERR(ret);
00236       }
00237 
00238       if( pDataOut->getIsChunked()  )
00239       {
00240         ret = send("\r\n"); //Chunk-terminating CRLF
00241         CHECK_CONN_ERR(ret);
00242       }
00243       else
00244       {
00245         writtenLen += trfLen;
00246         if( writtenLen >= pDataOut->getDataLen() )
00247         {
00248           break;
00249         }
00250       }
00251 
00252       if( trfLen == 0 )
00253       {
00254         break;
00255       }
00256     }
00257 
00258   }
00259   
00260   //Receive response
00261   DBG("Receiving response");
00262   ret = recv(buf, CHUNK_SIZE - 1, CHUNK_SIZE - 1, &trfLen); //Read n bytes
00263   CHECK_CONN_ERR(ret);
00264 
00265   buf[trfLen] = '\0';
00266 
00267   char* crlfPtr = strstr(buf, "\r\n");
00268   if(crlfPtr == NULL)
00269   {
00270     PRTCL_ERR();
00271   }
00272 
00273   int crlfPos = crlfPtr - buf;
00274   buf[crlfPos] = '\0';
00275 
00276   //Parse HTTP response
00277   if( sscanf(buf, "HTTP/%*d.%*d %d %*[^\r\n]", &m_httpResponseCode) != 1 )
00278   {
00279     //Cannot match string, error
00280     ERR("Not a correct HTTP answer : %s\n", buf);
00281     PRTCL_ERR();
00282   }
00283 
00284   if( (m_httpResponseCode < 200) || (m_httpResponseCode >= 300) )
00285   {
00286     //Did not return a 2xx code; TODO fetch headers/(&data?) anyway and implement a mean of writing/reading headers 
00287     WARN("Response code %d", m_httpResponseCode);
00288     PRTCL_ERR();
00289   }
00290 
00291   DBG("Reading headers");
00292 
00293   memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2) + 1); //Be sure to move NULL-terminating char as well
00294   trfLen -= (crlfPos + 2);
00295 
00296   size_t recvContentLength = 0;
00297   bool recvChunked = false;
00298   //Now get headers
00299   while( true )
00300   {
00301     crlfPtr = strstr(buf, "\r\n");
00302     if(crlfPtr == NULL)
00303     {
00304       if( trfLen < CHUNK_SIZE - 1 )
00305       {
00306         size_t newTrfLen;
00307         ret = recv(buf + trfLen, 1, CHUNK_SIZE - trfLen - 1, &newTrfLen);
00308         trfLen += newTrfLen;
00309         buf[trfLen] = '\0';
00310         DBG("Read %d chars; In buf: [%s]", newTrfLen, buf);
00311         CHECK_CONN_ERR(ret);
00312         continue;
00313       }
00314       else
00315       {
00316         PRTCL_ERR();
00317       }
00318     }
00319 
00320     crlfPos = crlfPtr - buf;
00321 
00322     if(crlfPos == 0) //End of headers
00323     {
00324       DBG("Headers read");
00325       memmove(buf, &buf[2], trfLen - 2 + 1); //Be sure to move NULL-terminating char as well
00326       trfLen -= 2;
00327       break;
00328     }
00329 
00330     buf[crlfPos] = '\0';
00331 
00332     char key[32];
00333     char value[32];
00334 
00335     key[31] = '\0';
00336     value[31] = '\0';
00337 
00338     int n = sscanf(buf, "%31[^:]: %31[^\r\n]", key, value);
00339     if ( n == 2 )
00340     {
00341       DBG("Read header : %s: %s\n", key, value);
00342       if( !strcmp(key, "Content-Length") )
00343       {
00344         sscanf(value, "%d", &recvContentLength);
00345         pDataIn->setDataLen(recvContentLength);
00346       }
00347       else if( !strcmp(key, "Transfer-Encoding") )
00348       {
00349         if( !strcmp(value, "Chunked") || !strcmp(value, "chunked") )
00350         {
00351           recvChunked = true;
00352           pDataIn->setIsChunked(true);
00353         }
00354       }
00355       else if( !strcmp(key, "Content-Type") )
00356       {
00357         pDataIn->setDataType(value);
00358       }
00359 
00360       memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2) + 1); //Be sure to move NULL-terminating char as well
00361       trfLen -= (crlfPos + 2);
00362 
00363     }
00364     else
00365     {
00366       ERR("Could not parse header");
00367       PRTCL_ERR();
00368     }
00369 
00370   }
00371 
00372   //Receive data
00373   DBG("Receiving data");
00374   while(true)
00375   {
00376     size_t readLen = 0;
00377 
00378     if( recvChunked )
00379     {
00380       //Read chunk header
00381       bool foundCrlf;
00382       do
00383       {
00384         foundCrlf = false;
00385         crlfPos=0;
00386         buf[trfLen]=0;
00387         if(trfLen >= 2)
00388         {
00389           for(; crlfPos < trfLen - 2; crlfPos++)
00390           {
00391             if( buf[crlfPos] == '\r' && buf[crlfPos + 1] == '\n' )
00392             {
00393               foundCrlf = true;
00394               break;
00395             }
00396           }
00397         }
00398         if(!foundCrlf) //Try to read more
00399         {
00400           if( trfLen < CHUNK_SIZE )
00401           {
00402             size_t newTrfLen;
00403             ret = recv(buf + trfLen, 0, CHUNK_SIZE - trfLen - 1, &newTrfLen);
00404             trfLen += newTrfLen;
00405             CHECK_CONN_ERR(ret);
00406             continue;
00407           }
00408           else
00409           {
00410             PRTCL_ERR();
00411           }
00412         }
00413       } while(!foundCrlf);
00414       buf[crlfPos] = '\0';
00415       int n = sscanf(buf, "%x", &readLen);
00416       if(n!=1)
00417       {
00418         ERR("Could not read chunk length");
00419         PRTCL_ERR();
00420       }
00421 
00422       memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2)); //Not need to move NULL-terminating char any more
00423       trfLen -= (crlfPos + 2);
00424 
00425       if( readLen == 0 )
00426       {
00427         //Last chunk
00428         break;
00429       }
00430     }
00431     else
00432     {
00433       readLen = recvContentLength;
00434     }
00435 
00436     DBG("Retrieving %d bytes", readLen);
00437 
00438     do
00439     {
00440       pDataIn->write(buf, MIN(trfLen, readLen));
00441       if( trfLen > readLen )
00442       {
00443         memmove(buf, &buf[readLen], trfLen - readLen);
00444         trfLen -= readLen;
00445         readLen = 0;
00446       }
00447       else
00448       {
00449         readLen -= trfLen;
00450       }
00451 
00452       if(readLen)
00453       {
00454         ret = recv(buf, 1, CHUNK_SIZE - trfLen - 1, &trfLen);
00455         CHECK_CONN_ERR(ret);
00456       }
00457     } while(readLen);
00458 
00459     if( recvChunked )
00460     {
00461       if(trfLen < 2)
00462       {
00463         size_t newTrfLen;
00464         //Read missing chars to find end of chunk
00465         ret = recv(buf + trfLen, 2 - trfLen, CHUNK_SIZE - trfLen - 1, &newTrfLen);
00466         CHECK_CONN_ERR(ret);
00467         trfLen += newTrfLen;
00468       }
00469       if( (buf[0] != '\r') || (buf[1] != '\n') )
00470       {
00471         ERR("Format error");
00472         PRTCL_ERR();
00473       }
00474       memmove(buf, &buf[2], trfLen - 2);
00475       trfLen -= 2;
00476     }
00477     else
00478     {
00479       break;
00480     }
00481 
00482   }
00483 
00484   m_sock.close();
00485   DBG("Completed HTTP transaction");
00486 
00487   return HTTP_OK;
00488 }
00489 
00490 //strysd add this function start
00491 //mainly inherit from connect(), but some code is different, see programer name, "strysd"
00492 HTTPResult HTTPClient::connectExt(const char* url, HTTP_METH method, const char* SOAPAction, IHTTPDataOut* pDataOut, IHTTPDataIn* pDataIn, int timeout) //Execute request
00493 { 
00494   m_httpResponseCode = 0; //Invalidate code
00495   m_timeout = timeout;
00496   
00497   pDataIn->writeReset();
00498   if( pDataOut )
00499   {
00500     pDataOut->readReset();
00501   }
00502 
00503   char scheme[8];
00504   uint16_t port;
00505   char host[64];//strysd change from 32
00506   char path[64];
00507   //First we need to parse the url (http[s]://host[:port][/[path]]) -- HTTPS not supported (yet?)
00508   HTTPResult res = parseURL(url, scheme, sizeof(scheme), host, sizeof(host), &port, path, sizeof(path));
00509   if(res != HTTP_OK)
00510   {
00511     ERR("parseURL returned %d", res);
00512     return res;
00513   }
00514 
00515   if(port == 0) //TODO do handle HTTPS->443
00516   {
00517     port = 80;
00518   }
00519 
00520   DBG("Scheme: %s", scheme);
00521   DBG("Host: %s", host);
00522   DBG("Port: %d", port);
00523   DBG("Path: %s", path);
00524 
00525   //Connect
00526   DBG("Connecting socket to server");
00527   int ret = m_sock.connect(host, port);
00528   if (ret < 0)
00529   {
00530     m_sock.close();
00531     ERR("Could not connect");
00532     return HTTP_CONN;
00533   }
00534 
00535   //Send request
00536   DBG("Sending request");
00537   char buf[CHUNK_SIZE];
00538   const char* meth = (method==HTTP_GET)?"GET":(method==HTTP_POST)?"POST":(method==HTTP_PUT)?"PUT":(method==HTTP_DELETE)?"DELETE":"";
00539   snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\nHost: %s\r\n", meth, path, host); //Write request
00540   ret = send(buf);
00541   if(ret)
00542   {
00543     m_sock.close();
00544     ERR("Could not write request");
00545     return HTTP_CONN;
00546   }
00547 
00548   //Send all headers
00549 
00550   //Send default headers
00551   DBG("Sending headers");
00552   if( pDataOut != NULL )
00553   {
00554     if( pDataOut->getIsChunked() )
00555     {
00556       ret = send("Transfer-Encoding: chunked\r\n");
00557       CHECK_CONN_ERR(ret);
00558     }
00559     else
00560     {
00561       snprintf(buf, sizeof(buf), "Content-Length: %d\r\n", pDataOut->getDataLen());
00562       ret = send(buf);
00563       CHECK_CONN_ERR(ret);
00564     }
00565     char type[48];
00566     if( pDataOut->getDataType(type, 48) == HTTP_OK )
00567     {
00568       //strysd change next line 
00569       //snprintf(buf, sizeof(buf), "Content-Type: %s\r\n", type);
00570       snprintf(buf, sizeof(buf), "Content-Type: text/xml;charset=UTF-8\r\n");
00571       
00572       ret = send(buf);
00573       CHECK_CONN_ERR(ret);
00574       //strysd add start
00575       snprintf(buf, sizeof(buf), "SOAPAction: \"%s\"\r\n", type);
00576       ret = send(buf);
00577       CHECK_CONN_ERR(ret);
00578       //strysd add end
00579     }
00580   }
00581   
00582   //Close headers
00583   DBG("Headers sent");
00584   ret = send("\r\n");
00585   CHECK_CONN_ERR(ret);
00586 
00587   size_t trfLen;
00588   
00589   //Send data (if available)
00590   if( pDataOut != NULL )
00591   {
00592     DBG("Sending data");
00593     while(true)
00594     {
00595       size_t writtenLen = 0;
00596       pDataOut->read(buf, CHUNK_SIZE, &trfLen);
00597       if( pDataOut->getIsChunked() )
00598       {
00599         //Write chunk header
00600         char chunkHeader[16];
00601         snprintf(chunkHeader, sizeof(chunkHeader), "%X\r\n", trfLen); //In hex encoding
00602         ret = send(chunkHeader);
00603         CHECK_CONN_ERR(ret);
00604       }
00605       else if( trfLen == 0 )
00606       {
00607         break;
00608       }
00609       if( trfLen != 0 )
00610       {
00611         ret = send(buf, trfLen);
00612         CHECK_CONN_ERR(ret);
00613       }
00614 
00615       if( pDataOut->getIsChunked()  )
00616       {
00617         ret = send("\r\n"); //Chunk-terminating CRLF
00618         CHECK_CONN_ERR(ret);
00619       }
00620       else
00621       {
00622         writtenLen += trfLen;
00623         if( writtenLen >= pDataOut->getDataLen() )
00624         {
00625           break;
00626         }
00627       }
00628 
00629       if( trfLen == 0 )
00630       {
00631         break;
00632       }
00633     }
00634 
00635   }
00636   
00637   //Receive response
00638   DBG("Receiving response");
00639   ret = recv(buf, CHUNK_SIZE - 1, CHUNK_SIZE - 1, &trfLen); //Read n bytes
00640   CHECK_CONN_ERR(ret);
00641 
00642   buf[trfLen] = '\0';
00643 
00644   char* crlfPtr = strstr(buf, "\r\n");
00645   if(crlfPtr == NULL)
00646   {
00647     PRTCL_ERR();
00648   }
00649 
00650   int crlfPos = crlfPtr - buf;
00651   buf[crlfPos] = '\0';
00652 
00653   //Parse HTTP response
00654   if( sscanf(buf, "HTTP/%*d.%*d %d %*[^\r\n]", &m_httpResponseCode) != 1 )
00655   {
00656     //Cannot match string, error
00657     ERR("Not a correct HTTP answer : %s\n", buf);
00658     PRTCL_ERR();
00659   }
00660 
00661   if( (m_httpResponseCode < 200) || (m_httpResponseCode >= 300) )
00662   {
00663     //Did not return a 2xx code; TODO fetch headers/(&data?) anyway and implement a mean of writing/reading headers 
00664     WARN("Response code %d", m_httpResponseCode);
00665     PRTCL_ERR();
00666   }
00667 
00668   DBG("Reading headers");
00669 
00670   memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2) + 1); //Be sure to move NULL-terminating char as well
00671   trfLen -= (crlfPos + 2);
00672 
00673   size_t recvContentLength = 0;
00674   bool recvChunked = false;
00675   //Now get headers
00676   while( true )
00677   {
00678     crlfPtr = strstr(buf, "\r\n");
00679     if(crlfPtr == NULL)
00680     {
00681       if( trfLen < CHUNK_SIZE - 1 )
00682       {
00683         size_t newTrfLen;
00684         ret = recv(buf + trfLen, 1, CHUNK_SIZE - trfLen - 1, &newTrfLen);
00685         trfLen += newTrfLen;
00686         buf[trfLen] = '\0';
00687         DBG("Read %d chars; In buf: [%s]", newTrfLen, buf);
00688         CHECK_CONN_ERR(ret);
00689         continue;
00690       }
00691       else
00692       {
00693         PRTCL_ERR();
00694       }
00695     }
00696 
00697     crlfPos = crlfPtr - buf;
00698 
00699     if(crlfPos == 0) //End of headers
00700     {
00701       DBG("Headers read");
00702       memmove(buf, &buf[2], trfLen - 2 + 1); //Be sure to move NULL-terminating char as well
00703       trfLen -= 2;
00704       break;
00705     }
00706 
00707     buf[crlfPos] = '\0';
00708 
00709     char key[32];
00710     char value[32];
00711 
00712     key[31] = '\0';
00713     value[31] = '\0';
00714 
00715     int n = sscanf(buf, "%31[^:]: %31[^\r\n]", key, value);
00716     if ( n == 2 )
00717     {
00718       DBG("Read header : %s: %s\n", key, value);
00719       if( !strcmp(key, "Content-Length") )
00720       {
00721         sscanf(value, "%d", &recvContentLength);
00722         pDataIn->setDataLen(recvContentLength);
00723       }
00724       else if( !strcmp(key, "Transfer-Encoding") )
00725       {
00726         if( !strcmp(value, "Chunked") || !strcmp(value, "chunked") )
00727         {
00728           recvChunked = true;
00729           pDataIn->setIsChunked(true);
00730         }
00731       }
00732       else if( !strcmp(key, "Content-Type") )
00733       {
00734         pDataIn->setDataType(value);
00735       }
00736 
00737       memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2) + 1); //Be sure to move NULL-terminating char as well
00738       trfLen -= (crlfPos + 2);
00739 
00740     }
00741     else
00742     {
00743       ERR("Could not parse header");
00744       PRTCL_ERR();
00745     }
00746 
00747   }
00748 
00749   //Receive data
00750   DBG("Receiving data");
00751   while(true)
00752   {
00753     size_t readLen = 0;
00754 
00755     if( recvChunked )
00756     {
00757       //Read chunk header
00758       bool foundCrlf;
00759       do
00760       {
00761         foundCrlf = false;
00762         crlfPos=0;
00763         buf[trfLen]=0;
00764         if(trfLen >= 2)
00765         {
00766           for(; crlfPos < trfLen - 2; crlfPos++)
00767           {
00768             if( buf[crlfPos] == '\r' && buf[crlfPos + 1] == '\n' )
00769             {
00770               foundCrlf = true;
00771               break;
00772             }
00773           }
00774         }
00775         if(!foundCrlf) //Try to read more
00776         {
00777           if( trfLen < CHUNK_SIZE )
00778           {
00779             size_t newTrfLen;
00780             ret = recv(buf + trfLen, 0, CHUNK_SIZE - trfLen - 1, &newTrfLen);
00781             trfLen += newTrfLen;
00782             CHECK_CONN_ERR(ret);
00783             continue;
00784           }
00785           else
00786           {
00787             PRTCL_ERR();
00788           }
00789         }
00790       } while(!foundCrlf);
00791       buf[crlfPos] = '\0';
00792       int n = sscanf(buf, "%x", &readLen);
00793       if(n!=1)
00794       {
00795         ERR("Could not read chunk length");
00796         PRTCL_ERR();
00797       }
00798 
00799       memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2)); //Not need to move NULL-terminating char any more
00800       trfLen -= (crlfPos + 2);
00801 
00802       if( readLen == 0 )
00803       {
00804         //Last chunk
00805         break;
00806       }
00807     }
00808     else
00809     {
00810       readLen = recvContentLength;
00811     }
00812 
00813     DBG("Retrieving %d bytes", readLen);
00814 
00815     do
00816     {
00817       pDataIn->write(buf, MIN(trfLen, readLen));
00818       if( trfLen > readLen )
00819       {
00820         memmove(buf, &buf[readLen], trfLen - readLen);
00821         trfLen -= readLen;
00822         readLen = 0;
00823       }
00824       else
00825       {
00826         readLen -= trfLen;
00827       }
00828 
00829       if(readLen)
00830       {
00831         ret = recv(buf, 1, CHUNK_SIZE - trfLen - 1, &trfLen);
00832         CHECK_CONN_ERR(ret);
00833       }
00834     } while(readLen);
00835 
00836     if( recvChunked )
00837     {
00838       if(trfLen < 2)
00839       {
00840         size_t newTrfLen;
00841         //Read missing chars to find end of chunk
00842         ret = recv(buf + trfLen, 2 - trfLen, CHUNK_SIZE - trfLen - 1, &newTrfLen);
00843         CHECK_CONN_ERR(ret);
00844         trfLen += newTrfLen;
00845       }
00846       if( (buf[0] != '\r') || (buf[1] != '\n') )
00847       {
00848         ERR("Format error");
00849         PRTCL_ERR();
00850       }
00851       memmove(buf, &buf[2], trfLen - 2);
00852       trfLen -= 2;
00853     }
00854     else
00855     {
00856       break;
00857     }
00858 
00859   }
00860 
00861   m_sock.close();
00862   DBG("Completed HTTP transaction");
00863 
00864   return HTTP_OK;
00865 }
00866 //strysd add this function end
00867 
00868 HTTPResult HTTPClient::recv(char* buf, size_t minLen, size_t maxLen, size_t* pReadLen) //0 on success, err code on failure
00869 {
00870   DBG("Trying to read between %d and %d bytes", minLen, maxLen);
00871   size_t readLen = 0;
00872       
00873   if(!m_sock.is_connected())
00874   {
00875     WARN("Connection was closed by server");
00876     return HTTP_CLOSED; //Connection was closed by server 
00877   }
00878     
00879   int ret;
00880   while(readLen < maxLen)
00881   {
00882     if(readLen < minLen)
00883     {
00884       DBG("Trying to read at most %d bytes [Blocking]", minLen - readLen);
00885       m_sock.set_blocking(false, m_timeout);
00886       ret = m_sock.receive_all(buf + readLen, minLen - readLen);
00887     }
00888     else
00889     {
00890       DBG("Trying to read at most %d bytes [Not blocking]", maxLen - readLen);
00891       m_sock.set_blocking(false, 0);
00892       ret = m_sock.receive(buf + readLen, maxLen - readLen);
00893     }
00894     
00895     if( ret > 0)
00896     {
00897       readLen += ret;
00898     }
00899     else if( ret == 0 )
00900     {
00901       break;
00902     }
00903     else
00904     {
00905       if(!m_sock.is_connected())
00906       {
00907         ERR("Connection error (recv returned %d)", ret);
00908         *pReadLen = readLen;
00909         return HTTP_CONN;
00910       }
00911       else
00912       {
00913         break;      
00914       }
00915     }
00916     
00917     if(!m_sock.is_connected())
00918     {
00919       break;
00920     }
00921   }
00922   DBG("Read %d bytes", readLen);
00923   *pReadLen = readLen;
00924   return HTTP_OK;
00925 }
00926 
00927 HTTPResult HTTPClient::send(char* buf, size_t len) //0 on success, err code on failure
00928 {
00929   if(len == 0)
00930   {
00931     len = strlen(buf);
00932   }
00933   DBG("Trying to write %d bytes", len);
00934   size_t writtenLen = 0;
00935     
00936   if(!m_sock.is_connected())
00937   {
00938     WARN("Connection was closed by server");
00939     return HTTP_CLOSED; //Connection was closed by server 
00940   }
00941   
00942   m_sock.set_blocking(false, m_timeout);
00943   int ret = m_sock.send_all(buf, len);
00944   if(ret > 0)
00945   {
00946     writtenLen += ret;
00947   }
00948   else if( ret == 0 )
00949   {
00950     WARN("Connection was closed by server");
00951     return HTTP_CLOSED; //Connection was closed by server
00952   }
00953   else
00954   {
00955     ERR("Connection error (send returned %d)", ret);
00956     return HTTP_CONN;
00957   }
00958   
00959   DBG("Written %d bytes", writtenLen);
00960   return HTTP_OK;
00961 }
00962 
00963 HTTPResult HTTPClient::parseURL(const char* url, char* scheme, size_t maxSchemeLen, char* host, size_t maxHostLen, uint16_t* port, char* path, size_t maxPathLen) //Parse URL
00964 {
00965   char* schemePtr = (char*) url;
00966   char* hostPtr = (char*) strstr(url, "://");
00967   if(hostPtr == NULL)
00968   {
00969     WARN("Could not find host");
00970     return HTTP_PARSE; //URL is invalid
00971   }
00972 
00973   if( maxSchemeLen < hostPtr - schemePtr + 1 ) //including NULL-terminating char
00974   {
00975     WARN("Scheme str is too small (%d >= %d)", maxSchemeLen, hostPtr - schemePtr + 1);
00976     return HTTP_PARSE;
00977   }
00978   memcpy(scheme, schemePtr, hostPtr - schemePtr);
00979   scheme[hostPtr - schemePtr] = '\0';
00980 
00981   hostPtr+=3;
00982 
00983   size_t hostLen = 0;
00984 
00985   char* portPtr = strchr(hostPtr, ':');
00986   if( portPtr != NULL )
00987   {
00988     hostLen = portPtr - hostPtr;
00989     portPtr++;
00990     if( sscanf(portPtr, "%hu", port) != 1)
00991     {
00992       WARN("Could not find port");
00993       return HTTP_PARSE;
00994     }
00995   }
00996   else
00997   {
00998     *port=0;
00999   }
01000   char* pathPtr = strchr(hostPtr, '/');
01001   if( hostLen == 0 )
01002   {
01003     hostLen = pathPtr - hostPtr;
01004   }
01005 
01006   if( maxHostLen < hostLen + 1 ) //including NULL-terminating char
01007   {
01008     WARN("Host str is too small (%d >= %d)", maxHostLen, hostLen + 1);
01009     return HTTP_PARSE;
01010   }
01011   memcpy(host, hostPtr, hostLen);
01012   host[hostLen] = '\0';
01013 
01014   size_t pathLen;
01015   char* fragmentPtr = strchr(hostPtr, '#');
01016   if(fragmentPtr != NULL)
01017   {
01018     pathLen = fragmentPtr - pathPtr;
01019   }
01020   else
01021   {
01022     pathLen = strlen(pathPtr);
01023   }
01024 
01025   if( maxPathLen < pathLen + 1 ) //including NULL-terminating char
01026   {
01027     WARN("Path str is too small (%d >= %d)", maxPathLen, pathLen + 1);
01028     return HTTP_PARSE;
01029   }
01030   memcpy(path, pathPtr, pathLen);
01031   path[pathLen] = '\0';
01032 
01033   return HTTP_OK;
01034 }