Azure IoT common library

Fork of azure_c_shared_utility by Azure IoT

Revision:
13:920e00014ee3
Parent:
11:77df6d7e65ae
Child:
14:b7e6599cacf5
--- a/httpapi_compact.c	Thu Sep 22 18:17:00 2016 -0700
+++ b/httpapi_compact.c	Thu Oct 20 17:08:18 2016 -0700
@@ -27,24 +27,22 @@
 #define MAX_HOSTNAME     64
 #define TEMP_BUFFER_SIZE 1024
 
+/*Codes_SRS_HTTPAPI_COMPACT_21_076: [ The HTTPAPI_ExecuteRequest shall try to read the message with the response up to 20 times. ]*/
+/*Codes_SRS_HTTPAPI_COMPACT_21_077: [ If the HTTPAPI_ExecuteRequest retries 20 times to receive the message without success, it shall fail and return HTTPAPI_READ_DATA_FAILED. ]*/
+#define MAX_RECEIVE_RETRY   20
+/*Codes_SRS_HTTPAPI_COMPACT_21_078: [ The HTTPAPI_ExecuteRequest shall wait, at least, 100 milliseconds between retries. ]*/
+#define RECEIVE_RETRY_INTERVAL_IN_MICROSECONDS  100
+#define OPEN_RETRY_INTERVAL_IN_MICROSECONDS  100
+
 
 DEFINE_ENUM_STRINGS(HTTPAPI_RESULT, HTTPAPI_RESULT_VALUES)
 
-typedef enum SEND_ALL_RESULT_TAG
-{
-    SEND_ALL_RESULT_NOT_STARTED,
-    SEND_ALL_RESULT_PENDING,
-    SEND_ALL_RESULT_OK,
-    SEND_ALL_RESULT_ERROR
-} SEND_ALL_RESULT;
-
 typedef struct HTTP_HANDLE_DATA_TAG
 {
     char*           certificate;
     XIO_HANDLE      xio_handle;
     size_t          received_bytes_count;
     unsigned char*  received_bytes;
-    SEND_ALL_RESULT send_all_result;
     unsigned int    is_io_error : 1;
     unsigned int    is_connected : 1;
 } HTTP_HANDLE_DATA;
@@ -187,26 +185,26 @@
 /*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* httpHandle;
+    HTTP_HANDLE_DATA* http_instance;
     TLSIO_CONFIG tlsio_config;
 
 	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;
+		http_instance = 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;
+		http_instance = NULL;
 	}
 	else
 	{
-		httpHandle = (HTTP_HANDLE_DATA*)malloc(sizeof(HTTP_HANDLE_DATA));
+		http_instance = (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)
+		if (http_instance == NULL)
 		{
 			LogError("There is no memory to control the http connection");
 		}
@@ -215,70 +213,68 @@
 			tlsio_config.hostname = hostName;
 			tlsio_config.port = 443;
 
-			httpHandle->xio_handle = xio_create(platform_get_default_tlsio(), (void*)&tlsio_config);
+			http_instance->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)
+			if (http_instance->xio_handle == NULL)
 			{
 				LogError("Create connection failed");
-				free(httpHandle);
-				httpHandle = NULL;
+				free(http_instance);
+				http_instance = 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;
+				http_instance->is_connected = 0;
+				http_instance->is_io_error = 0;
+				http_instance->received_bytes_count = 0;
+				http_instance->received_bytes = NULL;
+				http_instance->certificate = NULL;
 			}
 		}
 	}
 
 	/*Codes_SRS_HTTPAPI_COMPACT_21_012: [ The HTTPAPI_CreateConnection shall return a non-NULL handle on success. ]*/
-	return (HTTP_HANDLE)httpHandle;
+	return (HTTP_HANDLE)http_instance;
 }
 
 void HTTPAPI_CloseConnection(HTTP_HANDLE handle)
 {
-    HTTP_HANDLE_DATA* httpHandle = (HTTP_HANDLE_DATA*)handle;
+    HTTP_HANDLE_DATA* http_instance = (HTTP_HANDLE_DATA*)handle;
 
 	/*Codes_SRS_HTTPAPI_COMPACT_21_020: [ If the connection handle is NULL, the HTTPAPI_CloseConnection shall not do anything. ]*/
-	if (httpHandle != NULL)
+	if (http_instance != 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)
+		if (http_instance->xio_handle != NULL)
         {
 			/*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);
+            xio_destroy(http_instance->xio_handle);
         }
 
 		/*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)
+		if (http_instance->certificate)
         {
-            free(httpHandle->certificate);
+            free(http_instance->certificate);
         }
 
-        free(httpHandle);
+        free(http_instance);
     }
 }
 
 static void on_io_open_complete(void* context, IO_OPEN_RESULT open_result)
 {
-    HTTP_HANDLE_DATA* httpHandle = (HTTP_HANDLE_DATA*)context;
+    HTTP_HANDLE_DATA* http_instance = (HTTP_HANDLE_DATA*)context;
     
-    if (httpHandle != NULL)
+    if (http_instance != NULL)
 	{
 		if (open_result == IO_OPEN_OK)
 		{
-			httpHandle->is_connected = 1;
-			httpHandle->is_io_error = 0;
+			http_instance->is_connected = 1;
+			http_instance->is_io_error = 0;
 		}
 		else
 		{
-			httpHandle->is_io_error = 1;
+			http_instance->is_io_error = 1;
 		}
 	}
 }
@@ -315,36 +311,36 @@
 static void on_bytes_received(void* context, const unsigned char* buffer, size_t size)
 {
     unsigned char* new_received_bytes;
-    HTTP_HANDLE_DATA* httpHandle = (HTTP_HANDLE_DATA*)context;
+    HTTP_HANDLE_DATA* http_instance = (HTTP_HANDLE_DATA*)context;
 
-    if (httpHandle != NULL)
-	{
+    if (http_instance != NULL)
+    {
 
         if (buffer == NULL)
         {
-            httpHandle->is_io_error = 1;
-            LogError("on_bytes_received: NULL pointer error");
+            http_instance->is_io_error = 1;
+            LogError("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);
+            new_received_bytes = (unsigned char*)realloc(http_instance->received_bytes, http_instance->received_bytes_count + size);
             if (new_received_bytes == NULL)
             {
-                httpHandle->is_io_error = 1;
-                LogError("on_bytes_received: Error allocating memory for received data");
+                http_instance->is_io_error = 1;
+                LogError("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)
+                http_instance->received_bytes = new_received_bytes;
+                if (memcpy(http_instance->received_bytes + http_instance->received_bytes_count, buffer, size) == NULL)
                 {
-                    httpHandle->is_io_error = 1;
-                    LogError("on_bytes_received: Error copping received data to the HTTP bufffer");
+                    http_instance->is_io_error = 1;
+                    LogError("Error copping received data to the HTTP bufffer");
                 }
                 else
                 {
-                    httpHandle->received_bytes_count += size;
+                    http_instance->received_bytes_count += size;
                 }
             }
         }
@@ -353,12 +349,12 @@
 
 static void on_io_error(void* context)
 {
-    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");
-	}
+    HTTP_HANDLE_DATA* http_instance = (HTTP_HANDLE_DATA*)context;
+    if (http_instance != NULL)
+    {
+        http_instance->is_io_error = 1;
+        LogError("Error signalled by underlying IO");
+    }
 }
 
 static int conn_receive(HTTP_HANDLE_DATA* http_instance, char* buffer, int count)
@@ -380,7 +376,7 @@
 			/* 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");
+                LogError("xio reported error on dowork");
                 result = -1;
 				break;
 			}
@@ -403,7 +399,7 @@
 				break;
 			}
 
-			ThreadAPI_Sleep(1);
+			ThreadAPI_Sleep(RECEIVE_RETRY_INTERVAL_IN_MICROSECONDS);
 		}
 	}
 
@@ -412,149 +408,105 @@
 
 static void conn_receive_discard_buffer(HTTP_HANDLE_DATA* http_instance)
 {
-    if (http_instance->received_bytes != NULL)
+    if (http_instance != NULL)
     {
-        free(http_instance->received_bytes);
-        http_instance->received_bytes = NULL;
+        if (http_instance->received_bytes != NULL)
+        {
+            free(http_instance->received_bytes);
+            http_instance->received_bytes = NULL;
+        }
+        http_instance->received_bytes_count = 0;
     }
-    http_instance->received_bytes_count = 0;
 }
 
-
-static void on_send_complete(void* context, IO_SEND_RESULT send_result)
+static int readLine(HTTP_HANDLE_DATA* http_instance, char* buf, const size_t maxBufSize)
 {
-    HTTP_HANDLE_DATA* http_instance = (HTTP_HANDLE_DATA*)context;
-    
-    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;
-		}
-	}
-}
+    int resultLineSize;
 
-static int conn_send_all(HTTP_HANDLE_DATA* http_instance, const unsigned char* buffer, size_t count)
-{
-    int result;
-
-	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;
+    if ((http_instance == NULL) || (buf == NULL) || (maxBufSize < 0))
+    {
+        LogError("%s", ((http_instance == NULL) ? "Invalid HTTP instance" : "Invalid HTTP buffer"));
+        resultLineSize = -1;
     }
     else
     {
-        http_instance->send_all_result = SEND_ALL_RESULT_PENDING;
-        if (xio_send(http_instance->xio_handle, buffer, count, on_send_complete, http_instance) != 0)
+        char* destByte = buf;
+        /*Codes_SRS_HTTPAPI_COMPACT_21_076: [ The HTTPAPI_ExecuteRequest shall try to read the message with the response up to 20 times. ]*/
+        int countRetry = MAX_RECEIVE_RETRY;
+        bool endOfSearch = false;
+        resultLineSize = -1;
+        while (!endOfSearch)
         {
-            LogError("conn_send_all: xio failed sending data");
-            result = -1;
-        }
-        else
-        {
-            /* 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 any error was detected while receiving then simply break and report it */
+            if (http_instance->is_io_error != 0)
+            {
+                LogError("xio reported error on dowork");
+                endOfSearch = true;
+            }
+            else
             {
-                /* If we got an error signalled from the underlying IO we simply report it up */
-                if (http_instance->is_io_error)
+                unsigned char* receivedByte = http_instance->received_bytes;
+                while (receivedByte < (http_instance->received_bytes + http_instance->received_bytes_count))
                 {
-                    http_instance->send_all_result = SEND_ALL_RESULT_ERROR;
-                    break;
-                }
+                    if ((*receivedByte) != '\r')
+                    {
+                        (*destByte) = (*receivedByte);
+                        destByte++;
+                        receivedByte++;
 
-                if (http_instance->send_all_result != SEND_ALL_RESULT_PENDING)
-                {
-                    break;
+                        if (destByte >= (buf + maxBufSize - 1))
+                        {
+                            LogError("Received message is bigger than the http buffer");
+                            receivedByte = http_instance->received_bytes + http_instance->received_bytes_count;
+                            endOfSearch = true;
+                            break;
+                        }
+                    }
+                    else
+                    {
+                        receivedByte++;
+                        if ((receivedByte < (http_instance->received_bytes + http_instance->received_bytes_count)) && ((*receivedByte) == '\n'))
+                        {
+                            receivedByte++;
+                        }
+                        (*destByte) = '\0';
+                        resultLineSize = (int)(destByte - buf);
+                        endOfSearch = true;
+                        break;
+                    }
                 }
 
-                xio_dowork(http_instance->xio_handle);
-
-                /* We yield the CPU for a bit so others can do their work */
-                ThreadAPI_Sleep(1);
+                http_instance->received_bytes_count -= (receivedByte - http_instance->received_bytes);
+                if (http_instance->received_bytes_count != 0)
+                {
+                    (void)memmove(http_instance->received_bytes, receivedByte, http_instance->received_bytes_count);
+                }
+                else
+                {
+                    conn_receive_discard_buffer(http_instance);
+                }
             }
 
-            /* The send_all_result indicates what is the status for the send operation.
-               Not started - means nothing should happen since no send was started
-               Pending - a send was started, but it is still being carried out 
-               Ok - Send complete
-               Error - error */
-            switch (http_instance->send_all_result)
+            if (!endOfSearch)
             {
-                default:
-                case SEND_ALL_RESULT_NOT_STARTED:
-                    result = -1;
-                    break;
-
-                case SEND_ALL_RESULT_OK:
-                    result = (int)count;
-                    break;
-
-                case SEND_ALL_RESULT_ERROR:
-                    result = -1;
-                    break;
+                if ((countRetry--) > 0)
+                {
+                    /*Codes_SRS_HTTPAPI_COMPACT_21_078: [ The HTTPAPI_ExecuteRequest shall wait, at least, 100 milliseconds between retries. ]*/
+                    ThreadAPI_Sleep(RECEIVE_RETRY_INTERVAL_IN_MICROSECONDS);
+                }
+                else
+                {
+                    /*Codes_SRS_HTTPAPI_COMPACT_21_077: [ If the HTTPAPI_ExecuteRequest retries 20 times to receive the message without success, it shall fail and return HTTPAPI_READ_DATA_FAILED. ]*/
+                    LogError("Timeout. The HTTP request is incomplete");
+                    endOfSearch = true;
+                }
             }
         }
     }
 
-    return result;
-}
-
-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
-	int result;
-    char* substr = buf;
-    char  c;
-
-	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);
-        }
-    }
-
-	return result;
+    return resultLineSize;
 }
 
 static int readChunk(HTTP_HANDLE_DATA* http_instance, char* buf, size_t size)
@@ -583,40 +535,77 @@
     return offset;
 }
 
-static int skipN(HTTP_HANDLE_DATA* http_instance, size_t n, char* buf, size_t size)
+static int skipN(HTTP_HANDLE_DATA* http_instance, size_t n)
 {
-    int org = (int)n;
     // read and abandon response content with specified length
     // returns -1 in case of error.
-    while (n > size)
+
+    int result;
+
+    if (http_instance == NULL)
+    {
+        LogError("Invalid HTTP instance");
+        result = -1;
+    }
+    else
     {
-		if (readChunk(http_instance, (char*)buf, size) < 0)
-		{
-			org = -1;
-			break;
-		}
+        /*Codes_SRS_HTTPAPI_COMPACT_21_076: [ The HTTPAPI_ExecuteRequest shall try to read the message with the response up to 20 times. ]*/
+        int countRetry = MAX_RECEIVE_RETRY;
+        result = (int)n;
+        while (n > 0)
+        {
+            xio_dowork(http_instance->xio_handle);
 
-        n -= size;
+            /* if any error was detected while receiving then simply break and report it */
+            if (http_instance->is_io_error != 0)
+            {
+                LogError("xio reported error on dowork");
+                result = -1;
+                n = 0;
+            }
+            else
+            {
+                if (http_instance->received_bytes_count <= n)
+                {
+                    n -= http_instance->received_bytes_count;
+                    http_instance->received_bytes_count = 0;
+                }
+                else
+                {
+                    http_instance->received_bytes_count -= n;
+                    (void)memmove(http_instance->received_bytes, http_instance->received_bytes + n, http_instance->received_bytes_count);
+                    n = 0;
+                }
+
+                if (n > 0)
+                {
+                    if ((countRetry--) > 0)
+                    {
+                        /*Codes_SRS_HTTPAPI_COMPACT_21_078: [ The HTTPAPI_ExecuteRequest shall wait, at least, 100 milliseconds between retries. ]*/
+                        ThreadAPI_Sleep(RECEIVE_RETRY_INTERVAL_IN_MICROSECONDS);
+                    }
+                    else
+                    {
+                        /*Codes_SRS_HTTPAPI_COMPACT_21_077: [ If the HTTPAPI_ExecuteRequest retries 20 times to receive the message without success, it shall fail and return HTTPAPI_READ_DATA_FAILED. ]*/
+                        LogError("Timeout. The HTTP request is incomplete");
+                        n = 0;
+                        result = -1;
+                    }
+                }
+            }
+        }
     }
 
-	if (org >= 0)
-	{
-		if (readChunk(http_instance, (char*)buf, n) < 0)
-		{
-			org = -1;
-		}
-	}
-
-    return org;
+    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. ]*/
-static HTTPAPI_RESULT OpenXIOConnection(HTTP_HANDLE_DATA* httpHandle)
+static HTTPAPI_RESULT OpenXIOConnection(HTTP_HANDLE_DATA* http_instance)
 {
 	HTTPAPI_RESULT result;
 
-	if (httpHandle->is_connected != 0)
+	if (http_instance->is_connected != 0)
 	{
 		/*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
 		result = HTTPAPI_OK;
@@ -624,8 +613,8 @@
 	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))
+		if ((http_instance->certificate != NULL) &&
+			(xio_setoption(http_instance->xio_handle, "TrustedCerts", http_instance->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;
@@ -634,7 +623,7 @@
 		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)
+			if (xio_open(http_instance->xio_handle, on_io_open_complete, http_instance, on_bytes_received, http_instance, on_io_error, http_instance) != 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;
@@ -643,18 +632,18 @@
 			{
 				/*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))
+				while ((http_instance->is_connected == 0) &&
+					(http_instance->is_io_error == 0))
 				{
-					xio_dowork(httpHandle->xio_handle);
+					xio_dowork(http_instance->xio_handle);
 					LogInfo("Waiting for TLS connection");
-					ThreadAPI_Sleep(1);
+					ThreadAPI_Sleep(OPEN_RETRY_INTERVAL_IN_MICROSECONDS);
 				}
 			}
 		}
 	}
 	
-	if ((httpHandle->is_io_error != 0) && (result == HTTPAPI_OK))
+	if ((http_instance->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;
@@ -671,7 +660,7 @@
 }
 
 /*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)
+static HTTPAPI_RESULT SendHeadsToXIO(HTTP_HANDLE_DATA* http_instance, HTTPAPI_REQUEST_TYPE requestType, const char* relativePath, HTTP_HEADERS_HANDLE httpHeadersHandle, size_t headersCount)
 {
 	HTTPAPI_RESULT result;
 	char    buf[TEMP_BUFFER_SIZE];
@@ -686,8 +675,8 @@
 		/*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)
-	{
+    else if (xio_send(http_instance->xio_handle, (const unsigned char*)buf, strlen(buf), NULL, NULL) != 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;
 	}
@@ -706,13 +695,13 @@
 			}
 			else
 			{
-				if (conn_send_all(httpHandle, (const unsigned char*)header, strlen(header)) < 0)
-				{
+                if (xio_send(http_instance->xio_handle, (const unsigned char*)header, strlen(header), NULL, NULL) != 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)
-				{
+                if (xio_send(http_instance->xio_handle, (const unsigned char*)"\r\n", (size_t)2, NULL, NULL) != 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;
 				}
@@ -721,8 +710,8 @@
 		}
 
 		//Close headers
-		if (conn_send_all(httpHandle, (const unsigned char*)"\r\n", (size_t)2) < 0)
-		{
+        if (xio_send(http_instance->xio_handle, (const unsigned char*)"\r\n", (size_t)2, NULL, NULL) != 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;
 		}
@@ -731,7 +720,7 @@
 }
 
 /*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)
+static HTTPAPI_RESULT SendContentToXIO(HTTP_HANDLE_DATA* http_instance, const unsigned char* content, size_t contentLength)
 {
 	HTTPAPI_RESULT result;
 
@@ -740,8 +729,8 @@
 	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)
-		{
+        if (xio_send(http_instance->xio_handle, content, contentLength, NULL, NULL) != 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;
 		}
@@ -761,24 +750,25 @@
 }
 
 /*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)
+static HTTPAPI_RESULT RecieveHeaderFromXIO(HTTP_HANDLE_DATA* http_instance, unsigned int* statusCode)
 {
 	HTTPAPI_RESULT result;
 	char    buf[TEMP_BUFFER_SIZE];
 	int     ret;
 
 	//Receive response
-	if (readLine(httpHandle, buf, TEMP_BUFFER_SIZE) < 0)
+	if (readLine(http_instance, 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;
+        /*Codes_SRS_HTTPAPI_COMPACT_21_077: [ If the HTTPAPI_ExecuteRequest retries 20 times to receive the message without success, it shall fail and 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");
+        LogInfo("Not a correct HTTP answer");
 		result = HTTPAPI_RECEIVE_RESPONSE_FAILED;
 	}
 	else
@@ -797,7 +787,7 @@
 	return result;
 }
 
-static HTTPAPI_RESULT RecieveContentInfoFromXIO(HTTP_HANDLE_DATA* httpHandle, HTTP_HEADERS_HANDLE responseHeadersHandle, size_t* bodyLength, bool* chunked)
+static HTTPAPI_RESULT RecieveContentInfoFromXIO(HTTP_HANDLE_DATA* http_instance, HTTP_HEADERS_HANDLE responseHeadersHandle, size_t* bodyLength, bool* chunked)
 {
 	HTTPAPI_RESULT result;
 	char    buf[TEMP_BUFFER_SIZE];
@@ -812,10 +802,11 @@
 	const int ChunkedSize = 8;
 
 	//Read HTTP response headers
-	if (readLine(httpHandle, buf, sizeof(buf)) < 0)
+	if (readLine(http_instance, 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;
+        /*Codes_SRS_HTTPAPI_COMPACT_21_077: [ If the HTTPAPI_ExecuteRequest retries 20 times to receive the message without success, it shall fail and return HTTPAPI_READ_DATA_FAILED. ]*/
+        result = HTTPAPI_READ_DATA_FAILED;
 	}
 	else
 	{
@@ -859,10 +850,11 @@
 					HTTPHeaders_AddHeaderNameValuePair(responseHeadersHandle, buf, whereIsColon + 1);
 				}
 
-				if (readLine(httpHandle, buf, sizeof(buf)) < 0)
+				if (readLine(http_instance, 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;
+                    /*Codes_SRS_HTTPAPI_COMPACT_21_077: [ If the HTTPAPI_ExecuteRequest retries 20 times to receive the message without success, it shall fail and return HTTPAPI_READ_DATA_FAILED. ]*/
+                    result = HTTPAPI_READ_DATA_FAILED;
 				}
 			}
 		}
@@ -871,7 +863,7 @@
 	return result;
 }
 
-static HTTPAPI_RESULT ReadHTTPResponseBodyFromXIO(HTTP_HANDLE_DATA* httpHandle, size_t bodyLength, bool chunked, BUFFER_HANDLE responseContent)
+static HTTPAPI_RESULT ReadHTTPResponseBodyFromXIO(HTTP_HANDLE_DATA* http_instance, size_t bodyLength, bool chunked, BUFFER_HANDLE responseContent)
 {
 	HTTPAPI_RESULT result;
 	char    buf[TEMP_BUFFER_SIZE];
@@ -896,7 +888,7 @@
 					/*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)
+				else if (readChunk(http_instance, (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;
@@ -907,12 +899,19 @@
 					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_051: [ If the responseContent is NULL, the HTTPAPI_ExecuteRequest shall ignore any content in the response. ]*/
+                if (skipN(http_instance, bodyLength) < 0)
+                {
+                    /*Codes_SRS_HTTPAPI_COMPACT_21_077: [ If the HTTPAPI_ExecuteRequest retries 20 times to receive the message without success, it shall fail and return HTTPAPI_READ_DATA_FAILED. ]*/
+                    result = HTTPAPI_READ_DATA_FAILED;
+                }
+                else
+                {
+                    result = HTTPAPI_OK;
+                }
+            }
 		}
 		else
 		{
@@ -928,10 +927,11 @@
 		while (result == HTTPAPI_OK)
 		{
 			size_t chunkSize;
-			if (readLine(httpHandle, buf, sizeof(buf)) < 0)    // read [length in hex]/r/n
+			if (readLine(http_instance, 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;
+                /*Codes_SRS_HTTPAPI_COMPACT_21_077: [ If the HTTPAPI_ExecuteRequest retries 20 times to receive the message without success, it shall fail and 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)
 			{
@@ -942,7 +942,7 @@
 			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
+				if (readChunk(http_instance, (char*)buf, (size_t)2) < 0
 					|| buf[0] != '\r' || buf[1] != '\n') // skip /r/n
 				{
 					(void)BUFFER_unbuild(responseContent);
@@ -969,7 +969,7 @@
 						/*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)
+					else if (readChunk(http_instance, (char*)receivedContent + size, chunkSize) < 0)
 					{
 						result = HTTPAPI_READ_DATA_FAILED;
 					}
@@ -977,15 +977,16 @@
 				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)
+					if (skipN(http_instance, chunkSize) < 0)
 					{
-						result = HTTPAPI_READ_DATA_FAILED;
+                        /*Codes_SRS_HTTPAPI_COMPACT_21_077: [ If the HTTPAPI_ExecuteRequest retries 20 times to receive the message without success, it shall fail and return HTTPAPI_READ_DATA_FAILED. ]*/
+                        result = HTTPAPI_READ_DATA_FAILED;
 					}
 				}
 
 				if (result == HTTPAPI_OK)
 				{
-					if (readChunk(httpHandle, (char*)buf, (size_t)2) < 0
+					if (readChunk(http_instance, (char*)buf, (size_t)2) < 0
 						|| buf[0] != '\r' || buf[1] != '\n') // skip /r/n
 					{
 						result = HTTPAPI_READ_DATA_FAILED;
@@ -1034,7 +1035,7 @@
     size_t  headersCount;
     size_t  bodyLength = 0;
     bool    chunked = false;
-	HTTP_HANDLE_DATA* httpHandle = (HTTP_HANDLE_DATA*)handle;
+	HTTP_HANDLE_DATA* http_instance = (HTTP_HANDLE_DATA*)handle;
 
 	/*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. ]*/
@@ -1043,7 +1044,7 @@
 	/*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 ||
+	if (http_instance == NULL ||
         relativePath == NULL ||
         httpHeadersHandle == NULL ||
 		!validRequestType(requestType) ||
@@ -1053,44 +1054,45 @@
         LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
     }
 	/*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)
+	else if ((result = OpenXIOConnection(http_instance)) != 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)
+	else if ((result = SendHeadsToXIO(http_instance, 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)
+	else if ((result = SendContentToXIO(http_instance, 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)
+	else if ((result = RecieveHeaderFromXIO(http_instance, 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)
+	else if ((result = RecieveContentInfoFromXIO(http_instance, 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)
+	else if ((result = ReadHTTPResponseBodyFromXIO(http_instance, bodyLength, chunked, responseContent)) != HTTPAPI_OK)
 	{
 		LogError("Read HTTP response body from HTTP failed (result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
 	}
 
-	/*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))
+    conn_receive_discard_buffer(http_instance);
+
+    /*Codes_SRS_HTTPAPI_COMPACT_21_031: [ After receive the response, the HTTPAPI_ExecuteRequest shall close the transport connection with the host. ]*/
+	if ((http_instance != NULL) &&
+        (http_instance->is_connected != 0))
     {
-        conn_receive_discard_buffer(httpHandle);
-        xio_close(httpHandle->xio_handle, NULL, NULL);
-        httpHandle->is_connected = 0;
+        xio_close(http_instance->xio_handle, NULL, NULL);
+        http_instance->is_connected = 0;
     }
 
     return result;
@@ -1102,10 +1104,10 @@
 HTTPAPI_RESULT HTTPAPI_SetOption(HTTP_HANDLE handle, const char* optionName, const void* value)
 {
     HTTPAPI_RESULT result;
-    HTTP_HANDLE_DATA* httpHandle = (HTTP_HANDLE_DATA*)handle;
+    HTTP_HANDLE_DATA* http_instance = (HTTP_HANDLE_DATA*)handle;
 
 	if (
-        (httpHandle == NULL) ||
+        (http_instance == NULL) ||
         (optionName == NULL) ||
         (value == NULL)
         )
@@ -1117,14 +1119,14 @@
     }
     else if (strcmp("TrustedCerts", optionName) == 0)
     {
-        if (httpHandle->certificate)
+        if (http_instance->certificate)
         {
-            free(httpHandle->certificate);
+            free(http_instance->certificate);
         }
 
         int len = (int)strlen((char*)value);
-        httpHandle->certificate = (char*)malloc((len + 1) * sizeof(char));
-        if (httpHandle->certificate == NULL)
+        http_instance->certificate = (char*)malloc((len + 1) * sizeof(char));
+        if (http_instance->certificate == NULL)
         {
 			/*SRS_HTTPAPI_COMPACT_21_062: [ If any memory allocation get fail, the HTTPAPI_SetOption shall return HTTPAPI_ALLOC_FAILED. ]*/
 			result = HTTPAPI_ALLOC_FAILED;
@@ -1133,7 +1135,7 @@
         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);
+            (void)strcpy(http_instance->certificate, (const char*)value);
             result = HTTPAPI_OK;
         }
     }