Xin Zhang / azure-iot-c-sdk-f767zi

Dependents:   samplemqtt

Committer:
XinZhangMS
Date:
Thu Aug 23 06:52:14 2018 +0000
Revision:
0:f7f1f0d76dd6
azure-c-sdk for mbed os supporting NUCLEO_F767ZI

Who changed what in which revision?

UserRevisionLine numberNew contents of line
XinZhangMS 0:f7f1f0d76dd6 1 // Copyright (c) Microsoft. All rights reserved.
XinZhangMS 0:f7f1f0d76dd6 2 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
XinZhangMS 0:f7f1f0d76dd6 3
XinZhangMS 0:f7f1f0d76dd6 4 #include <stdlib.h>
XinZhangMS 0:f7f1f0d76dd6 5 #include <stddef.h>
XinZhangMS 0:f7f1f0d76dd6 6 #include <stdbool.h>
XinZhangMS 0:f7f1f0d76dd6 7 #include <ctype.h>
XinZhangMS 0:f7f1f0d76dd6 8
XinZhangMS 0:f7f1f0d76dd6 9 #include "azure_c_shared_utility/umock_c_prod.h"
XinZhangMS 0:f7f1f0d76dd6 10 #include "azure_c_shared_utility/gballoc.h"
XinZhangMS 0:f7f1f0d76dd6 11
XinZhangMS 0:f7f1f0d76dd6 12 #include <string.h>
XinZhangMS 0:f7f1f0d76dd6 13 #include "azure_uhttp_c/uhttp.h"
XinZhangMS 0:f7f1f0d76dd6 14 #include "azure_c_shared_utility/httpheaders.h"
XinZhangMS 0:f7f1f0d76dd6 15 #include "azure_c_shared_utility/crt_abstractions.h"
XinZhangMS 0:f7f1f0d76dd6 16 #include "azure_c_shared_utility/strings.h"
XinZhangMS 0:f7f1f0d76dd6 17 #include "azure_c_shared_utility/xlogging.h"
XinZhangMS 0:f7f1f0d76dd6 18 #include "azure_c_shared_utility/buffer_.h"
XinZhangMS 0:f7f1f0d76dd6 19 #include "azure_c_shared_utility/singlylinkedlist.h"
XinZhangMS 0:f7f1f0d76dd6 20 #include "azure_c_shared_utility/shared_util_options.h"
XinZhangMS 0:f7f1f0d76dd6 21 #include "azure_c_shared_utility/optimize_size.h"
XinZhangMS 0:f7f1f0d76dd6 22
XinZhangMS 0:f7f1f0d76dd6 23 #define MAX_HOSTNAME 64
XinZhangMS 0:f7f1f0d76dd6 24 #define TIME_MAX_BUFFER 16
XinZhangMS 0:f7f1f0d76dd6 25 #define HTTP_CRLF_LEN 2
XinZhangMS 0:f7f1f0d76dd6 26 #define HTTP_END_TOKEN_LEN 4
XinZhangMS 0:f7f1f0d76dd6 27
XinZhangMS 0:f7f1f0d76dd6 28 static const char* HTTP_REQUEST_LINE_FMT = "%s %s HTTP/1.1\r\n";
XinZhangMS 0:f7f1f0d76dd6 29 static const char* HTTP_HOST = "Host";
XinZhangMS 0:f7f1f0d76dd6 30 static const char* HTTP_CONTENT_LEN = "content-length";
XinZhangMS 0:f7f1f0d76dd6 31 static const char* HTTP_TRANSFER_ENCODING = "transfer-encoding";
XinZhangMS 0:f7f1f0d76dd6 32 //static const char* HTTP_CHUNKED_ENCODING_HDR = "Transfer-Encoding: chunked\r\n";
XinZhangMS 0:f7f1f0d76dd6 33 static const char* HTTP_CRLF_VALUE = "\r\n";
XinZhangMS 0:f7f1f0d76dd6 34 //static const char* FORMAT_HEX_CHAR = "0x%02x ";
XinZhangMS 0:f7f1f0d76dd6 35
XinZhangMS 0:f7f1f0d76dd6 36 typedef enum RESPONSE_MESSAGE_STATE_TAG
XinZhangMS 0:f7f1f0d76dd6 37 {
XinZhangMS 0:f7f1f0d76dd6 38 state_initial,
XinZhangMS 0:f7f1f0d76dd6 39 state_opening,
XinZhangMS 0:f7f1f0d76dd6 40 state_open,
XinZhangMS 0:f7f1f0d76dd6 41 state_process_status_line,
XinZhangMS 0:f7f1f0d76dd6 42 state_process_headers,
XinZhangMS 0:f7f1f0d76dd6 43 state_process_body,
XinZhangMS 0:f7f1f0d76dd6 44 state_process_chunked_body,
XinZhangMS 0:f7f1f0d76dd6 45
XinZhangMS 0:f7f1f0d76dd6 46 state_send_user_callback,
XinZhangMS 0:f7f1f0d76dd6 47 state_parse_complete,
XinZhangMS 0:f7f1f0d76dd6 48
XinZhangMS 0:f7f1f0d76dd6 49 state_closing,
XinZhangMS 0:f7f1f0d76dd6 50 state_closed,
XinZhangMS 0:f7f1f0d76dd6 51 state_error
XinZhangMS 0:f7f1f0d76dd6 52 } RESPONSE_MESSAGE_STATE;
XinZhangMS 0:f7f1f0d76dd6 53
XinZhangMS 0:f7f1f0d76dd6 54 typedef struct HTTP_RECV_DATA_TAG
XinZhangMS 0:f7f1f0d76dd6 55 {
XinZhangMS 0:f7f1f0d76dd6 56 ON_HTTP_REQUEST_CALLBACK on_request_callback;
XinZhangMS 0:f7f1f0d76dd6 57 void* user_ctx;
XinZhangMS 0:f7f1f0d76dd6 58 int status_code;
XinZhangMS 0:f7f1f0d76dd6 59 RESPONSE_MESSAGE_STATE recv_state;
XinZhangMS 0:f7f1f0d76dd6 60 HTTP_HEADERS_HANDLE resp_header;
XinZhangMS 0:f7f1f0d76dd6 61 BUFFER_HANDLE msg_body;
XinZhangMS 0:f7f1f0d76dd6 62 size_t total_body_len;
XinZhangMS 0:f7f1f0d76dd6 63 BUFFER_HANDLE accrual_buff;
XinZhangMS 0:f7f1f0d76dd6 64 bool chunked_reply;
XinZhangMS 0:f7f1f0d76dd6 65 } HTTP_RECV_DATA;
XinZhangMS 0:f7f1f0d76dd6 66
XinZhangMS 0:f7f1f0d76dd6 67 typedef struct HTTP_CLIENT_HANDLE_DATA_TAG
XinZhangMS 0:f7f1f0d76dd6 68 {
XinZhangMS 0:f7f1f0d76dd6 69 XIO_HANDLE xio_handle;
XinZhangMS 0:f7f1f0d76dd6 70 ON_HTTP_OPEN_COMPLETE_CALLBACK on_connect;
XinZhangMS 0:f7f1f0d76dd6 71 void* connect_user_ctx;
XinZhangMS 0:f7f1f0d76dd6 72 ON_HTTP_ERROR_CALLBACK on_error;
XinZhangMS 0:f7f1f0d76dd6 73 void* error_user_ctx;
XinZhangMS 0:f7f1f0d76dd6 74 ON_HTTP_CLOSED_CALLBACK on_close_callback;
XinZhangMS 0:f7f1f0d76dd6 75 void* close_user_ctx;
XinZhangMS 0:f7f1f0d76dd6 76 HTTP_RECV_DATA recv_msg;
XinZhangMS 0:f7f1f0d76dd6 77 bool chunk_request;
XinZhangMS 0:f7f1f0d76dd6 78 bool trace_on;
XinZhangMS 0:f7f1f0d76dd6 79 bool trace_body;
XinZhangMS 0:f7f1f0d76dd6 80 char* host_name;
XinZhangMS 0:f7f1f0d76dd6 81 int port_num;
XinZhangMS 0:f7f1f0d76dd6 82 SINGLYLINKEDLIST_HANDLE data_list;
XinZhangMS 0:f7f1f0d76dd6 83 bool cert_type_ecc;
XinZhangMS 0:f7f1f0d76dd6 84 char* x509_cert;
XinZhangMS 0:f7f1f0d76dd6 85 char* x509_pk;
XinZhangMS 0:f7f1f0d76dd6 86 char* certificate;
XinZhangMS 0:f7f1f0d76dd6 87 int connected;
XinZhangMS 0:f7f1f0d76dd6 88 } HTTP_CLIENT_HANDLE_DATA;
XinZhangMS 0:f7f1f0d76dd6 89
XinZhangMS 0:f7f1f0d76dd6 90 typedef struct HTTP_SEND_DATA_TAG
XinZhangMS 0:f7f1f0d76dd6 91 {
XinZhangMS 0:f7f1f0d76dd6 92 HTTP_CLIENT_REQUEST_TYPE request_type;
XinZhangMS 0:f7f1f0d76dd6 93 STRING_HANDLE relative_path;
XinZhangMS 0:f7f1f0d76dd6 94 STRING_HANDLE header_line;
XinZhangMS 0:f7f1f0d76dd6 95 BUFFER_HANDLE content;
XinZhangMS 0:f7f1f0d76dd6 96 } HTTP_SEND_DATA;
XinZhangMS 0:f7f1f0d76dd6 97
XinZhangMS 0:f7f1f0d76dd6 98 static void send_complete_callback(void* context, IO_SEND_RESULT send_result)
XinZhangMS 0:f7f1f0d76dd6 99 {
XinZhangMS 0:f7f1f0d76dd6 100 (void)context;(void)send_result;
XinZhangMS 0:f7f1f0d76dd6 101 }
XinZhangMS 0:f7f1f0d76dd6 102
XinZhangMS 0:f7f1f0d76dd6 103 static int initialize_received_data(HTTP_CLIENT_HANDLE_DATA* http_data)
XinZhangMS 0:f7f1f0d76dd6 104 {
XinZhangMS 0:f7f1f0d76dd6 105 int result = 0;
XinZhangMS 0:f7f1f0d76dd6 106
XinZhangMS 0:f7f1f0d76dd6 107 // Initialize data if neccessary
XinZhangMS 0:f7f1f0d76dd6 108 if (http_data->recv_msg.resp_header == NULL)
XinZhangMS 0:f7f1f0d76dd6 109 {
XinZhangMS 0:f7f1f0d76dd6 110 http_data->recv_msg.resp_header = HTTPHeaders_Alloc();
XinZhangMS 0:f7f1f0d76dd6 111 if (http_data->recv_msg.resp_header == NULL)
XinZhangMS 0:f7f1f0d76dd6 112 {
XinZhangMS 0:f7f1f0d76dd6 113 /* Codes_SRS_UHTTP_07_048: [ If any error is encountered on_bytes_received shall set the state to error. ] */
XinZhangMS 0:f7f1f0d76dd6 114 LogError("Failure creating Http header.");
XinZhangMS 0:f7f1f0d76dd6 115 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 116 }
XinZhangMS 0:f7f1f0d76dd6 117 }
XinZhangMS 0:f7f1f0d76dd6 118 if (result == 0 && http_data->recv_msg.accrual_buff == NULL)
XinZhangMS 0:f7f1f0d76dd6 119 {
XinZhangMS 0:f7f1f0d76dd6 120 http_data->recv_msg.accrual_buff = BUFFER_new();
XinZhangMS 0:f7f1f0d76dd6 121 if (http_data->recv_msg.accrual_buff == NULL)
XinZhangMS 0:f7f1f0d76dd6 122 {
XinZhangMS 0:f7f1f0d76dd6 123 /* Codes_SRS_UHTTP_07_048: [ If any error is encountered on_bytes_received shall set the state to error. ] */
XinZhangMS 0:f7f1f0d76dd6 124 LogError("Failure creating accrual buffer.");
XinZhangMS 0:f7f1f0d76dd6 125 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 126 }
XinZhangMS 0:f7f1f0d76dd6 127 }
XinZhangMS 0:f7f1f0d76dd6 128 http_data->recv_msg.chunked_reply = false;
XinZhangMS 0:f7f1f0d76dd6 129 return result;
XinZhangMS 0:f7f1f0d76dd6 130 }
XinZhangMS 0:f7f1f0d76dd6 131
XinZhangMS 0:f7f1f0d76dd6 132 static int process_status_code_line(const unsigned char* buffer, size_t len, size_t* position, int* statusLen)
XinZhangMS 0:f7f1f0d76dd6 133 {
XinZhangMS 0:f7f1f0d76dd6 134 int result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 135 size_t index;
XinZhangMS 0:f7f1f0d76dd6 136 int spaceFound = 0;
XinZhangMS 0:f7f1f0d76dd6 137 const char* initSpace = NULL;
XinZhangMS 0:f7f1f0d76dd6 138 char status_code[4];
XinZhangMS 0:f7f1f0d76dd6 139
XinZhangMS 0:f7f1f0d76dd6 140 for (index = 0; index < len; index++)
XinZhangMS 0:f7f1f0d76dd6 141 {
XinZhangMS 0:f7f1f0d76dd6 142 if (buffer[index] == ' ')
XinZhangMS 0:f7f1f0d76dd6 143 {
XinZhangMS 0:f7f1f0d76dd6 144 if (spaceFound == 1)
XinZhangMS 0:f7f1f0d76dd6 145 {
XinZhangMS 0:f7f1f0d76dd6 146 strncpy(status_code, initSpace, 3);
XinZhangMS 0:f7f1f0d76dd6 147 status_code[3] = '\0';
XinZhangMS 0:f7f1f0d76dd6 148 }
XinZhangMS 0:f7f1f0d76dd6 149 else
XinZhangMS 0:f7f1f0d76dd6 150 {
XinZhangMS 0:f7f1f0d76dd6 151 initSpace = (const char*)buffer+index+1;
XinZhangMS 0:f7f1f0d76dd6 152 }
XinZhangMS 0:f7f1f0d76dd6 153 spaceFound++;
XinZhangMS 0:f7f1f0d76dd6 154 }
XinZhangMS 0:f7f1f0d76dd6 155 else if (buffer[index] == '\n')
XinZhangMS 0:f7f1f0d76dd6 156 {
XinZhangMS 0:f7f1f0d76dd6 157 *statusLen = (int)atol(status_code);
XinZhangMS 0:f7f1f0d76dd6 158 if (index < len)
XinZhangMS 0:f7f1f0d76dd6 159 {
XinZhangMS 0:f7f1f0d76dd6 160 *position = index+1;
XinZhangMS 0:f7f1f0d76dd6 161 }
XinZhangMS 0:f7f1f0d76dd6 162 else
XinZhangMS 0:f7f1f0d76dd6 163 {
XinZhangMS 0:f7f1f0d76dd6 164 *position = index;
XinZhangMS 0:f7f1f0d76dd6 165 }
XinZhangMS 0:f7f1f0d76dd6 166 result = 0;
XinZhangMS 0:f7f1f0d76dd6 167 break;
XinZhangMS 0:f7f1f0d76dd6 168 }
XinZhangMS 0:f7f1f0d76dd6 169 }
XinZhangMS 0:f7f1f0d76dd6 170 return result;
XinZhangMS 0:f7f1f0d76dd6 171 }
XinZhangMS 0:f7f1f0d76dd6 172
XinZhangMS 0:f7f1f0d76dd6 173 static int process_header_line(const unsigned char* buffer, size_t len, size_t* position, HTTP_HEADERS_HANDLE resp_header, size_t* contentLen, bool* isChunked)
XinZhangMS 0:f7f1f0d76dd6 174 {
XinZhangMS 0:f7f1f0d76dd6 175 int result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 176 size_t index;
XinZhangMS 0:f7f1f0d76dd6 177 const unsigned char* targetPos = buffer;
XinZhangMS 0:f7f1f0d76dd6 178 bool crlfEncounted = false;
XinZhangMS 0:f7f1f0d76dd6 179 bool colonEncountered = false;
XinZhangMS 0:f7f1f0d76dd6 180 char* headerKey = NULL;
XinZhangMS 0:f7f1f0d76dd6 181 bool continueProcessing = true;
XinZhangMS 0:f7f1f0d76dd6 182
XinZhangMS 0:f7f1f0d76dd6 183 for (index = 0; index < len && continueProcessing; index++)
XinZhangMS 0:f7f1f0d76dd6 184 {
XinZhangMS 0:f7f1f0d76dd6 185 if (buffer[index] == ':' && !colonEncountered)
XinZhangMS 0:f7f1f0d76dd6 186 {
XinZhangMS 0:f7f1f0d76dd6 187 colonEncountered = true;
XinZhangMS 0:f7f1f0d76dd6 188 size_t keyLen = (&buffer[index])-targetPos;
XinZhangMS 0:f7f1f0d76dd6 189 headerKey = (char*)malloc(keyLen+1);
XinZhangMS 0:f7f1f0d76dd6 190 if (headerKey == NULL)
XinZhangMS 0:f7f1f0d76dd6 191 {
XinZhangMS 0:f7f1f0d76dd6 192 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 193 continueProcessing = false;
XinZhangMS 0:f7f1f0d76dd6 194 }
XinZhangMS 0:f7f1f0d76dd6 195 else
XinZhangMS 0:f7f1f0d76dd6 196 {
XinZhangMS 0:f7f1f0d76dd6 197 memcpy(headerKey, targetPos, keyLen);
XinZhangMS 0:f7f1f0d76dd6 198 headerKey[keyLen] = '\0';
XinZhangMS 0:f7f1f0d76dd6 199
XinZhangMS 0:f7f1f0d76dd6 200 // Convert to lower case
XinZhangMS 0:f7f1f0d76dd6 201 for (size_t inner = 0; inner < keyLen; inner++)
XinZhangMS 0:f7f1f0d76dd6 202 {
XinZhangMS 0:f7f1f0d76dd6 203 headerKey[inner] = (char)tolower(headerKey[inner]);
XinZhangMS 0:f7f1f0d76dd6 204 }
XinZhangMS 0:f7f1f0d76dd6 205
XinZhangMS 0:f7f1f0d76dd6 206 targetPos = buffer+index+1;
XinZhangMS 0:f7f1f0d76dd6 207 crlfEncounted = false;
XinZhangMS 0:f7f1f0d76dd6 208 }
XinZhangMS 0:f7f1f0d76dd6 209 }
XinZhangMS 0:f7f1f0d76dd6 210 else if (buffer[index] == '\r')
XinZhangMS 0:f7f1f0d76dd6 211 {
XinZhangMS 0:f7f1f0d76dd6 212 if (headerKey != NULL)
XinZhangMS 0:f7f1f0d76dd6 213 {
XinZhangMS 0:f7f1f0d76dd6 214 // Remove leading spaces
XinZhangMS 0:f7f1f0d76dd6 215 while (*targetPos == 32) { targetPos++; }
XinZhangMS 0:f7f1f0d76dd6 216
XinZhangMS 0:f7f1f0d76dd6 217 size_t valueLen = (&buffer[index])-targetPos;
XinZhangMS 0:f7f1f0d76dd6 218 char* headerValue = (char*)malloc(valueLen+1);
XinZhangMS 0:f7f1f0d76dd6 219 if (headerValue == NULL)
XinZhangMS 0:f7f1f0d76dd6 220 {
XinZhangMS 0:f7f1f0d76dd6 221 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 222 continueProcessing = false;
XinZhangMS 0:f7f1f0d76dd6 223 }
XinZhangMS 0:f7f1f0d76dd6 224 else
XinZhangMS 0:f7f1f0d76dd6 225 {
XinZhangMS 0:f7f1f0d76dd6 226 memcpy(headerValue, targetPos, valueLen);
XinZhangMS 0:f7f1f0d76dd6 227 headerValue[valueLen] = '\0';
XinZhangMS 0:f7f1f0d76dd6 228
XinZhangMS 0:f7f1f0d76dd6 229 if (HTTPHeaders_AddHeaderNameValuePair(resp_header, headerKey, headerValue) != HTTP_HEADERS_OK)
XinZhangMS 0:f7f1f0d76dd6 230 {
XinZhangMS 0:f7f1f0d76dd6 231 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 232 continueProcessing = false;
XinZhangMS 0:f7f1f0d76dd6 233 }
XinZhangMS 0:f7f1f0d76dd6 234 else
XinZhangMS 0:f7f1f0d76dd6 235 {
XinZhangMS 0:f7f1f0d76dd6 236 if (strcmp(headerKey, HTTP_CONTENT_LEN) == 0)
XinZhangMS 0:f7f1f0d76dd6 237 {
XinZhangMS 0:f7f1f0d76dd6 238 *isChunked = false;
XinZhangMS 0:f7f1f0d76dd6 239 *contentLen = atol(headerValue);
XinZhangMS 0:f7f1f0d76dd6 240 }
XinZhangMS 0:f7f1f0d76dd6 241 else if (strcmp(headerKey, HTTP_TRANSFER_ENCODING) == 0)
XinZhangMS 0:f7f1f0d76dd6 242 {
XinZhangMS 0:f7f1f0d76dd6 243 *isChunked = true;
XinZhangMS 0:f7f1f0d76dd6 244 *contentLen = 0;
XinZhangMS 0:f7f1f0d76dd6 245 }
XinZhangMS 0:f7f1f0d76dd6 246 if (index < len)
XinZhangMS 0:f7f1f0d76dd6 247 {
XinZhangMS 0:f7f1f0d76dd6 248 *position = index;
XinZhangMS 0:f7f1f0d76dd6 249 }
XinZhangMS 0:f7f1f0d76dd6 250 else
XinZhangMS 0:f7f1f0d76dd6 251 {
XinZhangMS 0:f7f1f0d76dd6 252 *position = index-1;
XinZhangMS 0:f7f1f0d76dd6 253 }
XinZhangMS 0:f7f1f0d76dd6 254 }
XinZhangMS 0:f7f1f0d76dd6 255 }
XinZhangMS 0:f7f1f0d76dd6 256 free(headerKey);
XinZhangMS 0:f7f1f0d76dd6 257 headerKey = NULL;
XinZhangMS 0:f7f1f0d76dd6 258 free(headerValue);
XinZhangMS 0:f7f1f0d76dd6 259 }
XinZhangMS 0:f7f1f0d76dd6 260 }
XinZhangMS 0:f7f1f0d76dd6 261 else if (buffer[index] == '\n')
XinZhangMS 0:f7f1f0d76dd6 262 {
XinZhangMS 0:f7f1f0d76dd6 263 if (crlfEncounted)
XinZhangMS 0:f7f1f0d76dd6 264 {
XinZhangMS 0:f7f1f0d76dd6 265 if (index < len)
XinZhangMS 0:f7f1f0d76dd6 266 {
XinZhangMS 0:f7f1f0d76dd6 267 *position = index+1;
XinZhangMS 0:f7f1f0d76dd6 268 }
XinZhangMS 0:f7f1f0d76dd6 269 else
XinZhangMS 0:f7f1f0d76dd6 270 {
XinZhangMS 0:f7f1f0d76dd6 271 *position = index;
XinZhangMS 0:f7f1f0d76dd6 272 }
XinZhangMS 0:f7f1f0d76dd6 273 result = 0;
XinZhangMS 0:f7f1f0d76dd6 274 break;
XinZhangMS 0:f7f1f0d76dd6 275 }
XinZhangMS 0:f7f1f0d76dd6 276 else
XinZhangMS 0:f7f1f0d76dd6 277 {
XinZhangMS 0:f7f1f0d76dd6 278 colonEncountered = false;
XinZhangMS 0:f7f1f0d76dd6 279 crlfEncounted = true;
XinZhangMS 0:f7f1f0d76dd6 280 targetPos = buffer+index+1;
XinZhangMS 0:f7f1f0d76dd6 281 }
XinZhangMS 0:f7f1f0d76dd6 282 }
XinZhangMS 0:f7f1f0d76dd6 283 else
XinZhangMS 0:f7f1f0d76dd6 284 {
XinZhangMS 0:f7f1f0d76dd6 285 crlfEncounted = false;
XinZhangMS 0:f7f1f0d76dd6 286 }
XinZhangMS 0:f7f1f0d76dd6 287 }
XinZhangMS 0:f7f1f0d76dd6 288 if (headerKey != NULL)
XinZhangMS 0:f7f1f0d76dd6 289 {
XinZhangMS 0:f7f1f0d76dd6 290 free(headerKey);
XinZhangMS 0:f7f1f0d76dd6 291 }
XinZhangMS 0:f7f1f0d76dd6 292 return result;
XinZhangMS 0:f7f1f0d76dd6 293 }
XinZhangMS 0:f7f1f0d76dd6 294
XinZhangMS 0:f7f1f0d76dd6 295 static int write_text_line(HTTP_CLIENT_HANDLE_DATA* http_data, const char* text_line)
XinZhangMS 0:f7f1f0d76dd6 296 {
XinZhangMS 0:f7f1f0d76dd6 297 int result;
XinZhangMS 0:f7f1f0d76dd6 298 if (xio_send(http_data->xio_handle, text_line, strlen(text_line), send_complete_callback, NULL) != 0)
XinZhangMS 0:f7f1f0d76dd6 299 {
XinZhangMS 0:f7f1f0d76dd6 300 LogError("Failure calling xio_send.");
XinZhangMS 0:f7f1f0d76dd6 301 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 302 }
XinZhangMS 0:f7f1f0d76dd6 303 else
XinZhangMS 0:f7f1f0d76dd6 304 {
XinZhangMS 0:f7f1f0d76dd6 305 result = 0;
XinZhangMS 0:f7f1f0d76dd6 306 if (http_data->trace_on)
XinZhangMS 0:f7f1f0d76dd6 307 {
XinZhangMS 0:f7f1f0d76dd6 308 LOG(AZ_LOG_TRACE, LOG_LINE, "%s", text_line);
XinZhangMS 0:f7f1f0d76dd6 309 }
XinZhangMS 0:f7f1f0d76dd6 310 }
XinZhangMS 0:f7f1f0d76dd6 311 return result;
XinZhangMS 0:f7f1f0d76dd6 312 }
XinZhangMS 0:f7f1f0d76dd6 313
XinZhangMS 0:f7f1f0d76dd6 314 static int write_data_line(HTTP_CLIENT_HANDLE_DATA* http_data, const unsigned char* data_line, size_t length)
XinZhangMS 0:f7f1f0d76dd6 315 {
XinZhangMS 0:f7f1f0d76dd6 316 int result;
XinZhangMS 0:f7f1f0d76dd6 317 if (xio_send(http_data->xio_handle, data_line, length, send_complete_callback, NULL) != 0)
XinZhangMS 0:f7f1f0d76dd6 318 {
XinZhangMS 0:f7f1f0d76dd6 319 LogError("Failure calling xio_send.");
XinZhangMS 0:f7f1f0d76dd6 320 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 321 }
XinZhangMS 0:f7f1f0d76dd6 322 else
XinZhangMS 0:f7f1f0d76dd6 323 {
XinZhangMS 0:f7f1f0d76dd6 324 result = 0;
XinZhangMS 0:f7f1f0d76dd6 325 if (http_data->trace_on)
XinZhangMS 0:f7f1f0d76dd6 326 {
XinZhangMS 0:f7f1f0d76dd6 327 if (length > 0)
XinZhangMS 0:f7f1f0d76dd6 328 {
XinZhangMS 0:f7f1f0d76dd6 329 if (http_data->trace_body)
XinZhangMS 0:f7f1f0d76dd6 330 {
XinZhangMS 0:f7f1f0d76dd6 331 LOG(AZ_LOG_TRACE, LOG_LINE, "len: %d\r\n%.*s\r\n", (int)length, (int)length, data_line);
XinZhangMS 0:f7f1f0d76dd6 332 }
XinZhangMS 0:f7f1f0d76dd6 333 else
XinZhangMS 0:f7f1f0d76dd6 334 {
XinZhangMS 0:f7f1f0d76dd6 335 LOG(AZ_LOG_TRACE, LOG_LINE, "<data> len: %d\r\n", (int)length);
XinZhangMS 0:f7f1f0d76dd6 336 }
XinZhangMS 0:f7f1f0d76dd6 337 }
XinZhangMS 0:f7f1f0d76dd6 338 else
XinZhangMS 0:f7f1f0d76dd6 339 {
XinZhangMS 0:f7f1f0d76dd6 340 LOG(AZ_LOG_TRACE, LOG_LINE, "len: %d\r\n", (int)length);
XinZhangMS 0:f7f1f0d76dd6 341 }
XinZhangMS 0:f7f1f0d76dd6 342 }
XinZhangMS 0:f7f1f0d76dd6 343 }
XinZhangMS 0:f7f1f0d76dd6 344 return result;
XinZhangMS 0:f7f1f0d76dd6 345 }
XinZhangMS 0:f7f1f0d76dd6 346
XinZhangMS 0:f7f1f0d76dd6 347 static int convert_char_to_hex(const unsigned char* hexText, size_t len)
XinZhangMS 0:f7f1f0d76dd6 348 {
XinZhangMS 0:f7f1f0d76dd6 349 int result = 0;
XinZhangMS 0:f7f1f0d76dd6 350 for (size_t index = 0; index < len; index++)
XinZhangMS 0:f7f1f0d76dd6 351 {
XinZhangMS 0:f7f1f0d76dd6 352 if (hexText[index] == ';')
XinZhangMS 0:f7f1f0d76dd6 353 {
XinZhangMS 0:f7f1f0d76dd6 354 break;
XinZhangMS 0:f7f1f0d76dd6 355 }
XinZhangMS 0:f7f1f0d76dd6 356 else
XinZhangMS 0:f7f1f0d76dd6 357 {
XinZhangMS 0:f7f1f0d76dd6 358 int accumulator = 0;
XinZhangMS 0:f7f1f0d76dd6 359 if (hexText[index] >= 48 && hexText[index] <= 57)
XinZhangMS 0:f7f1f0d76dd6 360 {
XinZhangMS 0:f7f1f0d76dd6 361 accumulator = hexText[index] - 48;
XinZhangMS 0:f7f1f0d76dd6 362 }
XinZhangMS 0:f7f1f0d76dd6 363 else if (hexText[index] >= 65 && hexText[index] <= 70)
XinZhangMS 0:f7f1f0d76dd6 364 {
XinZhangMS 0:f7f1f0d76dd6 365 accumulator = hexText[index] - 55;
XinZhangMS 0:f7f1f0d76dd6 366 }
XinZhangMS 0:f7f1f0d76dd6 367 else if (hexText[index] >= 97 && hexText[index] <= 102)
XinZhangMS 0:f7f1f0d76dd6 368 {
XinZhangMS 0:f7f1f0d76dd6 369 accumulator = hexText[index] - 87;
XinZhangMS 0:f7f1f0d76dd6 370 }
XinZhangMS 0:f7f1f0d76dd6 371 if (index > 0)
XinZhangMS 0:f7f1f0d76dd6 372 {
XinZhangMS 0:f7f1f0d76dd6 373 result = result << 4;
XinZhangMS 0:f7f1f0d76dd6 374 }
XinZhangMS 0:f7f1f0d76dd6 375 result += accumulator;
XinZhangMS 0:f7f1f0d76dd6 376 }
XinZhangMS 0:f7f1f0d76dd6 377 }
XinZhangMS 0:f7f1f0d76dd6 378 return result;
XinZhangMS 0:f7f1f0d76dd6 379 }
XinZhangMS 0:f7f1f0d76dd6 380
XinZhangMS 0:f7f1f0d76dd6 381 static void on_bytes_received(void* context, const unsigned char* buffer, size_t len)
XinZhangMS 0:f7f1f0d76dd6 382 {
XinZhangMS 0:f7f1f0d76dd6 383 HTTP_CLIENT_HANDLE_DATA* http_data = (HTTP_CLIENT_HANDLE_DATA*)context;
XinZhangMS 0:f7f1f0d76dd6 384
XinZhangMS 0:f7f1f0d76dd6 385 if (http_data != NULL && buffer != NULL && len > 0 && http_data->recv_msg.recv_state != state_error)
XinZhangMS 0:f7f1f0d76dd6 386 {
XinZhangMS 0:f7f1f0d76dd6 387 if (http_data->recv_msg.recv_state == state_initial || http_data->recv_msg.recv_state == state_open)
XinZhangMS 0:f7f1f0d76dd6 388 {
XinZhangMS 0:f7f1f0d76dd6 389 if (initialize_received_data(http_data) != 0)
XinZhangMS 0:f7f1f0d76dd6 390 {
XinZhangMS 0:f7f1f0d76dd6 391 http_data->recv_msg.recv_state = state_error;
XinZhangMS 0:f7f1f0d76dd6 392 }
XinZhangMS 0:f7f1f0d76dd6 393 else
XinZhangMS 0:f7f1f0d76dd6 394 {
XinZhangMS 0:f7f1f0d76dd6 395 http_data->recv_msg.recv_state = state_process_status_line;
XinZhangMS 0:f7f1f0d76dd6 396 }
XinZhangMS 0:f7f1f0d76dd6 397 }
XinZhangMS 0:f7f1f0d76dd6 398
XinZhangMS 0:f7f1f0d76dd6 399 // Put the data in the buffer
XinZhangMS 0:f7f1f0d76dd6 400 if (BUFFER_append_build(http_data->recv_msg.accrual_buff, buffer, len) != 0)
XinZhangMS 0:f7f1f0d76dd6 401 {
XinZhangMS 0:f7f1f0d76dd6 402 /* Codes_SRS_UHTTP_07_048: [ If any error is encountered on_bytes_received shall set the state to error. ] */
XinZhangMS 0:f7f1f0d76dd6 403 LogError("Failure appending bytes to buffer.");
XinZhangMS 0:f7f1f0d76dd6 404 http_data->recv_msg.recv_state = state_error;
XinZhangMS 0:f7f1f0d76dd6 405 }
XinZhangMS 0:f7f1f0d76dd6 406
XinZhangMS 0:f7f1f0d76dd6 407 if (http_data->recv_msg.recv_state == state_process_status_line)
XinZhangMS 0:f7f1f0d76dd6 408 {
XinZhangMS 0:f7f1f0d76dd6 409 size_t index = 0;
XinZhangMS 0:f7f1f0d76dd6 410 const unsigned char* stored_bytes = BUFFER_u_char(http_data->recv_msg.accrual_buff);
XinZhangMS 0:f7f1f0d76dd6 411 size_t stored_len = BUFFER_length(http_data->recv_msg.accrual_buff);
XinZhangMS 0:f7f1f0d76dd6 412
XinZhangMS 0:f7f1f0d76dd6 413 int lineComplete = process_status_code_line(stored_bytes, stored_len, &index, &http_data->recv_msg.status_code);
XinZhangMS 0:f7f1f0d76dd6 414 if (lineComplete == 0 && http_data->recv_msg.status_code > 0)
XinZhangMS 0:f7f1f0d76dd6 415 {
XinZhangMS 0:f7f1f0d76dd6 416 if (BUFFER_shrink(http_data->recv_msg.accrual_buff, index, false) != 0)
XinZhangMS 0:f7f1f0d76dd6 417 {
XinZhangMS 0:f7f1f0d76dd6 418 LogError("Failure appending bytes to buffer.");
XinZhangMS 0:f7f1f0d76dd6 419 http_data->recv_msg.recv_state = state_error;
XinZhangMS 0:f7f1f0d76dd6 420 }
XinZhangMS 0:f7f1f0d76dd6 421 else
XinZhangMS 0:f7f1f0d76dd6 422 {
XinZhangMS 0:f7f1f0d76dd6 423 http_data->recv_msg.recv_state = state_process_headers;
XinZhangMS 0:f7f1f0d76dd6 424 }
XinZhangMS 0:f7f1f0d76dd6 425 }
XinZhangMS 0:f7f1f0d76dd6 426 }
XinZhangMS 0:f7f1f0d76dd6 427
XinZhangMS 0:f7f1f0d76dd6 428 if (http_data->recv_msg.recv_state == state_process_headers)
XinZhangMS 0:f7f1f0d76dd6 429 {
XinZhangMS 0:f7f1f0d76dd6 430 size_t index = 0;
XinZhangMS 0:f7f1f0d76dd6 431 const unsigned char* stored_bytes = BUFFER_u_char(http_data->recv_msg.accrual_buff);
XinZhangMS 0:f7f1f0d76dd6 432 size_t stored_len = BUFFER_length(http_data->recv_msg.accrual_buff);
XinZhangMS 0:f7f1f0d76dd6 433
XinZhangMS 0:f7f1f0d76dd6 434 int headerComplete = process_header_line(stored_bytes, stored_len, &index, http_data->recv_msg.resp_header, &http_data->recv_msg.total_body_len, &http_data->recv_msg.chunked_reply);
XinZhangMS 0:f7f1f0d76dd6 435 if (headerComplete == 0)
XinZhangMS 0:f7f1f0d76dd6 436 {
XinZhangMS 0:f7f1f0d76dd6 437 if (http_data->recv_msg.total_body_len == 0)
XinZhangMS 0:f7f1f0d76dd6 438 {
XinZhangMS 0:f7f1f0d76dd6 439 if (http_data->recv_msg.chunked_reply)
XinZhangMS 0:f7f1f0d76dd6 440 {
XinZhangMS 0:f7f1f0d76dd6 441
XinZhangMS 0:f7f1f0d76dd6 442 /* Codes_SRS_UHTTP_07_054: [ If the http header does not include a content length then it indicates a chunk response. ] */
XinZhangMS 0:f7f1f0d76dd6 443 http_data->recv_msg.recv_state = state_process_chunked_body;
XinZhangMS 0:f7f1f0d76dd6 444 }
XinZhangMS 0:f7f1f0d76dd6 445 else
XinZhangMS 0:f7f1f0d76dd6 446 {
XinZhangMS 0:f7f1f0d76dd6 447 // Content len is 0 so we are finished with the body
XinZhangMS 0:f7f1f0d76dd6 448 http_data->recv_msg.recv_state = state_send_user_callback;
XinZhangMS 0:f7f1f0d76dd6 449 }
XinZhangMS 0:f7f1f0d76dd6 450 }
XinZhangMS 0:f7f1f0d76dd6 451 else
XinZhangMS 0:f7f1f0d76dd6 452 {
XinZhangMS 0:f7f1f0d76dd6 453 http_data->recv_msg.recv_state = state_process_body;
XinZhangMS 0:f7f1f0d76dd6 454 }
XinZhangMS 0:f7f1f0d76dd6 455 }
XinZhangMS 0:f7f1f0d76dd6 456 if (index > 0)
XinZhangMS 0:f7f1f0d76dd6 457 {
XinZhangMS 0:f7f1f0d76dd6 458 if (BUFFER_shrink(http_data->recv_msg.accrual_buff, index, false) != 0)
XinZhangMS 0:f7f1f0d76dd6 459 {
XinZhangMS 0:f7f1f0d76dd6 460 LogError("Failure appending bytes to buffer.");
XinZhangMS 0:f7f1f0d76dd6 461 http_data->recv_msg.recv_state = state_error;
XinZhangMS 0:f7f1f0d76dd6 462 }
XinZhangMS 0:f7f1f0d76dd6 463 }
XinZhangMS 0:f7f1f0d76dd6 464 }
XinZhangMS 0:f7f1f0d76dd6 465
XinZhangMS 0:f7f1f0d76dd6 466 if (http_data->recv_msg.recv_state == state_process_body)
XinZhangMS 0:f7f1f0d76dd6 467 {
XinZhangMS 0:f7f1f0d76dd6 468 if (http_data->recv_msg.total_body_len != 0)
XinZhangMS 0:f7f1f0d76dd6 469 {
XinZhangMS 0:f7f1f0d76dd6 470 size_t stored_len = BUFFER_length(http_data->recv_msg.accrual_buff);
XinZhangMS 0:f7f1f0d76dd6 471
XinZhangMS 0:f7f1f0d76dd6 472 if ((http_data->recv_msg.total_body_len == stored_len) || (http_data->recv_msg.total_body_len == (stored_len - HTTP_END_TOKEN_LEN)))
XinZhangMS 0:f7f1f0d76dd6 473 {
XinZhangMS 0:f7f1f0d76dd6 474 if (http_data->recv_msg.msg_body != NULL)
XinZhangMS 0:f7f1f0d76dd6 475 {
XinZhangMS 0:f7f1f0d76dd6 476 BUFFER_delete(http_data->recv_msg.msg_body);
XinZhangMS 0:f7f1f0d76dd6 477 }
XinZhangMS 0:f7f1f0d76dd6 478 if ((http_data->recv_msg.msg_body = BUFFER_clone(http_data->recv_msg.accrual_buff)) == NULL)
XinZhangMS 0:f7f1f0d76dd6 479 {
XinZhangMS 0:f7f1f0d76dd6 480 LogError("Failure cloning BUFFER.");
XinZhangMS 0:f7f1f0d76dd6 481 http_data->recv_msg.recv_state = state_error;
XinZhangMS 0:f7f1f0d76dd6 482 }
XinZhangMS 0:f7f1f0d76dd6 483 else
XinZhangMS 0:f7f1f0d76dd6 484 {
XinZhangMS 0:f7f1f0d76dd6 485 http_data->recv_msg.recv_state = state_send_user_callback;
XinZhangMS 0:f7f1f0d76dd6 486 }
XinZhangMS 0:f7f1f0d76dd6 487 }
XinZhangMS 0:f7f1f0d76dd6 488 else if (stored_len > http_data->recv_msg.total_body_len)
XinZhangMS 0:f7f1f0d76dd6 489 {
XinZhangMS 0:f7f1f0d76dd6 490 LogError("Failure bytes encountered is greater then body length.");
XinZhangMS 0:f7f1f0d76dd6 491 http_data->recv_msg.recv_state = state_error;
XinZhangMS 0:f7f1f0d76dd6 492 }
XinZhangMS 0:f7f1f0d76dd6 493 }
XinZhangMS 0:f7f1f0d76dd6 494 }
XinZhangMS 0:f7f1f0d76dd6 495
XinZhangMS 0:f7f1f0d76dd6 496 if (http_data->recv_msg.recv_state == state_process_chunked_body)
XinZhangMS 0:f7f1f0d76dd6 497 {
XinZhangMS 0:f7f1f0d76dd6 498 const unsigned char* iterator = BUFFER_u_char(http_data->recv_msg.accrual_buff);
XinZhangMS 0:f7f1f0d76dd6 499 const unsigned char* initial_pos = iterator;
XinZhangMS 0:f7f1f0d76dd6 500 const unsigned char* begin = iterator;
XinZhangMS 0:f7f1f0d76dd6 501 const unsigned char* end = iterator;
XinZhangMS 0:f7f1f0d76dd6 502 size_t accural_len = BUFFER_length(http_data->recv_msg.accrual_buff);
XinZhangMS 0:f7f1f0d76dd6 503
XinZhangMS 0:f7f1f0d76dd6 504 /* Codes_SRS_UHTTP_07_059: [ on_bytes_received shall loop throught the stored data to find the /r/n separator. ] */
XinZhangMS 0:f7f1f0d76dd6 505 while (iterator < (initial_pos + accural_len))
XinZhangMS 0:f7f1f0d76dd6 506 {
XinZhangMS 0:f7f1f0d76dd6 507 if (*iterator == '\r')
XinZhangMS 0:f7f1f0d76dd6 508 {
XinZhangMS 0:f7f1f0d76dd6 509 // Don't need anything
XinZhangMS 0:f7f1f0d76dd6 510 end = iterator;
XinZhangMS 0:f7f1f0d76dd6 511 iterator++;
XinZhangMS 0:f7f1f0d76dd6 512 }
XinZhangMS 0:f7f1f0d76dd6 513 else if (*iterator == '\n')
XinZhangMS 0:f7f1f0d76dd6 514 {
XinZhangMS 0:f7f1f0d76dd6 515 size_t data_length = 0;
XinZhangMS 0:f7f1f0d76dd6 516
XinZhangMS 0:f7f1f0d76dd6 517 /* Codes_SRS_UHTTP_07_055: [ on_bytes_received shall convert the hexs length supplied in the response to the data length of the chunked data. ] */
XinZhangMS 0:f7f1f0d76dd6 518 size_t hex_len = end - begin;
XinZhangMS 0:f7f1f0d76dd6 519 data_length = convert_char_to_hex(begin, hex_len);
XinZhangMS 0:f7f1f0d76dd6 520 if (data_length == 0)
XinZhangMS 0:f7f1f0d76dd6 521 {
XinZhangMS 0:f7f1f0d76dd6 522 if (accural_len - (iterator - initial_pos + 1) <= HTTP_END_TOKEN_LEN)
XinZhangMS 0:f7f1f0d76dd6 523 {
XinZhangMS 0:f7f1f0d76dd6 524 http_data->recv_msg.recv_state = state_send_user_callback;
XinZhangMS 0:f7f1f0d76dd6 525 }
XinZhangMS 0:f7f1f0d76dd6 526 else
XinZhangMS 0:f7f1f0d76dd6 527 {
XinZhangMS 0:f7f1f0d76dd6 528 // Need to continue parsing
XinZhangMS 0:f7f1f0d76dd6 529 http_data->recv_msg.recv_state = state_process_headers;
XinZhangMS 0:f7f1f0d76dd6 530 }
XinZhangMS 0:f7f1f0d76dd6 531 break;
XinZhangMS 0:f7f1f0d76dd6 532 }
XinZhangMS 0:f7f1f0d76dd6 533 else if ((data_length + HTTP_CRLF_LEN) < accural_len - (iterator - initial_pos))
XinZhangMS 0:f7f1f0d76dd6 534 {
XinZhangMS 0:f7f1f0d76dd6 535 /* Codes_SRS_UHTTP_07_056: [ After the response chunk is parsed it shall be placed in a BUFFER_HANDLE. ] */
XinZhangMS 0:f7f1f0d76dd6 536 iterator += 1;
XinZhangMS 0:f7f1f0d76dd6 537 if (BUFFER_append_build(http_data->recv_msg.msg_body, iterator, data_length) != 0)
XinZhangMS 0:f7f1f0d76dd6 538 {
XinZhangMS 0:f7f1f0d76dd6 539 /* Codes_SRS_UHTTP_07_048: [ If any error is encountered on_bytes_received shall set the stop processing the request. ] */
XinZhangMS 0:f7f1f0d76dd6 540 LogError("Failure building buffer for chunked data.");
XinZhangMS 0:f7f1f0d76dd6 541 http_data->recv_msg.recv_state = state_error;
XinZhangMS 0:f7f1f0d76dd6 542 }
XinZhangMS 0:f7f1f0d76dd6 543 else
XinZhangMS 0:f7f1f0d76dd6 544 {
XinZhangMS 0:f7f1f0d76dd6 545 /* Codes_SRS_UHTTP_07_060: [ if the data_length specified in the chunk is beyond the amount of data recieved, the parsing shall end and wait for more data. ] */
XinZhangMS 0:f7f1f0d76dd6 546 if (iterator + (data_length + HTTP_CRLF_LEN) > initial_pos + accural_len)
XinZhangMS 0:f7f1f0d76dd6 547 {
XinZhangMS 0:f7f1f0d76dd6 548 LogError("Invalid length specified.");
XinZhangMS 0:f7f1f0d76dd6 549 http_data->recv_msg.recv_state = state_error;
XinZhangMS 0:f7f1f0d76dd6 550 break;
XinZhangMS 0:f7f1f0d76dd6 551 }
XinZhangMS 0:f7f1f0d76dd6 552 else if (iterator + (data_length + HTTP_CRLF_LEN) == initial_pos + accural_len)
XinZhangMS 0:f7f1f0d76dd6 553 {
XinZhangMS 0:f7f1f0d76dd6 554 if (BUFFER_shrink(http_data->recv_msg.accrual_buff, accural_len, false) != 0)
XinZhangMS 0:f7f1f0d76dd6 555 {
XinZhangMS 0:f7f1f0d76dd6 556 LogError("Failure shrinking accural buffer.");
XinZhangMS 0:f7f1f0d76dd6 557 http_data->recv_msg.recv_state = state_error;
XinZhangMS 0:f7f1f0d76dd6 558 }
XinZhangMS 0:f7f1f0d76dd6 559 break;
XinZhangMS 0:f7f1f0d76dd6 560 }
XinZhangMS 0:f7f1f0d76dd6 561 else
XinZhangMS 0:f7f1f0d76dd6 562 {
XinZhangMS 0:f7f1f0d76dd6 563 // Move the iterator beyond the data we read and the /r/n
XinZhangMS 0:f7f1f0d76dd6 564 iterator += (data_length + HTTP_CRLF_LEN);
XinZhangMS 0:f7f1f0d76dd6 565 }
XinZhangMS 0:f7f1f0d76dd6 566
XinZhangMS 0:f7f1f0d76dd6 567 /* Codes_SRS_UHTTP_07_058: [ Once a chunk size value of 0 is encountered on_bytes_received shall call the on_request_callback with the http message ] */
XinZhangMS 0:f7f1f0d76dd6 568 if (*iterator == '0' && (accural_len - (iterator - initial_pos + 1) <= HTTP_END_TOKEN_LEN))
XinZhangMS 0:f7f1f0d76dd6 569 {
XinZhangMS 0:f7f1f0d76dd6 570 if (accural_len - (iterator - initial_pos + 1) <= HTTP_END_TOKEN_LEN)
XinZhangMS 0:f7f1f0d76dd6 571 {
XinZhangMS 0:f7f1f0d76dd6 572 http_data->recv_msg.recv_state = state_send_user_callback;
XinZhangMS 0:f7f1f0d76dd6 573 }
XinZhangMS 0:f7f1f0d76dd6 574 else
XinZhangMS 0:f7f1f0d76dd6 575 {
XinZhangMS 0:f7f1f0d76dd6 576 // Need to continue parsing
XinZhangMS 0:f7f1f0d76dd6 577 http_data->recv_msg.recv_state = state_process_headers;
XinZhangMS 0:f7f1f0d76dd6 578 }
XinZhangMS 0:f7f1f0d76dd6 579 break;
XinZhangMS 0:f7f1f0d76dd6 580 }
XinZhangMS 0:f7f1f0d76dd6 581 else
XinZhangMS 0:f7f1f0d76dd6 582 {
XinZhangMS 0:f7f1f0d76dd6 583 size_t shrink_len = iterator - initial_pos;
XinZhangMS 0:f7f1f0d76dd6 584 if (shrink_len > 0)
XinZhangMS 0:f7f1f0d76dd6 585 {
XinZhangMS 0:f7f1f0d76dd6 586 if (BUFFER_shrink(http_data->recv_msg.accrual_buff, shrink_len, false) != 0)
XinZhangMS 0:f7f1f0d76dd6 587 {
XinZhangMS 0:f7f1f0d76dd6 588 LogError("Failure shrinking accrual buffer.");
XinZhangMS 0:f7f1f0d76dd6 589 http_data->recv_msg.recv_state = state_error;
XinZhangMS 0:f7f1f0d76dd6 590 }
XinZhangMS 0:f7f1f0d76dd6 591 else
XinZhangMS 0:f7f1f0d76dd6 592 {
XinZhangMS 0:f7f1f0d76dd6 593 accural_len = BUFFER_length(http_data->recv_msg.accrual_buff);
XinZhangMS 0:f7f1f0d76dd6 594 initial_pos = iterator = BUFFER_u_char(http_data->recv_msg.accrual_buff);
XinZhangMS 0:f7f1f0d76dd6 595 }
XinZhangMS 0:f7f1f0d76dd6 596 }
XinZhangMS 0:f7f1f0d76dd6 597 }
XinZhangMS 0:f7f1f0d76dd6 598 }
XinZhangMS 0:f7f1f0d76dd6 599 begin = end = iterator;
XinZhangMS 0:f7f1f0d76dd6 600 }
XinZhangMS 0:f7f1f0d76dd6 601 else
XinZhangMS 0:f7f1f0d76dd6 602 {
XinZhangMS 0:f7f1f0d76dd6 603 break;
XinZhangMS 0:f7f1f0d76dd6 604 }
XinZhangMS 0:f7f1f0d76dd6 605 }
XinZhangMS 0:f7f1f0d76dd6 606 else
XinZhangMS 0:f7f1f0d76dd6 607 {
XinZhangMS 0:f7f1f0d76dd6 608 end = iterator;
XinZhangMS 0:f7f1f0d76dd6 609 iterator++;
XinZhangMS 0:f7f1f0d76dd6 610 }
XinZhangMS 0:f7f1f0d76dd6 611 }
XinZhangMS 0:f7f1f0d76dd6 612 }
XinZhangMS 0:f7f1f0d76dd6 613
XinZhangMS 0:f7f1f0d76dd6 614 if (http_data->recv_msg.recv_state == state_send_user_callback || http_data->recv_msg.recv_state == state_error)
XinZhangMS 0:f7f1f0d76dd6 615 {
XinZhangMS 0:f7f1f0d76dd6 616 const unsigned char* reply_data = NULL;
XinZhangMS 0:f7f1f0d76dd6 617 size_t reply_len = 0;
XinZhangMS 0:f7f1f0d76dd6 618 HTTP_CALLBACK_REASON http_reason = HTTP_CALLBACK_REASON_OK;
XinZhangMS 0:f7f1f0d76dd6 619 if (http_data->recv_msg.msg_body != NULL)
XinZhangMS 0:f7f1f0d76dd6 620 {
XinZhangMS 0:f7f1f0d76dd6 621 reply_data = BUFFER_u_char(http_data->recv_msg.msg_body);
XinZhangMS 0:f7f1f0d76dd6 622 reply_len = BUFFER_length(http_data->recv_msg.msg_body);
XinZhangMS 0:f7f1f0d76dd6 623 }
XinZhangMS 0:f7f1f0d76dd6 624 if (http_data->recv_msg.recv_state == state_error)
XinZhangMS 0:f7f1f0d76dd6 625 {
XinZhangMS 0:f7f1f0d76dd6 626 http_reason = HTTP_CALLBACK_REASON_PARSING_ERROR;
XinZhangMS 0:f7f1f0d76dd6 627 }
XinZhangMS 0:f7f1f0d76dd6 628 if (http_data->trace_on)
XinZhangMS 0:f7f1f0d76dd6 629 {
XinZhangMS 0:f7f1f0d76dd6 630 LOG(AZ_LOG_TRACE, LOG_LINE, "\r\nHTTP Status: %d\r\n", http_data->recv_msg.status_code);
XinZhangMS 0:f7f1f0d76dd6 631
XinZhangMS 0:f7f1f0d76dd6 632 // Loop through headers
XinZhangMS 0:f7f1f0d76dd6 633 size_t count;
XinZhangMS 0:f7f1f0d76dd6 634 HTTPHeaders_GetHeaderCount(http_data->recv_msg.resp_header, &count);
XinZhangMS 0:f7f1f0d76dd6 635 for (size_t index = 0; index < count; index++)
XinZhangMS 0:f7f1f0d76dd6 636 {
XinZhangMS 0:f7f1f0d76dd6 637 char* header;
XinZhangMS 0:f7f1f0d76dd6 638 if (HTTPHeaders_GetHeader(http_data->recv_msg.resp_header, index, &header) == HTTP_HEADERS_OK)
XinZhangMS 0:f7f1f0d76dd6 639 {
XinZhangMS 0:f7f1f0d76dd6 640 LOG(AZ_LOG_TRACE, LOG_LINE, "%s", header);
XinZhangMS 0:f7f1f0d76dd6 641 free(header);
XinZhangMS 0:f7f1f0d76dd6 642 }
XinZhangMS 0:f7f1f0d76dd6 643 }
XinZhangMS 0:f7f1f0d76dd6 644 if (http_data->trace_body && reply_len > 0)
XinZhangMS 0:f7f1f0d76dd6 645 {
XinZhangMS 0:f7f1f0d76dd6 646 LOG(AZ_LOG_TRACE, LOG_LINE, "\r\n%.*s\r\n", (int)reply_len, reply_data);
XinZhangMS 0:f7f1f0d76dd6 647 }
XinZhangMS 0:f7f1f0d76dd6 648 }
XinZhangMS 0:f7f1f0d76dd6 649 http_data->recv_msg.on_request_callback(http_data->recv_msg.user_ctx, http_reason, reply_data, reply_len, http_data->recv_msg.status_code, http_data->recv_msg.resp_header);
XinZhangMS 0:f7f1f0d76dd6 650 http_data->recv_msg.recv_state = state_parse_complete;
XinZhangMS 0:f7f1f0d76dd6 651 }
XinZhangMS 0:f7f1f0d76dd6 652
XinZhangMS 0:f7f1f0d76dd6 653 if (http_data->recv_msg.recv_state == state_parse_complete)
XinZhangMS 0:f7f1f0d76dd6 654 {
XinZhangMS 0:f7f1f0d76dd6 655 HTTPHeaders_Free(http_data->recv_msg.resp_header);
XinZhangMS 0:f7f1f0d76dd6 656 http_data->recv_msg.resp_header = NULL;
XinZhangMS 0:f7f1f0d76dd6 657 BUFFER_delete(http_data->recv_msg.msg_body);
XinZhangMS 0:f7f1f0d76dd6 658 http_data->recv_msg.msg_body = NULL;
XinZhangMS 0:f7f1f0d76dd6 659 BUFFER_delete(http_data->recv_msg.accrual_buff);
XinZhangMS 0:f7f1f0d76dd6 660 http_data->recv_msg.accrual_buff = NULL;
XinZhangMS 0:f7f1f0d76dd6 661 }
XinZhangMS 0:f7f1f0d76dd6 662 }
XinZhangMS 0:f7f1f0d76dd6 663 }
XinZhangMS 0:f7f1f0d76dd6 664
XinZhangMS 0:f7f1f0d76dd6 665 static void on_xio_close_complete(void* context)
XinZhangMS 0:f7f1f0d76dd6 666 {
XinZhangMS 0:f7f1f0d76dd6 667 if (context != NULL)
XinZhangMS 0:f7f1f0d76dd6 668 {
XinZhangMS 0:f7f1f0d76dd6 669 /* Codes_SRS_UHTTP_07_045: [ If on_close_callback is not NULL, on_close_callback shall be called once the underlying xio is closed. ] */
XinZhangMS 0:f7f1f0d76dd6 670 HTTP_CLIENT_HANDLE_DATA* http_data = (HTTP_CLIENT_HANDLE_DATA*)context;
XinZhangMS 0:f7f1f0d76dd6 671 if (http_data->on_close_callback)
XinZhangMS 0:f7f1f0d76dd6 672 {
XinZhangMS 0:f7f1f0d76dd6 673 http_data->on_close_callback(http_data->close_user_ctx);
XinZhangMS 0:f7f1f0d76dd6 674 }
XinZhangMS 0:f7f1f0d76dd6 675 http_data->recv_msg.recv_state = state_closed;
XinZhangMS 0:f7f1f0d76dd6 676 http_data->connected = 0;
XinZhangMS 0:f7f1f0d76dd6 677 }
XinZhangMS 0:f7f1f0d76dd6 678 }
XinZhangMS 0:f7f1f0d76dd6 679
XinZhangMS 0:f7f1f0d76dd6 680 static void on_xio_open_complete(void* context, IO_OPEN_RESULT open_result)
XinZhangMS 0:f7f1f0d76dd6 681 {
XinZhangMS 0:f7f1f0d76dd6 682 /* Codes_SRS_UHTTP_07_049: [ If not NULL uhttp_client_open shall call the on_connect callback with the callback_ctx, once the underlying xio's open is complete. ] */
XinZhangMS 0:f7f1f0d76dd6 683 if (context != NULL)
XinZhangMS 0:f7f1f0d76dd6 684 {
XinZhangMS 0:f7f1f0d76dd6 685 HTTP_CLIENT_HANDLE_DATA* http_data = (HTTP_CLIENT_HANDLE_DATA*)context;
XinZhangMS 0:f7f1f0d76dd6 686 if (open_result == IO_OPEN_OK)
XinZhangMS 0:f7f1f0d76dd6 687 {
XinZhangMS 0:f7f1f0d76dd6 688 /* Codes_SRS_UHTTP_07_042: [ If the underlying socket opens successfully the on_connect callback shall be call with HTTP_CALLBACK_REASON_OK... ] */
XinZhangMS 0:f7f1f0d76dd6 689 if (http_data->on_connect != NULL)
XinZhangMS 0:f7f1f0d76dd6 690 {
XinZhangMS 0:f7f1f0d76dd6 691 http_data->on_connect(http_data->connect_user_ctx, HTTP_CALLBACK_REASON_OK);
XinZhangMS 0:f7f1f0d76dd6 692 }
XinZhangMS 0:f7f1f0d76dd6 693 http_data->recv_msg.recv_state = state_open;
XinZhangMS 0:f7f1f0d76dd6 694 http_data->connected = 1;
XinZhangMS 0:f7f1f0d76dd6 695 }
XinZhangMS 0:f7f1f0d76dd6 696 else
XinZhangMS 0:f7f1f0d76dd6 697 {
XinZhangMS 0:f7f1f0d76dd6 698 /* Codes_SRS_UHTTP_07_043: [ Otherwise on_connect callback shall be call with HTTP_CLIENT_OPEN_REQUEST_FAILED. ] */
XinZhangMS 0:f7f1f0d76dd6 699 if (http_data->on_connect != NULL)
XinZhangMS 0:f7f1f0d76dd6 700 {
XinZhangMS 0:f7f1f0d76dd6 701 http_data->on_connect(http_data->connect_user_ctx, HTTP_CALLBACK_REASON_OPEN_FAILED);
XinZhangMS 0:f7f1f0d76dd6 702 }
XinZhangMS 0:f7f1f0d76dd6 703 }
XinZhangMS 0:f7f1f0d76dd6 704 }
XinZhangMS 0:f7f1f0d76dd6 705 else
XinZhangMS 0:f7f1f0d76dd6 706 {
XinZhangMS 0:f7f1f0d76dd6 707 LogError("Context on_xio_open_complete is NULL");
XinZhangMS 0:f7f1f0d76dd6 708 }
XinZhangMS 0:f7f1f0d76dd6 709 }
XinZhangMS 0:f7f1f0d76dd6 710
XinZhangMS 0:f7f1f0d76dd6 711 static void on_io_error(void* context)
XinZhangMS 0:f7f1f0d76dd6 712 {
XinZhangMS 0:f7f1f0d76dd6 713 /* Codes_SRS_UHTTP_07_050: [ if context is NULL on_io_error shall do nothing. ] */
XinZhangMS 0:f7f1f0d76dd6 714 if (context != NULL)
XinZhangMS 0:f7f1f0d76dd6 715 {
XinZhangMS 0:f7f1f0d76dd6 716 HTTP_CLIENT_HANDLE_DATA* http_data = (HTTP_CLIENT_HANDLE_DATA*)context;
XinZhangMS 0:f7f1f0d76dd6 717 /* Codes_SRS_UHTTP_07_051: [ if on_error callback is not NULL, on_io_error shall call on_error callback. ] */
XinZhangMS 0:f7f1f0d76dd6 718 if (http_data->on_error)
XinZhangMS 0:f7f1f0d76dd6 719 {
XinZhangMS 0:f7f1f0d76dd6 720 http_data->on_error(http_data->error_user_ctx, HTTP_CALLBACK_REASON_ERROR);
XinZhangMS 0:f7f1f0d76dd6 721 }
XinZhangMS 0:f7f1f0d76dd6 722 http_data->connected = 0;
XinZhangMS 0:f7f1f0d76dd6 723 }
XinZhangMS 0:f7f1f0d76dd6 724 else
XinZhangMS 0:f7f1f0d76dd6 725 {
XinZhangMS 0:f7f1f0d76dd6 726 LogError("Context on_io_error is NULL");
XinZhangMS 0:f7f1f0d76dd6 727 }
XinZhangMS 0:f7f1f0d76dd6 728 }
XinZhangMS 0:f7f1f0d76dd6 729
XinZhangMS 0:f7f1f0d76dd6 730 static int construct_http_headers(HTTP_HEADERS_HANDLE http_header, size_t content_len, STRING_HANDLE buffData, bool chunk_data, const char* hostname, int port_num)
XinZhangMS 0:f7f1f0d76dd6 731 {
XinZhangMS 0:f7f1f0d76dd6 732 (void)chunk_data;
XinZhangMS 0:f7f1f0d76dd6 733 int result = 0;
XinZhangMS 0:f7f1f0d76dd6 734 size_t headerCnt = 0;
XinZhangMS 0:f7f1f0d76dd6 735 if ( (http_header != NULL) && HTTPHeaders_GetHeaderCount(http_header, &headerCnt) != HTTP_HEADERS_OK)
XinZhangMS 0:f7f1f0d76dd6 736 {
XinZhangMS 0:f7f1f0d76dd6 737 LogError("Failed in HTTPHeaders_GetHeaderCount");
XinZhangMS 0:f7f1f0d76dd6 738 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 739 }
XinZhangMS 0:f7f1f0d76dd6 740 else
XinZhangMS 0:f7f1f0d76dd6 741 {
XinZhangMS 0:f7f1f0d76dd6 742 bool hostname_found = false;
XinZhangMS 0:f7f1f0d76dd6 743 for (size_t index = 0; index < headerCnt && result == 0; index++)
XinZhangMS 0:f7f1f0d76dd6 744 {
XinZhangMS 0:f7f1f0d76dd6 745 char* header;
XinZhangMS 0:f7f1f0d76dd6 746 if (HTTPHeaders_GetHeader(http_header, index, &header) != HTTP_HEADERS_OK)
XinZhangMS 0:f7f1f0d76dd6 747 {
XinZhangMS 0:f7f1f0d76dd6 748 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 749 LogError("Failed in HTTPHeaders_GetHeader");
XinZhangMS 0:f7f1f0d76dd6 750 }
XinZhangMS 0:f7f1f0d76dd6 751 else
XinZhangMS 0:f7f1f0d76dd6 752 {
XinZhangMS 0:f7f1f0d76dd6 753 size_t dataLen = strlen(header)+2;
XinZhangMS 0:f7f1f0d76dd6 754 char* sendData = malloc(dataLen+1);
XinZhangMS 0:f7f1f0d76dd6 755 if (sendData == NULL)
XinZhangMS 0:f7f1f0d76dd6 756 {
XinZhangMS 0:f7f1f0d76dd6 757 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 758 LogError("Failed in allocating header data");
XinZhangMS 0:f7f1f0d76dd6 759 }
XinZhangMS 0:f7f1f0d76dd6 760 else
XinZhangMS 0:f7f1f0d76dd6 761 {
XinZhangMS 0:f7f1f0d76dd6 762 if (strcmp(header, HTTP_HOST) == 0)
XinZhangMS 0:f7f1f0d76dd6 763 {
XinZhangMS 0:f7f1f0d76dd6 764 hostname_found = true;
XinZhangMS 0:f7f1f0d76dd6 765 }
XinZhangMS 0:f7f1f0d76dd6 766
XinZhangMS 0:f7f1f0d76dd6 767 if (snprintf(sendData, dataLen+1, "%s\r\n", header) <= 0)
XinZhangMS 0:f7f1f0d76dd6 768 {
XinZhangMS 0:f7f1f0d76dd6 769 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 770 LogError("Failed in constructing header data");
XinZhangMS 0:f7f1f0d76dd6 771 }
XinZhangMS 0:f7f1f0d76dd6 772 else
XinZhangMS 0:f7f1f0d76dd6 773 {
XinZhangMS 0:f7f1f0d76dd6 774 if (STRING_concat(buffData, sendData) != 0)
XinZhangMS 0:f7f1f0d76dd6 775 {
XinZhangMS 0:f7f1f0d76dd6 776 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 777 LogError("Failed in building header data");
XinZhangMS 0:f7f1f0d76dd6 778 }
XinZhangMS 0:f7f1f0d76dd6 779 }
XinZhangMS 0:f7f1f0d76dd6 780 free(sendData);
XinZhangMS 0:f7f1f0d76dd6 781 }
XinZhangMS 0:f7f1f0d76dd6 782 free(header);
XinZhangMS 0:f7f1f0d76dd6 783 }
XinZhangMS 0:f7f1f0d76dd6 784 }
XinZhangMS 0:f7f1f0d76dd6 785 if (!hostname_found)
XinZhangMS 0:f7f1f0d76dd6 786 {
XinZhangMS 0:f7f1f0d76dd6 787 size_t host_len = strlen(HTTP_HOST)+strlen(hostname)+8+2;
XinZhangMS 0:f7f1f0d76dd6 788 char* host_header = malloc(host_len+1);
XinZhangMS 0:f7f1f0d76dd6 789 if (host_header == NULL)
XinZhangMS 0:f7f1f0d76dd6 790 {
XinZhangMS 0:f7f1f0d76dd6 791 LogError("Failed allocating host header");
XinZhangMS 0:f7f1f0d76dd6 792 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 793 }
XinZhangMS 0:f7f1f0d76dd6 794 else
XinZhangMS 0:f7f1f0d76dd6 795 {
XinZhangMS 0:f7f1f0d76dd6 796 if (snprintf(host_header, host_len+1, "%s: %s:%d\r\n", HTTP_HOST, hostname, port_num) <= 0)
XinZhangMS 0:f7f1f0d76dd6 797 {
XinZhangMS 0:f7f1f0d76dd6 798 LogError("Failed constructing host header");
XinZhangMS 0:f7f1f0d76dd6 799 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 800 }
XinZhangMS 0:f7f1f0d76dd6 801 else if (STRING_concat(buffData, host_header) != 0)
XinZhangMS 0:f7f1f0d76dd6 802 {
XinZhangMS 0:f7f1f0d76dd6 803 LogError("Failed adding the host header to the http item");
XinZhangMS 0:f7f1f0d76dd6 804 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 805 }
XinZhangMS 0:f7f1f0d76dd6 806 free(host_header);
XinZhangMS 0:f7f1f0d76dd6 807 }
XinZhangMS 0:f7f1f0d76dd6 808 }
XinZhangMS 0:f7f1f0d76dd6 809
XinZhangMS 0:f7f1f0d76dd6 810 if (result == 0)
XinZhangMS 0:f7f1f0d76dd6 811 {
XinZhangMS 0:f7f1f0d76dd6 812 /* Codes_SRS_UHTTP_07_015: [uhttp_client_execute_request shall add the Content-Length to the request if the contentLength is > 0] */
XinZhangMS 0:f7f1f0d76dd6 813 size_t fmtLen = strlen(HTTP_CONTENT_LEN)+strlen(HTTP_CRLF_VALUE)+8;
XinZhangMS 0:f7f1f0d76dd6 814 char* content = malloc(fmtLen+1);
XinZhangMS 0:f7f1f0d76dd6 815 if (content == NULL)
XinZhangMS 0:f7f1f0d76dd6 816 {
XinZhangMS 0:f7f1f0d76dd6 817 LogError("Failed allocating chunk header");
XinZhangMS 0:f7f1f0d76dd6 818 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 819 }
XinZhangMS 0:f7f1f0d76dd6 820 else
XinZhangMS 0:f7f1f0d76dd6 821 {
XinZhangMS 0:f7f1f0d76dd6 822 /* Codes_SRS_UHTTP_07_015: [on_bytes_received shall add the Content-Length http header item to the request.] */
XinZhangMS 0:f7f1f0d76dd6 823 if (sprintf(content, "%s: %lu%s", HTTP_CONTENT_LEN, content_len, HTTP_CRLF_VALUE) <= 0)
XinZhangMS 0:f7f1f0d76dd6 824 {
XinZhangMS 0:f7f1f0d76dd6 825 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 826 LogError("Failed allocating content len header data");
XinZhangMS 0:f7f1f0d76dd6 827 }
XinZhangMS 0:f7f1f0d76dd6 828 else
XinZhangMS 0:f7f1f0d76dd6 829 {
XinZhangMS 0:f7f1f0d76dd6 830 if (STRING_concat(buffData, content) != 0)
XinZhangMS 0:f7f1f0d76dd6 831 {
XinZhangMS 0:f7f1f0d76dd6 832 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 833 LogError("Failed building content len header data");
XinZhangMS 0:f7f1f0d76dd6 834 }
XinZhangMS 0:f7f1f0d76dd6 835 }
XinZhangMS 0:f7f1f0d76dd6 836 free(content);
XinZhangMS 0:f7f1f0d76dd6 837 }
XinZhangMS 0:f7f1f0d76dd6 838
XinZhangMS 0:f7f1f0d76dd6 839 if (STRING_concat(buffData, "\r\n") != 0)
XinZhangMS 0:f7f1f0d76dd6 840 {
XinZhangMS 0:f7f1f0d76dd6 841 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 842 LogError("Failed sending header finalization data");
XinZhangMS 0:f7f1f0d76dd6 843 }
XinZhangMS 0:f7f1f0d76dd6 844 }
XinZhangMS 0:f7f1f0d76dd6 845 }
XinZhangMS 0:f7f1f0d76dd6 846 return result;
XinZhangMS 0:f7f1f0d76dd6 847 }
XinZhangMS 0:f7f1f0d76dd6 848
XinZhangMS 0:f7f1f0d76dd6 849 static STRING_HANDLE construct_http_data(HTTP_CLIENT_REQUEST_TYPE request_type, const char* relative_path, STRING_HANDLE http_line)
XinZhangMS 0:f7f1f0d76dd6 850 {
XinZhangMS 0:f7f1f0d76dd6 851 STRING_HANDLE result;
XinZhangMS 0:f7f1f0d76dd6 852
XinZhangMS 0:f7f1f0d76dd6 853 const char* method = (request_type == HTTP_CLIENT_REQUEST_GET) ? "GET"
XinZhangMS 0:f7f1f0d76dd6 854 : (request_type == HTTP_CLIENT_REQUEST_OPTIONS) ? "OPTIONS"
XinZhangMS 0:f7f1f0d76dd6 855 : (request_type == HTTP_CLIENT_REQUEST_POST) ? "POST"
XinZhangMS 0:f7f1f0d76dd6 856 : (request_type == HTTP_CLIENT_REQUEST_PUT) ? "PUT"
XinZhangMS 0:f7f1f0d76dd6 857 : (request_type == HTTP_CLIENT_REQUEST_DELETE) ? "DELETE"
XinZhangMS 0:f7f1f0d76dd6 858 : (request_type == HTTP_CLIENT_REQUEST_PATCH) ? "PATCH"
XinZhangMS 0:f7f1f0d76dd6 859 : NULL;
XinZhangMS 0:f7f1f0d76dd6 860 /* Codes_SRS_UHTTP_07_014: [If the request_type is not a valid request http_client_execute_request shall return HTTP_CLIENT_ERROR] */
XinZhangMS 0:f7f1f0d76dd6 861 if (method == NULL)
XinZhangMS 0:f7f1f0d76dd6 862 {
XinZhangMS 0:f7f1f0d76dd6 863 LogError("Invalid request method %s specified", method);
XinZhangMS 0:f7f1f0d76dd6 864 result = NULL;
XinZhangMS 0:f7f1f0d76dd6 865 }
XinZhangMS 0:f7f1f0d76dd6 866 else
XinZhangMS 0:f7f1f0d76dd6 867 {
XinZhangMS 0:f7f1f0d76dd6 868 size_t buffLen = strlen(HTTP_REQUEST_LINE_FMT)+strlen(method)+strlen(relative_path);
XinZhangMS 0:f7f1f0d76dd6 869 char* request = malloc(buffLen+1);
XinZhangMS 0:f7f1f0d76dd6 870 if (request == NULL)
XinZhangMS 0:f7f1f0d76dd6 871 {
XinZhangMS 0:f7f1f0d76dd6 872 result = NULL;
XinZhangMS 0:f7f1f0d76dd6 873 LogError("Failure allocating Request data");
XinZhangMS 0:f7f1f0d76dd6 874 }
XinZhangMS 0:f7f1f0d76dd6 875 else
XinZhangMS 0:f7f1f0d76dd6 876 {
XinZhangMS 0:f7f1f0d76dd6 877 if (snprintf(request, buffLen+1, HTTP_REQUEST_LINE_FMT, method, relative_path) <= 0)
XinZhangMS 0:f7f1f0d76dd6 878 {
XinZhangMS 0:f7f1f0d76dd6 879 result = NULL;
XinZhangMS 0:f7f1f0d76dd6 880 LogError("Failure writing request buffer");
XinZhangMS 0:f7f1f0d76dd6 881 }
XinZhangMS 0:f7f1f0d76dd6 882 else
XinZhangMS 0:f7f1f0d76dd6 883 {
XinZhangMS 0:f7f1f0d76dd6 884 result = STRING_construct(request);
XinZhangMS 0:f7f1f0d76dd6 885 if (result == NULL)
XinZhangMS 0:f7f1f0d76dd6 886 {
XinZhangMS 0:f7f1f0d76dd6 887 LogError("Failure creating buffer object");
XinZhangMS 0:f7f1f0d76dd6 888 }
XinZhangMS 0:f7f1f0d76dd6 889 else if (STRING_concat_with_STRING(result, http_line) != 0)
XinZhangMS 0:f7f1f0d76dd6 890 {
XinZhangMS 0:f7f1f0d76dd6 891 STRING_delete(result);
XinZhangMS 0:f7f1f0d76dd6 892 result = NULL;
XinZhangMS 0:f7f1f0d76dd6 893 LogError("Failure writing request buffers");
XinZhangMS 0:f7f1f0d76dd6 894 }
XinZhangMS 0:f7f1f0d76dd6 895 }
XinZhangMS 0:f7f1f0d76dd6 896 free(request);
XinZhangMS 0:f7f1f0d76dd6 897 }
XinZhangMS 0:f7f1f0d76dd6 898 }
XinZhangMS 0:f7f1f0d76dd6 899 return result;
XinZhangMS 0:f7f1f0d76dd6 900 }
XinZhangMS 0:f7f1f0d76dd6 901
XinZhangMS 0:f7f1f0d76dd6 902 static int send_http_data(HTTP_CLIENT_HANDLE_DATA* http_data, HTTP_CLIENT_REQUEST_TYPE request_type, const char* relative_path,
XinZhangMS 0:f7f1f0d76dd6 903 STRING_HANDLE http_line)
XinZhangMS 0:f7f1f0d76dd6 904 {
XinZhangMS 0:f7f1f0d76dd6 905 int result;
XinZhangMS 0:f7f1f0d76dd6 906 STRING_HANDLE transmit_data = construct_http_data(request_type, relative_path, http_line);
XinZhangMS 0:f7f1f0d76dd6 907 if (transmit_data == NULL)
XinZhangMS 0:f7f1f0d76dd6 908 {
XinZhangMS 0:f7f1f0d76dd6 909 LogError("Failure constructing http data");
XinZhangMS 0:f7f1f0d76dd6 910 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 911 }
XinZhangMS 0:f7f1f0d76dd6 912 else
XinZhangMS 0:f7f1f0d76dd6 913 {
XinZhangMS 0:f7f1f0d76dd6 914 /* Tests_SRS_UHTTP_07_016: [http_client_execute_request shall transmit the http headers data through a call to xio_send;]*/
XinZhangMS 0:f7f1f0d76dd6 915 if (write_text_line(http_data, STRING_c_str(transmit_data) ) != 0)
XinZhangMS 0:f7f1f0d76dd6 916 {
XinZhangMS 0:f7f1f0d76dd6 917 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 918 LogError("Failure writing request buffer");
XinZhangMS 0:f7f1f0d76dd6 919 }
XinZhangMS 0:f7f1f0d76dd6 920 else
XinZhangMS 0:f7f1f0d76dd6 921 {
XinZhangMS 0:f7f1f0d76dd6 922 result = 0;
XinZhangMS 0:f7f1f0d76dd6 923 }
XinZhangMS 0:f7f1f0d76dd6 924 STRING_delete(transmit_data);
XinZhangMS 0:f7f1f0d76dd6 925 }
XinZhangMS 0:f7f1f0d76dd6 926 return result;
XinZhangMS 0:f7f1f0d76dd6 927 }
XinZhangMS 0:f7f1f0d76dd6 928
XinZhangMS 0:f7f1f0d76dd6 929 HTTP_CLIENT_HANDLE uhttp_client_create(const IO_INTERFACE_DESCRIPTION* io_interface_desc, const void* xio_param, ON_HTTP_ERROR_CALLBACK on_http_error, void* callback_ctx)
XinZhangMS 0:f7f1f0d76dd6 930 {
XinZhangMS 0:f7f1f0d76dd6 931 HTTP_CLIENT_HANDLE_DATA* result;
XinZhangMS 0:f7f1f0d76dd6 932 /* Codes_SRS_UHTTP_07_002: [If io_interface_desc is NULL, uhttp_client_create shall return NULL.] */
XinZhangMS 0:f7f1f0d76dd6 933 if (io_interface_desc == NULL)
XinZhangMS 0:f7f1f0d76dd6 934 {
XinZhangMS 0:f7f1f0d76dd6 935 LogError("Invalid Parameter io_interface_desc is NULL");
XinZhangMS 0:f7f1f0d76dd6 936 result = NULL;
XinZhangMS 0:f7f1f0d76dd6 937 }
XinZhangMS 0:f7f1f0d76dd6 938 else
XinZhangMS 0:f7f1f0d76dd6 939 {
XinZhangMS 0:f7f1f0d76dd6 940 result = malloc(sizeof(HTTP_CLIENT_HANDLE_DATA));
XinZhangMS 0:f7f1f0d76dd6 941 if (result == NULL)
XinZhangMS 0:f7f1f0d76dd6 942 {
XinZhangMS 0:f7f1f0d76dd6 943 /* Codes_SRS_UHTTP_07_003: [If uhttp_client_create encounters any error then it shall return NULL] */
XinZhangMS 0:f7f1f0d76dd6 944 LogError("Failure allocating http_client_handle");
XinZhangMS 0:f7f1f0d76dd6 945 }
XinZhangMS 0:f7f1f0d76dd6 946 else
XinZhangMS 0:f7f1f0d76dd6 947 {
XinZhangMS 0:f7f1f0d76dd6 948 memset(result, 0, sizeof(HTTP_CLIENT_HANDLE_DATA) );
XinZhangMS 0:f7f1f0d76dd6 949 if ((result->data_list = singlylinkedlist_create() ) == NULL)
XinZhangMS 0:f7f1f0d76dd6 950 {
XinZhangMS 0:f7f1f0d76dd6 951 /* Codes_SRS_UHTTP_07_003: [If uhttp_client_create encounters any error then it shall return NULL] */
XinZhangMS 0:f7f1f0d76dd6 952 LogError("Failure allocating data list");
XinZhangMS 0:f7f1f0d76dd6 953 free(result);
XinZhangMS 0:f7f1f0d76dd6 954 result = NULL;
XinZhangMS 0:f7f1f0d76dd6 955 }
XinZhangMS 0:f7f1f0d76dd6 956 else if ((result->xio_handle = xio_create(io_interface_desc, xio_param) ) == NULL)
XinZhangMS 0:f7f1f0d76dd6 957 {
XinZhangMS 0:f7f1f0d76dd6 958 /* Codes_SRS_UHTTP_07_044: [ if a failure is encountered on xio_open uhttp_client_open shall return HTTP_CLIENT_OPEN_REQUEST_FAILED. ] */
XinZhangMS 0:f7f1f0d76dd6 959 LogError("xio create failed");
XinZhangMS 0:f7f1f0d76dd6 960 singlylinkedlist_destroy(result->data_list);
XinZhangMS 0:f7f1f0d76dd6 961 free(result);
XinZhangMS 0:f7f1f0d76dd6 962 result = NULL;
XinZhangMS 0:f7f1f0d76dd6 963 }
XinZhangMS 0:f7f1f0d76dd6 964 else
XinZhangMS 0:f7f1f0d76dd6 965 {
XinZhangMS 0:f7f1f0d76dd6 966 /* Codes_SRS_UHTTP_07_001: [uhttp_client_create shall return an initialize the http client handle.] */
XinZhangMS 0:f7f1f0d76dd6 967 result->on_error = on_http_error;
XinZhangMS 0:f7f1f0d76dd6 968 result->error_user_ctx = callback_ctx;
XinZhangMS 0:f7f1f0d76dd6 969 result->recv_msg.recv_state = state_initial;
XinZhangMS 0:f7f1f0d76dd6 970 result->chunk_request = false;
XinZhangMS 0:f7f1f0d76dd6 971 result->trace_on = false;
XinZhangMS 0:f7f1f0d76dd6 972 bool ignore_check = true;
XinZhangMS 0:f7f1f0d76dd6 973 (void)xio_setoption(result->xio_handle, "ignore_server_name_check", &ignore_check);
XinZhangMS 0:f7f1f0d76dd6 974 }
XinZhangMS 0:f7f1f0d76dd6 975 }
XinZhangMS 0:f7f1f0d76dd6 976 }
XinZhangMS 0:f7f1f0d76dd6 977 return (HTTP_CLIENT_HANDLE)result;
XinZhangMS 0:f7f1f0d76dd6 978 }
XinZhangMS 0:f7f1f0d76dd6 979
XinZhangMS 0:f7f1f0d76dd6 980 void uhttp_client_destroy(HTTP_CLIENT_HANDLE handle)
XinZhangMS 0:f7f1f0d76dd6 981 {
XinZhangMS 0:f7f1f0d76dd6 982 /* Codes_SRS_UHTTP_07_004: [ If handle is NULL then uhttp_client_destroy shall do nothing ] */
XinZhangMS 0:f7f1f0d76dd6 983 if (handle != NULL)
XinZhangMS 0:f7f1f0d76dd6 984 {
XinZhangMS 0:f7f1f0d76dd6 985 /* Codes_SRS_UHTTP_07_005: [uhttp_client_destroy shall free any resource that is allocated in this translation unit] */
XinZhangMS 0:f7f1f0d76dd6 986 singlylinkedlist_destroy(handle->data_list);
XinZhangMS 0:f7f1f0d76dd6 987 xio_destroy(handle->xio_handle);
XinZhangMS 0:f7f1f0d76dd6 988 free(handle->certificate);
XinZhangMS 0:f7f1f0d76dd6 989 free(handle->x509_pk);
XinZhangMS 0:f7f1f0d76dd6 990 free(handle->x509_cert);
XinZhangMS 0:f7f1f0d76dd6 991 free(handle);
XinZhangMS 0:f7f1f0d76dd6 992 }
XinZhangMS 0:f7f1f0d76dd6 993 }
XinZhangMS 0:f7f1f0d76dd6 994
XinZhangMS 0:f7f1f0d76dd6 995 HTTP_CLIENT_RESULT uhttp_client_open(HTTP_CLIENT_HANDLE handle, const char* host, int port_num, ON_HTTP_OPEN_COMPLETE_CALLBACK on_connect, void* callback_ctx)
XinZhangMS 0:f7f1f0d76dd6 996 {
XinZhangMS 0:f7f1f0d76dd6 997 HTTP_CLIENT_RESULT result;
XinZhangMS 0:f7f1f0d76dd6 998 if (handle == NULL || host == NULL)
XinZhangMS 0:f7f1f0d76dd6 999 {
XinZhangMS 0:f7f1f0d76dd6 1000 /* Codes_SRS_UHTTP_07_006: [If handle, io_interface_desc or host is NULL then `uhttp_client_open` shall return HTTP_CLIENT_INVALID_ARG] */
XinZhangMS 0:f7f1f0d76dd6 1001 LogError("Invalid handle value");
XinZhangMS 0:f7f1f0d76dd6 1002 result = HTTP_CLIENT_INVALID_ARG;
XinZhangMS 0:f7f1f0d76dd6 1003 }
XinZhangMS 0:f7f1f0d76dd6 1004 else
XinZhangMS 0:f7f1f0d76dd6 1005 {
XinZhangMS 0:f7f1f0d76dd6 1006 HTTP_CLIENT_HANDLE_DATA* http_data = (HTTP_CLIENT_HANDLE_DATA*)handle;
XinZhangMS 0:f7f1f0d76dd6 1007
XinZhangMS 0:f7f1f0d76dd6 1008 if (http_data->recv_msg.recv_state != state_initial && http_data->recv_msg.recv_state != state_error && http_data->recv_msg.recv_state != state_closed)
XinZhangMS 0:f7f1f0d76dd6 1009 {
XinZhangMS 0:f7f1f0d76dd6 1010 LogError("Unable to open previously open client.");
XinZhangMS 0:f7f1f0d76dd6 1011 result = HTTP_CLIENT_INVALID_STATE;
XinZhangMS 0:f7f1f0d76dd6 1012 }
XinZhangMS 0:f7f1f0d76dd6 1013 else if (mallocAndStrcpy_s(&http_data->host_name, host) != 0)
XinZhangMS 0:f7f1f0d76dd6 1014 {
XinZhangMS 0:f7f1f0d76dd6 1015 LogError("copying hostname has failed");
XinZhangMS 0:f7f1f0d76dd6 1016 result = HTTP_CLIENT_ERROR;
XinZhangMS 0:f7f1f0d76dd6 1017 }
XinZhangMS 0:f7f1f0d76dd6 1018 /* Codes_SRS_UHTTP_07_007: [http_client_connect shall attempt to open the xio_handle. ] */
XinZhangMS 0:f7f1f0d76dd6 1019 else
XinZhangMS 0:f7f1f0d76dd6 1020 {
XinZhangMS 0:f7f1f0d76dd6 1021 result = HTTP_CLIENT_OK;
XinZhangMS 0:f7f1f0d76dd6 1022 http_data->recv_msg.recv_state = state_opening;
XinZhangMS 0:f7f1f0d76dd6 1023 http_data->on_connect = on_connect;
XinZhangMS 0:f7f1f0d76dd6 1024 http_data->connect_user_ctx = callback_ctx;
XinZhangMS 0:f7f1f0d76dd6 1025 http_data->port_num = port_num;
XinZhangMS 0:f7f1f0d76dd6 1026
XinZhangMS 0:f7f1f0d76dd6 1027 if (http_data->x509_cert != NULL && http_data->x509_pk != NULL)
XinZhangMS 0:f7f1f0d76dd6 1028 {
XinZhangMS 0:f7f1f0d76dd6 1029 if (xio_setoption(http_data->xio_handle, SU_OPTION_X509_CERT, http_data->x509_cert) != 0 || xio_setoption(http_data->xio_handle, SU_OPTION_X509_PRIVATE_KEY, http_data->x509_pk) != 0)
XinZhangMS 0:f7f1f0d76dd6 1030 {
XinZhangMS 0:f7f1f0d76dd6 1031 LogError("Failed setting x509 certificate");
XinZhangMS 0:f7f1f0d76dd6 1032 result = HTTP_CLIENT_ERROR;
XinZhangMS 0:f7f1f0d76dd6 1033 free(http_data->host_name);
XinZhangMS 0:f7f1f0d76dd6 1034 http_data->host_name = NULL;
XinZhangMS 0:f7f1f0d76dd6 1035 http_data->on_connect = NULL;
XinZhangMS 0:f7f1f0d76dd6 1036 http_data->connect_user_ctx = NULL;
XinZhangMS 0:f7f1f0d76dd6 1037 http_data->port_num = 0;
XinZhangMS 0:f7f1f0d76dd6 1038 }
XinZhangMS 0:f7f1f0d76dd6 1039 }
XinZhangMS 0:f7f1f0d76dd6 1040 if (result == HTTP_CLIENT_OK && http_data->certificate != NULL)
XinZhangMS 0:f7f1f0d76dd6 1041 {
XinZhangMS 0:f7f1f0d76dd6 1042 if (xio_setoption(http_data->xio_handle, OPTION_TRUSTED_CERT, http_data->certificate) != 0)
XinZhangMS 0:f7f1f0d76dd6 1043 {
XinZhangMS 0:f7f1f0d76dd6 1044 LogError("Failed setting Trusted certificate");
XinZhangMS 0:f7f1f0d76dd6 1045 result = HTTP_CLIENT_ERROR;
XinZhangMS 0:f7f1f0d76dd6 1046 free(http_data->host_name);
XinZhangMS 0:f7f1f0d76dd6 1047 http_data->host_name = NULL;
XinZhangMS 0:f7f1f0d76dd6 1048 http_data->on_connect = NULL;
XinZhangMS 0:f7f1f0d76dd6 1049 http_data->connect_user_ctx = NULL;
XinZhangMS 0:f7f1f0d76dd6 1050 http_data->port_num = 0;
XinZhangMS 0:f7f1f0d76dd6 1051 }
XinZhangMS 0:f7f1f0d76dd6 1052 }
XinZhangMS 0:f7f1f0d76dd6 1053
XinZhangMS 0:f7f1f0d76dd6 1054 if (result == HTTP_CLIENT_OK)
XinZhangMS 0:f7f1f0d76dd6 1055 {
XinZhangMS 0:f7f1f0d76dd6 1056 #ifdef USE_OPENSSL
XinZhangMS 0:f7f1f0d76dd6 1057 // Default to tls 1.2
XinZhangMS 0:f7f1f0d76dd6 1058 int tls_version = 12;
XinZhangMS 0:f7f1f0d76dd6 1059 xio_setoption(http_data->xio_handle, OPTION_TLS_VERSION, &tls_version);
XinZhangMS 0:f7f1f0d76dd6 1060 #endif
XinZhangMS 0:f7f1f0d76dd6 1061 if (xio_open(http_data->xio_handle, on_xio_open_complete, http_data, on_bytes_received, http_data, on_io_error, http_data) != 0)
XinZhangMS 0:f7f1f0d76dd6 1062 {
XinZhangMS 0:f7f1f0d76dd6 1063 /* Codes_SRS_UHTTP_07_044: [ if a failure is encountered on xio_open uhttp_client_open shall return HTTP_CLIENT_OPEN_REQUEST_FAILED. ] */
XinZhangMS 0:f7f1f0d76dd6 1064 LogError("opening xio failed");
XinZhangMS 0:f7f1f0d76dd6 1065 free(http_data->host_name);
XinZhangMS 0:f7f1f0d76dd6 1066 http_data->host_name = NULL;
XinZhangMS 0:f7f1f0d76dd6 1067 http_data->on_connect = NULL;
XinZhangMS 0:f7f1f0d76dd6 1068 http_data->connect_user_ctx = NULL;
XinZhangMS 0:f7f1f0d76dd6 1069 http_data->port_num = 0;
XinZhangMS 0:f7f1f0d76dd6 1070
XinZhangMS 0:f7f1f0d76dd6 1071 result = HTTP_CLIENT_OPEN_FAILED;
XinZhangMS 0:f7f1f0d76dd6 1072 }
XinZhangMS 0:f7f1f0d76dd6 1073 else
XinZhangMS 0:f7f1f0d76dd6 1074 {
XinZhangMS 0:f7f1f0d76dd6 1075 /* Codes_SRS_UHTTP_07_008: [If http_client_connect succeeds then it shall return HTTP_CLIENT_OK] */
XinZhangMS 0:f7f1f0d76dd6 1076 result = HTTP_CLIENT_OK;
XinZhangMS 0:f7f1f0d76dd6 1077 }
XinZhangMS 0:f7f1f0d76dd6 1078 }
XinZhangMS 0:f7f1f0d76dd6 1079 }
XinZhangMS 0:f7f1f0d76dd6 1080 }
XinZhangMS 0:f7f1f0d76dd6 1081 return result;
XinZhangMS 0:f7f1f0d76dd6 1082 }
XinZhangMS 0:f7f1f0d76dd6 1083
XinZhangMS 0:f7f1f0d76dd6 1084 void uhttp_client_close(HTTP_CLIENT_HANDLE handle, ON_HTTP_CLOSED_CALLBACK on_close_callback, void* callback_ctx)
XinZhangMS 0:f7f1f0d76dd6 1085 {
XinZhangMS 0:f7f1f0d76dd6 1086 HTTP_CLIENT_HANDLE_DATA* http_data = (HTTP_CLIENT_HANDLE_DATA*)handle;
XinZhangMS 0:f7f1f0d76dd6 1087 /* Codes_SRS_UHTTP_07_009: [If handle is NULL then http_client_close shall do nothing] */
XinZhangMS 0:f7f1f0d76dd6 1088 /* Codes_SRS_UHTTP_07_049: [ If the state has been previously set to state_closed, uhttp_client_close shall do nothing. ] */
XinZhangMS 0:f7f1f0d76dd6 1089 if (http_data != NULL && http_data->recv_msg.recv_state != state_closed && http_data->recv_msg.recv_state != state_closing)
XinZhangMS 0:f7f1f0d76dd6 1090 {
XinZhangMS 0:f7f1f0d76dd6 1091 http_data->on_close_callback = on_close_callback;
XinZhangMS 0:f7f1f0d76dd6 1092 http_data->close_user_ctx = callback_ctx;
XinZhangMS 0:f7f1f0d76dd6 1093 /* Codes_SRS_UHTTP_07_010: [If the xio_handle is NOT NULL http_client_close shall call xio_close to close the handle] */
XinZhangMS 0:f7f1f0d76dd6 1094 (void)xio_close(http_data->xio_handle, on_xio_close_complete, http_data);
XinZhangMS 0:f7f1f0d76dd6 1095
XinZhangMS 0:f7f1f0d76dd6 1096 LIST_ITEM_HANDLE pending_list_item;
XinZhangMS 0:f7f1f0d76dd6 1097 while ((pending_list_item = singlylinkedlist_get_head_item(http_data->data_list)) != NULL)
XinZhangMS 0:f7f1f0d76dd6 1098 {
XinZhangMS 0:f7f1f0d76dd6 1099 HTTP_SEND_DATA* send_data = (HTTP_SEND_DATA*)singlylinkedlist_item_get_value(pending_list_item);
XinZhangMS 0:f7f1f0d76dd6 1100 if (send_data != NULL)
XinZhangMS 0:f7f1f0d76dd6 1101 {
XinZhangMS 0:f7f1f0d76dd6 1102 STRING_delete(send_data->relative_path);
XinZhangMS 0:f7f1f0d76dd6 1103 BUFFER_delete(send_data->content);
XinZhangMS 0:f7f1f0d76dd6 1104 STRING_delete(send_data->header_line);
XinZhangMS 0:f7f1f0d76dd6 1105 free(send_data);
XinZhangMS 0:f7f1f0d76dd6 1106 }
XinZhangMS 0:f7f1f0d76dd6 1107 singlylinkedlist_remove(http_data->data_list, pending_list_item);
XinZhangMS 0:f7f1f0d76dd6 1108 }
XinZhangMS 0:f7f1f0d76dd6 1109
XinZhangMS 0:f7f1f0d76dd6 1110 http_data->recv_msg.status_code = 0;
XinZhangMS 0:f7f1f0d76dd6 1111 http_data->recv_msg.recv_state = state_closing;
XinZhangMS 0:f7f1f0d76dd6 1112 http_data->recv_msg.total_body_len = 0;
XinZhangMS 0:f7f1f0d76dd6 1113 free(http_data->host_name);
XinZhangMS 0:f7f1f0d76dd6 1114 http_data->host_name = NULL;
XinZhangMS 0:f7f1f0d76dd6 1115
XinZhangMS 0:f7f1f0d76dd6 1116 /* Codes_SRS_UHTTP_07_011: [http_client_close shall free any HTTPHeader object that has not been freed] */
XinZhangMS 0:f7f1f0d76dd6 1117 if (http_data->recv_msg.resp_header != NULL)
XinZhangMS 0:f7f1f0d76dd6 1118 {
XinZhangMS 0:f7f1f0d76dd6 1119 HTTPHeaders_Free(http_data->recv_msg.resp_header);
XinZhangMS 0:f7f1f0d76dd6 1120 http_data->recv_msg.resp_header = NULL;
XinZhangMS 0:f7f1f0d76dd6 1121 }
XinZhangMS 0:f7f1f0d76dd6 1122 if (http_data->recv_msg.msg_body != NULL)
XinZhangMS 0:f7f1f0d76dd6 1123 {
XinZhangMS 0:f7f1f0d76dd6 1124 BUFFER_delete(http_data->recv_msg.msg_body);
XinZhangMS 0:f7f1f0d76dd6 1125 http_data->recv_msg.msg_body = NULL;
XinZhangMS 0:f7f1f0d76dd6 1126 }
XinZhangMS 0:f7f1f0d76dd6 1127 }
XinZhangMS 0:f7f1f0d76dd6 1128 }
XinZhangMS 0:f7f1f0d76dd6 1129
XinZhangMS 0:f7f1f0d76dd6 1130 HTTP_CLIENT_RESULT uhttp_client_execute_request(HTTP_CLIENT_HANDLE handle, HTTP_CLIENT_REQUEST_TYPE request_type, const char* relative_path,
XinZhangMS 0:f7f1f0d76dd6 1131 HTTP_HEADERS_HANDLE http_header_handle, const unsigned char* content, size_t content_len, ON_HTTP_REQUEST_CALLBACK on_request_callback, void* callback_ctx)
XinZhangMS 0:f7f1f0d76dd6 1132 {
XinZhangMS 0:f7f1f0d76dd6 1133 HTTP_CLIENT_RESULT result;
XinZhangMS 0:f7f1f0d76dd6 1134 LIST_ITEM_HANDLE list_item;
XinZhangMS 0:f7f1f0d76dd6 1135
XinZhangMS 0:f7f1f0d76dd6 1136 /* Codes_SRS_UHTTP_07_012: [If handle, relativePath, or httpHeadersHandle is NULL then http_client_execute_request shall return HTTP_CLIENT_INVALID_ARG] */
XinZhangMS 0:f7f1f0d76dd6 1137 if (handle == NULL || on_request_callback == NULL ||
XinZhangMS 0:f7f1f0d76dd6 1138 (content != NULL && content_len == 0) || (content == NULL && content_len != 0) )
XinZhangMS 0:f7f1f0d76dd6 1139 {
XinZhangMS 0:f7f1f0d76dd6 1140 result = HTTP_CLIENT_INVALID_ARG;
XinZhangMS 0:f7f1f0d76dd6 1141 LogError("Invalid parameter sent to execute_request");
XinZhangMS 0:f7f1f0d76dd6 1142 }
XinZhangMS 0:f7f1f0d76dd6 1143 else
XinZhangMS 0:f7f1f0d76dd6 1144 {
XinZhangMS 0:f7f1f0d76dd6 1145 HTTP_CLIENT_HANDLE_DATA* http_data = (HTTP_CLIENT_HANDLE_DATA*)handle;
XinZhangMS 0:f7f1f0d76dd6 1146
XinZhangMS 0:f7f1f0d76dd6 1147 http_data->recv_msg.status_code = 0;
XinZhangMS 0:f7f1f0d76dd6 1148 http_data->recv_msg.recv_state = state_initial;
XinZhangMS 0:f7f1f0d76dd6 1149 http_data->recv_msg.total_body_len = 0;
XinZhangMS 0:f7f1f0d76dd6 1150 http_data->recv_msg.on_request_callback = on_request_callback;
XinZhangMS 0:f7f1f0d76dd6 1151 http_data->recv_msg.user_ctx = callback_ctx;
XinZhangMS 0:f7f1f0d76dd6 1152 if (http_data->recv_msg.resp_header != NULL)
XinZhangMS 0:f7f1f0d76dd6 1153 {
XinZhangMS 0:f7f1f0d76dd6 1154 HTTPHeaders_Free(http_data->recv_msg.resp_header);
XinZhangMS 0:f7f1f0d76dd6 1155 }
XinZhangMS 0:f7f1f0d76dd6 1156 if (http_data->recv_msg.msg_body != NULL)
XinZhangMS 0:f7f1f0d76dd6 1157 {
XinZhangMS 0:f7f1f0d76dd6 1158 BUFFER_delete(http_data->recv_msg.msg_body);
XinZhangMS 0:f7f1f0d76dd6 1159 }
XinZhangMS 0:f7f1f0d76dd6 1160 if ((http_data->recv_msg.resp_header = HTTPHeaders_Alloc()) == NULL)
XinZhangMS 0:f7f1f0d76dd6 1161 {
XinZhangMS 0:f7f1f0d76dd6 1162 /* Codes_SRS_UHTTP_07_017: [If any failure encountered http_client_execute_request shall return HTTP_CLIENT_ERROR] */
XinZhangMS 0:f7f1f0d76dd6 1163 LogError("Failure allocating http http_data items");
XinZhangMS 0:f7f1f0d76dd6 1164 result = HTTP_CLIENT_ERROR;
XinZhangMS 0:f7f1f0d76dd6 1165 }
XinZhangMS 0:f7f1f0d76dd6 1166 else if ( (http_data->recv_msg.msg_body = BUFFER_new() ) == NULL)
XinZhangMS 0:f7f1f0d76dd6 1167 {
XinZhangMS 0:f7f1f0d76dd6 1168 /* Codes_SRS_UHTTP_07_017: [If any failure encountered http_client_execute_request shall return HTTP_CLIENT_ERROR] */
XinZhangMS 0:f7f1f0d76dd6 1169 LogError("Failure allocating http data items");
XinZhangMS 0:f7f1f0d76dd6 1170 HTTPHeaders_Free(http_data->recv_msg.resp_header);
XinZhangMS 0:f7f1f0d76dd6 1171 http_data->recv_msg.resp_header = NULL;
XinZhangMS 0:f7f1f0d76dd6 1172 result = HTTP_CLIENT_ERROR;
XinZhangMS 0:f7f1f0d76dd6 1173 }
XinZhangMS 0:f7f1f0d76dd6 1174 else
XinZhangMS 0:f7f1f0d76dd6 1175 {
XinZhangMS 0:f7f1f0d76dd6 1176 HTTP_SEND_DATA* send_data = (HTTP_SEND_DATA*)malloc(sizeof(HTTP_SEND_DATA));
XinZhangMS 0:f7f1f0d76dd6 1177 if (send_data == NULL)
XinZhangMS 0:f7f1f0d76dd6 1178 {
XinZhangMS 0:f7f1f0d76dd6 1179 LogError("Failure allocating http data items");
XinZhangMS 0:f7f1f0d76dd6 1180 BUFFER_delete(http_data->recv_msg.msg_body);
XinZhangMS 0:f7f1f0d76dd6 1181 http_data->recv_msg.msg_body = NULL;
XinZhangMS 0:f7f1f0d76dd6 1182 HTTPHeaders_Free(http_data->recv_msg.resp_header);
XinZhangMS 0:f7f1f0d76dd6 1183 http_data->recv_msg.resp_header = NULL;
XinZhangMS 0:f7f1f0d76dd6 1184 result = HTTP_CLIENT_ERROR;
XinZhangMS 0:f7f1f0d76dd6 1185 }
XinZhangMS 0:f7f1f0d76dd6 1186 else
XinZhangMS 0:f7f1f0d76dd6 1187 {
XinZhangMS 0:f7f1f0d76dd6 1188 memset(send_data, 0, sizeof(HTTP_SEND_DATA));
XinZhangMS 0:f7f1f0d76dd6 1189 /* Codes_SRS_UHTTP_07_041: [HTTP_CLIENT_REQUEST_TYPE shall support all request types specified under section 9.1.2 in the spec.] */
XinZhangMS 0:f7f1f0d76dd6 1190 send_data->request_type = request_type;
XinZhangMS 0:f7f1f0d76dd6 1191 if ( (content_len > 0) && (send_data->content = BUFFER_create(content, content_len)) == NULL)
XinZhangMS 0:f7f1f0d76dd6 1192 {
XinZhangMS 0:f7f1f0d76dd6 1193 LogError("Failure allocating content buffer");
XinZhangMS 0:f7f1f0d76dd6 1194 result = HTTP_CLIENT_ERROR;
XinZhangMS 0:f7f1f0d76dd6 1195 BUFFER_delete(http_data->recv_msg.msg_body);
XinZhangMS 0:f7f1f0d76dd6 1196 http_data->recv_msg.msg_body = NULL;
XinZhangMS 0:f7f1f0d76dd6 1197 HTTPHeaders_Free(http_data->recv_msg.resp_header);
XinZhangMS 0:f7f1f0d76dd6 1198 http_data->recv_msg.resp_header = NULL;
XinZhangMS 0:f7f1f0d76dd6 1199 free(send_data);
XinZhangMS 0:f7f1f0d76dd6 1200 }
XinZhangMS 0:f7f1f0d76dd6 1201 else if ((send_data->header_line = STRING_new()) == NULL)
XinZhangMS 0:f7f1f0d76dd6 1202 {
XinZhangMS 0:f7f1f0d76dd6 1203 LogError("Failure allocating content buffer");
XinZhangMS 0:f7f1f0d76dd6 1204 result = HTTP_CLIENT_ERROR;
XinZhangMS 0:f7f1f0d76dd6 1205 BUFFER_delete(send_data->content);
XinZhangMS 0:f7f1f0d76dd6 1206 BUFFER_delete(http_data->recv_msg.msg_body);
XinZhangMS 0:f7f1f0d76dd6 1207 http_data->recv_msg.msg_body = NULL;
XinZhangMS 0:f7f1f0d76dd6 1208 HTTPHeaders_Free(http_data->recv_msg.resp_header);
XinZhangMS 0:f7f1f0d76dd6 1209 http_data->recv_msg.resp_header = NULL;
XinZhangMS 0:f7f1f0d76dd6 1210 free(send_data);
XinZhangMS 0:f7f1f0d76dd6 1211 }
XinZhangMS 0:f7f1f0d76dd6 1212 else if (construct_http_headers(http_header_handle, content_len, send_data->header_line, false, http_data->host_name, http_data->port_num))
XinZhangMS 0:f7f1f0d76dd6 1213 {
XinZhangMS 0:f7f1f0d76dd6 1214 LogError("Failure allocating content buffer");
XinZhangMS 0:f7f1f0d76dd6 1215 result = HTTP_CLIENT_ERROR;
XinZhangMS 0:f7f1f0d76dd6 1216 BUFFER_delete(send_data->content);
XinZhangMS 0:f7f1f0d76dd6 1217 STRING_delete(send_data->header_line);
XinZhangMS 0:f7f1f0d76dd6 1218 BUFFER_delete(http_data->recv_msg.msg_body);
XinZhangMS 0:f7f1f0d76dd6 1219 http_data->recv_msg.msg_body = NULL;
XinZhangMS 0:f7f1f0d76dd6 1220 HTTPHeaders_Free(http_data->recv_msg.resp_header);
XinZhangMS 0:f7f1f0d76dd6 1221 http_data->recv_msg.resp_header = NULL;
XinZhangMS 0:f7f1f0d76dd6 1222 free(send_data);
XinZhangMS 0:f7f1f0d76dd6 1223 }
XinZhangMS 0:f7f1f0d76dd6 1224 else if ((list_item = singlylinkedlist_add(http_data->data_list, send_data)) == NULL)
XinZhangMS 0:f7f1f0d76dd6 1225 {
XinZhangMS 0:f7f1f0d76dd6 1226 STRING_delete(send_data->header_line);
XinZhangMS 0:f7f1f0d76dd6 1227 BUFFER_delete(send_data->content);
XinZhangMS 0:f7f1f0d76dd6 1228 LogError("Failure adding send data to list");
XinZhangMS 0:f7f1f0d76dd6 1229 result = HTTP_CLIENT_ERROR;
XinZhangMS 0:f7f1f0d76dd6 1230 BUFFER_delete(http_data->recv_msg.msg_body);
XinZhangMS 0:f7f1f0d76dd6 1231 http_data->recv_msg.msg_body = NULL;
XinZhangMS 0:f7f1f0d76dd6 1232 HTTPHeaders_Free(http_data->recv_msg.resp_header);
XinZhangMS 0:f7f1f0d76dd6 1233 http_data->recv_msg.resp_header = NULL;
XinZhangMS 0:f7f1f0d76dd6 1234 free(send_data);
XinZhangMS 0:f7f1f0d76dd6 1235 }
XinZhangMS 0:f7f1f0d76dd6 1236 else
XinZhangMS 0:f7f1f0d76dd6 1237 {
XinZhangMS 0:f7f1f0d76dd6 1238 if (relative_path != NULL)
XinZhangMS 0:f7f1f0d76dd6 1239 {
XinZhangMS 0:f7f1f0d76dd6 1240 if ((send_data->relative_path = STRING_construct(relative_path)) == NULL)
XinZhangMS 0:f7f1f0d76dd6 1241 {
XinZhangMS 0:f7f1f0d76dd6 1242 (void)singlylinkedlist_remove(http_data->data_list, list_item);
XinZhangMS 0:f7f1f0d76dd6 1243 STRING_delete(send_data->header_line);
XinZhangMS 0:f7f1f0d76dd6 1244 BUFFER_delete(send_data->content);
XinZhangMS 0:f7f1f0d76dd6 1245 LogError("Failure allocating relative path buffer");
XinZhangMS 0:f7f1f0d76dd6 1246 BUFFER_delete(http_data->recv_msg.msg_body);
XinZhangMS 0:f7f1f0d76dd6 1247 http_data->recv_msg.msg_body = NULL;
XinZhangMS 0:f7f1f0d76dd6 1248 HTTPHeaders_Free(http_data->recv_msg.resp_header);
XinZhangMS 0:f7f1f0d76dd6 1249 http_data->recv_msg.resp_header = NULL;
XinZhangMS 0:f7f1f0d76dd6 1250 free(send_data);
XinZhangMS 0:f7f1f0d76dd6 1251 result = HTTP_CLIENT_ERROR;
XinZhangMS 0:f7f1f0d76dd6 1252 }
XinZhangMS 0:f7f1f0d76dd6 1253 else
XinZhangMS 0:f7f1f0d76dd6 1254 {
XinZhangMS 0:f7f1f0d76dd6 1255 /* Codes_SRS_UHTTP_07_018: [upon success http_client_execute_request shall return HTTP_CLIENT_OK.] */
XinZhangMS 0:f7f1f0d76dd6 1256 result = HTTP_CLIENT_OK;
XinZhangMS 0:f7f1f0d76dd6 1257 }
XinZhangMS 0:f7f1f0d76dd6 1258 }
XinZhangMS 0:f7f1f0d76dd6 1259 else
XinZhangMS 0:f7f1f0d76dd6 1260 {
XinZhangMS 0:f7f1f0d76dd6 1261 if ((send_data->relative_path = STRING_construct("/")) == NULL)
XinZhangMS 0:f7f1f0d76dd6 1262 {
XinZhangMS 0:f7f1f0d76dd6 1263 (void)singlylinkedlist_remove(http_data->data_list, list_item);
XinZhangMS 0:f7f1f0d76dd6 1264 STRING_delete(send_data->header_line);
XinZhangMS 0:f7f1f0d76dd6 1265 BUFFER_delete(send_data->content);
XinZhangMS 0:f7f1f0d76dd6 1266 LogError("Failure allocating relative path buffer");
XinZhangMS 0:f7f1f0d76dd6 1267 BUFFER_delete(http_data->recv_msg.msg_body);
XinZhangMS 0:f7f1f0d76dd6 1268 http_data->recv_msg.msg_body = NULL;
XinZhangMS 0:f7f1f0d76dd6 1269 HTTPHeaders_Free(http_data->recv_msg.resp_header);
XinZhangMS 0:f7f1f0d76dd6 1270 http_data->recv_msg.resp_header = NULL;
XinZhangMS 0:f7f1f0d76dd6 1271 free(send_data);
XinZhangMS 0:f7f1f0d76dd6 1272 result = HTTP_CLIENT_ERROR;
XinZhangMS 0:f7f1f0d76dd6 1273 }
XinZhangMS 0:f7f1f0d76dd6 1274 else
XinZhangMS 0:f7f1f0d76dd6 1275 {
XinZhangMS 0:f7f1f0d76dd6 1276 /* Codes_SRS_UHTTP_07_018: [upon success http_client_execute_request shall return HTTP_CLIENT_OK.] */
XinZhangMS 0:f7f1f0d76dd6 1277 result = HTTP_CLIENT_OK;
XinZhangMS 0:f7f1f0d76dd6 1278 }
XinZhangMS 0:f7f1f0d76dd6 1279 }
XinZhangMS 0:f7f1f0d76dd6 1280 }
XinZhangMS 0:f7f1f0d76dd6 1281 }
XinZhangMS 0:f7f1f0d76dd6 1282 }
XinZhangMS 0:f7f1f0d76dd6 1283 }
XinZhangMS 0:f7f1f0d76dd6 1284 return result;
XinZhangMS 0:f7f1f0d76dd6 1285 }
XinZhangMS 0:f7f1f0d76dd6 1286
XinZhangMS 0:f7f1f0d76dd6 1287 void uhttp_client_dowork(HTTP_CLIENT_HANDLE handle)
XinZhangMS 0:f7f1f0d76dd6 1288 {
XinZhangMS 0:f7f1f0d76dd6 1289 if (handle != NULL)
XinZhangMS 0:f7f1f0d76dd6 1290 {
XinZhangMS 0:f7f1f0d76dd6 1291 /* Codes_SRS_UHTTP_07_037: [http_client_dowork shall call the underlying xio_dowork function. ] */
XinZhangMS 0:f7f1f0d76dd6 1292 HTTP_CLIENT_HANDLE_DATA* http_data = (HTTP_CLIENT_HANDLE_DATA*)handle;
XinZhangMS 0:f7f1f0d76dd6 1293 xio_dowork(http_data->xio_handle);
XinZhangMS 0:f7f1f0d76dd6 1294
XinZhangMS 0:f7f1f0d76dd6 1295 // Wait till I'm connected
XinZhangMS 0:f7f1f0d76dd6 1296 if (handle->connected == 1)
XinZhangMS 0:f7f1f0d76dd6 1297 {
XinZhangMS 0:f7f1f0d76dd6 1298 LIST_ITEM_HANDLE pending_list_item;
XinZhangMS 0:f7f1f0d76dd6 1299 /* Codes_SRS_UHTTP_07_016: [http_client_dowork shall iterate through the queued Data using the xio interface to send the http request in the following ways...] */
XinZhangMS 0:f7f1f0d76dd6 1300 while ((pending_list_item = singlylinkedlist_get_head_item(http_data->data_list)) != NULL)
XinZhangMS 0:f7f1f0d76dd6 1301 {
XinZhangMS 0:f7f1f0d76dd6 1302 HTTP_SEND_DATA* send_data = (HTTP_SEND_DATA*)singlylinkedlist_item_get_value(pending_list_item);
XinZhangMS 0:f7f1f0d76dd6 1303 if (send_data != NULL)
XinZhangMS 0:f7f1f0d76dd6 1304 {
XinZhangMS 0:f7f1f0d76dd6 1305 size_t content_len = BUFFER_length(send_data->content);
XinZhangMS 0:f7f1f0d76dd6 1306 /* Codes_SRS_UHTTP_07_052: [uhttp_client_dowork shall call xio_send to transmits the header information... ] */
XinZhangMS 0:f7f1f0d76dd6 1307 if (send_http_data(http_data, send_data->request_type, STRING_c_str(send_data->relative_path), send_data->header_line) != 0)
XinZhangMS 0:f7f1f0d76dd6 1308 {
XinZhangMS 0:f7f1f0d76dd6 1309 LogError("Failure writing content buffer");
XinZhangMS 0:f7f1f0d76dd6 1310 if (http_data->on_error)
XinZhangMS 0:f7f1f0d76dd6 1311 {
XinZhangMS 0:f7f1f0d76dd6 1312 http_data->on_error(http_data->error_user_ctx, HTTP_CALLBACK_REASON_SEND_FAILED);
XinZhangMS 0:f7f1f0d76dd6 1313 }
XinZhangMS 0:f7f1f0d76dd6 1314 }
XinZhangMS 0:f7f1f0d76dd6 1315 else if (content_len > 0)
XinZhangMS 0:f7f1f0d76dd6 1316 {
XinZhangMS 0:f7f1f0d76dd6 1317 /* Codes_SRS_UHTTP_07_053: [ Then uhttp_client_dowork shall use xio_send to transmit the content of the http request. ] */
XinZhangMS 0:f7f1f0d76dd6 1318 if (write_data_line(http_data, BUFFER_u_char(send_data->content), content_len) != 0)
XinZhangMS 0:f7f1f0d76dd6 1319 {
XinZhangMS 0:f7f1f0d76dd6 1320 LogError("Failure writing content buffer");
XinZhangMS 0:f7f1f0d76dd6 1321 if (http_data->on_error)
XinZhangMS 0:f7f1f0d76dd6 1322 {
XinZhangMS 0:f7f1f0d76dd6 1323 http_data->on_error(http_data->error_user_ctx, HTTP_CALLBACK_REASON_SEND_FAILED);
XinZhangMS 0:f7f1f0d76dd6 1324 }
XinZhangMS 0:f7f1f0d76dd6 1325 }
XinZhangMS 0:f7f1f0d76dd6 1326 }
XinZhangMS 0:f7f1f0d76dd6 1327
XinZhangMS 0:f7f1f0d76dd6 1328 /* Codes_SRS_UHTTP_07_046: [ http_client_dowork shall free resouces queued to send to the http endpoint. ] */
XinZhangMS 0:f7f1f0d76dd6 1329 STRING_delete(send_data->relative_path);
XinZhangMS 0:f7f1f0d76dd6 1330 BUFFER_delete(send_data->content);
XinZhangMS 0:f7f1f0d76dd6 1331 STRING_delete(send_data->header_line);
XinZhangMS 0:f7f1f0d76dd6 1332 free(send_data);
XinZhangMS 0:f7f1f0d76dd6 1333 }
XinZhangMS 0:f7f1f0d76dd6 1334 (void)singlylinkedlist_remove(http_data->data_list, pending_list_item);
XinZhangMS 0:f7f1f0d76dd6 1335 }
XinZhangMS 0:f7f1f0d76dd6 1336 }
XinZhangMS 0:f7f1f0d76dd6 1337 }
XinZhangMS 0:f7f1f0d76dd6 1338 }
XinZhangMS 0:f7f1f0d76dd6 1339
XinZhangMS 0:f7f1f0d76dd6 1340 HTTP_CLIENT_RESULT uhttp_client_set_trace(HTTP_CLIENT_HANDLE handle, bool trace_on, bool trace_data)
XinZhangMS 0:f7f1f0d76dd6 1341 {
XinZhangMS 0:f7f1f0d76dd6 1342 HTTP_CLIENT_RESULT result;
XinZhangMS 0:f7f1f0d76dd6 1343 if (handle == NULL)
XinZhangMS 0:f7f1f0d76dd6 1344 {
XinZhangMS 0:f7f1f0d76dd6 1345 /* Codes_SRS_UHTTP_07_038: [If handle is NULL then http_client_set_trace shall return HTTP_CLIENT_INVALID_ARG] */
XinZhangMS 0:f7f1f0d76dd6 1346 result = HTTP_CLIENT_INVALID_ARG;
XinZhangMS 0:f7f1f0d76dd6 1347 LogError("invalid parameter (NULL) passed to http_client_set_trace");
XinZhangMS 0:f7f1f0d76dd6 1348 }
XinZhangMS 0:f7f1f0d76dd6 1349 else
XinZhangMS 0:f7f1f0d76dd6 1350 {
XinZhangMS 0:f7f1f0d76dd6 1351 /* Codes_SRS_UHTTP_07_039: [http_client_set_trace shall set the HTTP tracing to the trace_on variable.] */
XinZhangMS 0:f7f1f0d76dd6 1352 handle->trace_on = trace_on;
XinZhangMS 0:f7f1f0d76dd6 1353 handle->trace_body = trace_data;
XinZhangMS 0:f7f1f0d76dd6 1354 /* Codes_SRS_UHTTP_07_040: [if http_client_set_trace finishes successfully then it shall return HTTP_CLIENT_OK.] */
XinZhangMS 0:f7f1f0d76dd6 1355 result = HTTP_CLIENT_OK;
XinZhangMS 0:f7f1f0d76dd6 1356 }
XinZhangMS 0:f7f1f0d76dd6 1357 return result;
XinZhangMS 0:f7f1f0d76dd6 1358 }
XinZhangMS 0:f7f1f0d76dd6 1359
XinZhangMS 0:f7f1f0d76dd6 1360 HTTP_CLIENT_RESULT uhttp_client_set_X509_cert(HTTP_CLIENT_HANDLE handle, bool ecc_type, const char* certificate, const char* private_key)
XinZhangMS 0:f7f1f0d76dd6 1361 {
XinZhangMS 0:f7f1f0d76dd6 1362 HTTP_CLIENT_RESULT result;
XinZhangMS 0:f7f1f0d76dd6 1363 if (handle == NULL || certificate == NULL || private_key == NULL)
XinZhangMS 0:f7f1f0d76dd6 1364 {
XinZhangMS 0:f7f1f0d76dd6 1365 /* Codes_SRS_UHTTP_07_038: [If handle is NULL then http_client_set_trace shall return HTTP_CLIENT_INVALID_ARG] */
XinZhangMS 0:f7f1f0d76dd6 1366 result = HTTP_CLIENT_INVALID_ARG;
XinZhangMS 0:f7f1f0d76dd6 1367 LogError("invalid parameter handle: %p certificate: %p private_key: %p", handle, certificate, private_key);
XinZhangMS 0:f7f1f0d76dd6 1368 }
XinZhangMS 0:f7f1f0d76dd6 1369 else if (handle->recv_msg.recv_state != state_initial)
XinZhangMS 0:f7f1f0d76dd6 1370 {
XinZhangMS 0:f7f1f0d76dd6 1371 result = HTTP_CLIENT_INVALID_STATE;
XinZhangMS 0:f7f1f0d76dd6 1372 LogError("You must set the X509 certificates before opening the connection");
XinZhangMS 0:f7f1f0d76dd6 1373 }
XinZhangMS 0:f7f1f0d76dd6 1374 else
XinZhangMS 0:f7f1f0d76dd6 1375 {
XinZhangMS 0:f7f1f0d76dd6 1376 handle->cert_type_ecc = ecc_type;
XinZhangMS 0:f7f1f0d76dd6 1377 if (mallocAndStrcpy_s(&handle->x509_cert, certificate) != 0)
XinZhangMS 0:f7f1f0d76dd6 1378 {
XinZhangMS 0:f7f1f0d76dd6 1379 result = HTTP_CLIENT_ERROR;
XinZhangMS 0:f7f1f0d76dd6 1380 LogError("failure allocating certificate");
XinZhangMS 0:f7f1f0d76dd6 1381 }
XinZhangMS 0:f7f1f0d76dd6 1382 else if (mallocAndStrcpy_s(&handle->x509_pk, private_key) != 0)
XinZhangMS 0:f7f1f0d76dd6 1383 {
XinZhangMS 0:f7f1f0d76dd6 1384 free(handle->x509_cert);
XinZhangMS 0:f7f1f0d76dd6 1385 handle->x509_cert = NULL;
XinZhangMS 0:f7f1f0d76dd6 1386 result = HTTP_CLIENT_ERROR;
XinZhangMS 0:f7f1f0d76dd6 1387 LogError("failure allocating private key");
XinZhangMS 0:f7f1f0d76dd6 1388 }
XinZhangMS 0:f7f1f0d76dd6 1389 else
XinZhangMS 0:f7f1f0d76dd6 1390 {
XinZhangMS 0:f7f1f0d76dd6 1391 result = HTTP_CLIENT_OK;
XinZhangMS 0:f7f1f0d76dd6 1392 }
XinZhangMS 0:f7f1f0d76dd6 1393 }
XinZhangMS 0:f7f1f0d76dd6 1394 return result;
XinZhangMS 0:f7f1f0d76dd6 1395 }
XinZhangMS 0:f7f1f0d76dd6 1396
XinZhangMS 0:f7f1f0d76dd6 1397 HTTP_CLIENT_RESULT uhttp_client_set_trusted_cert(HTTP_CLIENT_HANDLE handle, const char* certificate)
XinZhangMS 0:f7f1f0d76dd6 1398 {
XinZhangMS 0:f7f1f0d76dd6 1399 HTTP_CLIENT_RESULT result;
XinZhangMS 0:f7f1f0d76dd6 1400 if (handle == NULL || certificate == NULL)
XinZhangMS 0:f7f1f0d76dd6 1401 {
XinZhangMS 0:f7f1f0d76dd6 1402 /* Codes_SRS_UHTTP_07_038: [If handle is NULL then http_client_set_trace shall return HTTP_CLIENT_INVALID_ARG] */
XinZhangMS 0:f7f1f0d76dd6 1403 result = HTTP_CLIENT_INVALID_ARG;
XinZhangMS 0:f7f1f0d76dd6 1404 LogError("invalid parameter handle: %p certificate: %p", handle, certificate);
XinZhangMS 0:f7f1f0d76dd6 1405 }
XinZhangMS 0:f7f1f0d76dd6 1406 else if (handle->recv_msg.recv_state != state_initial)
XinZhangMS 0:f7f1f0d76dd6 1407 {
XinZhangMS 0:f7f1f0d76dd6 1408 result = HTTP_CLIENT_INVALID_STATE;
XinZhangMS 0:f7f1f0d76dd6 1409 LogError("You must set the certificates before opening the connection");
XinZhangMS 0:f7f1f0d76dd6 1410 }
XinZhangMS 0:f7f1f0d76dd6 1411 else
XinZhangMS 0:f7f1f0d76dd6 1412 {
XinZhangMS 0:f7f1f0d76dd6 1413 if (mallocAndStrcpy_s(&handle->certificate, certificate) != 0)
XinZhangMS 0:f7f1f0d76dd6 1414 {
XinZhangMS 0:f7f1f0d76dd6 1415 result = HTTP_CLIENT_ERROR;
XinZhangMS 0:f7f1f0d76dd6 1416 LogError("failure allocating certificate");
XinZhangMS 0:f7f1f0d76dd6 1417 }
XinZhangMS 0:f7f1f0d76dd6 1418 else
XinZhangMS 0:f7f1f0d76dd6 1419 {
XinZhangMS 0:f7f1f0d76dd6 1420 result = HTTP_CLIENT_OK;
XinZhangMS 0:f7f1f0d76dd6 1421 }
XinZhangMS 0:f7f1f0d76dd6 1422 }
XinZhangMS 0:f7f1f0d76dd6 1423 return result;
XinZhangMS 0:f7f1f0d76dd6 1424 }
XinZhangMS 0:f7f1f0d76dd6 1425
XinZhangMS 0:f7f1f0d76dd6 1426 const char* uhttp_client_get_trusted_cert(HTTP_CLIENT_HANDLE handle)
XinZhangMS 0:f7f1f0d76dd6 1427 {
XinZhangMS 0:f7f1f0d76dd6 1428 const char* result;
XinZhangMS 0:f7f1f0d76dd6 1429 if (handle == NULL)
XinZhangMS 0:f7f1f0d76dd6 1430 {
XinZhangMS 0:f7f1f0d76dd6 1431 result = NULL;
XinZhangMS 0:f7f1f0d76dd6 1432 LogError("invalid parameter NULL handle");
XinZhangMS 0:f7f1f0d76dd6 1433 }
XinZhangMS 0:f7f1f0d76dd6 1434 else
XinZhangMS 0:f7f1f0d76dd6 1435 {
XinZhangMS 0:f7f1f0d76dd6 1436 result = handle->certificate;
XinZhangMS 0:f7f1f0d76dd6 1437 }
XinZhangMS 0:f7f1f0d76dd6 1438 return result;
XinZhangMS 0:f7f1f0d76dd6 1439 }
XinZhangMS 0:f7f1f0d76dd6 1440
XinZhangMS 0:f7f1f0d76dd6 1441 HTTP_CLIENT_RESULT uhttp_client_set_option(HTTP_CLIENT_HANDLE handle, const char* optionName, const void* value)
XinZhangMS 0:f7f1f0d76dd6 1442 {
XinZhangMS 0:f7f1f0d76dd6 1443 HTTP_CLIENT_RESULT result;
XinZhangMS 0:f7f1f0d76dd6 1444 if (handle == NULL)
XinZhangMS 0:f7f1f0d76dd6 1445 {
XinZhangMS 0:f7f1f0d76dd6 1446 /* Codes_SRS_UHTTP_07_038: [If handle is NULL then http_client_set_trace shall return HTTP_CLIENT_INVALID_ARG] */
XinZhangMS 0:f7f1f0d76dd6 1447 result = HTTP_CLIENT_INVALID_ARG;
XinZhangMS 0:f7f1f0d76dd6 1448 LogError("invalid parameter handle: %p", handle);
XinZhangMS 0:f7f1f0d76dd6 1449 }
XinZhangMS 0:f7f1f0d76dd6 1450 else
XinZhangMS 0:f7f1f0d76dd6 1451 {
XinZhangMS 0:f7f1f0d76dd6 1452 int setoption_result = xio_setoption(handle->xio_handle, optionName, value);
XinZhangMS 0:f7f1f0d76dd6 1453 if (setoption_result != 0)
XinZhangMS 0:f7f1f0d76dd6 1454 {
XinZhangMS 0:f7f1f0d76dd6 1455 LogError("xio_setoption fails, returns %d", setoption_result);
XinZhangMS 0:f7f1f0d76dd6 1456 result = HTTP_CLIENT_ERROR;
XinZhangMS 0:f7f1f0d76dd6 1457 }
XinZhangMS 0:f7f1f0d76dd6 1458 else
XinZhangMS 0:f7f1f0d76dd6 1459 {
XinZhangMS 0:f7f1f0d76dd6 1460 result = HTTP_CLIENT_OK;
XinZhangMS 0:f7f1f0d76dd6 1461 }
XinZhangMS 0:f7f1f0d76dd6 1462
XinZhangMS 0:f7f1f0d76dd6 1463 }
XinZhangMS 0:f7f1f0d76dd6 1464
XinZhangMS 0:f7f1f0d76dd6 1465 return result;
XinZhangMS 0:f7f1f0d76dd6 1466 }