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