source: azure_iot_hub/trunk/azure_iothub/iothub_client/src/blob.c@ 389

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

ビルドが通るよう更新

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