A HTTP/HTTPS Client for the mbed networking/CyaSSL ssl library

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