source: azure_iot_hub/trunk/azure_iohub/c-utility/adapters/httpapi_compact.c@ 388

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

Azure IoT Hub Device C SDK を使ったサンプルの追加

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