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.
Dependencies: CyaSSL
Dependents: MTS-Socket MTS-Socket
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)