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
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 }
Generated on Tue Jul 12 2022 19:44:54 by 1.7.2