Azure IoT common library

Dependents:   STM32F746_iothub_client_sample_mqtt f767zi_mqtt iothub_client_sample_amqp iothub_client_sample_http ... more

Committer:
Azure.IoT Build
Date:
Fri Jul 01 10:43:23 2016 -0700
Revision:
6:c55b013dfc2a
Child:
7:1af47e3a19b6
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 <stdlib.h>
Azure.IoT Build 6:c55b013dfc2a 11 #include <ctype.h>
Azure.IoT Build 6:c55b013dfc2a 12 #include "azure_c_shared_utility/httpapi.h"
Azure.IoT Build 6:c55b013dfc2a 13 #include "azure_c_shared_utility/httpheaders.h"
Azure.IoT Build 6:c55b013dfc2a 14 #include "azure_c_shared_utility/crt_abstractions.h"
Azure.IoT Build 6:c55b013dfc2a 15 #include "azure_c_shared_utility/xlogging.h"
Azure.IoT Build 6:c55b013dfc2a 16 #include "azure_c_shared_utility/xio.h"
Azure.IoT Build 6:c55b013dfc2a 17 #include "azure_c_shared_utility/platform.h"
Azure.IoT Build 6:c55b013dfc2a 18 #include "azure_c_shared_utility/tlsio.h"
Azure.IoT Build 6:c55b013dfc2a 19 #include "azure_c_shared_utility/threadapi.h"
Azure.IoT Build 6:c55b013dfc2a 20 #include <string.h>
Azure.IoT Build 6:c55b013dfc2a 21
Azure.IoT Build 6:c55b013dfc2a 22 #define MAX_HOSTNAME 64
Azure.IoT Build 6:c55b013dfc2a 23 #define TEMP_BUFFER_SIZE 4096
Azure.IoT Build 6:c55b013dfc2a 24
Azure.IoT Build 6:c55b013dfc2a 25 #define CHAR_COUNT(A) (sizeof(A) - 1)
Azure.IoT Build 6:c55b013dfc2a 26
Azure.IoT Build 6:c55b013dfc2a 27 DEFINE_ENUM_STRINGS(HTTPAPI_RESULT, HTTPAPI_RESULT_VALUES)
Azure.IoT Build 6:c55b013dfc2a 28
Azure.IoT Build 6:c55b013dfc2a 29 typedef enum SEND_ALL_RESULT_TAG
Azure.IoT Build 6:c55b013dfc2a 30 {
Azure.IoT Build 6:c55b013dfc2a 31 SEND_ALL_RESULT_NOT_STARTED,
Azure.IoT Build 6:c55b013dfc2a 32 SEND_ALL_RESULT_PENDING,
Azure.IoT Build 6:c55b013dfc2a 33 SEND_ALL_RESULT_OK,
Azure.IoT Build 6:c55b013dfc2a 34 SEND_ALL_RESULT_ERROR
Azure.IoT Build 6:c55b013dfc2a 35 } SEND_ALL_RESULT;
Azure.IoT Build 6:c55b013dfc2a 36
Azure.IoT Build 6:c55b013dfc2a 37 typedef struct HTTP_HANDLE_DATA_TAG
Azure.IoT Build 6:c55b013dfc2a 38 {
Azure.IoT Build 6:c55b013dfc2a 39 char host[MAX_HOSTNAME];
Azure.IoT Build 6:c55b013dfc2a 40 char* certificate;
Azure.IoT Build 6:c55b013dfc2a 41 XIO_HANDLE xio_handle;
Azure.IoT Build 6:c55b013dfc2a 42 size_t received_bytes_count;
Azure.IoT Build 6:c55b013dfc2a 43 unsigned char* received_bytes;
Azure.IoT Build 6:c55b013dfc2a 44 SEND_ALL_RESULT send_all_result;
Azure.IoT Build 6:c55b013dfc2a 45 unsigned int is_io_error : 1;
Azure.IoT Build 6:c55b013dfc2a 46 unsigned int is_connected : 1;
Azure.IoT Build 6:c55b013dfc2a 47 } HTTP_HANDLE_DATA;
Azure.IoT Build 6:c55b013dfc2a 48
Azure.IoT Build 6:c55b013dfc2a 49 HTTPAPI_RESULT HTTPAPI_Init(void)
Azure.IoT Build 6:c55b013dfc2a 50 {
Azure.IoT Build 6:c55b013dfc2a 51 return HTTPAPI_OK;
Azure.IoT Build 6:c55b013dfc2a 52 }
Azure.IoT Build 6:c55b013dfc2a 53
Azure.IoT Build 6:c55b013dfc2a 54 void HTTPAPI_Deinit(void)
Azure.IoT Build 6:c55b013dfc2a 55 {
Azure.IoT Build 6:c55b013dfc2a 56 }
Azure.IoT Build 6:c55b013dfc2a 57
Azure.IoT Build 6:c55b013dfc2a 58 HTTP_HANDLE HTTPAPI_CreateConnection(const char* hostName)
Azure.IoT Build 6:c55b013dfc2a 59 {
Azure.IoT Build 6:c55b013dfc2a 60 HTTP_HANDLE_DATA* handle = NULL;
Azure.IoT Build 6:c55b013dfc2a 61
Azure.IoT Build 6:c55b013dfc2a 62 if (hostName)
Azure.IoT Build 6:c55b013dfc2a 63 {
Azure.IoT Build 6:c55b013dfc2a 64 handle = (HTTP_HANDLE_DATA*)malloc(sizeof(HTTP_HANDLE_DATA));
Azure.IoT Build 6:c55b013dfc2a 65 if (handle != NULL)
Azure.IoT Build 6:c55b013dfc2a 66 {
Azure.IoT Build 6:c55b013dfc2a 67 if (strcpy_s(handle->host, MAX_HOSTNAME, hostName) != 0)
Azure.IoT Build 6:c55b013dfc2a 68 {
Azure.IoT Build 6:c55b013dfc2a 69 LogError("HTTPAPI_CreateConnection::Could not strcpy_s");
Azure.IoT Build 6:c55b013dfc2a 70 free(handle);
Azure.IoT Build 6:c55b013dfc2a 71 handle = NULL;
Azure.IoT Build 6:c55b013dfc2a 72 }
Azure.IoT Build 6:c55b013dfc2a 73 else
Azure.IoT Build 6:c55b013dfc2a 74 {
Azure.IoT Build 6:c55b013dfc2a 75 TLSIO_CONFIG tlsio_config = { hostName, 443 };
Azure.IoT Build 6:c55b013dfc2a 76 handle->xio_handle = xio_create(platform_get_default_tlsio(), (void*)&tlsio_config);
Azure.IoT Build 6:c55b013dfc2a 77 if (handle->xio_handle == NULL)
Azure.IoT Build 6:c55b013dfc2a 78 {
Azure.IoT Build 6:c55b013dfc2a 79 LogError("HTTPAPI_CreateConnection::xio_create failed");
Azure.IoT Build 6:c55b013dfc2a 80 free(handle->host);
Azure.IoT Build 6:c55b013dfc2a 81 free(handle);
Azure.IoT Build 6:c55b013dfc2a 82 handle = NULL;
Azure.IoT Build 6:c55b013dfc2a 83 }
Azure.IoT Build 6:c55b013dfc2a 84 else
Azure.IoT Build 6:c55b013dfc2a 85 {
Azure.IoT Build 6:c55b013dfc2a 86 handle->is_connected = 0;
Azure.IoT Build 6:c55b013dfc2a 87 handle->is_io_error = 0;
Azure.IoT Build 6:c55b013dfc2a 88 handle->received_bytes_count = 0;
Azure.IoT Build 6:c55b013dfc2a 89 handle->received_bytes = NULL;
Azure.IoT Build 6:c55b013dfc2a 90 handle->send_all_result = SEND_ALL_RESULT_NOT_STARTED;
Azure.IoT Build 6:c55b013dfc2a 91 handle->certificate = NULL;
Azure.IoT Build 6:c55b013dfc2a 92 }
Azure.IoT Build 6:c55b013dfc2a 93 }
Azure.IoT Build 6:c55b013dfc2a 94 }
Azure.IoT Build 6:c55b013dfc2a 95 }
Azure.IoT Build 6:c55b013dfc2a 96 else
Azure.IoT Build 6:c55b013dfc2a 97 {
Azure.IoT Build 6:c55b013dfc2a 98 LogInfo("HTTPAPI_CreateConnection:: null hostName parameter");
Azure.IoT Build 6:c55b013dfc2a 99 }
Azure.IoT Build 6:c55b013dfc2a 100
Azure.IoT Build 6:c55b013dfc2a 101 return (HTTP_HANDLE)handle;
Azure.IoT Build 6:c55b013dfc2a 102 }
Azure.IoT Build 6:c55b013dfc2a 103
Azure.IoT Build 6:c55b013dfc2a 104 void HTTPAPI_CloseConnection(HTTP_HANDLE handle)
Azure.IoT Build 6:c55b013dfc2a 105 {
Azure.IoT Build 6:c55b013dfc2a 106 HTTP_HANDLE_DATA* h = (HTTP_HANDLE_DATA*)handle;
Azure.IoT Build 6:c55b013dfc2a 107
Azure.IoT Build 6:c55b013dfc2a 108 if (h)
Azure.IoT Build 6:c55b013dfc2a 109 {
Azure.IoT Build 6:c55b013dfc2a 110 if (h->xio_handle != NULL)
Azure.IoT Build 6:c55b013dfc2a 111 {
Azure.IoT Build 6:c55b013dfc2a 112 LogInfo("HTTPAPI_CloseConnection xio_destroy(); to %s", h->host);
Azure.IoT Build 6:c55b013dfc2a 113 xio_destroy(h->xio_handle);
Azure.IoT Build 6:c55b013dfc2a 114 }
Azure.IoT Build 6:c55b013dfc2a 115
Azure.IoT Build 6:c55b013dfc2a 116 if (h->certificate)
Azure.IoT Build 6:c55b013dfc2a 117 {
Azure.IoT Build 6:c55b013dfc2a 118 free(h->certificate);
Azure.IoT Build 6:c55b013dfc2a 119 }
Azure.IoT Build 6:c55b013dfc2a 120
Azure.IoT Build 6:c55b013dfc2a 121 free(h);
Azure.IoT Build 6:c55b013dfc2a 122 }
Azure.IoT Build 6:c55b013dfc2a 123 }
Azure.IoT Build 6:c55b013dfc2a 124
Azure.IoT Build 6:c55b013dfc2a 125 static void on_io_open_complete(void* context, IO_OPEN_RESULT open_result)
Azure.IoT Build 6:c55b013dfc2a 126 {
Azure.IoT Build 6:c55b013dfc2a 127 HTTP_HANDLE_DATA* h = (HTTP_HANDLE_DATA*)context;
Azure.IoT Build 6:c55b013dfc2a 128 if (open_result == IO_OPEN_OK)
Azure.IoT Build 6:c55b013dfc2a 129 {
Azure.IoT Build 6:c55b013dfc2a 130 h->is_connected = 1;
Azure.IoT Build 6:c55b013dfc2a 131 h->is_io_error = 0;
Azure.IoT Build 6:c55b013dfc2a 132 }
Azure.IoT Build 6:c55b013dfc2a 133 else
Azure.IoT Build 6:c55b013dfc2a 134 {
Azure.IoT Build 6:c55b013dfc2a 135 h->is_io_error = 1;
Azure.IoT Build 6:c55b013dfc2a 136 }
Azure.IoT Build 6:c55b013dfc2a 137 }
Azure.IoT Build 6:c55b013dfc2a 138
Azure.IoT Build 6:c55b013dfc2a 139 static int my_strnicmp(const char* s1, const char* s2, size_t n)
Azure.IoT Build 6:c55b013dfc2a 140 {
Azure.IoT Build 6:c55b013dfc2a 141 size_t i;
Azure.IoT Build 6:c55b013dfc2a 142 int result = 0;
Azure.IoT Build 6:c55b013dfc2a 143
Azure.IoT Build 6:c55b013dfc2a 144 for (i = 0; i < n; i++)
Azure.IoT Build 6:c55b013dfc2a 145 {
Azure.IoT Build 6:c55b013dfc2a 146 /* compute the difference between the chars */
Azure.IoT Build 6:c55b013dfc2a 147 result = tolower(s1[i]) - tolower(s2[i]);
Azure.IoT Build 6:c55b013dfc2a 148
Azure.IoT Build 6:c55b013dfc2a 149 /* break if we have a difference ... */
Azure.IoT Build 6:c55b013dfc2a 150 if ((result != 0) ||
Azure.IoT Build 6:c55b013dfc2a 151 /* ... or if we got to the end of one the strings */
Azure.IoT Build 6:c55b013dfc2a 152 (s1[i] == '\0') || (s2[i] == '\0'))
Azure.IoT Build 6:c55b013dfc2a 153 {
Azure.IoT Build 6:c55b013dfc2a 154 break;
Azure.IoT Build 6:c55b013dfc2a 155 }
Azure.IoT Build 6:c55b013dfc2a 156 }
Azure.IoT Build 6:c55b013dfc2a 157
Azure.IoT Build 6:c55b013dfc2a 158 return result;
Azure.IoT Build 6:c55b013dfc2a 159 }
Azure.IoT Build 6:c55b013dfc2a 160
Azure.IoT Build 6:c55b013dfc2a 161 static int my_stricmp(const char* s1, const char* s2)
Azure.IoT Build 6:c55b013dfc2a 162 {
Azure.IoT Build 6:c55b013dfc2a 163 size_t i = 0;
Azure.IoT Build 6:c55b013dfc2a 164
Azure.IoT Build 6:c55b013dfc2a 165 while ((s1[i] != '\0') && (s2[i] != '\0'))
Azure.IoT Build 6:c55b013dfc2a 166 {
Azure.IoT Build 6:c55b013dfc2a 167 /* break if we have a difference ... */
Azure.IoT Build 6:c55b013dfc2a 168 if (tolower(s1[i]) != tolower(s2[i]))
Azure.IoT Build 6:c55b013dfc2a 169 {
Azure.IoT Build 6:c55b013dfc2a 170 break;
Azure.IoT Build 6:c55b013dfc2a 171 }
Azure.IoT Build 6:c55b013dfc2a 172
Azure.IoT Build 6:c55b013dfc2a 173 i++;
Azure.IoT Build 6:c55b013dfc2a 174 }
Azure.IoT Build 6:c55b013dfc2a 175
Azure.IoT Build 6:c55b013dfc2a 176 /* if we broke because we are at end of string this will yield 0 */
Azure.IoT Build 6:c55b013dfc2a 177 /* if we broke because there was a difference this will yield non-zero */
Azure.IoT Build 6:c55b013dfc2a 178 return tolower(s1[i]) - tolower(s2[i]);
Azure.IoT Build 6:c55b013dfc2a 179 }
Azure.IoT Build 6:c55b013dfc2a 180
Azure.IoT Build 6:c55b013dfc2a 181 static void on_bytes_received(void* context, const unsigned char* buffer, size_t size)
Azure.IoT Build 6:c55b013dfc2a 182 {
Azure.IoT Build 6:c55b013dfc2a 183 HTTP_HANDLE_DATA* h = (HTTP_HANDLE_DATA*)context;
Azure.IoT Build 6:c55b013dfc2a 184
Azure.IoT Build 6:c55b013dfc2a 185 /* Here we got some bytes so we'll buffer them so the receive functions can consumer it */
Azure.IoT Build 6:c55b013dfc2a 186 unsigned char* new_received_bytes = (unsigned char*)realloc(h->received_bytes, h->received_bytes_count + size);
Azure.IoT Build 6:c55b013dfc2a 187 if (new_received_bytes == NULL)
Azure.IoT Build 6:c55b013dfc2a 188 {
Azure.IoT Build 6:c55b013dfc2a 189 h->is_io_error = 1;
Azure.IoT Build 6:c55b013dfc2a 190 LogError("on_bytes_received: Error allocating memory for received data");
Azure.IoT Build 6:c55b013dfc2a 191 }
Azure.IoT Build 6:c55b013dfc2a 192 else
Azure.IoT Build 6:c55b013dfc2a 193 {
Azure.IoT Build 6:c55b013dfc2a 194 h->received_bytes = new_received_bytes;
Azure.IoT Build 6:c55b013dfc2a 195 (void)memcpy(h->received_bytes + h->received_bytes_count, buffer, size);
Azure.IoT Build 6:c55b013dfc2a 196 h->received_bytes_count += size;
Azure.IoT Build 6:c55b013dfc2a 197 }
Azure.IoT Build 6:c55b013dfc2a 198 }
Azure.IoT Build 6:c55b013dfc2a 199
Azure.IoT Build 6:c55b013dfc2a 200 static void on_io_error(void* context)
Azure.IoT Build 6:c55b013dfc2a 201 {
Azure.IoT Build 6:c55b013dfc2a 202 HTTP_HANDLE_DATA* h = (HTTP_HANDLE_DATA*)context;
Azure.IoT Build 6:c55b013dfc2a 203 h->is_io_error = 1;
Azure.IoT Build 6:c55b013dfc2a 204 LogError("on_io_error: Error signalled by underlying IO");
Azure.IoT Build 6:c55b013dfc2a 205 }
Azure.IoT Build 6:c55b013dfc2a 206
Azure.IoT Build 6:c55b013dfc2a 207 static int conn_receive(HTTP_HANDLE_DATA* http_instance, char* buffer, int count)
Azure.IoT Build 6:c55b013dfc2a 208 {
Azure.IoT Build 6:c55b013dfc2a 209 int result = 0;
Azure.IoT Build 6:c55b013dfc2a 210
Azure.IoT Build 6:c55b013dfc2a 211 if (count < 0)
Azure.IoT Build 6:c55b013dfc2a 212 {
Azure.IoT Build 6:c55b013dfc2a 213 result = -1;
Azure.IoT Build 6:c55b013dfc2a 214 }
Azure.IoT Build 6:c55b013dfc2a 215 else
Azure.IoT Build 6:c55b013dfc2a 216 {
Azure.IoT Build 6:c55b013dfc2a 217 while (result < count)
Azure.IoT Build 6:c55b013dfc2a 218 {
Azure.IoT Build 6:c55b013dfc2a 219 xio_dowork(http_instance->xio_handle);
Azure.IoT Build 6:c55b013dfc2a 220
Azure.IoT Build 6:c55b013dfc2a 221 /* if any error was detected while receiving then simply break and report it */
Azure.IoT Build 6:c55b013dfc2a 222 if (http_instance->is_io_error != 0)
Azure.IoT Build 6:c55b013dfc2a 223 {
Azure.IoT Build 6:c55b013dfc2a 224 result = -1;
Azure.IoT Build 6:c55b013dfc2a 225 break;
Azure.IoT Build 6:c55b013dfc2a 226 }
Azure.IoT Build 6:c55b013dfc2a 227
Azure.IoT Build 6:c55b013dfc2a 228 if (http_instance->received_bytes_count >= (size_t)count)
Azure.IoT Build 6:c55b013dfc2a 229 {
Azure.IoT Build 6:c55b013dfc2a 230 /* Consuming bytes from the receive buffer */
Azure.IoT Build 6:c55b013dfc2a 231 (void)memcpy(buffer, http_instance->received_bytes, count);
Azure.IoT Build 6:c55b013dfc2a 232 (void)memmove(http_instance->received_bytes, http_instance->received_bytes + count, http_instance->received_bytes_count - count);
Azure.IoT Build 6:c55b013dfc2a 233 http_instance->received_bytes_count -= count;
Azure.IoT Build 6:c55b013dfc2a 234
Azure.IoT Build 6:c55b013dfc2a 235 /* we're not reallocating at each consumption so that we don't trash due to byte by byte consumption */
Azure.IoT Build 6:c55b013dfc2a 236 if (http_instance->received_bytes_count == 0)
Azure.IoT Build 6:c55b013dfc2a 237 {
Azure.IoT Build 6:c55b013dfc2a 238 free(http_instance->received_bytes);
Azure.IoT Build 6:c55b013dfc2a 239 http_instance->received_bytes = NULL;
Azure.IoT Build 6:c55b013dfc2a 240 }
Azure.IoT Build 6:c55b013dfc2a 241
Azure.IoT Build 6:c55b013dfc2a 242 result = count;
Azure.IoT Build 6:c55b013dfc2a 243 break;
Azure.IoT Build 6:c55b013dfc2a 244 }
Azure.IoT Build 6:c55b013dfc2a 245
Azure.IoT Build 6:c55b013dfc2a 246 ThreadAPI_Sleep(1);
Azure.IoT Build 6:c55b013dfc2a 247 }
Azure.IoT Build 6:c55b013dfc2a 248 }
Azure.IoT Build 6:c55b013dfc2a 249
Azure.IoT Build 6:c55b013dfc2a 250 return result;
Azure.IoT Build 6:c55b013dfc2a 251 }
Azure.IoT Build 6:c55b013dfc2a 252
Azure.IoT Build 6:c55b013dfc2a 253 static void on_send_complete(void* context, IO_SEND_RESULT send_result)
Azure.IoT Build 6:c55b013dfc2a 254 {
Azure.IoT Build 6:c55b013dfc2a 255 /* If a send is complete we'll simply signal this by changing the send all state */
Azure.IoT Build 6:c55b013dfc2a 256 HTTP_HANDLE_DATA* http_instance = (HTTP_HANDLE_DATA*)context;
Azure.IoT Build 6:c55b013dfc2a 257 if (send_result == IO_SEND_OK)
Azure.IoT Build 6:c55b013dfc2a 258 {
Azure.IoT Build 6:c55b013dfc2a 259 http_instance->send_all_result = SEND_ALL_RESULT_OK;
Azure.IoT Build 6:c55b013dfc2a 260 }
Azure.IoT Build 6:c55b013dfc2a 261 else
Azure.IoT Build 6:c55b013dfc2a 262 {
Azure.IoT Build 6:c55b013dfc2a 263 http_instance->send_all_result = SEND_ALL_RESULT_ERROR;
Azure.IoT Build 6:c55b013dfc2a 264 }
Azure.IoT Build 6:c55b013dfc2a 265 }
Azure.IoT Build 6:c55b013dfc2a 266
Azure.IoT Build 6:c55b013dfc2a 267 static int conn_send_all(HTTP_HANDLE_DATA* http_instance, char* buffer, int count)
Azure.IoT Build 6:c55b013dfc2a 268 {
Azure.IoT Build 6:c55b013dfc2a 269 int result;
Azure.IoT Build 6:c55b013dfc2a 270
Azure.IoT Build 6:c55b013dfc2a 271 if (count < 0)
Azure.IoT Build 6:c55b013dfc2a 272 {
Azure.IoT Build 6:c55b013dfc2a 273 result = -1;
Azure.IoT Build 6:c55b013dfc2a 274 }
Azure.IoT Build 6:c55b013dfc2a 275 else
Azure.IoT Build 6:c55b013dfc2a 276 {
Azure.IoT Build 6:c55b013dfc2a 277 http_instance->send_all_result = SEND_ALL_RESULT_PENDING;
Azure.IoT Build 6:c55b013dfc2a 278 if (xio_send(http_instance->xio_handle, buffer, count, on_send_complete, http_instance) != 0)
Azure.IoT Build 6:c55b013dfc2a 279 {
Azure.IoT Build 6:c55b013dfc2a 280 result = -1;
Azure.IoT Build 6:c55b013dfc2a 281 }
Azure.IoT Build 6:c55b013dfc2a 282 else
Azure.IoT Build 6:c55b013dfc2a 283 {
Azure.IoT Build 6:c55b013dfc2a 284 /* We have to loop in here until all bytes are sent or we encounter an error. */
Azure.IoT Build 6:c55b013dfc2a 285 while (1)
Azure.IoT Build 6:c55b013dfc2a 286 {
Azure.IoT Build 6:c55b013dfc2a 287 xio_dowork(http_instance->xio_handle);
Azure.IoT Build 6:c55b013dfc2a 288
Azure.IoT Build 6:c55b013dfc2a 289 /* If we got an error signalled from the underlying IO we simply report it up */
Azure.IoT Build 6:c55b013dfc2a 290 if (http_instance->is_io_error)
Azure.IoT Build 6:c55b013dfc2a 291 {
Azure.IoT Build 6:c55b013dfc2a 292 http_instance->send_all_result = SEND_ALL_RESULT_ERROR;
Azure.IoT Build 6:c55b013dfc2a 293 break;
Azure.IoT Build 6:c55b013dfc2a 294 }
Azure.IoT Build 6:c55b013dfc2a 295
Azure.IoT Build 6:c55b013dfc2a 296 if (http_instance->send_all_result != SEND_ALL_RESULT_PENDING)
Azure.IoT Build 6:c55b013dfc2a 297 {
Azure.IoT Build 6:c55b013dfc2a 298 break;
Azure.IoT Build 6:c55b013dfc2a 299 }
Azure.IoT Build 6:c55b013dfc2a 300
Azure.IoT Build 6:c55b013dfc2a 301 /* We yield the CPU for a bit so others can do their work */
Azure.IoT Build 6:c55b013dfc2a 302 ThreadAPI_Sleep(1);
Azure.IoT Build 6:c55b013dfc2a 303 }
Azure.IoT Build 6:c55b013dfc2a 304
Azure.IoT Build 6:c55b013dfc2a 305 /* The send_all_result indicates what is the status for the send operation.
Azure.IoT Build 6:c55b013dfc2a 306 Not started - means nothing should happen since no send was started
Azure.IoT Build 6:c55b013dfc2a 307 Pending - a send was started, but it is still being carried out
Azure.IoT Build 6:c55b013dfc2a 308 Ok - Send complete
Azure.IoT Build 6:c55b013dfc2a 309 Error - error */
Azure.IoT Build 6:c55b013dfc2a 310 switch (http_instance->send_all_result)
Azure.IoT Build 6:c55b013dfc2a 311 {
Azure.IoT Build 6:c55b013dfc2a 312 default:
Azure.IoT Build 6:c55b013dfc2a 313 case SEND_ALL_RESULT_NOT_STARTED:
Azure.IoT Build 6:c55b013dfc2a 314 result = -1;
Azure.IoT Build 6:c55b013dfc2a 315 break;
Azure.IoT Build 6:c55b013dfc2a 316
Azure.IoT Build 6:c55b013dfc2a 317 case SEND_ALL_RESULT_OK:
Azure.IoT Build 6:c55b013dfc2a 318 result = count;
Azure.IoT Build 6:c55b013dfc2a 319 break;
Azure.IoT Build 6:c55b013dfc2a 320
Azure.IoT Build 6:c55b013dfc2a 321 case SEND_ALL_RESULT_ERROR:
Azure.IoT Build 6:c55b013dfc2a 322 result = -1;
Azure.IoT Build 6:c55b013dfc2a 323 break;
Azure.IoT Build 6:c55b013dfc2a 324 }
Azure.IoT Build 6:c55b013dfc2a 325 }
Azure.IoT Build 6:c55b013dfc2a 326 }
Azure.IoT Build 6:c55b013dfc2a 327
Azure.IoT Build 6:c55b013dfc2a 328 return result;
Azure.IoT Build 6:c55b013dfc2a 329 }
Azure.IoT Build 6:c55b013dfc2a 330
Azure.IoT Build 6:c55b013dfc2a 331 static int readLine(HTTP_HANDLE_DATA* http_instance, char* buf, const size_t size)
Azure.IoT Build 6:c55b013dfc2a 332 {
Azure.IoT Build 6:c55b013dfc2a 333 // reads until \r\n is encountered. writes in buf all the characters
Azure.IoT Build 6:c55b013dfc2a 334 char* p = buf;
Azure.IoT Build 6:c55b013dfc2a 335 char c;
Azure.IoT Build 6:c55b013dfc2a 336 if (conn_receive(http_instance, &c, 1) < 0)
Azure.IoT Build 6:c55b013dfc2a 337 return -1;
Azure.IoT Build 6:c55b013dfc2a 338 while (c != '\r') {
Azure.IoT Build 6:c55b013dfc2a 339 if ((p - buf + 1) >= (int)size)
Azure.IoT Build 6:c55b013dfc2a 340 return -1;
Azure.IoT Build 6:c55b013dfc2a 341 *p++ = c;
Azure.IoT Build 6:c55b013dfc2a 342 if (conn_receive(http_instance, &c, 1) < 0)
Azure.IoT Build 6:c55b013dfc2a 343 return -1;
Azure.IoT Build 6:c55b013dfc2a 344 }
Azure.IoT Build 6:c55b013dfc2a 345 *p = 0;
Azure.IoT Build 6:c55b013dfc2a 346 if (conn_receive(http_instance, &c, 1) < 0 || c != '\n') // skip \n
Azure.IoT Build 6:c55b013dfc2a 347 return -1;
Azure.IoT Build 6:c55b013dfc2a 348 return p - buf;
Azure.IoT Build 6:c55b013dfc2a 349 }
Azure.IoT Build 6:c55b013dfc2a 350
Azure.IoT Build 6:c55b013dfc2a 351 static int readChunk(HTTP_HANDLE_DATA* http_instance, char* buf, size_t size)
Azure.IoT Build 6:c55b013dfc2a 352 {
Azure.IoT Build 6:c55b013dfc2a 353 size_t cur, offset;
Azure.IoT Build 6:c55b013dfc2a 354
Azure.IoT Build 6:c55b013dfc2a 355 // read content with specified length, even if it is received
Azure.IoT Build 6:c55b013dfc2a 356 // only in chunks due to fragmentation in the networking layer.
Azure.IoT Build 6:c55b013dfc2a 357 // returns -1 in case of error.
Azure.IoT Build 6:c55b013dfc2a 358 offset = 0;
Azure.IoT Build 6:c55b013dfc2a 359 while (size > 0)
Azure.IoT Build 6:c55b013dfc2a 360 {
Azure.IoT Build 6:c55b013dfc2a 361 cur = conn_receive(http_instance, buf + offset, size);
Azure.IoT Build 6:c55b013dfc2a 362
Azure.IoT Build 6:c55b013dfc2a 363 // end of stream reached
Azure.IoT Build 6:c55b013dfc2a 364 if (cur == 0)
Azure.IoT Build 6:c55b013dfc2a 365 return offset;
Azure.IoT Build 6:c55b013dfc2a 366
Azure.IoT Build 6:c55b013dfc2a 367 // read cur bytes (might be less than requested)
Azure.IoT Build 6:c55b013dfc2a 368 size -= cur;
Azure.IoT Build 6:c55b013dfc2a 369 offset += cur;
Azure.IoT Build 6:c55b013dfc2a 370 }
Azure.IoT Build 6:c55b013dfc2a 371
Azure.IoT Build 6:c55b013dfc2a 372 return offset;
Azure.IoT Build 6:c55b013dfc2a 373 }
Azure.IoT Build 6:c55b013dfc2a 374
Azure.IoT Build 6:c55b013dfc2a 375 static int skipN(HTTP_HANDLE_DATA* http_instance, size_t n, char* buf, size_t size)
Azure.IoT Build 6:c55b013dfc2a 376 {
Azure.IoT Build 6:c55b013dfc2a 377 size_t org = n;
Azure.IoT Build 6:c55b013dfc2a 378 // read and abandon response content with specified length
Azure.IoT Build 6:c55b013dfc2a 379 // returns -1 in case of error.
Azure.IoT Build 6:c55b013dfc2a 380 while (n > size)
Azure.IoT Build 6:c55b013dfc2a 381 {
Azure.IoT Build 6:c55b013dfc2a 382 if (readChunk(http_instance, (char*)buf, size) < 0)
Azure.IoT Build 6:c55b013dfc2a 383 return -1;
Azure.IoT Build 6:c55b013dfc2a 384
Azure.IoT Build 6:c55b013dfc2a 385 n -= size;
Azure.IoT Build 6:c55b013dfc2a 386 }
Azure.IoT Build 6:c55b013dfc2a 387
Azure.IoT Build 6:c55b013dfc2a 388 if (readChunk(http_instance, (char*)buf, n) < 0)
Azure.IoT Build 6:c55b013dfc2a 389 return -1;
Azure.IoT Build 6:c55b013dfc2a 390
Azure.IoT Build 6:c55b013dfc2a 391 return org;
Azure.IoT Build 6:c55b013dfc2a 392 }
Azure.IoT Build 6:c55b013dfc2a 393
Azure.IoT Build 6:c55b013dfc2a 394 //Note: This function assumes that "Host:" and "Content-Length:" headers are setup
Azure.IoT Build 6:c55b013dfc2a 395 // by the caller of HTTPAPI_ExecuteRequest() (which is true for httptransport.c).
Azure.IoT Build 6:c55b013dfc2a 396 HTTPAPI_RESULT HTTPAPI_ExecuteRequest(HTTP_HANDLE handle, HTTPAPI_REQUEST_TYPE requestType, const char* relativePath,
Azure.IoT Build 6:c55b013dfc2a 397 HTTP_HEADERS_HANDLE httpHeadersHandle, const unsigned char* content,
Azure.IoT Build 6:c55b013dfc2a 398 size_t contentLength, unsigned int* statusCode,
Azure.IoT Build 6:c55b013dfc2a 399 HTTP_HEADERS_HANDLE responseHeadersHandle, BUFFER_HANDLE responseContent)
Azure.IoT Build 6:c55b013dfc2a 400 {
Azure.IoT Build 6:c55b013dfc2a 401
Azure.IoT Build 6:c55b013dfc2a 402 HTTPAPI_RESULT result;
Azure.IoT Build 6:c55b013dfc2a 403 size_t headersCount;
Azure.IoT Build 6:c55b013dfc2a 404 char buf[TEMP_BUFFER_SIZE];
Azure.IoT Build 6:c55b013dfc2a 405 int ret;
Azure.IoT Build 6:c55b013dfc2a 406 size_t bodyLength = 0;
Azure.IoT Build 6:c55b013dfc2a 407 bool chunked = false;
Azure.IoT Build 6:c55b013dfc2a 408 const unsigned char* receivedContent;
Azure.IoT Build 6:c55b013dfc2a 409
Azure.IoT Build 6:c55b013dfc2a 410 const char* method = (requestType == HTTPAPI_REQUEST_GET) ? "GET"
Azure.IoT Build 6:c55b013dfc2a 411 : (requestType == HTTPAPI_REQUEST_POST) ? "POST"
Azure.IoT Build 6:c55b013dfc2a 412 : (requestType == HTTPAPI_REQUEST_PUT) ? "PUT"
Azure.IoT Build 6:c55b013dfc2a 413 : (requestType == HTTPAPI_REQUEST_DELETE) ? "DELETE"
Azure.IoT Build 6:c55b013dfc2a 414 : (requestType == HTTPAPI_REQUEST_PATCH) ? "PATCH"
Azure.IoT Build 6:c55b013dfc2a 415 : NULL;
Azure.IoT Build 6:c55b013dfc2a 416
Azure.IoT Build 6:c55b013dfc2a 417 if (handle == NULL ||
Azure.IoT Build 6:c55b013dfc2a 418 relativePath == NULL ||
Azure.IoT Build 6:c55b013dfc2a 419 httpHeadersHandle == NULL ||
Azure.IoT Build 6:c55b013dfc2a 420 method == NULL ||
Azure.IoT Build 6:c55b013dfc2a 421 HTTPHeaders_GetHeaderCount(httpHeadersHandle, &headersCount) != HTTP_HEADERS_OK)
Azure.IoT Build 6:c55b013dfc2a 422 {
Azure.IoT Build 6:c55b013dfc2a 423 result = HTTPAPI_INVALID_ARG;
Azure.IoT Build 6:c55b013dfc2a 424 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 6:c55b013dfc2a 425 goto exit;
Azure.IoT Build 6:c55b013dfc2a 426 }
Azure.IoT Build 6:c55b013dfc2a 427
Azure.IoT Build 6:c55b013dfc2a 428 HTTP_HANDLE_DATA* httpHandle = (HTTP_HANDLE_DATA*)handle;
Azure.IoT Build 6:c55b013dfc2a 429
Azure.IoT Build 6:c55b013dfc2a 430 if (handle->is_connected == 0)
Azure.IoT Build 6:c55b013dfc2a 431 {
Azure.IoT Build 6:c55b013dfc2a 432 // Load the certificate
Azure.IoT Build 6:c55b013dfc2a 433 if ((httpHandle->certificate != NULL) &&
Azure.IoT Build 6:c55b013dfc2a 434 (xio_setoption(httpHandle->xio_handle, "TrustedCerts", httpHandle->certificate) != 0))
Azure.IoT Build 6:c55b013dfc2a 435 {
Azure.IoT Build 6:c55b013dfc2a 436 result = HTTPAPI_ERROR;
Azure.IoT Build 6:c55b013dfc2a 437 LogError("Could not load certificate (result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 6:c55b013dfc2a 438 goto exit;
Azure.IoT Build 6:c55b013dfc2a 439 }
Azure.IoT Build 6:c55b013dfc2a 440
Azure.IoT Build 6:c55b013dfc2a 441 // Make the connection
Azure.IoT Build 6:c55b013dfc2a 442 if (xio_open(httpHandle->xio_handle, on_io_open_complete, httpHandle, on_bytes_received, httpHandle, on_io_error, httpHandle) != 0)
Azure.IoT Build 6:c55b013dfc2a 443 {
Azure.IoT Build 6:c55b013dfc2a 444 result = HTTPAPI_ERROR;
Azure.IoT Build 6:c55b013dfc2a 445 LogError("Could not connect (result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 6:c55b013dfc2a 446 goto exit;
Azure.IoT Build 6:c55b013dfc2a 447 }
Azure.IoT Build 6:c55b013dfc2a 448
Azure.IoT Build 6:c55b013dfc2a 449 while (1)
Azure.IoT Build 6:c55b013dfc2a 450 {
Azure.IoT Build 6:c55b013dfc2a 451 xio_dowork(httpHandle->xio_handle);
Azure.IoT Build 6:c55b013dfc2a 452 if ((handle->is_connected == 1) ||
Azure.IoT Build 6:c55b013dfc2a 453 (handle->is_io_error == 1))
Azure.IoT Build 6:c55b013dfc2a 454 {
Azure.IoT Build 6:c55b013dfc2a 455 break;
Azure.IoT Build 6:c55b013dfc2a 456 }
Azure.IoT Build 6:c55b013dfc2a 457
Azure.IoT Build 6:c55b013dfc2a 458 ThreadAPI_Sleep(1);
Azure.IoT Build 6:c55b013dfc2a 459 }
Azure.IoT Build 6:c55b013dfc2a 460 }
Azure.IoT Build 6:c55b013dfc2a 461
Azure.IoT Build 6:c55b013dfc2a 462 //Send request
Azure.IoT Build 6:c55b013dfc2a 463 if ((ret = snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\n", method, relativePath)) < 0
Azure.IoT Build 6:c55b013dfc2a 464 || ret >= sizeof(buf))
Azure.IoT Build 6:c55b013dfc2a 465 {
Azure.IoT Build 6:c55b013dfc2a 466 result = HTTPAPI_STRING_PROCESSING_ERROR;
Azure.IoT Build 6:c55b013dfc2a 467 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 6:c55b013dfc2a 468 goto exit;
Azure.IoT Build 6:c55b013dfc2a 469 }
Azure.IoT Build 6:c55b013dfc2a 470 if (conn_send_all(httpHandle, buf, strlen(buf)) < 0)
Azure.IoT Build 6:c55b013dfc2a 471 {
Azure.IoT Build 6:c55b013dfc2a 472 result = HTTPAPI_SEND_REQUEST_FAILED;
Azure.IoT Build 6:c55b013dfc2a 473 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 6:c55b013dfc2a 474 goto exit;
Azure.IoT Build 6:c55b013dfc2a 475 }
Azure.IoT Build 6:c55b013dfc2a 476
Azure.IoT Build 6:c55b013dfc2a 477 //Send default headers
Azure.IoT Build 6:c55b013dfc2a 478 for (size_t i = 0; i < headersCount; i++)
Azure.IoT Build 6:c55b013dfc2a 479 {
Azure.IoT Build 6:c55b013dfc2a 480 char* header;
Azure.IoT Build 6:c55b013dfc2a 481 if (HTTPHeaders_GetHeader(httpHeadersHandle, i, &header) != HTTP_HEADERS_OK)
Azure.IoT Build 6:c55b013dfc2a 482 {
Azure.IoT Build 6:c55b013dfc2a 483 result = HTTPAPI_HTTP_HEADERS_FAILED;
Azure.IoT Build 6:c55b013dfc2a 484 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 6:c55b013dfc2a 485 goto exit;
Azure.IoT Build 6:c55b013dfc2a 486 }
Azure.IoT Build 6:c55b013dfc2a 487 if (conn_send_all(httpHandle, header, strlen(header)) < 0)
Azure.IoT Build 6:c55b013dfc2a 488 {
Azure.IoT Build 6:c55b013dfc2a 489 result = HTTPAPI_SEND_REQUEST_FAILED;
Azure.IoT Build 6:c55b013dfc2a 490 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 6:c55b013dfc2a 491 free(header);
Azure.IoT Build 6:c55b013dfc2a 492 goto exit;
Azure.IoT Build 6:c55b013dfc2a 493 }
Azure.IoT Build 6:c55b013dfc2a 494 if (conn_send_all(httpHandle, "\r\n", 2) < 0)
Azure.IoT Build 6:c55b013dfc2a 495 {
Azure.IoT Build 6:c55b013dfc2a 496 result = HTTPAPI_SEND_REQUEST_FAILED;
Azure.IoT Build 6:c55b013dfc2a 497 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 6:c55b013dfc2a 498 free(header);
Azure.IoT Build 6:c55b013dfc2a 499 goto exit;
Azure.IoT Build 6:c55b013dfc2a 500 }
Azure.IoT Build 6:c55b013dfc2a 501 free(header);
Azure.IoT Build 6:c55b013dfc2a 502 }
Azure.IoT Build 6:c55b013dfc2a 503
Azure.IoT Build 6:c55b013dfc2a 504 //Close headers
Azure.IoT Build 6:c55b013dfc2a 505 if (conn_send_all(httpHandle, "\r\n", 2) < 0)
Azure.IoT Build 6:c55b013dfc2a 506 {
Azure.IoT Build 6:c55b013dfc2a 507 result = HTTPAPI_SEND_REQUEST_FAILED;
Azure.IoT Build 6:c55b013dfc2a 508 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 6:c55b013dfc2a 509 goto exit;
Azure.IoT Build 6:c55b013dfc2a 510 }
Azure.IoT Build 6:c55b013dfc2a 511
Azure.IoT Build 6:c55b013dfc2a 512 //Send data (if available)
Azure.IoT Build 6:c55b013dfc2a 513 if (content && contentLength > 0)
Azure.IoT Build 6:c55b013dfc2a 514 {
Azure.IoT Build 6:c55b013dfc2a 515 if (conn_send_all(httpHandle, (char*)content, contentLength) < 0)
Azure.IoT Build 6:c55b013dfc2a 516 {
Azure.IoT Build 6:c55b013dfc2a 517 result = HTTPAPI_SEND_REQUEST_FAILED;
Azure.IoT Build 6:c55b013dfc2a 518 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 6:c55b013dfc2a 519 goto exit;
Azure.IoT Build 6:c55b013dfc2a 520 }
Azure.IoT Build 6:c55b013dfc2a 521 }
Azure.IoT Build 6:c55b013dfc2a 522
Azure.IoT Build 6:c55b013dfc2a 523 //Receive response
Azure.IoT Build 6:c55b013dfc2a 524 if (readLine(httpHandle, buf, sizeof(buf)) < 0)
Azure.IoT Build 6:c55b013dfc2a 525 {
Azure.IoT Build 6:c55b013dfc2a 526 result = HTTPAPI_READ_DATA_FAILED;
Azure.IoT Build 6:c55b013dfc2a 527 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 6:c55b013dfc2a 528 goto exit;
Azure.IoT Build 6:c55b013dfc2a 529 }
Azure.IoT Build 6:c55b013dfc2a 530
Azure.IoT Build 6:c55b013dfc2a 531 //Parse HTTP response
Azure.IoT Build 6:c55b013dfc2a 532 if (sscanf(buf, "HTTP/%*d.%*d %d %*[^\r\n]", &ret) != 1)
Azure.IoT Build 6:c55b013dfc2a 533 {
Azure.IoT Build 6:c55b013dfc2a 534 //Cannot match string, error
Azure.IoT Build 6:c55b013dfc2a 535 LogInfo("HTTPAPI_ExecuteRequest::Not a correct HTTP answer=%s", buf);
Azure.IoT Build 6:c55b013dfc2a 536 result = HTTPAPI_READ_DATA_FAILED;
Azure.IoT Build 6:c55b013dfc2a 537 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 6:c55b013dfc2a 538 goto exit;
Azure.IoT Build 6:c55b013dfc2a 539 }
Azure.IoT Build 6:c55b013dfc2a 540 if (statusCode)
Azure.IoT Build 6:c55b013dfc2a 541 *statusCode = ret;
Azure.IoT Build 6:c55b013dfc2a 542
Azure.IoT Build 6:c55b013dfc2a 543 //Read HTTP response headers
Azure.IoT Build 6:c55b013dfc2a 544 if (readLine(httpHandle, buf, sizeof(buf)) < 0)
Azure.IoT Build 6:c55b013dfc2a 545 {
Azure.IoT Build 6:c55b013dfc2a 546 result = HTTPAPI_READ_DATA_FAILED;
Azure.IoT Build 6:c55b013dfc2a 547 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 6:c55b013dfc2a 548 goto exit;
Azure.IoT Build 6:c55b013dfc2a 549 }
Azure.IoT Build 6:c55b013dfc2a 550
Azure.IoT Build 6:c55b013dfc2a 551 while (buf[0])
Azure.IoT Build 6:c55b013dfc2a 552 {
Azure.IoT Build 6:c55b013dfc2a 553 const char ContentLength[] = "content-length:";
Azure.IoT Build 6:c55b013dfc2a 554 const char TransferEncoding[] = "transfer-encoding:";
Azure.IoT Build 6:c55b013dfc2a 555
Azure.IoT Build 6:c55b013dfc2a 556 if (my_strnicmp(buf, ContentLength, CHAR_COUNT(ContentLength)) == 0)
Azure.IoT Build 6:c55b013dfc2a 557 {
Azure.IoT Build 6:c55b013dfc2a 558 if (sscanf(buf + CHAR_COUNT(ContentLength), " %d", &bodyLength) != 1)
Azure.IoT Build 6:c55b013dfc2a 559 {
Azure.IoT Build 6:c55b013dfc2a 560 result = HTTPAPI_READ_DATA_FAILED;
Azure.IoT Build 6:c55b013dfc2a 561 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 6:c55b013dfc2a 562 goto exit;
Azure.IoT Build 6:c55b013dfc2a 563 }
Azure.IoT Build 6:c55b013dfc2a 564 }
Azure.IoT Build 6:c55b013dfc2a 565 else if (my_strnicmp(buf, TransferEncoding, CHAR_COUNT(TransferEncoding)) == 0)
Azure.IoT Build 6:c55b013dfc2a 566 {
Azure.IoT Build 6:c55b013dfc2a 567 const char* p = buf + CHAR_COUNT(TransferEncoding);
Azure.IoT Build 6:c55b013dfc2a 568 while (isspace(*p)) p++;
Azure.IoT Build 6:c55b013dfc2a 569 if (my_stricmp(p, "chunked") == 0)
Azure.IoT Build 6:c55b013dfc2a 570 chunked = true;
Azure.IoT Build 6:c55b013dfc2a 571 }
Azure.IoT Build 6:c55b013dfc2a 572
Azure.IoT Build 6:c55b013dfc2a 573 char* whereIsColon = strchr((char*)buf, ':');
Azure.IoT Build 6:c55b013dfc2a 574 if (whereIsColon && responseHeadersHandle != NULL)
Azure.IoT Build 6:c55b013dfc2a 575 {
Azure.IoT Build 6:c55b013dfc2a 576 *whereIsColon = '\0';
Azure.IoT Build 6:c55b013dfc2a 577 HTTPHeaders_AddHeaderNameValuePair(responseHeadersHandle, buf, whereIsColon + 1);
Azure.IoT Build 6:c55b013dfc2a 578 }
Azure.IoT Build 6:c55b013dfc2a 579
Azure.IoT Build 6:c55b013dfc2a 580 if (readLine(httpHandle, buf, sizeof(buf)) < 0)
Azure.IoT Build 6:c55b013dfc2a 581 {
Azure.IoT Build 6:c55b013dfc2a 582 result = HTTPAPI_READ_DATA_FAILED;
Azure.IoT Build 6:c55b013dfc2a 583 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 6:c55b013dfc2a 584 goto exit;
Azure.IoT Build 6:c55b013dfc2a 585 }
Azure.IoT Build 6:c55b013dfc2a 586 }
Azure.IoT Build 6:c55b013dfc2a 587
Azure.IoT Build 6:c55b013dfc2a 588 //Read HTTP response body
Azure.IoT Build 6:c55b013dfc2a 589 if (!chunked)
Azure.IoT Build 6:c55b013dfc2a 590 {
Azure.IoT Build 6:c55b013dfc2a 591 if (bodyLength)
Azure.IoT Build 6:c55b013dfc2a 592 {
Azure.IoT Build 6:c55b013dfc2a 593 if (responseContent != NULL)
Azure.IoT Build 6:c55b013dfc2a 594 {
Azure.IoT Build 6:c55b013dfc2a 595 if (BUFFER_pre_build(responseContent, bodyLength) != 0)
Azure.IoT Build 6:c55b013dfc2a 596 {
Azure.IoT Build 6:c55b013dfc2a 597 result = HTTPAPI_ALLOC_FAILED;
Azure.IoT Build 6:c55b013dfc2a 598 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 6:c55b013dfc2a 599 }
Azure.IoT Build 6:c55b013dfc2a 600 else if (BUFFER_content(responseContent, &receivedContent) != 0)
Azure.IoT Build 6:c55b013dfc2a 601 {
Azure.IoT Build 6:c55b013dfc2a 602 (void)BUFFER_unbuild(responseContent);
Azure.IoT Build 6:c55b013dfc2a 603
Azure.IoT Build 6:c55b013dfc2a 604 result = HTTPAPI_ALLOC_FAILED;
Azure.IoT Build 6:c55b013dfc2a 605 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 6:c55b013dfc2a 606 }
Azure.IoT Build 6:c55b013dfc2a 607
Azure.IoT Build 6:c55b013dfc2a 608 if (readChunk(httpHandle, (char*)receivedContent, bodyLength) < 0)
Azure.IoT Build 6:c55b013dfc2a 609 {
Azure.IoT Build 6:c55b013dfc2a 610 result = HTTPAPI_READ_DATA_FAILED;
Azure.IoT Build 6:c55b013dfc2a 611 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 6:c55b013dfc2a 612 goto exit;
Azure.IoT Build 6:c55b013dfc2a 613 }
Azure.IoT Build 6:c55b013dfc2a 614 else
Azure.IoT Build 6:c55b013dfc2a 615 {
Azure.IoT Build 6:c55b013dfc2a 616 result = HTTPAPI_OK;
Azure.IoT Build 6:c55b013dfc2a 617 }
Azure.IoT Build 6:c55b013dfc2a 618 }
Azure.IoT Build 6:c55b013dfc2a 619 else
Azure.IoT Build 6:c55b013dfc2a 620 {
Azure.IoT Build 6:c55b013dfc2a 621 (void)skipN(httpHandle, bodyLength, buf, sizeof(buf));
Azure.IoT Build 6:c55b013dfc2a 622 result = HTTPAPI_OK;
Azure.IoT Build 6:c55b013dfc2a 623 }
Azure.IoT Build 6:c55b013dfc2a 624 }
Azure.IoT Build 6:c55b013dfc2a 625 else
Azure.IoT Build 6:c55b013dfc2a 626 {
Azure.IoT Build 6:c55b013dfc2a 627 result = HTTPAPI_OK;
Azure.IoT Build 6:c55b013dfc2a 628 }
Azure.IoT Build 6:c55b013dfc2a 629 }
Azure.IoT Build 6:c55b013dfc2a 630 else
Azure.IoT Build 6:c55b013dfc2a 631 {
Azure.IoT Build 6:c55b013dfc2a 632 size_t size = 0;
Azure.IoT Build 6:c55b013dfc2a 633 result = HTTPAPI_OK;
Azure.IoT Build 6:c55b013dfc2a 634 for (;;)
Azure.IoT Build 6:c55b013dfc2a 635 {
Azure.IoT Build 6:c55b013dfc2a 636 int chunkSize;
Azure.IoT Build 6:c55b013dfc2a 637 if (readLine(httpHandle, buf, sizeof(buf)) < 0) // read [length in hex]/r/n
Azure.IoT Build 6:c55b013dfc2a 638 {
Azure.IoT Build 6:c55b013dfc2a 639 result = HTTPAPI_READ_DATA_FAILED;
Azure.IoT Build 6:c55b013dfc2a 640 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 6:c55b013dfc2a 641 goto exit;
Azure.IoT Build 6:c55b013dfc2a 642 }
Azure.IoT Build 6:c55b013dfc2a 643 if (sscanf(buf, "%x", &chunkSize) != 1) // chunkSize is length of next line (/r/n is not counted)
Azure.IoT Build 6:c55b013dfc2a 644 {
Azure.IoT Build 6:c55b013dfc2a 645 //Cannot match string, error
Azure.IoT Build 6:c55b013dfc2a 646 result = HTTPAPI_RECEIVE_RESPONSE_FAILED;
Azure.IoT Build 6:c55b013dfc2a 647 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 6:c55b013dfc2a 648 goto exit;
Azure.IoT Build 6:c55b013dfc2a 649 }
Azure.IoT Build 6:c55b013dfc2a 650
Azure.IoT Build 6:c55b013dfc2a 651 if (chunkSize == 0)
Azure.IoT Build 6:c55b013dfc2a 652 {
Azure.IoT Build 6:c55b013dfc2a 653 // 0 length means next line is just '\r\n' and end of chunks
Azure.IoT Build 6:c55b013dfc2a 654 if (readChunk(httpHandle, (char*)buf, 2) < 0
Azure.IoT Build 6:c55b013dfc2a 655 || buf[0] != '\r' || buf[1] != '\n') // skip /r/n
Azure.IoT Build 6:c55b013dfc2a 656 {
Azure.IoT Build 6:c55b013dfc2a 657 (void)BUFFER_unbuild(responseContent);
Azure.IoT Build 6:c55b013dfc2a 658
Azure.IoT Build 6:c55b013dfc2a 659 result = HTTPAPI_READ_DATA_FAILED;
Azure.IoT Build 6:c55b013dfc2a 660 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 6:c55b013dfc2a 661 goto exit;
Azure.IoT Build 6:c55b013dfc2a 662 }
Azure.IoT Build 6:c55b013dfc2a 663 break;
Azure.IoT Build 6:c55b013dfc2a 664 }
Azure.IoT Build 6:c55b013dfc2a 665 else
Azure.IoT Build 6:c55b013dfc2a 666 {
Azure.IoT Build 6:c55b013dfc2a 667 if (responseContent != NULL)
Azure.IoT Build 6:c55b013dfc2a 668 {
Azure.IoT Build 6:c55b013dfc2a 669 if (BUFFER_enlarge(responseContent, chunkSize) != 0)
Azure.IoT Build 6:c55b013dfc2a 670 {
Azure.IoT Build 6:c55b013dfc2a 671 (void)BUFFER_unbuild(responseContent);
Azure.IoT Build 6:c55b013dfc2a 672
Azure.IoT Build 6:c55b013dfc2a 673 result = HTTPAPI_ALLOC_FAILED;
Azure.IoT Build 6:c55b013dfc2a 674 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 6:c55b013dfc2a 675 }
Azure.IoT Build 6:c55b013dfc2a 676 else if (BUFFER_content(responseContent, &receivedContent) != 0)
Azure.IoT Build 6:c55b013dfc2a 677 {
Azure.IoT Build 6:c55b013dfc2a 678 (void)BUFFER_unbuild(responseContent);
Azure.IoT Build 6:c55b013dfc2a 679
Azure.IoT Build 6:c55b013dfc2a 680 result = HTTPAPI_ALLOC_FAILED;
Azure.IoT Build 6:c55b013dfc2a 681 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 6:c55b013dfc2a 682 }
Azure.IoT Build 6:c55b013dfc2a 683
Azure.IoT Build 6:c55b013dfc2a 684 if (readChunk(httpHandle, (char*)receivedContent + size, chunkSize) < 0)
Azure.IoT Build 6:c55b013dfc2a 685 {
Azure.IoT Build 6:c55b013dfc2a 686 result = HTTPAPI_READ_DATA_FAILED;
Azure.IoT Build 6:c55b013dfc2a 687 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 6:c55b013dfc2a 688 goto exit;
Azure.IoT Build 6:c55b013dfc2a 689 }
Azure.IoT Build 6:c55b013dfc2a 690 }
Azure.IoT Build 6:c55b013dfc2a 691 else
Azure.IoT Build 6:c55b013dfc2a 692 {
Azure.IoT Build 6:c55b013dfc2a 693 if (skipN(httpHandle, chunkSize, buf, sizeof(buf)) < 0)
Azure.IoT Build 6:c55b013dfc2a 694 {
Azure.IoT Build 6:c55b013dfc2a 695 result = HTTPAPI_READ_DATA_FAILED;
Azure.IoT Build 6:c55b013dfc2a 696 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 6:c55b013dfc2a 697 goto exit;
Azure.IoT Build 6:c55b013dfc2a 698 }
Azure.IoT Build 6:c55b013dfc2a 699 }
Azure.IoT Build 6:c55b013dfc2a 700
Azure.IoT Build 6:c55b013dfc2a 701 if (readChunk(httpHandle, (char*)buf, 2) < 0
Azure.IoT Build 6:c55b013dfc2a 702 || buf[0] != '\r' || buf[1] != '\n') // skip /r/n
Azure.IoT Build 6:c55b013dfc2a 703 {
Azure.IoT Build 6:c55b013dfc2a 704 result = HTTPAPI_READ_DATA_FAILED;
Azure.IoT Build 6:c55b013dfc2a 705 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 6:c55b013dfc2a 706 goto exit;
Azure.IoT Build 6:c55b013dfc2a 707 }
Azure.IoT Build 6:c55b013dfc2a 708 size += chunkSize;
Azure.IoT Build 6:c55b013dfc2a 709 }
Azure.IoT Build 6:c55b013dfc2a 710 }
Azure.IoT Build 6:c55b013dfc2a 711
Azure.IoT Build 6:c55b013dfc2a 712 }
Azure.IoT Build 6:c55b013dfc2a 713
Azure.IoT Build 6:c55b013dfc2a 714 exit:
Azure.IoT Build 6:c55b013dfc2a 715 if ((handle != NULL) &&
Azure.IoT Build 6:c55b013dfc2a 716 (handle->is_io_error != 0))
Azure.IoT Build 6:c55b013dfc2a 717 {
Azure.IoT Build 6:c55b013dfc2a 718 xio_close(handle->xio_handle, NULL, NULL);
Azure.IoT Build 6:c55b013dfc2a 719 handle->is_connected = 0;
Azure.IoT Build 6:c55b013dfc2a 720 }
Azure.IoT Build 6:c55b013dfc2a 721
Azure.IoT Build 6:c55b013dfc2a 722 return result;
Azure.IoT Build 6:c55b013dfc2a 723 }
Azure.IoT Build 6:c55b013dfc2a 724
Azure.IoT Build 6:c55b013dfc2a 725 HTTPAPI_RESULT HTTPAPI_SetOption(HTTP_HANDLE handle, const char* optionName, const void* value)
Azure.IoT Build 6:c55b013dfc2a 726 {
Azure.IoT Build 6:c55b013dfc2a 727 HTTPAPI_RESULT result;
Azure.IoT Build 6:c55b013dfc2a 728 if (
Azure.IoT Build 6:c55b013dfc2a 729 (handle == NULL) ||
Azure.IoT Build 6:c55b013dfc2a 730 (optionName == NULL) ||
Azure.IoT Build 6:c55b013dfc2a 731 (value == NULL)
Azure.IoT Build 6:c55b013dfc2a 732 )
Azure.IoT Build 6:c55b013dfc2a 733 {
Azure.IoT Build 6:c55b013dfc2a 734 result = HTTPAPI_INVALID_ARG;
Azure.IoT Build 6:c55b013dfc2a 735 LogError("invalid parameter (NULL) passed to HTTPAPI_SetOption");
Azure.IoT Build 6:c55b013dfc2a 736 }
Azure.IoT Build 6:c55b013dfc2a 737 else if (strcmp("TrustedCerts", optionName) == 0)
Azure.IoT Build 6:c55b013dfc2a 738 {
Azure.IoT Build 6:c55b013dfc2a 739 HTTP_HANDLE_DATA* h = (HTTP_HANDLE_DATA*)handle;
Azure.IoT Build 6:c55b013dfc2a 740 if (h->certificate)
Azure.IoT Build 6:c55b013dfc2a 741 {
Azure.IoT Build 6:c55b013dfc2a 742 free(h->certificate);
Azure.IoT Build 6:c55b013dfc2a 743 }
Azure.IoT Build 6:c55b013dfc2a 744
Azure.IoT Build 6:c55b013dfc2a 745 int len = strlen((char*)value);
Azure.IoT Build 6:c55b013dfc2a 746 h->certificate = (char*)malloc(len + 1);
Azure.IoT Build 6:c55b013dfc2a 747 if (h->certificate == NULL)
Azure.IoT Build 6:c55b013dfc2a 748 {
Azure.IoT Build 6:c55b013dfc2a 749 result = HTTPAPI_ERROR;
Azure.IoT Build 6:c55b013dfc2a 750 LogError("unable to allocate certificate memory in HTTPAPI_SetOption");
Azure.IoT Build 6:c55b013dfc2a 751 }
Azure.IoT Build 6:c55b013dfc2a 752 else
Azure.IoT Build 6:c55b013dfc2a 753 {
Azure.IoT Build 6:c55b013dfc2a 754 (void)strcpy(h->certificate, (const char*)value);
Azure.IoT Build 6:c55b013dfc2a 755 result = HTTPAPI_OK;
Azure.IoT Build 6:c55b013dfc2a 756 }
Azure.IoT Build 6:c55b013dfc2a 757 }
Azure.IoT Build 6:c55b013dfc2a 758 else
Azure.IoT Build 6:c55b013dfc2a 759 {
Azure.IoT Build 6:c55b013dfc2a 760 result = HTTPAPI_INVALID_ARG;
Azure.IoT Build 6:c55b013dfc2a 761 LogError("unknown option %s", optionName);
Azure.IoT Build 6:c55b013dfc2a 762 }
Azure.IoT Build 6:c55b013dfc2a 763 return result;
Azure.IoT Build 6:c55b013dfc2a 764 }
Azure.IoT Build 6:c55b013dfc2a 765
Azure.IoT Build 6:c55b013dfc2a 766 HTTPAPI_RESULT HTTPAPI_CloneOption(const char* optionName, const void* value, const void** savedValue)
Azure.IoT Build 6:c55b013dfc2a 767 {
Azure.IoT Build 6:c55b013dfc2a 768 HTTPAPI_RESULT result;
Azure.IoT Build 6:c55b013dfc2a 769 if (
Azure.IoT Build 6:c55b013dfc2a 770 (optionName == NULL) ||
Azure.IoT Build 6:c55b013dfc2a 771 (value == NULL) ||
Azure.IoT Build 6:c55b013dfc2a 772 (savedValue == NULL)
Azure.IoT Build 6:c55b013dfc2a 773 )
Azure.IoT Build 6:c55b013dfc2a 774 {
Azure.IoT Build 6:c55b013dfc2a 775 result = HTTPAPI_INVALID_ARG;
Azure.IoT Build 6:c55b013dfc2a 776 LogError("invalid argument(NULL) passed to HTTPAPI_CloneOption");
Azure.IoT Build 6:c55b013dfc2a 777 }
Azure.IoT Build 6:c55b013dfc2a 778 else if (strcmp("TrustedCerts", optionName) == 0)
Azure.IoT Build 6:c55b013dfc2a 779 {
Azure.IoT Build 6:c55b013dfc2a 780 size_t certLen = strlen((const char*)value);
Azure.IoT Build 6:c55b013dfc2a 781 char* tempCert = (char*)malloc(certLen+1);
Azure.IoT Build 6:c55b013dfc2a 782 if (tempCert == NULL)
Azure.IoT Build 6:c55b013dfc2a 783 {
Azure.IoT Build 6:c55b013dfc2a 784 result = HTTPAPI_INVALID_ARG;
Azure.IoT Build 6:c55b013dfc2a 785 LogError("unable to allocate certificate memory in HTTPAPI_CloneOption");
Azure.IoT Build 6:c55b013dfc2a 786 }
Azure.IoT Build 6:c55b013dfc2a 787 else
Azure.IoT Build 6:c55b013dfc2a 788 {
Azure.IoT Build 6:c55b013dfc2a 789 (void)strcpy(tempCert, (const char*)value);
Azure.IoT Build 6:c55b013dfc2a 790 *savedValue = tempCert;
Azure.IoT Build 6:c55b013dfc2a 791 result = HTTPAPI_OK;
Azure.IoT Build 6:c55b013dfc2a 792 }
Azure.IoT Build 6:c55b013dfc2a 793 }
Azure.IoT Build 6:c55b013dfc2a 794 else
Azure.IoT Build 6:c55b013dfc2a 795 {
Azure.IoT Build 6:c55b013dfc2a 796 result = HTTPAPI_INVALID_ARG;
Azure.IoT Build 6:c55b013dfc2a 797 LogError("unknown option %s", optionName);
Azure.IoT Build 6:c55b013dfc2a 798 }
Azure.IoT Build 6:c55b013dfc2a 799 return result;
Azure.IoT Build 6:c55b013dfc2a 800 }