Renesas / SecureDweet
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SecureHttpClient.cpp Source File

SecureHttpClient.cpp

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