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