Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of HTTPClient-SSL 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)
