Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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
Generated on Tue Jul 12 2022 15:55:20 by
1.7.2