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