corrected version (with typedef struct IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE_DATA* IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE;) included in the sources

Dependents:   STM32F746_iothub_client_sample_mqtt

Fork of iothub_client by Azure IoT

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers blob.c Source File

blob.c

00001 // Copyright (c) Microsoft. All rights reserved.
00002 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
00003 
00004 #include <stdlib.h>
00005 #ifdef _CRTDBG_MAP_ALLOC
00006 #include <crtdbg.h>
00007 #endif
00008 #include "azure_c_shared_utility/gballoc.h"
00009 
00010 #include "blob.h"
00011 
00012 #include "azure_c_shared_utility/httpapiex.h"
00013 #include "azure_c_shared_utility/iot_logging.h"
00014 #include "azure_c_shared_utility/base64.h"
00015 
00016 /*a block has 4MB*/
00017 #define BLOCK_SIZE (4*1024*1024)
00018 
00019 BLOB_RESULT Blob_UploadFromSasUri(const char* SASURI, const unsigned char* source, size_t size, unsigned int* httpStatus, BUFFER_HANDLE httpResponse)
00020 {
00021     BLOB_RESULT result;
00022     /*Codes_SRS_BLOB_02_001: [ If SASURI is NULL then Blob_UploadFromSasUri shall fail and return BLOB_INVALID_ARG. ]*/
00023     if (SASURI == NULL)
00024     {
00025         LogError("parameter SASURI is NULL");
00026         result = BLOB_INVALID_ARG;
00027     }
00028     else
00029     {
00030         /*Codes_SRS_BLOB_02_002: [ If source is NULL and size is not zero then Blob_UploadFromSasUri shall fail and return BLOB_INVALID_ARG. ]*/
00031         if (
00032             (size > 0) &&
00033             (source == NULL)
00034             )
00035         {
00036             LogError("combination of source = %p and size = %zu is invalid", source, size);
00037             result = BLOB_INVALID_ARG;
00038         }
00039         /*Codes_SRS_BLOB_02_034: [ If size is bigger than 50000*4*1024*1024 then Blob_UploadFromSasUri shall fail and return BLOB_INVALID_ARG. ]*/
00040         else if (size > 50000ULL * 4 * 1024 * 1024) /*https://msdn.microsoft.com/en-us/library/azure/dd179467.aspx says "Each block can be a different size, up to a maximum of 4 MB, and a block blob can include a maximum of 50,000 blocks."*/
00041         {
00042             LogError("size too big (%zu)", size);
00043             result = BLOB_INVALID_ARG;
00044         }
00045         else
00046         {
00047             /*Codes_SRS_BLOB_02_017: [ Blob_UploadFromSasUri shall copy from SASURI the hostname to a new const char* ]*/
00048             /*Codes_SRS_BLOB_02_004: [ Blob_UploadFromSasUri shall copy from SASURI the hostname to a new const char*. ]*/
00049             /*to find the hostname, the following logic is applied:*/
00050             /*the hostname starts at the first character after "://"*/
00051             /*the hostname ends at the first character before the next "/" after "://"*/
00052             const char* hostnameBegin = strstr(SASURI, "://");
00053             if (hostnameBegin == NULL)
00054             {
00055                 /*Codes_SRS_BLOB_02_005: [ If the hostname cannot be determined, then Blob_UploadFromSasUri shall fail and return BLOB_INVALID_ARG. ]*/
00056                 LogError("hostname cannot be determined");
00057                 result = BLOB_INVALID_ARG;
00058             }
00059             else
00060             {
00061                 hostnameBegin += 3; /*have to skip 3 characters which are "://"*/
00062                 const char* hostnameEnd = strchr(hostnameBegin, '/');
00063                 if (hostnameEnd == NULL)
00064                 {
00065                     /*Codes_SRS_BLOB_02_005: [ If the hostname cannot be determined, then Blob_UploadFromSasUri shall fail and return BLOB_INVALID_ARG. ]*/
00066                     LogError("hostname cannot be determined");
00067                     result = BLOB_INVALID_ARG;
00068                 }
00069                 else
00070                 {
00071                     size_t hostnameSize = hostnameEnd - hostnameBegin;
00072                     char* hostname = (char*)malloc(hostnameSize + 1); /*+1 because of '\0' at the end*/
00073                     if (hostname == NULL)
00074                     {
00075                         /*Codes_SRS_BLOB_02_016: [ If the hostname copy cannot be made then then Blob_UploadFromSasUri shall fail and return BLOB_ERROR ]*/
00076                         LogError("oom - out of memory");
00077                         result = BLOB_ERROR;
00078                     }
00079                     else
00080                     {
00081                         HTTPAPIEX_HANDLE httpApiExHandle;
00082                         memcpy(hostname, hostnameBegin, hostnameSize);
00083                         hostname[hostnameSize] = '\0';
00084 
00085                         /*Codes_SRS_BLOB_02_006: [ Blob_UploadFromSasUri shall create a new HTTPAPI_EX_HANDLE by calling HTTPAPIEX_Create passing the hostname. ]*/
00086                         /*Codes_SRS_BLOB_02_018: [ Blob_UploadFromSasUri shall create a new HTTPAPI_EX_HANDLE by calling HTTPAPIEX_Create passing the hostname. ]*/
00087                         httpApiExHandle = HTTPAPIEX_Create(hostname);
00088                         if (httpApiExHandle == NULL)
00089                         {
00090                             /*Codes_SRS_BLOB_02_007: [ If HTTPAPIEX_Create fails then Blob_UploadFromSasUri shall fail and return BLOB_ERROR. ]*/
00091                             LogError("unable to create a HTTPAPIEX_HANDLE");
00092                             result = BLOB_ERROR;
00093                         }
00094                         else
00095                         {
00096                             /*Codes_SRS_BLOB_02_008: [ Blob_UploadFromSasUri shall compute the relative path of the request from the SASURI parameter. ]*/
00097                             /*Codes_SRS_BLOB_02_019: [ Blob_UploadFromSasUri shall compute the base relative path of the request from the SASURI parameter. ]*/
00098                             const char* relativePath = hostnameEnd; /*this is where the relative path begins in the SasUri*/
00099 
00100                             if (size < 64 * 1024 * 1024) /*code path for sizes <64MB*/
00101                             {
00102                                 /*Codes_SRS_BLOB_02_010: [ Blob_UploadFromSasUri shall create a BUFFER_HANDLE from source and size parameters. ]*/
00103                                 BUFFER_HANDLE requestBuffer = BUFFER_create(source, size);
00104                                 if (requestBuffer == NULL)
00105                                 {
00106                                     /*Codes_SRS_BLOB_02_011: [ If any of the previous steps related to building the HTTPAPI_EX_ExecuteRequest parameters fails, then Blob_UploadFromSasUri shall fail and return BLOB_ERROR. ]*/
00107                                     LogError("unable to BUFFER_create");
00108                                     result = BLOB_ERROR;
00109                                 }
00110                                 else
00111                                 {
00112                                     /*Codes_SRS_BLOB_02_009: [ Blob_UploadFromSasUri shall create an HTTP_HEADERS_HANDLE for the request HTTP headers carrying the following headers: ]*/
00113                                     HTTP_HEADERS_HANDLE requestHttpHeaders = HTTPHeaders_Alloc();
00114                                     if (requestHttpHeaders == NULL)
00115                                     {
00116                                         /*Codes_SRS_BLOB_02_011: [ If any of the previous steps related to building the HTTPAPI_EX_ExecuteRequest parameters fails, then Blob_UploadFromSasUri shall fail and return BLOB_ERROR. ]*/
00117                                         LogError("unable to HTTPHeaders_Alloc");
00118                                         result = BLOB_ERROR;
00119                                     }
00120                                     else
00121                                     {
00122                                         if (HTTPHeaders_AddHeaderNameValuePair(requestHttpHeaders, "x-ms-blob-type", "BlockBlob") != HTTP_HEADERS_OK)
00123                                         {
00124                                             /*Codes_SRS_BLOB_02_011: [ If any of the previous steps related to building the HTTPAPI_EX_ExecuteRequest parameters fails, then Blob_UploadFromSasUri shall fail and return BLOB_ERROR. ]*/
00125                                             LogError("unable to HTTPHeaders_AddHeaderNameValuePair");
00126                                             result = BLOB_ERROR;
00127                                         }
00128                                         else
00129                                         {
00130                                             /*Codes_SRS_BLOB_02_012: [ Blob_UploadFromSasUri shall call HTTPAPIEX_ExecuteRequest passing the parameters previously build, httpStatus and httpResponse ]*/
00131                                             if (HTTPAPIEX_ExecuteRequest(httpApiExHandle, HTTPAPI_REQUEST_PUT, relativePath, requestHttpHeaders, requestBuffer, httpStatus, NULL, httpResponse) != HTTPAPIEX_OK)
00132                                             {
00133                                                 /*Codes_SRS_BLOB_02_013: [ If HTTPAPIEX_ExecuteRequest fails, then Blob_UploadFromSasUri shall fail and return BLOB_HTTP_ERROR. ]*/
00134                                                 LogError("failed to HTTPAPIEX_ExecuteRequest");
00135                                                 result = BLOB_HTTP_ERROR;
00136                                             }
00137                                             else
00138                                             {
00139                                                 /*Codes_SRS_BLOB_02_015: [ Otherwise, HTTPAPIEX_ExecuteRequest shall succeed and return BLOB_OK. ]*/
00140                                                 result = BLOB_OK;
00141                                             }
00142                                         }
00143                                         HTTPHeaders_Free(requestHttpHeaders);
00144                                     }
00145                                     BUFFER_delete(requestBuffer);
00146                                 }
00147                             }
00148                             else /*code path for size >= 64MB*/
00149                             {
00150                                 size_t toUpload = size;
00151                                 /*Codes_SRS_BLOB_02_028: [ Blob_UploadFromSasUri shall construct an XML string with the following content: ]*/
00152                                 STRING_HANDLE xml = STRING_construct("<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<BlockList>"); /*the XML "build as we go"*/
00153                                 if (xml == NULL)
00154                                 {
00155                                     /*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadFromSasUri shall fail and return BLOB_ERROR ]*/
00156                                     LogError("failed to STRING_construct");
00157                                     result = BLOB_HTTP_ERROR;
00158                                 }
00159                                 else
00160                                 {
00161                                     /*Codes_SRS_BLOB_02_021: [ For every block of 4MB the following operations shall happen: ]*/
00162                                     unsigned int blockID = 0;
00163                                     int isError = 0; /*used to cleanly exit the loop*/
00164                                     do
00165                                     {
00166                                         /*setting this block size*/
00167                                         size_t thisBlockSize = (toUpload > BLOCK_SIZE) ? BLOCK_SIZE : toUpload;
00168                                         /*Codes_SRS_BLOB_02_020: [ Blob_UploadFromSasUri shall construct a BASE64 encoded string from the block ID (000000... 0499999) ]*/
00169                                         char temp[7]; /*this will contain 000000... 049999*/
00170                                         if (sprintf(temp, "%6u", (unsigned int)blockID) != 6) /*produces 000000... 049999*/
00171                                         {
00172                                             /*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadFromSasUri shall fail and return BLOB_ERROR ]*/
00173                                             LogError("failed to sprintf");
00174                                             result = BLOB_ERROR;
00175                                             isError = 1;
00176                                         }
00177                                         else
00178                                         {
00179                                             STRING_HANDLE blockIdString = Base64_Encode_Bytes(temp, 6);
00180                                             if (blockIdString == NULL)
00181                                             {
00182                                                 /*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadFromSasUri shall fail and return BLOB_ERROR ]*/
00183                                                 LogError("unable to Base64_Encode_Bytes");
00184                                                 result = BLOB_ERROR;
00185                                                 isError = 1;
00186                                             }
00187                                             else
00188                                             {
00189                                                 /*add the blockId base64 encoded to the XML*/
00190                                                 if (!(
00191                                                     (STRING_concat(xml, "<Latest>")==0) &&
00192                                                     (STRING_concat_with_STRING(xml, blockIdString)==0) &&
00193                                                     (STRING_concat(xml, "</Latest>") == 0)
00194                                                     ))
00195                                                 {
00196                                                     /*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadFromSasUri shall fail and return BLOB_ERROR ]*/
00197                                                     LogError("unable to STRING_concat");
00198                                                     result = BLOB_ERROR;
00199                                                     isError = 1;
00200                                                 }
00201                                                 else
00202                                                 {
00203                                                     /*Codes_SRS_BLOB_02_022: [ Blob_UploadFromSasUri shall construct a new relativePath from following string: base relativePath + "&comp=block&blockid=BASE64 encoded string of blockId" ]*/
00204                                                     STRING_HANDLE newRelativePath = STRING_construct(relativePath);
00205                                                     if (newRelativePath == NULL)
00206                                                     {
00207                                                         /*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadFromSasUri shall fail and return BLOB_ERROR ]*/
00208                                                         LogError("unable to STRING_construct");
00209                                                         result = BLOB_ERROR;
00210                                                         isError = 1;
00211                                                     }
00212                                                     else
00213                                                     {
00214                                                         if (!(
00215                                                             (STRING_concat(newRelativePath, "&comp=block&blockid=") == 0) &&
00216                                                             (STRING_concat_with_STRING(newRelativePath, blockIdString) == 0)
00217                                                             ))
00218                                                         {
00219                                                             /*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadFromSasUri shall fail and return BLOB_ERROR ]*/
00220                                                             LogError("unable to STRING concatenate");
00221                                                             result = BLOB_ERROR;
00222                                                             isError = 1;
00223                                                         }
00224                                                         else
00225                                                         {
00226                                                             /*Codes_SRS_BLOB_02_023: [ Blob_UploadFromSasUri shall create a BUFFER_HANDLE from source and size parameters. ]*/
00227                                                             BUFFER_HANDLE requestContent = BUFFER_create(source + (size - toUpload), thisBlockSize);
00228                                                             if (requestContent == NULL)
00229                                                             {
00230                                                                 /*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadFromSasUri shall fail and return BLOB_ERROR ]*/
00231                                                                 LogError("unable to BUFFER_create");
00232                                                                 result = BLOB_ERROR;
00233                                                                 isError = 1;
00234                                                             }
00235                                                             else
00236                                                             {
00237                                                                 /*Codes_SRS_BLOB_02_024: [ Blob_UploadFromSasUri shall call HTTPAPIEX_ExecuteRequest with a PUT operation, passing httpStatus and httpResponse. ]*/
00238                                                                 if (HTTPAPIEX_ExecuteRequest(
00239                                                                     httpApiExHandle,
00240                                                                     HTTPAPI_REQUEST_PUT,
00241                                                                     STRING_c_str(newRelativePath),
00242                                                                     NULL,
00243                                                                     requestContent,
00244                                                                     httpStatus,
00245                                                                     NULL,
00246                                                                     httpResponse) != HTTPAPIEX_OK
00247                                                                     )
00248                                                                 {
00249                                                                     /*Codes_SRS_BLOB_02_025: [ If HTTPAPIEX_ExecuteRequest fails then Blob_UploadFromSasUri shall fail and return BLOB_HTTP_ERROR. ]*/
00250                                                                     LogError("unable to HTTPAPIEX_ExecuteRequest");
00251                                                                     result = BLOB_HTTP_ERROR;
00252                                                                     isError = 1;
00253                                                                 }
00254                                                                 else if (*httpStatus >= 300)
00255                                                                 {
00256                                                                     /*Codes_SRS_BLOB_02_026: [ Otherwise, if HTTP response code is >=300 then Blob_UploadFromSasUri shall succeed and return BLOB_OK. ]*/
00257                                                                     LogError("HTTP status from storage does not indicate success (%d)", (int)*httpStatus);
00258                                                                     result = BLOB_OK;
00259                                                                     isError = 1;
00260                                                                 }
00261                                                                 else
00262                                                                 {
00263                                                                     /*Codes_SRS_BLOB_02_027: [ Otherwise Blob_UploadFromSasUri shall continue execution. ]*/
00264                                                                 }
00265                                                                 BUFFER_delete(requestContent);
00266                                                             }
00267                                                         }
00268                                                         STRING_delete(newRelativePath);
00269                                                     }
00270                                                 }
00271                                                 STRING_delete(blockIdString);
00272                                             }
00273                                         }
00274 
00275                                         blockID++;
00276                                         toUpload -= thisBlockSize;
00277                                     } while ((toUpload > 0) && !isError);
00278 
00279                                     if (isError)
00280                                     {
00281                                         /*do nothing, it will be reported "as is"*/
00282                                     }
00283                                     else
00284                                     {
00285                                         /*complete the XML*/
00286                                         if (STRING_concat(xml, "</BlockList>") != 0)
00287                                         {
00288                                             /*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadFromSasUri shall fail and return BLOB_ERROR ]*/
00289                                             LogError("failed to STRING_concat");
00290                                             result = BLOB_ERROR;
00291                                         }
00292                                         else
00293                                         {
00294                                             /*Codes_SRS_BLOB_02_029: [Blob_UploadFromSasUri shall construct a new relativePath from following string : base relativePath + "&comp=blocklist"]*/
00295                                             STRING_HANDLE newRelativePath = STRING_construct(relativePath);
00296                                             if (newRelativePath == NULL)
00297                                             {
00298                                                 /*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadFromSasUri shall fail and return BLOB_ERROR ]*/
00299                                                 LogError("failed to STRING_construct");
00300                                                 result = BLOB_ERROR;
00301                                             }
00302                                             else
00303                                             {
00304                                                 if (STRING_concat(newRelativePath, "&comp=blocklist") != 0)
00305                                                 {
00306                                                     /*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadFromSasUri shall fail and return BLOB_ERROR ]*/
00307                                                     LogError("failed to STRING_concat");
00308                                                     result = BLOB_ERROR;
00309                                                 }
00310                                                 else
00311                                                 {
00312                                                     /*Codes_SRS_BLOB_02_030: [ Blob_UploadFromSasUri shall call HTTPAPIEX_ExecuteRequest with a PUT operation, passing the new relativePath, httpStatus and httpResponse and the XML string as content. ]*/
00313                                                     const unsigned char* s = (const unsigned char*)STRING_c_str(xml);
00314                                                     BUFFER_HANDLE xmlAsBuffer = BUFFER_create(s, strlen(s));
00315                                                     if (xmlAsBuffer == NULL)
00316                                                     {
00317                                                         /*Codes_SRS_BLOB_02_033: [ If any previous operation that doesn't have an explicit failure description fails then Blob_UploadFromSasUri shall fail and return BLOB_ERROR ]*/
00318                                                         LogError("failed to BUFFER_create");
00319                                                         result = BLOB_ERROR;
00320                                                     }
00321                                                     else
00322                                                     {
00323                                                         if (HTTPAPIEX_ExecuteRequest(
00324                                                             httpApiExHandle,
00325                                                             HTTPAPI_REQUEST_PUT,
00326                                                             STRING_c_str(newRelativePath),
00327                                                             NULL,
00328                                                             xmlAsBuffer,
00329                                                             httpStatus,
00330                                                             NULL,
00331                                                             httpResponse
00332                                                         ) != HTTPAPIEX_OK)
00333                                                         {
00334                                                             /*Codes_SRS_BLOB_02_031: [ If HTTPAPIEX_ExecuteRequest fails then Blob_UploadFromSasUri shall fail and return BLOB_HTTP_ERROR. ]*/
00335                                                             LogError("unable to HTTPAPIEX_ExecuteRequest");
00336                                                             result = BLOB_HTTP_ERROR;
00337                                                         }
00338                                                         else
00339                                                         {
00340                                                             /*Codes_SRS_BLOB_02_032: [ Otherwise, Blob_UploadFromSasUri shall succeed and return BLOB_OK. ]*/
00341                                                             result = BLOB_OK;
00342                                                         }
00343                                                         BUFFER_delete(xmlAsBuffer);
00344                                                     }
00345                                                 }
00346                                                 STRING_delete(newRelativePath);
00347                                             }
00348                                         }
00349                                     }
00350                                     STRING_delete(xml);
00351                                 }
00352                             }
00353                             HTTPAPIEX_Destroy(httpApiExHandle);
00354                         }
00355                         free(hostname);
00356                     }
00357                 }
00358             }
00359         }
00360     }
00361     return result;
00362 }