Azure IoT common library

Dependents:   STM32F746_iothub_client_sample_mqtt f767zi_mqtt iothub_client_sample_amqp iothub_client_sample_http ... more

Revision:
11:77df6d7e65ae
Parent:
7:1af47e3a19b6
Child:
13:920e00014ee3
diff -r 1be0bc9a9deb -r 77df6d7e65ae httpapi_compact.c
--- a/httpapi_compact.c	Fri Aug 26 12:59:40 2016 -0700
+++ b/httpapi_compact.c	Fri Sep 09 13:38:26 2016 -0700
@@ -7,9 +7,8 @@
 #endif
 
 #include <stdio.h>
-#include <stdlib.h>
 #include <ctype.h>
-#include "azure_c_shared_utility/httpapi.h"
+#include "azure_c_shared_utility/gballoc.h"
 #include "azure_c_shared_utility/httpheaders.h"
 #include "azure_c_shared_utility/crt_abstractions.h"
 #include "azure_c_shared_utility/xlogging.h"
@@ -20,10 +19,14 @@
 #include <string.h>
 #include <limits.h>
 
+/*Codes_SRS_HTTPAPI_COMPACT_21_001: [ The httpapi_compact shall implement the methods defined by the `httpapi.h`. ]*/ 
+/*Codes_SRS_HTTPAPI_COMPACT_21_002: [ The httpapi_compact shall support the http requests. ]*/
+/*Codes_SRS_HTTPAPI_COMPACT_21_003: [ The httpapi_compact shall return error codes defined by HTTPAPI_RESULT. ]*/
+#include "azure_c_shared_utility/httpapi.h"
+
 #define MAX_HOSTNAME     64
-#define TEMP_BUFFER_SIZE 4096
+#define TEMP_BUFFER_SIZE 1024
 
-#define CHAR_COUNT(A)   (sizeof(A) - 1)
 
 DEFINE_ENUM_STRINGS(HTTPAPI_RESULT, HTTPAPI_RESULT_VALUES)
 
@@ -37,7 +40,6 @@
 
 typedef struct HTTP_HANDLE_DATA_TAG
 {
-    char            host[MAX_HOSTNAME];
     char*           certificate;
     XIO_HANDLE      xio_handle;
     size_t          received_bytes_count;
@@ -51,288 +53,399 @@
 /*this function only exists because some of platforms do not have sscanf. */
 static int ParseStringToDecimal(const char *src, int* dst)
 {
+	int result;
     char* next;
     (*dst) = strtol(src, &next, 0);
     if ((src == next) || ((((*dst) == LONG_MAX) || ((*dst) == LONG_MIN)) && (errno != 0)))
     {
-        return EOF;
+		result = EOF;
     }
-    return 1;
+	else
+	{
+		result = 1;
+	}
+    return result;
 }
 
 /*the following function does the same as sscanf(pos2, "%x", &sec)*/
 /*this function only exists because some of platforms do not have sscanf. This is not a full implementation; it only works with well-defined x numbers. */
 #define HEXA_DIGIT_VAL(c)         (((c>='0') && (c<='9')) ? (c-'0') : ((c>='a') && (c<='f')) ? (c-'a'+10) : ((c>='A') && (c<='F')) ? (c-'A'+10) : -1)
-static int ParseStringToHexadecimal(const char *src, int* dst)
+static int ParseStringToHexadecimal(const char *src, size_t* dst)
 {
-    if (src == NULL)
-        return EOF;
-    if (HEXA_DIGIT_VAL(*src) == -1)
-        return EOF;
-
+	int result;
     int digitVal;
-    (*dst) = 0;
-    while ((digitVal = HEXA_DIGIT_VAL(*src)) != -1)
-    {
-        (*dst) *= 0x10;
-        (*dst) += digitVal;
-        src++;
-    }
-    return 1;
+    if (src == NULL)
+	{
+		result = EOF;
+	}
+	else if (HEXA_DIGIT_VAL(*src) == -1)
+	{
+		result = EOF;
+	}
+	else
+	{
+		(*dst) = 0;
+		while ((digitVal = HEXA_DIGIT_VAL(*src)) != -1)
+		{
+			(*dst) *= 0x10;
+			(*dst) += (size_t)digitVal;
+			src++;
+		}
+		result = 1;
+	}
+    return result;
 }
 
 /*the following function does the same as sscanf(buf, "HTTP/%*d.%*d %d %*[^\r\n]", &ret) */
 /*this function only exists because some of platforms do not have sscanf. This is not a full implementation; it only works with well-defined HTTP response. */
-static int ParseHttpResponse(const char* src, int* dst)
+static int  ParseHttpResponse(const char* src, int* dst)
 {
-    const char* prefix = "HTTP/";
-    while ((*prefix) != '\0')
-    {
-        if ((*prefix) != (*src))
-            return EOF;
-        prefix++;
-        src++;
-    }
+	int result;
+	static const char HTTPPrefix[] = "HTTP/";
+    bool fail;
+    const char* runPrefix;
+
+	if ((src == NULL) || (dst == NULL))
+	{
+		result = EOF;
+	}
+	else
+	{
+		fail = false;
+		runPrefix = HTTPPrefix;
+
+		while((*runPrefix) != '\0')
+		{
+			if ((*runPrefix) != (*src))
+			{
+				fail = true;
+				break;
+			}
+			src++;
+			runPrefix++;
+		}
 
-    while ((*src) != '.')
-    {
-        if ((*src) == '\0')
-            return EOF;
-    }
+		if (!fail)
+		{
+			while ((*src) != '.')
+			{
+				if ((*src) == '\0')
+				{
+					fail = true;
+                    break;
+				}
+				src++;
+			}
+		}
 
-    while ((*src) != ' ')
-    {
-        if ((*src) == '\0')
-            return EOF;
-    }
+		if (!fail)
+		{
+			while ((*src) != ' ')
+			{
+				if ((*src) == '\0')
+				{
+					fail = true;
+                    break;
+				}
+				src++;
+			}
+		}
 
-    return ParseStringToDecimal(src, dst);
+		if (fail)
+		{
+			result = EOF;
+		}
+		else
+		{
+			result = ParseStringToDecimal(src, dst);
+		}
+	}
+
+    return result;
 }
 
 HTTPAPI_RESULT HTTPAPI_Init(void)
 {
+	/*Codes_SRS_HTTPAPI_COMPACT_21_004: [ The HTTPAPI_Init shall allocate all memory to control the http protocol. ]*/
+	/*Codes_SRS_HTTPAPI_COMPACT_21_007: [ If there is not enough memory to control the http protocol, the HTTPAPI_Init shall return HTTPAPI_ALLOC_FAILED. ]*/
+	/**
+	 * No memory is necessary. 
+	 */
+
+	/*Codes_SRS_HTTPAPI_COMPACT_21_006: [ If HTTPAPI_Init succeed allocating all the needed memory, it shall return HTTPAPI_OK. ]*/
     return HTTPAPI_OK;
 }
 
 void HTTPAPI_Deinit(void)
 {
+	/*Codes_SRS_HTTPAPI_COMPACT_21_009: [ The HTTPAPI_Init shall release all memory allocated by the httpapi_compact. ]*/
+	/**
+	* No memory was necessary.
+	*/
 }
 
+/*Codes_SRS_HTTPAPI_COMPACT_21_011: [ The HTTPAPI_CreateConnection shall create an http connection to the host specified by the hostName parameter. ]*/
 HTTP_HANDLE HTTPAPI_CreateConnection(const char* hostName)
 {
-    HTTP_HANDLE_DATA* handle = NULL;
+    HTTP_HANDLE_DATA* httpHandle;
+    TLSIO_CONFIG tlsio_config;
 
-    if (hostName)
-    {
-        handle = (HTTP_HANDLE_DATA*)malloc(sizeof(HTTP_HANDLE_DATA));
-        if (handle != NULL)
-        {
-            if (strcpy_s(handle->host, MAX_HOSTNAME, hostName) != 0)
-            {
-                LogError("HTTPAPI_CreateConnection::Could not strcpy_s");
-                free(handle);
-                handle = NULL;
-            }
-            else
-            {
-                TLSIO_CONFIG tlsio_config = { hostName, 443 };
-                handle->xio_handle = xio_create(platform_get_default_tlsio(), (void*)&tlsio_config);
-                if (handle->xio_handle == NULL)
-                {
-                    LogError("HTTPAPI_CreateConnection::xio_create failed");
-                    free(handle->host);
-                    free(handle);
-                    handle = NULL;
-                }
-                else
-                {
-                    handle->is_connected = 0;
-                    handle->is_io_error = 0;
-                    handle->received_bytes_count = 0;
-                    handle->received_bytes = NULL;
-                    handle->send_all_result = SEND_ALL_RESULT_NOT_STARTED;
-                    handle->certificate = NULL;
-                }
-            }
-        }
-    }
-    else
-    {
-        LogInfo("HTTPAPI_CreateConnection:: null hostName parameter");
-    }
+	if (hostName == NULL)
+	{
+		/*Codes_SRS_HTTPAPI_COMPACT_21_014: [ If the hostName is NULL, the HTTPAPI_CreateConnection shall return NULL as the handle. ]*/
+		LogError("Invalid host name. Null hostName parameter.");
+		httpHandle = NULL;
+	}
+	else if (*hostName == '\0')
+	{
+		/*Codes_SRS_HTTPAPI_COMPACT_21_015: [ If the hostName is empty, the HTTPAPI_CreateConnection shall return NULL as the handle. ]*/
+		LogError("Invalid host name. Empty string.");
+		httpHandle = NULL;
+	}
+	else
+	{
+		httpHandle = (HTTP_HANDLE_DATA*)malloc(sizeof(HTTP_HANDLE_DATA));
+		/*Codes_SRS_HTTPAPI_COMPACT_21_013: [ If there is not enough memory to control the http connection, the HTTPAPI_CreateConnection shall return NULL as the handle. ]*/
+		if (httpHandle == NULL)
+		{
+			LogError("There is no memory to control the http connection");
+		}
+		else
+		{
+			tlsio_config.hostname = hostName;
+			tlsio_config.port = 443;
 
-    return (HTTP_HANDLE)handle;
+			httpHandle->xio_handle = xio_create(platform_get_default_tlsio(), (void*)&tlsio_config);
+
+			/*Codes_SRS_HTTPAPI_COMPACT_21_016: [ If the HTTPAPI_CreateConnection failed to create the connection, it shall return NULL as the handle. ]*/
+			if (httpHandle->xio_handle == NULL)
+			{
+				LogError("Create connection failed");
+				free(httpHandle);
+				httpHandle = NULL;
+			}
+			else
+			{
+				httpHandle->is_connected = 0;
+				httpHandle->is_io_error = 0;
+				httpHandle->received_bytes_count = 0;
+				httpHandle->received_bytes = NULL;
+				httpHandle->send_all_result = SEND_ALL_RESULT_NOT_STARTED;
+				httpHandle->certificate = NULL;
+			}
+		}
+	}
+
+	/*Codes_SRS_HTTPAPI_COMPACT_21_012: [ The HTTPAPI_CreateConnection shall return a non-NULL handle on success. ]*/
+	return (HTTP_HANDLE)httpHandle;
 }
 
 void HTTPAPI_CloseConnection(HTTP_HANDLE handle)
 {
-    HTTP_HANDLE_DATA* h = (HTTP_HANDLE_DATA*)handle;
+    HTTP_HANDLE_DATA* httpHandle = (HTTP_HANDLE_DATA*)handle;
 
-    if (h)
+	/*Codes_SRS_HTTPAPI_COMPACT_21_020: [ If the connection handle is NULL, the HTTPAPI_CloseConnection shall not do anything. ]*/
+	if (httpHandle != NULL)
     {
-        if (h->xio_handle != NULL)
+		/*Codes_SRS_HTTPAPI_COMPACT_21_019: [ If there is no previous connection, the HTTPAPI_CloseConnection shall not do anything. ]*/
+		if (httpHandle->xio_handle != NULL)
         {
-            LogInfo("HTTPAPI_CloseConnection xio_destroy(); to %s", h->host);
-            xio_destroy(h->xio_handle);
+			/*Codes_SRS_HTTPAPI_COMPACT_21_017: [ The HTTPAPI_CloseConnection shall close the connection previously created in HTTPAPI_CreateConnection. ]*/
+			LogInfo("Close http connection.");
+            xio_destroy(httpHandle->xio_handle);
         }
 
-        if (h->certificate)
+		/*Codes_SRS_HTTPAPI_COMPACT_21_018: [ If there is a certificate associated to this connection, the HTTPAPI_CloseConnection shall free all allocated memory for the certificate. ]*/
+		if (httpHandle->certificate)
         {
-            free(h->certificate);
+            free(httpHandle->certificate);
         }
 
-        free(h);
+        free(httpHandle);
     }
 }
 
 static void on_io_open_complete(void* context, IO_OPEN_RESULT open_result)
 {
-    HTTP_HANDLE_DATA* h = (HTTP_HANDLE_DATA*)context;
-    if (open_result == IO_OPEN_OK)
-    {
-        h->is_connected = 1;
-        h->is_io_error = 0;
-    }
-    else
-    {
-        h->is_io_error = 1;
-    }
+    HTTP_HANDLE_DATA* httpHandle = (HTTP_HANDLE_DATA*)context;
+    
+    if (httpHandle != NULL)
+	{
+		if (open_result == IO_OPEN_OK)
+		{
+			httpHandle->is_connected = 1;
+			httpHandle->is_io_error = 0;
+		}
+		else
+		{
+			httpHandle->is_io_error = 1;
+		}
+	}
 }
 
-static int my_strnicmp(const char* s1, const char* s2, size_t n)
+#define TOLOWER(c) (((c>='A') && (c<='Z'))?c-'A'+'a':c)
+static int InternStrnicmp(const char* s1, const char* s2, size_t n)
 {
-    size_t i;
-    int result = 0;
+    int result;
 
-    for (i = 0; i < n; i++)
-    {
-        /* compute the difference between the chars */
-        result = tolower(s1[i]) - tolower(s2[i]);
+	if ((s1 == NULL) || (s2 == NULL))
+	{
+		result = -1;
+	}
+	else
+	{
+		result = 0;
+		while (((n--) >= 0) && ((*s1) != '\0') && ((*s2) != '\0') && (result == 0))
+		{
+			/* compute the difference between the chars */
+			result = TOLOWER(*s1) - TOLOWER(*s2);
+			s1++;
+			s2++;
+		}
 
-        /* break if we have a difference ... */
-        if ((result != 0) ||
-            /* ... or if we got to the end of one the strings */
-            (s1[i] == '\0') || (s2[i] == '\0'))
+        if ((*s2) != '\0')
         {
-            break;
+            result = -1;
         }
-    }
+	}
 
     return result;
 }
 
-static int my_stricmp(const char* s1, const char* s2)
-{
-    size_t i = 0;
-
-    while ((s1[i] != '\0') && (s2[i] != '\0'))
-    {
-        /* break if we have a difference ... */
-        if (tolower(s1[i]) != tolower(s2[i]))
-        {
-            break;
-        }
-
-        i++;
-    }
-
-    /* if we broke because we are at end of string this will yield 0 */
-    /* if we broke because there was a difference this will yield non-zero  */
-    return tolower(s1[i]) - tolower(s2[i]);
-}
-
 static void on_bytes_received(void* context, const unsigned char* buffer, size_t size)
 {
-    HTTP_HANDLE_DATA* h = (HTTP_HANDLE_DATA*)context;
+    unsigned char* new_received_bytes;
+    HTTP_HANDLE_DATA* httpHandle = (HTTP_HANDLE_DATA*)context;
+
+    if (httpHandle != NULL)
+	{
 
-    /* Here we got some bytes so we'll buffer them so the receive functions can consumer it */
-    unsigned char* new_received_bytes = (unsigned char*)realloc(h->received_bytes, h->received_bytes_count + size);
-    if (new_received_bytes == NULL)
-    {
-        h->is_io_error = 1;
-        LogError("on_bytes_received: Error allocating memory for received data");
-    }
-    else
-    {
-        h->received_bytes = new_received_bytes;
-        (void)memcpy(h->received_bytes + h->received_bytes_count, buffer, size);
-        h->received_bytes_count += size;
-    }
+        if (buffer == NULL)
+        {
+            httpHandle->is_io_error = 1;
+            LogError("on_bytes_received: NULL pointer error");
+        }
+        else
+        {
+            /* Here we got some bytes so we'll buffer them so the receive functions can consumer it */
+            new_received_bytes = (unsigned char*)realloc(httpHandle->received_bytes, httpHandle->received_bytes_count + size);
+            if (new_received_bytes == NULL)
+            {
+                httpHandle->is_io_error = 1;
+                LogError("on_bytes_received: Error allocating memory for received data");
+            }
+            else
+            {
+                httpHandle->received_bytes = new_received_bytes;
+                if (memcpy(httpHandle->received_bytes + httpHandle->received_bytes_count, buffer, size) == NULL)
+                {
+                    httpHandle->is_io_error = 1;
+                    LogError("on_bytes_received: Error copping received data to the HTTP bufffer");
+                }
+                else
+                {
+                    httpHandle->received_bytes_count += size;
+                }
+            }
+        }
+	}
 }
 
 static void on_io_error(void* context)
 {
-    HTTP_HANDLE_DATA* h = (HTTP_HANDLE_DATA*)context;
-    h->is_io_error = 1;
-    LogError("on_io_error: Error signalled by underlying IO");
+    HTTP_HANDLE_DATA* httpHandle = (HTTP_HANDLE_DATA*)context;
+    if (httpHandle != NULL)
+	{
+		httpHandle->is_io_error = 1;
+		LogError("on_io_error: Error signalled by underlying IO");
+	}
 }
 
 static int conn_receive(HTTP_HANDLE_DATA* http_instance, char* buffer, int count)
 {
-    int result = 0;
+    int result;
 
-    if (count < 0)
-    {
+	if ((http_instance == NULL) || (buffer == NULL) || (count < 0))
+	{
+        LogError("conn_receive: %s", ((http_instance == NULL) ? "Invalid HTTP instance" : "Invalid HTTP buffer"));
         result = -1;
-    }
-    else
-    {
-        while (result < count)
-        {
-            xio_dowork(http_instance->xio_handle);
+	}
+	else
+	{
+		result = 0;
+		while (result < count)
+		{
+			xio_dowork(http_instance->xio_handle);
 
-            /* if any error was detected while receiving then simply break and report it */
-            if (http_instance->is_io_error != 0)
-            {
+			/* if any error was detected while receiving then simply break and report it */
+			if (http_instance->is_io_error != 0)
+			{
+                LogError("conn_receive: xio reported error on dowork");
                 result = -1;
-                break;
-            }
+				break;
+			}
 
-            if (http_instance->received_bytes_count >= (size_t)count)
-            {
-                /* Consuming bytes from the receive buffer */
-                (void)memcpy(buffer, http_instance->received_bytes, count);
-                (void)memmove(http_instance->received_bytes, http_instance->received_bytes + count, http_instance->received_bytes_count - count);
-                http_instance->received_bytes_count -= count;
+			if (http_instance->received_bytes_count >= (size_t)count)
+			{
+				/* Consuming bytes from the receive buffer */
+				(void)memcpy(buffer, http_instance->received_bytes, count);
+				(void)memmove(http_instance->received_bytes, http_instance->received_bytes + count, http_instance->received_bytes_count - count);
+				http_instance->received_bytes_count -= count;
 
-                /* we're not reallocating at each consumption so that we don't trash due to byte by byte consumption */
-                if (http_instance->received_bytes_count == 0)
-                {
-                    free(http_instance->received_bytes);
-                    http_instance->received_bytes = NULL;
-                }
+				/* we're not reallocating at each consumption so that we don't trash due to byte by byte consumption */
+				if (http_instance->received_bytes_count == 0)
+				{
+					free(http_instance->received_bytes);
+					http_instance->received_bytes = NULL;
+				}
 
-                result = count;
-                break;
-            }
+				result = count;
+				break;
+			}
 
-            ThreadAPI_Sleep(1);
-        }
-    }
+			ThreadAPI_Sleep(1);
+		}
+	}
 
     return result;
 }
 
+static void conn_receive_discard_buffer(HTTP_HANDLE_DATA* http_instance)
+{
+    if (http_instance->received_bytes != NULL)
+    {
+        free(http_instance->received_bytes);
+        http_instance->received_bytes = NULL;
+    }
+    http_instance->received_bytes_count = 0;
+}
+
+
 static void on_send_complete(void* context, IO_SEND_RESULT send_result)
 {
-    /* If a send is complete we'll simply signal this by changing the send all state */
     HTTP_HANDLE_DATA* http_instance = (HTTP_HANDLE_DATA*)context;
-    if (send_result == IO_SEND_OK)
-    {
-        http_instance->send_all_result = SEND_ALL_RESULT_OK;
-    }
-    else
-    {
-        http_instance->send_all_result = SEND_ALL_RESULT_ERROR;
-    }
+    
+    if (http_instance != NULL)
+	{
+		/* If a send is complete we'll simply signal this by changing the send all state */
+		if (send_result == IO_SEND_OK)
+		{
+			http_instance->send_all_result = SEND_ALL_RESULT_OK;
+		}
+		else
+		{
+			http_instance->send_all_result = SEND_ALL_RESULT_ERROR;
+		}
+	}
 }
 
-static int conn_send_all(HTTP_HANDLE_DATA* http_instance, char* buffer, int count)
+static int conn_send_all(HTTP_HANDLE_DATA* http_instance, const unsigned char* buffer, size_t count)
 {
     int result;
 
-    if (count < 0)
-    {
+	if ((http_instance == NULL) || (buffer == 0) || (count < (size_t)0))
+	{
+        LogError("conn_send_all: %s", ((http_instance == NULL) ? "Invalid HTTP instance" : "Invalid HTTP buffer"));
         result = -1;
     }
     else
@@ -340,6 +453,7 @@
         http_instance->send_all_result = SEND_ALL_RESULT_PENDING;
         if (xio_send(http_instance->xio_handle, buffer, count, on_send_complete, http_instance) != 0)
         {
+            LogError("conn_send_all: xio failed sending data");
             result = -1;
         }
         else
@@ -347,8 +461,6 @@
             /* We have to loop in here until all bytes are sent or we encounter an error. */
             while (1)
             {
-                xio_dowork(http_instance->xio_handle);
-
                 /* If we got an error signalled from the underlying IO we simply report it up */
                 if (http_instance->is_io_error)
                 {
@@ -361,6 +473,8 @@
                     break;
                 }
 
+                xio_dowork(http_instance->xio_handle);
+
                 /* We yield the CPU for a bit so others can do their work */
                 ThreadAPI_Sleep(1);
             }
@@ -378,7 +492,7 @@
                     break;
 
                 case SEND_ALL_RESULT_OK:
-                    result = count;
+                    result = (int)count;
                     break;
 
                 case SEND_ALL_RESULT_ERROR:
@@ -394,41 +508,75 @@
 static int readLine(HTTP_HANDLE_DATA* http_instance, char* buf, const size_t size)
 {
     // reads until \r\n is encountered. writes in buf all the characters
-    char* p = buf;
+	int result;
+    char* substr = buf;
     char  c;
-    if (conn_receive(http_instance, &c, 1) < 0)
-        return -1;
-    while (c != '\r') {
-        if ((p - buf + 1) >= (int)size)
-            return -1;
-        *p++ = c;
-        if (conn_receive(http_instance, &c, 1) < 0)
-            return -1;
+
+	if (conn_receive(http_instance, &c, 1) < 0)
+	{
+        result = -1;
+	}
+	else
+	{
+		result = 0;
+		while (c != '\r') 
+		{
+			if ((substr - buf + 1) >= (int)size)
+			{
+                result = -1;
+                conn_receive_discard_buffer(http_instance);
+                break;
+			}
+            else
+            {
+                *substr++ = c;
+            }
+			
+			if (conn_receive(http_instance, &c, 1) < 0)
+			{
+				result = -1;
+				break;
+			}
+		}
+
+		if (result != -1)
+		{
+			*substr = 0;
+			if (conn_receive(http_instance, &c, 1) < 0 || c != '\n') // skip \n
+			{
+				result = -1;
+			}
+		}
+
+        if (result != -1)
+        {
+            result = (int)(substr - buf);
+        }
     }
-    *p = 0;
-    if (conn_receive(http_instance, &c, 1) < 0 || c != '\n') // skip \n
-        return -1;
-    return p - buf;
+
+	return result;
 }
 
 static int readChunk(HTTP_HANDLE_DATA* http_instance, char* buf, size_t size)
 {
-    size_t cur, offset;
+    int cur, offset;
 
     // read content with specified length, even if it is received
     // only in chunks due to fragmentation in the networking layer.
     // returns -1 in case of error.
     offset = 0;
-    while (size > 0)
+    while (size > (size_t)0)
     {
-        cur = conn_receive(http_instance, buf + offset, size);
+        cur = conn_receive(http_instance, buf + offset, (int)size);
 
         // end of stream reached
-        if (cur == 0)
-            return offset;
+		if (cur == 0)
+		{
+			break;
+		}
 
         // read cur bytes (might be less than requested)
-        size -= cur;
+        size -= (size_t)cur;
         offset += cur;
     }
 
@@ -437,23 +585,444 @@
 
 static int skipN(HTTP_HANDLE_DATA* http_instance, size_t n, char* buf, size_t size)
 {
-    size_t org = n;
+    int org = (int)n;
     // read and abandon response content with specified length
     // returns -1 in case of error.
     while (n > size)
     {
-        if (readChunk(http_instance, (char*)buf, size) < 0)
-            return -1;
+		if (readChunk(http_instance, (char*)buf, size) < 0)
+		{
+			org = -1;
+			break;
+		}
 
         n -= size;
     }
 
-    if (readChunk(http_instance, (char*)buf, n) < 0)
-        return -1;
+	if (org >= 0)
+	{
+		if (readChunk(http_instance, (char*)buf, n) < 0)
+		{
+			org = -1;
+		}
+	}
 
     return org;
 }
 
+
+/*Codes_SRS_HTTPAPI_COMPACT_21_021: [ The HTTPAPI_ExecuteRequest shall execute the http communtication with the provided host, sending a request and reciving the response. ]*/
+static HTTPAPI_RESULT OpenXIOConnection(HTTP_HANDLE_DATA* httpHandle)
+{
+	HTTPAPI_RESULT result;
+
+	if (httpHandle->is_connected != 0)
+	{
+		/*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
+		result = HTTPAPI_OK;
+	}
+	else
+	{
+		/*Codes_SRS_HTTPAPI_COMPACT_21_022: [ If a Certificate was provided, the HTTPAPI_ExecuteRequest shall set this option on the transport layer. ]*/
+		if ((httpHandle->certificate != NULL) &&
+			(xio_setoption(httpHandle->xio_handle, "TrustedCerts", httpHandle->certificate) != 0))
+		{
+			/*Codes_SRS_HTTPAPI_COMPACT_21_023: [ If the transport failed setting the Certificate, the HTTPAPI_ExecuteRequest shall not send any request and return HTTPAPI_SET_OPTION_FAILED. ]*/
+			result = HTTPAPI_SET_OPTION_FAILED;
+			LogInfo("Could not load certificate");
+		}
+		else
+		{
+			/*Codes_SRS_HTTPAPI_COMPACT_21_024: [ The HTTPAPI_ExecuteRequest shall open the transport connection with the host to send the request. ]*/
+			if (xio_open(httpHandle->xio_handle, on_io_open_complete, httpHandle, on_bytes_received, httpHandle, on_io_error, httpHandle) != 0)
+			{
+				/*Codes_SRS_HTTPAPI_COMPACT_21_025: [ If the open process failed, the HTTPAPI_ExecuteRequest shall not send any request and return HTTPAPI_OPEN_REQUEST_FAILED. ]*/
+				result = HTTPAPI_OPEN_REQUEST_FAILED;
+			}
+			else
+			{
+				/*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
+				result = HTTPAPI_OK;
+				while ((httpHandle->is_connected == 0) &&
+					(httpHandle->is_io_error == 0))
+				{
+					xio_dowork(httpHandle->xio_handle);
+					LogInfo("Waiting for TLS connection");
+					ThreadAPI_Sleep(1);
+				}
+			}
+		}
+	}
+	
+	if ((httpHandle->is_io_error != 0) && (result == HTTPAPI_OK))
+	{
+		/*Codes_SRS_HTTPAPI_COMPACT_21_025: [ If the open process failed, the HTTPAPI_ExecuteRequest shall not send any request and return HTTPAPI_OPEN_REQUEST_FAILED. ]*/
+		result = HTTPAPI_OPEN_REQUEST_FAILED;
+	}
+
+	return result;
+}
+
+/*Codes_SRS_HTTPAPI_COMPACT_21_035: [ The HTTPAPI_ExecuteRequest shall execute resquest for types `GET`, `POST`, `PUT`, `DELETE`, `PATCH`. ]*/
+const char httpapiRequestString[5][7] = { "GET", "POST", "PUT", "DELETE", "PATCH" };
+const char* get_request_type(HTTPAPI_REQUEST_TYPE requestType)
+{
+    return (const char*)httpapiRequestString[requestType];
+}
+
+/*Codes_SRS_HTTPAPI_COMPACT_21_026: [ If the open process succeed, the HTTPAPI_ExecuteRequest shall send the request message to the host. ]*/
+static HTTPAPI_RESULT SendHeadsToXIO(HTTP_HANDLE_DATA* httpHandle, HTTPAPI_REQUEST_TYPE requestType, const char* relativePath, HTTP_HEADERS_HANDLE httpHeadersHandle, size_t headersCount)
+{
+	HTTPAPI_RESULT result;
+	char    buf[TEMP_BUFFER_SIZE];
+	int     ret;
+
+	//Send request
+	/*Codes_SRS_HTTPAPI_COMPACT_21_038: [ The HTTPAPI_ExecuteRequest shall execute the resquest for the path in relativePath parameter. ]*/
+	/*Codes_SRS_HTTPAPI_COMPACT_21_036: [ The request type shall be provided in the parameter requestType. ]*/
+	if (((ret = snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\n", get_request_type(requestType), relativePath)) < 0) ||
+		(ret >= sizeof(buf)))
+	{
+		/*Codes_SRS_HTTPAPI_COMPACT_21_027: [ If the HTTPAPI_ExecuteRequest cannot create a buffer to send the request, it shall not send any request and return HTTPAPI_STRING_PROCESSING_ERROR. ]*/
+		result = HTTPAPI_STRING_PROCESSING_ERROR;
+	}
+	else if (conn_send_all(httpHandle, (const unsigned char*)buf, strlen(buf)) < 0)
+	{
+		/*Codes_SRS_HTTPAPI_COMPACT_21_028: [ If the HTTPAPI_ExecuteRequest cannot send the request header, it shall return HTTPAPI_HTTP_HEADERS_FAILED. ]*/
+		result = HTTPAPI_SEND_REQUEST_FAILED;
+	}
+	else
+	{
+		//Send default headers
+		/*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
+		result = HTTPAPI_OK;
+		for (size_t i = 0; ((i < headersCount) && (result == HTTPAPI_OK)); i++)
+		{
+			char* header;
+			if (HTTPHeaders_GetHeader(httpHeadersHandle, i, &header) != HTTP_HEADERS_OK)
+			{
+				/*Codes_SRS_HTTPAPI_COMPACT_21_027: [ If the HTTPAPI_ExecuteRequest cannot create a buffer to send the request, it shall not send any request and return HTTPAPI_STRING_PROCESSING_ERROR. ]*/
+				result = HTTPAPI_STRING_PROCESSING_ERROR;
+			}
+			else
+			{
+				if (conn_send_all(httpHandle, (const unsigned char*)header, strlen(header)) < 0)
+				{
+					/*Codes_SRS_HTTPAPI_COMPACT_21_028: [ If the HTTPAPI_ExecuteRequest cannot send the request header, it shall return HTTPAPI_HTTP_HEADERS_FAILED. ]*/
+					result = HTTPAPI_SEND_REQUEST_FAILED;
+				}
+				if (conn_send_all(httpHandle, (const unsigned char*)"\r\n", (size_t)2) < 0)
+				{
+					/*Codes_SRS_HTTPAPI_COMPACT_21_028: [ If the HTTPAPI_ExecuteRequest cannot send the request header, it shall return HTTPAPI_HTTP_HEADERS_FAILED. ]*/
+					result = HTTPAPI_SEND_REQUEST_FAILED;
+				}
+				free(header);
+			}
+		}
+
+		//Close headers
+		if (conn_send_all(httpHandle, (const unsigned char*)"\r\n", (size_t)2) < 0)
+		{
+			/*Codes_SRS_HTTPAPI_COMPACT_21_028: [ If the HTTPAPI_ExecuteRequest cannot send the request header, it shall return HTTPAPI_HTTP_HEADERS_FAILED. ]*/
+			result = HTTPAPI_SEND_REQUEST_FAILED;
+		}
+	}
+	return result;
+}
+
+/*Codes_SRS_HTTPAPI_COMPACT_21_042: [ The request can contain the a content message, provided in content parameter. ]*/
+static HTTPAPI_RESULT SendContentToXIO(HTTP_HANDLE_DATA* httpHandle, const unsigned char* content, size_t contentLength)
+{
+	HTTPAPI_RESULT result;
+
+	//Send data (if available)
+	/*Codes_SRS_HTTPAPI_COMPACT_21_045: [ If the contentLength is lower than one, the HTTPAPI_ExecuteRequest shall send the request without content. ]*/
+	if (content && contentLength > 0)
+	{
+		/*Codes_SRS_HTTPAPI_COMPACT_21_044: [ If the content is not NULL, the number of bytes in the content shall be provided in contentLength parameter. ]*/
+		if (conn_send_all(httpHandle, content, contentLength) < 0)
+		{
+			/*Codes_SRS_HTTPAPI_COMPACT_21_029: [ If the HTTPAPI_ExecuteRequest cannot send the buffer with the request, it shall return HTTPAPI_SEND_REQUEST_FAILED. ]*/
+			result = HTTPAPI_SEND_REQUEST_FAILED;
+		}
+		else
+		{
+			/*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
+			result = HTTPAPI_OK;
+		}
+	}
+	else
+	{
+		/*Codes_SRS_HTTPAPI_COMPACT_21_043: [ If the content is NULL, the HTTPAPI_ExecuteRequest shall send the request without content. ]*/
+		/*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
+		result = HTTPAPI_OK;
+	}
+	return result;
+}
+
+/*Codes_SRS_HTTPAPI_COMPACT_21_030: [ At the end of the transmission, the HTTPAPI_ExecuteRequest shall receive the response from the host. ]*/
+static HTTPAPI_RESULT RecieveHeaderFromXIO(HTTP_HANDLE_DATA* httpHandle, unsigned int* statusCode)
+{
+	HTTPAPI_RESULT result;
+	char    buf[TEMP_BUFFER_SIZE];
+	int     ret;
+
+	//Receive response
+	if (readLine(httpHandle, buf, TEMP_BUFFER_SIZE) < 0)
+	{
+		/*Codes_SRS_HTTPAPI_COMPACT_21_032: [ If the HTTPAPI_ExecuteRequest cannot read the message with the request result, it shall return HTTPAPI_READ_DATA_FAILED. ]*/
+		result = HTTPAPI_READ_DATA_FAILED;
+	}
+	//Parse HTTP response
+	else if (ParseHttpResponse(buf, &ret) != 1)
+	{
+		//Cannot match string, error
+        /*Codes_SRS_HTTPAPI_COMPACT_21_055: [ If the HTTPAPI_ExecuteRequest cannot parser the recived message, it shall return HTTPAPI_RECEIVE_RESPONSE_FAILED. ]*/
+        LogInfo("HTTPAPI_ExecuteRequest::Not a correct HTTP answer");
+		result = HTTPAPI_RECEIVE_RESPONSE_FAILED;
+	}
+	else
+	{
+		/*Codes_SRS_HTTPAPI_COMPACT_21_046: [ The HTTPAPI_ExecuteRequest shall return the http status reported by the host in the received response. ]*/
+		/*Codes_SRS_HTTPAPI_COMPACT_21_048: [ If the statusCode is NULL, the HTTPAPI_ExecuteRequest shall report not report any status. ]*/
+		if (statusCode)
+		{
+			/*Codes_SRS_HTTPAPI_COMPACT_21_047: [ The HTTPAPI_ExecuteRequest shall report the status in the statusCode parameter. ]*/
+			*statusCode = ret;
+		}
+		/*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
+		result = HTTPAPI_OK;
+	}
+
+	return result;
+}
+
+static HTTPAPI_RESULT RecieveContentInfoFromXIO(HTTP_HANDLE_DATA* httpHandle, HTTP_HEADERS_HANDLE responseHeadersHandle, size_t* bodyLength, bool* chunked)
+{
+	HTTPAPI_RESULT result;
+	char    buf[TEMP_BUFFER_SIZE];
+    const char* substr;
+    char* whereIsColon;
+    int lengthInMsg;
+	const char* ContentLength = "content-length:";
+	const int ContentLengthSize = 16;
+	const char* TransferEncoding = "transfer-encoding:";
+	const int TransferEncodingSize = 19;
+	const char* Chunked = "chunked";
+	const int ChunkedSize = 8;
+
+	//Read HTTP response headers
+	if (readLine(httpHandle, buf, sizeof(buf)) < 0)
+	{
+		/*Codes_SRS_HTTPAPI_COMPACT_21_032: [ If the HTTPAPI_ExecuteRequest cannot read the message with the request result, it shall return HTTPAPI_READ_DATA_FAILED. ]*/
+		result = HTTPAPI_READ_DATA_FAILED;
+	}
+	else
+	{
+		/*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
+		result = HTTPAPI_OK;
+
+		while (*buf && (result == HTTPAPI_OK))
+		{
+			if (InternStrnicmp(buf, ContentLength, ContentLengthSize) == 0)
+			{
+				substr = buf + ContentLengthSize - 1;
+				if (ParseStringToDecimal(substr, &lengthInMsg) != 1)
+				{
+					/*Codes_SRS_HTTPAPI_COMPACT_21_032: [ If the HTTPAPI_ExecuteRequest cannot read the message with the request result, it shall return HTTPAPI_READ_DATA_FAILED. ]*/
+					result = HTTPAPI_READ_DATA_FAILED;
+				}
+				else
+				{
+					(*bodyLength) = (size_t)lengthInMsg;
+				}
+			}
+			else if (InternStrnicmp(buf, TransferEncoding, TransferEncodingSize) == 0)
+			{
+				substr = buf + TransferEncodingSize - 1;
+
+				while (isspace(*substr)) substr++;
+				
+				if (InternStrnicmp(substr, Chunked, ChunkedSize) == 0)
+				{
+					(*chunked) = true;
+				}
+			}
+
+			if (result == HTTPAPI_OK)
+			{
+				whereIsColon = strchr((char*)buf, ':');
+				/*Codes_SRS_HTTPAPI_COMPACT_21_049: [ If responseHeadersHandle is provide, the HTTPAPI_ExecuteRequest shall prepare a Response Header usign the HTTPHeaders_AddHeaderNameValuePair. ]*/
+				if (whereIsColon && (responseHeadersHandle != NULL))
+				{
+					*whereIsColon = '\0';
+					HTTPHeaders_AddHeaderNameValuePair(responseHeadersHandle, buf, whereIsColon + 1);
+				}
+
+				if (readLine(httpHandle, buf, sizeof(buf)) < 0)
+				{
+					/*Codes_SRS_HTTPAPI_COMPACT_21_032: [ If the HTTPAPI_ExecuteRequest cannot read the message with the request result, it shall return HTTPAPI_READ_DATA_FAILED. ]*/
+					result = HTTPAPI_READ_DATA_FAILED;
+				}
+			}
+		}
+	}
+
+	return result;
+}
+
+static HTTPAPI_RESULT ReadHTTPResponseBodyFromXIO(HTTP_HANDLE_DATA* httpHandle, size_t bodyLength, bool chunked, BUFFER_HANDLE responseContent)
+{
+	HTTPAPI_RESULT result;
+	char    buf[TEMP_BUFFER_SIZE];
+	const unsigned char* receivedContent;
+
+	//Read HTTP response body
+	if (!chunked)
+	{
+		if (bodyLength)
+		{
+			if (responseContent != NULL)
+			{
+				if (BUFFER_pre_build(responseContent, bodyLength) != 0)
+				{
+					/*Codes_SRS_HTTPAPI_COMPACT_21_052: [ If any memory allocation get fail, the HTTPAPI_ExecuteRequest shall return HTTPAPI_ALLOC_FAILED. ]*/
+					result = HTTPAPI_ALLOC_FAILED;
+				}
+				else if (BUFFER_content(responseContent, &receivedContent) != 0)
+				{
+					(void)BUFFER_unbuild(responseContent);
+
+					/*Codes_SRS_HTTPAPI_COMPACT_21_052: [ If any memory allocation get fail, the HTTPAPI_ExecuteRequest shall return HTTPAPI_ALLOC_FAILED. ]*/
+					result = HTTPAPI_ALLOC_FAILED;
+				}
+				else if (readChunk(httpHandle, (char*)receivedContent, bodyLength) < 0)
+				{
+					/*Codes_SRS_HTTPAPI_COMPACT_21_032: [ If the HTTPAPI_ExecuteRequest cannot read the message with the request result, it shall return HTTPAPI_READ_DATA_FAILED. ]*/
+					result = HTTPAPI_READ_DATA_FAILED;
+				}
+				else
+				{
+					/*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
+					result = HTTPAPI_OK;
+				}
+			}
+			else
+			{
+				/*Codes_SRS_HTTPAPI_COMPACT_21_051: [ If the responseContent is NULL, the HTTPAPI_ExecuteRequest shall ignore any content in the response. ]*/
+				(void)skipN(httpHandle, bodyLength, buf, sizeof(buf));
+				result = HTTPAPI_OK;
+			}
+		}
+		else
+		{
+			/*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
+			result = HTTPAPI_OK;
+		}
+	}
+	else
+	{
+		size_t size = 0;
+		/*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
+		result = HTTPAPI_OK;
+		while (result == HTTPAPI_OK)
+		{
+			size_t chunkSize;
+			if (readLine(httpHandle, buf, sizeof(buf)) < 0)    // read [length in hex]/r/n
+			{
+				/*Codes_SRS_HTTPAPI_COMPACT_21_032: [ If the HTTPAPI_ExecuteRequest cannot read the message with the request result, it shall return HTTPAPI_READ_DATA_FAILED. ]*/
+				result = HTTPAPI_READ_DATA_FAILED;
+			}
+			else if (ParseStringToHexadecimal(buf, &chunkSize) != 1)     // chunkSize is length of next line (/r/n is not counted)
+			{
+				//Cannot match string, error
+				/*Codes_SRS_HTTPAPI_COMPACT_21_055: [ If the HTTPAPI_ExecuteRequest cannot parser the recived message, it shall return HTTPAPI_RECEIVE_RESPONSE_FAILED. ]*/
+				result = HTTPAPI_RECEIVE_RESPONSE_FAILED;
+			}
+			else if (chunkSize == 0)
+			{
+				// 0 length means next line is just '\r\n' and end of chunks
+				if (readChunk(httpHandle, (char*)buf, (size_t)2) < 0
+					|| buf[0] != '\r' || buf[1] != '\n') // skip /r/n
+				{
+					(void)BUFFER_unbuild(responseContent);
+
+					result = HTTPAPI_READ_DATA_FAILED;
+				}
+				break;
+			}
+			else
+			{
+				if (responseContent != NULL)
+				{
+					if (BUFFER_enlarge(responseContent, chunkSize) != 0)
+					{
+						(void)BUFFER_unbuild(responseContent);
+
+						/*Codes_SRS_HTTPAPI_COMPACT_21_052: [ If any memory allocation get fail, the HTTPAPI_ExecuteRequest shall return HTTPAPI_ALLOC_FAILED. ]*/
+						result = HTTPAPI_ALLOC_FAILED;
+					}
+					else if (BUFFER_content(responseContent, &receivedContent) != 0)
+					{
+						(void)BUFFER_unbuild(responseContent);
+
+						/*Codes_SRS_HTTPAPI_COMPACT_21_052: [ If any memory allocation get fail, the HTTPAPI_ExecuteRequest shall return HTTPAPI_ALLOC_FAILED. ]*/
+						result = HTTPAPI_ALLOC_FAILED;
+					}
+					else if (readChunk(httpHandle, (char*)receivedContent + size, chunkSize) < 0)
+					{
+						result = HTTPAPI_READ_DATA_FAILED;
+					}
+				}
+				else
+				{
+					/*Codes_SRS_HTTPAPI_COMPACT_21_051: [ If the responseContent is NULL, the HTTPAPI_ExecuteRequest shall ignore any content in the response. ]*/
+					if (skipN(httpHandle, chunkSize, buf, sizeof(buf)) < 0)
+					{
+						result = HTTPAPI_READ_DATA_FAILED;
+					}
+				}
+
+				if (result == HTTPAPI_OK)
+				{
+					if (readChunk(httpHandle, (char*)buf, (size_t)2) < 0
+						|| buf[0] != '\r' || buf[1] != '\n') // skip /r/n
+					{
+						result = HTTPAPI_READ_DATA_FAILED;
+					}
+					size += chunkSize;
+				}
+			}
+		}
+
+	}
+	return result;
+}
+
+
+/*Codes_SRS_HTTPAPI_COMPACT_21_037: [ If the request type is unknown, the HTTPAPI_ExecuteRequest shall return HTTPAPI_INVALID_ARG. ]*/
+static bool validRequestType(HTTPAPI_REQUEST_TYPE requestType)
+{
+	bool result;
+
+	if ((requestType == HTTPAPI_REQUEST_GET) ||
+		(requestType == HTTPAPI_REQUEST_POST) ||
+		(requestType == HTTPAPI_REQUEST_PUT) ||
+		(requestType == HTTPAPI_REQUEST_DELETE) ||
+		(requestType == HTTPAPI_REQUEST_PATCH))
+	{
+		result = true;
+	}
+	else
+	{
+		result = false;
+	}
+
+	return result;
+}
+
+/*Codes_SRS_HTTPAPI_COMPACT_21_021: [ The HTTPAPI_ExecuteRequest shall execute the http communtication with the provided host, sending a request and reciving the response. ]*/
+/*Codes_SRS_HTTPAPI_COMPACT_21_050: [ If there is a content in the response, the HTTPAPI_ExecuteRequest shall copy it in the responseContent buffer. ]*/
 //Note: This function assumes that "Host:" and "Content-Length:" headers are setup
 //      by the caller of HTTPAPI_ExecuteRequest() (which is true for httptransport.c).
 HTTPAPI_RESULT HTTPAPI_ExecuteRequest(HTTP_HANDLE handle, HTTPAPI_REQUEST_TYPE requestType, const char* relativePath,
@@ -461,403 +1030,163 @@
     size_t contentLength, unsigned int* statusCode,
     HTTP_HEADERS_HANDLE responseHeadersHandle, BUFFER_HANDLE responseContent)
 {
-
-    HTTPAPI_RESULT result;
+    HTTPAPI_RESULT result = HTTPAPI_ERROR;
     size_t  headersCount;
-    char    buf[TEMP_BUFFER_SIZE];
-    int     ret;
     size_t  bodyLength = 0;
     bool    chunked = false;
-    const unsigned char* receivedContent;
+	HTTP_HANDLE_DATA* httpHandle = (HTTP_HANDLE_DATA*)handle;
 
-    const char* method = (requestType == HTTPAPI_REQUEST_GET) ? "GET"
-        : (requestType == HTTPAPI_REQUEST_POST) ? "POST"
-        : (requestType == HTTPAPI_REQUEST_PUT) ? "PUT"
-        : (requestType == HTTPAPI_REQUEST_DELETE) ? "DELETE"
-        : (requestType == HTTPAPI_REQUEST_PATCH) ? "PATCH"
-        : NULL;
-
-    if (handle == NULL ||
+	/*Codes_SRS_HTTPAPI_COMPACT_21_034: [ If there is no previous connection, the HTTPAPI_ExecuteRequest shall return HTTPAPI_INVALID_ARG. ]*/
+	/*Codes_SRS_HTTPAPI_COMPACT_21_037: [ If the request type is unknown, the HTTPAPI_ExecuteRequest shall return HTTPAPI_INVALID_ARG. ]*/
+	/*Codes_SRS_HTTPAPI_COMPACT_21_039: [ If the relativePath is NULL or invalid, the HTTPAPI_ExecuteRequest shall return HTTPAPI_INVALID_ARG. ]*/
+	/*Codes_SRS_HTTPAPI_COMPACT_21_041: [ If the httpHeadersHandle is NULL or invalid, the HTTPAPI_ExecuteRequest shall return HTTPAPI_INVALID_ARG. ]*/
+	/*Codes_SRS_HTTPAPI_COMPACT_21_053: [ The HTTPAPI_ExecuteRequest shall produce a set of http header to send to the host. ]*/
+	/*Codes_SRS_HTTPAPI_COMPACT_21_040: [ The request shall contain the http header provided in httpHeadersHandle parameter. ]*/
+	/*Codes_SRS_HTTPAPI_COMPACT_21_054: [ If Http header maker cannot provide the number of headers, the HTTPAPI_ExecuteRequest shall return HTTPAPI_INVALID_ARG. ]*/
+	if (httpHandle == NULL ||
         relativePath == NULL ||
         httpHeadersHandle == NULL ||
-        method == NULL ||
+		!validRequestType(requestType) ||
         HTTPHeaders_GetHeaderCount(httpHeadersHandle, &headersCount) != HTTP_HEADERS_OK)
     {
         result = HTTPAPI_INVALID_ARG;
         LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
-        goto exit;
     }
-
-    HTTP_HANDLE_DATA* httpHandle = (HTTP_HANDLE_DATA*)handle;
-
-    if (handle->is_connected == 0)
-    {
-        // Load the certificate
-        if ((httpHandle->certificate != NULL) &&
-			(xio_setoption(httpHandle->xio_handle, "TrustedCerts", httpHandle->certificate) != 0))
-        {
-            result = HTTPAPI_ERROR;
-            LogError("Could not load certificate (result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
-            goto exit;
-        }
+	/*Codes_SRS_HTTPAPI_COMPACT_21_024: [ The HTTPAPI_ExecuteRequest shall open the transport connection with the host to send the request. ]*/
+	else if ((result = OpenXIOConnection(httpHandle)) != HTTPAPI_OK)
+	{
+		LogError("Open HTTP connection failed (result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
+	}
+	/*Codes_SRS_HTTPAPI_COMPACT_21_026: [ If the open process succeed, the HTTPAPI_ExecuteRequest shall send the request message to the host. ]*/
+	else if ((result = SendHeadsToXIO(httpHandle, requestType, relativePath, httpHeadersHandle, headersCount)) != HTTPAPI_OK)
+	{
+		LogError("Send heads to HTTP failed (result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
+	}
+	/*Codes_SRS_HTTPAPI_COMPACT_21_042: [ The request can contain the a content message, provided in content parameter. ]*/
+	else if ((result = SendContentToXIO(httpHandle, content, contentLength)) != HTTPAPI_OK)
+	{
+		LogError("Send content to HTTP failed (result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
+	}
+	/*Codes_SRS_HTTPAPI_COMPACT_21_030: [ At the end of the transmission, the HTTPAPI_ExecuteRequest shall receive the response from the host. ]*/
+	/*Codes_SRS_HTTPAPI_COMPACT_21_073: [ The message recived by the HTTPAPI_ExecuteRequest shall starts with a valid header. ]*/
+	else if ((result = RecieveHeaderFromXIO(httpHandle, statusCode)) != HTTPAPI_OK)
+	{
+		LogError("Receive header from HTTP failed (result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
+	}
+	/*Codes_SRS_HTTPAPI_COMPACT_21_074: [ After the header, the message recieved by the HTTPAPI_ExecuteRequest can contain addition information about the content. ]*/
+	else if ((result = RecieveContentInfoFromXIO(httpHandle, responseHeadersHandle, &bodyLength, &chunked)) != HTTPAPI_OK)
+	{
+		LogError("Receive content information from HTTP failed (result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
+	}
+	/*Codes_SRS_HTTPAPI_COMPACT_21_075: [ The message recieved by the HTTPAPI_ExecuteRequest can contain a body with the message content. ]*/
+	else if ((result = ReadHTTPResponseBodyFromXIO(httpHandle, bodyLength, chunked, responseContent)) != HTTPAPI_OK)
+	{
+		LogError("Read HTTP response body from HTTP failed (result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
+	}
 
-        // Make the connection
-        if (xio_open(httpHandle->xio_handle, on_io_open_complete, httpHandle, on_bytes_received, httpHandle, on_io_error, httpHandle) != 0)
-        {
-            result = HTTPAPI_ERROR;
-            LogError("Could not connect (result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
-            goto exit;
-        }
-
-        while (1)
-        {
-            xio_dowork(httpHandle->xio_handle);
-            if ((handle->is_connected == 1) ||
-                (handle->is_io_error == 1))
-            {
-                break;
-            }
-
-            ThreadAPI_Sleep(1);
-        }
-    }
-
-    //Send request
-    if ((ret = snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\n", method, relativePath)) < 0
-        || ret >= sizeof(buf))
-    {
-        result = HTTPAPI_STRING_PROCESSING_ERROR;
-        LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
-        goto exit;
-    }
-    if (conn_send_all(httpHandle, buf, strlen(buf)) < 0)
+	/*Codes_SRS_HTTPAPI_COMPACT_21_031: [ After receive the response, the HTTPAPI_ExecuteRequest shall close the transport connection with the host. ]*/
+	if ((httpHandle != NULL) &&
+        (httpHandle->is_connected != 0))
     {
-        result = HTTPAPI_SEND_REQUEST_FAILED;
-        LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
-        goto exit;
-    }
-
-    //Send default headers
-    for (size_t i = 0; i < headersCount; i++)
-    {
-        char* header;
-        if (HTTPHeaders_GetHeader(httpHeadersHandle, i, &header) != HTTP_HEADERS_OK)
-        {
-            result = HTTPAPI_HTTP_HEADERS_FAILED;
-            LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
-            goto exit;
-        }
-        if (conn_send_all(httpHandle, header, strlen(header)) < 0)
-        {
-            result = HTTPAPI_SEND_REQUEST_FAILED;
-            LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
-            free(header);
-            goto exit;
-        }
-        if (conn_send_all(httpHandle, "\r\n", 2) < 0)
-        {
-            result = HTTPAPI_SEND_REQUEST_FAILED;
-            LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
-            free(header);
-            goto exit;
-        }
-        free(header);
-    }
-
-    //Close headers
-    if (conn_send_all(httpHandle, "\r\n", 2) < 0)
-    {
-        result = HTTPAPI_SEND_REQUEST_FAILED;
-        LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
-        goto exit;
-    }
-
-    //Send data (if available)
-    if (content && contentLength > 0)
-    {
-        if (conn_send_all(httpHandle, (char*)content, contentLength) < 0)
-        {
-            result = HTTPAPI_SEND_REQUEST_FAILED;
-            LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
-            goto exit;
-        }
+        conn_receive_discard_buffer(httpHandle);
+        xio_close(httpHandle->xio_handle, NULL, NULL);
+        httpHandle->is_connected = 0;
     }
 
-    //Receive response
-    if (readLine(httpHandle, buf, sizeof(buf)) < 0)
-    {
-        result = HTTPAPI_READ_DATA_FAILED;
-        LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
-        goto exit;
-    }
+    return result;
+}
 
-    //Parse HTTP response
-    if (ParseHttpResponse(buf, &ret) != 1)
-    {
-        //Cannot match string, error
-        LogInfo("HTTPAPI_ExecuteRequest::Not a correct HTTP answer=%s", buf);
-        result = HTTPAPI_READ_DATA_FAILED;
-        LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
-        goto exit;
-    }
-    if (statusCode)
-        *statusCode = ret;
+/*Codes_SRS_HTTPAPI_COMPACT_21_056: [ The HTTPAPI_SetOption shall change the HTTP options. ]*/
+/*Codes_SRS_HTTPAPI_COMPACT_21_057: [ The HTTPAPI_SetOption shall recieve a handle that identiry the HTTP connection. ]*/
+/*Codes_SRS_HTTPAPI_COMPACT_21_058: [ The HTTPAPI_SetOption shall recieve the option as a pair optionName/value. ]*/
+HTTPAPI_RESULT HTTPAPI_SetOption(HTTP_HANDLE handle, const char* optionName, const void* value)
+{
+    HTTPAPI_RESULT result;
+    HTTP_HANDLE_DATA* httpHandle = (HTTP_HANDLE_DATA*)handle;
 
-    //Read HTTP response headers
-    if (readLine(httpHandle, buf, sizeof(buf)) < 0)
+	if (
+        (httpHandle == NULL) ||
+        (optionName == NULL) ||
+        (value == NULL)
+        )
     {
-        result = HTTPAPI_READ_DATA_FAILED;
-        LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
-        goto exit;
+		/*Codes_SRS_HTTPAPI_COMPACT_21_059: [ If the handle is NULL, the HTTPAPI_SetOption shall return HTTPAPI_INVALID_ARG. ]*/
+		/*Codes_SRS_HTTPAPI_COMPACT_21_060: [ If the optionName is NULL, the HTTPAPI_SetOption shall return HTTPAPI_INVALID_ARG. ]*/
+		/*Codes_SRS_HTTPAPI_COMPACT_21_061: [ If the value is NULL, the HTTPAPI_SetOption shall return HTTPAPI_INVALID_ARG. ]*/
+		result = HTTPAPI_INVALID_ARG;
     }
-
-    while (buf[0])
+    else if (strcmp("TrustedCerts", optionName) == 0)
     {
-        const char ContentLength[] = "content-length:";
-        const char TransferEncoding[] = "transfer-encoding:";
-
-        if (my_strnicmp(buf, ContentLength, CHAR_COUNT(ContentLength)) == 0)
+        if (httpHandle->certificate)
         {
-            if (ParseStringToDecimal(buf + CHAR_COUNT(ContentLength), &bodyLength) != 1)
-            {
-                result = HTTPAPI_READ_DATA_FAILED;
-                LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
-                goto exit;
-            }
-        }
-        else if (my_strnicmp(buf, TransferEncoding, CHAR_COUNT(TransferEncoding)) == 0)
-        {
-            const char* p = buf + CHAR_COUNT(TransferEncoding);
-            while (isspace(*p)) p++;
-            if (my_stricmp(p, "chunked") == 0)
-                chunked = true;
+            free(httpHandle->certificate);
         }
 
-        char* whereIsColon = strchr((char*)buf, ':');
-        if (whereIsColon && responseHeadersHandle != NULL)
-        {
-            *whereIsColon = '\0';
-            HTTPHeaders_AddHeaderNameValuePair(responseHeadersHandle, buf, whereIsColon + 1);
-        }
-
-        if (readLine(httpHandle, buf, sizeof(buf)) < 0)
-        {
-            result = HTTPAPI_READ_DATA_FAILED;
-            LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
-            goto exit;
-        }
-    }
-
-    //Read HTTP response body
-    if (!chunked)
-    {
-        if (bodyLength)
+        int len = (int)strlen((char*)value);
+        httpHandle->certificate = (char*)malloc((len + 1) * sizeof(char));
+        if (httpHandle->certificate == NULL)
         {
-            if (responseContent != NULL)
-            {
-                if (BUFFER_pre_build(responseContent, bodyLength) != 0)
-                {
-                    result = HTTPAPI_ALLOC_FAILED;
-                    LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
-                }
-                else if (BUFFER_content(responseContent, &receivedContent) != 0)
-                {
-                    (void)BUFFER_unbuild(responseContent);
-
-                    result = HTTPAPI_ALLOC_FAILED;
-                    LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
-                }
-
-                if (readChunk(httpHandle, (char*)receivedContent, bodyLength) < 0)
-                {
-                    result = HTTPAPI_READ_DATA_FAILED;
-                    LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
-                    goto exit;
-                }
-                else
-                {
-                    result = HTTPAPI_OK;
-                }
-            }
-            else
-            {
-                (void)skipN(httpHandle, bodyLength, buf, sizeof(buf));
-                result = HTTPAPI_OK;
-            }
+			/*SRS_HTTPAPI_COMPACT_21_062: [ If any memory allocation get fail, the HTTPAPI_SetOption shall return HTTPAPI_ALLOC_FAILED. ]*/
+			result = HTTPAPI_ALLOC_FAILED;
+            LogInfo("unable to allocate memory for the certificate in HTTPAPI_SetOption");
         }
         else
         {
+			/*SRS_HTTPAPI_COMPACT_21_064: [ If the HTTPAPI_SetOption get success setting the option, it shall return HTTPAPI_OK. ]*/
+            (void)strcpy(httpHandle->certificate, (const char*)value);
             result = HTTPAPI_OK;
         }
     }
     else
     {
-        size_t size = 0;
-        result = HTTPAPI_OK;
-        for (;;)
-        {
-            int chunkSize;
-            if (readLine(httpHandle, buf, sizeof(buf)) < 0)    // read [length in hex]/r/n
-            {
-                result = HTTPAPI_READ_DATA_FAILED;
-                LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
-                goto exit;
-            }
-            if (ParseStringToHexadecimal(buf, &chunkSize) != 1)     // chunkSize is length of next line (/r/n is not counted)
-            {
-                //Cannot match string, error
-                result = HTTPAPI_RECEIVE_RESPONSE_FAILED;
-                LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
-                goto exit;
-            }
-
-            if (chunkSize == 0)
-            {
-                // 0 length means next line is just '\r\n' and end of chunks
-                if (readChunk(httpHandle, (char*)buf, 2) < 0
-                    || buf[0] != '\r' || buf[1] != '\n') // skip /r/n
-                {
-                    (void)BUFFER_unbuild(responseContent);
-
-                    result = HTTPAPI_READ_DATA_FAILED;
-                    LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
-                    goto exit;
-                }
-                break;
-            }
-            else
-            {
-                if (responseContent != NULL)
-                {
-                    if (BUFFER_enlarge(responseContent, chunkSize) != 0)
-                    {
-                        (void)BUFFER_unbuild(responseContent);
-
-                        result = HTTPAPI_ALLOC_FAILED;
-                        LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
-                    }
-                    else if (BUFFER_content(responseContent, &receivedContent) != 0)
-                    {
-                        (void)BUFFER_unbuild(responseContent);
-
-                        result = HTTPAPI_ALLOC_FAILED;
-                        LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
-                    }
-
-                    if (readChunk(httpHandle, (char*)receivedContent + size, chunkSize) < 0)
-                    {
-                        result = HTTPAPI_READ_DATA_FAILED;
-                        LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
-                        goto exit;
-                    }
-                }
-                else
-                {
-                    if (skipN(httpHandle, chunkSize, buf, sizeof(buf)) < 0)
-                    {
-                        result = HTTPAPI_READ_DATA_FAILED;
-                        LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
-                        goto exit;
-                    }
-                }
-
-                if (readChunk(httpHandle, (char*)buf, 2) < 0
-                    || buf[0] != '\r' || buf[1] != '\n') // skip /r/n
-                {
-                    result = HTTPAPI_READ_DATA_FAILED;
-                    LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
-                    goto exit;
-                }
-                size += chunkSize;
-            }
-        }
-
-    }
-
-exit:
-    if ((handle != NULL) &&
-        (handle->is_io_error != 0))
-    {
-        xio_close(handle->xio_handle, NULL, NULL);
-        handle->is_connected = 0;
-    }
-
-    return result;
-}
-
-HTTPAPI_RESULT HTTPAPI_SetOption(HTTP_HANDLE handle, const char* optionName, const void* value)
-{
-    HTTPAPI_RESULT result;
-    if (
-        (handle == NULL) ||
-        (optionName == NULL) ||
-        (value == NULL)
-        )
-    {
+		/*Codes_SRS_HTTPAPI_COMPACT_21_063: [ If the HTTP do not support the optionName, the HTTPAPI_SetOption shall return HTTPAPI_INVALID_ARG. ]*/
         result = HTTPAPI_INVALID_ARG;
-        LogError("invalid parameter (NULL) passed to HTTPAPI_SetOption");
-    }
-    else if (strcmp("TrustedCerts", optionName) == 0)
-    {
-        HTTP_HANDLE_DATA* h = (HTTP_HANDLE_DATA*)handle;
-        if (h->certificate)
-        {
-            free(h->certificate);
-        }
-
-        int len = strlen((char*)value);
-        h->certificate = (char*)malloc(len + 1);
-        if (h->certificate == NULL)
-        {
-            result = HTTPAPI_ERROR;
-            LogError("unable to allocate certificate memory in HTTPAPI_SetOption");
-        }
-        else
-        {
-            (void)strcpy(h->certificate, (const char*)value);
-            result = HTTPAPI_OK;
-        }
-    }
-    else
-    {
-        result = HTTPAPI_INVALID_ARG;
-        LogError("unknown option %s", optionName);
+        LogInfo("unknown option %s", optionName);
     }
     return result;
 }
 
+/*Codes_SRS_HTTPAPI_COMPACT_21_065: [ The HTTPAPI_CloneOption shall provide the means to clone the HTTP option. ]*/
+/*Codes_SRS_HTTPAPI_COMPACT_21_066: [ The HTTPAPI_CloneOption shall return a clone of the value identified by the optionName. ]*/
 HTTPAPI_RESULT HTTPAPI_CloneOption(const char* optionName, const void* value, const void** savedValue)
 {
     HTTPAPI_RESULT result;
-    if (
+    size_t certLen;
+    char* tempCert;
+
+	if (
         (optionName == NULL) ||
         (value == NULL) ||
         (savedValue == NULL)
         )
     {
-        result = HTTPAPI_INVALID_ARG;
-        LogError("invalid argument(NULL) passed to HTTPAPI_CloneOption");
+		/*Codes_SRS_HTTPAPI_COMPACT_21_067: [ If the optionName is NULL, the HTTPAPI_CloneOption shall return HTTPAPI_INVALID_ARG. ]*/
+		/*Codes_SRS_HTTPAPI_COMPACT_21_068: [ If the value is NULL, the HTTPAPI_CloneOption shall return HTTPAPI_INVALID_ARG. ]*/
+		/*Codes_SRS_HTTPAPI_COMPACT_21_069: [ If the savedValue is NULL, the HTTPAPI_CloneOption shall return HTTPAPI_INVALID_ARG. ]*/
+		result = HTTPAPI_INVALID_ARG;
     }
     else if (strcmp("TrustedCerts", optionName) == 0)
     {
-        size_t certLen = strlen((const char*)value);
-        char* tempCert = (char*)malloc(certLen+1);
+        certLen = strlen((const char*)value);
+        tempCert = (char*)malloc((certLen + 1) * sizeof(char));
         if (tempCert == NULL)
         {
-            result = HTTPAPI_INVALID_ARG;
-            LogError("unable to allocate certificate memory in HTTPAPI_CloneOption");
+			/*Codes_SRS_HTTPAPI_COMPACT_21_070: [ If any memory allocation get fail, the HTTPAPI_CloneOption shall return HTTPAPI_ALLOC_FAILED. ]*/
+			result = HTTPAPI_ALLOC_FAILED;
         }
         else
         {
-            (void)strcpy(tempCert, (const char*)value);
+			/*Codes_SRS_HTTPAPI_COMPACT_21_072: [ If the HTTPAPI_CloneOption get success setting the option, it shall return HTTPAPI_OK. ]*/
+			(void)strcpy(tempCert, (const char*)value);
             *savedValue = tempCert;
             result = HTTPAPI_OK;
         }
     }
     else
     {
-        result = HTTPAPI_INVALID_ARG;
-        LogError("unknown option %s", optionName);
+		/*Codes_SRS_HTTPAPI_COMPACT_21_071: [ If the HTTP do not support the optionName, the HTTPAPI_CloneOption shall return HTTPAPI_INVALID_ARG. ]*/
+		result = HTTPAPI_INVALID_ARG;
+        LogInfo("unknown option %s", optionName);
     }
     return result;
 }