IOTHUB_MESSAGE_RESULT IoTHubMessage_GetByteArray(IOTHUB_MESSAGE_HANDLE iotHubMessageHandle, const unsigned char** buffer, size_t* size) { IOTHUB_MESSAGE_RESULT result; if ( (iotHubMessageHandle == NULL) || (buffer == NULL) || (size == NULL) ) { /*Codes_SRS_IOTHUBMESSAGE_01_014: [If any of the arguments passed to IoTHubMessage_GetByteArray is NULL IoTHubMessage_GetByteArray shall return IOTHUBMESSAGE_INVALID_ARG.] */ LogError("invalid parameter (NULL) to IoTHubMessage_GetByteArray IOTHUB_MESSAGE_HANDLE iotHubMessageHandle=%p, const unsigned char** buffer=%p, size_t* size=%p\r\n", iotHubMessageHandle, buffer, size); result = IOTHUB_MESSAGE_INVALID_ARG; } else { IOTHUB_MESSAGE_HANDLE_DATA* handleData = iotHubMessageHandle; if (handleData->contentType != IOTHUBMESSAGE_BYTEARRAY) { /*Codes_SRS_IOTHUBMESSAGE_02_021: [If iotHubMessageHandle is not a iothubmessage containing BYTEARRAY data, then IoTHubMessage_GetData shall write in *buffer NULL and shall set *size to 0.] */ result = IOTHUB_MESSAGE_INVALID_ARG; LogError("invalid type of message %s\r\n", ENUM_TO_STRING(IOTHUBMESSAGE_CONTENT_TYPE, handleData->contentType)); } else { /*Codes_SRS_IOTHUBMESSAGE_01_011: [The pointer shall be obtained by using BUFFER_u_char and it shall be copied in the buffer argument.]*/ *buffer = BUFFER_u_char(handleData->value.byteArray); /*Codes_SRS_IOTHUBMESSAGE_01_012: [The size of the associated data shall be obtained by using BUFFER_length and it shall be copied to the size argument.]*/ *size = BUFFER_length(handleData->value.byteArray); result = IOTHUB_MESSAGE_OK; } } return result; }
BLEIO_SEQ_RESULT schedule_write( BLEIO_SEQ_HANDLE_DATA* handle_data, BLEIO_SEQ_INSTRUCTION* instruction, ON_INTERNAL_IO_COMPLETE on_internal_read_complete ) { BLEIO_SEQ_RESULT result; WRITE_CONTEXT* context = (WRITE_CONTEXT*)malloc(sizeof(WRITE_CONTEXT)); /*Codes_SRS_BLEIO_SEQ_13_014: [ BLEIO_Seq_Run shall return BLEIO_SEQ_ERROR if an underlying platform call fails. ]*/ if (context == NULL) { LogError("malloc failed"); result = BLEIO_SEQ_ERROR; } else { context->handle_data = handle_data; context->instruction = instruction; context->on_internal_read_complete = on_internal_read_complete; const unsigned char* buffer = BUFFER_u_char(instruction->data.buffer); size_t buffer_size = BUFFER_length(instruction->data.buffer); // add ref to the handle data object since we now will have an // outstanding I/O operation; the reason why we increment the // reference here as opposed to when we know that BLEIO_gatt_read_char_by_uuid // was successful is because the operation could potentially complete // even before we hit the if check after this call and 'on_read_complete' // might have run by then in which case it would have done a DEC_REF and // the ref counts will be out of whack INC_REF(BLEIO_SEQ_HANDLE_DATA, handle_data); int write_result = BLEIO_gatt_write_char_by_uuid( handle_data->bleio_gatt_handle, STRING_c_str(instruction->characteristic_uuid), buffer, buffer_size, on_write_complete, context ); if (write_result != 0) { /*Codes_SRS_BLEIO_SEQ_13_014: [ BLEIO_Seq_Run shall return BLEIO_SEQ_ERROR if an underlying platform call fails. ]*/ result = BLEIO_SEQ_ERROR; free(context); DEC_REF(BLEIO_SEQ_HANDLE_DATA, handle_data); LogError("BLEIO_gatt_write_char_by_uuid failed with %d.", write_result); } else { result = BLEIO_SEQ_OK; } } return result; }
/*any other code is error*/ static int buildRequestHttpHeadersHandle(HTTPAPIEX_HANDLE_DATA *handleData, BUFFER_HANDLE requestContent, HTTP_HEADERS_HANDLE originalRequestHttpHeadersHandle, bool* isOriginalRequestHttpHeadersHandle, HTTP_HEADERS_HANDLE* toBeUsedRequestHttpHeadersHandle) { int result; if (originalRequestHttpHeadersHandle != NULL) { *toBeUsedRequestHttpHeadersHandle = originalRequestHttpHeadersHandle; *isOriginalRequestHttpHeadersHandle = true; } else { /*Codes_SRS_HTTPAPIEX_02_009: [If parameter requestHttpHeadersHandle is NULL then HTTPAPIEX_ExecuteRequest shall allocate a temporary internal instance of HTTPHEADERS, shall add to that instance the following headers Host:{hostname} - as it was indicated by the call to HTTPAPIEX_Create API call Content-Length:the size of the requestContent parameter, and use this instance to all the subsequent calls to HTTPAPI_ExecuteRequest as parameter httpHeadersHandle.] */ *isOriginalRequestHttpHeadersHandle = false; *toBeUsedRequestHttpHeadersHandle = HTTPHeaders_Alloc(); } if (*toBeUsedRequestHttpHeadersHandle == NULL) { result = __LINE__; LogError("unable to HTTPHeaders_Alloc\r\n"); } else { char temp[22]; (void)size_tToString(temp, 22, BUFFER_length(requestContent)); /*cannot fail, MAX_uint64 has 19 digits*/ /*Codes_SRS_HTTPAPIEX_02_011: [If parameter requestHttpHeadersHandle is not NULL then HTTPAPIEX_ExecuteRequest shall create or update the following headers of the request: Host:{hostname} Content-Length:the size of the requestContent parameter, and shall use the so constructed HTTPHEADERS object to all calls to HTTPAPI_ExecuteRequest as parameter httpHeadersHandle.] */ /*Codes_SRS_HTTPAPIEX_02_009: [If parameter requestHttpHeadersHandle is NULL then HTTPAPIEX_ExecuteRequest shall allocate a temporary internal instance of HTTPHEADERS, shall add to that instance the following headers Host:{hostname} - as it was indicated by the call to HTTPAPIEX_Create API call Content-Length:the size of the requestContent parameter, and use this instance to all the subsequent calls to HTTPAPI_ExecuteRequest as parameter httpHeadersHandle.] */ if (!( (HTTPHeaders_ReplaceHeaderNameValuePair(*toBeUsedRequestHttpHeadersHandle, "Host", STRING_c_str(handleData->hostName)) == HTTP_HEADERS_OK) && (HTTPHeaders_ReplaceHeaderNameValuePair(*toBeUsedRequestHttpHeadersHandle, "Content-Length", temp) == HTTP_HEADERS_OK) )) { if (! *isOriginalRequestHttpHeadersHandle) { HTTPHeaders_Free(*toBeUsedRequestHttpHeadersHandle); } *toBeUsedRequestHttpHeadersHandle = NULL; result = __LINE__; } else { result = 0; } } return result; }
static void setup_dev_auth_emulator_retrieve_data_mocks(void) { STRICT_EXPECTED_CALL(BUFFER_length(IGNORED_PTR_ARG)) .IgnoreArgument_handle() .SetReturn(TEST_DATA_LEN); STRICT_EXPECTED_CALL(gballoc_malloc(IGNORED_NUM_ARG)) .IgnoreArgument_size(); STRICT_EXPECTED_CALL(BUFFER_u_char(IGNORED_PTR_ARG)) .IgnoreArgument_handle() .SetReturn(TEST_DATA); }
/*this creates a new constbuffer from an existing BUFFER_HANDLE*/ CONSTBUFFER_HANDLE CONSTBUFFER_CreateFromBuffer(BUFFER_HANDLE buffer) { CONSTBUFFER_HANDLE_DATA* result; /*Codes_SRS_CONSTBUFFER_02_006: [If buffer is NULL then CONSTBUFFER_CreateFromBuffer shall fail and return NULL.]*/ if (buffer == NULL) { LogError("invalid arg passed to CONSTBUFFER_CreateFromBuffer"); result = NULL; } else { result = CONSTBUFFER_Create_Internal(BUFFER_u_char(buffer), BUFFER_length(buffer)); } return result; }
static void parseResponseJsonExpectedCalls() { STRICT_EXPECTED_CALL(BUFFER_u_char(IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(BUFFER_length(IGNORED_PTR_ARG)).CallCannotFail(); //cannot fail (returns length 0) STRICT_EXPECTED_CALL(STRING_from_byte_array(IGNORED_PTR_ARG, IGNORED_NUM_ARG)); STRICT_EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(json_parse_string(IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(json_value_get_object(IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(json_object_get_value(IGNORED_PTR_ARG, IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(json_object_get_value(IGNORED_PTR_ARG, IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(json_serialize_to_string(IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(json_value_get_number(IGNORED_PTR_ARG)).CallCannotFail(); //cannot fail (returns -1, which isn't strictly failure) STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG)); //cannot fail STRICT_EXPECTED_CALL(json_value_free(IGNORED_PTR_ARG)); //cannot fail }
/*this creates a new constbuffer from an existing BUFFER_HANDLE*/ CONSTBUFFER_HANDLE CONSTBUFFER_CreateFromBuffer(BUFFER_HANDLE buffer) { CONSTBUFFER_HANDLE_DATA* result; /*Codes_SRS_CONSTBUFFER_02_006: [If buffer is NULL then CONSTBUFFER_CreateFromBuffer shall fail and return NULL.]*/ if (buffer == NULL) { LogError("invalid arg passed to CONSTBUFFER_CreateFromBuffer"); result = NULL; } else { size_t length = BUFFER_length(buffer); unsigned char* rawBuffer = BUFFER_u_char(buffer); result = (CONSTBUFFER_HANDLE_DATA*)CONSTBUFFER_Create_Internal(rawBuffer, length); } return (CONSTBUFFER_HANDLE)result; }
static int parseDeviceJson(IOTHUB_ACCOUNT_INFO* accountInfo, BUFFER_HANDLE jsonBuffer) { int result = __LINE__; const char* deviceJson = (const char*)BUFFER_u_char(jsonBuffer); size_t jsonLen = BUFFER_length(jsonBuffer); if (deviceJson != NULL && jsonLen > PRIMARY_KEY_FIELD_LEN) { // Start to the end of the json because the primary key is at the end const char* iterator = deviceJson + jsonLen - PRIMARY_KEY_FIELD_LEN; while (iterator >= deviceJson) { // Once we find the primary key field then copy it into the buffer if (memcmp(iterator, PRIMARY_KEY_FIELD, PRIMARY_KEY_FIELD_LEN) == 0) { // Move to the beginning of the primary key value iterator += PRIMARY_KEY_FIELD_LEN; // Store where we are const char* devKeyMarker = iterator; // Now go till we find the quote while (*devKeyMarker != '\"' && devKeyMarker != (deviceJson + jsonLen - PRIMARY_KEY_FIELD_LEN)) { devKeyMarker++; } size_t keyLen = devKeyMarker - iterator; // Allocate key accountInfo->deviceKey = (char*)malloc(keyLen + 1); if (accountInfo->deviceKey == NULL) { LogError("Failure allocating device key.\r\n"); result = __LINE__; } else { // Copy the data to the key memcpy(accountInfo->deviceKey, iterator, keyLen); accountInfo->deviceKey[keyLen] = '\0'; result = 0; } break; } iterator--; } } return result; }
static IOTHUB_DEVICE_METHOD_RESULT parseResponseJson(BUFFER_HANDLE responseJson, int* responseStatus, unsigned char** responsePayload, size_t* responsePayloadSize) { IOTHUB_DEVICE_METHOD_RESULT result; JSON_Value* root_value; JSON_Object* json_object; JSON_Value* statusJsonValue; JSON_Value* payloadJsonValue; char* payload; STRING_HANDLE jsonStringHandle; const char* jsonStr; unsigned char* bufferStr; if ((bufferStr = BUFFER_u_char(responseJson)) == NULL) { LogError("BUFFER_u_char failed"); result = IOTHUB_DEVICE_METHOD_ERROR; } else if ((jsonStringHandle = STRING_from_byte_array(bufferStr, BUFFER_length(responseJson))) == NULL) { LogError("STRING_construct_n failed"); result = IOTHUB_DEVICE_METHOD_ERROR; } else if ((jsonStr = STRING_c_str(jsonStringHandle)) == NULL) { LogError("STRING_c_str failed"); STRING_delete(jsonStringHandle); result = IOTHUB_DEVICE_METHOD_ERROR; } else if ((root_value = json_parse_string(jsonStr)) == NULL) { LogError("json_parse_string failed"); STRING_delete(jsonStringHandle); result = IOTHUB_DEVICE_METHOD_ERROR; } else if ((json_object = json_value_get_object(root_value)) == NULL) { LogError("json_value_get_object failed"); STRING_delete(jsonStringHandle); json_value_free(root_value); result = IOTHUB_DEVICE_METHOD_ERROR; } else if ((statusJsonValue = json_object_get_value(json_object, "status")) == NULL) { LogError("json_object_get_value failed for status"); STRING_delete(jsonStringHandle); json_value_free(root_value); result = IOTHUB_DEVICE_METHOD_ERROR; } else if ((payloadJsonValue = json_object_get_value(json_object, "payload")) == NULL) { LogError("json_object_get_value failed for payload"); STRING_delete(jsonStringHandle); json_value_free(root_value); result = IOTHUB_DEVICE_METHOD_ERROR; } else if ((payload = json_serialize_to_string(payloadJsonValue)) == NULL) { LogError("json_serialize_to_string failed for payload"); STRING_delete(jsonStringHandle); json_value_free(root_value); result = IOTHUB_DEVICE_METHOD_ERROR; } else { *responseStatus = (int)json_value_get_number(statusJsonValue); *responsePayload = (unsigned char *)payload; *responsePayloadSize = strlen(payload); STRING_delete(jsonStringHandle); json_value_free(root_value); result = IOTHUB_DEVICE_METHOD_OK; } return result; }
static void setup_retrieve_persisted_key_mocks(bool json_file_found) { if (json_file_found) { STRICT_EXPECTED_CALL(json_parse_file(IGNORED_PTR_ARG)) .IgnoreArgument_string(); STRICT_EXPECTED_CALL(json_value_get_object(IGNORED_PTR_ARG)) .IgnoreArgument_value(); STRICT_EXPECTED_CALL(json_object_get_value(IGNORED_PTR_ARG, IGNORED_PTR_ARG)) .IgnoreArgument_name() .IgnoreArgument_object(); STRICT_EXPECTED_CALL(json_object_get_value(IGNORED_PTR_ARG, IGNORED_PTR_ARG)) .IgnoreArgument_name() .IgnoreArgument_object(); STRICT_EXPECTED_CALL(json_object_get_value(IGNORED_PTR_ARG, IGNORED_PTR_ARG)) .IgnoreArgument_name() .IgnoreArgument_object(); STRICT_EXPECTED_CALL(json_object_get_value(IGNORED_PTR_ARG, IGNORED_PTR_ARG)) .IgnoreArgument_name() .IgnoreArgument_object(); STRICT_EXPECTED_CALL(json_value_get_string(IGNORED_PTR_ARG)) .IgnoreArgument_value(); STRICT_EXPECTED_CALL(Azure_Base64_Decode(IGNORED_PTR_ARG)) .IgnoreArgument_source(); STRICT_EXPECTED_CALL(json_value_get_string(IGNORED_PTR_ARG)) .IgnoreArgument_value(); STRICT_EXPECTED_CALL(Azure_Base64_Decode(IGNORED_PTR_ARG)) .IgnoreArgument_source(); STRICT_EXPECTED_CALL(json_value_get_string(IGNORED_PTR_ARG)) .IgnoreArgument_value(); STRICT_EXPECTED_CALL(mallocAndStrcpy_s(IGNORED_PTR_ARG, IGNORED_PTR_ARG)) .IgnoreArgument_destination() .IgnoreArgument_source(); STRICT_EXPECTED_CALL(json_value_get_string(IGNORED_PTR_ARG)) .IgnoreArgument_value(); STRICT_EXPECTED_CALL(Azure_Base64_Decode(IGNORED_PTR_ARG)) .IgnoreArgument_source(); STRICT_EXPECTED_CALL(BUFFER_u_char(IGNORED_PTR_ARG)) .IgnoreArgument_handle(); STRICT_EXPECTED_CALL(BUFFER_length(IGNORED_PTR_ARG)) .IgnoreArgument_handle(); STRICT_EXPECTED_CALL(BIO_new_mem_buf(IGNORED_PTR_ARG, IGNORED_NUM_ARG)) .IgnoreArgument_buf() .IgnoreArgument_len(); STRICT_EXPECTED_CALL(PEM_read_bio_RSA_PUBKEY(IGNORED_PTR_ARG, IGNORED_NUM_ARG, IGNORED_PTR_ARG, IGNORED_NUM_ARG)) .IgnoreAllArguments(); STRICT_EXPECTED_CALL(BUFFER_u_char(IGNORED_PTR_ARG)) .IgnoreArgument_handle(); STRICT_EXPECTED_CALL(BUFFER_length(IGNORED_PTR_ARG)) .IgnoreArgument_handle(); STRICT_EXPECTED_CALL(BIO_new_mem_buf(IGNORED_PTR_ARG, IGNORED_NUM_ARG)) .IgnoreArgument_buf() .IgnoreArgument_len(); STRICT_EXPECTED_CALL(PEM_read_bio_RSAPrivateKey(IGNORED_PTR_ARG, IGNORED_NUM_ARG, IGNORED_PTR_ARG, IGNORED_NUM_ARG)) .IgnoreAllArguments(); STRICT_EXPECTED_CALL(BUFFER_delete(IGNORED_PTR_ARG)) .IgnoreArgument_handle(); STRICT_EXPECTED_CALL(BUFFER_delete(IGNORED_PTR_ARG)) .IgnoreArgument_handle(); } else { STRICT_EXPECTED_CALL(json_parse_file(IGNORED_PTR_ARG)) .IgnoreArgument_string() .SetReturn(NULL); } }
HTTPAPIEX_RESULT HTTPAPIEX_ExecuteRequest(HTTPAPIEX_HANDLE handle, HTTPAPI_REQUEST_TYPE requestType, const char* relativePath, HTTP_HEADERS_HANDLE requestHttpHeadersHandle, BUFFER_HANDLE requestContent, unsigned int* statusCode, HTTP_HEADERS_HANDLE responseHttpHeadersHandle, BUFFER_HANDLE responseContent) { HTTPAPIEX_RESULT result; /*Codes_SRS_HTTPAPIEX_02_006: [If parameter handle is NULL then HTTPAPIEX_ExecuteRequest shall fail and return HTTPAPIEX_INVALID_ARG.]*/ if (handle == NULL) { result = HTTPAPIEX_INVALID_ARG; LOG_HTTAPIEX_ERROR(); } else { /*Codes_SRS_HTTPAPIEX_02_007: [If parameter requestType does not indicate a valid request, HTTPAPIEX_ExecuteRequest shall fail and return HTTPAPIEX_INVALID_ARG.] */ if (requestType >= COUNT_ARG(HTTPAPI_REQUEST_TYPE_VALUES)) { result = HTTPAPIEX_INVALID_ARG; LOG_HTTAPIEX_ERROR(); } else { HTTPAPIEX_HANDLE_DATA *handleData = (HTTPAPIEX_HANDLE_DATA *)handle; /*call to buildAll*/ const char* toBeUsedRelativePath; HTTP_HEADERS_HANDLE toBeUsedRequestHttpHeadersHandle; bool isOriginalRequestHttpHeadersHandle; BUFFER_HANDLE toBeUsedRequestContent; bool isOriginalRequestContent; unsigned int* toBeUsedStatusCode; HTTP_HEADERS_HANDLE toBeUsedResponseHttpHeadersHandle; bool isOriginalResponseHttpHeadersHandle; BUFFER_HANDLE toBeUsedResponseContent; bool isOriginalResponseContent; if (buildAllRequests(handleData, requestType, relativePath, requestHttpHeadersHandle, requestContent, statusCode, responseHttpHeadersHandle, responseContent, &toBeUsedRelativePath, &toBeUsedRequestHttpHeadersHandle, &isOriginalRequestHttpHeadersHandle, &toBeUsedRequestContent, &isOriginalRequestContent, &toBeUsedStatusCode, &toBeUsedResponseHttpHeadersHandle, &isOriginalResponseHttpHeadersHandle, &toBeUsedResponseContent, &isOriginalResponseContent) != 0) { result = HTTPAPIEX_ERROR; LOG_HTTAPIEX_ERROR(); } else { /*Codes_SRS_HTTPAPIEX_02_023: [HTTPAPIEX_ExecuteRequest shall try to execute the HTTP call by ensuring the following API call sequence is respected:]*/ /*Codes_SRS_HTTPAPIEX_02_024: [If any point in the sequence fails, HTTPAPIEX_ExecuteRequest shall attempt to recover by going back to the previous step and retrying that step.]*/ /*Codes_SRS_HTTPAPIEX_02_025: [If the first step fails, then the sequence fails.]*/ /*Codes_SRS_HTTPAPIEX_02_026: [A step shall be retried at most once.]*/ /*Codes_SRS_HTTPAPIEX_02_027: [If a step has been retried then all subsequent steps shall be retried too.]*/ bool st[3] = { false, false, false }; /*the three levels of possible failure in resilient send: HTTAPI_Init, HTTPAPI_CreateConnection, HTTPAPI_ExecuteRequest*/ if (handleData->k == -1) { handleData->k = 0; } do { bool goOn; if (handleData->k > 2) { /* error */ break; } if (st[handleData->k] == true) /*already been tried*/ { goOn = false; } else { switch (handleData->k) { case 0: { if (HTTPAPI_Init() != HTTPAPI_OK) { goOn = false; } else { goOn = true; } break; } case 1: { if ((handleData->httpHandle = HTTPAPI_CreateConnection(STRING_c_str(handleData->hostName))) == NULL) { goOn = false; } else { size_t i; size_t vectorSize = VECTOR_size(handleData->savedOptions); for (i = 0; i < vectorSize; i++) { /*Codes_SRS_HTTPAPIEX_02_035: [HTTPAPIEX_ExecuteRequest shall pass all the saved options (see HTTPAPIEX_SetOption) to the newly create HTTPAPI_HANDLE in step 2 by calling HTTPAPI_SetOption.]*/ /*Codes_SRS_HTTPAPIEX_02_036: [If setting the option fails, then the failure shall be ignored.] */ HTTPAPIEX_SAVED_OPTION* option = VECTOR_element(handleData->savedOptions, i); if (HTTPAPI_SetOption(handleData->httpHandle, option->optionName, option->value) != HTTPAPI_OK) { LogError("HTTPAPI_SetOption failed when called for option %s\r\n", option->optionName); } } goOn = true; } break; } case 2: { if (HTTPAPI_ExecuteRequest(handleData->httpHandle, requestType, toBeUsedRelativePath, toBeUsedRequestHttpHeadersHandle, BUFFER_u_char(toBeUsedRequestContent), BUFFER_length(toBeUsedRequestContent), toBeUsedStatusCode, toBeUsedResponseHttpHeadersHandle, toBeUsedResponseContent) != HTTPAPI_OK) { goOn = false; } else { goOn = true; } break; } default: { /*serious error*/ goOn = false; break; } } } if (goOn) { if (handleData->k == 2) { /*Codes_SRS_HTTPAPIEX_02_028: [HTTPAPIEX_ExecuteRequest shall return HTTPAPIEX_OK when a call to HTTPAPI_ExecuteRequest has been completed successfully.]*/ result = HTTPAPIEX_OK; goto out; } else { st[handleData->k] = true; handleData->k++; st[handleData->k] = false; } } else { st[handleData->k] = false; handleData->k--; switch (handleData->k) { case 0: { HTTPAPI_Deinit(); break; } case 1: { HTTPAPI_CloseConnection(handleData->httpHandle); handleData->httpHandle = NULL; break; } case 2: { break; } default: { break; } } } } while (handleData->k >= 0); /*Codes_SRS_HTTPAPIEX_02_029: [Otherwise, HTTAPIEX_ExecuteRequest shall return HTTPAPIEX_RECOVERYFAILED.] */ result = HTTPAPIEX_RECOVERYFAILED; LogError("unable to recover sending to a working state\r\n"); out:; /*in all cases, unbuild the temporaries*/ if (isOriginalRequestContent == false) { BUFFER_delete(toBeUsedRequestContent); } if (isOriginalRequestHttpHeadersHandle == false) { HTTPHeaders_Free(toBeUsedRequestHttpHeadersHandle); } if (isOriginalResponseContent == false) { BUFFER_delete(toBeUsedResponseContent); } if (isOriginalResponseHttpHeadersHandle == false) { HTTPHeaders_Free(toBeUsedResponseHttpHeadersHandle); } } } } return result; }
static int sign_sas_data(PROV_AUTH_INFO* auth_info, const char* payload, unsigned char** output, size_t* len) { int result; size_t payload_len = strlen(payload); if (auth_info->sec_type == PROV_AUTH_TYPE_TPM) { if (auth_info->hsm_client_sign_data(auth_info->hsm_client_handle, (const unsigned char*)payload, strlen(payload), output, len) != 0) { LogError("Failed signing data"); result = MU_FAILURE; } else { result = 0; } } else { char* symmetrical_key = auth_info->hsm_client_get_symm_key(auth_info->hsm_client_handle); if (symmetrical_key == NULL) { LogError("Failed getting asymmetrical key"); result = MU_FAILURE; } else { BUFFER_HANDLE decoded_key; BUFFER_HANDLE output_hash; if ((decoded_key = Azure_Base64_Decode(symmetrical_key)) == NULL) { LogError("Failed decoding symmetrical key"); result = MU_FAILURE; } else if ((output_hash = BUFFER_new()) == NULL) { LogError("Failed allocating output hash buffer"); BUFFER_delete(decoded_key); result = MU_FAILURE; } else { size_t decoded_key_len = BUFFER_length(decoded_key); const unsigned char* decoded_key_bytes = BUFFER_u_char(decoded_key); if (HMACSHA256_ComputeHash(decoded_key_bytes, decoded_key_len, (const unsigned char*)payload, payload_len, output_hash) != HMACSHA256_OK) { LogError("Failed computing HMAC Hash"); result = MU_FAILURE; } else { *len = BUFFER_length(output_hash); if ((*output = malloc(*len)) == NULL) { LogError("Failed allocating output buffer"); result = MU_FAILURE; } else { const unsigned char* output_data = BUFFER_u_char(output_hash); memcpy(*output, output_data, *len); result = 0; } } BUFFER_delete(decoded_key); BUFFER_delete(output_hash); } } free(symmetrical_key); } return result; }
STRING_HANDLE SASToken_Create(STRING_HANDLE key, STRING_HANDLE scope, STRING_HANDLE keyName, size_t expiry) { STRING_HANDLE result = NULL; char tokenExpirationTime[32] = { 0 }; /*Codes_SRS_SASTOKEN_06_001: [If key is NULL then SASToken_Create shall return NULL.]*/ /*Codes_SRS_SASTOKEN_06_003: [If scope is NULL then SASToken_Create shall return NULL.]*/ /*Codes_SRS_SASTOKEN_06_007: [If keyName is NULL then SASToken_Create shall return NULL.]*/ if ((key == NULL) || (scope == NULL) || (keyName == NULL)) { LogError("Invalid Parameter to SASToken_Create. handle key: %p, handle scope: %p, handle keyName: %p\r\n", key, scope, keyName); } else { BUFFER_HANDLE decodedKey; /*Codes_SRS_SASTOKEN_06_029: [The key parameter is decoded from base64.]*/ if ((decodedKey = Base64_Decoder(STRING_c_str(key))) == NULL) { /*Codes_SRS_SASTOKEN_06_030: [If there is an error in the decoding then SASToken_Create shall return NULL.]*/ LogError("Unable to decode the key for generating the SAS.\r\n"); } else { /*Codes_SRS_SASTOKEN_06_026: [If the conversion to string form fails for any reason then SASToken_Create shall return NULL.]*/ if (size_tToString(tokenExpirationTime, sizeof(tokenExpirationTime), expiry) != 0) { LogError("For some reason converting seconds to a string failed. No SAS can be generated.\r\n"); } else { STRING_HANDLE toBeHashed = NULL; BUFFER_HANDLE hash = NULL; if (((hash = BUFFER_new()) == NULL) || ((toBeHashed = STRING_new()) == NULL) || ((result = STRING_new()) == NULL)) { LogError("Unable to allocate memory to prepare SAS token.\r\n") } else { /*Codes_SRS_SASTOKEN_06_009: [The scope is the basis for creating a STRING_HANDLE.]*/ /*Codes_SRS_SASTOKEN_06_010: [A "\n" is appended to that string.]*/ /*Codes_SRS_SASTOKEN_06_011: [tokenExpirationTime is appended to that string.]*/ if ((STRING_concat_with_STRING(toBeHashed, scope) != 0) || (STRING_concat(toBeHashed, "\n") != 0) || (STRING_concat(toBeHashed, tokenExpirationTime) != 0)) { LogError("Unable to build the input to the HMAC to prepare SAS token.\r\n"); STRING_delete(result); result = NULL; } else { STRING_HANDLE base64Signature = NULL; STRING_HANDLE urlEncodedSignature = NULL; /*Codes_SRS_SASTOKEN_06_013: [If an error is returned from the HMAC256 function then NULL is returned from SASToken_Create.]*/ /*Codes_SRS_SASTOKEN_06_012: [An HMAC256 hash is calculated using the decodedKey, over toBeHashed.]*/ /*Codes_SRS_SASTOKEN_06_014: [If there are any errors from the following operations then NULL shall be returned.]*/ /*Codes_SRS_SASTOKEN_06_015: [The hash is base 64 encoded.]*/ /*Codes_SRS_SASTOKEN_06_028: [base64Signature shall be url encoded.]*/ /*Codes_SRS_SASTOKEN_06_016: [The string "SharedAccessSignature sr=" is the first part of the result of SASToken_Create.]*/ /*Codes_SRS_SASTOKEN_06_017: [The scope parameter is appended to result.]*/ /*Codes_SRS_SASTOKEN_06_018: [The string "&sig=" is appended to result.]*/ /*Codes_SRS_SASTOKEN_06_019: [The string urlEncodedSignature shall be appended to result.]*/ /*Codes_SRS_SASTOKEN_06_020: [The string "&se=" shall be appended to result.]*/ /*Codes_SRS_SASTOKEN_06_021: [tokenExpirationTime is appended to result.]*/ /*Codes_SRS_SASTOKEN_06_022: [The string "&skn=" is appended to result.]*/ /*Codes_SRS_SASTOKEN_06_023: [The argument keyName is appended to result.]*/ if ((HMACSHA256_ComputeHash(BUFFER_u_char(decodedKey), BUFFER_length(decodedKey), (const unsigned char*)STRING_c_str(toBeHashed), STRING_length(toBeHashed), hash) != HMACSHA256_OK) || ((base64Signature = Base64_Encode(hash)) == NULL) || ((urlEncodedSignature = URL_Encode(base64Signature)) == NULL) || (STRING_copy(result, "SharedAccessSignature sr=") != 0) || (STRING_concat_with_STRING(result, scope) != 0) || (STRING_concat(result, "&sig=") != 0) || (STRING_concat_with_STRING(result, urlEncodedSignature) != 0) || (STRING_concat(result, "&se=") != 0) || (STRING_concat(result, tokenExpirationTime) != 0) || (STRING_concat(result, "&skn=") != 0) || (STRING_concat_with_STRING(result, keyName) != 0)) { LogError("Unable to build the SAS token.\r\n"); STRING_delete(result); result = NULL; } else { /* everything OK */ } STRING_delete(base64Signature); STRING_delete(urlEncodedSignature); } } STRING_delete(toBeHashed); BUFFER_delete(hash); } BUFFER_delete(decodedKey); } } return result; }
HTTPAPI_RESULT HTTPAPI_ExecuteRequest(HTTP_HANDLE handle, HTTPAPI_REQUEST_TYPE requestType, const char* relativePath, HTTP_HEADERS_HANDLE httpHeadersHandle, const unsigned char* content, size_t contentLength, unsigned int* statusCode, HTTP_HEADERS_HANDLE responseHeadersHandle, BUFFER_HANDLE responseContent) { HTTPAPI_RESULT result; if (g_HTTPAPIState != HTTPAPI_INITIALIZED) { LogError("g_HTTPAPIState not HTTPAPI_INITIALIZED\r\n"); result = HTTPAPI_NOT_INIT; } else { HTTP_HANDLE_DATA* handleData = (HTTP_HANDLE_DATA*)handle; if ((handleData == NULL) || (relativePath == NULL) || (httpHeadersHandle == NULL)) { result = HTTPAPI_INVALID_ARG; LogError("NULL parameter detected (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); } else { wchar_t* requestTypeString = NULL; switch (requestType) { default: break; case HTTPAPI_REQUEST_GET: requestTypeString = L"GET"; break; case HTTPAPI_REQUEST_POST: requestTypeString = L"POST"; break; case HTTPAPI_REQUEST_PUT: requestTypeString = L"PUT"; break; case HTTPAPI_REQUEST_DELETE: requestTypeString = L"DELETE"; break; case HTTPAPI_REQUEST_PATCH: requestTypeString = L"PATCH"; break; } if (requestTypeString == NULL) { result = HTTPAPI_INVALID_ARG; LogError("requestTypeString was NULL (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); } else { const char* headers2; headers2 = ConstructHeadersString(httpHeadersHandle); if (headers2 != NULL) { size_t requiredCharactersForRelativePath = MultiByteToWideChar(CP_ACP, 0, relativePath, -1, NULL, 0); wchar_t* relativePathTemp = malloc((requiredCharactersForRelativePath+1) * sizeof(wchar_t)); result = HTTPAPI_OK; /*legacy code*/ if (relativePathTemp == NULL) { result = HTTPAPI_ALLOC_FAILED; LogError("malloc failed (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); } else { if (MultiByteToWideChar(CP_ACP, 0, relativePath, -1, relativePathTemp, requiredCharactersForRelativePath) == 0) { result = HTTPAPI_STRING_PROCESSING_ERROR; LogError("MultiByteToWideChar was 0. (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); } else { size_t requiredCharactersForHeaders = MultiByteToWideChar(CP_ACP, 0, headers2, -1, NULL, 0); wchar_t* headersTemp = malloc((requiredCharactersForHeaders +1) * sizeof(wchar_t) ); if (headersTemp == NULL) { result = HTTPAPI_STRING_PROCESSING_ERROR; LogError("MultiByteToWideChar was 0. (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); } else { if (MultiByteToWideChar(CP_ACP, 0, headers2, -1, headersTemp, requiredCharactersForHeaders) == 0) { result = HTTPAPI_STRING_PROCESSING_ERROR; LogError("MultiByteToWideChar was 0(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); } else { HINTERNET requestHandle = WinHttpOpenRequest( handleData->ConnectionHandle, requestTypeString, relativePathTemp, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE); if (requestHandle == NULL) { result = HTTPAPI_OPEN_REQUEST_FAILED; LogErrorWinHTTPWithGetLastErrorAsString("WinHttpOpenRequest failed (result = %s).\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); } else { if (WinHttpSetTimeouts(requestHandle, 0, /*_In_ int dwResolveTimeout - The initial value is zero, meaning no time-out (infinite). */ 60000, /*_In_ int dwConnectTimeout, - The initial value is 60,000 (60 seconds).*/ handleData->timeout, /*_In_ int dwSendTimeout, - The initial value is 30,000 (30 seconds).*/ handleData->timeout /* int dwReceiveTimeout The initial value is 30,000 (30 seconds).*/ ) == FALSE) { result = HTTPAPI_SET_TIMEOUTS_FAILED; LogErrorWinHTTPWithGetLastErrorAsString("WinHttpOpenRequest failed (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); } else { DWORD dwSecurityFlags = 0; if (!WinHttpSetOption( requestHandle, WINHTTP_OPTION_SECURITY_FLAGS, &dwSecurityFlags, sizeof(dwSecurityFlags))) { result = HTTPAPI_SET_OPTION_FAILED; LogErrorWinHTTPWithGetLastErrorAsString("WinHttpSetOption failed (result = %s).\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); } else { if (!WinHttpSendRequest( requestHandle, headersTemp, (DWORD)-1L, /*An unsigned long integer value that contains the length, in characters, of the additional headers. If this parameter is -1L ... */ (void*)content, (DWORD)contentLength, (DWORD)contentLength, 0)) { result = HTTPAPI_SEND_REQUEST_FAILED; LogErrorWinHTTPWithGetLastErrorAsString("WinHttpSendRequest: (result = %s).\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); } else { if (!WinHttpReceiveResponse( requestHandle, 0)) { result = HTTPAPI_RECEIVE_RESPONSE_FAILED; LogErrorWinHTTPWithGetLastErrorAsString("WinHttpReceiveResponse: (result = %s).\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); } else { DWORD dwStatusCode = 0; DWORD dwBufferLength = sizeof(DWORD); DWORD responseBytesAvailable; if (!WinHttpQueryHeaders( requestHandle, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &dwStatusCode, &dwBufferLength, WINHTTP_NO_HEADER_INDEX)) { result = HTTPAPI_QUERY_HEADERS_FAILED; LogErrorWinHTTPWithGetLastErrorAsString("WinHttpQueryHeaders failed (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); } else { BUFFER_HANDLE useToReadAllResponse = (responseContent != NULL) ? responseContent : BUFFER_new(); if (statusCode != NULL) { *statusCode = dwStatusCode; } if (useToReadAllResponse == NULL) { result = HTTPAPI_ERROR; LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); } else { int goOnAndReadEverything = 1; do { /*from MSDN: If no data is available and the end of the file has not been reached, one of two things happens. If the session is synchronous, the request waits until data becomes available.*/ if (!WinHttpQueryDataAvailable(requestHandle, &responseBytesAvailable)) { result = HTTPAPI_QUERY_DATA_AVAILABLE_FAILED; LogErrorWinHTTPWithGetLastErrorAsString("WinHttpQueryDataAvailable failed (result = %s).\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); goOnAndReadEverything = 0; } else if (responseBytesAvailable == 0) { /*end of the stream, go out*/ if (dwStatusCode >= HTTP_STATUS_AMBIGUOUS) { LogError("HTTP status code was: %d \r\n", (int)dwStatusCode); LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); } result = HTTPAPI_OK; goOnAndReadEverything = 0; } else { if (BUFFER_enlarge(useToReadAllResponse, responseBytesAvailable) != 0) { result = HTTPAPI_ERROR; LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); goOnAndReadEverything = 0; } else { /*Add the read bytes to the response buffer*/ size_t bufferSize; const unsigned char* bufferContent; if (BUFFER_content(useToReadAllResponse, &bufferContent) != 0) { result = HTTPAPI_ERROR; LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); goOnAndReadEverything = 0; } else if (BUFFER_size(useToReadAllResponse, &bufferSize) != 0) { result = HTTPAPI_ERROR; LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); goOnAndReadEverything = 0; } else { DWORD bytesReceived; if (!WinHttpReadData(requestHandle, (LPVOID)(bufferContent + bufferSize - responseBytesAvailable), responseBytesAvailable, &bytesReceived)) { result = HTTPAPI_READ_DATA_FAILED; LogErrorWinHTTPWithGetLastErrorAsString("WinHttpReadData failed (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); goOnAndReadEverything = 0; } else { /*if for some reason bytesReceived is zero If you are using WinHttpReadData synchronously, and the return value is TRUE and the number of bytes read is zero, the transfer has been completed and there are no more bytes to read on the handle.*/ if (bytesReceived == 0) { /*end of everything, but this looks like an error still, or a non-conformance between WinHttpQueryDataAvailable and WinHttpReadData*/ result = HTTPAPI_READ_DATA_FAILED; LogError("bytesReceived was unexpectedly zero (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); goOnAndReadEverything = 0; } else { /*all is fine, keep going*/ } } } } } } while (goOnAndReadEverything != 0); if (responseContent != NULL) { if (BUFFER_u_char(responseContent) != NULL) { LogInfo("Buffer Content:\r\n %.*s\r\n", BUFFER_length(responseContent), BUFFER_u_char(responseContent)); } } else if (useToReadAllResponse != NULL) { if (BUFFER_u_char(useToReadAllResponse) != NULL) { LogInfo("Buffer Content:\r\n %.*s\r\n", BUFFER_length(useToReadAllResponse), BUFFER_u_char(useToReadAllResponse)); } BUFFER_delete(useToReadAllResponse); } } } if (result == HTTPAPI_OK && responseHeadersHandle != NULL) { wchar_t* responseHeadersTemp; DWORD responseHeadersTempLength = sizeof(responseHeadersTemp); (void)WinHttpQueryHeaders( requestHandle, WINHTTP_QUERY_RAW_HEADERS_CRLF, WINHTTP_HEADER_NAME_BY_INDEX, WINHTTP_NO_OUTPUT_BUFFER, &responseHeadersTempLength, WINHTTP_NO_HEADER_INDEX); responseHeadersTemp = (wchar_t*)malloc(responseHeadersTempLength + 2); if (responseHeadersTemp == NULL) { result = HTTPAPI_ALLOC_FAILED; LogError("malloc failed: (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); } else { if (WinHttpQueryHeaders( requestHandle, WINHTTP_QUERY_RAW_HEADERS_CRLF, WINHTTP_HEADER_NAME_BY_INDEX, responseHeadersTemp, &responseHeadersTempLength, WINHTTP_NO_HEADER_INDEX)) { wchar_t *next_token; wchar_t* token = wcstok_s(responseHeadersTemp, L"\r\n", &next_token); while ((token != NULL) && (token[0] != L'\0')) { char* tokenTemp; size_t tokenTemp_size; tokenTemp_size = WideCharToMultiByte(CP_ACP, 0, token, -1, NULL, 0, NULL, NULL); if (tokenTemp_size == 0) { LogError("WideCharToMultiByte failed\r\n"); } else { tokenTemp = malloc(sizeof(char)*tokenTemp_size); if (tokenTemp == NULL) { LogError("malloc failed\r\n"); } else { if (WideCharToMultiByte(CP_ACP, 0, token, -1, tokenTemp, tokenTemp_size, NULL, NULL) > 0) { /*breaking the token in 2 parts: everything before the first ":" and everything after the first ":"*/ /* if there is no such character, then skip it*/ /*if there is a : then replace is by a '\0' and so it breaks the original string in name and value*/ char* whereIsColon = strchr(tokenTemp, ':'); if (whereIsColon != NULL) { *whereIsColon = '\0'; if (HTTPHeaders_AddHeaderNameValuePair(responseHeadersHandle, tokenTemp, whereIsColon + 1) != HTTP_HEADERS_OK) { LogError("HTTPHeaders_AddHeaderNameValuePair failed\r\n"); result = HTTPAPI_HTTP_HEADERS_FAILED; break; } } } else { LogError("WideCharToMultiByte failed\r\n"); } free(tokenTemp); } } token = wcstok_s(NULL, L"\r\n", &next_token); } } else { LogError("WinHttpQueryHeaders failed\r\n"); } free(responseHeadersTemp); } } } } } } (void)WinHttpCloseHandle(requestHandle); } } free(headersTemp); } } free(relativePathTemp); } free((void*)headers2); } else { result = HTTPAPI_ALLOC_FAILED; /*likely*/ LogError("ConstructHeadersString failed\r\n"); } } } } return result; }