Nigel Rantor / azure_c_shared_utility

Fork of azure_c_shared_utility by Azure IoT

Committer:
AzureIoTClient
Date:
Fri Jun 17 17:03:29 2016 -0700
Revision:
5:921351ce6973
Parent:
1:9190c0f4d23a
1.0.9

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Azure.IoT Build 0:fa2de1b79154 1 // Copyright (c) Microsoft. All rights reserved.
Azure.IoT Build 0:fa2de1b79154 2 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
Azure.IoT Build 0:fa2de1b79154 3
Azure.IoT Build 0:fa2de1b79154 4 #include <cstdlib>
Azure.IoT Build 0:fa2de1b79154 5 #ifdef _CRTDBG_MAP_ALLOC
Azure.IoT Build 0:fa2de1b79154 6 #include <crtdbg.h>
Azure.IoT Build 0:fa2de1b79154 7 #endif
Azure.IoT Build 0:fa2de1b79154 8
Azure.IoT Build 0:fa2de1b79154 9 #include <cstdio>
Azure.IoT Build 0:fa2de1b79154 10 #include <cstdlib>
Azure.IoT Build 0:fa2de1b79154 11 #include <cctype>
Azure.IoT Build 0:fa2de1b79154 12 #include "azure_c_shared_utility/httpapi.h"
Azure.IoT Build 0:fa2de1b79154 13 #include "azure_c_shared_utility/httpheaders.h"
Azure.IoT Build 0:fa2de1b79154 14 #include "azure_c_shared_utility/crt_abstractions.h"
Azure.IoT Build 0:fa2de1b79154 15 #include "mbed.h"
Azure.IoT Build 0:fa2de1b79154 16 #include "EthernetInterface.h"
Azure.IoT Build 0:fa2de1b79154 17 #include "azure_c_shared_utility/wolfssl_connection.h"
Azure.IoT Build 0:fa2de1b79154 18 #include "azure_c_shared_utility/iot_logging.h"
Azure.IoT Build 0:fa2de1b79154 19 #include <string.h>
Azure.IoT Build 0:fa2de1b79154 20
Azure.IoT Build 0:fa2de1b79154 21 #define MAX_HOSTNAME 64
Azure.IoT Build 0:fa2de1b79154 22 #define TEMP_BUFFER_SIZE 4096
Azure.IoT Build 0:fa2de1b79154 23
Azure.IoT Build 0:fa2de1b79154 24 #define CHAR_COUNT(A) (sizeof(A) - 1)
Azure.IoT Build 0:fa2de1b79154 25
Azure.IoT Build 0:fa2de1b79154 26 DEFINE_ENUM_STRINGS(HTTPAPI_RESULT, HTTPAPI_RESULT_VALUES)
Azure.IoT Build 0:fa2de1b79154 27
Azure.IoT Build 0:fa2de1b79154 28 class HTTP_HANDLE_DATA
Azure.IoT Build 0:fa2de1b79154 29 {
Azure.IoT Build 0:fa2de1b79154 30 public:
Azure.IoT Build 0:fa2de1b79154 31 char host[MAX_HOSTNAME];
Azure.IoT Build 0:fa2de1b79154 32 char* certificate;
Azure.IoT Build 0:fa2de1b79154 33 WolfSSLConnection con;
Azure.IoT Build 0:fa2de1b79154 34 };
Azure.IoT Build 0:fa2de1b79154 35
Azure.IoT Build 0:fa2de1b79154 36 HTTPAPI_RESULT HTTPAPI_Init(void)
Azure.IoT Build 0:fa2de1b79154 37 {
Azure.IoT Build 0:fa2de1b79154 38 time_t ctTime;
Azure.IoT Build 0:fa2de1b79154 39 ctTime = time(NULL);
Azure.IoT Build 0:fa2de1b79154 40 HTTPAPI_RESULT result;
AzureIoTClient 1:9190c0f4d23a 41 LogInfo("HTTAPI_Init::Time is now (UTC) %s", ctime(&ctTime));
Azure.IoT Build 0:fa2de1b79154 42
Azure.IoT Build 0:fa2de1b79154 43 result = HTTPAPI_OK;
Azure.IoT Build 0:fa2de1b79154 44
Azure.IoT Build 0:fa2de1b79154 45 return result;
Azure.IoT Build 0:fa2de1b79154 46 }
Azure.IoT Build 0:fa2de1b79154 47
Azure.IoT Build 0:fa2de1b79154 48 void HTTPAPI_Deinit(void)
Azure.IoT Build 0:fa2de1b79154 49 {
Azure.IoT Build 0:fa2de1b79154 50 ;
Azure.IoT Build 0:fa2de1b79154 51 }
Azure.IoT Build 0:fa2de1b79154 52
Azure.IoT Build 0:fa2de1b79154 53 HTTP_HANDLE HTTPAPI_CreateConnection(const char* hostName)
Azure.IoT Build 0:fa2de1b79154 54 {
Azure.IoT Build 0:fa2de1b79154 55 HTTP_HANDLE_DATA* handle = NULL;
Azure.IoT Build 0:fa2de1b79154 56
Azure.IoT Build 0:fa2de1b79154 57 if (hostName)
Azure.IoT Build 0:fa2de1b79154 58 {
Azure.IoT Build 0:fa2de1b79154 59 handle = new HTTP_HANDLE_DATA();
Azure.IoT Build 0:fa2de1b79154 60 if (strcpy_s(handle->host, MAX_HOSTNAME, hostName) != 0)
Azure.IoT Build 0:fa2de1b79154 61 {
AzureIoTClient 1:9190c0f4d23a 62 LogError("HTTPAPI_CreateConnection::Could not strcpy_s");
Azure.IoT Build 0:fa2de1b79154 63 delete handle;
Azure.IoT Build 0:fa2de1b79154 64 handle = NULL;
Azure.IoT Build 0:fa2de1b79154 65 }
Azure.IoT Build 0:fa2de1b79154 66 else
Azure.IoT Build 0:fa2de1b79154 67 {
Azure.IoT Build 0:fa2de1b79154 68 handle->certificate = NULL;
Azure.IoT Build 0:fa2de1b79154 69 }
Azure.IoT Build 0:fa2de1b79154 70 }
Azure.IoT Build 0:fa2de1b79154 71 else
Azure.IoT Build 0:fa2de1b79154 72 {
AzureIoTClient 1:9190c0f4d23a 73 LogInfo("HTTPAPI_CreateConnection:: null hostName parameter");
Azure.IoT Build 0:fa2de1b79154 74 }
Azure.IoT Build 0:fa2de1b79154 75
Azure.IoT Build 0:fa2de1b79154 76 return (HTTP_HANDLE)handle;
Azure.IoT Build 0:fa2de1b79154 77 }
Azure.IoT Build 0:fa2de1b79154 78
Azure.IoT Build 0:fa2de1b79154 79 void HTTPAPI_CloseConnection(HTTP_HANDLE handle)
Azure.IoT Build 0:fa2de1b79154 80 {
Azure.IoT Build 0:fa2de1b79154 81 HTTP_HANDLE_DATA* h = (HTTP_HANDLE_DATA*)handle;
Azure.IoT Build 0:fa2de1b79154 82
Azure.IoT Build 0:fa2de1b79154 83 if (h)
Azure.IoT Build 0:fa2de1b79154 84 {
Azure.IoT Build 0:fa2de1b79154 85 if (h->con.is_connected())
Azure.IoT Build 0:fa2de1b79154 86 {
AzureIoTClient 1:9190c0f4d23a 87 LogInfo("HTTPAPI_CloseConnection h->con.close(); to %s", h->host);
Azure.IoT Build 0:fa2de1b79154 88 h->con.close();
Azure.IoT Build 0:fa2de1b79154 89 }
Azure.IoT Build 0:fa2de1b79154 90 if (h->certificate)
Azure.IoT Build 0:fa2de1b79154 91 {
Azure.IoT Build 0:fa2de1b79154 92 delete[] h->certificate;
Azure.IoT Build 0:fa2de1b79154 93 }
Azure.IoT Build 0:fa2de1b79154 94 delete h;
Azure.IoT Build 0:fa2de1b79154 95 }
Azure.IoT Build 0:fa2de1b79154 96 }
Azure.IoT Build 0:fa2de1b79154 97
Azure.IoT Build 0:fa2de1b79154 98 static int readLine(WolfSSLConnection* con, char* buf, const size_t size)
Azure.IoT Build 0:fa2de1b79154 99 {
Azure.IoT Build 0:fa2de1b79154 100 // reads until \r\n is encountered. writes in buf all the characters
Azure.IoT Build 0:fa2de1b79154 101 // read until \r\n and returns the number of characters in the buffer.
Azure.IoT Build 0:fa2de1b79154 102 char* p = buf;
Azure.IoT Build 0:fa2de1b79154 103 char c;
Azure.IoT Build 0:fa2de1b79154 104 if (con->receive(&c, 1) < 0)
Azure.IoT Build 0:fa2de1b79154 105 return -1;
Azure.IoT Build 0:fa2de1b79154 106 while (c != '\r') {
Azure.IoT Build 0:fa2de1b79154 107 if ((p - buf + 1) >= (int)size)
Azure.IoT Build 0:fa2de1b79154 108 return -1;
Azure.IoT Build 0:fa2de1b79154 109 *p++ = c;
Azure.IoT Build 0:fa2de1b79154 110 if (con->receive(&c, 1) < 0)
Azure.IoT Build 0:fa2de1b79154 111 return -1;
Azure.IoT Build 0:fa2de1b79154 112 }
Azure.IoT Build 0:fa2de1b79154 113 *p = 0;
Azure.IoT Build 0:fa2de1b79154 114 if (con->receive(&c, 1) < 0 || c != '\n') // skip \n
Azure.IoT Build 0:fa2de1b79154 115 return -1;
Azure.IoT Build 0:fa2de1b79154 116 return p - buf;
Azure.IoT Build 0:fa2de1b79154 117 }
Azure.IoT Build 0:fa2de1b79154 118
Azure.IoT Build 0:fa2de1b79154 119 static int readChunk(WolfSSLConnection* con, char* buf, size_t size)
Azure.IoT Build 0:fa2de1b79154 120 {
Azure.IoT Build 0:fa2de1b79154 121 size_t cur, offset;
Azure.IoT Build 0:fa2de1b79154 122
Azure.IoT Build 0:fa2de1b79154 123 // read content with specified length, even if it is received
Azure.IoT Build 0:fa2de1b79154 124 // only in chunks due to fragmentation in the networking layer.
Azure.IoT Build 0:fa2de1b79154 125 // returns -1 in case of error.
Azure.IoT Build 0:fa2de1b79154 126 offset = 0;
Azure.IoT Build 0:fa2de1b79154 127 while (size > 0)
Azure.IoT Build 0:fa2de1b79154 128 {
Azure.IoT Build 0:fa2de1b79154 129 cur = con->receive(buf + offset, size);
Azure.IoT Build 0:fa2de1b79154 130
Azure.IoT Build 0:fa2de1b79154 131 // end of stream reached
Azure.IoT Build 0:fa2de1b79154 132 if (cur == 0)
Azure.IoT Build 0:fa2de1b79154 133 return offset;
Azure.IoT Build 0:fa2de1b79154 134
Azure.IoT Build 0:fa2de1b79154 135 // read cur bytes (might be less than requested)
Azure.IoT Build 0:fa2de1b79154 136 size -= cur;
Azure.IoT Build 0:fa2de1b79154 137 offset += cur;
Azure.IoT Build 0:fa2de1b79154 138 }
Azure.IoT Build 0:fa2de1b79154 139
Azure.IoT Build 0:fa2de1b79154 140 return offset;
Azure.IoT Build 0:fa2de1b79154 141 }
Azure.IoT Build 0:fa2de1b79154 142
Azure.IoT Build 0:fa2de1b79154 143 static int skipN(WolfSSLConnection* con, size_t n, char* buf, size_t size)
Azure.IoT Build 0:fa2de1b79154 144 {
Azure.IoT Build 0:fa2de1b79154 145 size_t org = n;
Azure.IoT Build 0:fa2de1b79154 146 // read and abandon response content with specified length
Azure.IoT Build 0:fa2de1b79154 147 // returns -1 in case of error.
Azure.IoT Build 0:fa2de1b79154 148 while (n > size)
Azure.IoT Build 0:fa2de1b79154 149 {
Azure.IoT Build 0:fa2de1b79154 150 if (readChunk(con, (char*)buf, size) < 0)
Azure.IoT Build 0:fa2de1b79154 151 return -1;
Azure.IoT Build 0:fa2de1b79154 152
Azure.IoT Build 0:fa2de1b79154 153 n -= size;
Azure.IoT Build 0:fa2de1b79154 154 }
Azure.IoT Build 0:fa2de1b79154 155
Azure.IoT Build 0:fa2de1b79154 156 if (readChunk(con, (char*)buf, n) < 0)
Azure.IoT Build 0:fa2de1b79154 157 return -1;
Azure.IoT Build 0:fa2de1b79154 158
Azure.IoT Build 0:fa2de1b79154 159 return org;
Azure.IoT Build 0:fa2de1b79154 160 }
Azure.IoT Build 0:fa2de1b79154 161
Azure.IoT Build 0:fa2de1b79154 162 //Note: This function assumes that "Host:" and "Content-Length:" headers are setup
Azure.IoT Build 0:fa2de1b79154 163 // by the caller of HTTPAPI_ExecuteRequest() (which is true for httptransport.c).
Azure.IoT Build 0:fa2de1b79154 164 HTTPAPI_RESULT HTTPAPI_ExecuteRequest(HTTP_HANDLE handle, HTTPAPI_REQUEST_TYPE requestType, const char* relativePath,
Azure.IoT Build 0:fa2de1b79154 165 HTTP_HEADERS_HANDLE httpHeadersHandle, const unsigned char* content,
Azure.IoT Build 0:fa2de1b79154 166 size_t contentLength, unsigned int* statusCode,
Azure.IoT Build 0:fa2de1b79154 167 HTTP_HEADERS_HANDLE responseHeadersHandle, BUFFER_HANDLE responseContent)
Azure.IoT Build 0:fa2de1b79154 168 {
Azure.IoT Build 0:fa2de1b79154 169
Azure.IoT Build 0:fa2de1b79154 170 HTTPAPI_RESULT result;
Azure.IoT Build 0:fa2de1b79154 171 size_t headersCount;
Azure.IoT Build 0:fa2de1b79154 172 char buf[TEMP_BUFFER_SIZE];
Azure.IoT Build 0:fa2de1b79154 173 int ret;
Azure.IoT Build 0:fa2de1b79154 174 WolfSSLConnection* con = NULL;
Azure.IoT Build 0:fa2de1b79154 175 size_t bodyLength = 0;
Azure.IoT Build 0:fa2de1b79154 176 bool chunked = false;
Azure.IoT Build 0:fa2de1b79154 177 const unsigned char* receivedContent;
Azure.IoT Build 0:fa2de1b79154 178
Azure.IoT Build 0:fa2de1b79154 179 const char* method = (requestType == HTTPAPI_REQUEST_GET) ? "GET"
Azure.IoT Build 0:fa2de1b79154 180 : (requestType == HTTPAPI_REQUEST_POST) ? "POST"
Azure.IoT Build 0:fa2de1b79154 181 : (requestType == HTTPAPI_REQUEST_PUT) ? "PUT"
Azure.IoT Build 0:fa2de1b79154 182 : (requestType == HTTPAPI_REQUEST_DELETE) ? "DELETE"
Azure.IoT Build 0:fa2de1b79154 183 : (requestType == HTTPAPI_REQUEST_PATCH) ? "PATCH"
Azure.IoT Build 0:fa2de1b79154 184 : NULL;
Azure.IoT Build 0:fa2de1b79154 185
Azure.IoT Build 0:fa2de1b79154 186 if (handle == NULL ||
Azure.IoT Build 0:fa2de1b79154 187 relativePath == NULL ||
Azure.IoT Build 0:fa2de1b79154 188 httpHeadersHandle == NULL ||
Azure.IoT Build 0:fa2de1b79154 189 method == NULL ||
Azure.IoT Build 0:fa2de1b79154 190 HTTPHeaders_GetHeaderCount(httpHeadersHandle, &headersCount) != HTTP_HEADERS_OK)
Azure.IoT Build 0:fa2de1b79154 191 {
Azure.IoT Build 0:fa2de1b79154 192 result = HTTPAPI_INVALID_ARG;
AzureIoTClient 1:9190c0f4d23a 193 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 0:fa2de1b79154 194 goto exit;
Azure.IoT Build 0:fa2de1b79154 195 }
Azure.IoT Build 0:fa2de1b79154 196
Azure.IoT Build 0:fa2de1b79154 197 HTTP_HANDLE_DATA* httpHandle = (HTTP_HANDLE_DATA*)handle;
Azure.IoT Build 0:fa2de1b79154 198 con = &(httpHandle->con);
Azure.IoT Build 0:fa2de1b79154 199
Azure.IoT Build 0:fa2de1b79154 200 if (!con->is_connected())
Azure.IoT Build 0:fa2de1b79154 201 {
Azure.IoT Build 0:fa2de1b79154 202 // Load the certificate
Azure.IoT Build 0:fa2de1b79154 203 if ((httpHandle->certificate != NULL) &&
Azure.IoT Build 0:fa2de1b79154 204 (!con->load_certificate((const unsigned char*)httpHandle->certificate, strlen(httpHandle->certificate) + 1)))
Azure.IoT Build 0:fa2de1b79154 205 {
Azure.IoT Build 0:fa2de1b79154 206 result = HTTPAPI_ERROR;
AzureIoTClient 1:9190c0f4d23a 207 LogError("Could not load certificate (result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 0:fa2de1b79154 208 goto exit;
Azure.IoT Build 0:fa2de1b79154 209 }
Azure.IoT Build 0:fa2de1b79154 210
Azure.IoT Build 0:fa2de1b79154 211 // Make the connection
Azure.IoT Build 0:fa2de1b79154 212 if (con->connect(httpHandle->host, 443) != 0)
Azure.IoT Build 0:fa2de1b79154 213 {
Azure.IoT Build 0:fa2de1b79154 214 result = HTTPAPI_ERROR;
AzureIoTClient 1:9190c0f4d23a 215 LogError("Could not connect (result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 0:fa2de1b79154 216 goto exit;
Azure.IoT Build 0:fa2de1b79154 217 }
Azure.IoT Build 0:fa2de1b79154 218 }
Azure.IoT Build 0:fa2de1b79154 219
Azure.IoT Build 0:fa2de1b79154 220 //Send request
Azure.IoT Build 0:fa2de1b79154 221 if ((ret = snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\n", method, relativePath)) < 0
Azure.IoT Build 0:fa2de1b79154 222 || ret >= sizeof(buf))
Azure.IoT Build 0:fa2de1b79154 223 {
Azure.IoT Build 0:fa2de1b79154 224 result = HTTPAPI_STRING_PROCESSING_ERROR;
AzureIoTClient 1:9190c0f4d23a 225 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 0:fa2de1b79154 226 goto exit;
Azure.IoT Build 0:fa2de1b79154 227 }
Azure.IoT Build 0:fa2de1b79154 228 if (con->send_all(buf, strlen(buf)) < 0)
Azure.IoT Build 0:fa2de1b79154 229 {
Azure.IoT Build 0:fa2de1b79154 230 result = HTTPAPI_SEND_REQUEST_FAILED;
AzureIoTClient 1:9190c0f4d23a 231 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 0:fa2de1b79154 232 goto exit;
Azure.IoT Build 0:fa2de1b79154 233 }
Azure.IoT Build 0:fa2de1b79154 234
Azure.IoT Build 0:fa2de1b79154 235 //Send default headers
Azure.IoT Build 0:fa2de1b79154 236 for (size_t i = 0; i < headersCount; i++)
Azure.IoT Build 0:fa2de1b79154 237 {
Azure.IoT Build 0:fa2de1b79154 238 char* header;
Azure.IoT Build 0:fa2de1b79154 239 if (HTTPHeaders_GetHeader(httpHeadersHandle, i, &header) != HTTP_HEADERS_OK)
Azure.IoT Build 0:fa2de1b79154 240 {
Azure.IoT Build 0:fa2de1b79154 241 result = HTTPAPI_HTTP_HEADERS_FAILED;
AzureIoTClient 1:9190c0f4d23a 242 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 0:fa2de1b79154 243 goto exit;
Azure.IoT Build 0:fa2de1b79154 244 }
Azure.IoT Build 0:fa2de1b79154 245 if (con->send_all(header, strlen(header)) < 0)
Azure.IoT Build 0:fa2de1b79154 246 {
Azure.IoT Build 0:fa2de1b79154 247 result = HTTPAPI_SEND_REQUEST_FAILED;
AzureIoTClient 1:9190c0f4d23a 248 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 0:fa2de1b79154 249 free(header);
Azure.IoT Build 0:fa2de1b79154 250 goto exit;
Azure.IoT Build 0:fa2de1b79154 251 }
Azure.IoT Build 0:fa2de1b79154 252 if (con->send_all("\r\n", 2) < 0)
Azure.IoT Build 0:fa2de1b79154 253 {
Azure.IoT Build 0:fa2de1b79154 254 result = HTTPAPI_SEND_REQUEST_FAILED;
AzureIoTClient 1:9190c0f4d23a 255 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 0:fa2de1b79154 256 free(header);
Azure.IoT Build 0:fa2de1b79154 257 goto exit;
Azure.IoT Build 0:fa2de1b79154 258 }
Azure.IoT Build 0:fa2de1b79154 259 free(header);
Azure.IoT Build 0:fa2de1b79154 260 }
Azure.IoT Build 0:fa2de1b79154 261
Azure.IoT Build 0:fa2de1b79154 262 //Close headers
Azure.IoT Build 0:fa2de1b79154 263 if (con->send_all("\r\n", 2) < 0)
Azure.IoT Build 0:fa2de1b79154 264 {
Azure.IoT Build 0:fa2de1b79154 265 result = HTTPAPI_SEND_REQUEST_FAILED;
AzureIoTClient 1:9190c0f4d23a 266 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 0:fa2de1b79154 267 goto exit;
Azure.IoT Build 0:fa2de1b79154 268 }
Azure.IoT Build 0:fa2de1b79154 269
Azure.IoT Build 0:fa2de1b79154 270 //Send data (if available)
Azure.IoT Build 0:fa2de1b79154 271 if (content && contentLength > 0)
Azure.IoT Build 0:fa2de1b79154 272 {
Azure.IoT Build 0:fa2de1b79154 273 if (con->send_all((char*)content, contentLength) < 0)
Azure.IoT Build 0:fa2de1b79154 274 {
Azure.IoT Build 0:fa2de1b79154 275 result = HTTPAPI_SEND_REQUEST_FAILED;
AzureIoTClient 1:9190c0f4d23a 276 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 0:fa2de1b79154 277 goto exit;
Azure.IoT Build 0:fa2de1b79154 278 }
Azure.IoT Build 0:fa2de1b79154 279 }
Azure.IoT Build 0:fa2de1b79154 280
Azure.IoT Build 0:fa2de1b79154 281 //Receive response
Azure.IoT Build 0:fa2de1b79154 282 if (readLine(con, buf, sizeof(buf)) < 0)
Azure.IoT Build 0:fa2de1b79154 283 {
Azure.IoT Build 0:fa2de1b79154 284 result = HTTPAPI_READ_DATA_FAILED;
AzureIoTClient 1:9190c0f4d23a 285 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 0:fa2de1b79154 286 goto exit;
Azure.IoT Build 0:fa2de1b79154 287 }
Azure.IoT Build 0:fa2de1b79154 288
Azure.IoT Build 0:fa2de1b79154 289 //Parse HTTP response
Azure.IoT Build 0:fa2de1b79154 290 if (sscanf(buf, "HTTP/%*d.%*d %d %*[^\r\n]", &ret) != 1)
Azure.IoT Build 0:fa2de1b79154 291 {
Azure.IoT Build 0:fa2de1b79154 292 //Cannot match string, error
AzureIoTClient 1:9190c0f4d23a 293 LogInfo("HTTPAPI_ExecuteRequest::Not a correct HTTP answer=%s", buf);
Azure.IoT Build 0:fa2de1b79154 294 result = HTTPAPI_READ_DATA_FAILED;
AzureIoTClient 1:9190c0f4d23a 295 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 0:fa2de1b79154 296 goto exit;
Azure.IoT Build 0:fa2de1b79154 297 }
Azure.IoT Build 0:fa2de1b79154 298 if (statusCode)
Azure.IoT Build 0:fa2de1b79154 299 *statusCode = ret;
Azure.IoT Build 0:fa2de1b79154 300
Azure.IoT Build 0:fa2de1b79154 301 //Read HTTP response headers
Azure.IoT Build 0:fa2de1b79154 302 if (readLine(con, buf, sizeof(buf)) < 0)
Azure.IoT Build 0:fa2de1b79154 303 {
Azure.IoT Build 0:fa2de1b79154 304 result = HTTPAPI_READ_DATA_FAILED;
AzureIoTClient 1:9190c0f4d23a 305 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 0:fa2de1b79154 306 goto exit;
Azure.IoT Build 0:fa2de1b79154 307 }
Azure.IoT Build 0:fa2de1b79154 308
Azure.IoT Build 0:fa2de1b79154 309 while (buf[0])
Azure.IoT Build 0:fa2de1b79154 310 {
Azure.IoT Build 0:fa2de1b79154 311 const char ContentLength[] = "content-length:";
Azure.IoT Build 0:fa2de1b79154 312 const char TransferEncoding[] = "transfer-encoding:";
Azure.IoT Build 0:fa2de1b79154 313
Azure.IoT Build 0:fa2de1b79154 314 if (strncasecmp(buf, ContentLength, CHAR_COUNT(ContentLength)) == 0)
Azure.IoT Build 0:fa2de1b79154 315 {
Azure.IoT Build 0:fa2de1b79154 316 if (sscanf(buf + CHAR_COUNT(ContentLength), " %d", &bodyLength) != 1)
Azure.IoT Build 0:fa2de1b79154 317 {
Azure.IoT Build 0:fa2de1b79154 318 result = HTTPAPI_READ_DATA_FAILED;
AzureIoTClient 1:9190c0f4d23a 319 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 0:fa2de1b79154 320 goto exit;
Azure.IoT Build 0:fa2de1b79154 321 }
Azure.IoT Build 0:fa2de1b79154 322 }
Azure.IoT Build 0:fa2de1b79154 323 else if (strncasecmp(buf, TransferEncoding, CHAR_COUNT(TransferEncoding)) == 0)
Azure.IoT Build 0:fa2de1b79154 324 {
Azure.IoT Build 0:fa2de1b79154 325 const char* p = buf + CHAR_COUNT(TransferEncoding);
Azure.IoT Build 0:fa2de1b79154 326 while (isspace(*p)) p++;
Azure.IoT Build 0:fa2de1b79154 327 if (strcasecmp(p, "chunked") == 0)
Azure.IoT Build 0:fa2de1b79154 328 chunked = true;
Azure.IoT Build 0:fa2de1b79154 329 }
Azure.IoT Build 0:fa2de1b79154 330
Azure.IoT Build 0:fa2de1b79154 331 char* whereIsColon = strchr((char*)buf, ':');
Azure.IoT Build 0:fa2de1b79154 332 if (whereIsColon && responseHeadersHandle != NULL)
Azure.IoT Build 0:fa2de1b79154 333 {
Azure.IoT Build 0:fa2de1b79154 334 *whereIsColon = '\0';
Azure.IoT Build 0:fa2de1b79154 335 HTTPHeaders_AddHeaderNameValuePair(responseHeadersHandle, buf, whereIsColon + 1);
Azure.IoT Build 0:fa2de1b79154 336 }
Azure.IoT Build 0:fa2de1b79154 337
Azure.IoT Build 0:fa2de1b79154 338 if (readLine(con, buf, sizeof(buf)) < 0)
Azure.IoT Build 0:fa2de1b79154 339 {
Azure.IoT Build 0:fa2de1b79154 340 result = HTTPAPI_READ_DATA_FAILED;
AzureIoTClient 1:9190c0f4d23a 341 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 0:fa2de1b79154 342 goto exit;
Azure.IoT Build 0:fa2de1b79154 343 }
Azure.IoT Build 0:fa2de1b79154 344 }
Azure.IoT Build 0:fa2de1b79154 345
Azure.IoT Build 0:fa2de1b79154 346 //Read HTTP response body
Azure.IoT Build 0:fa2de1b79154 347 if (!chunked)
Azure.IoT Build 0:fa2de1b79154 348 {
Azure.IoT Build 0:fa2de1b79154 349 if (bodyLength)
Azure.IoT Build 0:fa2de1b79154 350 {
Azure.IoT Build 0:fa2de1b79154 351 if (responseContent != NULL)
Azure.IoT Build 0:fa2de1b79154 352 {
Azure.IoT Build 0:fa2de1b79154 353 if (BUFFER_pre_build(responseContent, bodyLength) != 0)
Azure.IoT Build 0:fa2de1b79154 354 {
Azure.IoT Build 0:fa2de1b79154 355 result = HTTPAPI_ALLOC_FAILED;
AzureIoTClient 1:9190c0f4d23a 356 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 0:fa2de1b79154 357 }
Azure.IoT Build 0:fa2de1b79154 358 else if (BUFFER_content(responseContent, &receivedContent) != 0)
Azure.IoT Build 0:fa2de1b79154 359 {
Azure.IoT Build 0:fa2de1b79154 360 (void)BUFFER_unbuild(responseContent);
Azure.IoT Build 0:fa2de1b79154 361
Azure.IoT Build 0:fa2de1b79154 362 result = HTTPAPI_ALLOC_FAILED;
AzureIoTClient 1:9190c0f4d23a 363 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 0:fa2de1b79154 364 }
Azure.IoT Build 0:fa2de1b79154 365
Azure.IoT Build 0:fa2de1b79154 366 if (readChunk(con, (char*)receivedContent, bodyLength) < 0)
Azure.IoT Build 0:fa2de1b79154 367 {
Azure.IoT Build 0:fa2de1b79154 368 result = HTTPAPI_READ_DATA_FAILED;
AzureIoTClient 1:9190c0f4d23a 369 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 0:fa2de1b79154 370 goto exit;
Azure.IoT Build 0:fa2de1b79154 371 }
Azure.IoT Build 0:fa2de1b79154 372 else
Azure.IoT Build 0:fa2de1b79154 373 {
Azure.IoT Build 0:fa2de1b79154 374 result = HTTPAPI_OK;
Azure.IoT Build 0:fa2de1b79154 375 }
Azure.IoT Build 0:fa2de1b79154 376 }
Azure.IoT Build 0:fa2de1b79154 377 else
Azure.IoT Build 0:fa2de1b79154 378 {
Azure.IoT Build 0:fa2de1b79154 379 (void)skipN(con, bodyLength, buf, sizeof(buf));
Azure.IoT Build 0:fa2de1b79154 380 result = HTTPAPI_OK;
Azure.IoT Build 0:fa2de1b79154 381 }
Azure.IoT Build 0:fa2de1b79154 382 }
Azure.IoT Build 0:fa2de1b79154 383 else
Azure.IoT Build 0:fa2de1b79154 384 {
Azure.IoT Build 0:fa2de1b79154 385 result = HTTPAPI_OK;
Azure.IoT Build 0:fa2de1b79154 386 }
Azure.IoT Build 0:fa2de1b79154 387 }
Azure.IoT Build 0:fa2de1b79154 388 else
Azure.IoT Build 0:fa2de1b79154 389 {
Azure.IoT Build 0:fa2de1b79154 390 size_t size = 0;
Azure.IoT Build 0:fa2de1b79154 391 result = HTTPAPI_OK;
Azure.IoT Build 0:fa2de1b79154 392 for (;;)
Azure.IoT Build 0:fa2de1b79154 393 {
Azure.IoT Build 0:fa2de1b79154 394 int chunkSize;
Azure.IoT Build 0:fa2de1b79154 395 if (readLine(con, buf, sizeof(buf)) < 0) // read [length in hex]/r/n
Azure.IoT Build 0:fa2de1b79154 396 {
Azure.IoT Build 0:fa2de1b79154 397 result = HTTPAPI_READ_DATA_FAILED;
AzureIoTClient 1:9190c0f4d23a 398 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 0:fa2de1b79154 399 goto exit;
Azure.IoT Build 0:fa2de1b79154 400 }
Azure.IoT Build 0:fa2de1b79154 401 if (sscanf(buf, "%x", &chunkSize) != 1) // chunkSize is length of next line (/r/n is not counted)
Azure.IoT Build 0:fa2de1b79154 402 {
Azure.IoT Build 0:fa2de1b79154 403 //Cannot match string, error
Azure.IoT Build 0:fa2de1b79154 404 result = HTTPAPI_RECEIVE_RESPONSE_FAILED;
AzureIoTClient 1:9190c0f4d23a 405 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 0:fa2de1b79154 406 goto exit;
Azure.IoT Build 0:fa2de1b79154 407 }
Azure.IoT Build 0:fa2de1b79154 408
Azure.IoT Build 0:fa2de1b79154 409 if (chunkSize == 0)
Azure.IoT Build 0:fa2de1b79154 410 {
Azure.IoT Build 0:fa2de1b79154 411 // 0 length means next line is just '\r\n' and end of chunks
Azure.IoT Build 0:fa2de1b79154 412 if (readChunk(con, (char*)buf, 2) < 0
Azure.IoT Build 0:fa2de1b79154 413 || buf[0] != '\r' || buf[1] != '\n') // skip /r/n
Azure.IoT Build 0:fa2de1b79154 414 {
Azure.IoT Build 0:fa2de1b79154 415 (void)BUFFER_unbuild(responseContent);
Azure.IoT Build 0:fa2de1b79154 416
Azure.IoT Build 0:fa2de1b79154 417 result = HTTPAPI_READ_DATA_FAILED;
AzureIoTClient 1:9190c0f4d23a 418 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 0:fa2de1b79154 419 goto exit;
Azure.IoT Build 0:fa2de1b79154 420 }
Azure.IoT Build 0:fa2de1b79154 421 break;
Azure.IoT Build 0:fa2de1b79154 422 }
Azure.IoT Build 0:fa2de1b79154 423 else
Azure.IoT Build 0:fa2de1b79154 424 {
Azure.IoT Build 0:fa2de1b79154 425 if (responseContent != NULL)
Azure.IoT Build 0:fa2de1b79154 426 {
Azure.IoT Build 0:fa2de1b79154 427 if (BUFFER_enlarge(responseContent, chunkSize) != 0)
Azure.IoT Build 0:fa2de1b79154 428 {
Azure.IoT Build 0:fa2de1b79154 429 (void)BUFFER_unbuild(responseContent);
Azure.IoT Build 0:fa2de1b79154 430
Azure.IoT Build 0:fa2de1b79154 431 result = HTTPAPI_ALLOC_FAILED;
AzureIoTClient 1:9190c0f4d23a 432 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 0:fa2de1b79154 433 }
Azure.IoT Build 0:fa2de1b79154 434 else if (BUFFER_content(responseContent, &receivedContent) != 0)
Azure.IoT Build 0:fa2de1b79154 435 {
Azure.IoT Build 0:fa2de1b79154 436 (void)BUFFER_unbuild(responseContent);
Azure.IoT Build 0:fa2de1b79154 437
Azure.IoT Build 0:fa2de1b79154 438 result = HTTPAPI_ALLOC_FAILED;
AzureIoTClient 1:9190c0f4d23a 439 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 0:fa2de1b79154 440 }
Azure.IoT Build 0:fa2de1b79154 441
Azure.IoT Build 0:fa2de1b79154 442 if (readChunk(con, (char*)receivedContent + size, chunkSize) < 0)
Azure.IoT Build 0:fa2de1b79154 443 {
Azure.IoT Build 0:fa2de1b79154 444 result = HTTPAPI_READ_DATA_FAILED;
AzureIoTClient 1:9190c0f4d23a 445 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 0:fa2de1b79154 446 goto exit;
Azure.IoT Build 0:fa2de1b79154 447 }
Azure.IoT Build 0:fa2de1b79154 448 }
Azure.IoT Build 0:fa2de1b79154 449 else
Azure.IoT Build 0:fa2de1b79154 450 {
Azure.IoT Build 0:fa2de1b79154 451 if (skipN(con, chunkSize, buf, sizeof(buf)) < 0)
Azure.IoT Build 0:fa2de1b79154 452 {
Azure.IoT Build 0:fa2de1b79154 453 result = HTTPAPI_READ_DATA_FAILED;
AzureIoTClient 1:9190c0f4d23a 454 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 0:fa2de1b79154 455 goto exit;
Azure.IoT Build 0:fa2de1b79154 456 }
Azure.IoT Build 0:fa2de1b79154 457 }
Azure.IoT Build 0:fa2de1b79154 458
Azure.IoT Build 0:fa2de1b79154 459 if (readChunk(con, (char*)buf, 2) < 0
Azure.IoT Build 0:fa2de1b79154 460 || buf[0] != '\r' || buf[1] != '\n') // skip /r/n
Azure.IoT Build 0:fa2de1b79154 461 {
Azure.IoT Build 0:fa2de1b79154 462 result = HTTPAPI_READ_DATA_FAILED;
AzureIoTClient 1:9190c0f4d23a 463 LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
Azure.IoT Build 0:fa2de1b79154 464 goto exit;
Azure.IoT Build 0:fa2de1b79154 465 }
Azure.IoT Build 0:fa2de1b79154 466 size += chunkSize;
Azure.IoT Build 0:fa2de1b79154 467 }
Azure.IoT Build 0:fa2de1b79154 468 }
Azure.IoT Build 0:fa2de1b79154 469
Azure.IoT Build 0:fa2de1b79154 470 }
Azure.IoT Build 0:fa2de1b79154 471
Azure.IoT Build 0:fa2de1b79154 472 exit:
Azure.IoT Build 0:fa2de1b79154 473 return result;
Azure.IoT Build 0:fa2de1b79154 474 }
Azure.IoT Build 0:fa2de1b79154 475
Azure.IoT Build 0:fa2de1b79154 476 HTTPAPI_RESULT HTTPAPI_SetOption(HTTP_HANDLE handle, const char* optionName, const void* value)
Azure.IoT Build 0:fa2de1b79154 477 {
Azure.IoT Build 0:fa2de1b79154 478 HTTPAPI_RESULT result;
Azure.IoT Build 0:fa2de1b79154 479 if (
Azure.IoT Build 0:fa2de1b79154 480 (handle == NULL) ||
Azure.IoT Build 0:fa2de1b79154 481 (optionName == NULL) ||
Azure.IoT Build 0:fa2de1b79154 482 (value == NULL)
Azure.IoT Build 0:fa2de1b79154 483 )
Azure.IoT Build 0:fa2de1b79154 484 {
Azure.IoT Build 0:fa2de1b79154 485 result = HTTPAPI_INVALID_ARG;
AzureIoTClient 1:9190c0f4d23a 486 LogError("invalid parameter (NULL) passed to HTTPAPI_SetOption");
Azure.IoT Build 0:fa2de1b79154 487 }
Azure.IoT Build 0:fa2de1b79154 488 else if (strcmp("TrustedCerts", optionName) == 0)
Azure.IoT Build 0:fa2de1b79154 489 {
Azure.IoT Build 0:fa2de1b79154 490 HTTP_HANDLE_DATA* h = (HTTP_HANDLE_DATA*)handle;
Azure.IoT Build 0:fa2de1b79154 491 if (h->certificate)
Azure.IoT Build 0:fa2de1b79154 492 {
Azure.IoT Build 0:fa2de1b79154 493 delete[] h->certificate;
Azure.IoT Build 0:fa2de1b79154 494 }
Azure.IoT Build 0:fa2de1b79154 495
Azure.IoT Build 0:fa2de1b79154 496 int len = strlen((char*)value);
Azure.IoT Build 0:fa2de1b79154 497 h->certificate = new char[len + 1];
Azure.IoT Build 0:fa2de1b79154 498 if (h->certificate == NULL)
Azure.IoT Build 0:fa2de1b79154 499 {
Azure.IoT Build 0:fa2de1b79154 500 result = HTTPAPI_ERROR;
AzureIoTClient 1:9190c0f4d23a 501 LogError("unable to allocate certificate memory in HTTPAPI_SetOption");
Azure.IoT Build 0:fa2de1b79154 502 }
Azure.IoT Build 0:fa2de1b79154 503 else
Azure.IoT Build 0:fa2de1b79154 504 {
Azure.IoT Build 0:fa2de1b79154 505 (void)strcpy(h->certificate, (const char*)value);
Azure.IoT Build 0:fa2de1b79154 506 result = HTTPAPI_OK;
Azure.IoT Build 0:fa2de1b79154 507 }
Azure.IoT Build 0:fa2de1b79154 508 }
Azure.IoT Build 0:fa2de1b79154 509 else
Azure.IoT Build 0:fa2de1b79154 510 {
Azure.IoT Build 0:fa2de1b79154 511 result = HTTPAPI_INVALID_ARG;
AzureIoTClient 1:9190c0f4d23a 512 LogError("unknown option %s", optionName);
Azure.IoT Build 0:fa2de1b79154 513 }
Azure.IoT Build 0:fa2de1b79154 514 return result;
Azure.IoT Build 0:fa2de1b79154 515 }
Azure.IoT Build 0:fa2de1b79154 516
Azure.IoT Build 0:fa2de1b79154 517 HTTPAPI_RESULT HTTPAPI_CloneOption(const char* optionName, const void* value, const void** savedValue)
Azure.IoT Build 0:fa2de1b79154 518 {
Azure.IoT Build 0:fa2de1b79154 519 HTTPAPI_RESULT result;
Azure.IoT Build 0:fa2de1b79154 520 if (
Azure.IoT Build 0:fa2de1b79154 521 (optionName == NULL) ||
Azure.IoT Build 0:fa2de1b79154 522 (value == NULL) ||
Azure.IoT Build 0:fa2de1b79154 523 (savedValue == NULL)
Azure.IoT Build 0:fa2de1b79154 524 )
Azure.IoT Build 0:fa2de1b79154 525 {
Azure.IoT Build 0:fa2de1b79154 526 result = HTTPAPI_INVALID_ARG;
AzureIoTClient 1:9190c0f4d23a 527 LogError("invalid argument(NULL) passed to HTTPAPI_CloneOption");
Azure.IoT Build 0:fa2de1b79154 528 }
Azure.IoT Build 0:fa2de1b79154 529 else if (strcmp("TrustedCerts", optionName) == 0)
Azure.IoT Build 0:fa2de1b79154 530 {
Azure.IoT Build 0:fa2de1b79154 531 size_t certLen = strlen((const char*)value);
Azure.IoT Build 0:fa2de1b79154 532 char* tempCert = (char*)malloc(certLen+1);
Azure.IoT Build 0:fa2de1b79154 533 if (tempCert == NULL)
Azure.IoT Build 0:fa2de1b79154 534 {
Azure.IoT Build 0:fa2de1b79154 535 result = HTTPAPI_INVALID_ARG;
AzureIoTClient 1:9190c0f4d23a 536 LogError("unable to allocate certificate memory in HTTPAPI_CloneOption");
Azure.IoT Build 0:fa2de1b79154 537 }
Azure.IoT Build 0:fa2de1b79154 538 else
Azure.IoT Build 0:fa2de1b79154 539 {
Azure.IoT Build 0:fa2de1b79154 540 (void)strcpy(tempCert, (const char*)value);
Azure.IoT Build 0:fa2de1b79154 541 *savedValue = tempCert;
Azure.IoT Build 0:fa2de1b79154 542 result = HTTPAPI_OK;
Azure.IoT Build 0:fa2de1b79154 543 }
Azure.IoT Build 0:fa2de1b79154 544 }
Azure.IoT Build 0:fa2de1b79154 545 else
Azure.IoT Build 0:fa2de1b79154 546 {
Azure.IoT Build 0:fa2de1b79154 547 result = HTTPAPI_INVALID_ARG;
AzureIoTClient 1:9190c0f4d23a 548 LogError("unknown option %s", optionName);
Azure.IoT Build 0:fa2de1b79154 549 }
Azure.IoT Build 0:fa2de1b79154 550 return result;
Azure.IoT Build 0:fa2de1b79154 551 }