Azure IoT common library

Dependents:   STM32F746_iothub_client_sample_mqtt f767zi_mqtt iothub_client_sample_amqp iothub_client_sample_http ... more

Committer:
AzureIoTClient
Date:
Thu Oct 20 17:08:18 2016 -0700
Revision:
13:920e00014ee3
Parent:
11:77df6d7e65ae
Child:
14:b7e6599cacf5
1.0.10

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Azure.IoT Build 6:c55b013dfc2a 1 // Copyright (c) Microsoft. All rights reserved.
Azure.IoT Build 6:c55b013dfc2a 2 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
Azure.IoT Build 6:c55b013dfc2a 3
Azure.IoT Build 6:c55b013dfc2a 4 #include <stdlib.h>
Azure.IoT Build 6:c55b013dfc2a 5 #ifdef _CRTDBG_MAP_ALLOC
Azure.IoT Build 6:c55b013dfc2a 6 #include <crtdbg.h>
Azure.IoT Build 6:c55b013dfc2a 7 #endif
Azure.IoT Build 6:c55b013dfc2a 8
Azure.IoT Build 6:c55b013dfc2a 9 #include <stdio.h>
Azure.IoT Build 6:c55b013dfc2a 10 #include <ctype.h>
AzureIoTClient 11:77df6d7e65ae 11 #include "azure_c_shared_utility/gballoc.h"
Azure.IoT Build 6:c55b013dfc2a 12 #include "azure_c_shared_utility/httpheaders.h"
Azure.IoT Build 6:c55b013dfc2a 13 #include "azure_c_shared_utility/crt_abstractions.h"
Azure.IoT Build 6:c55b013dfc2a 14 #include "azure_c_shared_utility/xlogging.h"
Azure.IoT Build 6:c55b013dfc2a 15 #include "azure_c_shared_utility/xio.h"
Azure.IoT Build 6:c55b013dfc2a 16 #include "azure_c_shared_utility/platform.h"
Azure.IoT Build 6:c55b013dfc2a 17 #include "azure_c_shared_utility/tlsio.h"
Azure.IoT Build 6:c55b013dfc2a 18 #include "azure_c_shared_utility/threadapi.h"
Azure.IoT Build 6:c55b013dfc2a 19 #include <string.h>
AzureIoTClient 7:1af47e3a19b6 20 #include <limits.h>
Azure.IoT Build 6:c55b013dfc2a 21
AzureIoTClient 11:77df6d7e65ae 22 /*Codes_SRS_HTTPAPI_COMPACT_21_001: [ The httpapi_compact shall implement the methods defined by the `httpapi.h`. ]*/
AzureIoTClient 11:77df6d7e65ae 23 /*Codes_SRS_HTTPAPI_COMPACT_21_002: [ The httpapi_compact shall support the http requests. ]*/
AzureIoTClient 11:77df6d7e65ae 24 /*Codes_SRS_HTTPAPI_COMPACT_21_003: [ The httpapi_compact shall return error codes defined by HTTPAPI_RESULT. ]*/
AzureIoTClient 11:77df6d7e65ae 25 #include "azure_c_shared_utility/httpapi.h"
AzureIoTClient 11:77df6d7e65ae 26
Azure.IoT Build 6:c55b013dfc2a 27 #define MAX_HOSTNAME 64
AzureIoTClient 11:77df6d7e65ae 28 #define TEMP_BUFFER_SIZE 1024
Azure.IoT Build 6:c55b013dfc2a 29
AzureIoTClient 13:920e00014ee3 30 /*Codes_SRS_HTTPAPI_COMPACT_21_076: [ The HTTPAPI_ExecuteRequest shall try to read the message with the response up to 20 times. ]*/
AzureIoTClient 13:920e00014ee3 31 /*Codes_SRS_HTTPAPI_COMPACT_21_077: [ If the HTTPAPI_ExecuteRequest retries 20 times to receive the message without success, it shall fail and return HTTPAPI_READ_DATA_FAILED. ]*/
AzureIoTClient 13:920e00014ee3 32 #define MAX_RECEIVE_RETRY 20
AzureIoTClient 13:920e00014ee3 33 /*Codes_SRS_HTTPAPI_COMPACT_21_078: [ The HTTPAPI_ExecuteRequest shall wait, at least, 100 milliseconds between retries. ]*/
AzureIoTClient 13:920e00014ee3 34 #define RECEIVE_RETRY_INTERVAL_IN_MICROSECONDS 100
AzureIoTClient 13:920e00014ee3 35 #define OPEN_RETRY_INTERVAL_IN_MICROSECONDS 100
AzureIoTClient 13:920e00014ee3 36
Azure.IoT Build 6:c55b013dfc2a 37
Azure.IoT Build 6:c55b013dfc2a 38 DEFINE_ENUM_STRINGS(HTTPAPI_RESULT, HTTPAPI_RESULT_VALUES)
Azure.IoT Build 6:c55b013dfc2a 39
Azure.IoT Build 6:c55b013dfc2a 40 typedef struct HTTP_HANDLE_DATA_TAG
Azure.IoT Build 6:c55b013dfc2a 41 {
Azure.IoT Build 6:c55b013dfc2a 42 char* certificate;
Azure.IoT Build 6:c55b013dfc2a 43 XIO_HANDLE xio_handle;
Azure.IoT Build 6:c55b013dfc2a 44 size_t received_bytes_count;
Azure.IoT Build 6:c55b013dfc2a 45 unsigned char* received_bytes;
Azure.IoT Build 6:c55b013dfc2a 46 unsigned int is_io_error : 1;
Azure.IoT Build 6:c55b013dfc2a 47 unsigned int is_connected : 1;
Azure.IoT Build 6:c55b013dfc2a 48 } HTTP_HANDLE_DATA;
Azure.IoT Build 6:c55b013dfc2a 49
AzureIoTClient 7:1af47e3a19b6 50 /*the following function does the same as sscanf(pos2, "%d", &sec)*/
AzureIoTClient 7:1af47e3a19b6 51 /*this function only exists because some of platforms do not have sscanf. */
AzureIoTClient 7:1af47e3a19b6 52 static int ParseStringToDecimal(const char *src, int* dst)
AzureIoTClient 7:1af47e3a19b6 53 {
AzureIoTClient 11:77df6d7e65ae 54 int result;
AzureIoTClient 7:1af47e3a19b6 55 char* next;
AzureIoTClient 7:1af47e3a19b6 56 (*dst) = strtol(src, &next, 0);
AzureIoTClient 7:1af47e3a19b6 57 if ((src == next) || ((((*dst) == LONG_MAX) || ((*dst) == LONG_MIN)) && (errno != 0)))
AzureIoTClient 7:1af47e3a19b6 58 {
AzureIoTClient 11:77df6d7e65ae 59 result = EOF;
AzureIoTClient 7:1af47e3a19b6 60 }
AzureIoTClient 11:77df6d7e65ae 61 else
AzureIoTClient 11:77df6d7e65ae 62 {
AzureIoTClient 11:77df6d7e65ae 63 result = 1;
AzureIoTClient 11:77df6d7e65ae 64 }
AzureIoTClient 11:77df6d7e65ae 65 return result;
AzureIoTClient 7:1af47e3a19b6 66 }
AzureIoTClient 7:1af47e3a19b6 67
AzureIoTClient 7:1af47e3a19b6 68 /*the following function does the same as sscanf(pos2, "%x", &sec)*/
AzureIoTClient 7:1af47e3a19b6 69 /*this function only exists because some of platforms do not have sscanf. This is not a full implementation; it only works with well-defined x numbers. */
AzureIoTClient 7:1af47e3a19b6 70 #define HEXA_DIGIT_VAL(c) (((c>='0') && (c<='9')) ? (c-'0') : ((c>='a') && (c<='f')) ? (c-'a'+10) : ((c>='A') && (c<='F')) ? (c-'A'+10) : -1)
AzureIoTClient 11:77df6d7e65ae 71 static int ParseStringToHexadecimal(const char *src, size_t* dst)
AzureIoTClient 7:1af47e3a19b6 72 {
AzureIoTClient 11:77df6d7e65ae 73 int result;
AzureIoTClient 7:1af47e3a19b6 74 int digitVal;
AzureIoTClient 11:77df6d7e65ae 75 if (src == NULL)
AzureIoTClient 11:77df6d7e65ae 76 {
AzureIoTClient 11:77df6d7e65ae 77 result = EOF;
AzureIoTClient 11:77df6d7e65ae 78 }
AzureIoTClient 11:77df6d7e65ae 79 else if (HEXA_DIGIT_VAL(*src) == -1)
AzureIoTClient 11:77df6d7e65ae 80 {
AzureIoTClient 11:77df6d7e65ae 81 result = EOF;
AzureIoTClient 11:77df6d7e65ae 82 }
AzureIoTClient 11:77df6d7e65ae 83 else
AzureIoTClient 11:77df6d7e65ae 84 {
AzureIoTClient 11:77df6d7e65ae 85 (*dst) = 0;
AzureIoTClient 11:77df6d7e65ae 86 while ((digitVal = HEXA_DIGIT_VAL(*src)) != -1)
AzureIoTClient 11:77df6d7e65ae 87 {
AzureIoTClient 11:77df6d7e65ae 88 (*dst) *= 0x10;
AzureIoTClient 11:77df6d7e65ae 89 (*dst) += (size_t)digitVal;
AzureIoTClient 11:77df6d7e65ae 90 src++;
AzureIoTClient 11:77df6d7e65ae 91 }
AzureIoTClient 11:77df6d7e65ae 92 result = 1;
AzureIoTClient 11:77df6d7e65ae 93 }
AzureIoTClient 11:77df6d7e65ae 94 return result;
AzureIoTClient 7:1af47e3a19b6 95 }
AzureIoTClient 7:1af47e3a19b6 96
AzureIoTClient 7:1af47e3a19b6 97 /*the following function does the same as sscanf(buf, "HTTP/%*d.%*d %d %*[^\r\n]", &ret) */
AzureIoTClient 7:1af47e3a19b6 98 /*this function only exists because some of platforms do not have sscanf. This is not a full implementation; it only works with well-defined HTTP response. */
AzureIoTClient 11:77df6d7e65ae 99 static int ParseHttpResponse(const char* src, int* dst)
AzureIoTClient 7:1af47e3a19b6 100 {
AzureIoTClient 11:77df6d7e65ae 101 int result;
AzureIoTClient 11:77df6d7e65ae 102 static const char HTTPPrefix[] = "HTTP/";
AzureIoTClient 11:77df6d7e65ae 103 bool fail;
AzureIoTClient 11:77df6d7e65ae 104 const char* runPrefix;
AzureIoTClient 11:77df6d7e65ae 105
AzureIoTClient 11:77df6d7e65ae 106 if ((src == NULL) || (dst == NULL))
AzureIoTClient 11:77df6d7e65ae 107 {
AzureIoTClient 11:77df6d7e65ae 108 result = EOF;
AzureIoTClient 11:77df6d7e65ae 109 }
AzureIoTClient 11:77df6d7e65ae 110 else
AzureIoTClient 11:77df6d7e65ae 111 {
AzureIoTClient 11:77df6d7e65ae 112 fail = false;
AzureIoTClient 11:77df6d7e65ae 113 runPrefix = HTTPPrefix;
AzureIoTClient 11:77df6d7e65ae 114
AzureIoTClient 11:77df6d7e65ae 115 while((*runPrefix) != '\0')
AzureIoTClient 11:77df6d7e65ae 116 {
AzureIoTClient 11:77df6d7e65ae 117 if ((*runPrefix) != (*src))
AzureIoTClient 11:77df6d7e65ae 118 {
AzureIoTClient 11:77df6d7e65ae 119 fail = true;
AzureIoTClient 11:77df6d7e65ae 120 break;
AzureIoTClient 11:77df6d7e65ae 121 }
AzureIoTClient 11:77df6d7e65ae 122 src++;
AzureIoTClient 11:77df6d7e65ae 123 runPrefix++;
AzureIoTClient 11:77df6d7e65ae 124 }
AzureIoTClient 7:1af47e3a19b6 125
AzureIoTClient 11:77df6d7e65ae 126 if (!fail)
AzureIoTClient 11:77df6d7e65ae 127 {
AzureIoTClient 11:77df6d7e65ae 128 while ((*src) != '.')
AzureIoTClient 11:77df6d7e65ae 129 {
AzureIoTClient 11:77df6d7e65ae 130 if ((*src) == '\0')
AzureIoTClient 11:77df6d7e65ae 131 {
AzureIoTClient 11:77df6d7e65ae 132 fail = true;
AzureIoTClient 11:77df6d7e65ae 133 break;
AzureIoTClient 11:77df6d7e65ae 134 }
AzureIoTClient 11:77df6d7e65ae 135 src++;
AzureIoTClient 11:77df6d7e65ae 136 }
AzureIoTClient 11:77df6d7e65ae 137 }
AzureIoTClient 7:1af47e3a19b6 138
AzureIoTClient 11:77df6d7e65ae 139 if (!fail)
AzureIoTClient 11:77df6d7e65ae 140 {
AzureIoTClient 11:77df6d7e65ae 141 while ((*src) != ' ')
AzureIoTClient 11:77df6d7e65ae 142 {
AzureIoTClient 11:77df6d7e65ae 143 if ((*src) == '\0')
AzureIoTClient 11:77df6d7e65ae 144 {
AzureIoTClient 11:77df6d7e65ae 145 fail = true;
AzureIoTClient 11:77df6d7e65ae 146 break;
AzureIoTClient 11:77df6d7e65ae 147 }
AzureIoTClient 11:77df6d7e65ae 148 src++;
AzureIoTClient 11:77df6d7e65ae 149 }
AzureIoTClient 11:77df6d7e65ae 150 }
AzureIoTClient 7:1af47e3a19b6 151
AzureIoTClient 11:77df6d7e65ae 152 if (fail)
AzureIoTClient 11:77df6d7e65ae 153 {
AzureIoTClient 11:77df6d7e65ae 154 result = EOF;
AzureIoTClient 11:77df6d7e65ae 155 }
AzureIoTClient 11:77df6d7e65ae 156 else
AzureIoTClient 11:77df6d7e65ae 157 {
AzureIoTClient 11:77df6d7e65ae 158 result = ParseStringToDecimal(src, dst);
AzureIoTClient 11:77df6d7e65ae 159 }
AzureIoTClient 11:77df6d7e65ae 160 }
AzureIoTClient 11:77df6d7e65ae 161
AzureIoTClient 11:77df6d7e65ae 162 return result;
AzureIoTClient 7:1af47e3a19b6 163 }
AzureIoTClient 7:1af47e3a19b6 164
Azure.IoT Build 6:c55b013dfc2a 165 HTTPAPI_RESULT HTTPAPI_Init(void)
Azure.IoT Build 6:c55b013dfc2a 166 {
AzureIoTClient 11:77df6d7e65ae 167 /*Codes_SRS_HTTPAPI_COMPACT_21_004: [ The HTTPAPI_Init shall allocate all memory to control the http protocol. ]*/
AzureIoTClient 11:77df6d7e65ae 168 /*Codes_SRS_HTTPAPI_COMPACT_21_007: [ If there is not enough memory to control the http protocol, the HTTPAPI_Init shall return HTTPAPI_ALLOC_FAILED. ]*/
AzureIoTClient 11:77df6d7e65ae 169 /**
AzureIoTClient 11:77df6d7e65ae 170 * No memory is necessary.
AzureIoTClient 11:77df6d7e65ae 171 */
AzureIoTClient 11:77df6d7e65ae 172
AzureIoTClient 11:77df6d7e65ae 173 /*Codes_SRS_HTTPAPI_COMPACT_21_006: [ If HTTPAPI_Init succeed allocating all the needed memory, it shall return HTTPAPI_OK. ]*/
Azure.IoT Build 6:c55b013dfc2a 174 return HTTPAPI_OK;
Azure.IoT Build 6:c55b013dfc2a 175 }
Azure.IoT Build 6:c55b013dfc2a 176
Azure.IoT Build 6:c55b013dfc2a 177 void HTTPAPI_Deinit(void)
Azure.IoT Build 6:c55b013dfc2a 178 {
AzureIoTClient 11:77df6d7e65ae 179 /*Codes_SRS_HTTPAPI_COMPACT_21_009: [ The HTTPAPI_Init shall release all memory allocated by the httpapi_compact. ]*/
AzureIoTClient 11:77df6d7e65ae 180 /**
AzureIoTClient 11:77df6d7e65ae 181 * No memory was necessary.
AzureIoTClient 11:77df6d7e65ae 182 */
Azure.IoT Build 6:c55b013dfc2a 183 }
Azure.IoT Build 6:c55b013dfc2a 184
AzureIoTClient 11:77df6d7e65ae 185 /*Codes_SRS_HTTPAPI_COMPACT_21_011: [ The HTTPAPI_CreateConnection shall create an http connection to the host specified by the hostName parameter. ]*/
Azure.IoT Build 6:c55b013dfc2a 186 HTTP_HANDLE HTTPAPI_CreateConnection(const char* hostName)
Azure.IoT Build 6:c55b013dfc2a 187 {
AzureIoTClient 13:920e00014ee3 188 HTTP_HANDLE_DATA* http_instance;
AzureIoTClient 11:77df6d7e65ae 189 TLSIO_CONFIG tlsio_config;
Azure.IoT Build 6:c55b013dfc2a 190
AzureIoTClient 11:77df6d7e65ae 191 if (hostName == NULL)
AzureIoTClient 11:77df6d7e65ae 192 {
AzureIoTClient 11:77df6d7e65ae 193 /*Codes_SRS_HTTPAPI_COMPACT_21_014: [ If the hostName is NULL, the HTTPAPI_CreateConnection shall return NULL as the handle. ]*/
AzureIoTClient 11:77df6d7e65ae 194 LogError("Invalid host name. Null hostName parameter.");
AzureIoTClient 13:920e00014ee3 195 http_instance = NULL;
AzureIoTClient 11:77df6d7e65ae 196 }
AzureIoTClient 11:77df6d7e65ae 197 else if (*hostName == '\0')
AzureIoTClient 11:77df6d7e65ae 198 {
AzureIoTClient 11:77df6d7e65ae 199 /*Codes_SRS_HTTPAPI_COMPACT_21_015: [ If the hostName is empty, the HTTPAPI_CreateConnection shall return NULL as the handle. ]*/
AzureIoTClient 11:77df6d7e65ae 200 LogError("Invalid host name. Empty string.");
AzureIoTClient 13:920e00014ee3 201 http_instance = NULL;
AzureIoTClient 11:77df6d7e65ae 202 }
AzureIoTClient 11:77df6d7e65ae 203 else
AzureIoTClient 11:77df6d7e65ae 204 {
AzureIoTClient 13:920e00014ee3 205 http_instance = (HTTP_HANDLE_DATA*)malloc(sizeof(HTTP_HANDLE_DATA));
AzureIoTClient 11:77df6d7e65ae 206 /*Codes_SRS_HTTPAPI_COMPACT_21_013: [ If there is not enough memory to control the http connection, the HTTPAPI_CreateConnection shall return NULL as the handle. ]*/
AzureIoTClient 13:920e00014ee3 207 if (http_instance == NULL)
AzureIoTClient 11:77df6d7e65ae 208 {
AzureIoTClient 11:77df6d7e65ae 209 LogError("There is no memory to control the http connection");
AzureIoTClient 11:77df6d7e65ae 210 }
AzureIoTClient 11:77df6d7e65ae 211 else
AzureIoTClient 11:77df6d7e65ae 212 {
AzureIoTClient 11:77df6d7e65ae 213 tlsio_config.hostname = hostName;
AzureIoTClient 11:77df6d7e65ae 214 tlsio_config.port = 443;
Azure.IoT Build 6:c55b013dfc2a 215
AzureIoTClient 13:920e00014ee3 216 http_instance->xio_handle = xio_create(platform_get_default_tlsio(), (void*)&tlsio_config);
AzureIoTClient 11:77df6d7e65ae 217
AzureIoTClient 11:77df6d7e65ae 218 /*Codes_SRS_HTTPAPI_COMPACT_21_016: [ If the HTTPAPI_CreateConnection failed to create the connection, it shall return NULL as the handle. ]*/
AzureIoTClient 13:920e00014ee3 219 if (http_instance->xio_handle == NULL)
AzureIoTClient 11:77df6d7e65ae 220 {
AzureIoTClient 11:77df6d7e65ae 221 LogError("Create connection failed");
AzureIoTClient 13:920e00014ee3 222 free(http_instance);
AzureIoTClient 13:920e00014ee3 223 http_instance = NULL;
AzureIoTClient 11:77df6d7e65ae 224 }
AzureIoTClient 11:77df6d7e65ae 225 else
AzureIoTClient 11:77df6d7e65ae 226 {
AzureIoTClient 13:920e00014ee3 227 http_instance->is_connected = 0;
AzureIoTClient 13:920e00014ee3 228 http_instance->is_io_error = 0;
AzureIoTClient 13:920e00014ee3 229 http_instance->received_bytes_count = 0;
AzureIoTClient 13:920e00014ee3 230 http_instance->received_bytes = NULL;
AzureIoTClient 13:920e00014ee3 231 http_instance->certificate = NULL;
AzureIoTClient 11:77df6d7e65ae 232 }
AzureIoTClient 11:77df6d7e65ae 233 }
AzureIoTClient 11:77df6d7e65ae 234 }
AzureIoTClient 11:77df6d7e65ae 235
AzureIoTClient 11:77df6d7e65ae 236 /*Codes_SRS_HTTPAPI_COMPACT_21_012: [ The HTTPAPI_CreateConnection shall return a non-NULL handle on success. ]*/
AzureIoTClient 13:920e00014ee3 237 return (HTTP_HANDLE)http_instance;
Azure.IoT Build 6:c55b013dfc2a 238 }
Azure.IoT Build 6:c55b013dfc2a 239
Azure.IoT Build 6:c55b013dfc2a 240 void HTTPAPI_CloseConnection(HTTP_HANDLE handle)
Azure.IoT Build 6:c55b013dfc2a 241 {
AzureIoTClient 13:920e00014ee3 242 HTTP_HANDLE_DATA* http_instance = (HTTP_HANDLE_DATA*)handle;
Azure.IoT Build 6:c55b013dfc2a 243
AzureIoTClient 11:77df6d7e65ae 244 /*Codes_SRS_HTTPAPI_COMPACT_21_020: [ If the connection handle is NULL, the HTTPAPI_CloseConnection shall not do anything. ]*/
AzureIoTClient 13:920e00014ee3 245 if (http_instance != NULL)
Azure.IoT Build 6:c55b013dfc2a 246 {
AzureIoTClient 11:77df6d7e65ae 247 /*Codes_SRS_HTTPAPI_COMPACT_21_019: [ If there is no previous connection, the HTTPAPI_CloseConnection shall not do anything. ]*/
AzureIoTClient 13:920e00014ee3 248 if (http_instance->xio_handle != NULL)
Azure.IoT Build 6:c55b013dfc2a 249 {
AzureIoTClient 11:77df6d7e65ae 250 /*Codes_SRS_HTTPAPI_COMPACT_21_017: [ The HTTPAPI_CloseConnection shall close the connection previously created in HTTPAPI_CreateConnection. ]*/
AzureIoTClient 13:920e00014ee3 251 xio_destroy(http_instance->xio_handle);
Azure.IoT Build 6:c55b013dfc2a 252 }
Azure.IoT Build 6:c55b013dfc2a 253
AzureIoTClient 11:77df6d7e65ae 254 /*Codes_SRS_HTTPAPI_COMPACT_21_018: [ If there is a certificate associated to this connection, the HTTPAPI_CloseConnection shall free all allocated memory for the certificate. ]*/
AzureIoTClient 13:920e00014ee3 255 if (http_instance->certificate)
Azure.IoT Build 6:c55b013dfc2a 256 {
AzureIoTClient 13:920e00014ee3 257 free(http_instance->certificate);
Azure.IoT Build 6:c55b013dfc2a 258 }
Azure.IoT Build 6:c55b013dfc2a 259
AzureIoTClient 13:920e00014ee3 260 free(http_instance);
Azure.IoT Build 6:c55b013dfc2a 261 }
Azure.IoT Build 6:c55b013dfc2a 262 }
Azure.IoT Build 6:c55b013dfc2a 263
Azure.IoT Build 6:c55b013dfc2a 264 static void on_io_open_complete(void* context, IO_OPEN_RESULT open_result)
Azure.IoT Build 6:c55b013dfc2a 265 {
AzureIoTClient 13:920e00014ee3 266 HTTP_HANDLE_DATA* http_instance = (HTTP_HANDLE_DATA*)context;
AzureIoTClient 11:77df6d7e65ae 267
AzureIoTClient 13:920e00014ee3 268 if (http_instance != NULL)
AzureIoTClient 11:77df6d7e65ae 269 {
AzureIoTClient 11:77df6d7e65ae 270 if (open_result == IO_OPEN_OK)
AzureIoTClient 11:77df6d7e65ae 271 {
AzureIoTClient 13:920e00014ee3 272 http_instance->is_connected = 1;
AzureIoTClient 13:920e00014ee3 273 http_instance->is_io_error = 0;
AzureIoTClient 11:77df6d7e65ae 274 }
AzureIoTClient 11:77df6d7e65ae 275 else
AzureIoTClient 11:77df6d7e65ae 276 {
AzureIoTClient 13:920e00014ee3 277 http_instance->is_io_error = 1;
AzureIoTClient 11:77df6d7e65ae 278 }
AzureIoTClient 11:77df6d7e65ae 279 }
Azure.IoT Build 6:c55b013dfc2a 280 }
Azure.IoT Build 6:c55b013dfc2a 281
AzureIoTClient 11:77df6d7e65ae 282 #define TOLOWER(c) (((c>='A') && (c<='Z'))?c-'A'+'a':c)
AzureIoTClient 11:77df6d7e65ae 283 static int InternStrnicmp(const char* s1, const char* s2, size_t n)
Azure.IoT Build 6:c55b013dfc2a 284 {
AzureIoTClient 11:77df6d7e65ae 285 int result;
Azure.IoT Build 6:c55b013dfc2a 286
AzureIoTClient 11:77df6d7e65ae 287 if ((s1 == NULL) || (s2 == NULL))
AzureIoTClient 11:77df6d7e65ae 288 {
AzureIoTClient 11:77df6d7e65ae 289 result = -1;
AzureIoTClient 11:77df6d7e65ae 290 }
AzureIoTClient 11:77df6d7e65ae 291 else
AzureIoTClient 11:77df6d7e65ae 292 {
AzureIoTClient 11:77df6d7e65ae 293 result = 0;
AzureIoTClient 11:77df6d7e65ae 294 while (((n--) >= 0) && ((*s1) != '\0') && ((*s2) != '\0') && (result == 0))
AzureIoTClient 11:77df6d7e65ae 295 {
AzureIoTClient 11:77df6d7e65ae 296 /* compute the difference between the chars */
AzureIoTClient 11:77df6d7e65ae 297 result = TOLOWER(*s1) - TOLOWER(*s2);
AzureIoTClient 11:77df6d7e65ae 298 s1++;
AzureIoTClient 11:77df6d7e65ae 299 s2++;
AzureIoTClient 11:77df6d7e65ae 300 }
Azure.IoT Build 6:c55b013dfc2a 301
AzureIoTClient 11:77df6d7e65ae 302 if ((*s2) != '\0')
Azure.IoT Build 6:c55b013dfc2a 303 {
AzureIoTClient 11:77df6d7e65ae 304 result = -1;
Azure.IoT Build 6:c55b013dfc2a 305 }
AzureIoTClient 11:77df6d7e65ae 306 }
Azure.IoT Build 6:c55b013dfc2a 307
Azure.IoT Build 6:c55b013dfc2a 308 return result;
Azure.IoT Build 6:c55b013dfc2a 309 }
Azure.IoT Build 6:c55b013dfc2a 310
Azure.IoT Build 6:c55b013dfc2a 311 static void on_bytes_received(void* context, const unsigned char* buffer, size_t size)
Azure.IoT Build 6:c55b013dfc2a 312 {
AzureIoTClient 11:77df6d7e65ae 313 unsigned char* new_received_bytes;
AzureIoTClient 13:920e00014ee3 314 HTTP_HANDLE_DATA* http_instance = (HTTP_HANDLE_DATA*)context;
AzureIoTClient 11:77df6d7e65ae 315
AzureIoTClient 13:920e00014ee3 316 if (http_instance != NULL)
AzureIoTClient 13:920e00014ee3 317 {
Azure.IoT Build 6:c55b013dfc2a 318
AzureIoTClient 11:77df6d7e65ae 319 if (buffer == NULL)
AzureIoTClient 11:77df6d7e65ae 320 {
AzureIoTClient 13:920e00014ee3 321 http_instance->is_io_error = 1;
AzureIoTClient 13:920e00014ee3 322 LogError("NULL pointer error");
AzureIoTClient 11:77df6d7e65ae 323 }
AzureIoTClient 11:77df6d7e65ae 324 else
AzureIoTClient 11:77df6d7e65ae 325 {
AzureIoTClient 11:77df6d7e65ae 326 /* Here we got some bytes so we'll buffer them so the receive functions can consumer it */
AzureIoTClient 13:920e00014ee3 327 new_received_bytes = (unsigned char*)realloc(http_instance->received_bytes, http_instance->received_bytes_count + size);
AzureIoTClient 11:77df6d7e65ae 328 if (new_received_bytes == NULL)
AzureIoTClient 11:77df6d7e65ae 329 {
AzureIoTClient 13:920e00014ee3 330 http_instance->is_io_error = 1;
AzureIoTClient 13:920e00014ee3 331 LogError("Error allocating memory for received data");
AzureIoTClient 11:77df6d7e65ae 332 }
AzureIoTClient 11:77df6d7e65ae 333 else
AzureIoTClient 11:77df6d7e65ae 334 {
AzureIoTClient 13:920e00014ee3 335 http_instance->received_bytes = new_received_bytes;
AzureIoTClient 13:920e00014ee3 336 if (memcpy(http_instance->received_bytes + http_instance->received_bytes_count, buffer, size) == NULL)
AzureIoTClient 11:77df6d7e65ae 337 {
AzureIoTClient 13:920e00014ee3 338 http_instance->is_io_error = 1;
AzureIoTClient 13:920e00014ee3 339 LogError("Error copping received data to the HTTP bufffer");
AzureIoTClient 11:77df6d7e65ae 340 }
AzureIoTClient 11:77df6d7e65ae 341 else
AzureIoTClient 11:77df6d7e65ae 342 {
AzureIoTClient 13:920e00014ee3 343 http_instance->received_bytes_count += size;
AzureIoTClient 11:77df6d7e65ae 344 }
AzureIoTClient 11:77df6d7e65ae 345 }
AzureIoTClient 11:77df6d7e65ae 346 }
AzureIoTClient 11:77df6d7e65ae 347 }
Azure.IoT Build 6:c55b013dfc2a 348 }
Azure.IoT Build 6:c55b013dfc2a 349
Azure.IoT Build 6:c55b013dfc2a 350 static void on_io_error(void* context)
Azure.IoT Build 6:c55b013dfc2a 351 {
AzureIoTClient 13:920e00014ee3 352 HTTP_HANDLE_DATA* http_instance = (HTTP_HANDLE_DATA*)context;
AzureIoTClient 13:920e00014ee3 353 if (http_instance != NULL)
AzureIoTClient 13:920e00014ee3 354 {
AzureIoTClient 13:920e00014ee3 355 http_instance->is_io_error = 1;
AzureIoTClient 13:920e00014ee3 356 LogError("Error signalled by underlying IO");
AzureIoTClient 13:920e00014ee3 357 }
Azure.IoT Build 6:c55b013dfc2a 358 }
Azure.IoT Build 6:c55b013dfc2a 359
Azure.IoT Build 6:c55b013dfc2a 360 static int conn_receive(HTTP_HANDLE_DATA* http_instance, char* buffer, int count)
Azure.IoT Build 6:c55b013dfc2a 361 {
AzureIoTClient 11:77df6d7e65ae 362 int result;
Azure.IoT Build 6:c55b013dfc2a 363
AzureIoTClient 11:77df6d7e65ae 364 if ((http_instance == NULL) || (buffer == NULL) || (count < 0))
AzureIoTClient 11:77df6d7e65ae 365 {
AzureIoTClient 11:77df6d7e65ae 366 LogError("conn_receive: %s", ((http_instance == NULL) ? "Invalid HTTP instance" : "Invalid HTTP buffer"));
Azure.IoT Build 6:c55b013dfc2a 367 result = -1;
AzureIoTClient 11:77df6d7e65ae 368 }
AzureIoTClient 11:77df6d7e65ae 369 else
AzureIoTClient 11:77df6d7e65ae 370 {
AzureIoTClient 11:77df6d7e65ae 371 result = 0;
AzureIoTClient 11:77df6d7e65ae 372 while (result < count)
AzureIoTClient 11:77df6d7e65ae 373 {
AzureIoTClient 11:77df6d7e65ae 374 xio_dowork(http_instance->xio_handle);
Azure.IoT Build 6:c55b013dfc2a 375
AzureIoTClient 11:77df6d7e65ae 376 /* if any error was detected while receiving then simply break and report it */
AzureIoTClient 11:77df6d7e65ae 377 if (http_instance->is_io_error != 0)
AzureIoTClient 11:77df6d7e65ae 378 {
AzureIoTClient 13:920e00014ee3 379 LogError("xio reported error on dowork");
Azure.IoT Build 6:c55b013dfc2a 380 result = -1;
AzureIoTClient 11:77df6d7e65ae 381 break;
AzureIoTClient 11:77df6d7e65ae 382 }
Azure.IoT Build 6:c55b013dfc2a 383
AzureIoTClient 11:77df6d7e65ae 384 if (http_instance->received_bytes_count >= (size_t)count)
AzureIoTClient 11:77df6d7e65ae 385 {
AzureIoTClient 11:77df6d7e65ae 386 /* Consuming bytes from the receive buffer */
AzureIoTClient 11:77df6d7e65ae 387 (void)memcpy(buffer, http_instance->received_bytes, count);
AzureIoTClient 11:77df6d7e65ae 388 (void)memmove(http_instance->received_bytes, http_instance->received_bytes + count, http_instance->received_bytes_count - count);
AzureIoTClient 11:77df6d7e65ae 389 http_instance->received_bytes_count -= count;
Azure.IoT Build 6:c55b013dfc2a 390
AzureIoTClient 11:77df6d7e65ae 391 /* we're not reallocating at each consumption so that we don't trash due to byte by byte consumption */
AzureIoTClient 11:77df6d7e65ae 392 if (http_instance->received_bytes_count == 0)
AzureIoTClient 11:77df6d7e65ae 393 {
AzureIoTClient 11:77df6d7e65ae 394 free(http_instance->received_bytes);
AzureIoTClient 11:77df6d7e65ae 395 http_instance->received_bytes = NULL;
AzureIoTClient 11:77df6d7e65ae 396 }
Azure.IoT Build 6:c55b013dfc2a 397
AzureIoTClient 11:77df6d7e65ae 398 result = count;
AzureIoTClient 11:77df6d7e65ae 399 break;
AzureIoTClient 11:77df6d7e65ae 400 }
Azure.IoT Build 6:c55b013dfc2a 401
AzureIoTClient 13:920e00014ee3 402 ThreadAPI_Sleep(RECEIVE_RETRY_INTERVAL_IN_MICROSECONDS);
AzureIoTClient 11:77df6d7e65ae 403 }
AzureIoTClient 11:77df6d7e65ae 404 }
Azure.IoT Build 6:c55b013dfc2a 405
Azure.IoT Build 6:c55b013dfc2a 406 return result;
Azure.IoT Build 6:c55b013dfc2a 407 }
Azure.IoT Build 6:c55b013dfc2a 408
AzureIoTClient 11:77df6d7e65ae 409 static void conn_receive_discard_buffer(HTTP_HANDLE_DATA* http_instance)
AzureIoTClient 11:77df6d7e65ae 410 {
AzureIoTClient 13:920e00014ee3 411 if (http_instance != NULL)
AzureIoTClient 11:77df6d7e65ae 412 {
AzureIoTClient 13:920e00014ee3 413 if (http_instance->received_bytes != NULL)
AzureIoTClient 13:920e00014ee3 414 {
AzureIoTClient 13:920e00014ee3 415 free(http_instance->received_bytes);
AzureIoTClient 13:920e00014ee3 416 http_instance->received_bytes = NULL;
AzureIoTClient 13:920e00014ee3 417 }
AzureIoTClient 13:920e00014ee3 418 http_instance->received_bytes_count = 0;
AzureIoTClient 11:77df6d7e65ae 419 }
AzureIoTClient 11:77df6d7e65ae 420 }
AzureIoTClient 11:77df6d7e65ae 421
AzureIoTClient 13:920e00014ee3 422 static int readLine(HTTP_HANDLE_DATA* http_instance, char* buf, const size_t maxBufSize)
Azure.IoT Build 6:c55b013dfc2a 423 {
AzureIoTClient 13:920e00014ee3 424 int resultLineSize;
Azure.IoT Build 6:c55b013dfc2a 425
AzureIoTClient 13:920e00014ee3 426 if ((http_instance == NULL) || (buf == NULL) || (maxBufSize < 0))
AzureIoTClient 13:920e00014ee3 427 {
AzureIoTClient 13:920e00014ee3 428 LogError("%s", ((http_instance == NULL) ? "Invalid HTTP instance" : "Invalid HTTP buffer"));
AzureIoTClient 13:920e00014ee3 429 resultLineSize = -1;
Azure.IoT Build 6:c55b013dfc2a 430 }
Azure.IoT Build 6:c55b013dfc2a 431 else
Azure.IoT Build 6:c55b013dfc2a 432 {
AzureIoTClient 13:920e00014ee3 433 char* destByte = buf;
AzureIoTClient 13:920e00014ee3 434 /*Codes_SRS_HTTPAPI_COMPACT_21_076: [ The HTTPAPI_ExecuteRequest shall try to read the message with the response up to 20 times. ]*/
AzureIoTClient 13:920e00014ee3 435 int countRetry = MAX_RECEIVE_RETRY;
AzureIoTClient 13:920e00014ee3 436 bool endOfSearch = false;
AzureIoTClient 13:920e00014ee3 437 resultLineSize = -1;
AzureIoTClient 13:920e00014ee3 438 while (!endOfSearch)
Azure.IoT Build 6:c55b013dfc2a 439 {
AzureIoTClient 13:920e00014ee3 440 xio_dowork(http_instance->xio_handle);
AzureIoTClient 13:920e00014ee3 441
AzureIoTClient 13:920e00014ee3 442 /* if any error was detected while receiving then simply break and report it */
AzureIoTClient 13:920e00014ee3 443 if (http_instance->is_io_error != 0)
AzureIoTClient 13:920e00014ee3 444 {
AzureIoTClient 13:920e00014ee3 445 LogError("xio reported error on dowork");
AzureIoTClient 13:920e00014ee3 446 endOfSearch = true;
AzureIoTClient 13:920e00014ee3 447 }
AzureIoTClient 13:920e00014ee3 448 else
Azure.IoT Build 6:c55b013dfc2a 449 {
AzureIoTClient 13:920e00014ee3 450 unsigned char* receivedByte = http_instance->received_bytes;
AzureIoTClient 13:920e00014ee3 451 while (receivedByte < (http_instance->received_bytes + http_instance->received_bytes_count))
Azure.IoT Build 6:c55b013dfc2a 452 {
AzureIoTClient 13:920e00014ee3 453 if ((*receivedByte) != '\r')
AzureIoTClient 13:920e00014ee3 454 {
AzureIoTClient 13:920e00014ee3 455 (*destByte) = (*receivedByte);
AzureIoTClient 13:920e00014ee3 456 destByte++;
AzureIoTClient 13:920e00014ee3 457 receivedByte++;
Azure.IoT Build 6:c55b013dfc2a 458
AzureIoTClient 13:920e00014ee3 459 if (destByte >= (buf + maxBufSize - 1))
AzureIoTClient 13:920e00014ee3 460 {
AzureIoTClient 13:920e00014ee3 461 LogError("Received message is bigger than the http buffer");
AzureIoTClient 13:920e00014ee3 462 receivedByte = http_instance->received_bytes + http_instance->received_bytes_count;
AzureIoTClient 13:920e00014ee3 463 endOfSearch = true;
AzureIoTClient 13:920e00014ee3 464 break;
AzureIoTClient 13:920e00014ee3 465 }
AzureIoTClient 13:920e00014ee3 466 }
AzureIoTClient 13:920e00014ee3 467 else
AzureIoTClient 13:920e00014ee3 468 {
AzureIoTClient 13:920e00014ee3 469 receivedByte++;
AzureIoTClient 13:920e00014ee3 470 if ((receivedByte < (http_instance->received_bytes + http_instance->received_bytes_count)) && ((*receivedByte) == '\n'))
AzureIoTClient 13:920e00014ee3 471 {
AzureIoTClient 13:920e00014ee3 472 receivedByte++;
AzureIoTClient 13:920e00014ee3 473 }
AzureIoTClient 13:920e00014ee3 474 (*destByte) = '\0';
AzureIoTClient 13:920e00014ee3 475 resultLineSize = (int)(destByte - buf);
AzureIoTClient 13:920e00014ee3 476 endOfSearch = true;
AzureIoTClient 13:920e00014ee3 477 break;
AzureIoTClient 13:920e00014ee3 478 }
Azure.IoT Build 6:c55b013dfc2a 479 }
Azure.IoT Build 6:c55b013dfc2a 480
AzureIoTClient 13:920e00014ee3 481 http_instance->received_bytes_count -= (receivedByte - http_instance->received_bytes);
AzureIoTClient 13:920e00014ee3 482 if (http_instance->received_bytes_count != 0)
AzureIoTClient 13:920e00014ee3 483 {
AzureIoTClient 13:920e00014ee3 484 (void)memmove(http_instance->received_bytes, receivedByte, http_instance->received_bytes_count);
AzureIoTClient 13:920e00014ee3 485 }
AzureIoTClient 13:920e00014ee3 486 else
AzureIoTClient 13:920e00014ee3 487 {
AzureIoTClient 13:920e00014ee3 488 conn_receive_discard_buffer(http_instance);
AzureIoTClient 13:920e00014ee3 489 }
Azure.IoT Build 6:c55b013dfc2a 490 }
Azure.IoT Build 6:c55b013dfc2a 491
AzureIoTClient 13:920e00014ee3 492 if (!endOfSearch)
Azure.IoT Build 6:c55b013dfc2a 493 {
AzureIoTClient 13:920e00014ee3 494 if ((countRetry--) > 0)
AzureIoTClient 13:920e00014ee3 495 {
AzureIoTClient 13:920e00014ee3 496 /*Codes_SRS_HTTPAPI_COMPACT_21_078: [ The HTTPAPI_ExecuteRequest shall wait, at least, 100 milliseconds between retries. ]*/
AzureIoTClient 13:920e00014ee3 497 ThreadAPI_Sleep(RECEIVE_RETRY_INTERVAL_IN_MICROSECONDS);
AzureIoTClient 13:920e00014ee3 498 }
AzureIoTClient 13:920e00014ee3 499 else
AzureIoTClient 13:920e00014ee3 500 {
AzureIoTClient 13:920e00014ee3 501 /*Codes_SRS_HTTPAPI_COMPACT_21_077: [ If the HTTPAPI_ExecuteRequest retries 20 times to receive the message without success, it shall fail and return HTTPAPI_READ_DATA_FAILED. ]*/
AzureIoTClient 13:920e00014ee3 502 LogError("Timeout. The HTTP request is incomplete");
AzureIoTClient 13:920e00014ee3 503 endOfSearch = true;
AzureIoTClient 13:920e00014ee3 504 }
Azure.IoT Build 6:c55b013dfc2a 505 }
Azure.IoT Build 6:c55b013dfc2a 506 }
Azure.IoT Build 6:c55b013dfc2a 507 }
Azure.IoT Build 6:c55b013dfc2a 508
AzureIoTClient 13:920e00014ee3 509 return resultLineSize;
Azure.IoT Build 6:c55b013dfc2a 510 }
Azure.IoT Build 6:c55b013dfc2a 511
Azure.IoT Build 6:c55b013dfc2a 512 static int readChunk(HTTP_HANDLE_DATA* http_instance, char* buf, size_t size)
Azure.IoT Build 6:c55b013dfc2a 513 {
AzureIoTClient 11:77df6d7e65ae 514 int cur, offset;
Azure.IoT Build 6:c55b013dfc2a 515
Azure.IoT Build 6:c55b013dfc2a 516 // read content with specified length, even if it is received
Azure.IoT Build 6:c55b013dfc2a 517 // only in chunks due to fragmentation in the networking layer.
Azure.IoT Build 6:c55b013dfc2a 518 // returns -1 in case of error.
Azure.IoT Build 6:c55b013dfc2a 519 offset = 0;
AzureIoTClient 11:77df6d7e65ae 520 while (size > (size_t)0)
Azure.IoT Build 6:c55b013dfc2a 521 {
AzureIoTClient 11:77df6d7e65ae 522 cur = conn_receive(http_instance, buf + offset, (int)size);
Azure.IoT Build 6:c55b013dfc2a 523
Azure.IoT Build 6:c55b013dfc2a 524 // end of stream reached
AzureIoTClient 11:77df6d7e65ae 525 if (cur == 0)
AzureIoTClient 11:77df6d7e65ae 526 {
AzureIoTClient 11:77df6d7e65ae 527 break;
AzureIoTClient 11:77df6d7e65ae 528 }
Azure.IoT Build 6:c55b013dfc2a 529
Azure.IoT Build 6:c55b013dfc2a 530 // read cur bytes (might be less than requested)
AzureIoTClient 11:77df6d7e65ae 531 size -= (size_t)cur;
Azure.IoT Build 6:c55b013dfc2a 532 offset += cur;
Azure.IoT Build 6:c55b013dfc2a 533 }
Azure.IoT Build 6:c55b013dfc2a 534
Azure.IoT Build 6:c55b013dfc2a 535 return offset;
Azure.IoT Build 6:c55b013dfc2a 536 }
Azure.IoT Build 6:c55b013dfc2a 537
AzureIoTClient 13:920e00014ee3 538 static int skipN(HTTP_HANDLE_DATA* http_instance, size_t n)
Azure.IoT Build 6:c55b013dfc2a 539 {
Azure.IoT Build 6:c55b013dfc2a 540 // read and abandon response content with specified length
Azure.IoT Build 6:c55b013dfc2a 541 // returns -1 in case of error.
AzureIoTClient 13:920e00014ee3 542
AzureIoTClient 13:920e00014ee3 543 int result;
AzureIoTClient 13:920e00014ee3 544
AzureIoTClient 13:920e00014ee3 545 if (http_instance == NULL)
AzureIoTClient 13:920e00014ee3 546 {
AzureIoTClient 13:920e00014ee3 547 LogError("Invalid HTTP instance");
AzureIoTClient 13:920e00014ee3 548 result = -1;
AzureIoTClient 13:920e00014ee3 549 }
AzureIoTClient 13:920e00014ee3 550 else
Azure.IoT Build 6:c55b013dfc2a 551 {
AzureIoTClient 13:920e00014ee3 552 /*Codes_SRS_HTTPAPI_COMPACT_21_076: [ The HTTPAPI_ExecuteRequest shall try to read the message with the response up to 20 times. ]*/
AzureIoTClient 13:920e00014ee3 553 int countRetry = MAX_RECEIVE_RETRY;
AzureIoTClient 13:920e00014ee3 554 result = (int)n;
AzureIoTClient 13:920e00014ee3 555 while (n > 0)
AzureIoTClient 13:920e00014ee3 556 {
AzureIoTClient 13:920e00014ee3 557 xio_dowork(http_instance->xio_handle);
Azure.IoT Build 6:c55b013dfc2a 558
AzureIoTClient 13:920e00014ee3 559 /* if any error was detected while receiving then simply break and report it */
AzureIoTClient 13:920e00014ee3 560 if (http_instance->is_io_error != 0)
AzureIoTClient 13:920e00014ee3 561 {
AzureIoTClient 13:920e00014ee3 562 LogError("xio reported error on dowork");
AzureIoTClient 13:920e00014ee3 563 result = -1;
AzureIoTClient 13:920e00014ee3 564 n = 0;
AzureIoTClient 13:920e00014ee3 565 }
AzureIoTClient 13:920e00014ee3 566 else
AzureIoTClient 13:920e00014ee3 567 {
AzureIoTClient 13:920e00014ee3 568 if (http_instance->received_bytes_count <= n)
AzureIoTClient 13:920e00014ee3 569 {
AzureIoTClient 13:920e00014ee3 570 n -= http_instance->received_bytes_count;
AzureIoTClient 13:920e00014ee3 571 http_instance->received_bytes_count = 0;
AzureIoTClient 13:920e00014ee3 572 }
AzureIoTClient 13:920e00014ee3 573 else
AzureIoTClient 13:920e00014ee3 574 {
AzureIoTClient 13:920e00014ee3 575 http_instance->received_bytes_count -= n;
AzureIoTClient 13:920e00014ee3 576 (void)memmove(http_instance->received_bytes, http_instance->received_bytes + n, http_instance->received_bytes_count);
AzureIoTClient 13:920e00014ee3 577 n = 0;
AzureIoTClient 13:920e00014ee3 578 }
AzureIoTClient 13:920e00014ee3 579
AzureIoTClient 13:920e00014ee3 580 if (n > 0)
AzureIoTClient 13:920e00014ee3 581 {
AzureIoTClient 13:920e00014ee3 582 if ((countRetry--) > 0)
AzureIoTClient 13:920e00014ee3 583 {
AzureIoTClient 13:920e00014ee3 584 /*Codes_SRS_HTTPAPI_COMPACT_21_078: [ The HTTPAPI_ExecuteRequest shall wait, at least, 100 milliseconds between retries. ]*/
AzureIoTClient 13:920e00014ee3 585 ThreadAPI_Sleep(RECEIVE_RETRY_INTERVAL_IN_MICROSECONDS);
AzureIoTClient 13:920e00014ee3 586 }
AzureIoTClient 13:920e00014ee3 587 else
AzureIoTClient 13:920e00014ee3 588 {
AzureIoTClient 13:920e00014ee3 589 /*Codes_SRS_HTTPAPI_COMPACT_21_077: [ If the HTTPAPI_ExecuteRequest retries 20 times to receive the message without success, it shall fail and return HTTPAPI_READ_DATA_FAILED. ]*/
AzureIoTClient 13:920e00014ee3 590 LogError("Timeout. The HTTP request is incomplete");
AzureIoTClient 13:920e00014ee3 591 n = 0;
AzureIoTClient 13:920e00014ee3 592 result = -1;
AzureIoTClient 13:920e00014ee3 593 }
AzureIoTClient 13:920e00014ee3 594 }
AzureIoTClient 13:920e00014ee3 595 }
AzureIoTClient 13:920e00014ee3 596 }
Azure.IoT Build 6:c55b013dfc2a 597 }
Azure.IoT Build 6:c55b013dfc2a 598
AzureIoTClient 13:920e00014ee3 599 return result;
Azure.IoT Build 6:c55b013dfc2a 600 }
Azure.IoT Build 6:c55b013dfc2a 601
AzureIoTClient 11:77df6d7e65ae 602
AzureIoTClient 11:77df6d7e65ae 603 /*Codes_SRS_HTTPAPI_COMPACT_21_021: [ The HTTPAPI_ExecuteRequest shall execute the http communtication with the provided host, sending a request and reciving the response. ]*/
AzureIoTClient 13:920e00014ee3 604 static HTTPAPI_RESULT OpenXIOConnection(HTTP_HANDLE_DATA* http_instance)
AzureIoTClient 11:77df6d7e65ae 605 {
AzureIoTClient 11:77df6d7e65ae 606 HTTPAPI_RESULT result;
AzureIoTClient 11:77df6d7e65ae 607
AzureIoTClient 13:920e00014ee3 608 if (http_instance->is_connected != 0)
AzureIoTClient 11:77df6d7e65ae 609 {
AzureIoTClient 11:77df6d7e65ae 610 /*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
AzureIoTClient 11:77df6d7e65ae 611 result = HTTPAPI_OK;
AzureIoTClient 11:77df6d7e65ae 612 }
AzureIoTClient 11:77df6d7e65ae 613 else
AzureIoTClient 11:77df6d7e65ae 614 {
AzureIoTClient 11:77df6d7e65ae 615 /*Codes_SRS_HTTPAPI_COMPACT_21_022: [ If a Certificate was provided, the HTTPAPI_ExecuteRequest shall set this option on the transport layer. ]*/
AzureIoTClient 13:920e00014ee3 616 if ((http_instance->certificate != NULL) &&
AzureIoTClient 13:920e00014ee3 617 (xio_setoption(http_instance->xio_handle, "TrustedCerts", http_instance->certificate) != 0))
AzureIoTClient 11:77df6d7e65ae 618 {
AzureIoTClient 11:77df6d7e65ae 619 /*Codes_SRS_HTTPAPI_COMPACT_21_023: [ If the transport failed setting the Certificate, the HTTPAPI_ExecuteRequest shall not send any request and return HTTPAPI_SET_OPTION_FAILED. ]*/
AzureIoTClient 11:77df6d7e65ae 620 result = HTTPAPI_SET_OPTION_FAILED;
AzureIoTClient 11:77df6d7e65ae 621 LogInfo("Could not load certificate");
AzureIoTClient 11:77df6d7e65ae 622 }
AzureIoTClient 11:77df6d7e65ae 623 else
AzureIoTClient 11:77df6d7e65ae 624 {
AzureIoTClient 11:77df6d7e65ae 625 /*Codes_SRS_HTTPAPI_COMPACT_21_024: [ The HTTPAPI_ExecuteRequest shall open the transport connection with the host to send the request. ]*/
AzureIoTClient 13:920e00014ee3 626 if (xio_open(http_instance->xio_handle, on_io_open_complete, http_instance, on_bytes_received, http_instance, on_io_error, http_instance) != 0)
AzureIoTClient 11:77df6d7e65ae 627 {
AzureIoTClient 11:77df6d7e65ae 628 /*Codes_SRS_HTTPAPI_COMPACT_21_025: [ If the open process failed, the HTTPAPI_ExecuteRequest shall not send any request and return HTTPAPI_OPEN_REQUEST_FAILED. ]*/
AzureIoTClient 11:77df6d7e65ae 629 result = HTTPAPI_OPEN_REQUEST_FAILED;
AzureIoTClient 11:77df6d7e65ae 630 }
AzureIoTClient 11:77df6d7e65ae 631 else
AzureIoTClient 11:77df6d7e65ae 632 {
AzureIoTClient 11:77df6d7e65ae 633 /*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
AzureIoTClient 11:77df6d7e65ae 634 result = HTTPAPI_OK;
AzureIoTClient 13:920e00014ee3 635 while ((http_instance->is_connected == 0) &&
AzureIoTClient 13:920e00014ee3 636 (http_instance->is_io_error == 0))
AzureIoTClient 11:77df6d7e65ae 637 {
AzureIoTClient 13:920e00014ee3 638 xio_dowork(http_instance->xio_handle);
AzureIoTClient 11:77df6d7e65ae 639 LogInfo("Waiting for TLS connection");
AzureIoTClient 13:920e00014ee3 640 ThreadAPI_Sleep(OPEN_RETRY_INTERVAL_IN_MICROSECONDS);
AzureIoTClient 11:77df6d7e65ae 641 }
AzureIoTClient 11:77df6d7e65ae 642 }
AzureIoTClient 11:77df6d7e65ae 643 }
AzureIoTClient 11:77df6d7e65ae 644 }
AzureIoTClient 11:77df6d7e65ae 645
AzureIoTClient 13:920e00014ee3 646 if ((http_instance->is_io_error != 0) && (result == HTTPAPI_OK))
AzureIoTClient 11:77df6d7e65ae 647 {
AzureIoTClient 11:77df6d7e65ae 648 /*Codes_SRS_HTTPAPI_COMPACT_21_025: [ If the open process failed, the HTTPAPI_ExecuteRequest shall not send any request and return HTTPAPI_OPEN_REQUEST_FAILED. ]*/
AzureIoTClient 11:77df6d7e65ae 649 result = HTTPAPI_OPEN_REQUEST_FAILED;
AzureIoTClient 11:77df6d7e65ae 650 }
AzureIoTClient 11:77df6d7e65ae 651
AzureIoTClient 11:77df6d7e65ae 652 return result;
AzureIoTClient 11:77df6d7e65ae 653 }
AzureIoTClient 11:77df6d7e65ae 654
AzureIoTClient 11:77df6d7e65ae 655 /*Codes_SRS_HTTPAPI_COMPACT_21_035: [ The HTTPAPI_ExecuteRequest shall execute resquest for types `GET`, `POST`, `PUT`, `DELETE`, `PATCH`. ]*/
AzureIoTClient 11:77df6d7e65ae 656 const char httpapiRequestString[5][7] = { "GET", "POST", "PUT", "DELETE", "PATCH" };
AzureIoTClient 11:77df6d7e65ae 657 const char* get_request_type(HTTPAPI_REQUEST_TYPE requestType)
AzureIoTClient 11:77df6d7e65ae 658 {
AzureIoTClient 11:77df6d7e65ae 659 return (const char*)httpapiRequestString[requestType];
AzureIoTClient 11:77df6d7e65ae 660 }
AzureIoTClient 11:77df6d7e65ae 661
AzureIoTClient 11:77df6d7e65ae 662 /*Codes_SRS_HTTPAPI_COMPACT_21_026: [ If the open process succeed, the HTTPAPI_ExecuteRequest shall send the request message to the host. ]*/
AzureIoTClient 13:920e00014ee3 663 static HTTPAPI_RESULT SendHeadsToXIO(HTTP_HANDLE_DATA* http_instance, HTTPAPI_REQUEST_TYPE requestType, const char* relativePath, HTTP_HEADERS_HANDLE httpHeadersHandle, size_t headersCount)
AzureIoTClient 11:77df6d7e65ae 664 {
AzureIoTClient 11:77df6d7e65ae 665 HTTPAPI_RESULT result;
AzureIoTClient 11:77df6d7e65ae 666 char buf[TEMP_BUFFER_SIZE];
AzureIoTClient 11:77df6d7e65ae 667 int ret;
AzureIoTClient 11:77df6d7e65ae 668
AzureIoTClient 11:77df6d7e65ae 669 //Send request
AzureIoTClient 11:77df6d7e65ae 670 /*Codes_SRS_HTTPAPI_COMPACT_21_038: [ The HTTPAPI_ExecuteRequest shall execute the resquest for the path in relativePath parameter. ]*/
AzureIoTClient 11:77df6d7e65ae 671 /*Codes_SRS_HTTPAPI_COMPACT_21_036: [ The request type shall be provided in the parameter requestType. ]*/
AzureIoTClient 11:77df6d7e65ae 672 if (((ret = snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\n", get_request_type(requestType), relativePath)) < 0) ||
AzureIoTClient 11:77df6d7e65ae 673 (ret >= sizeof(buf)))
AzureIoTClient 11:77df6d7e65ae 674 {
AzureIoTClient 11:77df6d7e65ae 675 /*Codes_SRS_HTTPAPI_COMPACT_21_027: [ If the HTTPAPI_ExecuteRequest cannot create a buffer to send the request, it shall not send any request and return HTTPAPI_STRING_PROCESSING_ERROR. ]*/
AzureIoTClient 11:77df6d7e65ae 676 result = HTTPAPI_STRING_PROCESSING_ERROR;
AzureIoTClient 11:77df6d7e65ae 677 }
AzureIoTClient 13:920e00014ee3 678 else if (xio_send(http_instance->xio_handle, (const unsigned char*)buf, strlen(buf), NULL, NULL) != 0)
AzureIoTClient 13:920e00014ee3 679 {
AzureIoTClient 11:77df6d7e65ae 680 /*Codes_SRS_HTTPAPI_COMPACT_21_028: [ If the HTTPAPI_ExecuteRequest cannot send the request header, it shall return HTTPAPI_HTTP_HEADERS_FAILED. ]*/
AzureIoTClient 11:77df6d7e65ae 681 result = HTTPAPI_SEND_REQUEST_FAILED;
AzureIoTClient 11:77df6d7e65ae 682 }
AzureIoTClient 11:77df6d7e65ae 683 else
AzureIoTClient 11:77df6d7e65ae 684 {
AzureIoTClient 11:77df6d7e65ae 685 //Send default headers
AzureIoTClient 11:77df6d7e65ae 686 /*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
AzureIoTClient 11:77df6d7e65ae 687 result = HTTPAPI_OK;
AzureIoTClient 11:77df6d7e65ae 688 for (size_t i = 0; ((i < headersCount) && (result == HTTPAPI_OK)); i++)
AzureIoTClient 11:77df6d7e65ae 689 {
AzureIoTClient 11:77df6d7e65ae 690 char* header;
AzureIoTClient 11:77df6d7e65ae 691 if (HTTPHeaders_GetHeader(httpHeadersHandle, i, &header) != HTTP_HEADERS_OK)
AzureIoTClient 11:77df6d7e65ae 692 {
AzureIoTClient 11:77df6d7e65ae 693 /*Codes_SRS_HTTPAPI_COMPACT_21_027: [ If the HTTPAPI_ExecuteRequest cannot create a buffer to send the request, it shall not send any request and return HTTPAPI_STRING_PROCESSING_ERROR. ]*/
AzureIoTClient 11:77df6d7e65ae 694 result = HTTPAPI_STRING_PROCESSING_ERROR;
AzureIoTClient 11:77df6d7e65ae 695 }
AzureIoTClient 11:77df6d7e65ae 696 else
AzureIoTClient 11:77df6d7e65ae 697 {
AzureIoTClient 13:920e00014ee3 698 if (xio_send(http_instance->xio_handle, (const unsigned char*)header, strlen(header), NULL, NULL) != 0)
AzureIoTClient 13:920e00014ee3 699 {
AzureIoTClient 11:77df6d7e65ae 700 /*Codes_SRS_HTTPAPI_COMPACT_21_028: [ If the HTTPAPI_ExecuteRequest cannot send the request header, it shall return HTTPAPI_HTTP_HEADERS_FAILED. ]*/
AzureIoTClient 11:77df6d7e65ae 701 result = HTTPAPI_SEND_REQUEST_FAILED;
AzureIoTClient 11:77df6d7e65ae 702 }
AzureIoTClient 13:920e00014ee3 703 if (xio_send(http_instance->xio_handle, (const unsigned char*)"\r\n", (size_t)2, NULL, NULL) != 0)
AzureIoTClient 13:920e00014ee3 704 {
AzureIoTClient 11:77df6d7e65ae 705 /*Codes_SRS_HTTPAPI_COMPACT_21_028: [ If the HTTPAPI_ExecuteRequest cannot send the request header, it shall return HTTPAPI_HTTP_HEADERS_FAILED. ]*/
AzureIoTClient 11:77df6d7e65ae 706 result = HTTPAPI_SEND_REQUEST_FAILED;
AzureIoTClient 11:77df6d7e65ae 707 }
AzureIoTClient 11:77df6d7e65ae 708 free(header);
AzureIoTClient 11:77df6d7e65ae 709 }
AzureIoTClient 11:77df6d7e65ae 710 }
AzureIoTClient 11:77df6d7e65ae 711
AzureIoTClient 11:77df6d7e65ae 712 //Close headers
AzureIoTClient 13:920e00014ee3 713 if (xio_send(http_instance->xio_handle, (const unsigned char*)"\r\n", (size_t)2, NULL, NULL) != 0)
AzureIoTClient 13:920e00014ee3 714 {
AzureIoTClient 11:77df6d7e65ae 715 /*Codes_SRS_HTTPAPI_COMPACT_21_028: [ If the HTTPAPI_ExecuteRequest cannot send the request header, it shall return HTTPAPI_HTTP_HEADERS_FAILED. ]*/
AzureIoTClient 11:77df6d7e65ae 716 result = HTTPAPI_SEND_REQUEST_FAILED;
AzureIoTClient 11:77df6d7e65ae 717 }
AzureIoTClient 11:77df6d7e65ae 718 }
AzureIoTClient 11:77df6d7e65ae 719 return result;
AzureIoTClient 11:77df6d7e65ae 720 }
AzureIoTClient 11:77df6d7e65ae 721
AzureIoTClient 11:77df6d7e65ae 722 /*Codes_SRS_HTTPAPI_COMPACT_21_042: [ The request can contain the a content message, provided in content parameter. ]*/
AzureIoTClient 13:920e00014ee3 723 static HTTPAPI_RESULT SendContentToXIO(HTTP_HANDLE_DATA* http_instance, const unsigned char* content, size_t contentLength)
AzureIoTClient 11:77df6d7e65ae 724 {
AzureIoTClient 11:77df6d7e65ae 725 HTTPAPI_RESULT result;
AzureIoTClient 11:77df6d7e65ae 726
AzureIoTClient 11:77df6d7e65ae 727 //Send data (if available)
AzureIoTClient 11:77df6d7e65ae 728 /*Codes_SRS_HTTPAPI_COMPACT_21_045: [ If the contentLength is lower than one, the HTTPAPI_ExecuteRequest shall send the request without content. ]*/
AzureIoTClient 11:77df6d7e65ae 729 if (content && contentLength > 0)
AzureIoTClient 11:77df6d7e65ae 730 {
AzureIoTClient 11:77df6d7e65ae 731 /*Codes_SRS_HTTPAPI_COMPACT_21_044: [ If the content is not NULL, the number of bytes in the content shall be provided in contentLength parameter. ]*/
AzureIoTClient 13:920e00014ee3 732 if (xio_send(http_instance->xio_handle, content, contentLength, NULL, NULL) != 0)
AzureIoTClient 13:920e00014ee3 733 {
AzureIoTClient 11:77df6d7e65ae 734 /*Codes_SRS_HTTPAPI_COMPACT_21_029: [ If the HTTPAPI_ExecuteRequest cannot send the buffer with the request, it shall return HTTPAPI_SEND_REQUEST_FAILED. ]*/
AzureIoTClient 11:77df6d7e65ae 735 result = HTTPAPI_SEND_REQUEST_FAILED;
AzureIoTClient 11:77df6d7e65ae 736 }
AzureIoTClient 11:77df6d7e65ae 737 else
AzureIoTClient 11:77df6d7e65ae 738 {
AzureIoTClient 11:77df6d7e65ae 739 /*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
AzureIoTClient 11:77df6d7e65ae 740 result = HTTPAPI_OK;
AzureIoTClient 11:77df6d7e65ae 741 }
AzureIoTClient 11:77df6d7e65ae 742 }
AzureIoTClient 11:77df6d7e65ae 743 else
AzureIoTClient 11:77df6d7e65ae 744 {
AzureIoTClient 11:77df6d7e65ae 745 /*Codes_SRS_HTTPAPI_COMPACT_21_043: [ If the content is NULL, the HTTPAPI_ExecuteRequest shall send the request without content. ]*/
AzureIoTClient 11:77df6d7e65ae 746 /*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
AzureIoTClient 11:77df6d7e65ae 747 result = HTTPAPI_OK;
AzureIoTClient 11:77df6d7e65ae 748 }
AzureIoTClient 11:77df6d7e65ae 749 return result;
AzureIoTClient 11:77df6d7e65ae 750 }
AzureIoTClient 11:77df6d7e65ae 751
AzureIoTClient 11:77df6d7e65ae 752 /*Codes_SRS_HTTPAPI_COMPACT_21_030: [ At the end of the transmission, the HTTPAPI_ExecuteRequest shall receive the response from the host. ]*/
AzureIoTClient 13:920e00014ee3 753 static HTTPAPI_RESULT RecieveHeaderFromXIO(HTTP_HANDLE_DATA* http_instance, unsigned int* statusCode)
AzureIoTClient 11:77df6d7e65ae 754 {
AzureIoTClient 11:77df6d7e65ae 755 HTTPAPI_RESULT result;
AzureIoTClient 11:77df6d7e65ae 756 char buf[TEMP_BUFFER_SIZE];
AzureIoTClient 11:77df6d7e65ae 757 int ret;
AzureIoTClient 11:77df6d7e65ae 758
AzureIoTClient 11:77df6d7e65ae 759 //Receive response
AzureIoTClient 13:920e00014ee3 760 if (readLine(http_instance, buf, TEMP_BUFFER_SIZE) < 0)
AzureIoTClient 11:77df6d7e65ae 761 {
AzureIoTClient 11:77df6d7e65ae 762 /*Codes_SRS_HTTPAPI_COMPACT_21_032: [ If the HTTPAPI_ExecuteRequest cannot read the message with the request result, it shall return HTTPAPI_READ_DATA_FAILED. ]*/
AzureIoTClient 13:920e00014ee3 763 /*Codes_SRS_HTTPAPI_COMPACT_21_077: [ If the HTTPAPI_ExecuteRequest retries 20 times to receive the message without success, it shall fail and return HTTPAPI_READ_DATA_FAILED. ]*/
AzureIoTClient 13:920e00014ee3 764 result = HTTPAPI_READ_DATA_FAILED;
AzureIoTClient 11:77df6d7e65ae 765 }
AzureIoTClient 11:77df6d7e65ae 766 //Parse HTTP response
AzureIoTClient 11:77df6d7e65ae 767 else if (ParseHttpResponse(buf, &ret) != 1)
AzureIoTClient 11:77df6d7e65ae 768 {
AzureIoTClient 11:77df6d7e65ae 769 //Cannot match string, error
AzureIoTClient 11:77df6d7e65ae 770 /*Codes_SRS_HTTPAPI_COMPACT_21_055: [ If the HTTPAPI_ExecuteRequest cannot parser the recived message, it shall return HTTPAPI_RECEIVE_RESPONSE_FAILED. ]*/
AzureIoTClient 13:920e00014ee3 771 LogInfo("Not a correct HTTP answer");
AzureIoTClient 11:77df6d7e65ae 772 result = HTTPAPI_RECEIVE_RESPONSE_FAILED;
AzureIoTClient 11:77df6d7e65ae 773 }
AzureIoTClient 11:77df6d7e65ae 774 else
AzureIoTClient 11:77df6d7e65ae 775 {
AzureIoTClient 11:77df6d7e65ae 776 /*Codes_SRS_HTTPAPI_COMPACT_21_046: [ The HTTPAPI_ExecuteRequest shall return the http status reported by the host in the received response. ]*/
AzureIoTClient 11:77df6d7e65ae 777 /*Codes_SRS_HTTPAPI_COMPACT_21_048: [ If the statusCode is NULL, the HTTPAPI_ExecuteRequest shall report not report any status. ]*/
AzureIoTClient 11:77df6d7e65ae 778 if (statusCode)
AzureIoTClient 11:77df6d7e65ae 779 {
AzureIoTClient 11:77df6d7e65ae 780 /*Codes_SRS_HTTPAPI_COMPACT_21_047: [ The HTTPAPI_ExecuteRequest shall report the status in the statusCode parameter. ]*/
AzureIoTClient 11:77df6d7e65ae 781 *statusCode = ret;
AzureIoTClient 11:77df6d7e65ae 782 }
AzureIoTClient 11:77df6d7e65ae 783 /*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
AzureIoTClient 11:77df6d7e65ae 784 result = HTTPAPI_OK;
AzureIoTClient 11:77df6d7e65ae 785 }
AzureIoTClient 11:77df6d7e65ae 786
AzureIoTClient 11:77df6d7e65ae 787 return result;
AzureIoTClient 11:77df6d7e65ae 788 }
AzureIoTClient 11:77df6d7e65ae 789
AzureIoTClient 13:920e00014ee3 790 static HTTPAPI_RESULT RecieveContentInfoFromXIO(HTTP_HANDLE_DATA* http_instance, HTTP_HEADERS_HANDLE responseHeadersHandle, size_t* bodyLength, bool* chunked)
AzureIoTClient 11:77df6d7e65ae 791 {
AzureIoTClient 11:77df6d7e65ae 792 HTTPAPI_RESULT result;
AzureIoTClient 11:77df6d7e65ae 793 char buf[TEMP_BUFFER_SIZE];
AzureIoTClient 11:77df6d7e65ae 794 const char* substr;
AzureIoTClient 11:77df6d7e65ae 795 char* whereIsColon;
AzureIoTClient 11:77df6d7e65ae 796 int lengthInMsg;
AzureIoTClient 11:77df6d7e65ae 797 const char* ContentLength = "content-length:";
AzureIoTClient 11:77df6d7e65ae 798 const int ContentLengthSize = 16;
AzureIoTClient 11:77df6d7e65ae 799 const char* TransferEncoding = "transfer-encoding:";
AzureIoTClient 11:77df6d7e65ae 800 const int TransferEncodingSize = 19;
AzureIoTClient 11:77df6d7e65ae 801 const char* Chunked = "chunked";
AzureIoTClient 11:77df6d7e65ae 802 const int ChunkedSize = 8;
AzureIoTClient 11:77df6d7e65ae 803
AzureIoTClient 11:77df6d7e65ae 804 //Read HTTP response headers
AzureIoTClient 13:920e00014ee3 805 if (readLine(http_instance, buf, sizeof(buf)) < 0)
AzureIoTClient 11:77df6d7e65ae 806 {
AzureIoTClient 11:77df6d7e65ae 807 /*Codes_SRS_HTTPAPI_COMPACT_21_032: [ If the HTTPAPI_ExecuteRequest cannot read the message with the request result, it shall return HTTPAPI_READ_DATA_FAILED. ]*/
AzureIoTClient 13:920e00014ee3 808 /*Codes_SRS_HTTPAPI_COMPACT_21_077: [ If the HTTPAPI_ExecuteRequest retries 20 times to receive the message without success, it shall fail and return HTTPAPI_READ_DATA_FAILED. ]*/
AzureIoTClient 13:920e00014ee3 809 result = HTTPAPI_READ_DATA_FAILED;
AzureIoTClient 11:77df6d7e65ae 810 }
AzureIoTClient 11:77df6d7e65ae 811 else
AzureIoTClient 11:77df6d7e65ae 812 {
AzureIoTClient 11:77df6d7e65ae 813 /*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
AzureIoTClient 11:77df6d7e65ae 814 result = HTTPAPI_OK;
AzureIoTClient 11:77df6d7e65ae 815
AzureIoTClient 11:77df6d7e65ae 816 while (*buf && (result == HTTPAPI_OK))
AzureIoTClient 11:77df6d7e65ae 817 {
AzureIoTClient 11:77df6d7e65ae 818 if (InternStrnicmp(buf, ContentLength, ContentLengthSize) == 0)
AzureIoTClient 11:77df6d7e65ae 819 {
AzureIoTClient 11:77df6d7e65ae 820 substr = buf + ContentLengthSize - 1;
AzureIoTClient 11:77df6d7e65ae 821 if (ParseStringToDecimal(substr, &lengthInMsg) != 1)
AzureIoTClient 11:77df6d7e65ae 822 {
AzureIoTClient 11:77df6d7e65ae 823 /*Codes_SRS_HTTPAPI_COMPACT_21_032: [ If the HTTPAPI_ExecuteRequest cannot read the message with the request result, it shall return HTTPAPI_READ_DATA_FAILED. ]*/
AzureIoTClient 11:77df6d7e65ae 824 result = HTTPAPI_READ_DATA_FAILED;
AzureIoTClient 11:77df6d7e65ae 825 }
AzureIoTClient 11:77df6d7e65ae 826 else
AzureIoTClient 11:77df6d7e65ae 827 {
AzureIoTClient 11:77df6d7e65ae 828 (*bodyLength) = (size_t)lengthInMsg;
AzureIoTClient 11:77df6d7e65ae 829 }
AzureIoTClient 11:77df6d7e65ae 830 }
AzureIoTClient 11:77df6d7e65ae 831 else if (InternStrnicmp(buf, TransferEncoding, TransferEncodingSize) == 0)
AzureIoTClient 11:77df6d7e65ae 832 {
AzureIoTClient 11:77df6d7e65ae 833 substr = buf + TransferEncodingSize - 1;
AzureIoTClient 11:77df6d7e65ae 834
AzureIoTClient 11:77df6d7e65ae 835 while (isspace(*substr)) substr++;
AzureIoTClient 11:77df6d7e65ae 836
AzureIoTClient 11:77df6d7e65ae 837 if (InternStrnicmp(substr, Chunked, ChunkedSize) == 0)
AzureIoTClient 11:77df6d7e65ae 838 {
AzureIoTClient 11:77df6d7e65ae 839 (*chunked) = true;
AzureIoTClient 11:77df6d7e65ae 840 }
AzureIoTClient 11:77df6d7e65ae 841 }
AzureIoTClient 11:77df6d7e65ae 842
AzureIoTClient 11:77df6d7e65ae 843 if (result == HTTPAPI_OK)
AzureIoTClient 11:77df6d7e65ae 844 {
AzureIoTClient 11:77df6d7e65ae 845 whereIsColon = strchr((char*)buf, ':');
AzureIoTClient 11:77df6d7e65ae 846 /*Codes_SRS_HTTPAPI_COMPACT_21_049: [ If responseHeadersHandle is provide, the HTTPAPI_ExecuteRequest shall prepare a Response Header usign the HTTPHeaders_AddHeaderNameValuePair. ]*/
AzureIoTClient 11:77df6d7e65ae 847 if (whereIsColon && (responseHeadersHandle != NULL))
AzureIoTClient 11:77df6d7e65ae 848 {
AzureIoTClient 11:77df6d7e65ae 849 *whereIsColon = '\0';
AzureIoTClient 11:77df6d7e65ae 850 HTTPHeaders_AddHeaderNameValuePair(responseHeadersHandle, buf, whereIsColon + 1);
AzureIoTClient 11:77df6d7e65ae 851 }
AzureIoTClient 11:77df6d7e65ae 852
AzureIoTClient 13:920e00014ee3 853 if (readLine(http_instance, buf, sizeof(buf)) < 0)
AzureIoTClient 11:77df6d7e65ae 854 {
AzureIoTClient 11:77df6d7e65ae 855 /*Codes_SRS_HTTPAPI_COMPACT_21_032: [ If the HTTPAPI_ExecuteRequest cannot read the message with the request result, it shall return HTTPAPI_READ_DATA_FAILED. ]*/
AzureIoTClient 13:920e00014ee3 856 /*Codes_SRS_HTTPAPI_COMPACT_21_077: [ If the HTTPAPI_ExecuteRequest retries 20 times to receive the message without success, it shall fail and return HTTPAPI_READ_DATA_FAILED. ]*/
AzureIoTClient 13:920e00014ee3 857 result = HTTPAPI_READ_DATA_FAILED;
AzureIoTClient 11:77df6d7e65ae 858 }
AzureIoTClient 11:77df6d7e65ae 859 }
AzureIoTClient 11:77df6d7e65ae 860 }
AzureIoTClient 11:77df6d7e65ae 861 }
AzureIoTClient 11:77df6d7e65ae 862
AzureIoTClient 11:77df6d7e65ae 863 return result;
AzureIoTClient 11:77df6d7e65ae 864 }
AzureIoTClient 11:77df6d7e65ae 865
AzureIoTClient 13:920e00014ee3 866 static HTTPAPI_RESULT ReadHTTPResponseBodyFromXIO(HTTP_HANDLE_DATA* http_instance, size_t bodyLength, bool chunked, BUFFER_HANDLE responseContent)
AzureIoTClient 11:77df6d7e65ae 867 {
AzureIoTClient 11:77df6d7e65ae 868 HTTPAPI_RESULT result;
AzureIoTClient 11:77df6d7e65ae 869 char buf[TEMP_BUFFER_SIZE];
AzureIoTClient 11:77df6d7e65ae 870 const unsigned char* receivedContent;
AzureIoTClient 11:77df6d7e65ae 871
AzureIoTClient 11:77df6d7e65ae 872 //Read HTTP response body
AzureIoTClient 11:77df6d7e65ae 873 if (!chunked)
AzureIoTClient 11:77df6d7e65ae 874 {
AzureIoTClient 11:77df6d7e65ae 875 if (bodyLength)
AzureIoTClient 11:77df6d7e65ae 876 {
AzureIoTClient 11:77df6d7e65ae 877 if (responseContent != NULL)
AzureIoTClient 11:77df6d7e65ae 878 {
AzureIoTClient 11:77df6d7e65ae 879 if (BUFFER_pre_build(responseContent, bodyLength) != 0)
AzureIoTClient 11:77df6d7e65ae 880 {
AzureIoTClient 11:77df6d7e65ae 881 /*Codes_SRS_HTTPAPI_COMPACT_21_052: [ If any memory allocation get fail, the HTTPAPI_ExecuteRequest shall return HTTPAPI_ALLOC_FAILED. ]*/
AzureIoTClient 11:77df6d7e65ae 882 result = HTTPAPI_ALLOC_FAILED;
AzureIoTClient 11:77df6d7e65ae 883 }
AzureIoTClient 11:77df6d7e65ae 884 else if (BUFFER_content(responseContent, &receivedContent) != 0)
AzureIoTClient 11:77df6d7e65ae 885 {
AzureIoTClient 11:77df6d7e65ae 886 (void)BUFFER_unbuild(responseContent);
AzureIoTClient 11:77df6d7e65ae 887
AzureIoTClient 11:77df6d7e65ae 888 /*Codes_SRS_HTTPAPI_COMPACT_21_052: [ If any memory allocation get fail, the HTTPAPI_ExecuteRequest shall return HTTPAPI_ALLOC_FAILED. ]*/
AzureIoTClient 11:77df6d7e65ae 889 result = HTTPAPI_ALLOC_FAILED;
AzureIoTClient 11:77df6d7e65ae 890 }
AzureIoTClient 13:920e00014ee3 891 else if (readChunk(http_instance, (char*)receivedContent, bodyLength) < 0)
AzureIoTClient 11:77df6d7e65ae 892 {
AzureIoTClient 11:77df6d7e65ae 893 /*Codes_SRS_HTTPAPI_COMPACT_21_032: [ If the HTTPAPI_ExecuteRequest cannot read the message with the request result, it shall return HTTPAPI_READ_DATA_FAILED. ]*/
AzureIoTClient 11:77df6d7e65ae 894 result = HTTPAPI_READ_DATA_FAILED;
AzureIoTClient 11:77df6d7e65ae 895 }
AzureIoTClient 11:77df6d7e65ae 896 else
AzureIoTClient 11:77df6d7e65ae 897 {
AzureIoTClient 11:77df6d7e65ae 898 /*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
AzureIoTClient 11:77df6d7e65ae 899 result = HTTPAPI_OK;
AzureIoTClient 11:77df6d7e65ae 900 }
AzureIoTClient 11:77df6d7e65ae 901 }
AzureIoTClient 13:920e00014ee3 902 else
AzureIoTClient 13:920e00014ee3 903 {
AzureIoTClient 13:920e00014ee3 904 /*Codes_SRS_HTTPAPI_COMPACT_21_051: [ If the responseContent is NULL, the HTTPAPI_ExecuteRequest shall ignore any content in the response. ]*/
AzureIoTClient 13:920e00014ee3 905 if (skipN(http_instance, bodyLength) < 0)
AzureIoTClient 13:920e00014ee3 906 {
AzureIoTClient 13:920e00014ee3 907 /*Codes_SRS_HTTPAPI_COMPACT_21_077: [ If the HTTPAPI_ExecuteRequest retries 20 times to receive the message without success, it shall fail and return HTTPAPI_READ_DATA_FAILED. ]*/
AzureIoTClient 13:920e00014ee3 908 result = HTTPAPI_READ_DATA_FAILED;
AzureIoTClient 13:920e00014ee3 909 }
AzureIoTClient 13:920e00014ee3 910 else
AzureIoTClient 13:920e00014ee3 911 {
AzureIoTClient 13:920e00014ee3 912 result = HTTPAPI_OK;
AzureIoTClient 13:920e00014ee3 913 }
AzureIoTClient 13:920e00014ee3 914 }
AzureIoTClient 11:77df6d7e65ae 915 }
AzureIoTClient 11:77df6d7e65ae 916 else
AzureIoTClient 11:77df6d7e65ae 917 {
AzureIoTClient 11:77df6d7e65ae 918 /*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
AzureIoTClient 11:77df6d7e65ae 919 result = HTTPAPI_OK;
AzureIoTClient 11:77df6d7e65ae 920 }
AzureIoTClient 11:77df6d7e65ae 921 }
AzureIoTClient 11:77df6d7e65ae 922 else
AzureIoTClient 11:77df6d7e65ae 923 {
AzureIoTClient 11:77df6d7e65ae 924 size_t size = 0;
AzureIoTClient 11:77df6d7e65ae 925 /*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
AzureIoTClient 11:77df6d7e65ae 926 result = HTTPAPI_OK;
AzureIoTClient 11:77df6d7e65ae 927 while (result == HTTPAPI_OK)
AzureIoTClient 11:77df6d7e65ae 928 {
AzureIoTClient 11:77df6d7e65ae 929 size_t chunkSize;
AzureIoTClient 13:920e00014ee3 930 if (readLine(http_instance, buf, sizeof(buf)) < 0) // read [length in hex]/r/n
AzureIoTClient 11:77df6d7e65ae 931 {
AzureIoTClient 11:77df6d7e65ae 932 /*Codes_SRS_HTTPAPI_COMPACT_21_032: [ If the HTTPAPI_ExecuteRequest cannot read the message with the request result, it shall return HTTPAPI_READ_DATA_FAILED. ]*/
AzureIoTClient 13:920e00014ee3 933 /*Codes_SRS_HTTPAPI_COMPACT_21_077: [ If the HTTPAPI_ExecuteRequest retries 20 times to receive the message without success, it shall fail and return HTTPAPI_READ_DATA_FAILED. ]*/
AzureIoTClient 13:920e00014ee3 934 result = HTTPAPI_READ_DATA_FAILED;
AzureIoTClient 11:77df6d7e65ae 935 }
AzureIoTClient 11:77df6d7e65ae 936 else if (ParseStringToHexadecimal(buf, &chunkSize) != 1) // chunkSize is length of next line (/r/n is not counted)
AzureIoTClient 11:77df6d7e65ae 937 {
AzureIoTClient 11:77df6d7e65ae 938 //Cannot match string, error
AzureIoTClient 11:77df6d7e65ae 939 /*Codes_SRS_HTTPAPI_COMPACT_21_055: [ If the HTTPAPI_ExecuteRequest cannot parser the recived message, it shall return HTTPAPI_RECEIVE_RESPONSE_FAILED. ]*/
AzureIoTClient 11:77df6d7e65ae 940 result = HTTPAPI_RECEIVE_RESPONSE_FAILED;
AzureIoTClient 11:77df6d7e65ae 941 }
AzureIoTClient 11:77df6d7e65ae 942 else if (chunkSize == 0)
AzureIoTClient 11:77df6d7e65ae 943 {
AzureIoTClient 11:77df6d7e65ae 944 // 0 length means next line is just '\r\n' and end of chunks
AzureIoTClient 13:920e00014ee3 945 if (readChunk(http_instance, (char*)buf, (size_t)2) < 0
AzureIoTClient 11:77df6d7e65ae 946 || buf[0] != '\r' || buf[1] != '\n') // skip /r/n
AzureIoTClient 11:77df6d7e65ae 947 {
AzureIoTClient 11:77df6d7e65ae 948 (void)BUFFER_unbuild(responseContent);
AzureIoTClient 11:77df6d7e65ae 949
AzureIoTClient 11:77df6d7e65ae 950 result = HTTPAPI_READ_DATA_FAILED;
AzureIoTClient 11:77df6d7e65ae 951 }
AzureIoTClient 11:77df6d7e65ae 952 break;
AzureIoTClient 11:77df6d7e65ae 953 }
AzureIoTClient 11:77df6d7e65ae 954 else
AzureIoTClient 11:77df6d7e65ae 955 {
AzureIoTClient 11:77df6d7e65ae 956 if (responseContent != NULL)
AzureIoTClient 11:77df6d7e65ae 957 {
AzureIoTClient 11:77df6d7e65ae 958 if (BUFFER_enlarge(responseContent, chunkSize) != 0)
AzureIoTClient 11:77df6d7e65ae 959 {
AzureIoTClient 11:77df6d7e65ae 960 (void)BUFFER_unbuild(responseContent);
AzureIoTClient 11:77df6d7e65ae 961
AzureIoTClient 11:77df6d7e65ae 962 /*Codes_SRS_HTTPAPI_COMPACT_21_052: [ If any memory allocation get fail, the HTTPAPI_ExecuteRequest shall return HTTPAPI_ALLOC_FAILED. ]*/
AzureIoTClient 11:77df6d7e65ae 963 result = HTTPAPI_ALLOC_FAILED;
AzureIoTClient 11:77df6d7e65ae 964 }
AzureIoTClient 11:77df6d7e65ae 965 else if (BUFFER_content(responseContent, &receivedContent) != 0)
AzureIoTClient 11:77df6d7e65ae 966 {
AzureIoTClient 11:77df6d7e65ae 967 (void)BUFFER_unbuild(responseContent);
AzureIoTClient 11:77df6d7e65ae 968
AzureIoTClient 11:77df6d7e65ae 969 /*Codes_SRS_HTTPAPI_COMPACT_21_052: [ If any memory allocation get fail, the HTTPAPI_ExecuteRequest shall return HTTPAPI_ALLOC_FAILED. ]*/
AzureIoTClient 11:77df6d7e65ae 970 result = HTTPAPI_ALLOC_FAILED;
AzureIoTClient 11:77df6d7e65ae 971 }
AzureIoTClient 13:920e00014ee3 972 else if (readChunk(http_instance, (char*)receivedContent + size, chunkSize) < 0)
AzureIoTClient 11:77df6d7e65ae 973 {
AzureIoTClient 11:77df6d7e65ae 974 result = HTTPAPI_READ_DATA_FAILED;
AzureIoTClient 11:77df6d7e65ae 975 }
AzureIoTClient 11:77df6d7e65ae 976 }
AzureIoTClient 11:77df6d7e65ae 977 else
AzureIoTClient 11:77df6d7e65ae 978 {
AzureIoTClient 11:77df6d7e65ae 979 /*Codes_SRS_HTTPAPI_COMPACT_21_051: [ If the responseContent is NULL, the HTTPAPI_ExecuteRequest shall ignore any content in the response. ]*/
AzureIoTClient 13:920e00014ee3 980 if (skipN(http_instance, chunkSize) < 0)
AzureIoTClient 11:77df6d7e65ae 981 {
AzureIoTClient 13:920e00014ee3 982 /*Codes_SRS_HTTPAPI_COMPACT_21_077: [ If the HTTPAPI_ExecuteRequest retries 20 times to receive the message without success, it shall fail and return HTTPAPI_READ_DATA_FAILED. ]*/
AzureIoTClient 13:920e00014ee3 983 result = HTTPAPI_READ_DATA_FAILED;
AzureIoTClient 11:77df6d7e65ae 984 }
AzureIoTClient 11:77df6d7e65ae 985 }
AzureIoTClient 11:77df6d7e65ae 986
AzureIoTClient 11:77df6d7e65ae 987 if (result == HTTPAPI_OK)
AzureIoTClient 11:77df6d7e65ae 988 {
AzureIoTClient 13:920e00014ee3 989 if (readChunk(http_instance, (char*)buf, (size_t)2) < 0
AzureIoTClient 11:77df6d7e65ae 990 || buf[0] != '\r' || buf[1] != '\n') // skip /r/n
AzureIoTClient 11:77df6d7e65ae 991 {
AzureIoTClient 11:77df6d7e65ae 992 result = HTTPAPI_READ_DATA_FAILED;
AzureIoTClient 11:77df6d7e65ae 993 }
AzureIoTClient 11:77df6d7e65ae 994 size += chunkSize;
AzureIoTClient 11:77df6d7e65ae 995 }
AzureIoTClient 11:77df6d7e65ae 996 }
AzureIoTClient 11:77df6d7e65ae 997 }
AzureIoTClient 11:77df6d7e65ae 998
AzureIoTClient 11:77df6d7e65ae 999 }
AzureIoTClient 11:77df6d7e65ae 1000 return result;
AzureIoTClient 11:77df6d7e65ae 1001 }
AzureIoTClient 11:77df6d7e65ae 1002
AzureIoTClient 11:77df6d7e65ae 1003
AzureIoTClient 11:77df6d7e65ae 1004 /*Codes_SRS_HTTPAPI_COMPACT_21_037: [ If the request type is unknown, the HTTPAPI_ExecuteRequest shall return HTTPAPI_INVALID_ARG. ]*/
AzureIoTClient 11:77df6d7e65ae 1005 static bool validRequestType(HTTPAPI_REQUEST_TYPE requestType)
AzureIoTClient 11:77df6d7e65ae 1006 {
AzureIoTClient 11:77df6d7e65ae 1007 bool result;
AzureIoTClient 11:77df6d7e65ae 1008
AzureIoTClient 11:77df6d7e65ae 1009 if ((requestType == HTTPAPI_REQUEST_GET) ||
AzureIoTClient 11:77df6d7e65ae 1010 (requestType == HTTPAPI_REQUEST_POST) ||
AzureIoTClient 11:77df6d7e65ae 1011 (requestType == HTTPAPI_REQUEST_PUT) ||
AzureIoTClient 11:77df6d7e65ae 1012 (requestType == HTTPAPI_REQUEST_DELETE) ||
AzureIoTClient 11:77df6d7e65ae 1013 (requestType == HTTPAPI_REQUEST_PATCH))
AzureIoTClient 11:77df6d7e65ae 1014 {
AzureIoTClient 11:77df6d7e65ae 1015 result = true;
AzureIoTClient 11:77df6d7e65ae 1016 }
AzureIoTClient 11:77df6d7e65ae 1017 else
AzureIoTClient 11:77df6d7e65ae 1018 {
AzureIoTClient 11:77df6d7e65ae 1019 result = false;
AzureIoTClient 11:77df6d7e65ae 1020 }
AzureIoTClient 11:77df6d7e65ae 1021
AzureIoTClient 11:77df6d7e65ae 1022 return result;
AzureIoTClient 11:77df6d7e65ae 1023 }
AzureIoTClient 11:77df6d7e65ae 1024
AzureIoTClient 11:77df6d7e65ae 1025 /*Codes_SRS_HTTPAPI_COMPACT_21_021: [ The HTTPAPI_ExecuteRequest shall execute the http communtication with the provided host, sending a request and reciving the response. ]*/
AzureIoTClient 11:77df6d7e65ae 1026 /*Codes_SRS_HTTPAPI_COMPACT_21_050: [ If there is a content in the response, the HTTPAPI_ExecuteRequest shall copy it in the responseContent buffer. ]*/
Azure.IoT Build 6:c55b013dfc2a 1027 //Note: This function assumes that "Host:" and "Content-Length:" headers are setup
Azure.IoT Build 6:c55b013dfc2a 1028 // by the caller of HTTPAPI_ExecuteRequest() (which is true for httptransport.c).
Azure.IoT Build 6:c55b013dfc2a 1029 HTTPAPI_RESULT HTTPAPI_ExecuteRequest(HTTP_HANDLE handle, HTTPAPI_REQUEST_TYPE requestType, const char* relativePath,
Azure.IoT Build 6:c55b013dfc2a 1030 HTTP_HEADERS_HANDLE httpHeadersHandle, const unsigned char* content,
Azure.IoT Build 6:c55b013dfc2a 1031 size_t contentLength, unsigned int* statusCode,
Azure.IoT Build 6:c55b013dfc2a 1032 HTTP_HEADERS_HANDLE responseHeadersHandle, BUFFER_HANDLE responseContent)
Azure.IoT Build 6:c55b013dfc2a 1033 {
AzureIoTClient 11:77df6d7e65ae 1034 HTTPAPI_RESULT result = HTTPAPI_ERROR;
Azure.IoT Build 6:c55b013dfc2a 1035 size_t headersCount;
Azure.IoT Build 6:c55b013dfc2a 1036 size_t bodyLength = 0;
Azure.IoT Build 6:c55b013dfc2a 1037 bool chunked = false;
AzureIoTClient 13:920e00014ee3 1038 HTTP_HANDLE_DATA* http_instance = (HTTP_HANDLE_DATA*)handle;
Azure.IoT Build 6:c55b013dfc2a 1039
AzureIoTClient 11:77df6d7e65ae 1040 /*Codes_SRS_HTTPAPI_COMPACT_21_034: [ If there is no previous connection, the HTTPAPI_ExecuteRequest shall return HTTPAPI_INVALID_ARG. ]*/
AzureIoTClient 11:77df6d7e65ae 1041 /*Codes_SRS_HTTPAPI_COMPACT_21_037: [ If the request type is unknown, the HTTPAPI_ExecuteRequest shall return HTTPAPI_INVALID_ARG. ]*/
AzureIoTClient 11:77df6d7e65ae 1042 /*Codes_SRS_HTTPAPI_COMPACT_21_039: [ If the relativePath is NULL or invalid, the HTTPAPI_ExecuteRequest shall return HTTPAPI_INVALID_ARG. ]*/
AzureIoTClient 11:77df6d7e65ae 1043 /*Codes_SRS_HTTPAPI_COMPACT_21_041: [ If the httpHeadersHandle is NULL or invalid, the HTTPAPI_ExecuteRequest shall return HTTPAPI_INVALID_ARG. ]*/
AzureIoTClient 11:77df6d7e65ae 1044 /*Codes_SRS_HTTPAPI_COMPACT_21_053: [ The HTTPAPI_ExecuteRequest shall produce a set of http header to send to the host. ]*/
AzureIoTClient 11:77df6d7e65ae 1045 /*Codes_SRS_HTTPAPI_COMPACT_21_040: [ The request shall contain the http header provided in httpHeadersHandle parameter. ]*/
AzureIoTClient 11:77df6d7e65ae 1046 /*Codes_SRS_HTTPAPI_COMPACT_21_054: [ If Http header maker cannot provide the number of headers, the HTTPAPI_ExecuteRequest shall return HTTPAPI_INVALID_ARG. ]*/
AzureIoTClient 13:920e00014ee3 1047 if (http_instance == NULL ||
Azure.IoT Build 6:c55b013dfc2a 1048 relativePath == NULL ||
Azure.IoT Build 6:c55b013dfc2a 1049 httpHeadersHandle == NULL ||
AzureIoTClient 11:77df6d7e65ae 1050 !validRequestType(requestType) ||
Azure.IoT Build 6:c55b013dfc2a 1051 HTTPHeaders_GetHeaderCount(httpHeadersHandle, &headersCount) != HTTP_HEADERS_OK)
Azure.IoT Build 6:c55b013dfc2a 1052 {
Azure.IoT Build 6:c55b013dfc2a 1053 result = HTTPAPI_INVALID_ARG;
Azure.IoT Build 6:c55b013dfc2a 1054 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 6:c55b013dfc2a 1055 }
AzureIoTClient 11:77df6d7e65ae 1056 /*Codes_SRS_HTTPAPI_COMPACT_21_024: [ The HTTPAPI_ExecuteRequest shall open the transport connection with the host to send the request. ]*/
AzureIoTClient 13:920e00014ee3 1057 else if ((result = OpenXIOConnection(http_instance)) != HTTPAPI_OK)
AzureIoTClient 11:77df6d7e65ae 1058 {
AzureIoTClient 11:77df6d7e65ae 1059 LogError("Open HTTP connection failed (result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
AzureIoTClient 11:77df6d7e65ae 1060 }
AzureIoTClient 11:77df6d7e65ae 1061 /*Codes_SRS_HTTPAPI_COMPACT_21_026: [ If the open process succeed, the HTTPAPI_ExecuteRequest shall send the request message to the host. ]*/
AzureIoTClient 13:920e00014ee3 1062 else if ((result = SendHeadsToXIO(http_instance, requestType, relativePath, httpHeadersHandle, headersCount)) != HTTPAPI_OK)
AzureIoTClient 11:77df6d7e65ae 1063 {
AzureIoTClient 11:77df6d7e65ae 1064 LogError("Send heads to HTTP failed (result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
AzureIoTClient 11:77df6d7e65ae 1065 }
AzureIoTClient 11:77df6d7e65ae 1066 /*Codes_SRS_HTTPAPI_COMPACT_21_042: [ The request can contain the a content message, provided in content parameter. ]*/
AzureIoTClient 13:920e00014ee3 1067 else if ((result = SendContentToXIO(http_instance, content, contentLength)) != HTTPAPI_OK)
AzureIoTClient 11:77df6d7e65ae 1068 {
AzureIoTClient 11:77df6d7e65ae 1069 LogError("Send content to HTTP failed (result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
AzureIoTClient 11:77df6d7e65ae 1070 }
AzureIoTClient 11:77df6d7e65ae 1071 /*Codes_SRS_HTTPAPI_COMPACT_21_030: [ At the end of the transmission, the HTTPAPI_ExecuteRequest shall receive the response from the host. ]*/
AzureIoTClient 11:77df6d7e65ae 1072 /*Codes_SRS_HTTPAPI_COMPACT_21_073: [ The message recived by the HTTPAPI_ExecuteRequest shall starts with a valid header. ]*/
AzureIoTClient 13:920e00014ee3 1073 else if ((result = RecieveHeaderFromXIO(http_instance, statusCode)) != HTTPAPI_OK)
AzureIoTClient 11:77df6d7e65ae 1074 {
AzureIoTClient 11:77df6d7e65ae 1075 LogError("Receive header from HTTP failed (result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
AzureIoTClient 11:77df6d7e65ae 1076 }
AzureIoTClient 11:77df6d7e65ae 1077 /*Codes_SRS_HTTPAPI_COMPACT_21_074: [ After the header, the message recieved by the HTTPAPI_ExecuteRequest can contain addition information about the content. ]*/
AzureIoTClient 13:920e00014ee3 1078 else if ((result = RecieveContentInfoFromXIO(http_instance, responseHeadersHandle, &bodyLength, &chunked)) != HTTPAPI_OK)
AzureIoTClient 11:77df6d7e65ae 1079 {
AzureIoTClient 11:77df6d7e65ae 1080 LogError("Receive content information from HTTP failed (result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
AzureIoTClient 11:77df6d7e65ae 1081 }
AzureIoTClient 11:77df6d7e65ae 1082 /*Codes_SRS_HTTPAPI_COMPACT_21_075: [ The message recieved by the HTTPAPI_ExecuteRequest can contain a body with the message content. ]*/
AzureIoTClient 13:920e00014ee3 1083 else if ((result = ReadHTTPResponseBodyFromXIO(http_instance, bodyLength, chunked, responseContent)) != HTTPAPI_OK)
AzureIoTClient 11:77df6d7e65ae 1084 {
AzureIoTClient 11:77df6d7e65ae 1085 LogError("Read HTTP response body from HTTP failed (result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
AzureIoTClient 11:77df6d7e65ae 1086 }
Azure.IoT Build 6:c55b013dfc2a 1087
AzureIoTClient 13:920e00014ee3 1088 conn_receive_discard_buffer(http_instance);
AzureIoTClient 13:920e00014ee3 1089
AzureIoTClient 13:920e00014ee3 1090 /*Codes_SRS_HTTPAPI_COMPACT_21_031: [ After receive the response, the HTTPAPI_ExecuteRequest shall close the transport connection with the host. ]*/
AzureIoTClient 13:920e00014ee3 1091 if ((http_instance != NULL) &&
AzureIoTClient 13:920e00014ee3 1092 (http_instance->is_connected != 0))
Azure.IoT Build 6:c55b013dfc2a 1093 {
AzureIoTClient 13:920e00014ee3 1094 xio_close(http_instance->xio_handle, NULL, NULL);
AzureIoTClient 13:920e00014ee3 1095 http_instance->is_connected = 0;
Azure.IoT Build 6:c55b013dfc2a 1096 }
Azure.IoT Build 6:c55b013dfc2a 1097
AzureIoTClient 11:77df6d7e65ae 1098 return result;
AzureIoTClient 11:77df6d7e65ae 1099 }
Azure.IoT Build 6:c55b013dfc2a 1100
AzureIoTClient 11:77df6d7e65ae 1101 /*Codes_SRS_HTTPAPI_COMPACT_21_056: [ The HTTPAPI_SetOption shall change the HTTP options. ]*/
AzureIoTClient 11:77df6d7e65ae 1102 /*Codes_SRS_HTTPAPI_COMPACT_21_057: [ The HTTPAPI_SetOption shall recieve a handle that identiry the HTTP connection. ]*/
AzureIoTClient 11:77df6d7e65ae 1103 /*Codes_SRS_HTTPAPI_COMPACT_21_058: [ The HTTPAPI_SetOption shall recieve the option as a pair optionName/value. ]*/
AzureIoTClient 11:77df6d7e65ae 1104 HTTPAPI_RESULT HTTPAPI_SetOption(HTTP_HANDLE handle, const char* optionName, const void* value)
AzureIoTClient 11:77df6d7e65ae 1105 {
AzureIoTClient 11:77df6d7e65ae 1106 HTTPAPI_RESULT result;
AzureIoTClient 13:920e00014ee3 1107 HTTP_HANDLE_DATA* http_instance = (HTTP_HANDLE_DATA*)handle;
Azure.IoT Build 6:c55b013dfc2a 1108
AzureIoTClient 11:77df6d7e65ae 1109 if (
AzureIoTClient 13:920e00014ee3 1110 (http_instance == NULL) ||
AzureIoTClient 11:77df6d7e65ae 1111 (optionName == NULL) ||
AzureIoTClient 11:77df6d7e65ae 1112 (value == NULL)
AzureIoTClient 11:77df6d7e65ae 1113 )
Azure.IoT Build 6:c55b013dfc2a 1114 {
AzureIoTClient 11:77df6d7e65ae 1115 /*Codes_SRS_HTTPAPI_COMPACT_21_059: [ If the handle is NULL, the HTTPAPI_SetOption shall return HTTPAPI_INVALID_ARG. ]*/
AzureIoTClient 11:77df6d7e65ae 1116 /*Codes_SRS_HTTPAPI_COMPACT_21_060: [ If the optionName is NULL, the HTTPAPI_SetOption shall return HTTPAPI_INVALID_ARG. ]*/
AzureIoTClient 11:77df6d7e65ae 1117 /*Codes_SRS_HTTPAPI_COMPACT_21_061: [ If the value is NULL, the HTTPAPI_SetOption shall return HTTPAPI_INVALID_ARG. ]*/
AzureIoTClient 11:77df6d7e65ae 1118 result = HTTPAPI_INVALID_ARG;
Azure.IoT Build 6:c55b013dfc2a 1119 }
AzureIoTClient 11:77df6d7e65ae 1120 else if (strcmp("TrustedCerts", optionName) == 0)
Azure.IoT Build 6:c55b013dfc2a 1121 {
AzureIoTClient 13:920e00014ee3 1122 if (http_instance->certificate)
Azure.IoT Build 6:c55b013dfc2a 1123 {
AzureIoTClient 13:920e00014ee3 1124 free(http_instance->certificate);
Azure.IoT Build 6:c55b013dfc2a 1125 }
Azure.IoT Build 6:c55b013dfc2a 1126
AzureIoTClient 11:77df6d7e65ae 1127 int len = (int)strlen((char*)value);
AzureIoTClient 13:920e00014ee3 1128 http_instance->certificate = (char*)malloc((len + 1) * sizeof(char));
AzureIoTClient 13:920e00014ee3 1129 if (http_instance->certificate == NULL)
Azure.IoT Build 6:c55b013dfc2a 1130 {
AzureIoTClient 11:77df6d7e65ae 1131 /*SRS_HTTPAPI_COMPACT_21_062: [ If any memory allocation get fail, the HTTPAPI_SetOption shall return HTTPAPI_ALLOC_FAILED. ]*/
AzureIoTClient 11:77df6d7e65ae 1132 result = HTTPAPI_ALLOC_FAILED;
AzureIoTClient 11:77df6d7e65ae 1133 LogInfo("unable to allocate memory for the certificate in HTTPAPI_SetOption");
Azure.IoT Build 6:c55b013dfc2a 1134 }
Azure.IoT Build 6:c55b013dfc2a 1135 else
Azure.IoT Build 6:c55b013dfc2a 1136 {
AzureIoTClient 11:77df6d7e65ae 1137 /*SRS_HTTPAPI_COMPACT_21_064: [ If the HTTPAPI_SetOption get success setting the option, it shall return HTTPAPI_OK. ]*/
AzureIoTClient 13:920e00014ee3 1138 (void)strcpy(http_instance->certificate, (const char*)value);
Azure.IoT Build 6:c55b013dfc2a 1139 result = HTTPAPI_OK;
Azure.IoT Build 6:c55b013dfc2a 1140 }
Azure.IoT Build 6:c55b013dfc2a 1141 }
Azure.IoT Build 6:c55b013dfc2a 1142 else
Azure.IoT Build 6:c55b013dfc2a 1143 {
AzureIoTClient 11:77df6d7e65ae 1144 /*Codes_SRS_HTTPAPI_COMPACT_21_063: [ If the HTTP do not support the optionName, the HTTPAPI_SetOption shall return HTTPAPI_INVALID_ARG. ]*/
Azure.IoT Build 6:c55b013dfc2a 1145 result = HTTPAPI_INVALID_ARG;
AzureIoTClient 11:77df6d7e65ae 1146 LogInfo("unknown option %s", optionName);
Azure.IoT Build 6:c55b013dfc2a 1147 }
Azure.IoT Build 6:c55b013dfc2a 1148 return result;
Azure.IoT Build 6:c55b013dfc2a 1149 }
Azure.IoT Build 6:c55b013dfc2a 1150
AzureIoTClient 11:77df6d7e65ae 1151 /*Codes_SRS_HTTPAPI_COMPACT_21_065: [ The HTTPAPI_CloneOption shall provide the means to clone the HTTP option. ]*/
AzureIoTClient 11:77df6d7e65ae 1152 /*Codes_SRS_HTTPAPI_COMPACT_21_066: [ The HTTPAPI_CloneOption shall return a clone of the value identified by the optionName. ]*/
Azure.IoT Build 6:c55b013dfc2a 1153 HTTPAPI_RESULT HTTPAPI_CloneOption(const char* optionName, const void* value, const void** savedValue)
Azure.IoT Build 6:c55b013dfc2a 1154 {
Azure.IoT Build 6:c55b013dfc2a 1155 HTTPAPI_RESULT result;
AzureIoTClient 11:77df6d7e65ae 1156 size_t certLen;
AzureIoTClient 11:77df6d7e65ae 1157 char* tempCert;
AzureIoTClient 11:77df6d7e65ae 1158
AzureIoTClient 11:77df6d7e65ae 1159 if (
Azure.IoT Build 6:c55b013dfc2a 1160 (optionName == NULL) ||
Azure.IoT Build 6:c55b013dfc2a 1161 (value == NULL) ||
Azure.IoT Build 6:c55b013dfc2a 1162 (savedValue == NULL)
Azure.IoT Build 6:c55b013dfc2a 1163 )
Azure.IoT Build 6:c55b013dfc2a 1164 {
AzureIoTClient 11:77df6d7e65ae 1165 /*Codes_SRS_HTTPAPI_COMPACT_21_067: [ If the optionName is NULL, the HTTPAPI_CloneOption shall return HTTPAPI_INVALID_ARG. ]*/
AzureIoTClient 11:77df6d7e65ae 1166 /*Codes_SRS_HTTPAPI_COMPACT_21_068: [ If the value is NULL, the HTTPAPI_CloneOption shall return HTTPAPI_INVALID_ARG. ]*/
AzureIoTClient 11:77df6d7e65ae 1167 /*Codes_SRS_HTTPAPI_COMPACT_21_069: [ If the savedValue is NULL, the HTTPAPI_CloneOption shall return HTTPAPI_INVALID_ARG. ]*/
AzureIoTClient 11:77df6d7e65ae 1168 result = HTTPAPI_INVALID_ARG;
Azure.IoT Build 6:c55b013dfc2a 1169 }
Azure.IoT Build 6:c55b013dfc2a 1170 else if (strcmp("TrustedCerts", optionName) == 0)
Azure.IoT Build 6:c55b013dfc2a 1171 {
AzureIoTClient 11:77df6d7e65ae 1172 certLen = strlen((const char*)value);
AzureIoTClient 11:77df6d7e65ae 1173 tempCert = (char*)malloc((certLen + 1) * sizeof(char));
Azure.IoT Build 6:c55b013dfc2a 1174 if (tempCert == NULL)
Azure.IoT Build 6:c55b013dfc2a 1175 {
AzureIoTClient 11:77df6d7e65ae 1176 /*Codes_SRS_HTTPAPI_COMPACT_21_070: [ If any memory allocation get fail, the HTTPAPI_CloneOption shall return HTTPAPI_ALLOC_FAILED. ]*/
AzureIoTClient 11:77df6d7e65ae 1177 result = HTTPAPI_ALLOC_FAILED;
Azure.IoT Build 6:c55b013dfc2a 1178 }
Azure.IoT Build 6:c55b013dfc2a 1179 else
Azure.IoT Build 6:c55b013dfc2a 1180 {
AzureIoTClient 11:77df6d7e65ae 1181 /*Codes_SRS_HTTPAPI_COMPACT_21_072: [ If the HTTPAPI_CloneOption get success setting the option, it shall return HTTPAPI_OK. ]*/
AzureIoTClient 11:77df6d7e65ae 1182 (void)strcpy(tempCert, (const char*)value);
Azure.IoT Build 6:c55b013dfc2a 1183 *savedValue = tempCert;
Azure.IoT Build 6:c55b013dfc2a 1184 result = HTTPAPI_OK;
Azure.IoT Build 6:c55b013dfc2a 1185 }
Azure.IoT Build 6:c55b013dfc2a 1186 }
Azure.IoT Build 6:c55b013dfc2a 1187 else
Azure.IoT Build 6:c55b013dfc2a 1188 {
AzureIoTClient 11:77df6d7e65ae 1189 /*Codes_SRS_HTTPAPI_COMPACT_21_071: [ If the HTTP do not support the optionName, the HTTPAPI_CloneOption shall return HTTPAPI_INVALID_ARG. ]*/
AzureIoTClient 11:77df6d7e65ae 1190 result = HTTPAPI_INVALID_ARG;
AzureIoTClient 11:77df6d7e65ae 1191 LogInfo("unknown option %s", optionName);
Azure.IoT Build 6:c55b013dfc2a 1192 }
Azure.IoT Build 6:c55b013dfc2a 1193 return result;
Azure.IoT Build 6:c55b013dfc2a 1194 }