SOAPの為に修正します。

Dependents:   temp_FIAP temp_FIAP_fetch tepco_demand BlueUSB_f_IEEE1888 ... more

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