my fork
Fork of HTTPClient by
Diff: HTTPClient.cpp
- Revision:
- 17:c73d8e61d391
- Parent:
- 16:1f743885e7de
- Child:
- 18:d89df40b4cf3
diff -r 1f743885e7de -r c73d8e61d391 HTTPClient.cpp --- a/HTTPClient.cpp Thu Aug 30 15:38:57 2012 +0000 +++ b/HTTPClient.cpp Mon Apr 07 23:30:35 2014 +0000 @@ -34,22 +34,68 @@ #endif #define HTTP_PORT 80 +#define HTTPS_PORT 443 #define OK 0 #define MIN(x,y) (((x)<(y))?(x):(y)) #define MAX(x,y) (((x)>(y))?(x):(y)) -#define CHUNK_SIZE 256 +#include <cstring> -#include <cstring> +#include <../CyaSSL/cyassl/ctaocrypt/settings.h> +#include <../CyaSSL/cyassl/ctaocrypt/types.h> +#include <../CyaSSL/cyassl/internal.h> +#include <../CyaSSL/cyassl/ssl.h> #include "HTTPClient.h" +#include "TCPSocketConnection.h" + +class TCPSocketConnection_fd: public TCPSocketConnection +{ +public: + int get_fd() { + return _sock_fd ; + } +} ; + +static TCPSocketConnection_fd m_sock; + +#define CHUNK_SIZE 256 +#define SEND_BUF_SIZE 512 +static char send_buf[SEND_BUF_SIZE] ; +static char *send_buf_p ; + +static int SocketReceive(CYASSL* ssl, char *buf, int sz, void *ctx) +{ + int n ; + int i ; + #define RECV_RETRY 3 + for(i=0; i<RECV_RETRY; i++) { + n = m_sock.receive(buf, sz) ; + if(n >= 0)return n ; + } + ERR("SocketReceive:%d/%d\n", n, sz) ; + return n ; +} + +static int SocketSend(CYASSL* ssl, char *buf, int sz, void *ctx) +{ + int n ; + + n = m_sock.send(buf, sz); + if(n > 0) { + return n ; + } else ERR("SocketSend:%d/%d\n", n, sz); + return n ; +} HTTPClient::HTTPClient() : -m_sock(), m_basicAuthUser(NULL), m_basicAuthPassword(NULL), m_httpResponseCode(0) +m_basicAuthUser(NULL), m_basicAuthPassword(NULL), m_httpResponseCode(0) { - + //CyaSSL_Debugging_ON() ; + ctx = 0 ; + ssl = 0 ; } HTTPClient::~HTTPClient() @@ -97,9 +143,16 @@ return m_httpResponseCode; } +void HTTPClient::setHeader(char * h) +{ + header = h ; +} + + #define CHECK_CONN_ERR(ret) \ do{ \ if(ret) { \ + cyassl_free() ;\ m_sock.close(); \ ERR("Connection error (%d)", ret); \ return HTTP_CONN; \ @@ -108,11 +161,21 @@ #define PRTCL_ERR() \ do{ \ + cyassl_free() ;\ m_sock.close(); \ ERR("Protocol error"); \ return HTTP_PRTCL; \ } while(0) +void HTTPClient::cyassl_free(void) +{ + if(ssl) + CyaSSL_free(ssl) ; + if(ctx) + CyaSSL_CTX_free(ctx) ; +} + + HTTPResult HTTPClient::connect(const char* url, HTTP_METH method, IHTTPDataOut* pDataOut, IHTTPDataIn* pDataIn, int timeout) //Execute request { m_httpResponseCode = 0; //Invalidate code @@ -125,10 +188,12 @@ } char scheme[8]; - uint16_t port; char host[32]; char path[64]; - //First we need to parse the url (http[s]://host[:port][/[path]]) -- HTTPS not supported (yet?) + + int ret ; + + //First we need to parse the url (http[s]://host[:port][/[path]]) HTTPResult res = parseURL(url, scheme, sizeof(scheme), host, sizeof(host), &port, path, sizeof(path)); if(res != HTTP_OK) { @@ -138,7 +203,10 @@ if(port == 0) //TODO do handle HTTPS->443 { - port = 80; + if(strcmp(scheme, "http") == 0) + port = HTTP_PORT ; + else if(strcmp(scheme, "https") == 0) + port = HTTPS_PORT ; } DBG("Scheme: %s", scheme); @@ -148,17 +216,59 @@ //Connect DBG("Connecting socket to server"); - int ret = m_sock.connect(host, port); - if (ret < 0) + sockfd = m_sock.get_fd() ; + + #define MAX_RETRY 5 + int retry ; + + for(retry=0; retry<MAX_RETRY; retry++) { + int ret = m_sock.connect(host, port); + if(ret == 0)break ; + } + if(retry == MAX_RETRY) { m_sock.close(); ERR("Could not connect"); return HTTP_CONN; } + if(port == HTTPS_PORT) { + /* Start SSL connect */ + ctx = CyaSSL_CTX_new( + CyaTLSv1_2_client_method + //CyaSSLv3_client_method + ()); + if (ctx == NULL) { + ERR("unable to get ctx"); + return HTTP_CONN; + } + CyaSSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0); + + ssl = CyaSSL_new(ctx); + if (ssl == NULL) { + ERR("unable to get SSL object"); + cyassl_free() ; + return HTTP_CONN; + } + + CyaSSL_SetVersion(ssl, CYASSL_TLSV1_2) ; + CyaSSL_set_fd(ssl, sockfd); + CyaSSL_SetIORecv(ctx, SocketReceive) ; + CyaSSL_SetIOSend(ctx, SocketSend) ; + DBG("ctx=%x, ssl=%x, ssl->ctx->CBIORecv, CBIOSend=%x, %x\n", + ctx, ssl, SocketReceive, SocketSend ) ; + if (CyaSSL_connect(ssl) != SSL_SUCCESS) { + ERR("SSL_connect failed"); + cyassl_free() ; + return HTTP_CONN; + } + } /* SSL connect complete */ + //Send request DBG("Sending request"); char buf[CHUNK_SIZE]; + send_buf_p = send_buf ; // Reset send buffer ; + const char* meth = (method==HTTP_GET)?"GET":(method==HTTP_POST)?"POST":(method==HTTP_PUT)?"PUT":(method==HTTP_DELETE)?"DELETE":""; snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\nHost: %s\r\n", meth, path, host); //Write request ret = send(buf); @@ -195,6 +305,12 @@ } } + //Add user headers + if(header) { + ret = send(header); + CHECK_CONN_ERR(ret); + } + //Close headers DBG("Headers sent"); ret = send("\r\n"); @@ -210,6 +326,8 @@ { size_t writtenLen = 0; pDataOut->read(buf, CHUNK_SIZE, &trfLen); + buf[trfLen] = 0x0 ; + DBG("buf:%s", buf) ; if( pDataOut->getIsChunked() ) { //Write chunk header @@ -249,9 +367,12 @@ } } + ret = flush() ; // flush the send buffer ; + CHECK_CONN_ERR(ret); //Receive response DBG("Receiving response"); + ret = recv(buf, CHUNK_SIZE - 1, CHUNK_SIZE - 1, &trfLen); //Read n bytes CHECK_CONN_ERR(ret); @@ -364,6 +485,7 @@ //Receive data DBG("Receiving data"); + while(true) { size_t readLen = 0; @@ -473,7 +595,8 @@ } } - + + cyassl_free() ; m_sock.close(); DBG("Completed HTTP transaction"); @@ -492,6 +615,24 @@ } int ret; + + if(port == HTTPS_PORT) { + DBG("Enter CyaSSL_read") ; + + m_sock.set_blocking(false, m_timeout); + readLen = CyaSSL_read(ssl, buf, maxLen); + if (readLen > 0) { + buf[readLen] = 0; + DBG("CyaSSL_read:%s\n", buf); + } else { + ERR("CyaSSL_read, ret = %d", readLen) ; + return HTTP_ERROR ; + } + DBG("Read %d bytes", readLen); + *pReadLen = readLen; + return HTTP_OK; + } + while(readLen < maxLen) { if(readLen < minLen) @@ -510,7 +651,7 @@ if( ret > 0) { readLen += ret; - } + } else if( ret == 0 ) { break; @@ -541,11 +682,42 @@ HTTPResult HTTPClient::send(char* buf, size_t len) //0 on success, err code on failure { + HTTPResult ret ; + int cp_len ; + if(len == 0) { len = strlen(buf); } - DBG("Trying to write %d bytes", len); + + do { + if((SEND_BUF_SIZE - (send_buf_p - send_buf)) >= len){ + cp_len = len ; + } else { + cp_len = send_buf_p - send_buf ; + } + memcpy(send_buf_p, buf, cp_len) ; + send_buf_p += cp_len ; + len -= cp_len ; + + if(send_buf_p == send_buf + SEND_BUF_SIZE){ + ret = flush() ; + if(ret)return(ret) ; + } + } while(len) ; + return HTTP_OK ; +} + +HTTPResult HTTPClient::flush() //0 on success, err code on failure +{ + int len ; + char * buf ; + + buf = send_buf ; + len = send_buf_p - send_buf ; + send_buf_p = send_buf ; // reset send buffer + + DBG("Trying to write %d bytes:%s\n", len, buf); size_t writtenLen = 0; if(!m_sock.is_connected()) @@ -554,6 +726,15 @@ return HTTP_CLOSED; //Connection was closed by server } + if(port == HTTPS_PORT) { + DBG("Enter CyaSSL_write") ; + if (CyaSSL_write(ssl, buf, len) != len) { + ERR("SSL_write failed"); + return HTTP_ERROR ; + } + DBG("Written %d bytes", writtenLen); + return HTTP_OK; + } m_sock.set_blocking(false, m_timeout); int ret = m_sock.send_all(buf, len); if(ret > 0)