source: azure_iot_hub_f767zi/trunk/azure_iot_sdk/iothub_client/src/iothub_client_ll_uploadtoblob.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: 62.9 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#ifndef DONT_USE_UPLOADTOBLOB
5
6#include <stdlib.h>
7#include <string.h>
8#include "azure_c_shared_utility/optimize_size.h"
9#include "azure_c_shared_utility/gballoc.h"
10#include "azure_c_shared_utility/string_tokenizer.h"
11#include "azure_c_shared_utility/doublylinkedlist.h"
12#include "azure_c_shared_utility/xlogging.h"
13#include "azure_c_shared_utility/tickcounter.h"
14#include "azure_c_shared_utility/httpapiexsas.h"
15#include "azure_c_shared_utility/shared_util_options.h"
16#include "azure_c_shared_utility/urlencode.h"
17
18#include "iothub_client_core_ll.h"
19#include "iothub_client_options.h"
20#include "internal/iothub_client_private.h"
21#include "iothub_client_version.h"
22#include "iothub_transport_ll.h"
23#include "parson.h"
24#include "internal/iothub_client_ll_uploadtoblob.h"
25#include "internal/iothub_client_authorization.h"
26#include "internal/blob.h"
27
28#define API_VERSION "?api-version=2016-11-14"
29
30#ifdef WINCE
31#include <stdarg.h>
32// Returns number of characters copied.
33int snprintf(char * s, size_t n, const char * format, ...)
34{
35 int result;
36 va_list args;
37 va_start(args, format);
38 result = vsnprintf(s, n, format, args);
39 va_end(args);
40 return result;
41}
42#endif
43
44/*Codes_SRS_IOTHUBCLIENT_LL_02_085: [ IoTHubClient_LL_UploadToBlob shall use the same authorization as step 1. to prepare and perform a HTTP request with the following parameters: ]*/
45static const char* const RESPONSE_BODY_FORMAT = "{\"correlationId\":\"%s\", \"isSuccess\":%s, \"statusCode\":%d, \"statusDescription\":\"%s\"}";
46static const char* const RESPONSE_BODY_ABORTED_MESSAGE = "file upload aborted";
47static const char* const RESPONSE_BODY_FAILED_MESSAGE = "client not able to connect with the server";
48static const char* const RESPONSE_BODY_ERROR_RETURN_CODE = "-1";
49static const char* const RESPONSE_BODY_ERROR_BOOLEAN_STRING = "false";
50
51#define INDEFINITE_TIME ((time_t)-1)
52
53static const char* const EMPTY_STRING = "";
54static const char* const HEADER_AUTHORIZATION = "Authorization";
55static const char* const HEADER_APP_JSON = "application/json";
56
57typedef struct UPLOADTOBLOB_X509_CREDENTIALS_TAG
58{
59 char* x509certificate;
60 char* x509privatekey;
61} UPLOADTOBLOB_X509_CREDENTIALS;
62
63typedef enum UPOADTOBLOB_CURL_VERBOSITY_TAG
64{
65 UPOADTOBLOB_CURL_VERBOSITY_UNSET,
66 UPOADTOBLOB_CURL_VERBOSITY_ON,
67 UPOADTOBLOB_CURL_VERBOSITY_OFF
68} UPOADTOBLOB_CURL_VERBOSITY;
69
70typedef struct IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE_DATA_TAG
71{
72 const char* deviceId;
73 char* hostname;
74 IOTHUB_AUTHORIZATION_HANDLE authorization_module;
75 IOTHUB_CREDENTIAL_TYPE cred_type;
76 union
77 {
78 UPLOADTOBLOB_X509_CREDENTIALS x509_credentials;
79 char* supplied_sas_token;
80 } credentials;
81
82 char* certificates;
83 HTTP_PROXY_OPTIONS http_proxy_options;
84 UPOADTOBLOB_CURL_VERBOSITY curl_verbosity_level;
85 size_t blob_upload_timeout_secs;
86}IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE_DATA;
87
88typedef struct BLOB_UPLOAD_CONTEXT_TAG
89{
90 const unsigned char* blobSource; /* source to upload */
91 size_t blobSourceSize; /* size of the source */
92 size_t remainingSizeToUpload; /* size not yet uploaded */
93} BLOB_UPLOAD_CONTEXT;
94
95static int send_http_sas_request(IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE_DATA* upload_client, const char* uri_resource, HTTPAPIEX_HANDLE http_api_handle, const char* relative_path, HTTP_HEADERS_HANDLE request_header, BUFFER_HANDLE blobBuffer, BUFFER_HANDLE response_buff)
96{
97 int result;
98 unsigned int statusCode;
99
100 /*Codes_SRS_IOTHUBCLIENT_LL_02_089: [ If creating the HTTPAPIEX_SAS_HANDLE fails then IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall fail and return IOTHUB_CLIENT_ERROR. ]*/
101 HTTPAPIEX_SAS_HANDLE http_sas_handle = HTTPAPIEX_SAS_Create_From_String(IoTHubClient_Auth_Get_DeviceKey(upload_client->authorization_module), uri_resource, EMPTY_STRING);
102 if (http_sas_handle == NULL)
103 {
104 LogError("unable to HTTPAPIEX_SAS_Create");
105 result = MU_FAILURE;
106 }
107 else
108 {
109 /*Codes_SRS_IOTHUBCLIENT_LL_32_003: [ IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall execute HTTPAPIEX_ExecuteRequest passing the following information for arguments: ]*/
110 if (HTTPAPIEX_SAS_ExecuteRequest(http_sas_handle, http_api_handle, HTTPAPI_REQUEST_POST, relative_path, request_header,
111 blobBuffer, &statusCode, NULL, response_buff) != HTTPAPIEX_OK)
112 {
113 /*Codes_SRS_IOTHUBCLIENT_LL_02_076: [ If HTTPAPIEX_ExecuteRequest call fails then IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall fail and return IOTHUB_CLIENT_ERROR. ]*/
114 result = MU_FAILURE;
115 LogError("unable to HTTPAPIEX_ExecuteRequest");
116 }
117 else if (statusCode >= 300)
118 {
119 result = MU_FAILURE;
120 LogError("HTTP code was %u", statusCode);
121 }
122 else
123 {
124 result = 0;
125 }
126 HTTPAPIEX_SAS_Destroy(http_sas_handle);
127 }
128 return result;
129}
130
131static int send_http_request(HTTPAPIEX_HANDLE http_api_handle, const char* relative_path, HTTP_HEADERS_HANDLE request_header, BUFFER_HANDLE blobBuffer, BUFFER_HANDLE response_buff)
132{
133 int result;
134 unsigned int statusCode;
135 /*Codes_SRS_IOTHUBCLIENT_LL_32_003: [ IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall execute HTTPAPIEX_ExecuteRequest passing the following information for arguments: ]*/
136 if (HTTPAPIEX_ExecuteRequest(http_api_handle, HTTPAPI_REQUEST_POST, relative_path, request_header,
137 blobBuffer, &statusCode, NULL, response_buff) != HTTPAPIEX_OK)
138 {
139 /*Codes_SRS_IOTHUBCLIENT_LL_02_076: [ If HTTPAPIEX_ExecuteRequest call fails then IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall fail and return IOTHUB_CLIENT_ERROR. ]*/
140 result = MU_FAILURE;
141 LogError("unable to HTTPAPIEX_ExecuteRequest");
142 }
143 else if (statusCode >= 300)
144 {
145 result = MU_FAILURE;
146 LogError("HTTP code was %u", statusCode);
147 }
148 else
149 {
150 result = 0;
151 }
152 return result;
153}
154
155static int parse_result_json(const char* json_response, STRING_HANDLE correlation_id, STRING_HANDLE sas_uri)
156{
157 int result;
158
159 JSON_Object* json_obj;
160 /*Codes_SRS_IOTHUBCLIENT_LL_02_081: [ Otherwise, IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall use parson to extract and save the following information from the response buffer: correlationID and SasUri. ]*/
161 JSON_Value* json = json_parse_string(json_response);
162 if (json == NULL)
163 {
164 /*Codes_SRS_IOTHUBCLIENT_LL_02_082: [ If extracting and saving the correlationId or SasUri fails then IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall fail and return IOTHUB_CLIENT_ERROR. ]*/
165 LogError("unable to json_parse_string");
166 result = MU_FAILURE;
167
168 }
169 else
170 {
171 if ((json_obj = json_value_get_object(json)) == NULL)
172 {
173 LogError("unable to get json_value_get_object");
174 result = MU_FAILURE;
175 }
176 else
177 {
178 const char* json_corr_id;
179 const char* json_hostname;
180 const char* json_container_name;
181 const char* json_blob_name;
182 const char* json_sas_token;
183 STRING_HANDLE filename;
184 if ((json_corr_id = json_object_get_string(json_obj, "correlationId")) == NULL)
185 {
186 LogError("unable to retrieve correlation Id from json");
187 result = MU_FAILURE;
188 }
189 else if ((json_hostname = json_object_get_string(json_obj, "hostName")) == NULL)
190 {
191 LogError("unable to retrieve hostname Id from json");
192 result = MU_FAILURE;
193 }
194 else if ((json_container_name = json_object_get_string(json_obj, "containerName")) == NULL)
195 {
196 LogError("unable to retrieve container name Id from json");
197 result = MU_FAILURE;
198 }
199 else if ((json_blob_name = json_object_get_string(json_obj, "blobName")) == NULL)
200 {
201 LogError("unable to retrieve blob name Id from json");
202 result = MU_FAILURE;
203 }
204 else if ((json_sas_token = json_object_get_string(json_obj, "sasToken")) == NULL)
205 {
206 LogError("unable to retrieve sas token from json");
207 result = MU_FAILURE;
208 }
209 /*Codes_SRS_IOTHUBCLIENT_LL_32_008: [ The returned file name shall be URL encoded before passing back to the cloud. ]*/
210 else if ((filename = URL_EncodeString(json_blob_name)) == NULL)
211 {
212 /*Codes_SRS_IOTHUBCLIENT_LL_32_009: [ If URL_EncodeString fails then IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall fail and return IOTHUB_CLIENT_ERROR. ]*/
213 LogError("unable to URL encode of filename");
214 result = MU_FAILURE;
215 }
216 else
217 {
218 if (STRING_sprintf(sas_uri, "https://%s/%s/%s%s", json_hostname, json_container_name, STRING_c_str(filename), json_sas_token) != 0)
219 {
220 /*Codes_SRS_IOTHUBCLIENT_LL_02_082: [ If extracting and saving the correlationId or SasUri fails then IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall fail and return IOTHUB_CLIENT_ERROR. ]*/
221 LogError("unable to construct uri string");
222 result = MU_FAILURE;
223 }
224 else if (STRING_copy(correlation_id, json_corr_id) != 0)
225 {
226 /*Codes_SRS_IOTHUBCLIENT_LL_02_082: [ If extracting and saving the correlationId or SasUri fails then IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall fail and return IOTHUB_CLIENT_ERROR. ]*/
227 LogError("unable to copy correlation Id");
228 result = MU_FAILURE;
229 STRING_empty(sas_uri);
230 }
231 else
232 {
233 result = 0;
234 }
235 STRING_delete(filename);
236 }
237 }
238 json_value_free(json);
239 }
240 return result;
241}
242
243IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE IoTHubClient_LL_UploadToBlob_Create(const IOTHUB_CLIENT_CONFIG* config, IOTHUB_AUTHORIZATION_HANDLE auth_handle)
244{
245 IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE_DATA* upload_data;
246 if (auth_handle == NULL || config == NULL)
247 {
248 LogError("Invalid arguments auth_handle: %p, config: %p", auth_handle, config);
249 upload_data = NULL;
250 }
251 else
252 {
253 upload_data = malloc(sizeof(IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE_DATA));
254 if (upload_data == NULL)
255 {
256 LogError("Failed malloc allocation");
257 /*return as is*/
258 }
259 else
260 {
261 memset(upload_data, 0, sizeof(IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE_DATA));
262
263 upload_data->authorization_module = auth_handle;
264
265 size_t iotHubNameLength = strlen(config->iotHubName);
266 size_t iotHubSuffixLength = strlen(config->iotHubSuffix);
267 upload_data->hostname = malloc(iotHubNameLength + 1 + iotHubSuffixLength + 1); /*first +1 is because "." the second +1 is because \0*/
268 if (upload_data->hostname == NULL)
269 {
270 LogError("Failed malloc allocation");
271 free(upload_data);
272 upload_data = NULL;
273 }
274 else if ((upload_data->deviceId = IoTHubClient_Auth_Get_DeviceId(upload_data->authorization_module)) == NULL)
275 {
276 LogError("Failed retrieving device ID");
277 free(upload_data->hostname);
278 free(upload_data);
279 upload_data = NULL;
280 }
281 else
282 {
283 char* insert_pos = (char*)upload_data->hostname;
284 (void)memcpy((char*)insert_pos, config->iotHubName, iotHubNameLength);
285 insert_pos += iotHubNameLength;
286 *insert_pos = '.';
287 insert_pos += 1;
288 (void)memcpy(insert_pos, config->iotHubSuffix, iotHubSuffixLength); /*+1 will copy the \0 too*/
289 insert_pos += iotHubSuffixLength;
290 *insert_pos = '\0';
291
292 upload_data->cred_type = IoTHubClient_Auth_Get_Credential_Type(upload_data->authorization_module);
293 // If the credential type is unknown then it means that we are using x509 because the certs need to get
294 // passed down later in the process.
295 if (upload_data->cred_type == IOTHUB_CREDENTIAL_TYPE_UNKNOWN || upload_data->cred_type == IOTHUB_CREDENTIAL_TYPE_X509)
296 {
297 upload_data->cred_type = IOTHUB_CREDENTIAL_TYPE_X509;
298 upload_data->credentials.x509_credentials.x509certificate = NULL;
299 upload_data->credentials.x509_credentials.x509privatekey = NULL;
300 }
301 else if (upload_data->cred_type == IOTHUB_CREDENTIAL_TYPE_X509_ECC)
302 {
303 if (IoTHubClient_Auth_Get_x509_info(upload_data->authorization_module, &upload_data->credentials.x509_credentials.x509certificate, &upload_data->credentials.x509_credentials.x509privatekey) != 0)
304 {
305 LogError("Failed getting x509 certificate information");
306 free(upload_data->hostname);
307 free(upload_data);
308 upload_data = NULL;
309 }
310 }
311 else if (upload_data->cred_type == IOTHUB_CREDENTIAL_TYPE_SAS_TOKEN)
312 {
313 upload_data->credentials.supplied_sas_token = IoTHubClient_Auth_Get_SasToken(upload_data->authorization_module, NULL, 0, EMPTY_STRING);
314 if (upload_data->credentials.supplied_sas_token == NULL)
315 {
316 LogError("Failed retrieving supplied sas token");
317 free(upload_data->hostname);
318 free(upload_data);
319 upload_data = NULL;
320 }
321 }
322 }
323 }
324 }
325 return (IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE)upload_data;
326
327}
328
329/*returns 0 when correlationId, sasUri contain data*/
330static int IoTHubClient_LL_UploadToBlob_step1and2(IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE_DATA* upload_data, HTTPAPIEX_HANDLE iotHubHttpApiExHandle, HTTP_HEADERS_HANDLE requestHttpHeaders, const char* destinationFileName, STRING_HANDLE correlationId, STRING_HANDLE sasUri)
331{
332 int result;
333
334 /*Codes_SRS_IOTHUBCLIENT_LL_02_066: [ IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall create an HTTP relative path formed from "/devices/" + deviceId + "/files/" + "?api-version=API_VERSION". ]*/
335 STRING_HANDLE relativePath = STRING_construct_sprintf("/devices/%s/files/%s", upload_data->deviceId, API_VERSION);
336 if (relativePath == NULL)
337 {
338 /*Codes_SRS_IOTHUBCLIENT_LL_02_067: [ If creating the relativePath fails then IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall fail and return IOTHUB_CLIENT_ERROR. ]*/
339 LogError("Failure constructing string");
340 result = MU_FAILURE;
341 }
342 else
343 {
344 /*Codes_SRS_IOTHUBCLIENT_LL_32_001: [ IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall create a JSON string formed from "{ \"blobName\": \" + destinationFileName + "\" }" */
345 STRING_HANDLE blobName = STRING_construct_sprintf("{ \"blobName\": \"%s\" }", destinationFileName);
346 if (blobName == NULL)
347 {
348 /*Codes_SRS_IOTHUBCLIENT_LL_32_002: [ If creating the JSON string fails then IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall fail and return IOTHUB_CLIENT_ERROR. ]*/
349 LogError("Failure constructing string");
350 result = MU_FAILURE;
351 }
352 else
353 {
354 BUFFER_HANDLE responseContent;
355 size_t len = STRING_length(blobName);
356 BUFFER_HANDLE blobBuffer = BUFFER_create((const unsigned char *)STRING_c_str(blobName), len);
357 if (blobBuffer == NULL)
358 {
359 /*Codes_SRS_IOTHUBCLIENT_LL_32_002: [ If creating the JSON string fails then IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall fail and return IOTHUB_CLIENT_ERROR. ]*/
360 LogError("unable to create BUFFER");
361 result = MU_FAILURE;
362 }
363 else
364 {
365 /*Codes_SRS_IOTHUBCLIENT_LL_02_068: [ IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall create an HTTP responseContent BUFFER_HANDLE. ]*/
366 if ((responseContent = BUFFER_new()) == NULL)
367 {
368 /*Codes_SRS_IOTHUBCLIENT_LL_02_069: [ If creating the HTTP response buffer handle fails then IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall fail and return IOTHUB_CLIENT_ERROR. ]*/
369 result = MU_FAILURE;
370 LogError("unable to BUFFER_new");
371 }
372 else
373 {
374 /*Codes_SRS_IOTHUBCLIENT_LL_02_072: [ IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall add the following name:value to request HTTP headers: ] "Content-Type": "application/json" "Accept": "application/json" "User-Agent": "iothubclient/" IOTHUB_SDK_VERSION*/
375 /*Codes_SRS_IOTHUBCLIENT_LL_02_107: [ - "Authorization" header shall not be build. ]*/
376 if (!(
377 (HTTPHeaders_AddHeaderNameValuePair(requestHttpHeaders, "Content-Type", HEADER_APP_JSON) == HTTP_HEADERS_OK) &&
378 (HTTPHeaders_AddHeaderNameValuePair(requestHttpHeaders, "Accept", HEADER_APP_JSON) == HTTP_HEADERS_OK) &&
379 (HTTPHeaders_AddHeaderNameValuePair(requestHttpHeaders, "User-Agent", "iothubclient/" IOTHUB_SDK_VERSION) == HTTP_HEADERS_OK) &&
380 ((upload_data->cred_type == IOTHUB_CREDENTIAL_TYPE_X509 || upload_data->cred_type == IOTHUB_CREDENTIAL_TYPE_X509_ECC) ||
381 (HTTPHeaders_AddHeaderNameValuePair(requestHttpHeaders, HEADER_AUTHORIZATION, EMPTY_STRING) == HTTP_HEADERS_OK))
382 ))
383 {
384 /*Codes_SRS_IOTHUBCLIENT_LL_02_071: [ If creating the HTTP headers fails then IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall fail and return IOTHUB_CLIENT_ERROR. ]*/
385 LogError("unable to HTTPHeaders_AddHeaderNameValuePair");
386 result = MU_FAILURE;
387 }
388 else
389 {
390 int wasIoTHubRequestSuccess = 0; /*!=0 means responseContent has a buffer that should be parsed by parson after executing the below switch*/
391 /* set the result to error by default */
392 result = MU_FAILURE;
393 switch (upload_data->cred_type)
394 {
395 default:
396 {
397 /*wasIoTHubRequestSuccess takes care of the return value*/
398 LogError("Internal Error: unexpected value in auth schema = %d", upload_data->cred_type);
399 result = MU_FAILURE;
400 break;
401 }
402 case IOTHUB_CREDENTIAL_TYPE_X509_ECC:
403 case IOTHUB_CREDENTIAL_TYPE_X509:
404 {
405 if (send_http_request(iotHubHttpApiExHandle, STRING_c_str(relativePath), requestHttpHeaders, blobBuffer, responseContent) != 0)
406 {
407 /*Codes_SRS_IOTHUBCLIENT_LL_02_076: [ If HTTPAPIEX_ExecuteRequest call fails then IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall fail and return IOTHUB_CLIENT_ERROR. ]*/
408 result = MU_FAILURE;
409 LogError("unable to HTTPAPIEX_ExecuteRequest");
410 }
411 else
412 {
413 wasIoTHubRequestSuccess = 1;
414 }
415 break;
416 }
417 case IOTHUB_CREDENTIAL_TYPE_DEVICE_KEY:
418 case IOTHUB_CREDENTIAL_TYPE_DEVICE_AUTH:
419 {
420 STRING_HANDLE uri_resource = STRING_construct_sprintf("%s/devices/%s", upload_data->hostname, upload_data->deviceId);
421 if (uri_resource == NULL)
422 {
423 /*Codes_SRS_IOTHUBCLIENT_LL_02_089: [ If creating the HTTPAPIEX_SAS_HANDLE fails then IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall fail and return IOTHUB_CLIENT_ERROR. ]*/
424 result = MU_FAILURE;
425 LogError("Failure constructing string");
426 }
427 else
428 {
429 if (upload_data->cred_type == IOTHUB_CREDENTIAL_TYPE_DEVICE_AUTH)
430 {
431 time_t curr_time;
432 if ((curr_time = get_time(NULL)) == INDEFINITE_TIME)
433 {
434 result = MU_FAILURE;
435 LogError("failure retrieving time");
436 }
437 else
438 {
439 size_t expiry = (size_t)(difftime(curr_time, 0) + 3600);
440 char* sas_token = IoTHubClient_Auth_Get_SasToken(upload_data->authorization_module, STRING_c_str(uri_resource), expiry, EMPTY_STRING);
441 if (sas_token == NULL)
442 {
443 result = MU_FAILURE;
444 LogError("unable to retrieve sas token");
445 }
446 else
447 {
448 if (HTTPHeaders_ReplaceHeaderNameValuePair(requestHttpHeaders, HEADER_AUTHORIZATION, sas_token) != HTTP_HEADERS_OK)
449 {
450 /*Codes_SRS_IOTHUBCLIENT_LL_02_074: [ If adding "Authorization" fails then IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall fail and return IOTHUB_CLIENT_ERROR ]*/
451 result = MU_FAILURE;
452 LogError("unable to HTTPHeaders_AddHeaderNameValuePair");
453 }
454 else if (send_http_request(iotHubHttpApiExHandle, STRING_c_str(relativePath), requestHttpHeaders, blobBuffer, responseContent) != 0)
455 {
456 /*Codes_SRS_IOTHUBCLIENT_LL_02_076: [ If HTTPAPIEX_ExecuteRequest call fails then IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall fail and return IOTHUB_CLIENT_ERROR. ]*/
457 result = MU_FAILURE;
458 LogError("unable to HTTPAPIEX_ExecuteRequest");
459 }
460 else
461 {
462 wasIoTHubRequestSuccess = 1;
463 }
464 }
465 free(sas_token);
466 }
467 }
468 else
469 {
470 if (send_http_sas_request(upload_data, STRING_c_str(uri_resource), iotHubHttpApiExHandle, STRING_c_str(relativePath), requestHttpHeaders, blobBuffer, responseContent) != 0)
471 {
472 /*Codes_SRS_IOTHUBCLIENT_LL_02_076: [ If HTTPAPIEX_ExecuteRequest call fails then IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall fail and return IOTHUB_CLIENT_ERROR. ]*/
473 result = MU_FAILURE;
474 LogError("unable to HTTPAPIEX_ExecuteRequest");
475 }
476 else
477 {
478 wasIoTHubRequestSuccess = 1;
479 }
480 }
481 STRING_delete(uri_resource);
482 }
483 break;
484 }
485 case IOTHUB_CREDENTIAL_TYPE_SAS_TOKEN:
486 {
487 /*Codes_SRS_IOTHUBCLIENT_LL_02_073: [ If the credentials used to create handle have "sasToken" then IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall add the following HTTP request headers: ]*/
488 if (HTTPHeaders_ReplaceHeaderNameValuePair(requestHttpHeaders, HEADER_AUTHORIZATION, upload_data->credentials.supplied_sas_token) != HTTP_HEADERS_OK)
489 {
490 /*Codes_SRS_IOTHUBCLIENT_LL_02_074: [ If adding "Authorization" fails then IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall fail and return IOTHUB_CLIENT_ERROR ]*/
491 result = MU_FAILURE;
492 LogError("unable to HTTPHeaders_AddHeaderNameValuePair");
493 }
494 else if (send_http_request(iotHubHttpApiExHandle, STRING_c_str(relativePath), requestHttpHeaders, blobBuffer, responseContent) != 0)
495 {
496 /*Codes_SRS_IOTHUBCLIENT_LL_02_076: [ If HTTPAPIEX_ExecuteRequest call fails then IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall fail and return IOTHUB_CLIENT_ERROR. ]*/
497 result = MU_FAILURE;
498 LogError("unable to HTTPAPIEX_ExecuteRequest");
499 }
500 else
501 {
502 wasIoTHubRequestSuccess = 1;
503 }
504 break;
505 }
506 }
507 if (wasIoTHubRequestSuccess == 1)
508 {
509 const unsigned char*responseContent_u_char = BUFFER_u_char(responseContent);
510 size_t responseContent_length = BUFFER_length(responseContent);
511 STRING_HANDLE responseAsString = STRING_from_byte_array(responseContent_u_char, responseContent_length);
512 if (responseAsString == NULL)
513 {
514 result = MU_FAILURE;
515 LogError("unable to get the response as string");
516 }
517 else
518 {
519 if (parse_result_json(STRING_c_str(responseAsString), correlationId, sasUri) != 0)
520 {
521 /*Codes_SRS_IOTHUBCLIENT_LL_02_082: [ If extracting and saving the correlationId or SasUri fails then IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall fail and return IOTHUB_CLIENT_ERROR. ]*/
522 LogError("unable to parse json result");
523 result = MU_FAILURE;
524 }
525 else
526 {
527 result = 0;
528 }
529 STRING_delete(responseAsString);
530 }
531 }
532 }
533 BUFFER_delete(responseContent);
534 }
535 BUFFER_delete(blobBuffer);
536 }
537 STRING_delete(blobName);
538 }
539 STRING_delete(relativePath);
540 }
541 return result;
542}
543
544/*returns 0 when the IoTHub has been informed about the file upload status*/
545static int IoTHubClient_LL_UploadToBlob_step3(IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE_DATA* upload_data, HTTPAPIEX_HANDLE iotHubHttpApiExHandle, HTTP_HEADERS_HANDLE requestHttpHeaders, BUFFER_HANDLE messageBody)
546{
547 int result;
548 /*here is step 3. depending on the outcome of step 2 it needs to inform IoTHub about the file upload status*/
549 /*if step 1 failed, there's nothing that step 3 needs to report.*/
550 /*this POST "tries" to happen*/
551
552 /*Codes_SRS_IOTHUBCLIENT_LL_02_085: [ IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall use the same authorization as step 1. to prepare and perform a HTTP request with the following parameters: ]*/
553 STRING_HANDLE relativePathNotification = STRING_construct_sprintf("/devices/%s/files/notifications/%s", upload_data->deviceId, API_VERSION);
554 if (relativePathNotification == NULL)
555 {
556 result = MU_FAILURE;
557 LogError("Failure constructing string");
558 }
559 else
560 {
561 /*Codes_SRS_IOTHUBCLIENT_LL_02_086: [ If performing the HTTP request fails then IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall fail and return IOTHUB_CLIENT_ERROR. ]*/
562 switch (upload_data->cred_type)
563 {
564 default:
565 {
566 LogError("internal error: unknown authorization Scheme");
567 result = MU_FAILURE;
568 break;
569 }
570 case IOTHUB_CREDENTIAL_TYPE_SAS_TOKEN:
571 case IOTHUB_CREDENTIAL_TYPE_X509:
572 case IOTHUB_CREDENTIAL_TYPE_X509_ECC:
573 case IOTHUB_CREDENTIAL_TYPE_DEVICE_AUTH:
574 {
575 if (send_http_request(iotHubHttpApiExHandle, STRING_c_str(relativePathNotification), requestHttpHeaders, messageBody, NULL) != 0)
576 {
577 LogError("unable to execute HTTPAPIEX_ExecuteRequest");
578 result = MU_FAILURE;
579 }
580 else
581 {
582 result = 0;
583 }
584 break;
585 }
586 case IOTHUB_CREDENTIAL_TYPE_DEVICE_KEY:
587 {
588 STRING_HANDLE uriResource = STRING_construct_sprintf("%s/devices/%s/files/notifications", upload_data->hostname, upload_data->deviceId);
589 if (uriResource == NULL)
590 {
591 LogError("Failure constructing string");
592 result = MU_FAILURE;
593 }
594 else
595 {
596 if (send_http_sas_request(upload_data, STRING_c_str(uriResource), iotHubHttpApiExHandle, STRING_c_str(relativePathNotification), requestHttpHeaders, messageBody, NULL) != 0)
597 {
598 LogError("unable to execute HTTPAPIEX_ExecuteRequest");
599 result = MU_FAILURE;
600 }
601 else
602 {
603 result = 0;
604 }
605 STRING_delete(uriResource);
606 }
607 break;
608 }
609 }
610 STRING_delete(relativePathNotification);
611 }
612 return result;
613}
614
615// this callback splits the source data into blocks to be fed to IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex)_Impl
616static IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_RESULT FileUpload_GetData_Callback(IOTHUB_CLIENT_FILE_UPLOAD_RESULT result, unsigned char const ** data, size_t* size, void* context)
617{
618 BLOB_UPLOAD_CONTEXT* uploadContext = (BLOB_UPLOAD_CONTEXT*) context;
619
620 if (data == NULL || size == NULL)
621 {
622 // This is the last call, nothing to do
623 }
624 else if (result != FILE_UPLOAD_OK)
625 {
626 // Last call failed
627 *data = NULL;
628 *size = 0;
629 }
630 else if (uploadContext->remainingSizeToUpload == 0)
631 {
632 // Everything has been uploaded
633 *data = NULL;
634 *size = 0;
635 }
636 else
637 {
638 // Upload next block
639 size_t thisBlockSize = (uploadContext->remainingSizeToUpload > BLOCK_SIZE) ? BLOCK_SIZE : uploadContext->remainingSizeToUpload;
640 *data = (unsigned char*)uploadContext->blobSource + (uploadContext->blobSourceSize - uploadContext->remainingSizeToUpload);
641 *size = thisBlockSize;
642 uploadContext->remainingSizeToUpload -= thisBlockSize;
643 }
644
645 return IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_OK;
646}
647
648static HTTPAPIEX_RESULT set_transfer_timeout(IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE_DATA* upload_data, HTTPAPIEX_HANDLE iotHubHttpApiExHandle)
649{
650 HTTPAPIEX_RESULT result;
651 if (upload_data->blob_upload_timeout_secs != 0)
652 {
653 // Convert the timeout to milliseconds for curl
654 long http_timeout = (long)upload_data->blob_upload_timeout_secs * 1000;
655 result = HTTPAPIEX_SetOption(iotHubHttpApiExHandle, OPTION_HTTP_TIMEOUT, &http_timeout);
656 }
657 else
658 {
659 result = HTTPAPIEX_OK;
660 }
661 return result;
662}
663
664IOTHUB_CLIENT_RESULT IoTHubClient_LL_UploadMultipleBlocksToBlob_Impl(IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE handle, const char* destinationFileName, IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_CALLBACK_EX getDataCallbackEx, void* context)
665{
666 IOTHUB_CLIENT_RESULT result;
667
668 /*Codes_SRS_IOTHUBCLIENT_LL_02_061: [ If handle is NULL then IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall fail and return IOTHUB_CLIENT_INVALID_ARG. ]*/
669 /*Codes_SRS_IOTHUBCLIENT_LL_02_062: [ If destinationFileName is NULL then IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall fail and return IOTHUB_CLIENT_INVALID_ARG. ]*/
670
671 if (handle == NULL || destinationFileName == NULL || getDataCallbackEx == NULL)
672 {
673 LogError("invalid argument detected handle=%p destinationFileName=%p getDataCallbackEx=%p", handle, destinationFileName, getDataCallbackEx);
674 result = IOTHUB_CLIENT_INVALID_ARG;
675 }
676 else
677 {
678 IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE_DATA* upload_data = (IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE_DATA*)handle;
679
680 /*Codes_SRS_IOTHUBCLIENT_LL_02_064: [ IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall create an HTTPAPIEX_HANDLE to the IoTHub hostname. ]*/
681 HTTPAPIEX_HANDLE iotHubHttpApiExHandle = HTTPAPIEX_Create(upload_data->hostname);
682 /*Codes_SRS_IOTHUBCLIENT_LL_02_065: [ If creating the HTTPAPIEX_HANDLE fails then IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall fail and return IOTHUB_CLIENT_ERROR. ]*/
683 if (iotHubHttpApiExHandle == NULL)
684 {
685 LogError("unable to HTTPAPIEX_Create");
686 result = IOTHUB_CLIENT_ERROR;
687 }
688 /*Codes_SRS_IOTHUBCLIENT_LL_30_020: [ If the blob_upload_timeout_secs option has been set to non-zero, IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall set the timeout on the underlying transport accordingly. ]*/
689 else if (set_transfer_timeout(upload_data, iotHubHttpApiExHandle) != HTTPAPIEX_OK)
690 {
691 LogError("unable to set blob transfer timeout");
692 result = IOTHUB_CLIENT_ERROR;
693 }
694 else
695 {
696 if (upload_data->curl_verbosity_level != UPOADTOBLOB_CURL_VERBOSITY_UNSET)
697 {
698 size_t curl_verbose = (upload_data->curl_verbosity_level == UPOADTOBLOB_CURL_VERBOSITY_ON);
699 (void)HTTPAPIEX_SetOption(iotHubHttpApiExHandle, OPTION_CURL_VERBOSE, &curl_verbose);
700 }
701
702 /*transmit the x509certificate and x509privatekey*/
703 /*Codes_SRS_IOTHUBCLIENT_LL_02_106: [ - x509certificate and x509privatekey saved options shall be passed on the HTTPAPIEX_SetOption ]*/
704 if ((upload_data->cred_type == IOTHUB_CREDENTIAL_TYPE_X509 || upload_data->cred_type == IOTHUB_CREDENTIAL_TYPE_X509_ECC) &&
705 ((HTTPAPIEX_SetOption(iotHubHttpApiExHandle, OPTION_X509_CERT, upload_data->credentials.x509_credentials.x509certificate) != HTTPAPIEX_OK) ||
706 (HTTPAPIEX_SetOption(iotHubHttpApiExHandle, OPTION_X509_PRIVATE_KEY, upload_data->credentials.x509_credentials.x509privatekey) != HTTPAPIEX_OK))
707 )
708 {
709 LogError("unable to HTTPAPIEX_SetOption for x509 certificate");
710 result = IOTHUB_CLIENT_ERROR;
711 }
712 else
713 {
714 /*Codes_SRS_IOTHUBCLIENT_LL_02_111: [ If certificates is non-NULL then certificates shall be passed to HTTPAPIEX_SetOption with optionName TrustedCerts. ]*/
715 if ((upload_data->certificates != NULL) && (HTTPAPIEX_SetOption(iotHubHttpApiExHandle, OPTION_TRUSTED_CERT, upload_data->certificates) != HTTPAPIEX_OK))
716 {
717 LogError("unable to set TrustedCerts!");
718 result = IOTHUB_CLIENT_ERROR;
719 }
720 else
721 {
722
723 if (upload_data->http_proxy_options.host_address != NULL)
724 {
725 HTTP_PROXY_OPTIONS proxy_options;
726 proxy_options = upload_data->http_proxy_options;
727
728 if (HTTPAPIEX_SetOption(iotHubHttpApiExHandle, OPTION_HTTP_PROXY, &proxy_options) != HTTPAPIEX_OK)
729 {
730 LogError("unable to set http proxy!");
731 result = IOTHUB_CLIENT_ERROR;
732 }
733 else
734 {
735 result = IOTHUB_CLIENT_OK;
736 }
737 }
738 else
739 {
740 result = IOTHUB_CLIENT_OK;
741 }
742
743 if (result != IOTHUB_CLIENT_ERROR)
744 {
745 STRING_HANDLE sasUri;
746 STRING_HANDLE correlationId;
747 if ((correlationId = STRING_new()) == NULL)
748 {
749 LogError("unable to STRING_new");
750 result = IOTHUB_CLIENT_ERROR;
751 }
752 else if ((sasUri = STRING_new()) == NULL)
753 {
754 LogError("unable to create sas uri");
755 result = IOTHUB_CLIENT_ERROR;
756 STRING_delete(correlationId);
757 }
758 else
759 {
760 /*Codes_SRS_IOTHUBCLIENT_LL_02_070: [ IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall create request HTTP headers. ]*/
761 HTTP_HEADERS_HANDLE requestHttpHeaders = HTTPHeaders_Alloc(); /*these are build by step 1 and used by step 3 too*/
762 if (requestHttpHeaders == NULL)
763 {
764 LogError("unable to HTTPHeaders_Alloc");
765 result = IOTHUB_CLIENT_ERROR;
766 }
767 else
768 {
769 /*do step 1*/
770 if (IoTHubClient_LL_UploadToBlob_step1and2(upload_data, iotHubHttpApiExHandle, requestHttpHeaders, destinationFileName, correlationId, sasUri) != 0)
771 {
772 LogError("error in IoTHubClient_LL_UploadToBlob_step1");
773 result = IOTHUB_CLIENT_ERROR;
774 }
775 else
776 {
777 /*do step 2.*/
778
779 unsigned int httpResponse;
780 BUFFER_HANDLE responseToIoTHub = BUFFER_new();
781 if (responseToIoTHub == NULL)
782 {
783 result = IOTHUB_CLIENT_ERROR;
784 LogError("unable to BUFFER_new");
785 }
786 else
787 {
788 /*Codes_SRS_IOTHUBCLIENT_LL_02_083: [ IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall call Blob_UploadFromSasUri and capture the HTTP return code and HTTP body. ]*/
789 BLOB_RESULT uploadMultipleBlocksResult = Blob_UploadMultipleBlocksFromSasUri(STRING_c_str(sasUri), getDataCallbackEx, context, &httpResponse, responseToIoTHub, upload_data->certificates, &(upload_data->http_proxy_options));
790 if (uploadMultipleBlocksResult == BLOB_ABORTED)
791 {
792 /*Codes_SRS_IOTHUBCLIENT_LL_99_008: [ If step 2 is aborted by the client, then the HTTP message body shall look like: ]*/
793 LogInfo("Blob_UploadFromSasUri aborted file upload");
794
795 STRING_HANDLE aborted_response = STRING_construct_sprintf(RESPONSE_BODY_FORMAT,
796 STRING_c_str(correlationId),
797 RESPONSE_BODY_ERROR_BOOLEAN_STRING,
798 RESPONSE_BODY_ERROR_RETURN_CODE,
799 RESPONSE_BODY_ABORTED_MESSAGE);
800 if(aborted_response == NULL)
801 {
802 LogError("STRING_construct_sprintf failed");
803 result = IOTHUB_CLIENT_ERROR;
804 }
805 else
806 {
807 size_t response_length = STRING_length(aborted_response);
808 if (BUFFER_build(responseToIoTHub, (const unsigned char*)STRING_c_str(aborted_response), response_length) == 0)
809 {
810 if (IoTHubClient_LL_UploadToBlob_step3(upload_data, iotHubHttpApiExHandle, requestHttpHeaders, responseToIoTHub) != 0)
811 {
812 LogError("IoTHubClient_LL_UploadToBlob_step3 failed");
813 result = IOTHUB_CLIENT_ERROR;
814 }
815 else
816 {
817 /*Codes_SRS_IOTHUBCLIENT_LL_99_009: [ If step 2 is aborted by the client and if step 3 succeeds, then `IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex)` shall return `IOTHUB_CLIENT_OK`. ] */
818 result = IOTHUB_CLIENT_OK;
819 }
820 }
821 else
822 {
823 LogError("Unable to BUFFER_build, can't perform IoTHubClient_LL_UploadToBlob_step3");
824 result = IOTHUB_CLIENT_ERROR;
825 }
826 STRING_delete(aborted_response);
827 }
828 }
829 else if (uploadMultipleBlocksResult != BLOB_OK)
830 {
831 /*Codes_SRS_IOTHUBCLIENT_LL_02_084: [ If Blob_UploadFromSasUri fails then IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex) shall fail and return IOTHUB_CLIENT_ERROR. ]*/
832 LogError("unable to Blob_UploadFromSasUri");
833
834 /*do step 3*/ /*try*/
835 /*Codes_SRS_IOTHUBCLIENT_LL_02_091: [ If step 2 fails without establishing an HTTP dialogue, then the HTTP message body shall look like: ]*/
836 STRING_HANDLE failed_response = STRING_construct_sprintf(RESPONSE_BODY_FORMAT,
837 STRING_c_str(correlationId),
838 RESPONSE_BODY_ERROR_BOOLEAN_STRING,
839 RESPONSE_BODY_ERROR_RETURN_CODE,
840 RESPONSE_BODY_FAILED_MESSAGE);
841 if(failed_response == NULL)
842 {
843 LogError("STRING_construct_sprintf failed");
844 result = IOTHUB_CLIENT_ERROR;
845 }
846 else
847 {
848 size_t response_length = STRING_length(failed_response);
849 if (BUFFER_build(responseToIoTHub, (const unsigned char*)STRING_c_str(failed_response), response_length) == 0)
850 {
851 if (IoTHubClient_LL_UploadToBlob_step3(upload_data, iotHubHttpApiExHandle, requestHttpHeaders, responseToIoTHub) != 0)
852 {
853 LogError("IoTHubClient_LL_UploadToBlob_step3 failed");
854 }
855 }
856 STRING_delete(failed_response);
857 result = IOTHUB_CLIENT_ERROR;
858 }
859 }
860 else
861 {
862 /*must make a json*/
863 unsigned char * response = BUFFER_u_char(responseToIoTHub);
864 STRING_HANDLE req_string;
865 req_string = STRING_construct_sprintf(RESPONSE_BODY_FORMAT,
866 STRING_c_str(correlationId),
867 ((httpResponse < 300) ? "true" : "false"),
868 httpResponse,
869 (response == NULL ? (const unsigned char*)"" : response));
870 if (req_string == NULL)
871 {
872 LogError("Failure constructing string");
873 result = IOTHUB_CLIENT_ERROR;
874 }
875 else
876 {
877 /*do again snprintf*/
878 BUFFER_HANDLE toBeTransmitted = NULL;
879 size_t req_string_len = STRING_length(req_string);
880 const char* required_string = STRING_c_str(req_string);
881 if ((toBeTransmitted = BUFFER_create((const unsigned char*)required_string, req_string_len)) == NULL)
882 {
883 LogError("unable to BUFFER_create");
884 result = IOTHUB_CLIENT_ERROR;
885 }
886 else
887 {
888 if (IoTHubClient_LL_UploadToBlob_step3(upload_data, iotHubHttpApiExHandle, requestHttpHeaders, toBeTransmitted) != 0)
889 {
890 LogError("IoTHubClient_LL_UploadToBlob_step3 failed");
891 result = IOTHUB_CLIENT_ERROR;
892 }
893 else
894 {
895 result = (httpResponse < 300) ? IOTHUB_CLIENT_OK : IOTHUB_CLIENT_ERROR;
896 }
897 BUFFER_delete(toBeTransmitted);
898 }
899 STRING_delete(req_string);
900 }
901 }
902 BUFFER_delete(responseToIoTHub);
903 }
904 }
905 HTTPHeaders_Free(requestHttpHeaders);
906 }
907 STRING_delete(sasUri);
908 STRING_delete(correlationId);
909 }
910 }
911 }
912 }
913 HTTPAPIEX_Destroy(iotHubHttpApiExHandle);
914 }
915
916 /*Codes_SRS_IOTHUBCLIENT_LL_99_003: [ If `IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex)` return `IOTHUB_CLIENT_OK`, it shall call `getDataCallbackEx` with `result` set to `FILE_UPLOAD_OK`, and `data` and `size` set to NULL. ]*/
917 /*Codes_SRS_IOTHUBCLIENT_LL_99_004: [ If `IoTHubClient_LL_UploadMultipleBlocksToBlob(Ex)` does not return `IOTHUB_CLIENT_OK`, it shall call `getDataCallbackEx` with `result` set to `FILE_UPLOAD_ERROR`, and `data` and `size` set to NULL. ]*/
918 (void)getDataCallbackEx(result == IOTHUB_CLIENT_OK ? FILE_UPLOAD_OK : FILE_UPLOAD_ERROR, NULL, NULL, context);
919 }
920 return result;
921}
922
923IOTHUB_CLIENT_RESULT IoTHubClient_LL_UploadToBlob_Impl(IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE handle, const char* destinationFileName, const unsigned char* source, size_t size)
924{
925 IOTHUB_CLIENT_RESULT result;
926
927 if (handle == NULL || destinationFileName == NULL)
928 {
929 LogError("Invalid parameter handle:%p destinationFileName:%p", handle, destinationFileName);
930 result = IOTHUB_CLIENT_INVALID_ARG;
931 }
932 /*Codes_SRS_IOTHUBCLIENT_LL_02_063: [ If source is NULL and size is greater than 0 then IoTHubClient_LL_UploadToBlob shall fail and return IOTHUB_CLIENT_INVALID_ARG. ]*/
933 else if (source == NULL && size > 0)
934 {
935 LogError("Invalid source and size combination: source=%p size=%lu", source, (unsigned long)size);
936 result = IOTHUB_CLIENT_INVALID_ARG;
937 }
938 else
939 {
940 /*Codes_SRS_IOTHUBCLIENT_LL_99_001: [ `IoTHubClient_LL_UploadToBlob` shall create a struct containing the `source`, the `size`, and the remaining size to upload.]*/
941 BLOB_UPLOAD_CONTEXT context;
942 context.blobSource = source;
943 context.blobSourceSize = size;
944 context.remainingSizeToUpload = size;
945
946 /*Codes_SRS_IOTHUBCLIENT_LL_99_002: [ `IoTHubClient_LL_UploadToBlob` shall call `IoTHubClient_LL_UploadMultipleBlocksToBlob_Impl` with `FileUpload_GetData_Callback` as `getDataCallbackEx` and pass the struct created at step SRS_IOTHUBCLIENT_LL_99_001 as `context` ]*/
947 result = IoTHubClient_LL_UploadMultipleBlocksToBlob_Impl(handle, destinationFileName, FileUpload_GetData_Callback, &context);
948 }
949 return result;
950}
951
952void IoTHubClient_LL_UploadToBlob_Destroy(IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE handle)
953{
954 if (handle == NULL)
955 {
956 LogError("unexpected NULL argument");
957 }
958 else
959 {
960 IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE_DATA* upload_data = (IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE_DATA*)handle;
961
962 if (upload_data->cred_type == IOTHUB_CREDENTIAL_TYPE_X509 || upload_data->cred_type == IOTHUB_CREDENTIAL_TYPE_X509_ECC)
963 {
964 free(upload_data->credentials.x509_credentials.x509certificate);
965 free(upload_data->credentials.x509_credentials.x509privatekey);
966 }
967 else if (upload_data->cred_type == IOTHUB_CREDENTIAL_TYPE_SAS_TOKEN)
968 {
969 free(upload_data->credentials.supplied_sas_token);
970 }
971
972 free((void*)upload_data->hostname);
973 if (upload_data->certificates != NULL)
974 {
975 free(upload_data->certificates);
976 }
977 if (upload_data->http_proxy_options.host_address != NULL)
978 {
979 free((char *)upload_data->http_proxy_options.host_address);
980 }
981 if (upload_data->http_proxy_options.username != NULL)
982 {
983 free((char *)upload_data->http_proxy_options.username);
984 }
985 if (upload_data->http_proxy_options.password != NULL)
986 {
987 free((char *)upload_data->http_proxy_options.password);
988 }
989 free(upload_data);
990 }
991}
992
993IOTHUB_CLIENT_RESULT IoTHubClient_LL_UploadToBlob_SetOption(IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE handle, const char* optionName, const void* value)
994{
995 IOTHUB_CLIENT_RESULT result;
996 /*Codes_SRS_IOTHUBCLIENT_LL_02_110: [ If parameter handle is NULL then IoTHubClient_LL_UploadToBlob_SetOption shall fail and return IOTHUB_CLIENT_ERROR. ]*/
997 if (handle == NULL)
998 {
999 LogError("invalid argument detected: IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE handle=%p, const char* optionName=%s, const void* value=%p", handle, optionName, value);
1000 result = IOTHUB_CLIENT_ERROR;
1001 }
1002 else
1003 {
1004 IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE_DATA* upload_data = (IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE_DATA*)handle;
1005
1006 /*Codes_SRS_IOTHUBCLIENT_LL_02_100: [ x509certificate - then value then is a null terminated string that contains the x509 certificate. ]*/
1007 if (strcmp(optionName, OPTION_X509_CERT) == 0)
1008 {
1009 /*Codes_SRS_IOTHUBCLIENT_LL_02_109: [ If the authentication scheme is NOT x509 then IoTHubClient_LL_UploadToBlob_SetOption shall return IOTHUB_CLIENT_INVALID_ARG. ]*/
1010 if (upload_data->cred_type != IOTHUB_CREDENTIAL_TYPE_X509)
1011 {
1012 LogError("trying to set a x509 certificate while the authentication scheme is not x509");
1013 result = IOTHUB_CLIENT_INVALID_ARG;
1014 }
1015 else
1016 {
1017 /*Codes_SRS_IOTHUBCLIENT_LL_02_103: [ The options shall be saved. ]*/
1018 /*try to make a copy of the certificate*/
1019 char* temp;
1020 if (mallocAndStrcpy_s(&temp, value) != 0)
1021 {
1022 /*Codes_SRS_IOTHUBCLIENT_LL_02_104: [ If saving fails, then IoTHubClient_LL_UploadToBlob_SetOption shall fail and return IOTHUB_CLIENT_ERROR. ]*/
1023 LogError("unable to mallocAndStrcpy_s");
1024 result = IOTHUB_CLIENT_ERROR;
1025 }
1026 else
1027 {
1028 /*Codes_SRS_IOTHUBCLIENT_LL_02_105: [ Otherwise IoTHubClient_LL_UploadToBlob_SetOption shall succeed and return IOTHUB_CLIENT_OK. ]*/
1029 if (upload_data->credentials.x509_credentials.x509certificate != NULL) /*free any previous values, if any*/
1030 {
1031 free(upload_data->credentials.x509_credentials.x509certificate);
1032 }
1033 upload_data->credentials.x509_credentials.x509certificate = temp;
1034 result = IOTHUB_CLIENT_OK;
1035 }
1036 }
1037 }
1038 /*Codes_SRS_IOTHUBCLIENT_LL_02_101: [ x509privatekey - then value is a null terminated string that contains the x509 privatekey. ]*/
1039 else if (strcmp(optionName, OPTION_X509_PRIVATE_KEY) == 0)
1040 {
1041 /*Codes_SRS_IOTHUBCLIENT_LL_02_109: [ If the authentication scheme is NOT x509 then IoTHubClient_LL_UploadToBlob_SetOption shall return IOTHUB_CLIENT_INVALID_ARG. ]*/
1042 if (upload_data->cred_type != IOTHUB_CREDENTIAL_TYPE_X509)
1043 {
1044 LogError("trying to set a x509 privatekey while the authentication scheme is not x509");
1045 result = IOTHUB_CLIENT_INVALID_ARG;
1046 }
1047 else
1048 {
1049 /*Codes_SRS_IOTHUBCLIENT_LL_02_103: [ The options shall be saved. ]*/
1050 /*try to make a copy of the privatekey*/
1051 char* temp;
1052 if (mallocAndStrcpy_s(&temp, value) != 0)
1053 {
1054 /*Codes_SRS_IOTHUBCLIENT_LL_02_104: [ If saving fails, then IoTHubClient_LL_UploadToBlob_SetOption shall fail and return IOTHUB_CLIENT_ERROR. ]*/
1055 LogError("unable to mallocAndStrcpy_s");
1056 result = IOTHUB_CLIENT_ERROR;
1057 }
1058 else
1059 {
1060 /*Codes_SRS_IOTHUBCLIENT_LL_02_105: [ Otherwise IoTHubClient_LL_UploadToBlob_SetOption shall succeed and return IOTHUB_CLIENT_OK. ]*/
1061 if (upload_data->credentials.x509_credentials.x509privatekey != NULL) /*free any previous values, if any*/
1062 {
1063 free(upload_data->credentials.x509_credentials.x509privatekey);
1064 }
1065 upload_data->credentials.x509_credentials.x509privatekey = temp;
1066 result = IOTHUB_CLIENT_OK;
1067 }
1068 }
1069 }
1070 else if (strcmp(OPTION_TRUSTED_CERT, optionName) == 0)
1071 {
1072 if (value == NULL)
1073 {
1074 LogError("NULL is a not a valid value for TrustedCerts");
1075 result = IOTHUB_CLIENT_INVALID_ARG;
1076 }
1077 else
1078 {
1079 char* tempCopy;
1080 if (mallocAndStrcpy_s(&tempCopy, value) != 0)
1081 {
1082 LogError("failure in mallocAndStrcpy_s");
1083 result = IOTHUB_CLIENT_ERROR;
1084 }
1085 else
1086 {
1087 if (upload_data->certificates != NULL)
1088 {
1089 free(upload_data->certificates);
1090 }
1091 upload_data->certificates = tempCopy;
1092 result = IOTHUB_CLIENT_OK;
1093 }
1094 }
1095 }
1096 /*Codes_SRS_IOTHUBCLIENT_LL_32_008: [ OPTION_HTTP_PROXY - then the value will be a pointer to HTTP_PROXY_OPTIONS structure. ]*/
1097 else if (strcmp(optionName, OPTION_HTTP_PROXY) == 0)
1098 {
1099 HTTP_PROXY_OPTIONS* proxy_options = (HTTP_PROXY_OPTIONS *)value;
1100
1101 if (proxy_options->host_address == NULL)
1102 {
1103 /* Codes_SRS_IOTHUBCLIENT_LL_32_006: [ If `host_address` is NULL, `IoTHubClient_LL_UploadToBlob_SetOption` shall fail and return `IOTHUB_CLIENT_INVALID_ARG`. ]*/
1104 LogError("NULL host_address in proxy options");
1105 result = IOTHUB_CLIENT_INVALID_ARG;
1106 }
1107 /* Codes_SRS_IOTHUBCLIENT_LL_32_007: [ If only one of `username` and `password` is NULL, `IoTHubClient_LL_UploadToBlob_SetOption` shall fail and return `IOTHUB_CLIENT_INVALID_ARG`. ]*/
1108 else if (((proxy_options->username == NULL) || (proxy_options->password == NULL)) &&
1109 (proxy_options->username != proxy_options->password))
1110 {
1111 LogError("Only one of username and password for proxy settings was NULL");
1112 result = IOTHUB_CLIENT_INVALID_ARG;
1113 }
1114 else
1115 {
1116 if (upload_data->http_proxy_options.host_address != NULL)
1117 {
1118 free((char *)upload_data->http_proxy_options.host_address);
1119 upload_data->http_proxy_options.host_address = NULL;
1120 }
1121 if (upload_data->http_proxy_options.username != NULL)
1122 {
1123 free((char *)upload_data->http_proxy_options.username);
1124 upload_data->http_proxy_options.username = NULL;
1125 }
1126 if (upload_data->http_proxy_options.password != NULL)
1127 {
1128 free((char *)upload_data->http_proxy_options.password);
1129 upload_data->http_proxy_options.password = NULL;
1130 }
1131
1132 upload_data->http_proxy_options.port = proxy_options->port;
1133
1134 if (mallocAndStrcpy_s((char **)(&upload_data->http_proxy_options.host_address), proxy_options->host_address) != 0)
1135 {
1136 LogError("failure in mallocAndStrcpy_s - upload_data->http_proxy_options.host_address");
1137 result = IOTHUB_CLIENT_ERROR;
1138 }
1139 else if (proxy_options->username != NULL && mallocAndStrcpy_s((char **)(&upload_data->http_proxy_options.username), proxy_options->username) != 0)
1140 {
1141 LogError("failure in mallocAndStrcpy_s - upload_data->http_proxy_options.username");
1142 result = IOTHUB_CLIENT_ERROR;
1143 }
1144 else if (proxy_options->password != NULL && mallocAndStrcpy_s((char **)(&upload_data->http_proxy_options.password), proxy_options->password) != 0)
1145 {
1146 LogError("failure in mallocAndStrcpy_s - upload_data->http_proxy_options.password");
1147 result = IOTHUB_CLIENT_ERROR;
1148 }
1149 else
1150 {
1151 result = IOTHUB_CLIENT_OK;
1152 }
1153 }
1154 }
1155 else if (strcmp(optionName, OPTION_CURL_VERBOSE) == 0)
1156 {
1157 upload_data->curl_verbosity_level = ((*(bool*)value) == 0) ? UPOADTOBLOB_CURL_VERBOSITY_OFF : UPOADTOBLOB_CURL_VERBOSITY_ON;
1158 result = IOTHUB_CLIENT_OK;
1159 }
1160 else if (strcmp(optionName, OPTION_BLOB_UPLOAD_TIMEOUT_SECS) == 0)
1161 {
1162 upload_data->blob_upload_timeout_secs = *(size_t*)value;
1163 result = IOTHUB_CLIENT_OK;
1164 }
1165 else
1166 {
1167 /*Codes_SRS_IOTHUBCLIENT_LL_02_102: [ If an unknown option is presented then IoTHubClient_LL_UploadToBlob_SetOption shall return IOTHUB_CLIENT_INVALID_ARG. ]*/
1168 result = IOTHUB_CLIENT_INVALID_ARG;
1169 }
1170 }
1171 return result;
1172}
1173
1174#endif /*DONT_USE_UPLOADTOBLOB*/
1175
1176
Note: See TracBrowser for help on using the repository browser.