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