Index: azure_iot_hub_f767zi/trunk/azure_iot_sdk/iothub_client/src/blob.c
===================================================================
--- azure_iot_hub_f767zi/trunk/azure_iot_sdk/iothub_client/src/blob.c	(revision 457)
+++ azure_iot_hub_f767zi/trunk/azure_iot_sdk/iothub_client/src/blob.c	(revision 464)
@@ -13,4 +13,8 @@
 #include "azure_c_shared_utility/azure_base64.h"
 #include "azure_c_shared_utility/shared_util_options.h"
+
+static const char blockListXmlBegin[]  = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<BlockList>";
+static const char blockListXmlEnd[] = "</BlockList>";
+static const char blockListUriMarker[] = "&comp=blocklist";
 
 BLOB_RESULT Blob_UploadBlock(
@@ -132,256 +136,262 @@
 }
 
+
+// InvokeUserCallbackAndSendBlobs invokes the application's getDataCallbackEx as many time as callback requests and, for each call,
+// sends the blob contents to the server.
+static BLOB_RESULT InvokeUserCallbackAndSendBlobs(HTTPAPIEX_HANDLE httpApiExHandle, const char* relativePath, STRING_HANDLE blockIDList, IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_CALLBACK_EX getDataCallbackEx, void* context, unsigned int* httpStatus, BUFFER_HANDLE httpResponse)
+{
+    BLOB_RESULT result;
+
+    /*Codes_SRS_BLOB_02_021: [ For every block returned by `getDataCallbackEx` the following operations shall happen: ]*/
+    unsigned int blockID = 0; /* incremented for each new block */
+    unsigned int isError = 0; /* set to 1 if a block upload fails or if getDataCallbackEx returns incorrect blocks to upload */
+    unsigned int uploadOneMoreBlock = 1; /* set to 1 while getDataCallbackEx returns correct blocks to upload */
+    unsigned char const * source = NULL; /* data set by getDataCallbackEx */
+    size_t size = 0; /* source size set by getDataCallbackEx */
+    IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_RESULT getDataReturnValue;
+
+    do
+    {
+        getDataReturnValue = getDataCallbackEx(FILE_UPLOAD_OK, &source, &size, context);
+        if (getDataReturnValue == IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_ABORT)
+        {
+            /*Codes_SRS_BLOB_99_004: [ If `getDataCallbackEx` returns `IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_RESULT_ABORT`, then `Blob_UploadMultipleBlocksFromSasUri` shall exit the loop and return `BLOB_ABORTED`. ]*/
+            LogInfo("Upload to blob has been aborted by the user");
+            uploadOneMoreBlock = 0;
+            result = BLOB_ABORTED;
+        }
+        else if (source == NULL || size == 0)
+        {
+            /*Codes_SRS_BLOB_99_002: [ If the size of the block returned by `getDataCallbackEx` is 0 or if the data is NULL, then `Blob_UploadMultipleBlocksFromSasUri` shall exit the loop. ]*/
+            uploadOneMoreBlock = 0;
+            result = BLOB_OK;
+        }
+        else
+        {
+            if (size > BLOCK_SIZE)
+            {
+                /*Codes_SRS_BLOB_99_001: [ If the size of the block returned by `getDataCallbackEx` is bigger than 4MB, then `Blob_UploadMultipleBlocksFromSasUri` shall fail and return `BLOB_INVALID_ARG`. ]*/
+                LogError("tried to upload block of size %lu, max allowed size is %d", (unsigned long)size, BLOCK_SIZE);
+                result = BLOB_INVALID_ARG;
+                isError = 1;
+            }
+            else if (blockID >= MAX_BLOCK_COUNT)
+            {
+                /*Codes_SRS_BLOB_99_003: [ If `getDataCallbackEx` returns more than 50000 blocks, then `Blob_UploadMultipleBlocksFromSasUri` shall fail and return `BLOB_INVALID_ARG`. ]*/
+                LogError("unable to upload more than %lu blocks in one blob", (unsigned long)MAX_BLOCK_COUNT);
+                result = BLOB_INVALID_ARG;
+                isError = 1;
+            }
+            else
+            {
+                /*Codes_SRS_BLOB_02_023: [ Blob_UploadMultipleBlocksFromSasUri shall create a BUFFER_HANDLE from source and size parameters. ]*/
+                BUFFER_HANDLE requestContent = BUFFER_create(source, size);
+                if (requestContent == NULL)
+                {
+                    /*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR ]*/
+                    LogError("unable to BUFFER_create");
+                    result = BLOB_ERROR;
+                    isError = 1;
+                }
+                else
+                {
+                    result = Blob_UploadBlock(
+                            httpApiExHandle,
+                            relativePath,
+                            requestContent,
+                            blockID,
+                            blockIDList,
+                            httpStatus,
+                            httpResponse);
+
+                    BUFFER_delete(requestContent);
+                }
+
+                /*Codes_SRS_BLOB_02_026: [ Otherwise, if HTTP response code is >=300 then Blob_UploadMultipleBlocksFromSasUri shall succeed and return BLOB_OK. ]*/
+                if (result != BLOB_OK)
+                {
+                    LogError("unable to Blob_UploadBlock. Returned value=%d", result);
+                    isError = 1;
+                }
+                else if (*httpStatus >= 300)
+                {
+                    LogError("unable to Blob_UploadBlock. Returned httpStatus=%u", (unsigned int)*httpStatus);
+                    isError = 1;
+                }
+            }
+            blockID++;
+        }
+    }
+    while(uploadOneMoreBlock && !isError);
+
+    return result;
+}
+
+// SendBlockIdList to send an XML of uploaded blockIds to the server after the application's payload block(s) have been transfered.
+static BLOB_RESULT SendBlockIdList(HTTPAPIEX_HANDLE httpApiExHandle, const char* relativePath, STRING_HANDLE blockIDList, unsigned int* httpStatus, BUFFER_HANDLE httpResponse)
+{
+    BLOB_RESULT result;
+    
+    /*complete the XML*/
+    if (STRING_concat(blockIDList, blockListXmlEnd) != 0)
+    {
+        /*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR ]*/
+        LogError("failed to STRING_concat");
+        result = BLOB_ERROR;
+    }
+    else
+    {
+        /*Codes_SRS_BLOB_02_029: [Blob_UploadMultipleBlocksFromSasUri shall construct a new relativePath from following string : base relativePath + "&comp=blocklist"]*/
+        STRING_HANDLE newRelativePath = STRING_construct(relativePath);
+        if (newRelativePath == NULL)
+        {
+            /*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR ]*/
+            LogError("failed to STRING_construct");
+            result = BLOB_ERROR;
+        }
+        else
+        {
+            if (STRING_concat(newRelativePath, blockListUriMarker) != 0)
+            {
+                /*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR ]*/
+                LogError("failed to STRING_concat");
+                result = BLOB_ERROR;
+            }
+            else
+            {
+                /*Codes_SRS_BLOB_02_030: [ Blob_UploadMultipleBlocksFromSasUri shall call HTTPAPIEX_ExecuteRequest with a PUT operation, passing the new relativePath, httpStatus and httpResponse and the XML string as content. ]*/
+                const char* s = STRING_c_str(blockIDList);
+                BUFFER_HANDLE blockIDListAsBuffer = BUFFER_create((const unsigned char*)s, strlen(s));
+                if (blockIDListAsBuffer == NULL)
+                {
+                    /*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR ]*/
+                    LogError("failed to BUFFER_create");
+                    result = BLOB_ERROR;
+                }
+                else
+                {
+                    if (HTTPAPIEX_ExecuteRequest(
+                        httpApiExHandle,
+                        HTTPAPI_REQUEST_PUT,
+                        STRING_c_str(newRelativePath),
+                        NULL,
+                        blockIDListAsBuffer,
+                        httpStatus,
+                        NULL,
+                        httpResponse
+                    ) != HTTPAPIEX_OK)
+                    {
+                        /*Codes_SRS_BLOB_02_031: [ If HTTPAPIEX_ExecuteRequest fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_HTTP_ERROR. ]*/
+                        LogError("unable to HTTPAPIEX_ExecuteRequest");
+                        result = BLOB_HTTP_ERROR;
+                    }
+                    else
+                    {
+                        /*Codes_SRS_BLOB_02_032: [ Otherwise, Blob_UploadMultipleBlocksFromSasUri shall succeed and return BLOB_OK. ]*/
+                        result = BLOB_OK;
+                    }
+                    BUFFER_delete(blockIDListAsBuffer);
+                }
+            }
+            STRING_delete(newRelativePath);
+        }
+    }
+
+    return result;
+}
+
+
 BLOB_RESULT Blob_UploadMultipleBlocksFromSasUri(const char* SASURI, IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_CALLBACK_EX getDataCallbackEx, void* context, unsigned int* httpStatus, BUFFER_HANDLE httpResponse, const char* certificates, HTTP_PROXY_OPTIONS *proxyOptions)
 {
     BLOB_RESULT result;
+    const char* hostnameBegin;
+    STRING_HANDLE blockIDList = NULL;
+    HTTPAPIEX_HANDLE httpApiExHandle = NULL;
+    char* hostname = NULL;
+    
     /*Codes_SRS_BLOB_02_001: [ If SASURI is NULL then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_INVALID_ARG. ]*/
-    if (SASURI == NULL)
-    {
-        LogError("parameter SASURI is NULL");
+    /*Codes_SRS_BLOB_02_002: [ If getDataCallbackEx is NULL then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_INVALID_ARG. ]*/
+    if ((SASURI == NULL) || (getDataCallbackEx == NULL))
+    {
+        LogError("One or more required values is NULL, SASURI=%p, getDataCallbackEx=%p", SASURI, getDataCallbackEx);
         result = BLOB_INVALID_ARG;
     }
+    /*Codes_SRS_BLOB_02_017: [ Blob_UploadMultipleBlocksFromSasUri shall copy from SASURI the hostname to a new const char* ]*/
+    /*to find the hostname, the following logic is applied:*/
+    /*the hostname starts at the first character after "://"*/
+    /*the hostname ends at the first character before the next "/" after "://"*/
+    else if ((hostnameBegin = strstr(SASURI, "://")) == NULL)
+    {
+        /*Codes_SRS_BLOB_02_005: [ If the hostname cannot be determined, then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_INVALID_ARG. ]*/
+        LogError("hostname cannot be determined");
+        result = BLOB_INVALID_ARG;
+    }
     else
     {
-        /*Codes_SRS_BLOB_02_002: [ If getDataCallbackEx is NULL then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_INVALID_ARG. ]*/
-        if (getDataCallbackEx == NULL)
-        {
-            LogError("IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_CALLBACK_EX getDataCallbackEx is NULL");
+        hostnameBegin += 3; /*have to skip 3 characters which are "://"*/
+        const char* relativePath = strchr(hostnameBegin, '/');
+        if (relativePath == NULL)
+        {
+            /*Codes_SRS_BLOB_02_005: [ If the hostname cannot be determined, then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_INVALID_ARG. ]*/
+            LogError("hostname cannot be determined");
             result = BLOB_INVALID_ARG;
         }
-        /*the below define avoid a "condition always false" on some compilers*/
         else
         {
-            /*Codes_SRS_BLOB_02_017: [ Blob_UploadMultipleBlocksFromSasUri shall copy from SASURI the hostname to a new const char* ]*/
-            /*to find the hostname, the following logic is applied:*/
-            /*the hostname starts at the first character after "://"*/
-            /*the hostname ends at the first character before the next "/" after "://"*/
-            const char* hostnameBegin = strstr(SASURI, "://");
-            if (hostnameBegin == NULL)
-            {
-                /*Codes_SRS_BLOB_02_005: [ If the hostname cannot be determined, then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_INVALID_ARG. ]*/
-                LogError("hostname cannot be determined");
-                result = BLOB_INVALID_ARG;
+            size_t hostnameSize = relativePath - hostnameBegin;
+            if ((hostname = (char*)malloc(hostnameSize + 1)) == NULL)
+            {
+                /*Codes_SRS_BLOB_02_016: [ If the hostname copy cannot be made then then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR ]*/
+                LogError("oom - out of memory");
+                result = BLOB_ERROR;
             }
             else
             {
-                hostnameBegin += 3; /*have to skip 3 characters which are "://"*/
-                const char* hostnameEnd = strchr(hostnameBegin, '/');
-                if (hostnameEnd == NULL)
-                {
-                    /*Codes_SRS_BLOB_02_005: [ If the hostname cannot be determined, then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_INVALID_ARG. ]*/
-                    LogError("hostname cannot be determined");
-                    result = BLOB_INVALID_ARG;
-                }
-                else
-                {
-                    size_t hostnameSize = hostnameEnd - hostnameBegin;
-                    char* hostname = (char*)malloc(hostnameSize + 1); /*+1 because of '\0' at the end*/
-                    if (hostname == NULL)
-                    {
-                        /*Codes_SRS_BLOB_02_016: [ If the hostname copy cannot be made then then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR ]*/
-                        LogError("oom - out of memory");
-                        result = BLOB_ERROR;
-                    }
-                    else
-                    {
-                        HTTPAPIEX_HANDLE httpApiExHandle;
-                        (void)memcpy(hostname, hostnameBegin, hostnameSize);
-                        hostname[hostnameSize] = '\0';
-
-                        /*Codes_SRS_BLOB_02_018: [ Blob_UploadMultipleBlocksFromSasUri shall create a new HTTPAPI_EX_HANDLE by calling HTTPAPIEX_Create passing the hostname. ]*/
-                        httpApiExHandle = HTTPAPIEX_Create(hostname);
-                        if (httpApiExHandle == NULL)
-                        {
-                            /*Codes_SRS_BLOB_02_007: [ If HTTPAPIEX_Create fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR. ]*/
-                            LogError("unable to create a HTTPAPIEX_HANDLE");
-                            result = BLOB_ERROR;
-                        }
-                        else
-                        {
-                            if ((certificates != NULL)&& (HTTPAPIEX_SetOption(httpApiExHandle, "TrustedCerts", certificates) == HTTPAPIEX_ERROR))
-                            {
-                                LogError("failure in setting trusted certificates");
-                                result = BLOB_ERROR;
-                            }
-                            else if ((proxyOptions != NULL && proxyOptions->host_address != NULL) && HTTPAPIEX_SetOption(httpApiExHandle, OPTION_HTTP_PROXY, proxyOptions) == HTTPAPIEX_ERROR)
-                            {
-                                LogError("failure in setting proxy options");
-                                result = BLOB_ERROR;
-                            }
-                            else
-                            {
-                                /*Codes_SRS_BLOB_02_019: [ Blob_UploadMultipleBlocksFromSasUri shall compute the base relative path of the request from the SASURI parameter. ]*/
-                                const char* relativePath = hostnameEnd; /*this is where the relative path begins in the SasUri*/
-
-                                /*Codes_SRS_BLOB_02_028: [ Blob_UploadMultipleBlocksFromSasUri shall construct an XML string with the following content: ]*/
-                                STRING_HANDLE blockIDList = STRING_construct("<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<BlockList>"); /*the XML "build as we go"*/
-                                if (blockIDList == NULL)
-                                {
-                                    /*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR ]*/
-                                    LogError("failed to STRING_construct");
-                                    result = BLOB_HTTP_ERROR;
-                                }
-                                else
-                                {
-                                    /*Codes_SRS_BLOB_02_021: [ For every block returned by `getDataCallbackEx` the following operations shall happen: ]*/
-                                    unsigned int blockID = 0; /* incremented for each new block */
-                                    unsigned int isError = 0; /* set to 1 if a block upload fails or if getDataCallbackEx returns incorrect blocks to upload */
-                                    unsigned int uploadOneMoreBlock = 1; /* set to 1 while getDataCallbackEx returns correct blocks to upload */
-                                    unsigned char const * source; /* data set by getDataCallbackEx */
-                                    size_t size; /* source size set by getDataCallbackEx */
-                                    IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_RESULT getDataReturnValue;
-
-                                    do
-                                    {
-                                        getDataReturnValue = getDataCallbackEx(FILE_UPLOAD_OK, &source, &size, context);
-                                        if (getDataReturnValue == IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_ABORT)
-                                        {
-                                            /*Codes_SRS_BLOB_99_004: [ If `getDataCallbackEx` returns `IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_RESULT_ABORT`, then `Blob_UploadMultipleBlocksFromSasUri` shall exit the loop and return `BLOB_ABORTED`. ]*/
-                                            LogInfo("Upload to blob has been aborted by the user");
-                                            uploadOneMoreBlock = 0;
-                                            result = BLOB_ABORTED;
-                                        }
-                                        else if (source == NULL || size == 0)
-                                        {
-                                            /*Codes_SRS_BLOB_99_002: [ If the size of the block returned by `getDataCallbackEx` is 0 or if the data is NULL, then `Blob_UploadMultipleBlocksFromSasUri` shall exit the loop. ]*/
-                                            uploadOneMoreBlock = 0;
-                                            result = BLOB_OK;
-                                        }
-                                        else
-                                        {
-                                            if (size > BLOCK_SIZE)
-                                            {
-                                                /*Codes_SRS_BLOB_99_001: [ If the size of the block returned by `getDataCallbackEx` is bigger than 4MB, then `Blob_UploadMultipleBlocksFromSasUri` shall fail and return `BLOB_INVALID_ARG`. ]*/
-                                                LogError("tried to upload block of size %lu, max allowed size is %d", (unsigned long)size, BLOCK_SIZE);
-                                                result = BLOB_INVALID_ARG;
-                                                isError = 1;
-                                            }
-                                            else if (blockID >= MAX_BLOCK_COUNT)
-                                            {
-                                                /*Codes_SRS_BLOB_99_003: [ If `getDataCallbackEx` returns more than 50000 blocks, then `Blob_UploadMultipleBlocksFromSasUri` shall fail and return `BLOB_INVALID_ARG`. ]*/
-                                                LogError("unable to upload more than %lu blocks in one blob", (unsigned long)MAX_BLOCK_COUNT);
-                                                result = BLOB_INVALID_ARG;
-                                                isError = 1;
-                                            }
-                                            else
-                                            {
-                                                /*Codes_SRS_BLOB_02_023: [ Blob_UploadMultipleBlocksFromSasUri shall create a BUFFER_HANDLE from source and size parameters. ]*/
-                                                BUFFER_HANDLE requestContent = BUFFER_create(source, size);
-                                                if (requestContent == NULL)
-                                                {
-                                                    /*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR ]*/
-                                                    LogError("unable to BUFFER_create");
-                                                    result = BLOB_ERROR;
-                                                    isError = 1;
-                                                }
-                                                else
-                                                {
-                                                    result = Blob_UploadBlock(
-                                                            httpApiExHandle,
-                                                            relativePath,
-                                                            requestContent,
-                                                            blockID,
-                                                            blockIDList,
-                                                            httpStatus,
-                                                            httpResponse);
-
-                                                    BUFFER_delete(requestContent);
-                                                }
-
-                                                /*Codes_SRS_BLOB_02_026: [ Otherwise, if HTTP response code is >=300 then Blob_UploadMultipleBlocksFromSasUri shall succeed and return BLOB_OK. ]*/
-                                                if (result != BLOB_OK || *httpStatus >= 300)
-                                                {
-                                                    LogError("unable to Blob_UploadBlock. Returned value=%d, httpStatus=%u", result, (unsigned int)*httpStatus);
-                                                    isError = 1;
-                                                }
-                                            }
-                                            blockID++;
-                                        }
-                                    }
-                                    while(uploadOneMoreBlock && !isError);
-
-                                    if (isError || result != BLOB_OK)
-                                    {
-                                        /*do nothing, it will be reported "as is"*/
-                                    }
-                                    else
-                                    {
-                                        /*complete the XML*/
-                                        if (STRING_concat(blockIDList, "</BlockList>") != 0)
-                                        {
-                                            /*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR ]*/
-                                            LogError("failed to STRING_concat");
-                                            result = BLOB_ERROR;
-                                        }
-                                        else
-                                        {
-                                            /*Codes_SRS_BLOB_02_029: [Blob_UploadMultipleBlocksFromSasUri shall construct a new relativePath from following string : base relativePath + "&comp=blocklist"]*/
-                                            STRING_HANDLE newRelativePath = STRING_construct(relativePath);
-                                            if (newRelativePath == NULL)
-                                            {
-                                                /*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR ]*/
-                                                LogError("failed to STRING_construct");
-                                                result = BLOB_ERROR;
-                                            }
-                                            else
-                                            {
-                                                if (STRING_concat(newRelativePath, "&comp=blocklist") != 0)
-                                                {
-                                                    /*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR ]*/
-                                                    LogError("failed to STRING_concat");
-                                                    result = BLOB_ERROR;
-                                                }
-                                                else
-                                                {
-                                                    /*Codes_SRS_BLOB_02_030: [ Blob_UploadMultipleBlocksFromSasUri shall call HTTPAPIEX_ExecuteRequest with a PUT operation, passing the new relativePath, httpStatus and httpResponse and the XML string as content. ]*/
-                                                    const char* s = STRING_c_str(blockIDList);
-                                                    BUFFER_HANDLE blockIDListAsBuffer = BUFFER_create((const unsigned char*)s, strlen(s));
-                                                    if (blockIDListAsBuffer == NULL)
-                                                    {
-                                                        /*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR ]*/
-                                                        LogError("failed to BUFFER_create");
-                                                        result = BLOB_ERROR;
-                                                    }
-                                                    else
-                                                    {
-                                                        if (HTTPAPIEX_ExecuteRequest(
-                                                            httpApiExHandle,
-                                                            HTTPAPI_REQUEST_PUT,
-                                                            STRING_c_str(newRelativePath),
-                                                            NULL,
-                                                            blockIDListAsBuffer,
-                                                            httpStatus,
-                                                            NULL,
-                                                            httpResponse
-                                                        ) != HTTPAPIEX_OK)
-                                                        {
-                                                            /*Codes_SRS_BLOB_02_031: [ If HTTPAPIEX_ExecuteRequest fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_HTTP_ERROR. ]*/
-                                                            LogError("unable to HTTPAPIEX_ExecuteRequest");
-                                                            result = BLOB_HTTP_ERROR;
-                                                        }
-                                                        else
-                                                        {
-                                                            /*Codes_SRS_BLOB_02_032: [ Otherwise, Blob_UploadMultipleBlocksFromSasUri shall succeed and return BLOB_OK. ]*/
-                                                            result = BLOB_OK;
-                                                        }
-                                                        BUFFER_delete(blockIDListAsBuffer);
-                                                    }
-                                                }
-                                                STRING_delete(newRelativePath);
-                                            }
-                                        }
-                                    }
-                                    STRING_delete(blockIDList);
-                                }
-
-                            }
-                            HTTPAPIEX_Destroy(httpApiExHandle);
-                        }
-                        free(hostname);
-                    }
-                }
-            }
-        }
-    }
+                (void)memcpy(hostname, hostnameBegin, hostnameSize);
+                hostname[hostnameSize] = '\0';
+
+                /*Codes_SRS_BLOB_02_018: [ Blob_UploadMultipleBlocksFromSasUri shall create a new HTTPAPI_EX_HANDLE by calling HTTPAPIEX_Create passing the hostname. ]*/
+                httpApiExHandle = HTTPAPIEX_Create(hostname);
+                if (httpApiExHandle == NULL)
+                {
+                    /*Codes_SRS_BLOB_02_007: [ If HTTPAPIEX_Create fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR. ]*/
+                    LogError("unable to create a HTTPAPIEX_HANDLE");
+                    result = BLOB_ERROR;
+                }
+                else if ((certificates != NULL) && (HTTPAPIEX_SetOption(httpApiExHandle, "TrustedCerts", certificates) == HTTPAPIEX_ERROR))
+                {
+                    LogError("failure in setting trusted certificates");
+                    result = BLOB_ERROR;
+                }
+                else if ((proxyOptions != NULL && proxyOptions->host_address != NULL) && HTTPAPIEX_SetOption(httpApiExHandle, OPTION_HTTP_PROXY, proxyOptions) == HTTPAPIEX_ERROR)
+                {
+                    LogError("failure in setting proxy options");
+                    result = BLOB_ERROR;
+                }
+                /*Codes_SRS_BLOB_02_028: [ Blob_UploadMultipleBlocksFromSasUri shall construct an XML string with the following content: ]*/
+                else if ((blockIDList = STRING_construct(blockListXmlBegin)) == NULL)
+                {
+                    /*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR ]*/
+                    LogError("failed to STRING_construct");
+                    result = BLOB_HTTP_ERROR;
+                }
+                else if ((result = InvokeUserCallbackAndSendBlobs(httpApiExHandle, relativePath, blockIDList, getDataCallbackEx, context, httpStatus, httpResponse)) != BLOB_OK)
+                {
+                   LogError("Failed in invoking callback/sending blob step");
+                }
+                else if (*httpStatus < 300)
+                {
+                    // Per SRS_BLOB_02_026, it possible for us to have a result=BLOB_OK AND a non-success HTTP status code.
+                    // In order to maintain back-compat with existing code, we will return the BLOB_OK to the caller but NOT invoke this final step.
+                    result = SendBlockIdList(httpApiExHandle, relativePath, blockIDList, httpStatus, httpResponse);
+                }
+            }
+        }
+    }
+
+    HTTPAPIEX_Destroy(httpApiExHandle);
+    STRING_delete(blockIDList);
+    free(hostname);
+
     return result;
 }
