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