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