source: azure_iot_hub_f767zi/trunk/azure_iot_sdk/c-utility/adapters/httpapi_compact.c@ 457

Last change on this file since 457 was 457, checked in by coas-nagasima, 4 years ago

ファイルを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 64.8 KB
Line 
1// Copyright (c) Microsoft. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
4#include <stdlib.h>
5#include <stdio.h>
6#include <ctype.h>
7#include <string.h>
8#include <limits.h>
9
10#include "azure_macro_utils/macro_utils.h"
11#include "azure_c_shared_utility/gballoc.h"
12#include "azure_c_shared_utility/httpheaders.h"
13#include "azure_c_shared_utility/crt_abstractions.h"
14#include "azure_c_shared_utility/xlogging.h"
15#include "azure_c_shared_utility/xio.h"
16#include "azure_c_shared_utility/platform.h"
17#include "azure_c_shared_utility/tlsio.h"
18#include "azure_c_shared_utility/threadapi.h"
19#include "azure_c_shared_utility/shared_util_options.h"
20#include "azure_c_shared_utility/http_proxy_io.h"
21
22#ifdef _MSC_VER
23#define snprintf _snprintf
24#endif
25
26/*Codes_SRS_HTTPAPI_COMPACT_21_001: [ The httpapi_compact shall implement the methods defined by the httpapi.h. ]*/
27/*Codes_SRS_HTTPAPI_COMPACT_21_002: [ The httpapi_compact shall support the http requests. ]*/
28/*Codes_SRS_HTTPAPI_COMPACT_21_003: [ The httpapi_compact shall return error codes defined by HTTPAPI_RESULT. ]*/
29#include "azure_c_shared_utility/httpapi.h"
30
31#define MAX_HOSTNAME 64
32#define TEMP_BUFFER_SIZE 1024
33
34/*Codes_SRS_HTTPAPI_COMPACT_21_077: [ The HTTPAPI_ExecuteRequest shall wait, at least, 10 seconds for the SSL open process. ]*/
35#define MAX_OPEN_RETRY 100
36/*Codes_SRS_HTTPAPI_COMPACT_21_084: [ The HTTPAPI_CloseConnection shall wait, at least, 10 seconds for the SSL close process. ]*/
37#define MAX_CLOSE_RETRY 100
38/*Codes_SRS_HTTPAPI_COMPACT_21_079: [ The HTTPAPI_ExecuteRequest shall wait, at least, 20 seconds to send a buffer using the SSL connection. ]*/
39#define MAX_SEND_RETRY 200
40/*Codes_SRS_HTTPAPI_COMPACT_21_081: [ The HTTPAPI_ExecuteRequest shall try to read the message with the response up to 20 seconds. ]*/
41#define MAX_RECEIVE_RETRY 200
42/*Codes_SRS_HTTPAPI_COMPACT_21_083: [ The HTTPAPI_ExecuteRequest shall wait, at least, 100 milliseconds between retries. ]*/
43#define RETRY_INTERVAL_IN_MICROSECONDS 100
44
45MU_DEFINE_ENUM_STRINGS(HTTPAPI_RESULT, HTTPAPI_RESULT_VALUES)
46
47typedef struct HTTP_HANDLE_DATA_TAG
48{
49 char* hostName;
50 char* certificate;
51 char* x509ClientCertificate;
52 char* x509ClientPrivateKey;
53 const char* proxy_host;
54 int proxy_port;
55 const char* proxy_username;
56 const char* proxy_password;
57 XIO_HANDLE xio_handle;
58 size_t received_bytes_count;
59 unsigned char* received_bytes;
60 unsigned int is_io_error : 1;
61 unsigned int is_connected : 1;
62 unsigned int send_completed : 1;
63} HTTP_HANDLE_DATA;
64
65/*the following function does the same as sscanf(pos2, "%d", &sec)*/
66/*this function only exists because some of platforms do not have sscanf. */
67static int ParseStringToDecimal(const char *src, int* dst)
68{
69 int result;
70 char* next;
71 long num = strtol(src, &next, 0);
72 if (src == next || num < INT_MIN || num > INT_MAX)
73 {
74 result = EOF;
75 }
76 else
77 {
78 result = 1;
79 }
80 if (num < INT_MIN) num = INT_MIN;
81 if (num > INT_MAX) num = INT_MAX;
82 *dst = (int)num;
83 return result;
84}
85
86/*the following function does the same as sscanf(pos2, "%x", &sec)*/
87/*this function only exists because some of platforms do not have sscanf. This is not a full implementation; it only works with well-defined x numbers. */
88#define HEXA_DIGIT_VAL(c) (((c>='0') && (c<='9')) ? (c-'0') : ((c>='a') && (c<='f')) ? (c-'a'+10) : ((c>='A') && (c<='F')) ? (c-'A'+10) : -1)
89static int ParseStringToHexadecimal(const char *src, size_t* dst)
90{
91 int result;
92 int digitVal;
93 if (src == NULL)
94 {
95 result = EOF;
96 }
97 else if (HEXA_DIGIT_VAL(*src) == -1)
98 {
99 result = EOF;
100 }
101 else
102 {
103 (*dst) = 0;
104 while ((digitVal = HEXA_DIGIT_VAL(*src)) != -1)
105 {
106 (*dst) *= 0x10;
107 (*dst) += (size_t)digitVal;
108 src++;
109 }
110 result = 1;
111 }
112 return result;
113}
114
115/*the following function does the same as sscanf(buf, "HTTP/%*d.%*d %d %*[^\r\n]", &ret) */
116/*this function only exists because some of platforms do not have sscanf. This is not a full implementation; it only works with well-defined HTTP response. */
117static int ParseHttpResponse(const char* src, int* dst)
118{
119 int result;
120 static const char HTTPPrefix[] = "HTTP/";
121 bool fail;
122 const char* runPrefix;
123
124 if ((src == NULL) || (dst == NULL))
125 {
126 result = EOF;
127 }
128 else
129 {
130 fail = false;
131 runPrefix = HTTPPrefix;
132
133 while((*runPrefix) != '\0')
134 {
135 if ((*runPrefix) != (*src))
136 {
137 fail = true;
138 break;
139 }
140 src++;
141 runPrefix++;
142 }
143
144 if (!fail)
145 {
146 while ((*src) != '.')
147 {
148 if ((*src) == '\0')
149 {
150 fail = true;
151 break;
152 }
153 src++;
154 }
155 }
156
157 if (!fail)
158 {
159 while ((*src) != ' ')
160 {
161 if ((*src) == '\0')
162 {
163 fail = true;
164 break;
165 }
166 src++;
167 }
168 }
169
170 if (fail)
171 {
172 result = EOF;
173 }
174 else
175 {
176 result = ParseStringToDecimal(src, dst);
177 }
178 }
179
180 return result;
181}
182
183HTTPAPI_RESULT HTTPAPI_Init(void)
184{
185/*Codes_SRS_HTTPAPI_COMPACT_21_004: [ The HTTPAPI_Init shall allocate all memory to control the http protocol. ]*/
186/*Codes_SRS_HTTPAPI_COMPACT_21_007: [ If there is not enough memory to control the http protocol, the HTTPAPI_Init shall return HTTPAPI_ALLOC_FAILED. ]*/
187/**
188 * No memory is necessary.
189 */
190
191 /*Codes_SRS_HTTPAPI_COMPACT_21_006: [ If HTTPAPI_Init succeed allocating all the needed memory, it shall return HTTPAPI_OK. ]*/
192return HTTPAPI_OK;
193}
194
195void HTTPAPI_Deinit(void)
196{
197 /*Codes_SRS_HTTPAPI_COMPACT_21_009: [ The HTTPAPI_Init shall release all memory allocated by the httpapi_compact. ]*/
198 /**
199 * No memory was necessary.
200 */
201}
202
203/*Codes_SRS_HTTPAPI_COMPACT_21_011: [ The HTTPAPI_CreateConnection shall create an http connection to the host specified by the hostName parameter. ]*/
204HTTP_HANDLE HTTPAPI_CreateConnection(const char* hostName)
205{
206 HTTP_HANDLE_DATA* http_instance;
207
208 if (hostName == NULL)
209 {
210 /*Codes_SRS_HTTPAPI_COMPACT_21_014: [ If the hostName is NULL, the HTTPAPI_CreateConnection shall return NULL as the handle. ]*/
211 LogError("Invalid host name. Null hostName parameter.");
212 http_instance = NULL;
213 }
214 else if (*hostName == '\0')
215 {
216 /*Codes_SRS_HTTPAPI_COMPACT_21_015: [ If the hostName is empty, the HTTPAPI_CreateConnection shall return NULL as the handle. ]*/
217 LogError("Invalid host name. Empty string.");
218 http_instance = NULL;
219 }
220 else
221 {
222 http_instance = (HTTP_HANDLE_DATA*)malloc(sizeof(HTTP_HANDLE_DATA));
223 /*Codes_SRS_HTTPAPI_COMPACT_21_013: [ If there is not enough memory to control the http connection, the HTTPAPI_CreateConnection shall return NULL as the handle. ]*/
224 if (http_instance == NULL)
225 {
226 LogError("There is no memory to control the http connection");
227 }
228 else if(mallocAndStrcpy_s((char**)&(http_instance->hostName), hostName) != 0)
229 {
230 LogError("failure allocate host name");
231 free(http_instance);
232 http_instance = NULL;
233 }
234 else
235 {
236 http_instance->xio_handle = NULL;
237 http_instance->is_connected = 0;
238 http_instance->is_io_error = 0;
239 http_instance->received_bytes_count = 0;
240 http_instance->received_bytes = NULL;
241 http_instance->certificate = NULL;
242 http_instance->x509ClientCertificate = NULL;
243 http_instance->x509ClientPrivateKey = NULL;
244 http_instance->proxy_host = NULL;
245 http_instance->proxy_port = 0;
246 http_instance->proxy_username = NULL;
247 http_instance->proxy_password = NULL;
248 }
249 }
250
251 /*Codes_SRS_HTTPAPI_COMPACT_21_012: [ The HTTPAPI_CreateConnection shall return a non-NULL handle on success. ]*/
252 return (HTTP_HANDLE)http_instance;
253}
254
255static void on_io_close_complete(void* context)
256{
257 HTTP_HANDLE_DATA* http_instance = (HTTP_HANDLE_DATA*)context;
258
259 if (http_instance != NULL)
260 {
261 http_instance->is_connected = 0;
262 }
263}
264
265void HTTPAPI_CloseConnection(HTTP_HANDLE handle)
266{
267 HTTP_HANDLE_DATA* http_instance = (HTTP_HANDLE_DATA*)handle;
268
269 /*Codes_SRS_HTTPAPI_COMPACT_21_020: [ If the connection handle is NULL, the HTTPAPI_CloseConnection shall not do anything. ]*/
270 if (http_instance != NULL)
271 {
272 /*Codes_SRS_HTTPAPI_COMPACT_21_019: [ If there is no previous connection, the HTTPAPI_CloseConnection shall not do anything. ]*/
273 if (http_instance->xio_handle != NULL)
274 {
275 http_instance->is_io_error = 0;
276 /*Codes_SRS_HTTPAPI_COMPACT_21_017: [ The HTTPAPI_CloseConnection shall close the connection previously created in HTTPAPI_ExecuteRequest. ]*/
277 if (xio_close(http_instance->xio_handle, on_io_close_complete, http_instance) != 0)
278 {
279 LogError("The SSL got error closing the connection");
280 /*Codes_SRS_HTTPAPI_COMPACT_21_087: [ If the xio return anything different than 0, the HTTPAPI_CloseConnection shall destroy the connection anyway. ]*/
281 http_instance->is_connected = 0;
282 }
283 else
284 {
285 /*Codes_SRS_HTTPAPI_COMPACT_21_084: [ The HTTPAPI_CloseConnection shall wait, at least, 10 seconds for the SSL close process. ]*/
286 int countRetry = MAX_CLOSE_RETRY;
287 while (http_instance->is_connected == 1)
288 {
289 xio_dowork(http_instance->xio_handle);
290 if ((countRetry--) < 0)
291 {
292 /*Codes_SRS_HTTPAPI_COMPACT_21_085: [ If the HTTPAPI_CloseConnection retries 10 seconds to close the connection without success, it shall destroy the connection anyway. ]*/
293 LogError("Close timeout. The SSL didn't close the connection");
294 http_instance->is_connected = 0;
295 }
296 else if (http_instance->is_io_error == 1)
297 {
298 LogError("The SSL got error closing the connection");
299 http_instance->is_connected = 0;
300 }
301 else if (http_instance->is_connected == 1)
302 {
303 LogInfo("Waiting for TLS close connection");
304 /*Codes_SRS_HTTPAPI_COMPACT_21_086: [ The HTTPAPI_CloseConnection shall wait, at least, 100 milliseconds between retries. ]*/
305 ThreadAPI_Sleep(RETRY_INTERVAL_IN_MICROSECONDS);
306 }
307 }
308 }
309 /*Codes_SRS_HTTPAPI_COMPACT_21_076: [ After close the connection, The HTTPAPI_CloseConnection shall destroy the connection previously created in HTTPAPI_CreateConnection. ]*/
310 xio_destroy(http_instance->xio_handle);
311 }
312
313 if (http_instance->hostName != NULL)
314 {
315 free((void*)http_instance->hostName);
316 }
317
318#ifndef DO_NOT_COPY_TRUSTED_CERTS_STRING
319 /*Codes_SRS_HTTPAPI_COMPACT_21_018: [ If there is a certificate associated to this connection, the HTTPAPI_CloseConnection shall free all allocated memory for the certificate. ]*/
320 if (http_instance->certificate)
321 {
322 free(http_instance->certificate);
323 }
324#endif
325
326 /*Codes_SRS_HTTPAPI_COMPACT_06_001: [ If there is a x509 client certificate associated to this connection, the HTTAPI_CloseConnection shall free all allocated memory for the certificate. ]*/
327 if (http_instance->x509ClientCertificate)
328 {
329 free(http_instance->x509ClientCertificate);
330 }
331
332 /*Codes_SRS_HTTPAPI_COMPACT_06_002: [ If there is a x509 client private key associated to this connection, then HTTP_CloseConnection shall free all the allocated memory for the private key. ]*/
333 if (http_instance->x509ClientPrivateKey)
334 {
335 free(http_instance->x509ClientPrivateKey);
336 }
337
338 if (http_instance->proxy_host != NULL)
339 {
340 free((void*)http_instance->proxy_host);
341 }
342 if (http_instance->proxy_username != NULL)
343 {
344 free((void*)http_instance->proxy_username);
345 }
346 if (http_instance->proxy_password != NULL)
347 {
348 free((void*)http_instance->proxy_password);
349 }
350
351 free(http_instance);
352 }
353}
354
355static void on_io_open_complete(void* context, IO_OPEN_RESULT open_result)
356{
357 HTTP_HANDLE_DATA* http_instance = (HTTP_HANDLE_DATA*)context;
358
359 if (http_instance != NULL)
360 {
361 if (open_result == IO_OPEN_OK)
362 {
363 http_instance->is_connected = 1;
364 http_instance->is_io_error = 0;
365 }
366 else
367 {
368 http_instance->is_io_error = 1;
369 }
370 }
371}
372
373static void on_send_complete(void* context, IO_SEND_RESULT send_result)
374{
375 HTTP_HANDLE_DATA* http_instance = (HTTP_HANDLE_DATA*)context;
376
377 if (http_instance != NULL)
378 {
379 if (send_result == IO_SEND_OK)
380 {
381 http_instance->send_completed = 1;
382 http_instance->is_io_error = 0;
383 }
384 else
385 {
386 http_instance->is_io_error = 1;
387 }
388 }
389}
390
391#define TOLOWER(c) (((c>='A') && (c<='Z'))?c-'A'+'a':c)
392static int InternStrnicmp(const char* s1, const char* s2, size_t n)
393{
394 int result;
395
396 if (s1 == NULL) result = -1;
397 else if (s2 == NULL) result = 1;
398 else
399 {
400 result = 0;
401
402 while(n-- && result == 0)
403 {
404 if (*s1 == 0) result = -1;
405 else if (*s2 == 0) result = 1;
406 else
407 {
408
409 result = TOLOWER(*s1) - TOLOWER(*s2);
410 ++s1;
411 ++s2;
412 }
413 }
414 }
415
416 return result;
417}
418
419static void on_bytes_received(void* context, const unsigned char* buffer, size_t size)
420{
421 unsigned char* new_received_bytes;
422 HTTP_HANDLE_DATA* http_instance = (HTTP_HANDLE_DATA*)context;
423
424 if (http_instance != NULL)
425 {
426
427 if (buffer == NULL)
428 {
429 http_instance->is_io_error = 1;
430 LogError("NULL pointer error");
431 }
432 else
433 {
434 /* Here we got some bytes so we'll buffer them so the receive functions can consumer it */
435 new_received_bytes = (unsigned char*)realloc(http_instance->received_bytes, http_instance->received_bytes_count + size);
436 if (new_received_bytes == NULL)
437 {
438 http_instance->is_io_error = 1;
439 LogError("Error allocating memory for received data");
440 }
441 else
442 {
443 http_instance->received_bytes = new_received_bytes;
444 if (memcpy(http_instance->received_bytes + http_instance->received_bytes_count, buffer, size) == NULL)
445 {
446 http_instance->is_io_error = 1;
447 LogError("Error copping received data to the HTTP bufffer");
448 }
449 else
450 {
451 http_instance->received_bytes_count += size;
452 }
453 }
454 }
455 }
456}
457
458static void on_io_error(void* context)
459{
460 HTTP_HANDLE_DATA* http_instance = (HTTP_HANDLE_DATA*)context;
461 if (http_instance != NULL)
462 {
463 http_instance->is_io_error = 1;
464 LogError("Error signalled by underlying IO");
465 }
466}
467
468static int conn_receive(HTTP_HANDLE_DATA* http_instance, char* buffer, int count)
469{
470 int result;
471
472 if ((http_instance == NULL) || (buffer == NULL) || (count < 0))
473 {
474 LogError("conn_receive: %s", ((http_instance == NULL) ? "Invalid HTTP instance" : "Invalid HTTP buffer"));
475 result = -1;
476 }
477 else
478 {
479 result = 0;
480 while (result < count)
481 {
482 xio_dowork(http_instance->xio_handle);
483
484 /* if any error was detected while receiving then simply break and report it */
485 if (http_instance->is_io_error != 0)
486 {
487 LogError("xio reported error on dowork");
488 result = -1;
489 break;
490 }
491
492 if (http_instance->received_bytes_count >= (size_t)count)
493 {
494 /* Consuming bytes from the receive buffer */
495 (void)memcpy(buffer, http_instance->received_bytes, count);
496 (void)memmove(http_instance->received_bytes, http_instance->received_bytes + count, http_instance->received_bytes_count - count);
497 http_instance->received_bytes_count -= count;
498
499 /* we're not reallocating at each consumption so that we don't trash due to byte by byte consumption */
500 if (http_instance->received_bytes_count == 0)
501 {
502 free(http_instance->received_bytes);
503 http_instance->received_bytes = NULL;
504 }
505
506 result = count;
507 break;
508 }
509
510 /*Codes_SRS_HTTPAPI_COMPACT_21_083: [ The HTTPAPI_ExecuteRequest shall wait, at least, 100 milliseconds between retries. ]*/
511 ThreadAPI_Sleep(RETRY_INTERVAL_IN_MICROSECONDS);
512 }
513 }
514
515 return result;
516}
517
518static void conn_receive_discard_buffer(HTTP_HANDLE_DATA* http_instance)
519{
520 if (http_instance != NULL)
521 {
522 if (http_instance->received_bytes != NULL)
523 {
524 free(http_instance->received_bytes);
525 http_instance->received_bytes = NULL;
526 }
527 http_instance->received_bytes_count = 0;
528 }
529}
530
531static int readLine(HTTP_HANDLE_DATA* http_instance, char* buf, const size_t maxBufSize)
532{
533 int resultLineSize;
534
535 if ((http_instance == NULL) || (buf == NULL) || (maxBufSize == 0))
536 {
537 LogError("%s", ((http_instance == NULL) ? "Invalid HTTP instance" : "Invalid HTTP buffer"));
538 resultLineSize = -1;
539 }
540 else
541 {
542 char* destByte = buf;
543 /*Codes_SRS_HTTPAPI_COMPACT_21_081: [ The HTTPAPI_ExecuteRequest shall try to read the message with the response up to 20 seconds. ]*/
544 int countRetry = MAX_RECEIVE_RETRY;
545 bool endOfSearch = false;
546 resultLineSize = -1;
547 while (!endOfSearch)
548 {
549 xio_dowork(http_instance->xio_handle);
550
551 /* if any error was detected while receiving then simply break and report it */
552 if (http_instance->is_io_error != 0)
553 {
554 LogError("xio reported error on dowork");
555 endOfSearch = true;
556 }
557 else
558 {
559 unsigned char* receivedByte = http_instance->received_bytes;
560 while (receivedByte < (http_instance->received_bytes + http_instance->received_bytes_count))
561 {
562 if ((*receivedByte) != '\r')
563 {
564 (*destByte) = (*receivedByte);
565 destByte++;
566 receivedByte++;
567
568 if (destByte >= (buf + maxBufSize - 1))
569 {
570 LogError("Received message is bigger than the http buffer");
571 receivedByte = http_instance->received_bytes + http_instance->received_bytes_count;
572 endOfSearch = true;
573 break;
574 }
575 }
576 else
577 {
578 receivedByte++;
579 if ((receivedByte < (http_instance->received_bytes + http_instance->received_bytes_count)) && ((*receivedByte) == '\n'))
580 {
581 receivedByte++;
582 }
583 (*destByte) = '\0';
584 resultLineSize = (int)(destByte - buf);
585 endOfSearch = true;
586 break;
587 }
588 }
589
590 http_instance->received_bytes_count -= (receivedByte - http_instance->received_bytes);
591 if (http_instance->received_bytes_count != 0)
592 {
593 (void)memmove(http_instance->received_bytes, receivedByte, http_instance->received_bytes_count);
594 }
595 else
596 {
597 conn_receive_discard_buffer(http_instance);
598 }
599 }
600
601 if (!endOfSearch)
602 {
603 if ((countRetry--) > 0)
604 {
605 /*Codes_SRS_HTTPAPI_COMPACT_21_083: [ The HTTPAPI_ExecuteRequest shall wait, at least, 100 milliseconds between retries. ]*/
606 ThreadAPI_Sleep(RETRY_INTERVAL_IN_MICROSECONDS);
607 }
608 else
609 {
610 /*Codes_SRS_HTTPAPI_COMPACT_21_082: [ If the HTTPAPI_ExecuteRequest retries 20 seconds to receive the message without success, it shall fail and return HTTPAPI_READ_DATA_FAILED. ]*/
611 LogError("Receive timeout. The HTTP request is incomplete");
612 endOfSearch = true;
613 }
614 }
615 }
616 }
617
618 return resultLineSize;
619}
620
621static int readChunk(HTTP_HANDLE_DATA* http_instance, char* buf, size_t size)
622{
623 int cur, offset;
624
625 // read content with specified length, even if it is received
626 // only in chunks due to fragmentation in the networking layer.
627 // returns -1 in case of error.
628 offset = 0;
629 while (size > (size_t)0)
630 {
631 cur = conn_receive(http_instance, buf + offset, (int)size);
632
633 // end of stream reached
634 if (cur == 0)
635 {
636 break;
637 }
638
639 // read cur bytes (might be less than requested)
640 size -= (size_t)cur;
641 offset += cur;
642 }
643
644 return offset;
645}
646
647static int skipN(HTTP_HANDLE_DATA* http_instance, size_t n)
648{
649 // read and abandon response content with specified length
650 // returns -1 in case of error.
651
652 int result;
653
654 if (http_instance == NULL)
655 {
656 LogError("Invalid HTTP instance");
657 result = -1;
658 }
659 else
660 {
661 /*Codes_SRS_HTTPAPI_COMPACT_21_081: [ The HTTPAPI_ExecuteRequest shall try to read the message with the response up to 20 seconds. ]*/
662 int countRetry = MAX_RECEIVE_RETRY;
663 result = (int)n;
664 while (n > 0)
665 {
666 xio_dowork(http_instance->xio_handle);
667
668 /* if any error was detected while receiving then simply break and report it */
669 if (http_instance->is_io_error != 0)
670 {
671 LogError("xio reported error on dowork");
672 result = -1;
673 n = 0;
674 }
675 else
676 {
677 if (http_instance->received_bytes_count <= n)
678 {
679 n -= http_instance->received_bytes_count;
680 http_instance->received_bytes_count = 0;
681 }
682 else
683 {
684 http_instance->received_bytes_count -= n;
685 (void)memmove(http_instance->received_bytes, http_instance->received_bytes + n, http_instance->received_bytes_count);
686 n = 0;
687 }
688
689 if (n > 0)
690 {
691 if ((countRetry--) > 0)
692 {
693 /*Codes_SRS_HTTPAPI_COMPACT_21_083: [ The HTTPAPI_ExecuteRequest shall wait, at least, 100 milliseconds between retries. ]*/
694 ThreadAPI_Sleep(RETRY_INTERVAL_IN_MICROSECONDS);
695 }
696 else
697 {
698 /*Codes_SRS_HTTPAPI_COMPACT_21_082: [ If the HTTPAPI_ExecuteRequest retries 20 seconds to receive the message without success, it shall fail and return HTTPAPI_READ_DATA_FAILED. ]*/
699 LogError("Receive timeout. The HTTP request is incomplete");
700 n = 0;
701 result = -1;
702 }
703 }
704 }
705 }
706 }
707
708 return result;
709}
710
711
712/*Codes_SRS_HTTPAPI_COMPACT_21_021: [ The HTTPAPI_ExecuteRequest shall execute the http communtication with the provided host, sending a request and reciving the response. ]*/
713static HTTPAPI_RESULT OpenXIOConnection(HTTP_HANDLE_DATA* http_instance)
714{
715 HTTPAPI_RESULT result;
716 TLSIO_CONFIG tlsio_config;
717 HTTP_PROXY_IO_CONFIG http_proxy_io_config;
718
719 if (http_instance->is_connected != 0)
720 {
721 /*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
722 result = HTTPAPI_OK;
723 }
724 else
725 {
726 http_instance->is_io_error = 0;
727 tlsio_config.hostname = http_instance->hostName;
728 tlsio_config.port = 443;
729
730 if (http_instance->proxy_host != NULL) {
731 tlsio_config.underlying_io_interface = http_proxy_io_get_interface_description();
732 }
733 else {
734 tlsio_config.underlying_io_interface = NULL;
735 }
736
737 if (tlsio_config.underlying_io_interface != NULL) {
738 tlsio_config.underlying_io_parameters = (void*)&http_proxy_io_config;
739
740 http_proxy_io_config.proxy_hostname = http_instance->proxy_host;
741 http_proxy_io_config.proxy_port = http_instance->proxy_port;
742 http_proxy_io_config.username = http_instance->proxy_username;
743 http_proxy_io_config.password = http_instance->proxy_password;
744 http_proxy_io_config.hostname = http_instance->hostName;
745 http_proxy_io_config.port = 443;
746 }
747 else {
748 tlsio_config.underlying_io_parameters = NULL;
749 }
750
751 http_instance->xio_handle = xio_create(platform_get_default_tlsio(), (void*)&tlsio_config);
752
753 if (http_instance->xio_handle == NULL)
754 {
755 LogError("Create connection failed");
756 free(http_instance);
757 http_instance = NULL;
758 result = HTTPAPI_ERROR;
759 }
760 /*Codes_SRS_HTTPAPI_COMPACT_21_022: [ If a Certificate was provided, the HTTPAPI_ExecuteRequest shall set this option on the transport layer. ]*/
761 else if ((http_instance->certificate != NULL) &&
762 (xio_setoption(http_instance->xio_handle, OPTION_TRUSTED_CERT, http_instance->certificate) != 0))
763 {
764 /*Codes_SRS_HTTPAPI_COMPACT_21_023: [ If the transport failed setting the Certificate, the HTTPAPI_ExecuteRequest shall not send any request and return HTTPAPI_SET_OPTION_FAILED. ]*/
765 result = HTTPAPI_SET_OPTION_FAILED;
766 LogInfo("Could not load certificate");
767 }
768 /*Codes_SRS_HTTPAPI_COMPACT_06_003: [ If the x509 client certificate is provided, the HTTPAPI_ExecuteRequest shall set this option on the transport layer. ]*/
769 else if ((http_instance->x509ClientCertificate != NULL) &&
770 (xio_setoption(http_instance->xio_handle, SU_OPTION_X509_CERT, http_instance->x509ClientCertificate) != 0))
771 {
772 /*Codes_SRS_HTTPAPI_COMPACT_06_005: [ If the transport failed setting the client certificate, the HTTPAPI_ExecuteRequest shall not send any request and return HTTPAPI_SET_OPTION_FAILED. ]*/
773 result = HTTPAPI_SET_OPTION_FAILED;
774 LogInfo("Could not load the client certificate");
775 }
776 else if ((http_instance->x509ClientPrivateKey != NULL) &&
777 (xio_setoption(http_instance->xio_handle, SU_OPTION_X509_PRIVATE_KEY, http_instance->x509ClientPrivateKey) != 0))
778 {
779 /*Codes_SRS_HTTPAPI_COMPACT_06_006: [ If the transport failed setting the client certificate private key, the HTTPAPI_ExecuteRequest shall not send any request and return HTTPAPI_SET_OPTION_FAILED. ] */
780 result = HTTPAPI_SET_OPTION_FAILED;
781 LogInfo("Could not load the client certificate private key");
782 }
783 else
784 {
785 /*Codes_SRS_HTTPAPI_COMPACT_21_024: [ The HTTPAPI_ExecuteRequest shall open the transport connection with the host to send the request. ]*/
786 if (xio_open(http_instance->xio_handle, on_io_open_complete, http_instance, on_bytes_received, http_instance, on_io_error, http_instance) != 0)
787 {
788 /*Codes_SRS_HTTPAPI_COMPACT_21_025: [ If the open process failed, the HTTPAPI_ExecuteRequest shall not send any request and return HTTPAPI_OPEN_REQUEST_FAILED. ]*/
789 result = HTTPAPI_OPEN_REQUEST_FAILED;
790 }
791 else
792 {
793 int countRetry;
794 /*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
795 result = HTTPAPI_OK;
796 /*Codes_SRS_HTTPAPI_COMPACT_21_077: [ The HTTPAPI_ExecuteRequest shall wait, at least, 10 seconds for the SSL open process. ]*/
797 countRetry = MAX_OPEN_RETRY;
798 while ((http_instance->is_connected == 0) &&
799 (http_instance->is_io_error == 0))
800 {
801 xio_dowork(http_instance->xio_handle);
802 //LogInfo("Waiting for TLS connection");
803 if ((countRetry--) < 0)
804 {
805 /*Codes_SRS_HTTPAPI_COMPACT_21_078: [ If the HTTPAPI_ExecuteRequest cannot open the connection in 10 seconds, it shall fail and return HTTPAPI_OPEN_REQUEST_FAILED. ]*/
806 LogError("Open timeout. The HTTP request is incomplete");
807 result = HTTPAPI_OPEN_REQUEST_FAILED;
808 break;
809 }
810 else
811 {
812 /*Codes_SRS_HTTPAPI_COMPACT_21_083: [ The HTTPAPI_ExecuteRequest shall wait, at least, 100 milliseconds between retries. ]*/
813 ThreadAPI_Sleep(RETRY_INTERVAL_IN_MICROSECONDS);
814 }
815 }
816 }
817 }
818 }
819
820 if ((http_instance->is_io_error != 0) && (result == HTTPAPI_OK))
821 {
822 /*Codes_SRS_HTTPAPI_COMPACT_21_025: [ If the open process failed, the HTTPAPI_ExecuteRequest shall not send any request and return HTTPAPI_OPEN_REQUEST_FAILED. ]*/
823 result = HTTPAPI_OPEN_REQUEST_FAILED;
824 }
825
826 return result;
827}
828
829static HTTPAPI_RESULT conn_send_all(HTTP_HANDLE_DATA* http_instance, const unsigned char* buf, size_t bufLen)
830{
831 HTTPAPI_RESULT result;
832
833 http_instance->send_completed = 0;
834 http_instance->is_io_error = 0;
835 if (xio_send(http_instance->xio_handle, buf, bufLen, on_send_complete, http_instance) != 0)
836 {
837 /*Codes_SRS_HTTPAPI_COMPACT_21_028: [ If the HTTPAPI_ExecuteRequest cannot send the request header, it shall return HTTPAPI_HTTP_HEADERS_FAILED. ]*/
838 result = HTTPAPI_SEND_REQUEST_FAILED;
839 }
840 else
841 {
842 /*Codes_SRS_HTTPAPI_COMPACT_21_079: [ The HTTPAPI_ExecuteRequest shall wait, at least, 20 seconds to send a buffer using the SSL connection. ]*/
843 int countRetry = MAX_SEND_RETRY;
844 /*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
845 result = HTTPAPI_OK;
846 while ((http_instance->send_completed == 0) && (result == HTTPAPI_OK))
847 {
848 xio_dowork(http_instance->xio_handle);
849 if (http_instance->is_io_error != 0)
850 {
851 /*Codes_SRS_HTTPAPI_COMPACT_21_028: [ If the HTTPAPI_ExecuteRequest cannot send the request header, it shall return HTTPAPI_HTTP_HEADERS_FAILED. ]*/
852 result = HTTPAPI_SEND_REQUEST_FAILED;
853 }
854 else if ((countRetry--) <= 0)
855 {
856 /*Codes_SRS_HTTPAPI_COMPACT_21_080: [ If the HTTPAPI_ExecuteRequest retries to send the message for 20 seconds without success, it shall fail and return HTTPAPI_SEND_REQUEST_FAILED. ]*/
857 LogError("Send timeout. The HTTP request is incomplete");
858 /*Codes_SRS_HTTPAPI_COMPACT_21_028: [ If the HTTPAPI_ExecuteRequest cannot send the request header, it shall return HTTPAPI_HTTP_HEADERS_FAILED. ]*/
859 result = HTTPAPI_SEND_REQUEST_FAILED;
860 }
861 else
862 {
863 /*Codes_SRS_HTTPAPI_COMPACT_21_083: [ The HTTPAPI_ExecuteRequest shall wait, at least, 100 milliseconds between retries. ]*/
864 ThreadAPI_Sleep(RETRY_INTERVAL_IN_MICROSECONDS);
865 }
866 }
867 }
868
869 return result;
870}
871
872/*Codes_SRS_HTTPAPI_COMPACT_21_035: [ The HTTPAPI_ExecuteRequest shall execute resquest for types GET, POST, PUT, DELETE, PATCH, HEAD. ]*/
873const char httpapiRequestString[6][7] = { "GET", "POST", "PUT", "DELETE", "PATCH", "HEAD" };
874const char* get_request_type(HTTPAPI_REQUEST_TYPE requestType)
875{
876 return (const char*)httpapiRequestString[requestType - HTTPAPI_REQUEST_GET];
877}
878
879/*Codes_SRS_HTTPAPI_COMPACT_21_026: [ If the open process succeed, the HTTPAPI_ExecuteRequest shall send the request message to the host. ]*/
880static HTTPAPI_RESULT SendHeadsToXIO(HTTP_HANDLE_DATA* http_instance, HTTPAPI_REQUEST_TYPE requestType, const char* relativePath, HTTP_HEADERS_HANDLE httpHeadersHandle, size_t headersCount)
881{
882 HTTPAPI_RESULT result;
883 char buf[TEMP_BUFFER_SIZE];
884 int ret;
885
886 //Send request
887 /*Codes_SRS_HTTPAPI_COMPACT_21_038: [ The HTTPAPI_ExecuteRequest shall execute the resquest for the path in relativePath parameter. ]*/
888 /*Codes_SRS_HTTPAPI_COMPACT_21_036: [ The request type shall be provided in the parameter requestType. ]*/
889 if (((ret = snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\n", get_request_type(requestType), relativePath)) < 0) ||
890 ((size_t)ret >= sizeof(buf)))
891 {
892 /*Codes_SRS_HTTPAPI_COMPACT_21_027: [ If the HTTPAPI_ExecuteRequest cannot create a buffer to send the request, it shall not send any request and return HTTPAPI_STRING_PROCESSING_ERROR. ]*/
893 result = HTTPAPI_STRING_PROCESSING_ERROR;
894 }
895 /*Codes_SRS_HTTPAPI_COMPACT_21_028: [ If the HTTPAPI_ExecuteRequest cannot send the request header, it shall return HTTPAPI_HTTP_HEADERS_FAILED. ]*/
896 else if ((result = conn_send_all(http_instance, (const unsigned char*)buf, strlen(buf))) == HTTPAPI_OK)
897 {
898 size_t i;
899 //Send default headers
900 /*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
901 for (i = 0; ((i < headersCount) && (result == HTTPAPI_OK)); i++)
902 {
903 char* header;
904 if (HTTPHeaders_GetHeader(httpHeadersHandle, i, &header) != HTTP_HEADERS_OK)
905 {
906 /*Codes_SRS_HTTPAPI_COMPACT_21_027: [ If the HTTPAPI_ExecuteRequest cannot create a buffer to send the request, it shall not send any request and return HTTPAPI_STRING_PROCESSING_ERROR. ]*/
907 result = HTTPAPI_STRING_PROCESSING_ERROR;
908 }
909 else
910 {
911 if ((result = conn_send_all(http_instance, (const unsigned char*)header, strlen(header))) == HTTPAPI_OK)
912 {
913 result = conn_send_all(http_instance, (const unsigned char*)"\r\n", (size_t)2);
914 }
915 free(header);
916 }
917 }
918
919 //Close headers
920 if (result == HTTPAPI_OK)
921 {
922 result = conn_send_all(http_instance, (const unsigned char*)"\r\n", (size_t)2);
923 }
924 }
925 return result;
926}
927
928/*Codes_SRS_HTTPAPI_COMPACT_21_042: [ The request can contain the a content message, provided in content parameter. ]*/
929static HTTPAPI_RESULT SendContentToXIO(HTTP_HANDLE_DATA* http_instance, const unsigned char* content, size_t contentLength)
930{
931 HTTPAPI_RESULT result;
932
933 //Send data (if available)
934 /*Codes_SRS_HTTPAPI_COMPACT_21_045: [ If the contentLength is lower than one, the HTTPAPI_ExecuteRequest shall send the request without content. ]*/
935 if (content && contentLength > 0)
936 {
937 /*Codes_SRS_HTTPAPI_COMPACT_21_044: [ If the content is not NULL, the number of bytes in the content shall be provided in contentLength parameter. ]*/
938 result = conn_send_all(http_instance, content, contentLength);
939 }
940 else
941 {
942 /*Codes_SRS_HTTPAPI_COMPACT_21_043: [ If the content is NULL, the HTTPAPI_ExecuteRequest shall send the request without content. ]*/
943 /*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
944 result = HTTPAPI_OK;
945 }
946 return result;
947}
948
949/*Codes_SRS_HTTPAPI_COMPACT_21_030: [ At the end of the transmission, the HTTPAPI_ExecuteRequest shall receive the response from the host. ]*/
950static HTTPAPI_RESULT ReceiveHeaderFromXIO(HTTP_HANDLE_DATA* http_instance, unsigned int* statusCode)
951{
952 HTTPAPI_RESULT result;
953 char buf[TEMP_BUFFER_SIZE];
954 int ret;
955
956 http_instance->is_io_error = 0;
957
958 //Receive response
959 if (readLine(http_instance, buf, TEMP_BUFFER_SIZE) < 0)
960 {
961 /*Codes_SRS_HTTPAPI_COMPACT_21_032: [ If the HTTPAPI_ExecuteRequest cannot read the message with the request result, it shall return HTTPAPI_READ_DATA_FAILED. ]*/
962 /*Codes_SRS_HTTPAPI_COMPACT_21_082: [ If the HTTPAPI_ExecuteRequest retries 20 seconds to receive the message without success, it shall fail and return HTTPAPI_READ_DATA_FAILED. ]*/
963 result = HTTPAPI_READ_DATA_FAILED;
964 }
965 //Parse HTTP response
966 else if (ParseHttpResponse(buf, &ret) != 1)
967 {
968 //Cannot match string, error
969 /*Codes_SRS_HTTPAPI_COMPACT_21_055: [ If the HTTPAPI_ExecuteRequest cannot parser the received message, it shall return HTTPAPI_RECEIVE_RESPONSE_FAILED. ]*/
970 LogInfo("Not a correct HTTP answer");
971 result = HTTPAPI_RECEIVE_RESPONSE_FAILED;
972 }
973 else
974 {
975 /*Codes_SRS_HTTPAPI_COMPACT_21_046: [ The HTTPAPI_ExecuteRequest shall return the http status reported by the host in the received response. ]*/
976 /*Codes_SRS_HTTPAPI_COMPACT_21_048: [ If the statusCode is NULL, the HTTPAPI_ExecuteRequest shall report not report any status. ]*/
977 if (statusCode)
978 {
979 /*Codes_SRS_HTTPAPI_COMPACT_21_047: [ The HTTPAPI_ExecuteRequest shall report the status in the statusCode parameter. ]*/
980 *statusCode = ret;
981 }
982 /*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
983 result = HTTPAPI_OK;
984 }
985
986 return result;
987}
988
989static HTTPAPI_RESULT ReceiveContentInfoFromXIO(HTTP_HANDLE_DATA* http_instance, HTTP_HEADERS_HANDLE responseHeadersHandle, size_t* bodyLength, bool* chunked)
990{
991 HTTPAPI_RESULT result;
992 char buf[TEMP_BUFFER_SIZE];
993 const char* substr;
994 char* whereIsColon;
995 int lengthInMsg;
996 const char ContentLength[] = "content-length:";
997 const size_t ContentLengthSize = sizeof(ContentLength) - 1;
998 const char TransferEncoding[] = "transfer-encoding:";
999 const size_t TransferEncodingSize = sizeof(TransferEncoding) - 1;
1000 const char Chunked[] = "chunked";
1001 const size_t ChunkedSize = sizeof(Chunked) - 1;
1002
1003 http_instance->is_io_error = 0;
1004
1005 //Read HTTP response headers
1006 if (readLine(http_instance, buf, sizeof(buf)) < 0)
1007 {
1008 /*Codes_SRS_HTTPAPI_COMPACT_21_032: [ If the HTTPAPI_ExecuteRequest cannot read the message with the request result, it shall return HTTPAPI_READ_DATA_FAILED. ]*/
1009 /*Codes_SRS_HTTPAPI_COMPACT_21_082: [ If the HTTPAPI_ExecuteRequest retries 20 seconds to receive the message without success, it shall fail and return HTTPAPI_READ_DATA_FAILED. ]*/
1010 result = HTTPAPI_READ_DATA_FAILED;
1011 }
1012 else
1013 {
1014 /*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
1015 result = HTTPAPI_OK;
1016
1017 while (*buf && (result == HTTPAPI_OK))
1018 {
1019 if (InternStrnicmp(buf, ContentLength, ContentLengthSize) == 0)
1020 {
1021 substr = buf + ContentLengthSize;
1022 if (ParseStringToDecimal(substr, &lengthInMsg) != 1)
1023 {
1024 /*Codes_SRS_HTTPAPI_COMPACT_21_032: [ If the HTTPAPI_ExecuteRequest cannot read the message with the request result, it shall return HTTPAPI_READ_DATA_FAILED. ]*/
1025 result = HTTPAPI_READ_DATA_FAILED;
1026 }
1027 else
1028 {
1029 (*bodyLength) = (size_t)lengthInMsg;
1030 }
1031 }
1032 else if (InternStrnicmp(buf, TransferEncoding, TransferEncodingSize) == 0)
1033 {
1034 substr = buf + TransferEncodingSize;
1035
1036 while (isspace(*substr)) substr++;
1037
1038 if (InternStrnicmp(substr, Chunked, ChunkedSize) == 0)
1039 {
1040 (*chunked) = true;
1041 }
1042 }
1043
1044 if (result == HTTPAPI_OK)
1045 {
1046 whereIsColon = strchr((char*)buf, ':');
1047 /*Codes_SRS_HTTPAPI_COMPACT_21_049: [ If responseHeadersHandle is provide, the HTTPAPI_ExecuteRequest shall prepare a Response Header usign the HTTPHeaders_AddHeaderNameValuePair. ]*/
1048 if (whereIsColon && (responseHeadersHandle != NULL))
1049 {
1050 *whereIsColon = '\0';
1051 HTTPHeaders_AddHeaderNameValuePair(responseHeadersHandle, buf, whereIsColon + 1);
1052 }
1053
1054 if (readLine(http_instance, buf, sizeof(buf)) < 0)
1055 {
1056 /*Codes_SRS_HTTPAPI_COMPACT_21_032: [ If the HTTPAPI_ExecuteRequest cannot read the message with the request result, it shall return HTTPAPI_READ_DATA_FAILED. ]*/
1057 /*Codes_SRS_HTTPAPI_COMPACT_21_082: [ If the HTTPAPI_ExecuteRequest retries 20 seconds to receive the message without success, it shall fail and return HTTPAPI_READ_DATA_FAILED. ]*/
1058 result = HTTPAPI_READ_DATA_FAILED;
1059 }
1060 }
1061 }
1062 }
1063
1064 return result;
1065}
1066
1067static HTTPAPI_RESULT ReadHTTPResponseBodyFromXIO(HTTP_HANDLE_DATA* http_instance, size_t bodyLength, bool chunked, BUFFER_HANDLE responseContent)
1068{
1069 HTTPAPI_RESULT result;
1070 char buf[TEMP_BUFFER_SIZE];
1071 const unsigned char* receivedContent;
1072
1073 http_instance->is_io_error = 0;
1074
1075 //Read HTTP response body
1076 if (!chunked)
1077 {
1078 if (bodyLength)
1079 {
1080 if (responseContent != NULL)
1081 {
1082 if (BUFFER_pre_build(responseContent, bodyLength) != 0)
1083 {
1084 /*Codes_SRS_HTTPAPI_COMPACT_21_052: [ If any memory allocation get fail, the HTTPAPI_ExecuteRequest shall return HTTPAPI_ALLOC_FAILED. ]*/
1085 result = HTTPAPI_ALLOC_FAILED;
1086 }
1087 else if (BUFFER_content(responseContent, &receivedContent) != 0)
1088 {
1089 (void)BUFFER_unbuild(responseContent);
1090
1091 /*Codes_SRS_HTTPAPI_COMPACT_21_052: [ If any memory allocation get fail, the HTTPAPI_ExecuteRequest shall return HTTPAPI_ALLOC_FAILED. ]*/
1092 result = HTTPAPI_ALLOC_FAILED;
1093 }
1094 else if (readChunk(http_instance, (char*)receivedContent, bodyLength) < 0)
1095 {
1096 /*Codes_SRS_HTTPAPI_COMPACT_21_032: [ If the HTTPAPI_ExecuteRequest cannot read the message with the request result, it shall return HTTPAPI_READ_DATA_FAILED. ]*/
1097 result = HTTPAPI_READ_DATA_FAILED;
1098 }
1099 else
1100 {
1101 /*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
1102 result = HTTPAPI_OK;
1103 }
1104 }
1105 else
1106 {
1107 /*Codes_SRS_HTTPAPI_COMPACT_21_051: [ If the responseContent is NULL, the HTTPAPI_ExecuteRequest shall ignore any content in the response. ]*/
1108 if (skipN(http_instance, bodyLength) < 0)
1109 {
1110 /*Codes_SRS_HTTPAPI_COMPACT_21_082: [ If the HTTPAPI_ExecuteRequest retries 20 seconds to receive the message without success, it shall fail and return HTTPAPI_READ_DATA_FAILED. ]*/
1111 result = HTTPAPI_READ_DATA_FAILED;
1112 }
1113 else
1114 {
1115 result = HTTPAPI_OK;
1116 }
1117 }
1118 }
1119 else
1120 {
1121 /*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
1122 result = HTTPAPI_OK;
1123 }
1124 }
1125 else
1126 {
1127 size_t size = 0;
1128 /*Codes_SRS_HTTPAPI_COMPACT_21_033: [ If the whole process succeed, the HTTPAPI_ExecuteRequest shall retur HTTPAPI_OK. ]*/
1129 result = HTTPAPI_OK;
1130 while (result == HTTPAPI_OK)
1131 {
1132 size_t chunkSize;
1133 if (readLine(http_instance, buf, sizeof(buf)) < 0) // read [length in hex]/r/n
1134 {
1135 /*Codes_SRS_HTTPAPI_COMPACT_21_032: [ If the HTTPAPI_ExecuteRequest cannot read the message with the request result, it shall return HTTPAPI_READ_DATA_FAILED. ]*/
1136 /*Codes_SRS_HTTPAPI_COMPACT_21_082: [ If the HTTPAPI_ExecuteRequest retries 20 seconds to receive the message without success, it shall fail and return HTTPAPI_READ_DATA_FAILED. ]*/
1137 result = HTTPAPI_READ_DATA_FAILED;
1138 }
1139 else if (ParseStringToHexadecimal(buf, &chunkSize) != 1) // chunkSize is length of next line (/r/n is not counted)
1140 {
1141 //Cannot match string, error
1142 /*Codes_SRS_HTTPAPI_COMPACT_21_055: [ If the HTTPAPI_ExecuteRequest cannot parser the received message, it shall return HTTPAPI_RECEIVE_RESPONSE_FAILED. ]*/
1143 result = HTTPAPI_RECEIVE_RESPONSE_FAILED;
1144 }
1145 else if (chunkSize == 0)
1146 {
1147 // 0 length means next line is just '\r\n' and end of chunks
1148 if (readChunk(http_instance, (char*)buf, (size_t)2) < 0
1149 || buf[0] != '\r' || buf[1] != '\n') // skip /r/n
1150 {
1151 (void)BUFFER_unbuild(responseContent);
1152
1153 result = HTTPAPI_READ_DATA_FAILED;
1154 }
1155 break;
1156 }
1157 else
1158 {
1159 if (responseContent != NULL)
1160 {
1161 if (BUFFER_enlarge(responseContent, chunkSize) != 0)
1162 {
1163 (void)BUFFER_unbuild(responseContent);
1164
1165 /*Codes_SRS_HTTPAPI_COMPACT_21_052: [ If any memory allocation get fail, the HTTPAPI_ExecuteRequest shall return HTTPAPI_ALLOC_FAILED. ]*/
1166 result = HTTPAPI_ALLOC_FAILED;
1167 }
1168 else if (BUFFER_content(responseContent, &receivedContent) != 0)
1169 {
1170 (void)BUFFER_unbuild(responseContent);
1171
1172 /*Codes_SRS_HTTPAPI_COMPACT_21_052: [ If any memory allocation get fail, the HTTPAPI_ExecuteRequest shall return HTTPAPI_ALLOC_FAILED. ]*/
1173 result = HTTPAPI_ALLOC_FAILED;
1174 }
1175 else if (readChunk(http_instance, (char*)receivedContent + size, chunkSize) < 0)
1176 {
1177 result = HTTPAPI_READ_DATA_FAILED;
1178 }
1179 }
1180 else
1181 {
1182 /*Codes_SRS_HTTPAPI_COMPACT_21_051: [ If the responseContent is NULL, the HTTPAPI_ExecuteRequest shall ignore any content in the response. ]*/
1183 if (skipN(http_instance, chunkSize) < 0)
1184 {
1185 /*Codes_SRS_HTTPAPI_COMPACT_21_082: [ If the HTTPAPI_ExecuteRequest retries 20 seconds to receive the message without success, it shall fail and return HTTPAPI_READ_DATA_FAILED. ]*/
1186 result = HTTPAPI_READ_DATA_FAILED;
1187 }
1188 }
1189
1190 if (result == HTTPAPI_OK)
1191 {
1192 if (readChunk(http_instance, (char*)buf, (size_t)2) < 0
1193 || buf[0] != '\r' || buf[1] != '\n') // skip /r/n
1194 {
1195 result = HTTPAPI_READ_DATA_FAILED;
1196 }
1197 size += chunkSize;
1198 }
1199 }
1200 }
1201
1202 }
1203 return result;
1204}
1205
1206
1207/*Codes_SRS_HTTPAPI_COMPACT_21_037: [ If the request type is unknown, the HTTPAPI_ExecuteRequest shall return HTTPAPI_INVALID_ARG. ]*/
1208static bool validRequestType(HTTPAPI_REQUEST_TYPE requestType)
1209{
1210 bool result;
1211
1212 if ((requestType == HTTPAPI_REQUEST_GET) ||
1213 (requestType == HTTPAPI_REQUEST_POST) ||
1214 (requestType == HTTPAPI_REQUEST_PUT) ||
1215 (requestType == HTTPAPI_REQUEST_DELETE) ||
1216 (requestType == HTTPAPI_REQUEST_PATCH) ||
1217 (requestType == HTTPAPI_REQUEST_HEAD))
1218 {
1219 result = true;
1220 }
1221 else
1222 {
1223 result = false;
1224 }
1225
1226 return result;
1227}
1228
1229/*Codes_SRS_HTTPAPI_COMPACT_21_021: [ The HTTPAPI_ExecuteRequest shall execute the http communtication with the provided host, sending a request and reciving the response. ]*/
1230/*Codes_SRS_HTTPAPI_COMPACT_21_050: [ If there is a content in the response, the HTTPAPI_ExecuteRequest shall copy it in the responseContent buffer. ]*/
1231//Note: This function assumes that "Host:" and "Content-Length:" headers are setup
1232// by the caller of HTTPAPI_ExecuteRequest() (which is true for httptransport.c).
1233HTTPAPI_RESULT HTTPAPI_ExecuteRequest(HTTP_HANDLE handle, HTTPAPI_REQUEST_TYPE requestType, const char* relativePath,
1234 HTTP_HEADERS_HANDLE httpHeadersHandle, const unsigned char* content,
1235 size_t contentLength, unsigned int* statusCode,
1236 HTTP_HEADERS_HANDLE responseHeadersHandle, BUFFER_HANDLE responseContent)
1237{
1238 HTTPAPI_RESULT result = HTTPAPI_ERROR;
1239 size_t headersCount;
1240 size_t bodyLength = 0;
1241 bool chunked = false;
1242 HTTP_HANDLE_DATA* http_instance = (HTTP_HANDLE_DATA*)handle;
1243
1244 /*Codes_SRS_HTTPAPI_COMPACT_21_034: [ If there is no previous connection, the HTTPAPI_ExecuteRequest shall return HTTPAPI_INVALID_ARG. ]*/
1245 /*Codes_SRS_HTTPAPI_COMPACT_21_037: [ If the request type is unknown, the HTTPAPI_ExecuteRequest shall return HTTPAPI_INVALID_ARG. ]*/
1246 /*Codes_SRS_HTTPAPI_COMPACT_21_039: [ If the relativePath is NULL or invalid, the HTTPAPI_ExecuteRequest shall return HTTPAPI_INVALID_ARG. ]*/
1247 /*Codes_SRS_HTTPAPI_COMPACT_21_041: [ If the httpHeadersHandle is NULL or invalid, the HTTPAPI_ExecuteRequest shall return HTTPAPI_INVALID_ARG. ]*/
1248 /*Codes_SRS_HTTPAPI_COMPACT_21_053: [ The HTTPAPI_ExecuteRequest shall produce a set of http header to send to the host. ]*/
1249 /*Codes_SRS_HTTPAPI_COMPACT_21_040: [ The request shall contain the http header provided in httpHeadersHandle parameter. ]*/
1250 /*Codes_SRS_HTTPAPI_COMPACT_21_054: [ If Http header maker cannot provide the number of headers, the HTTPAPI_ExecuteRequest shall return HTTPAPI_INVALID_ARG. ]*/
1251 if (http_instance == NULL ||
1252 relativePath == NULL ||
1253 httpHeadersHandle == NULL ||
1254 !validRequestType(requestType) ||
1255 HTTPHeaders_GetHeaderCount(httpHeadersHandle, &headersCount) != HTTP_HEADERS_OK)
1256 {
1257 result = HTTPAPI_INVALID_ARG;
1258 LogError("(result = %" PRI_MU_ENUM ")", MU_ENUM_VALUE(HTTPAPI_RESULT, result));
1259 }
1260 /*Codes_SRS_HTTPAPI_COMPACT_21_024: [ The HTTPAPI_ExecuteRequest shall open the transport connection with the host to send the request. ]*/
1261 else if ((result = OpenXIOConnection(http_instance)) != HTTPAPI_OK)
1262 {
1263 LogError("Open HTTP connection failed (result = %" PRI_MU_ENUM ")", MU_ENUM_VALUE(HTTPAPI_RESULT, result));
1264 }
1265 /*Codes_SRS_HTTPAPI_COMPACT_21_026: [ If the open process succeed, the HTTPAPI_ExecuteRequest shall send the request message to the host. ]*/
1266 else if ((result = SendHeadsToXIO(http_instance, requestType, relativePath, httpHeadersHandle, headersCount)) != HTTPAPI_OK)
1267 {
1268 LogError("Send heads to HTTP failed (result = %" PRI_MU_ENUM ")", MU_ENUM_VALUE(HTTPAPI_RESULT, result));
1269 }
1270 /*Codes_SRS_HTTPAPI_COMPACT_21_042: [ The request can contain the a content message, provided in content parameter. ]*/
1271 else if ((result = SendContentToXIO(http_instance, content, contentLength)) != HTTPAPI_OK)
1272 {
1273 LogError("Send content to HTTP failed (result = %" PRI_MU_ENUM ")", MU_ENUM_VALUE(HTTPAPI_RESULT, result));
1274 }
1275 /*Codes_SRS_HTTPAPI_COMPACT_21_030: [ At the end of the transmission, the HTTPAPI_ExecuteRequest shall receive the response from the host. ]*/
1276 /*Codes_SRS_HTTPAPI_COMPACT_21_073: [ The message received by the HTTPAPI_ExecuteRequest shall starts with a valid header. ]*/
1277 else if ((result = ReceiveHeaderFromXIO(http_instance, statusCode)) != HTTPAPI_OK)
1278 {
1279 LogError("Receive header from HTTP failed (result = %" PRI_MU_ENUM ")", MU_ENUM_VALUE(HTTPAPI_RESULT, result));
1280 }
1281 /*Codes_SRS_HTTPAPI_COMPACT_21_074: [ After the header, the message received by the HTTPAPI_ExecuteRequest can contain addition information about the content. ]*/
1282 else if ((result = ReceiveContentInfoFromXIO(http_instance, responseHeadersHandle, &bodyLength, &chunked)) != HTTPAPI_OK)
1283 {
1284 LogError("Receive content information from HTTP failed (result = %" PRI_MU_ENUM ")", MU_ENUM_VALUE(HTTPAPI_RESULT, result));
1285 }
1286 /*Codes_SRS_HTTPAPI_COMPACT_42_084: [ The message received by the HTTPAPI_ExecuteRequest should not contain http body. ]*/
1287 else if (requestType != HTTPAPI_REQUEST_HEAD)
1288 {
1289 /*Codes_SRS_HTTPAPI_COMPACT_21_075: [ The message received by the HTTPAPI_ExecuteRequest can contain a body with the message content. ]*/
1290 if ((result = ReadHTTPResponseBodyFromXIO(http_instance, bodyLength, chunked, responseContent)) != HTTPAPI_OK)
1291 {
1292 LogError("Read HTTP response body from HTTP failed (result = %" PRI_MU_ENUM ")", MU_ENUM_VALUE(HTTPAPI_RESULT, result));
1293 }
1294 }
1295
1296 conn_receive_discard_buffer(http_instance);
1297
1298 return result;
1299}
1300
1301/*Codes_SRS_HTTPAPI_COMPACT_21_056: [ The HTTPAPI_SetOption shall change the HTTP options. ]*/
1302/*Codes_SRS_HTTPAPI_COMPACT_21_057: [ The HTTPAPI_SetOption shall receive a handle that identiry the HTTP connection. ]*/
1303/*Codes_SRS_HTTPAPI_COMPACT_21_058: [ The HTTPAPI_SetOption shall receive the option as a pair optionName/value. ]*/
1304HTTPAPI_RESULT HTTPAPI_SetOption(HTTP_HANDLE handle, const char* optionName, const void* value)
1305{
1306 HTTPAPI_RESULT result;
1307 HTTP_HANDLE_DATA* http_instance = (HTTP_HANDLE_DATA*)handle;
1308
1309 if (
1310 (http_instance == NULL) ||
1311 (optionName == NULL) ||
1312 (value == NULL)
1313 )
1314 {
1315 /*Codes_SRS_HTTPAPI_COMPACT_21_059: [ If the handle is NULL, the HTTPAPI_SetOption shall return HTTPAPI_INVALID_ARG. ]*/
1316 /*Codes_SRS_HTTPAPI_COMPACT_21_060: [ If the optionName is NULL, the HTTPAPI_SetOption shall return HTTPAPI_INVALID_ARG. ]*/
1317 /*Codes_SRS_HTTPAPI_COMPACT_21_061: [ If the value is NULL, the HTTPAPI_SetOption shall return HTTPAPI_INVALID_ARG. ]*/
1318 result = HTTPAPI_INVALID_ARG;
1319 }
1320 else if (strcmp(OPTION_TRUSTED_CERT, optionName) == 0)
1321 {
1322#ifdef DO_NOT_COPY_TRUSTED_CERTS_STRING
1323 result = HTTPAPI_OK;
1324 http_instance->certificate = (char*)value;
1325#else
1326 int len;
1327
1328 if (http_instance->certificate)
1329 {
1330 free(http_instance->certificate);
1331 }
1332
1333 len = (int)strlen((char*)value);
1334 http_instance->certificate = (char*)malloc((len + 1) * sizeof(char));
1335 if (http_instance->certificate == NULL)
1336 {
1337 /*Codes_SRS_HTTPAPI_COMPACT_21_062: [ If any memory allocation get fail, the HTTPAPI_SetOption shall return HTTPAPI_ALLOC_FAILED. ]*/
1338 result = HTTPAPI_ALLOC_FAILED;
1339 LogInfo("unable to allocate memory for the certificate in HTTPAPI_SetOption");
1340 }
1341 else
1342 {
1343 /*Codes_SRS_HTTPAPI_COMPACT_21_064: [ If the HTTPAPI_SetOption get success setting the option, it shall return HTTPAPI_OK. ]*/
1344 (void)strcpy(http_instance->certificate, (const char*)value);
1345 result = HTTPAPI_OK;
1346 }
1347#endif // DO_NOT_COPY_TRUSTED_CERTS_STRING
1348 }
1349 else if (strcmp(SU_OPTION_X509_CERT, optionName) == 0)
1350 {
1351 int len;
1352 if (http_instance->x509ClientCertificate)
1353 {
1354 free(http_instance->x509ClientCertificate);
1355 }
1356
1357 len = (int)strlen((char*)value);
1358 http_instance->x509ClientCertificate = (char*)malloc((len + 1) * sizeof(char));
1359 if (http_instance->x509ClientCertificate == NULL)
1360 {
1361 /*Codes_SRS_HTTPAPI_COMPACT_21_062: [ If any memory allocation get fail, the HTTPAPI_SetOption shall return HTTPAPI_ALLOC_FAILED. ]*/
1362 result = HTTPAPI_ALLOC_FAILED;
1363 LogInfo("unable to allocate memory for the client certificate in HTTPAPI_SetOption");
1364 }
1365 else
1366 {
1367 /*Codes_SRS_HTTPAPI_COMPACT_21_064: [ If the HTTPAPI_SetOption get success setting the option, it shall return HTTPAPI_OK. ]*/
1368 (void)strcpy(http_instance->x509ClientCertificate, (const char*)value);
1369 result = HTTPAPI_OK;
1370 }
1371 }
1372 else if (strcmp(SU_OPTION_X509_PRIVATE_KEY, optionName) == 0)
1373 {
1374 int len;
1375 if (http_instance->x509ClientPrivateKey)
1376 {
1377 free(http_instance->x509ClientPrivateKey);
1378 }
1379
1380 len = (int)strlen((char*)value);
1381 http_instance->x509ClientPrivateKey = (char*)malloc((len + 1) * sizeof(char));
1382 if (http_instance->x509ClientPrivateKey == NULL)
1383 {
1384 /*Codes_SRS_HTTPAPI_COMPACT_21_062: [ If any memory allocation get fail, the HTTPAPI_SetOption shall return HTTPAPI_ALLOC_FAILED. ]*/
1385 result = HTTPAPI_ALLOC_FAILED;
1386 LogInfo("unable to allocate memory for the client private key in HTTPAPI_SetOption");
1387 }
1388 else
1389 {
1390 /*Codes_SRS_HTTPAPI_COMPACT_21_064: [ If the HTTPAPI_SetOption get success setting the option, it shall return HTTPAPI_OK. ]*/
1391 (void)strcpy(http_instance->x509ClientPrivateKey, (const char*)value);
1392 result = HTTPAPI_OK;
1393 }
1394 }
1395 else if (strcmp(OPTION_HTTP_PROXY, optionName) == 0)
1396 {
1397 HTTP_PROXY_OPTIONS* proxy_data = (HTTP_PROXY_OPTIONS*)value;
1398 if (proxy_data->host_address == NULL || proxy_data->port <= 0)
1399 {
1400 LogError("invalid proxy_data values ( host_address = %p, port = %d)", proxy_data->host_address, proxy_data->port);
1401 result = HTTPAPI_ERROR;
1402 }
1403 else
1404 {
1405 if(http_instance->proxy_host != NULL)
1406 {
1407 free((void*)http_instance->proxy_host);
1408 http_instance->proxy_host = NULL;
1409 }
1410 if(mallocAndStrcpy_s((char**)&(http_instance->proxy_host), (const char*)proxy_data->host_address) != 0)
1411 {
1412 LogError("failure allocate proxy host");
1413 result = HTTPAPI_ERROR;
1414 }
1415 else
1416 {
1417 http_instance->proxy_port = proxy_data->port;
1418
1419 if (proxy_data->username != NULL && proxy_data->password != NULL)
1420 {
1421 if(http_instance->proxy_username != NULL)
1422 {
1423 free((void*)http_instance->proxy_username);
1424 http_instance->proxy_username = NULL;
1425 }
1426 if(mallocAndStrcpy_s((char**)&(http_instance->proxy_username), (const char*)proxy_data->username) != 0)
1427 {
1428 LogError("failure allocate proxy username");
1429 free((void*)http_instance->proxy_host);
1430 http_instance->proxy_host = NULL;
1431 result = HTTPAPI_ERROR;
1432 }
1433 else
1434 {
1435 if(http_instance->proxy_password != NULL)
1436 {
1437 free((void*)http_instance->proxy_password);
1438 http_instance->proxy_password = NULL;
1439 }
1440 if(mallocAndStrcpy_s((char**)&(http_instance->proxy_password), (const char*)proxy_data->password) != 0)
1441 {
1442 LogError("failure allocate proxy password");
1443 free((void*)http_instance->proxy_host);
1444 http_instance->proxy_host = NULL;
1445 free((void*)http_instance->proxy_username);
1446 http_instance->proxy_username = NULL;
1447 result = HTTPAPI_ERROR;
1448 }
1449 else
1450 {
1451 result = HTTPAPI_OK;
1452 }
1453 }
1454 }
1455 else
1456 {
1457 result = HTTPAPI_OK;
1458 }
1459 }
1460 }
1461 }
1462 else
1463 {
1464 /*Codes_SRS_HTTPAPI_COMPACT_21_063: [ If the HTTP do not support the optionName, the HTTPAPI_SetOption shall return HTTPAPI_INVALID_ARG. ]*/
1465 result = HTTPAPI_INVALID_ARG;
1466 LogInfo("unknown option %s", optionName);
1467 }
1468 return result;
1469}
1470
1471/*Codes_SRS_HTTPAPI_COMPACT_21_065: [ The HTTPAPI_CloneOption shall provide the means to clone the HTTP option. ]*/
1472/*Codes_SRS_HTTPAPI_COMPACT_21_066: [ The HTTPAPI_CloneOption shall return a clone of the value identified by the optionName. ]*/
1473HTTPAPI_RESULT HTTPAPI_CloneOption(const char* optionName, const void* value, const void** savedValue)
1474{
1475 HTTPAPI_RESULT result;
1476 size_t certLen;
1477 char* tempCert;
1478
1479 if (
1480 (optionName == NULL) ||
1481 (value == NULL) ||
1482 (savedValue == NULL)
1483 )
1484 {
1485 /*Codes_SRS_HTTPAPI_COMPACT_21_067: [ If the optionName is NULL, the HTTPAPI_CloneOption shall return HTTPAPI_INVALID_ARG. ]*/
1486 /*Codes_SRS_HTTPAPI_COMPACT_21_068: [ If the value is NULL, the HTTPAPI_CloneOption shall return HTTPAPI_INVALID_ARG. ]*/
1487 /*Codes_SRS_HTTPAPI_COMPACT_21_069: [ If the savedValue is NULL, the HTTPAPI_CloneOption shall return HTTPAPI_INVALID_ARG. ]*/
1488 result = HTTPAPI_INVALID_ARG;
1489 }
1490 else if (strcmp(OPTION_TRUSTED_CERT, optionName) == 0)
1491 {
1492#ifdef DO_NOT_COPY_TRUSTED_CERTS_STRING
1493 *savedValue = (const void*)value;
1494 result = HTTPAPI_OK;
1495#else
1496 certLen = strlen((const char*)value);
1497 tempCert = (char*)malloc((certLen + 1) * sizeof(char));
1498 if (tempCert == NULL)
1499 {
1500 /*Codes_SRS_HTTPAPI_COMPACT_21_070: [ If any memory allocation get fail, the HTTPAPI_CloneOption shall return HTTPAPI_ALLOC_FAILED. ]*/
1501 result = HTTPAPI_ALLOC_FAILED;
1502 }
1503 else
1504 {
1505 /*Codes_SRS_HTTPAPI_COMPACT_21_072: [ If the HTTPAPI_CloneOption get success setting the option, it shall return HTTPAPI_OK. ]*/
1506 (void)strcpy(tempCert, (const char*)value);
1507 *savedValue = tempCert;
1508 result = HTTPAPI_OK;
1509 }
1510#endif // DO_NOT_COPY_TRUSTED_CERTS_STRING
1511 }
1512 else if (strcmp(SU_OPTION_X509_CERT, optionName) == 0)
1513 {
1514 certLen = strlen((const char*)value);
1515 tempCert = (char*)malloc((certLen + 1) * sizeof(char));
1516 if (tempCert == NULL)
1517 {
1518 /*Codes_SRS_HTTPAPI_COMPACT_21_070: [ If any memory allocation get fail, the HTTPAPI_CloneOption shall return HTTPAPI_ALLOC_FAILED. ]*/
1519 result = HTTPAPI_ALLOC_FAILED;
1520 }
1521 else
1522 {
1523 /*Codes_SRS_HTTPAPI_COMPACT_21_072: [ If the HTTPAPI_CloneOption get success setting the option, it shall return HTTPAPI_OK. ]*/
1524 (void)strcpy(tempCert, (const char*)value);
1525 *savedValue = tempCert;
1526 result = HTTPAPI_OK;
1527 }
1528 }
1529 else if (strcmp(SU_OPTION_X509_PRIVATE_KEY, optionName) == 0)
1530 {
1531 certLen = strlen((const char*)value);
1532 tempCert = (char*)malloc((certLen + 1) * sizeof(char));
1533 if (tempCert == NULL)
1534 {
1535 /*Codes_SRS_HTTPAPI_COMPACT_21_070: [ If any memory allocation get fail, the HTTPAPI_CloneOption shall return HTTPAPI_ALLOC_FAILED. ]*/
1536 result = HTTPAPI_ALLOC_FAILED;
1537 }
1538 else
1539 {
1540 /*Codes_SRS_HTTPAPI_COMPACT_21_072: [ If the HTTPAPI_CloneOption get success setting the option, it shall return HTTPAPI_OK. ]*/
1541 (void)strcpy(tempCert, (const char*)value);
1542 *savedValue = tempCert;
1543 result = HTTPAPI_OK;
1544 }
1545 }
1546 else if (strcmp(OPTION_HTTP_PROXY, optionName) == 0)
1547 {
1548 HTTP_PROXY_OPTIONS* proxy_data = (HTTP_PROXY_OPTIONS*)value;
1549
1550 HTTP_PROXY_OPTIONS* new_proxy_info = malloc(sizeof(HTTP_PROXY_OPTIONS));
1551 if (new_proxy_info == NULL)
1552 {
1553 LogError("unable to allocate proxy option information");
1554 result = HTTPAPI_ERROR;
1555 }
1556 else
1557 {
1558 new_proxy_info->host_address = proxy_data->host_address;
1559 new_proxy_info->port = proxy_data->port;
1560 new_proxy_info->password = proxy_data->password;
1561 new_proxy_info->username = proxy_data->username;
1562 *savedValue = new_proxy_info;
1563 result = HTTPAPI_OK;
1564 }
1565 }
1566 else
1567 {
1568 /*Codes_SRS_HTTPAPI_COMPACT_21_071: [ If the HTTP do not support the optionName, the HTTPAPI_CloneOption shall return HTTPAPI_INVALID_ARG. ]*/
1569 result = HTTPAPI_INVALID_ARG;
1570 LogInfo("unknown option %s", optionName);
1571 }
1572 return result;
1573}
Note: See TracBrowser for help on using the repository browser.