source: azure_iot_hub_f767zi/trunk/azure_iot_sdk/iothub_client/src/blob.c@ 457

Last change on this file since 457 was 457, checked in by coas-nagasima, 4 years ago

ファイルを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 24.6 KB
RevLine 
[457]1// Copyright (c) Microsoft. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
4#include <stdlib.h>
5#include <stdint.h>
6
7#include "azure_c_shared_utility/gballoc.h"
8#include "internal/blob.h"
9#include "internal/iothub_client_ll_uploadtoblob.h"
10
11#include "azure_c_shared_utility/httpapiex.h"
12#include "azure_c_shared_utility/xlogging.h"
13#include "azure_c_shared_utility/azure_base64.h"
14#include "azure_c_shared_utility/shared_util_options.h"
15
16BLOB_RESULT Blob_UploadBlock(
17 HTTPAPIEX_HANDLE httpApiExHandle,
18 const char* relativePath,
19 BUFFER_HANDLE requestContent,
20 unsigned int blockID,
21 STRING_HANDLE blockIDList,
22 unsigned int* httpStatus,
23 BUFFER_HANDLE httpResponse)
24{
25 BLOB_RESULT result;
26
27 if (requestContent == NULL ||
28 blockIDList == NULL ||
29 relativePath == NULL ||
30 httpApiExHandle == NULL ||
31 httpStatus == NULL ||
32 httpResponse == NULL)
33 {
34 LogError("invalid argument detected requestContent=%p blockIDList=%p relativePath=%p httpApiExHandle=%p httpStatus=%p httpResponse=%p", requestContent, blockIDList, relativePath, httpApiExHandle, httpStatus, httpResponse);
35 result = BLOB_ERROR;
36 }
37 else if (blockID > 49999) /*outside the expected range of 000000... 049999*/
38 {
39 LogError("block ID too large");
40 result = BLOB_ERROR;
41 }
42 else
43 {
44 char temp[7]; /*this will contain 000000... 049999*/
45 if (sprintf(temp, "%6u", (unsigned int)blockID) != 6) /*produces 000000... 049999*/
46 {
47 /*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 ]*/
48 LogError("failed to sprintf");
49 result = BLOB_ERROR;
50 }
51 else
52 {
53 STRING_HANDLE blockIdString = Azure_Base64_Encode_Bytes((const unsigned char*)temp, 6);
54 if (blockIdString == NULL)
55 {
56 /*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 ]*/
57 LogError("unable to Azure_Base64_Encode_Bytes");
58 result = BLOB_ERROR;
59 }
60 else
61 {
62 /*add the blockId base64 encoded to the XML*/
63 if (!(
64 (STRING_concat(blockIDList, "<Latest>") == 0) &&
65 (STRING_concat_with_STRING(blockIDList, blockIdString) == 0) &&
66 (STRING_concat(blockIDList, "</Latest>") == 0)
67 ))
68 {
69 /*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 ]*/
70 LogError("unable to STRING_concat");
71 result = BLOB_ERROR;
72 }
73 else
74 {
75 /*Codes_SRS_BLOB_02_022: [ Blob_UploadMultipleBlocksFromSasUri shall construct a new relativePath from following string: base relativePath + "&comp=block&blockid=BASE64 encoded string of blockId" ]*/
76 STRING_HANDLE newRelativePath = STRING_construct(relativePath);
77 if (newRelativePath == NULL)
78 {
79 /*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 ]*/
80 LogError("unable to STRING_construct");
81 result = BLOB_ERROR;
82 }
83 else
84 {
85 if (!(
86 (STRING_concat(newRelativePath, "&comp=block&blockid=") == 0) &&
87 (STRING_concat_with_STRING(newRelativePath, blockIdString) == 0)
88 ))
89 {
90 /*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 ]*/
91 LogError("unable to STRING concatenate");
92 result = BLOB_ERROR;
93 }
94 else
95 {
96 /*Codes_SRS_BLOB_02_024: [ Blob_UploadMultipleBlocksFromSasUri shall call HTTPAPIEX_ExecuteRequest with a PUT operation, passing httpStatus and httpResponse. ]*/
97 if (HTTPAPIEX_ExecuteRequest(
98 httpApiExHandle,
99 HTTPAPI_REQUEST_PUT,
100 STRING_c_str(newRelativePath),
101 NULL,
102 requestContent,
103 httpStatus,
104 NULL,
105 httpResponse) != HTTPAPIEX_OK
106 )
107 {
108 /*Codes_SRS_BLOB_02_025: [ If HTTPAPIEX_ExecuteRequest fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_HTTP_ERROR. ]*/
109 LogError("unable to HTTPAPIEX_ExecuteRequest");
110 result = BLOB_HTTP_ERROR;
111 }
112 else if (*httpStatus >= 300)
113 {
114 /*Codes_SRS_BLOB_02_026: [ Otherwise, if HTTP response code is >=300 then Blob_UploadMultipleBlocksFromSasUri shall succeed and return BLOB_OK. ]*/
115 LogError("HTTP status from storage does not indicate success (%d)", (int)*httpStatus);
116 result = BLOB_OK;
117 }
118 else
119 {
120 /*Codes_SRS_BLOB_02_027: [ Otherwise Blob_UploadMultipleBlocksFromSasUri shall continue execution. ]*/
121 result = BLOB_OK;
122 }
123 }
124 STRING_delete(newRelativePath);
125 }
126 }
127 STRING_delete(blockIdString);
128 }
129 }
130 }
131 return result;
132}
133
134BLOB_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)
135{
136 BLOB_RESULT result;
137 /*Codes_SRS_BLOB_02_001: [ If SASURI is NULL then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_INVALID_ARG. ]*/
138 if (SASURI == NULL)
139 {
140 LogError("parameter SASURI is NULL");
141 result = BLOB_INVALID_ARG;
142 }
143 else
144 {
145 /*Codes_SRS_BLOB_02_002: [ If getDataCallbackEx is NULL then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_INVALID_ARG. ]*/
146 if (getDataCallbackEx == NULL)
147 {
148 LogError("IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_CALLBACK_EX getDataCallbackEx is NULL");
149 result = BLOB_INVALID_ARG;
150 }
151 /*the below define avoid a "condition always false" on some compilers*/
152 else
153 {
154 /*Codes_SRS_BLOB_02_017: [ Blob_UploadMultipleBlocksFromSasUri shall copy from SASURI the hostname to a new const char* ]*/
155 /*to find the hostname, the following logic is applied:*/
156 /*the hostname starts at the first character after "://"*/
157 /*the hostname ends at the first character before the next "/" after "://"*/
158 const char* hostnameBegin = strstr(SASURI, "://");
159 if (hostnameBegin == NULL)
160 {
161 /*Codes_SRS_BLOB_02_005: [ If the hostname cannot be determined, then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_INVALID_ARG. ]*/
162 LogError("hostname cannot be determined");
163 result = BLOB_INVALID_ARG;
164 }
165 else
166 {
167 hostnameBegin += 3; /*have to skip 3 characters which are "://"*/
168 const char* hostnameEnd = strchr(hostnameBegin, '/');
169 if (hostnameEnd == NULL)
170 {
171 /*Codes_SRS_BLOB_02_005: [ If the hostname cannot be determined, then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_INVALID_ARG. ]*/
172 LogError("hostname cannot be determined");
173 result = BLOB_INVALID_ARG;
174 }
175 else
176 {
177 size_t hostnameSize = hostnameEnd - hostnameBegin;
178 char* hostname = (char*)malloc(hostnameSize + 1); /*+1 because of '\0' at the end*/
179 if (hostname == NULL)
180 {
181 /*Codes_SRS_BLOB_02_016: [ If the hostname copy cannot be made then then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR ]*/
182 LogError("oom - out of memory");
183 result = BLOB_ERROR;
184 }
185 else
186 {
187 HTTPAPIEX_HANDLE httpApiExHandle;
188 (void)memcpy(hostname, hostnameBegin, hostnameSize);
189 hostname[hostnameSize] = '\0';
190
191 /*Codes_SRS_BLOB_02_018: [ Blob_UploadMultipleBlocksFromSasUri shall create a new HTTPAPI_EX_HANDLE by calling HTTPAPIEX_Create passing the hostname. ]*/
192 httpApiExHandle = HTTPAPIEX_Create(hostname);
193 if (httpApiExHandle == NULL)
194 {
195 /*Codes_SRS_BLOB_02_007: [ If HTTPAPIEX_Create fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_ERROR. ]*/
196 LogError("unable to create a HTTPAPIEX_HANDLE");
197 result = BLOB_ERROR;
198 }
199 else
200 {
201 if ((certificates != NULL)&& (HTTPAPIEX_SetOption(httpApiExHandle, "TrustedCerts", certificates) == HTTPAPIEX_ERROR))
202 {
203 LogError("failure in setting trusted certificates");
204 result = BLOB_ERROR;
205 }
206 else if ((proxyOptions != NULL && proxyOptions->host_address != NULL) && HTTPAPIEX_SetOption(httpApiExHandle, OPTION_HTTP_PROXY, proxyOptions) == HTTPAPIEX_ERROR)
207 {
208 LogError("failure in setting proxy options");
209 result = BLOB_ERROR;
210 }
211 else
212 {
213 /*Codes_SRS_BLOB_02_019: [ Blob_UploadMultipleBlocksFromSasUri shall compute the base relative path of the request from the SASURI parameter. ]*/
214 const char* relativePath = hostnameEnd; /*this is where the relative path begins in the SasUri*/
215
216 /*Codes_SRS_BLOB_02_028: [ Blob_UploadMultipleBlocksFromSasUri shall construct an XML string with the following content: ]*/
217 STRING_HANDLE blockIDList = STRING_construct("<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<BlockList>"); /*the XML "build as we go"*/
218 if (blockIDList == NULL)
219 {
220 /*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 ]*/
221 LogError("failed to STRING_construct");
222 result = BLOB_HTTP_ERROR;
223 }
224 else
225 {
226 /*Codes_SRS_BLOB_02_021: [ For every block returned by `getDataCallbackEx` the following operations shall happen: ]*/
227 unsigned int blockID = 0; /* incremented for each new block */
228 unsigned int isError = 0; /* set to 1 if a block upload fails or if getDataCallbackEx returns incorrect blocks to upload */
229 unsigned int uploadOneMoreBlock = 1; /* set to 1 while getDataCallbackEx returns correct blocks to upload */
230 unsigned char const * source; /* data set by getDataCallbackEx */
231 size_t size; /* source size set by getDataCallbackEx */
232 IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_RESULT getDataReturnValue;
233
234 do
235 {
236 getDataReturnValue = getDataCallbackEx(FILE_UPLOAD_OK, &source, &size, context);
237 if (getDataReturnValue == IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_ABORT)
238 {
239 /*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`. ]*/
240 LogInfo("Upload to blob has been aborted by the user");
241 uploadOneMoreBlock = 0;
242 result = BLOB_ABORTED;
243 }
244 else if (source == NULL || size == 0)
245 {
246 /*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. ]*/
247 uploadOneMoreBlock = 0;
248 result = BLOB_OK;
249 }
250 else
251 {
252 if (size > BLOCK_SIZE)
253 {
254 /*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`. ]*/
255 LogError("tried to upload block of size %lu, max allowed size is %d", (unsigned long)size, BLOCK_SIZE);
256 result = BLOB_INVALID_ARG;
257 isError = 1;
258 }
259 else if (blockID >= MAX_BLOCK_COUNT)
260 {
261 /*Codes_SRS_BLOB_99_003: [ If `getDataCallbackEx` returns more than 50000 blocks, then `Blob_UploadMultipleBlocksFromSasUri` shall fail and return `BLOB_INVALID_ARG`. ]*/
262 LogError("unable to upload more than %lu blocks in one blob", (unsigned long)MAX_BLOCK_COUNT);
263 result = BLOB_INVALID_ARG;
264 isError = 1;
265 }
266 else
267 {
268 /*Codes_SRS_BLOB_02_023: [ Blob_UploadMultipleBlocksFromSasUri shall create a BUFFER_HANDLE from source and size parameters. ]*/
269 BUFFER_HANDLE requestContent = BUFFER_create(source, size);
270 if (requestContent == NULL)
271 {
272 /*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 ]*/
273 LogError("unable to BUFFER_create");
274 result = BLOB_ERROR;
275 isError = 1;
276 }
277 else
278 {
279 result = Blob_UploadBlock(
280 httpApiExHandle,
281 relativePath,
282 requestContent,
283 blockID,
284 blockIDList,
285 httpStatus,
286 httpResponse);
287
288 BUFFER_delete(requestContent);
289 }
290
291 /*Codes_SRS_BLOB_02_026: [ Otherwise, if HTTP response code is >=300 then Blob_UploadMultipleBlocksFromSasUri shall succeed and return BLOB_OK. ]*/
292 if (result != BLOB_OK || *httpStatus >= 300)
293 {
294 LogError("unable to Blob_UploadBlock. Returned value=%d, httpStatus=%u", result, (unsigned int)*httpStatus);
295 isError = 1;
296 }
297 }
298 blockID++;
299 }
300 }
301 while(uploadOneMoreBlock && !isError);
302
303 if (isError || result != BLOB_OK)
304 {
305 /*do nothing, it will be reported "as is"*/
306 }
307 else
308 {
309 /*complete the XML*/
310 if (STRING_concat(blockIDList, "</BlockList>") != 0)
311 {
312 /*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 ]*/
313 LogError("failed to STRING_concat");
314 result = BLOB_ERROR;
315 }
316 else
317 {
318 /*Codes_SRS_BLOB_02_029: [Blob_UploadMultipleBlocksFromSasUri shall construct a new relativePath from following string : base relativePath + "&comp=blocklist"]*/
319 STRING_HANDLE newRelativePath = STRING_construct(relativePath);
320 if (newRelativePath == NULL)
321 {
322 /*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 ]*/
323 LogError("failed to STRING_construct");
324 result = BLOB_ERROR;
325 }
326 else
327 {
328 if (STRING_concat(newRelativePath, "&comp=blocklist") != 0)
329 {
330 /*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 ]*/
331 LogError("failed to STRING_concat");
332 result = BLOB_ERROR;
333 }
334 else
335 {
336 /*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. ]*/
337 const char* s = STRING_c_str(blockIDList);
338 BUFFER_HANDLE blockIDListAsBuffer = BUFFER_create((const unsigned char*)s, strlen(s));
339 if (blockIDListAsBuffer == NULL)
340 {
341 /*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 ]*/
342 LogError("failed to BUFFER_create");
343 result = BLOB_ERROR;
344 }
345 else
346 {
347 if (HTTPAPIEX_ExecuteRequest(
348 httpApiExHandle,
349 HTTPAPI_REQUEST_PUT,
350 STRING_c_str(newRelativePath),
351 NULL,
352 blockIDListAsBuffer,
353 httpStatus,
354 NULL,
355 httpResponse
356 ) != HTTPAPIEX_OK)
357 {
358 /*Codes_SRS_BLOB_02_031: [ If HTTPAPIEX_ExecuteRequest fails then Blob_UploadMultipleBlocksFromSasUri shall fail and return BLOB_HTTP_ERROR. ]*/
359 LogError("unable to HTTPAPIEX_ExecuteRequest");
360 result = BLOB_HTTP_ERROR;
361 }
362 else
363 {
364 /*Codes_SRS_BLOB_02_032: [ Otherwise, Blob_UploadMultipleBlocksFromSasUri shall succeed and return BLOB_OK. ]*/
365 result = BLOB_OK;
366 }
367 BUFFER_delete(blockIDListAsBuffer);
368 }
369 }
370 STRING_delete(newRelativePath);
371 }
372 }
373 }
374 STRING_delete(blockIDList);
375 }
376
377 }
378 HTTPAPIEX_Destroy(httpApiExHandle);
379 }
380 free(hostname);
381 }
382 }
383 }
384 }
385 }
386 return result;
387}
Note: See TracBrowser for help on using the repository browser.