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:   mbedTLSLibrary

Dependents:   SalesforceInterface df-2014-heroku-thermostat-k64f SalesforceInterface

Fork of HTTPClient by wolf SSL

This is a fork of the working HTTPS/SSL library that contains two extensions:

- HTTPJson - a derivation of HTTPText for emitting JSON strings specifically. No JSON parsing/checking is accomplished - HTTPJson simply sets the right Content-Type for HTTP(S).

- Expanded internal buffers for longer URLs. This is set in HTTPClient.cpp and is tunable.

Revision:
51:3bdf57f7fd60
Parent:
50:a18a06b000f3
Child:
52:cea1021a822d
--- a/HTTPClient.cpp	Tue Jun 09 16:26:02 2015 +0000
+++ b/HTTPClient.cpp	Thu Aug 20 18:55:41 2015 +0000
@@ -46,15 +46,8 @@
 
 #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"
 
-
-
 // ************ should be a better way to adjust for platform limitations 
 
 #if defined (TARGET_K64F)
@@ -68,6 +61,7 @@
     #define MAX_HEADER_KEY_LENGTH   40
     #define HEADER_SCANF_FORMAT     "%40[^:]: %4096[^\r\n]" /* must align with BIG_MEMORY_CHUNK */ 
     #define REDIRECT_SCANF_FORMAT   "%40[^:]: %4096[^\r\n]" /* must align with BIG_MEMORY_CHUNK */
+    #define RECV_RETRY              3
 #else
     // default smaller buffers
     #define CHUNK_SIZE              256
@@ -78,6 +72,7 @@
     #define MAX_HEADER_KEY_LENGTH   40
     #define HEADER_SCANF_FORMAT     "%40[^:]: %40[^\r\n]"   /* must align with MAX_HEADER_VALUE_LENGTH */ 
     #define REDIRECT_SCANF_FORMAT   "%40[^:]: %128[^\r\n]"  /* must align with MAX_URL_PATH_LENGTH */
+    #define RECV_RETRY              3
 #endif
 
 // ************ should be a better way to adjust for platform limitations
@@ -105,40 +100,101 @@
     }
     out[i] = '\0' ;
 }
-int SocketReceive(CYASSL* ssl, char *buf, int sz, void *ctx)
+
+static int SocketReceive(void* ssl, unsigned char *buf, size_t sz)
 {
-    int n ;
-    int i ;
-#define RECV_RETRY 3
+    int n = 0;
+    int i = 0;
 
     for(i=0; i<RECV_RETRY; i++) {
-        n =  m_sock_p->receive(buf, sz) ;
-        if(n >= 0)return n  ;
-        Thread::wait(200) ;
+        n = m_sock_p->receive((char *)buf,(int)sz) ;
+        if (n >= 0) return n;
     }
-    ERR("SocketReceive:%d/%d\n", n, sz)  ;
-    return n ;
+    ERR("SocketReceive: receive failed. received: %d bytes. tried to receive: %d bytes\n", n, sz)  ;
+    return n;
 }
-int SocketSend(CYASSL* ssl, char *buf, int sz, void *ctx)
+
+static int SocketSend(void* ssl, const unsigned char *buf, size_t sz)
 {
-    int n ;
-    
-    Thread::wait(100) ;
-    n =  m_sock_p->send(buf, sz);
-    if(n > 0) {
-        Thread::wait(300) ;
-        return n ;
-    } else  ERR("SocketSend:%d/%d\n", n, sz);
-    return n ;
+    int n = 0;
+    n = m_sock_p->send((char *)buf,(int)sz);
+    if(n > 0) return n;
+    ERR("SocketSend: send failed. sent: %d bytes. tried to send: %d bytes\n", n, sz);
+    return n;
+}
+
+short ssl_socket_read(ssl_context *ssl, char *receiveBuffer, unsigned int receiveBufferSize, unsigned int timeoutMilliseconds) {
+    int n = ssl_read(ssl,(unsigned char *)receiveBuffer, (size_t)receiveBufferSize);
+    if (n <= 0) {
+        ERR("ssl_socket_read failed\r\n");
+        return -1;
+    }
+    DBG("ssl_socket_read: read %d bytes...",n);
+    return n;
+}
+
+short ssl_socket_write(ssl_context *ssl, const char *sendBuffer, unsigned int sendBufferSize) {
+    sendBufferSize = strlen(sendBuffer);
+    int n = ssl_write(ssl,(const unsigned char *)sendBuffer,(size_t)sendBufferSize);
+    if (n != sendBufferSize) {
+        ERR("ssl_socket_write failed written=%d\r\n",n);
+        return -1;
+    }
+    DBG("ssl_socket_write: sent %d bytes...",sendBufferSize);
+    return sendBufferSize;
 }
 
-HTTPClient::HTTPClient() :
-    m_basicAuthUser(NULL), m_basicAuthPassword(NULL), m_httpResponseCode(0), m_oauthToken(NULL)
+void HTTPClient::set_ssl_version() {
+    // set the SSL version to be used
+    ssl_set_max_version(&this->ssl,SSL_MAX_MAJOR_VERSION,SSL_MAX_MINOR_VERSION);
+    if (this->SSLver == 0) {
+        // use v3
+        ssl_set_min_version(&this->ssl,SSL_MIN_MAJOR_VERSION,SSL_MIN_MINOR_VERSION);
+    }
+    if (this->SSLver == 1) {
+        // use v1
+        ssl_set_min_version(&this->ssl,SSL_MIN_MAJOR_VERSION,SSL_MINOR_VERSION_1);
+    }
+    if (this->SSLver == 2) {
+        // use v1.1
+        ssl_set_min_version(&this->ssl,SSL_MIN_MAJOR_VERSION,SSL_MINOR_VERSION_2);
+    }
+    if (this->SSLver == 3) {
+        // use v1.2
+        ssl_set_min_version(&this->ssl,SSL_MIN_MAJOR_VERSION,SSL_MINOR_VERSION_3);
+    } 
+}
+
+void HTTPClient::ssl_setup(const unsigned char *tag) {
+    entropy_init(&this->entropy);
+    ctr_drbg_init(&this->ctr_drbg,entropy_func,&this->entropy,tag,strlen((const char *)tag));
+    memset(&this->ssl,0,sizeof(ssl_context));
+    this->ssl_connected = false;
+}
+
+short HTTPClient::ssl_connect() {
+    short status = 0;
+    if (this->ssl_connected == false) {
+        this->ssl_setup("mbed_https_lib");              // debug tag could be taken from constructor parameter... fix me...
+        short status = ssl_init(&this->ssl);
+        if (status == 0) {
+            ssl_set_endpoint(&this->ssl,SSL_IS_CLIENT);
+            this->set_ssl_version();
+            ssl_set_rng(&this->ssl, ctr_drbg_random, &this->ctr_drbg);
+            ssl_set_authmode(&this->ssl,SSL_VERIFY_NONE);                                   // FIX ME:                             
+            ssl_set_bio(&this->ssl,SocketReceive,(void *)NULL,SocketSend,(void *)NULL);
+            this->ssl_connected = true;
+        }
+        DBG("ssl_connect: status=%d\r\n",status);
+    }
+    else {
+        DBG("ssl_connect: already connected (OK) status=%d\r\n",status);
+    }
+    return status;
+}
+
+HTTPClient::HTTPClient() : m_basicAuthUser(NULL), m_basicAuthPassword(NULL), m_httpResponseCode(0), m_oauthToken(NULL)
 {
-    // To DEBUG the underlying SSL - uncomment this...
-    //CyaSSL_Debugging_ON();
-    ctx = 0 ;
-    ssl = 0 ;
     SSLver = 3 ; 
     m_basicAuthUser = NULL ;
     m_basicAuthPassword = NULL;
@@ -250,7 +306,7 @@
 #define CHECK_CONN_ERR(ret) \
   do{ \
     if(ret) { \
-      cyassl_free() ;\
+      ssl_cleanup() ;\
       m_sock.close(); \
       ERR("Connection error (%d)", ret); \
       return HTTP_CONN; \
@@ -259,28 +315,22 @@
 
 #define PRTCL_ERR() \
   do{ \
-    cyassl_free() ;\
+    ssl_cleanup() ;\
     m_sock.close(); \
     ERR("Protocol error"); \
     return HTTP_PRTCL; \
   } while(0)
 
-void HTTPClient::cyassl_free(void)
+void HTTPClient::ssl_cleanup(void)
 {
-    if(ssl) {
-        CyaSSL_free(ssl) ;
-        ssl = NULL ;
-    }
-    if(ctx) {
-        CyaSSL_CTX_free(ctx) ;
-        ctx = NULL ;
-    }
-    CyaSSL_Cleanup() ;
+    ssl_free( &this->ssl );
+    ctr_drbg_free( &this->ctr_drbg );
+    entropy_free( &this->entropy );
+    this->ssl_connected = false;
 } 
 
 HTTPResult HTTPClient::connect(const char* url, HTTP_METH method, IHTTPDataOut* pDataOut, IHTTPDataIn* pDataIn, int timeout) //Execute request
 {
-    CYASSL_METHOD * SSLmethod = NULL;
     m_httpResponseCode = 0; //Invalidate code
     m_timeout = timeout;
     redirect = 0 ;
@@ -335,45 +385,15 @@
     }
 
     if(port == HTTPS_PORT) {
-
         /* Start SSL connect */
-        DBG("SSLver=%d", SSLver) ;
-        if(ctx == NULL) {
-            switch(SSLver) {
-            case 0 : SSLmethod = CyaSSLv3_client_method() ; break ;
-            case 1 : SSLmethod = CyaTLSv1_client_method() ; break ;
-            case 2 : SSLmethod = CyaTLSv1_1_client_method() ; break ;           
-            case 3 : SSLmethod = CyaTLSv1_2_client_method() ; break ;      
-            }
-            ctx = CyaSSL_CTX_new((CYASSL_METHOD *)SSLmethod);
-            if (ctx == NULL) {
-                ERR("unable to get ctx");
-                return HTTP_CONN;
-            }
-            CyaSSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0);
-            CyaSSL_SetIORecv(ctx, SocketReceive) ;
-            CyaSSL_SetIOSend(ctx, SocketSend) ;
-        }
-        if (ssl == NULL) {
-            ssl = CyaSSL_new(ctx);
-            if (ssl == NULL) {
-                ERR("unable to get SSL object");
-                cyassl_free() ;
-                return HTTP_CONN;
-            }
-        }
-        
-        DBG("ctx=%x, ssl=%x, ssl->ctx->CBIORecv, CBIOSend=%x, %x\n",ctx, ssl, SocketReceive, SocketSend ) ;
-        int result = CyaSSL_connect(ssl); 
-        if (result != SSL_SUCCESS) {
-            ERR("SSL_connect failed");
-            int err = CyaSSL_get_error(ssl, result);
-            char errorString[80];
-            CyaSSL_ERR_error_string(err, errorString);
-            ERR("SSL Error: %s (err=%d,status=%d)",errorString,err,result);
-            cyassl_free() ;
+        DBG("SSLver=%d", SSLver);
+        short ssl_connect_status = this->ssl_connect();
+        if (ssl_connect_status != 0) {
+            ERR("SSL connection failure: %d\r\n",ssl_connect_status);
+            ssl_cleanup();
             return HTTP_CONN;
         }
+        DBG("SSL connection succeeded...\r\n");
     } /* SSL connect complete */
 
     //Send request
@@ -668,7 +688,7 @@
         }
 
     }
-    cyassl_free() ;
+    ssl_cleanup() ;
     m_sock.close();
     DBG("Completed HTTP transaction");
     if(redirect)return HTTP_REDIRECT ;
@@ -688,15 +708,15 @@
     int ret;
 
     if(port == HTTPS_PORT) {
-        DBG("Enter CyaSSL_read") ;
+        DBG("Enter ssl_socket_read") ;
 
         m_sock.set_blocking(false, m_timeout);
-        readLen = CyaSSL_read(ssl, buf, maxLen);
+        readLen = ssl_socket_read(&this->ssl, buf, maxLen, m_timeout);
         if (readLen > 0) {
             buf[readLen] = 0;
-            DBG("CyaSSL_read:%s\n", buf);
+            DBG("ssl_socket_read:%s\n", buf);
         } else {
-            ERR("CyaSSL_read, ret = %d", readLen) ;
+            ERR("ssl_socket_read, ret = %d", readLen) ;
             return HTTP_ERROR ;
         }
         DBG("Read %d bytes", readLen);
@@ -789,12 +809,13 @@
     }
 
     if(port == HTTPS_PORT) {
-        DBG("Enter CyaSSL_write") ;
-        if (CyaSSL_write(ssl, buf, len) != len) {
-            ERR("SSL_write failed");
+        DBG("Enter ssl_socket_write");
+        int write_len = ssl_socket_write(&this->ssl, buf, len);
+        if (write_len != len) {
+            ERR("ssl_socket_write failed: wrote: %d bytes, expected to write %d bytes\r\n",write_len,len);
             return HTTP_ERROR ;
         }
-        DBG("Written %d bytes", writtenLen);
+        DBG("ssl_socket_write: sent %d bytes", writtenLen);
         return HTTP_OK;
     }
     m_sock.set_blocking(false, m_timeout);