Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
c-utility/src/http_proxy_io.c@0:f7f1f0d76dd6, 2018-08-23 (annotated)
- Committer:
- XinZhangMS
- Date:
- Thu Aug 23 06:52:14 2018 +0000
- Revision:
- 0:f7f1f0d76dd6
azure-c-sdk for mbed os supporting NUCLEO_F767ZI
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
XinZhangMS | 0:f7f1f0d76dd6 | 1 | // Copyright (c) Microsoft. All rights reserved. |
XinZhangMS | 0:f7f1f0d76dd6 | 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. |
XinZhangMS | 0:f7f1f0d76dd6 | 3 | |
XinZhangMS | 0:f7f1f0d76dd6 | 4 | #include <stdlib.h> |
XinZhangMS | 0:f7f1f0d76dd6 | 5 | #include <stdio.h> |
XinZhangMS | 0:f7f1f0d76dd6 | 6 | #include <stdbool.h> |
XinZhangMS | 0:f7f1f0d76dd6 | 7 | #include <stdint.h> |
XinZhangMS | 0:f7f1f0d76dd6 | 8 | #include <limits.h> |
XinZhangMS | 0:f7f1f0d76dd6 | 9 | #include <stddef.h> |
XinZhangMS | 0:f7f1f0d76dd6 | 10 | #include "azure_c_shared_utility/gballoc.h" |
XinZhangMS | 0:f7f1f0d76dd6 | 11 | #include "azure_c_shared_utility/xio.h" |
XinZhangMS | 0:f7f1f0d76dd6 | 12 | #include "azure_c_shared_utility/socketio.h" |
XinZhangMS | 0:f7f1f0d76dd6 | 13 | #include "azure_c_shared_utility/crt_abstractions.h" |
XinZhangMS | 0:f7f1f0d76dd6 | 14 | #include "azure_c_shared_utility/http_proxy_io.h" |
XinZhangMS | 0:f7f1f0d76dd6 | 15 | #include "azure_c_shared_utility/base64.h" |
XinZhangMS | 0:f7f1f0d76dd6 | 16 | |
XinZhangMS | 0:f7f1f0d76dd6 | 17 | typedef enum HTTP_PROXY_IO_STATE_TAG |
XinZhangMS | 0:f7f1f0d76dd6 | 18 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 19 | HTTP_PROXY_IO_STATE_CLOSED, |
XinZhangMS | 0:f7f1f0d76dd6 | 20 | HTTP_PROXY_IO_STATE_OPENING_UNDERLYING_IO, |
XinZhangMS | 0:f7f1f0d76dd6 | 21 | HTTP_PROXY_IO_STATE_WAITING_FOR_CONNECT_RESPONSE, |
XinZhangMS | 0:f7f1f0d76dd6 | 22 | HTTP_PROXY_IO_STATE_OPEN, |
XinZhangMS | 0:f7f1f0d76dd6 | 23 | HTTP_PROXY_IO_STATE_CLOSING, |
XinZhangMS | 0:f7f1f0d76dd6 | 24 | HTTP_PROXY_IO_STATE_ERROR |
XinZhangMS | 0:f7f1f0d76dd6 | 25 | } HTTP_PROXY_IO_STATE; |
XinZhangMS | 0:f7f1f0d76dd6 | 26 | |
XinZhangMS | 0:f7f1f0d76dd6 | 27 | typedef struct HTTP_PROXY_IO_INSTANCE_TAG |
XinZhangMS | 0:f7f1f0d76dd6 | 28 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 29 | HTTP_PROXY_IO_STATE http_proxy_io_state; |
XinZhangMS | 0:f7f1f0d76dd6 | 30 | ON_BYTES_RECEIVED on_bytes_received; |
XinZhangMS | 0:f7f1f0d76dd6 | 31 | void* on_bytes_received_context; |
XinZhangMS | 0:f7f1f0d76dd6 | 32 | ON_IO_ERROR on_io_error; |
XinZhangMS | 0:f7f1f0d76dd6 | 33 | void* on_io_error_context; |
XinZhangMS | 0:f7f1f0d76dd6 | 34 | ON_IO_OPEN_COMPLETE on_io_open_complete; |
XinZhangMS | 0:f7f1f0d76dd6 | 35 | void* on_io_open_complete_context; |
XinZhangMS | 0:f7f1f0d76dd6 | 36 | ON_IO_CLOSE_COMPLETE on_io_close_complete; |
XinZhangMS | 0:f7f1f0d76dd6 | 37 | void* on_io_close_complete_context; |
XinZhangMS | 0:f7f1f0d76dd6 | 38 | char* hostname; |
XinZhangMS | 0:f7f1f0d76dd6 | 39 | int port; |
XinZhangMS | 0:f7f1f0d76dd6 | 40 | char* proxy_hostname; |
XinZhangMS | 0:f7f1f0d76dd6 | 41 | int proxy_port; |
XinZhangMS | 0:f7f1f0d76dd6 | 42 | char* username; |
XinZhangMS | 0:f7f1f0d76dd6 | 43 | char* password; |
XinZhangMS | 0:f7f1f0d76dd6 | 44 | XIO_HANDLE underlying_io; |
XinZhangMS | 0:f7f1f0d76dd6 | 45 | unsigned char* receive_buffer; |
XinZhangMS | 0:f7f1f0d76dd6 | 46 | size_t receive_buffer_size; |
XinZhangMS | 0:f7f1f0d76dd6 | 47 | } HTTP_PROXY_IO_INSTANCE; |
XinZhangMS | 0:f7f1f0d76dd6 | 48 | |
XinZhangMS | 0:f7f1f0d76dd6 | 49 | static CONCRETE_IO_HANDLE http_proxy_io_create(void* io_create_parameters) |
XinZhangMS | 0:f7f1f0d76dd6 | 50 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 51 | HTTP_PROXY_IO_INSTANCE* result; |
XinZhangMS | 0:f7f1f0d76dd6 | 52 | |
XinZhangMS | 0:f7f1f0d76dd6 | 53 | if (io_create_parameters == NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 54 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 55 | /* Codes_SRS_HTTP_PROXY_IO_01_002: [ If `io_create_parameters` is NULL, `http_proxy_io_create` shall fail and return NULL. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 56 | result = NULL; |
XinZhangMS | 0:f7f1f0d76dd6 | 57 | LogError("NULL io_create_parameters."); |
XinZhangMS | 0:f7f1f0d76dd6 | 58 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 59 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 60 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 61 | /* Codes_SRS_HTTP_PROXY_IO_01_003: [ `io_create_parameters` shall be used as an `HTTP_PROXY_IO_CONFIG*`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 62 | HTTP_PROXY_IO_CONFIG* http_proxy_io_config = (HTTP_PROXY_IO_CONFIG*)io_create_parameters; |
XinZhangMS | 0:f7f1f0d76dd6 | 63 | if ((http_proxy_io_config->hostname == NULL) || |
XinZhangMS | 0:f7f1f0d76dd6 | 64 | (http_proxy_io_config->proxy_hostname == NULL)) |
XinZhangMS | 0:f7f1f0d76dd6 | 65 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 66 | /* Codes_SRS_HTTP_PROXY_IO_01_004: [ If the `hostname` or `proxy_hostname` member is NULL, then `http_proxy_io_create` shall fail and return NULL. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 67 | result = NULL; |
XinZhangMS | 0:f7f1f0d76dd6 | 68 | LogError("Bad arguments: hostname = %p, proxy_hostname = %p", |
XinZhangMS | 0:f7f1f0d76dd6 | 69 | http_proxy_io_config->hostname, http_proxy_io_config->proxy_hostname); |
XinZhangMS | 0:f7f1f0d76dd6 | 70 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 71 | /* Codes_SRS_HTTP_PROXY_IO_01_095: [ If one of the fields `username` and `password` is non-NULL, then the other has to be also non-NULL, otherwise `http_proxy_io_create` shall fail and return NULL. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 72 | else if (((http_proxy_io_config->username == NULL) && (http_proxy_io_config->password != NULL)) || |
XinZhangMS | 0:f7f1f0d76dd6 | 73 | ((http_proxy_io_config->username != NULL) && (http_proxy_io_config->password == NULL))) |
XinZhangMS | 0:f7f1f0d76dd6 | 74 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 75 | result = NULL; |
XinZhangMS | 0:f7f1f0d76dd6 | 76 | LogError("Bad arguments: username = %p, password = %p", |
XinZhangMS | 0:f7f1f0d76dd6 | 77 | http_proxy_io_config->username, http_proxy_io_config->password); |
XinZhangMS | 0:f7f1f0d76dd6 | 78 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 79 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 80 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 81 | /* Codes_SRS_HTTP_PROXY_IO_01_001: [ `http_proxy_io_create` shall create a new instance of the HTTP proxy IO. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 82 | result = (HTTP_PROXY_IO_INSTANCE*)malloc(sizeof(HTTP_PROXY_IO_INSTANCE)); |
XinZhangMS | 0:f7f1f0d76dd6 | 83 | if (result == NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 84 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 85 | /* Codes_SRS_HTTP_PROXY_IO_01_051: [ If allocating memory for the new instance fails, `http_proxy_io_create` shall fail and return NULL. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 86 | LogError("Failed allocating HTTP proxy IO instance."); |
XinZhangMS | 0:f7f1f0d76dd6 | 87 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 88 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 89 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 90 | /* Codes_SRS_HTTP_PROXY_IO_01_005: [ `http_proxy_io_create` shall copy the `hostname`, `port`, `username` and `password` values for later use when the actual CONNECT is performed. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 91 | /* Codes_SRS_HTTP_PROXY_IO_01_006: [ `hostname` and `proxy_hostname`, `username` and `password` shall be copied by calling `mallocAndStrcpy_s`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 92 | if (mallocAndStrcpy_s(&result->hostname, http_proxy_io_config->hostname) != 0) |
XinZhangMS | 0:f7f1f0d76dd6 | 93 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 94 | /* Codes_SRS_HTTP_PROXY_IO_01_007: [ If `mallocAndStrcpy_s` fails then `http_proxy_io_create` shall fail and return NULL. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 95 | LogError("Failed to copy the hostname."); |
XinZhangMS | 0:f7f1f0d76dd6 | 96 | /* Codes_SRS_HTTP_PROXY_IO_01_008: [ When `http_proxy_io_create` fails, all allocated resources up to that point shall be freed. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 97 | free(result); |
XinZhangMS | 0:f7f1f0d76dd6 | 98 | result = NULL; |
XinZhangMS | 0:f7f1f0d76dd6 | 99 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 100 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 101 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 102 | /* Codes_SRS_HTTP_PROXY_IO_01_006: [ `hostname` and `proxy_hostname`, `username` and `password` shall be copied by calling `mallocAndStrcpy_s`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 103 | if (mallocAndStrcpy_s(&result->proxy_hostname, http_proxy_io_config->proxy_hostname) != 0) |
XinZhangMS | 0:f7f1f0d76dd6 | 104 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 105 | /* Codes_SRS_HTTP_PROXY_IO_01_007: [ If `mallocAndStrcpy_s` fails then `http_proxy_io_create` shall fail and return NULL. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 106 | LogError("Failed to copy the proxy_hostname."); |
XinZhangMS | 0:f7f1f0d76dd6 | 107 | /* Codes_SRS_HTTP_PROXY_IO_01_008: [ When `http_proxy_io_create` fails, all allocated resources up to that point shall be freed. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 108 | free(result->hostname); |
XinZhangMS | 0:f7f1f0d76dd6 | 109 | free(result); |
XinZhangMS | 0:f7f1f0d76dd6 | 110 | result = NULL; |
XinZhangMS | 0:f7f1f0d76dd6 | 111 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 112 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 113 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 114 | result->username = NULL; |
XinZhangMS | 0:f7f1f0d76dd6 | 115 | result->password = NULL; |
XinZhangMS | 0:f7f1f0d76dd6 | 116 | |
XinZhangMS | 0:f7f1f0d76dd6 | 117 | /* Codes_SRS_HTTP_PROXY_IO_01_006: [ `hostname` and `proxy_hostname`, `username` and `password` shall be copied by calling `mallocAndStrcpy_s`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 118 | /* Codes_SRS_HTTP_PROXY_IO_01_094: [ `username` and `password` shall be optional. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 119 | if ((http_proxy_io_config->username != NULL) && (mallocAndStrcpy_s(&result->username, http_proxy_io_config->username) != 0)) |
XinZhangMS | 0:f7f1f0d76dd6 | 120 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 121 | /* Codes_SRS_HTTP_PROXY_IO_01_007: [ If `mallocAndStrcpy_s` fails then `http_proxy_io_create` shall fail and return NULL. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 122 | LogError("Failed to copy the username."); |
XinZhangMS | 0:f7f1f0d76dd6 | 123 | /* Codes_SRS_HTTP_PROXY_IO_01_008: [ When `http_proxy_io_create` fails, all allocated resources up to that point shall be freed. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 124 | free(result->proxy_hostname); |
XinZhangMS | 0:f7f1f0d76dd6 | 125 | free(result->hostname); |
XinZhangMS | 0:f7f1f0d76dd6 | 126 | free(result); |
XinZhangMS | 0:f7f1f0d76dd6 | 127 | result = NULL; |
XinZhangMS | 0:f7f1f0d76dd6 | 128 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 129 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 130 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 131 | /* Codes_SRS_HTTP_PROXY_IO_01_006: [ `hostname` and `proxy_hostname`, `username` and `password` shall be copied by calling `mallocAndStrcpy_s`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 132 | /* Codes_SRS_HTTP_PROXY_IO_01_094: [ `username` and `password` shall be optional. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 133 | if ((http_proxy_io_config->password != NULL) && (mallocAndStrcpy_s(&result->password, http_proxy_io_config->password) != 0)) |
XinZhangMS | 0:f7f1f0d76dd6 | 134 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 135 | /* Codes_SRS_HTTP_PROXY_IO_01_007: [ If `mallocAndStrcpy_s` fails then `http_proxy_io_create` shall fail and return NULL. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 136 | LogError("Failed to copy the passowrd."); |
XinZhangMS | 0:f7f1f0d76dd6 | 137 | /* Codes_SRS_HTTP_PROXY_IO_01_008: [ When `http_proxy_io_create` fails, all allocated resources up to that point shall be freed. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 138 | free(result->username); |
XinZhangMS | 0:f7f1f0d76dd6 | 139 | free(result->proxy_hostname); |
XinZhangMS | 0:f7f1f0d76dd6 | 140 | free(result->hostname); |
XinZhangMS | 0:f7f1f0d76dd6 | 141 | free(result); |
XinZhangMS | 0:f7f1f0d76dd6 | 142 | result = NULL; |
XinZhangMS | 0:f7f1f0d76dd6 | 143 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 144 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 145 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 146 | /* Codes_SRS_HTTP_PROXY_IO_01_010: [ - `io_interface_description` shall be set to the result of `socketio_get_interface_description`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 147 | const IO_INTERFACE_DESCRIPTION* underlying_io_interface = socketio_get_interface_description(); |
XinZhangMS | 0:f7f1f0d76dd6 | 148 | if (underlying_io_interface == NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 149 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 150 | /* Codes_SRS_HTTP_PROXY_IO_01_050: [ If `socketio_get_interface_description` fails, `http_proxy_io_create` shall fail and return NULL. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 151 | LogError("Unable to get the socket IO interface description."); |
XinZhangMS | 0:f7f1f0d76dd6 | 152 | /* Codes_SRS_HTTP_PROXY_IO_01_008: [ When `http_proxy_io_create` fails, all allocated resources up to that point shall be freed. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 153 | free(result->password); |
XinZhangMS | 0:f7f1f0d76dd6 | 154 | free(result->username); |
XinZhangMS | 0:f7f1f0d76dd6 | 155 | free(result->proxy_hostname); |
XinZhangMS | 0:f7f1f0d76dd6 | 156 | free(result->hostname); |
XinZhangMS | 0:f7f1f0d76dd6 | 157 | free(result); |
XinZhangMS | 0:f7f1f0d76dd6 | 158 | result = NULL; |
XinZhangMS | 0:f7f1f0d76dd6 | 159 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 160 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 161 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 162 | SOCKETIO_CONFIG socket_io_config; |
XinZhangMS | 0:f7f1f0d76dd6 | 163 | |
XinZhangMS | 0:f7f1f0d76dd6 | 164 | /* Codes_SRS_HTTP_PROXY_IO_01_011: [ - `xio_create_parameters` shall be set to a `SOCKETIO_CONFIG*` where `hostname` is set to the `proxy_hostname` member of `io_create_parameters` and `port` is set to the `proxy_port` member of `io_create_parameters`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 165 | socket_io_config.hostname = http_proxy_io_config->proxy_hostname; |
XinZhangMS | 0:f7f1f0d76dd6 | 166 | socket_io_config.port = http_proxy_io_config->proxy_port; |
XinZhangMS | 0:f7f1f0d76dd6 | 167 | socket_io_config.accepted_socket = NULL; |
XinZhangMS | 0:f7f1f0d76dd6 | 168 | |
XinZhangMS | 0:f7f1f0d76dd6 | 169 | /* Codes_SRS_HTTP_PROXY_IO_01_009: [ `http_proxy_io_create` shall create a new socket IO by calling `xio_create` with the arguments: ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 170 | result->underlying_io = xio_create(underlying_io_interface, &socket_io_config); |
XinZhangMS | 0:f7f1f0d76dd6 | 171 | if (result->underlying_io == NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 172 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 173 | /* Codes_SRS_HTTP_PROXY_IO_01_012: [ If `xio_create` fails, `http_proxy_io_create` shall fail and return NULL. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 174 | LogError("Unable to create the underlying IO."); |
XinZhangMS | 0:f7f1f0d76dd6 | 175 | /* Codes_SRS_HTTP_PROXY_IO_01_008: [ When `http_proxy_io_create` fails, all allocated resources up to that point shall be freed. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 176 | free(result->password); |
XinZhangMS | 0:f7f1f0d76dd6 | 177 | free(result->username); |
XinZhangMS | 0:f7f1f0d76dd6 | 178 | free(result->proxy_hostname); |
XinZhangMS | 0:f7f1f0d76dd6 | 179 | free(result->hostname); |
XinZhangMS | 0:f7f1f0d76dd6 | 180 | free(result); |
XinZhangMS | 0:f7f1f0d76dd6 | 181 | result = NULL; |
XinZhangMS | 0:f7f1f0d76dd6 | 182 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 183 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 184 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 185 | result->port = http_proxy_io_config->port; |
XinZhangMS | 0:f7f1f0d76dd6 | 186 | result->proxy_port = http_proxy_io_config->proxy_port; |
XinZhangMS | 0:f7f1f0d76dd6 | 187 | result->receive_buffer = NULL; |
XinZhangMS | 0:f7f1f0d76dd6 | 188 | result->receive_buffer_size = 0; |
XinZhangMS | 0:f7f1f0d76dd6 | 189 | result->http_proxy_io_state = HTTP_PROXY_IO_STATE_CLOSED; |
XinZhangMS | 0:f7f1f0d76dd6 | 190 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 191 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 192 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 193 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 194 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 195 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 196 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 197 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 198 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 199 | |
XinZhangMS | 0:f7f1f0d76dd6 | 200 | return result; |
XinZhangMS | 0:f7f1f0d76dd6 | 201 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 202 | |
XinZhangMS | 0:f7f1f0d76dd6 | 203 | static void http_proxy_io_destroy(CONCRETE_IO_HANDLE http_proxy_io) |
XinZhangMS | 0:f7f1f0d76dd6 | 204 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 205 | if (http_proxy_io == NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 206 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 207 | /* Codes_SRS_HTTP_PROXY_IO_01_014: [ If `http_proxy_io` is NULL, `http_proxy_io_destroy` shall do nothing. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 208 | LogError("NULL http_proxy_io."); |
XinZhangMS | 0:f7f1f0d76dd6 | 209 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 210 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 211 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 212 | HTTP_PROXY_IO_INSTANCE* http_proxy_io_instance = (HTTP_PROXY_IO_INSTANCE*)http_proxy_io; |
XinZhangMS | 0:f7f1f0d76dd6 | 213 | |
XinZhangMS | 0:f7f1f0d76dd6 | 214 | /* Codes_SRS_HTTP_PROXY_IO_01_013: [ `http_proxy_io_destroy` shall free the HTTP proxy IO instance indicated by `http_proxy_io`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 215 | if (http_proxy_io_instance->receive_buffer != NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 216 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 217 | free(http_proxy_io_instance->receive_buffer); |
XinZhangMS | 0:f7f1f0d76dd6 | 218 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 219 | |
XinZhangMS | 0:f7f1f0d76dd6 | 220 | /* Codes_SRS_HTTP_PROXY_IO_01_016: [ `http_proxy_io_destroy` shall destroy the underlying IO created in `http_proxy_io_create` by calling `xio_destroy`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 221 | xio_destroy(http_proxy_io_instance->underlying_io); |
XinZhangMS | 0:f7f1f0d76dd6 | 222 | free(http_proxy_io_instance->hostname); |
XinZhangMS | 0:f7f1f0d76dd6 | 223 | free(http_proxy_io_instance->proxy_hostname); |
XinZhangMS | 0:f7f1f0d76dd6 | 224 | free(http_proxy_io_instance->username); |
XinZhangMS | 0:f7f1f0d76dd6 | 225 | free(http_proxy_io_instance->password); |
XinZhangMS | 0:f7f1f0d76dd6 | 226 | free(http_proxy_io_instance); |
XinZhangMS | 0:f7f1f0d76dd6 | 227 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 228 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 229 | |
XinZhangMS | 0:f7f1f0d76dd6 | 230 | static void indicate_open_complete_error_and_close(HTTP_PROXY_IO_INSTANCE* http_proxy_io_instance) |
XinZhangMS | 0:f7f1f0d76dd6 | 231 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 232 | http_proxy_io_instance->http_proxy_io_state = HTTP_PROXY_IO_STATE_CLOSED; |
XinZhangMS | 0:f7f1f0d76dd6 | 233 | (void)xio_close(http_proxy_io_instance->underlying_io, NULL, NULL); |
XinZhangMS | 0:f7f1f0d76dd6 | 234 | http_proxy_io_instance->on_io_open_complete(http_proxy_io_instance->on_io_open_complete_context, IO_OPEN_ERROR); |
XinZhangMS | 0:f7f1f0d76dd6 | 235 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 236 | |
XinZhangMS | 0:f7f1f0d76dd6 | 237 | // This callback usage needs to be either verified and commented or integrated into |
XinZhangMS | 0:f7f1f0d76dd6 | 238 | // the state machine. |
XinZhangMS | 0:f7f1f0d76dd6 | 239 | static void unchecked_on_send_complete(void* context, IO_SEND_RESULT send_result) |
XinZhangMS | 0:f7f1f0d76dd6 | 240 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 241 | (void)context; |
XinZhangMS | 0:f7f1f0d76dd6 | 242 | (void)send_result; |
XinZhangMS | 0:f7f1f0d76dd6 | 243 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 244 | |
XinZhangMS | 0:f7f1f0d76dd6 | 245 | static void on_underlying_io_open_complete(void* context, IO_OPEN_RESULT open_result) |
XinZhangMS | 0:f7f1f0d76dd6 | 246 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 247 | if (context == NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 248 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 249 | /* Codes_SRS_HTTP_PROXY_IO_01_081: [ `on_underlying_io_open_complete` called with NULL context shall do nothing. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 250 | LogError("NULL context in on_underlying_io_open_complete"); |
XinZhangMS | 0:f7f1f0d76dd6 | 251 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 252 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 253 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 254 | HTTP_PROXY_IO_INSTANCE* http_proxy_io_instance = (HTTP_PROXY_IO_INSTANCE*)context; |
XinZhangMS | 0:f7f1f0d76dd6 | 255 | switch (http_proxy_io_instance->http_proxy_io_state) |
XinZhangMS | 0:f7f1f0d76dd6 | 256 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 257 | default: |
XinZhangMS | 0:f7f1f0d76dd6 | 258 | LogError("on_underlying_io_open_complete called in an unexpected state."); |
XinZhangMS | 0:f7f1f0d76dd6 | 259 | break; |
XinZhangMS | 0:f7f1f0d76dd6 | 260 | |
XinZhangMS | 0:f7f1f0d76dd6 | 261 | case HTTP_PROXY_IO_STATE_CLOSING: |
XinZhangMS | 0:f7f1f0d76dd6 | 262 | case HTTP_PROXY_IO_STATE_OPEN: |
XinZhangMS | 0:f7f1f0d76dd6 | 263 | /* Codes_SRS_HTTP_PROXY_IO_01_077: [ When `on_underlying_io_open_complete` is called in after OPEN has completed, the `on_io_error` callback shall be triggered passing the `on_io_error_context` argument as `context`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 264 | http_proxy_io_instance->on_io_error(http_proxy_io_instance->on_io_error_context); |
XinZhangMS | 0:f7f1f0d76dd6 | 265 | break; |
XinZhangMS | 0:f7f1f0d76dd6 | 266 | |
XinZhangMS | 0:f7f1f0d76dd6 | 267 | case HTTP_PROXY_IO_STATE_WAITING_FOR_CONNECT_RESPONSE: |
XinZhangMS | 0:f7f1f0d76dd6 | 268 | /* Codes_SRS_HTTP_PROXY_IO_01_076: [ When `on_underlying_io_open_complete` is called while waiting for the CONNECT reply, the `on_open_complete` callback shall be triggered with `IO_OPEN_ERROR`, passing also the `on_open_complete_context` argument as `context`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 269 | LogError("Open complete called again by underlying IO."); |
XinZhangMS | 0:f7f1f0d76dd6 | 270 | indicate_open_complete_error_and_close(http_proxy_io_instance); |
XinZhangMS | 0:f7f1f0d76dd6 | 271 | break; |
XinZhangMS | 0:f7f1f0d76dd6 | 272 | |
XinZhangMS | 0:f7f1f0d76dd6 | 273 | case HTTP_PROXY_IO_STATE_OPENING_UNDERLYING_IO: |
XinZhangMS | 0:f7f1f0d76dd6 | 274 | switch (open_result) |
XinZhangMS | 0:f7f1f0d76dd6 | 275 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 276 | default: |
XinZhangMS | 0:f7f1f0d76dd6 | 277 | case IO_OPEN_ERROR: |
XinZhangMS | 0:f7f1f0d76dd6 | 278 | /* Codes_SRS_HTTP_PROXY_IO_01_078: [ When `on_underlying_io_open_complete` is called with `IO_OPEN_ERROR`, the `on_open_complete` callback shall be triggered with `IO_OPEN_ERROR`, passing also the `on_open_complete_context` argument as `context`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 279 | LogError("Underlying IO open failed"); |
XinZhangMS | 0:f7f1f0d76dd6 | 280 | indicate_open_complete_error_and_close(http_proxy_io_instance); |
XinZhangMS | 0:f7f1f0d76dd6 | 281 | break; |
XinZhangMS | 0:f7f1f0d76dd6 | 282 | |
XinZhangMS | 0:f7f1f0d76dd6 | 283 | case IO_OPEN_CANCELLED: |
XinZhangMS | 0:f7f1f0d76dd6 | 284 | /* Codes_SRS_HTTP_PROXY_IO_01_079: [ When `on_underlying_io_open_complete` is called with `IO_OPEN_CANCELLED`, the `on_open_complete` callback shall be triggered with `IO_OPEN_CANCELLED`, passing also the `on_open_complete_context` argument as `context`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 285 | LogError("Underlying IO open failed"); |
XinZhangMS | 0:f7f1f0d76dd6 | 286 | http_proxy_io_instance->http_proxy_io_state = HTTP_PROXY_IO_STATE_CLOSED; |
XinZhangMS | 0:f7f1f0d76dd6 | 287 | (void)xio_close(http_proxy_io_instance->underlying_io, NULL, NULL); |
XinZhangMS | 0:f7f1f0d76dd6 | 288 | http_proxy_io_instance->on_io_open_complete(http_proxy_io_instance->on_io_open_complete_context, IO_OPEN_CANCELLED); |
XinZhangMS | 0:f7f1f0d76dd6 | 289 | break; |
XinZhangMS | 0:f7f1f0d76dd6 | 290 | |
XinZhangMS | 0:f7f1f0d76dd6 | 291 | case IO_OPEN_OK: |
XinZhangMS | 0:f7f1f0d76dd6 | 292 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 293 | STRING_HANDLE encoded_auth_string; |
XinZhangMS | 0:f7f1f0d76dd6 | 294 | |
XinZhangMS | 0:f7f1f0d76dd6 | 295 | /* Codes_SRS_HTTP_PROXY_IO_01_057: [ When `on_underlying_io_open_complete` is called, the `http_proxy_io` shall send the CONNECT request constructed per RFC 2817: ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 296 | http_proxy_io_instance->http_proxy_io_state = HTTP_PROXY_IO_STATE_WAITING_FOR_CONNECT_RESPONSE; |
XinZhangMS | 0:f7f1f0d76dd6 | 297 | |
XinZhangMS | 0:f7f1f0d76dd6 | 298 | if (http_proxy_io_instance->username != NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 299 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 300 | char* plain_auth_string_bytes; |
XinZhangMS | 0:f7f1f0d76dd6 | 301 | |
XinZhangMS | 0:f7f1f0d76dd6 | 302 | /* Codes_SRS_HTTP_PROXY_IO_01_060: [ - The value of `Proxy-Authorization` shall be the constructed according to RFC 2617. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 303 | int plain_auth_string_length = (int)(strlen(http_proxy_io_instance->username)+1); |
XinZhangMS | 0:f7f1f0d76dd6 | 304 | if (http_proxy_io_instance->password != NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 305 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 306 | plain_auth_string_length += (int)strlen(http_proxy_io_instance->password); |
XinZhangMS | 0:f7f1f0d76dd6 | 307 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 308 | |
XinZhangMS | 0:f7f1f0d76dd6 | 309 | if (plain_auth_string_length < 0) |
XinZhangMS | 0:f7f1f0d76dd6 | 310 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 311 | /* Codes_SRS_HTTP_PROXY_IO_01_062: [ If any failure is encountered while constructing the request, the `on_open_complete` callback shall be triggered with `IO_OPEN_ERROR`, passing also the `on_open_complete_context` argument as `context`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 312 | encoded_auth_string = NULL; |
XinZhangMS | 0:f7f1f0d76dd6 | 313 | indicate_open_complete_error_and_close(http_proxy_io_instance); |
XinZhangMS | 0:f7f1f0d76dd6 | 314 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 315 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 316 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 317 | plain_auth_string_bytes = (char*)malloc(plain_auth_string_length + 1); |
XinZhangMS | 0:f7f1f0d76dd6 | 318 | if (plain_auth_string_bytes == NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 319 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 320 | /* Codes_SRS_HTTP_PROXY_IO_01_062: [ If any failure is encountered while constructing the request, the `on_open_complete` callback shall be triggered with `IO_OPEN_ERROR`, passing also the `on_open_complete_context` argument as `context`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 321 | encoded_auth_string = NULL; |
XinZhangMS | 0:f7f1f0d76dd6 | 322 | indicate_open_complete_error_and_close(http_proxy_io_instance); |
XinZhangMS | 0:f7f1f0d76dd6 | 323 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 324 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 325 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 326 | /* Codes_SRS_HTTP_PROXY_IO_01_091: [ To receive authorization, the client sends the userid and password, separated by a single colon (":") character, within a base64 [7] encoded string in the credentials. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 327 | /* Codes_SRS_HTTP_PROXY_IO_01_092: [ A client MAY preemptively send the corresponding Authorization header with requests for resources in that space without receipt of another challenge from the server. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 328 | /* Codes_SRS_HTTP_PROXY_IO_01_093: [ Userids might be case sensitive. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 329 | if (sprintf(plain_auth_string_bytes, "%s:%s", http_proxy_io_instance->username, (http_proxy_io_instance->password == NULL) ? "" : http_proxy_io_instance->password) < 0) |
XinZhangMS | 0:f7f1f0d76dd6 | 330 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 331 | /* Codes_SRS_HTTP_PROXY_IO_01_062: [ If any failure is encountered while constructing the request, the `on_open_complete` callback shall be triggered with `IO_OPEN_ERROR`, passing also the `on_open_complete_context` argument as `context`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 332 | encoded_auth_string = NULL; |
XinZhangMS | 0:f7f1f0d76dd6 | 333 | indicate_open_complete_error_and_close(http_proxy_io_instance); |
XinZhangMS | 0:f7f1f0d76dd6 | 334 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 335 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 336 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 337 | /* Codes_SRS_HTTP_PROXY_IO_01_061: [ Encoding to Base64 shall be done by calling `Base64_Encode_Bytes`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 338 | encoded_auth_string = Base64_Encode_Bytes((const unsigned char*)plain_auth_string_bytes, plain_auth_string_length); |
XinZhangMS | 0:f7f1f0d76dd6 | 339 | if (encoded_auth_string == NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 340 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 341 | /* Codes_SRS_HTTP_PROXY_IO_01_062: [ If any failure is encountered while constructing the request, the `on_open_complete` callback shall be triggered with `IO_OPEN_ERROR`, passing also the `on_open_complete_context` argument as `context`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 342 | LogError("Cannot Base64 encode auth string"); |
XinZhangMS | 0:f7f1f0d76dd6 | 343 | indicate_open_complete_error_and_close(http_proxy_io_instance); |
XinZhangMS | 0:f7f1f0d76dd6 | 344 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 345 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 346 | |
XinZhangMS | 0:f7f1f0d76dd6 | 347 | free(plain_auth_string_bytes); |
XinZhangMS | 0:f7f1f0d76dd6 | 348 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 349 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 350 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 351 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 352 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 353 | encoded_auth_string = NULL; |
XinZhangMS | 0:f7f1f0d76dd6 | 354 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 355 | |
XinZhangMS | 0:f7f1f0d76dd6 | 356 | if ((http_proxy_io_instance->username != NULL) && |
XinZhangMS | 0:f7f1f0d76dd6 | 357 | (encoded_auth_string == NULL)) |
XinZhangMS | 0:f7f1f0d76dd6 | 358 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 359 | LogError("Cannot create authorization header"); |
XinZhangMS | 0:f7f1f0d76dd6 | 360 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 361 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 362 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 363 | int connect_request_length; |
XinZhangMS | 0:f7f1f0d76dd6 | 364 | const char* auth_string_payload; |
XinZhangMS | 0:f7f1f0d76dd6 | 365 | /* Codes_SRS_HTTP_PROXY_IO_01_075: [ The Request-URI portion of the Request-Line is always an 'authority' as defined by URI Generic Syntax [2], which is to say the host name and port number destination of the requested connection separated by a colon: ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 366 | const char request_format[] = "CONNECT %s:%d HTTP/1.1\r\nHost:%s:%d%s%s\r\n\r\n"; |
XinZhangMS | 0:f7f1f0d76dd6 | 367 | const char proxy_basic[] = "\r\nProxy-authorization: Basic "; |
XinZhangMS | 0:f7f1f0d76dd6 | 368 | if (http_proxy_io_instance->username != NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 369 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 370 | auth_string_payload = STRING_c_str(encoded_auth_string); |
XinZhangMS | 0:f7f1f0d76dd6 | 371 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 372 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 373 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 374 | auth_string_payload = ""; |
XinZhangMS | 0:f7f1f0d76dd6 | 375 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 376 | |
XinZhangMS | 0:f7f1f0d76dd6 | 377 | /* Codes_SRS_HTTP_PROXY_IO_01_059: [ - If `username` and `password` have been specified in the arguments passed to `http_proxy_io_create`, then the header `Proxy-Authorization` shall be added to the request. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 378 | |
XinZhangMS | 0:f7f1f0d76dd6 | 379 | connect_request_length = (int)(strlen(request_format)+(strlen(http_proxy_io_instance->hostname)*2)+strlen(auth_string_payload)+10); |
XinZhangMS | 0:f7f1f0d76dd6 | 380 | if (http_proxy_io_instance->username != NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 381 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 382 | connect_request_length += (int)strlen(proxy_basic); |
XinZhangMS | 0:f7f1f0d76dd6 | 383 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 384 | |
XinZhangMS | 0:f7f1f0d76dd6 | 385 | if (connect_request_length < 0) |
XinZhangMS | 0:f7f1f0d76dd6 | 386 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 387 | /* Codes_SRS_HTTP_PROXY_IO_01_062: [ If any failure is encountered while constructing the request, the `on_open_complete` callback shall be triggered with `IO_OPEN_ERROR`, passing also the `on_open_complete_context` argument as `context`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 388 | LogError("Cannot encode the CONNECT request"); |
XinZhangMS | 0:f7f1f0d76dd6 | 389 | indicate_open_complete_error_and_close(http_proxy_io_instance); |
XinZhangMS | 0:f7f1f0d76dd6 | 390 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 391 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 392 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 393 | char* connect_request = (char*)malloc(connect_request_length + 1); |
XinZhangMS | 0:f7f1f0d76dd6 | 394 | if (connect_request == NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 395 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 396 | /* Codes_SRS_HTTP_PROXY_IO_01_062: [ If any failure is encountered while constructing the request, the `on_open_complete` callback shall be triggered with `IO_OPEN_ERROR`, passing also the `on_open_complete_context` argument as `context`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 397 | LogError("Cannot allocate memory for CONNECT request"); |
XinZhangMS | 0:f7f1f0d76dd6 | 398 | indicate_open_complete_error_and_close(http_proxy_io_instance); |
XinZhangMS | 0:f7f1f0d76dd6 | 399 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 400 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 401 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 402 | /* Codes_SRS_HTTP_PROXY_IO_01_059: [ - If `username` and `password` have been specified in the arguments passed to `http_proxy_io_create`, then the header `Proxy-Authorization` shall be added to the request. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 403 | connect_request_length = sprintf(connect_request, request_format, |
XinZhangMS | 0:f7f1f0d76dd6 | 404 | http_proxy_io_instance->hostname, |
XinZhangMS | 0:f7f1f0d76dd6 | 405 | http_proxy_io_instance->port, |
XinZhangMS | 0:f7f1f0d76dd6 | 406 | http_proxy_io_instance->hostname, |
XinZhangMS | 0:f7f1f0d76dd6 | 407 | http_proxy_io_instance->port, |
XinZhangMS | 0:f7f1f0d76dd6 | 408 | (http_proxy_io_instance->username != NULL) ? proxy_basic : "", |
XinZhangMS | 0:f7f1f0d76dd6 | 409 | auth_string_payload); |
XinZhangMS | 0:f7f1f0d76dd6 | 410 | |
XinZhangMS | 0:f7f1f0d76dd6 | 411 | if (connect_request_length < 0) |
XinZhangMS | 0:f7f1f0d76dd6 | 412 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 413 | /* Codes_SRS_HTTP_PROXY_IO_01_062: [ If any failure is encountered while constructing the request, the `on_open_complete` callback shall be triggered with `IO_OPEN_ERROR`, passing also the `on_open_complete_context` argument as `context`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 414 | LogError("Cannot encode the CONNECT request"); |
XinZhangMS | 0:f7f1f0d76dd6 | 415 | indicate_open_complete_error_and_close(http_proxy_io_instance); |
XinZhangMS | 0:f7f1f0d76dd6 | 416 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 417 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 418 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 419 | /* Codes_SRS_HTTP_PROXY_IO_01_063: [ The request shall be sent by calling `xio_send` and passing NULL as `on_send_complete` callback. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 420 | if (xio_send(http_proxy_io_instance->underlying_io, connect_request, connect_request_length, unchecked_on_send_complete, NULL) != 0) |
XinZhangMS | 0:f7f1f0d76dd6 | 421 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 422 | /* Codes_SRS_HTTP_PROXY_IO_01_064: [ If `xio_send` fails, the `on_open_complete` callback shall be triggered with `IO_OPEN_ERROR`, passing also the `on_open_complete_context` argument as `context`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 423 | LogError("Could not send CONNECT request"); |
XinZhangMS | 0:f7f1f0d76dd6 | 424 | indicate_open_complete_error_and_close(http_proxy_io_instance); |
XinZhangMS | 0:f7f1f0d76dd6 | 425 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 426 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 427 | |
XinZhangMS | 0:f7f1f0d76dd6 | 428 | free(connect_request); |
XinZhangMS | 0:f7f1f0d76dd6 | 429 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 430 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 431 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 432 | |
XinZhangMS | 0:f7f1f0d76dd6 | 433 | if (encoded_auth_string != NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 434 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 435 | STRING_delete(encoded_auth_string); |
XinZhangMS | 0:f7f1f0d76dd6 | 436 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 437 | |
XinZhangMS | 0:f7f1f0d76dd6 | 438 | break; |
XinZhangMS | 0:f7f1f0d76dd6 | 439 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 440 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 441 | |
XinZhangMS | 0:f7f1f0d76dd6 | 442 | break; |
XinZhangMS | 0:f7f1f0d76dd6 | 443 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 444 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 445 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 446 | |
XinZhangMS | 0:f7f1f0d76dd6 | 447 | static void on_underlying_io_error(void* context) |
XinZhangMS | 0:f7f1f0d76dd6 | 448 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 449 | if (context == NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 450 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 451 | /* Codes_SRS_HTTP_PROXY_IO_01_088: [ `on_underlying_io_error` called with NULL context shall do nothing. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 452 | LogError("NULL context in on_underlying_io_error"); |
XinZhangMS | 0:f7f1f0d76dd6 | 453 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 454 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 455 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 456 | HTTP_PROXY_IO_INSTANCE* http_proxy_io_instance = (HTTP_PROXY_IO_INSTANCE*)context; |
XinZhangMS | 0:f7f1f0d76dd6 | 457 | |
XinZhangMS | 0:f7f1f0d76dd6 | 458 | switch (http_proxy_io_instance->http_proxy_io_state) |
XinZhangMS | 0:f7f1f0d76dd6 | 459 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 460 | default: |
XinZhangMS | 0:f7f1f0d76dd6 | 461 | LogError("on_underlying_io_error in invalid state"); |
XinZhangMS | 0:f7f1f0d76dd6 | 462 | break; |
XinZhangMS | 0:f7f1f0d76dd6 | 463 | |
XinZhangMS | 0:f7f1f0d76dd6 | 464 | case HTTP_PROXY_IO_STATE_OPENING_UNDERLYING_IO: |
XinZhangMS | 0:f7f1f0d76dd6 | 465 | case HTTP_PROXY_IO_STATE_WAITING_FOR_CONNECT_RESPONSE: |
XinZhangMS | 0:f7f1f0d76dd6 | 466 | /* Codes_SRS_HTTP_PROXY_IO_01_087: [ If the `on_underlying_io_error` callback is called while OPENING, the `on_open_complete` callback shall be triggered with `IO_OPEN_ERROR`, passing also the `on_open_complete_context` argument as `context`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 467 | indicate_open_complete_error_and_close(http_proxy_io_instance); |
XinZhangMS | 0:f7f1f0d76dd6 | 468 | break; |
XinZhangMS | 0:f7f1f0d76dd6 | 469 | |
XinZhangMS | 0:f7f1f0d76dd6 | 470 | case HTTP_PROXY_IO_STATE_OPEN: |
XinZhangMS | 0:f7f1f0d76dd6 | 471 | /* Codes_SRS_HTTP_PROXY_IO_01_089: [ If the `on_underlying_io_error` callback is called while the IO is OPEN, the `on_io_error` callback shall be called with the `on_io_error_context` argument as `context`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 472 | http_proxy_io_instance->http_proxy_io_state = HTTP_PROXY_IO_STATE_ERROR; |
XinZhangMS | 0:f7f1f0d76dd6 | 473 | http_proxy_io_instance->on_io_error(http_proxy_io_instance->on_io_error_context); |
XinZhangMS | 0:f7f1f0d76dd6 | 474 | break; |
XinZhangMS | 0:f7f1f0d76dd6 | 475 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 476 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 477 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 478 | |
XinZhangMS | 0:f7f1f0d76dd6 | 479 | static void on_underlying_io_close_complete(void* context) |
XinZhangMS | 0:f7f1f0d76dd6 | 480 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 481 | if (context == NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 482 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 483 | /* Cdoes_SRS_HTTP_PROXY_IO_01_084: [ `on_underlying_io_close_complete` called with NULL context shall do nothing. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 484 | LogError("NULL context in on_underlying_io_open_complete"); |
XinZhangMS | 0:f7f1f0d76dd6 | 485 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 486 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 487 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 488 | HTTP_PROXY_IO_INSTANCE* http_proxy_io_instance = (HTTP_PROXY_IO_INSTANCE*)context; |
XinZhangMS | 0:f7f1f0d76dd6 | 489 | |
XinZhangMS | 0:f7f1f0d76dd6 | 490 | switch (http_proxy_io_instance->http_proxy_io_state) |
XinZhangMS | 0:f7f1f0d76dd6 | 491 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 492 | default: |
XinZhangMS | 0:f7f1f0d76dd6 | 493 | LogError("on_underlying_io_close_complete called in an invalid state"); |
XinZhangMS | 0:f7f1f0d76dd6 | 494 | break; |
XinZhangMS | 0:f7f1f0d76dd6 | 495 | |
XinZhangMS | 0:f7f1f0d76dd6 | 496 | case HTTP_PROXY_IO_STATE_CLOSING: |
XinZhangMS | 0:f7f1f0d76dd6 | 497 | http_proxy_io_instance->http_proxy_io_state = HTTP_PROXY_IO_STATE_CLOSED; |
XinZhangMS | 0:f7f1f0d76dd6 | 498 | |
XinZhangMS | 0:f7f1f0d76dd6 | 499 | /* Codes_SRS_HTTP_PROXY_IO_01_086: [ If the `on_io_close_complete` callback passed to `http_proxy_io_close` was NULL, no callback shall be triggered. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 500 | if (http_proxy_io_instance->on_io_close_complete != NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 501 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 502 | /* Codes_SRS_HTTP_PROXY_IO_01_083: [ `on_underlying_io_close_complete` while CLOSING shall call the `on_io_close_complete` callback, passing to it the `on_io_close_complete_context` as `context` argument. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 503 | http_proxy_io_instance->on_io_close_complete(http_proxy_io_instance->on_io_close_complete_context); |
XinZhangMS | 0:f7f1f0d76dd6 | 504 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 505 | |
XinZhangMS | 0:f7f1f0d76dd6 | 506 | break; |
XinZhangMS | 0:f7f1f0d76dd6 | 507 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 508 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 509 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 510 | |
XinZhangMS | 0:f7f1f0d76dd6 | 511 | /*the following function does the same as sscanf(pos2, "%d", &sec)*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 512 | /*this function only exists because some of platforms do not have sscanf. */ |
XinZhangMS | 0:f7f1f0d76dd6 | 513 | static int ParseStringToDecimal(const char *src, int* dst) |
XinZhangMS | 0:f7f1f0d76dd6 | 514 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 515 | int result; |
XinZhangMS | 0:f7f1f0d76dd6 | 516 | char* next; |
XinZhangMS | 0:f7f1f0d76dd6 | 517 | |
XinZhangMS | 0:f7f1f0d76dd6 | 518 | (*dst) = (int)strtol(src, &next, 0); |
XinZhangMS | 0:f7f1f0d76dd6 | 519 | if ((src == next) || ((((*dst) == INT_MAX) || ((*dst) == INT_MIN)) && (errno != 0))) |
XinZhangMS | 0:f7f1f0d76dd6 | 520 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 521 | result = __LINE__; |
XinZhangMS | 0:f7f1f0d76dd6 | 522 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 523 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 524 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 525 | result = 0; |
XinZhangMS | 0:f7f1f0d76dd6 | 526 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 527 | |
XinZhangMS | 0:f7f1f0d76dd6 | 528 | return result; |
XinZhangMS | 0:f7f1f0d76dd6 | 529 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 530 | |
XinZhangMS | 0:f7f1f0d76dd6 | 531 | /*the following function does the same as sscanf(buf, "HTTP/%*d.%*d %d %*[^\r\n]", &ret) */ |
XinZhangMS | 0:f7f1f0d76dd6 | 532 | /*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. */ |
XinZhangMS | 0:f7f1f0d76dd6 | 533 | static int ParseHttpResponse(const char* src, int* dst) |
XinZhangMS | 0:f7f1f0d76dd6 | 534 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 535 | int result; |
XinZhangMS | 0:f7f1f0d76dd6 | 536 | static const char HTTPPrefix[] = "HTTP/"; |
XinZhangMS | 0:f7f1f0d76dd6 | 537 | bool fail; |
XinZhangMS | 0:f7f1f0d76dd6 | 538 | const char* runPrefix; |
XinZhangMS | 0:f7f1f0d76dd6 | 539 | |
XinZhangMS | 0:f7f1f0d76dd6 | 540 | if ((src == NULL) || (dst == NULL)) |
XinZhangMS | 0:f7f1f0d76dd6 | 541 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 542 | result = __LINE__; |
XinZhangMS | 0:f7f1f0d76dd6 | 543 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 544 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 545 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 546 | fail = false; |
XinZhangMS | 0:f7f1f0d76dd6 | 547 | runPrefix = HTTPPrefix; |
XinZhangMS | 0:f7f1f0d76dd6 | 548 | |
XinZhangMS | 0:f7f1f0d76dd6 | 549 | while ((*runPrefix) != '\0') |
XinZhangMS | 0:f7f1f0d76dd6 | 550 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 551 | if ((*runPrefix) != (*src)) |
XinZhangMS | 0:f7f1f0d76dd6 | 552 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 553 | fail = true; |
XinZhangMS | 0:f7f1f0d76dd6 | 554 | break; |
XinZhangMS | 0:f7f1f0d76dd6 | 555 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 556 | src++; |
XinZhangMS | 0:f7f1f0d76dd6 | 557 | runPrefix++; |
XinZhangMS | 0:f7f1f0d76dd6 | 558 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 559 | |
XinZhangMS | 0:f7f1f0d76dd6 | 560 | if (!fail) |
XinZhangMS | 0:f7f1f0d76dd6 | 561 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 562 | while ((*src) != '.') |
XinZhangMS | 0:f7f1f0d76dd6 | 563 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 564 | if ((*src) == '\0') |
XinZhangMS | 0:f7f1f0d76dd6 | 565 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 566 | fail = true; |
XinZhangMS | 0:f7f1f0d76dd6 | 567 | break; |
XinZhangMS | 0:f7f1f0d76dd6 | 568 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 569 | src++; |
XinZhangMS | 0:f7f1f0d76dd6 | 570 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 571 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 572 | |
XinZhangMS | 0:f7f1f0d76dd6 | 573 | if (!fail) |
XinZhangMS | 0:f7f1f0d76dd6 | 574 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 575 | while ((*src) != ' ') |
XinZhangMS | 0:f7f1f0d76dd6 | 576 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 577 | if ((*src) == '\0') |
XinZhangMS | 0:f7f1f0d76dd6 | 578 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 579 | fail = true; |
XinZhangMS | 0:f7f1f0d76dd6 | 580 | break; |
XinZhangMS | 0:f7f1f0d76dd6 | 581 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 582 | src++; |
XinZhangMS | 0:f7f1f0d76dd6 | 583 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 584 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 585 | |
XinZhangMS | 0:f7f1f0d76dd6 | 586 | if (fail) |
XinZhangMS | 0:f7f1f0d76dd6 | 587 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 588 | result = __LINE__; |
XinZhangMS | 0:f7f1f0d76dd6 | 589 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 590 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 591 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 592 | if (ParseStringToDecimal(src, dst) != 0) |
XinZhangMS | 0:f7f1f0d76dd6 | 593 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 594 | result = __LINE__; |
XinZhangMS | 0:f7f1f0d76dd6 | 595 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 596 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 597 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 598 | result = 0; |
XinZhangMS | 0:f7f1f0d76dd6 | 599 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 600 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 601 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 602 | |
XinZhangMS | 0:f7f1f0d76dd6 | 603 | return result; |
XinZhangMS | 0:f7f1f0d76dd6 | 604 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 605 | |
XinZhangMS | 0:f7f1f0d76dd6 | 606 | static void on_underlying_io_bytes_received(void* context, const unsigned char* buffer, size_t size) |
XinZhangMS | 0:f7f1f0d76dd6 | 607 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 608 | if (context == NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 609 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 610 | /* Codes_SRS_HTTP_PROXY_IO_01_082: [ `on_underlying_io_bytes_received` called with NULL context shall do nothing. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 611 | LogError("NULL context in on_underlying_io_bytes_received"); |
XinZhangMS | 0:f7f1f0d76dd6 | 612 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 613 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 614 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 615 | HTTP_PROXY_IO_INSTANCE* http_proxy_io_instance = (HTTP_PROXY_IO_INSTANCE*)context; |
XinZhangMS | 0:f7f1f0d76dd6 | 616 | |
XinZhangMS | 0:f7f1f0d76dd6 | 617 | switch (http_proxy_io_instance->http_proxy_io_state) |
XinZhangMS | 0:f7f1f0d76dd6 | 618 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 619 | default: |
XinZhangMS | 0:f7f1f0d76dd6 | 620 | case HTTP_PROXY_IO_STATE_CLOSING: |
XinZhangMS | 0:f7f1f0d76dd6 | 621 | LogError("Bytes received in invalid state"); |
XinZhangMS | 0:f7f1f0d76dd6 | 622 | break; |
XinZhangMS | 0:f7f1f0d76dd6 | 623 | |
XinZhangMS | 0:f7f1f0d76dd6 | 624 | case HTTP_PROXY_IO_STATE_OPENING_UNDERLYING_IO: |
XinZhangMS | 0:f7f1f0d76dd6 | 625 | /* Codes_SRS_HTTP_PROXY_IO_01_080: [ If `on_underlying_io_bytes_received` is called while the underlying IO is being opened, the `on_open_complete` callback shall be triggered with `IO_OPEN_ERROR`, passing also the `on_open_complete_context` argument as `context`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 626 | LogError("Bytes received while opening underlying IO"); |
XinZhangMS | 0:f7f1f0d76dd6 | 627 | indicate_open_complete_error_and_close(http_proxy_io_instance); |
XinZhangMS | 0:f7f1f0d76dd6 | 628 | break; |
XinZhangMS | 0:f7f1f0d76dd6 | 629 | |
XinZhangMS | 0:f7f1f0d76dd6 | 630 | case HTTP_PROXY_IO_STATE_WAITING_FOR_CONNECT_RESPONSE: |
XinZhangMS | 0:f7f1f0d76dd6 | 631 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 632 | /* Codes_SRS_HTTP_PROXY_IO_01_065: [ When bytes are received and the response to the CONNECT request was not yet received, the bytes shall be accumulated until a double new-line is detected. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 633 | unsigned char* new_receive_buffer = (unsigned char*)realloc(http_proxy_io_instance->receive_buffer, http_proxy_io_instance->receive_buffer_size + size + 1); |
XinZhangMS | 0:f7f1f0d76dd6 | 634 | if (new_receive_buffer == NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 635 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 636 | /* Codes_SRS_HTTP_PROXY_IO_01_067: [ If allocating memory for the buffered bytes fails, the `on_open_complete` callback shall be triggered with `IO_OPEN_ERROR`, passing also the `on_open_complete_context` argument as `context`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 637 | LogError("Cannot allocate memory for received data"); |
XinZhangMS | 0:f7f1f0d76dd6 | 638 | indicate_open_complete_error_and_close(http_proxy_io_instance); |
XinZhangMS | 0:f7f1f0d76dd6 | 639 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 640 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 641 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 642 | http_proxy_io_instance->receive_buffer = new_receive_buffer; |
XinZhangMS | 0:f7f1f0d76dd6 | 643 | memcpy(http_proxy_io_instance->receive_buffer + http_proxy_io_instance->receive_buffer_size, buffer, size); |
XinZhangMS | 0:f7f1f0d76dd6 | 644 | http_proxy_io_instance->receive_buffer_size += size; |
XinZhangMS | 0:f7f1f0d76dd6 | 645 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 646 | |
XinZhangMS | 0:f7f1f0d76dd6 | 647 | if (http_proxy_io_instance->receive_buffer_size >= 4) |
XinZhangMS | 0:f7f1f0d76dd6 | 648 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 649 | const char* request_end_ptr; |
XinZhangMS | 0:f7f1f0d76dd6 | 650 | |
XinZhangMS | 0:f7f1f0d76dd6 | 651 | http_proxy_io_instance->receive_buffer[http_proxy_io_instance->receive_buffer_size] = 0; |
XinZhangMS | 0:f7f1f0d76dd6 | 652 | |
XinZhangMS | 0:f7f1f0d76dd6 | 653 | /* Codes_SRS_HTTP_PROXY_IO_01_066: [ When a double new-line is detected the response shall be parsed in order to extract the status code. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 654 | if ((http_proxy_io_instance->receive_buffer_size >= 4) && |
XinZhangMS | 0:f7f1f0d76dd6 | 655 | ((request_end_ptr = strstr((const char*)http_proxy_io_instance->receive_buffer, "\r\n\r\n")) != NULL)) |
XinZhangMS | 0:f7f1f0d76dd6 | 656 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 657 | int status_code; |
XinZhangMS | 0:f7f1f0d76dd6 | 658 | |
XinZhangMS | 0:f7f1f0d76dd6 | 659 | /* This part should really be done with the HTTPAPI, but that has to be done as a separate step |
XinZhangMS | 0:f7f1f0d76dd6 | 660 | as the HTTPAPI has to expose somehow the underlying IO and currently this would be a too big of a change. */ |
XinZhangMS | 0:f7f1f0d76dd6 | 661 | |
XinZhangMS | 0:f7f1f0d76dd6 | 662 | if (ParseHttpResponse((const char*)http_proxy_io_instance->receive_buffer, &status_code) != 0) |
XinZhangMS | 0:f7f1f0d76dd6 | 663 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 664 | /* Codes_SRS_HTTP_PROXY_IO_01_068: [ If parsing the CONNECT response fails, the `on_open_complete` callback shall be triggered with `IO_OPEN_ERROR`, passing also the `on_open_complete_context` argument as `context`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 665 | LogError("Cannot decode HTTP response"); |
XinZhangMS | 0:f7f1f0d76dd6 | 666 | indicate_open_complete_error_and_close(http_proxy_io_instance); |
XinZhangMS | 0:f7f1f0d76dd6 | 667 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 668 | /* Codes_SRS_HTTP_PROXY_IO_01_069: [ Any successful (2xx) response to a CONNECT request indicates that the proxy has established a connection to the requested host and port, and has switched to tunneling the current connection to that server connection. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 669 | /* Codes_SRS_HTTP_PROXY_IO_01_090: [ Any successful (2xx) response to a CONNECT request indicates that the proxy has established a connection to the requested host and port, and has switched to tunneling the current connection to that server connection. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 670 | else if ((status_code < 200) || (status_code > 299)) |
XinZhangMS | 0:f7f1f0d76dd6 | 671 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 672 | /* Codes_SRS_HTTP_PROXY_IO_01_071: [ If the status code is not successful, the `on_open_complete` callback shall be triggered with `IO_OPEN_ERROR`, passing also the `on_open_complete_context` argument as `context`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 673 | LogError("Bad status (%d) received in CONNECT response", status_code); |
XinZhangMS | 0:f7f1f0d76dd6 | 674 | indicate_open_complete_error_and_close(http_proxy_io_instance); |
XinZhangMS | 0:f7f1f0d76dd6 | 675 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 676 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 677 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 678 | size_t length_remaining = http_proxy_io_instance->receive_buffer + http_proxy_io_instance->receive_buffer_size - ((const unsigned char *)request_end_ptr + 4); |
XinZhangMS | 0:f7f1f0d76dd6 | 679 | |
XinZhangMS | 0:f7f1f0d76dd6 | 680 | /* Codes_SRS_HTTP_PROXY_IO_01_073: [ Once a success status code was parsed, the IO shall be OPEN. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 681 | http_proxy_io_instance->http_proxy_io_state = HTTP_PROXY_IO_STATE_OPEN; |
XinZhangMS | 0:f7f1f0d76dd6 | 682 | /* Codes_SRS_HTTP_PROXY_IO_01_070: [ When a success status code is parsed, the `on_open_complete` callback shall be triggered with `IO_OPEN_OK`, passing also the `on_open_complete_context` argument as `context`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 683 | http_proxy_io_instance->on_io_open_complete(http_proxy_io_instance->on_io_open_complete_context, IO_OPEN_OK); |
XinZhangMS | 0:f7f1f0d76dd6 | 684 | |
XinZhangMS | 0:f7f1f0d76dd6 | 685 | if (length_remaining > 0) |
XinZhangMS | 0:f7f1f0d76dd6 | 686 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 687 | /* Codes_SRS_HTTP_PROXY_IO_01_072: [ Any bytes that are extra (not consumed by the CONNECT response), shall be indicated as received by calling the `on_bytes_received` callback and passing the `on_bytes_received_context` as context argument. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 688 | http_proxy_io_instance->on_bytes_received(http_proxy_io_instance->on_bytes_received_context, (const unsigned char*)request_end_ptr + 4, length_remaining); |
XinZhangMS | 0:f7f1f0d76dd6 | 689 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 690 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 691 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 692 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 693 | break; |
XinZhangMS | 0:f7f1f0d76dd6 | 694 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 695 | case HTTP_PROXY_IO_STATE_OPEN: |
XinZhangMS | 0:f7f1f0d76dd6 | 696 | /* Codes_SRS_HTTP_PROXY_IO_01_074: [ If `on_underlying_io_bytes_received` is called while OPEN, all bytes shall be indicated as received by calling the `on_bytes_received` callback and passing the `on_bytes_received_context` as context argument. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 697 | http_proxy_io_instance->on_bytes_received(http_proxy_io_instance->on_bytes_received_context, buffer, size); |
XinZhangMS | 0:f7f1f0d76dd6 | 698 | break; |
XinZhangMS | 0:f7f1f0d76dd6 | 699 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 700 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 701 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 702 | |
XinZhangMS | 0:f7f1f0d76dd6 | 703 | static int http_proxy_io_open(CONCRETE_IO_HANDLE http_proxy_io, ON_IO_OPEN_COMPLETE on_io_open_complete, void* on_io_open_complete_context, ON_BYTES_RECEIVED on_bytes_received, void* on_bytes_received_context, ON_IO_ERROR on_io_error, void* on_io_error_context) |
XinZhangMS | 0:f7f1f0d76dd6 | 704 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 705 | int result; |
XinZhangMS | 0:f7f1f0d76dd6 | 706 | |
XinZhangMS | 0:f7f1f0d76dd6 | 707 | /* Codes_SRS_HTTP_PROXY_IO_01_051: [ The arguments `on_io_open_complete_context`, `on_bytes_received_context` and `on_io_error_context` shall be allowed to be NULL. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 708 | /* Codes_SRS_HTTP_PROXY_IO_01_018: [ If any of the arguments `http_proxy_io`, `on_io_open_complete`, `on_bytes_received` or `on_io_error` are NULL then `http_proxy_io_open` shall return a non-zero value. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 709 | if ((http_proxy_io == NULL) || |
XinZhangMS | 0:f7f1f0d76dd6 | 710 | (on_io_open_complete == NULL) || |
XinZhangMS | 0:f7f1f0d76dd6 | 711 | (on_bytes_received == NULL) || |
XinZhangMS | 0:f7f1f0d76dd6 | 712 | (on_io_error == NULL)) |
XinZhangMS | 0:f7f1f0d76dd6 | 713 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 714 | LogError("Bad arguments: http_proxy_io = %p, on_io_open_complete = %p, on_bytes_received = %p, on_io_error_context = %p.", |
XinZhangMS | 0:f7f1f0d76dd6 | 715 | http_proxy_io, |
XinZhangMS | 0:f7f1f0d76dd6 | 716 | on_io_open_complete, |
XinZhangMS | 0:f7f1f0d76dd6 | 717 | on_bytes_received, |
XinZhangMS | 0:f7f1f0d76dd6 | 718 | on_io_error); |
XinZhangMS | 0:f7f1f0d76dd6 | 719 | result = __LINE__; |
XinZhangMS | 0:f7f1f0d76dd6 | 720 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 721 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 722 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 723 | HTTP_PROXY_IO_INSTANCE* http_proxy_io_instance = (HTTP_PROXY_IO_INSTANCE*)http_proxy_io; |
XinZhangMS | 0:f7f1f0d76dd6 | 724 | |
XinZhangMS | 0:f7f1f0d76dd6 | 725 | if (http_proxy_io_instance->http_proxy_io_state != HTTP_PROXY_IO_STATE_CLOSED) |
XinZhangMS | 0:f7f1f0d76dd6 | 726 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 727 | LogError("Invalid tlsio_state. Expected state is HTTP_PROXY_IO_STATE_CLOSED."); |
XinZhangMS | 0:f7f1f0d76dd6 | 728 | result = __LINE__; |
XinZhangMS | 0:f7f1f0d76dd6 | 729 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 730 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 731 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 732 | http_proxy_io_instance->on_bytes_received = on_bytes_received; |
XinZhangMS | 0:f7f1f0d76dd6 | 733 | http_proxy_io_instance->on_bytes_received_context = on_bytes_received_context; |
XinZhangMS | 0:f7f1f0d76dd6 | 734 | |
XinZhangMS | 0:f7f1f0d76dd6 | 735 | http_proxy_io_instance->on_io_error = on_io_error; |
XinZhangMS | 0:f7f1f0d76dd6 | 736 | http_proxy_io_instance->on_io_error_context = on_io_error_context; |
XinZhangMS | 0:f7f1f0d76dd6 | 737 | |
XinZhangMS | 0:f7f1f0d76dd6 | 738 | http_proxy_io_instance->on_io_open_complete = on_io_open_complete; |
XinZhangMS | 0:f7f1f0d76dd6 | 739 | http_proxy_io_instance->on_io_open_complete_context = on_io_open_complete_context; |
XinZhangMS | 0:f7f1f0d76dd6 | 740 | |
XinZhangMS | 0:f7f1f0d76dd6 | 741 | http_proxy_io_instance->http_proxy_io_state = HTTP_PROXY_IO_STATE_OPENING_UNDERLYING_IO; |
XinZhangMS | 0:f7f1f0d76dd6 | 742 | |
XinZhangMS | 0:f7f1f0d76dd6 | 743 | /* Codes_SRS_HTTP_PROXY_IO_01_019: [ `http_proxy_io_open` shall open the underlying IO by calling `xio_open` on the underlying IO handle created in `http_proxy_io_create`, while passing to it the callbacks `on_underlying_io_open_complete`, `on_underlying_io_bytes_received` and `on_underlying_io_error`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 744 | if (xio_open(http_proxy_io_instance->underlying_io, on_underlying_io_open_complete, http_proxy_io_instance, on_underlying_io_bytes_received, http_proxy_io_instance, on_underlying_io_error, http_proxy_io_instance) != 0) |
XinZhangMS | 0:f7f1f0d76dd6 | 745 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 746 | /* Codes_SRS_HTTP_PROXY_IO_01_020: [ If `xio_open` fails, then `http_proxy_io_open` shall return a non-zero value. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 747 | http_proxy_io_instance->http_proxy_io_state = HTTP_PROXY_IO_STATE_CLOSED; |
XinZhangMS | 0:f7f1f0d76dd6 | 748 | LogError("Cannot open the underlying IO."); |
XinZhangMS | 0:f7f1f0d76dd6 | 749 | result = __LINE__; |
XinZhangMS | 0:f7f1f0d76dd6 | 750 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 751 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 752 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 753 | /* Codes_SRS_HTTP_PROXY_IO_01_017: [ `http_proxy_io_open` shall open the HTTP proxy IO and on success it shall return 0. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 754 | result = 0; |
XinZhangMS | 0:f7f1f0d76dd6 | 755 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 756 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 757 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 758 | |
XinZhangMS | 0:f7f1f0d76dd6 | 759 | return result; |
XinZhangMS | 0:f7f1f0d76dd6 | 760 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 761 | |
XinZhangMS | 0:f7f1f0d76dd6 | 762 | static int http_proxy_io_close(CONCRETE_IO_HANDLE http_proxy_io, ON_IO_CLOSE_COMPLETE on_io_close_complete, void* on_io_close_complete_context) |
XinZhangMS | 0:f7f1f0d76dd6 | 763 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 764 | int result = 0; |
XinZhangMS | 0:f7f1f0d76dd6 | 765 | |
XinZhangMS | 0:f7f1f0d76dd6 | 766 | /* Codes_SRS_HTTP_PROXY_IO_01_052: [ `on_io_close_complete_context` shall be allowed to be NULL. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 767 | /* Codes_SRS_HTTP_PROXY_IO_01_028: [ `on_io_close_complete` shall be allowed to be NULL. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 768 | if (http_proxy_io == NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 769 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 770 | /* Codes_SRS_HTTP_PROXY_IO_01_023: [ If the argument `http_proxy_io` is NULL, `http_proxy_io_close` shall fail and return a non-zero value. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 771 | result = __LINE__; |
XinZhangMS | 0:f7f1f0d76dd6 | 772 | LogError("NULL http_proxy_io."); |
XinZhangMS | 0:f7f1f0d76dd6 | 773 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 774 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 775 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 776 | HTTP_PROXY_IO_INSTANCE* http_proxy_io_instance = (HTTP_PROXY_IO_INSTANCE*)http_proxy_io; |
XinZhangMS | 0:f7f1f0d76dd6 | 777 | |
XinZhangMS | 0:f7f1f0d76dd6 | 778 | /* Codes_SRS_HTTP_PROXY_IO_01_027: [ If `http_proxy_io_close` is called when not open, `http_proxy_io_close` shall fail and return a non-zero value. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 779 | if ((http_proxy_io_instance->http_proxy_io_state == HTTP_PROXY_IO_STATE_CLOSED) || |
XinZhangMS | 0:f7f1f0d76dd6 | 780 | /* Codes_SRS_HTTP_PROXY_IO_01_054: [ `http_proxy_io_close` while OPENING shall fail and return a non-zero value. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 781 | (http_proxy_io_instance->http_proxy_io_state == HTTP_PROXY_IO_STATE_CLOSING)) |
XinZhangMS | 0:f7f1f0d76dd6 | 782 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 783 | result = __LINE__; |
XinZhangMS | 0:f7f1f0d76dd6 | 784 | LogError("Invalid tlsio_state. Expected state is HTTP_PROXY_IO_STATE_OPEN."); |
XinZhangMS | 0:f7f1f0d76dd6 | 785 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 786 | else if ((http_proxy_io_instance->http_proxy_io_state == HTTP_PROXY_IO_STATE_OPENING_UNDERLYING_IO) || |
XinZhangMS | 0:f7f1f0d76dd6 | 787 | (http_proxy_io_instance->http_proxy_io_state == HTTP_PROXY_IO_STATE_WAITING_FOR_CONNECT_RESPONSE)) |
XinZhangMS | 0:f7f1f0d76dd6 | 788 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 789 | /* Codes_SRS_HTTP_PROXY_IO_01_053: [ `http_proxy_io_close` while OPENING shall trigger the `on_io_open_complete` callback with `IO_OPEN_CANCELLED`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 790 | http_proxy_io_instance->http_proxy_io_state = HTTP_PROXY_IO_STATE_CLOSED; |
XinZhangMS | 0:f7f1f0d76dd6 | 791 | (void)xio_close(http_proxy_io_instance->underlying_io, NULL, NULL); |
XinZhangMS | 0:f7f1f0d76dd6 | 792 | http_proxy_io_instance->on_io_open_complete(http_proxy_io_instance->on_io_open_complete_context, IO_OPEN_CANCELLED); |
XinZhangMS | 0:f7f1f0d76dd6 | 793 | |
XinZhangMS | 0:f7f1f0d76dd6 | 794 | /* Codes_SRS_HTTP_PROXY_IO_01_022: [ `http_proxy_io_close` shall close the HTTP proxy IO and on success it shall return 0. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 795 | result = 0; |
XinZhangMS | 0:f7f1f0d76dd6 | 796 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 797 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 798 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 799 | HTTP_PROXY_IO_STATE previous_state = http_proxy_io_instance->http_proxy_io_state; |
XinZhangMS | 0:f7f1f0d76dd6 | 800 | |
XinZhangMS | 0:f7f1f0d76dd6 | 801 | http_proxy_io_instance->http_proxy_io_state = HTTP_PROXY_IO_STATE_CLOSING; |
XinZhangMS | 0:f7f1f0d76dd6 | 802 | |
XinZhangMS | 0:f7f1f0d76dd6 | 803 | /* Codes_SRS_HTTP_PROXY_IO_01_026: [ The `on_io_close_complete` and `on_io_close_complete_context` arguments shall be saved for later use. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 804 | http_proxy_io_instance->on_io_close_complete = on_io_close_complete; |
XinZhangMS | 0:f7f1f0d76dd6 | 805 | http_proxy_io_instance->on_io_close_complete_context = on_io_close_complete_context; |
XinZhangMS | 0:f7f1f0d76dd6 | 806 | |
XinZhangMS | 0:f7f1f0d76dd6 | 807 | /* Codes_SRS_HTTP_PROXY_IO_01_024: [ `http_proxy_io_close` shall close the underlying IO by calling `xio_close` on the IO handle create in `http_proxy_io_create`, while passing to it the `on_underlying_io_close_complete` callback. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 808 | if (xio_close(http_proxy_io_instance->underlying_io, on_underlying_io_close_complete, http_proxy_io_instance) != 0) |
XinZhangMS | 0:f7f1f0d76dd6 | 809 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 810 | /* Codes_SRS_HTTP_PROXY_IO_01_025: [ If `xio_close` fails, `http_proxy_io_close` shall fail and return a non-zero value. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 811 | result = __LINE__; |
XinZhangMS | 0:f7f1f0d76dd6 | 812 | http_proxy_io_instance->http_proxy_io_state = previous_state; |
XinZhangMS | 0:f7f1f0d76dd6 | 813 | LogError("Cannot close underlying IO."); |
XinZhangMS | 0:f7f1f0d76dd6 | 814 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 815 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 816 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 817 | /* Codes_SRS_HTTP_PROXY_IO_01_022: [ `http_proxy_io_close` shall close the HTTP proxy IO and on success it shall return 0. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 818 | result = 0; |
XinZhangMS | 0:f7f1f0d76dd6 | 819 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 820 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 821 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 822 | |
XinZhangMS | 0:f7f1f0d76dd6 | 823 | return result; |
XinZhangMS | 0:f7f1f0d76dd6 | 824 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 825 | |
XinZhangMS | 0:f7f1f0d76dd6 | 826 | static int http_proxy_io_send(CONCRETE_IO_HANDLE http_proxy_io, const void* buffer, size_t size, ON_SEND_COMPLETE on_send_complete, void* on_send_complete_context) |
XinZhangMS | 0:f7f1f0d76dd6 | 827 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 828 | int result; |
XinZhangMS | 0:f7f1f0d76dd6 | 829 | |
XinZhangMS | 0:f7f1f0d76dd6 | 830 | /* Codes_SRS_HTTP_PROXY_IO_01_032: [ `on_send_complete` shall be allowed to be NULL. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 831 | /* Codes_SRS_HTTP_PROXY_IO_01_030: [ If any of the arguments `http_proxy_io` or `buffer` is NULL, `http_proxy_io_send` shall fail and return a non-zero value. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 832 | if ((http_proxy_io == NULL) || |
XinZhangMS | 0:f7f1f0d76dd6 | 833 | (buffer == NULL) || |
XinZhangMS | 0:f7f1f0d76dd6 | 834 | /* Codes_SRS_HTTP_PROXY_IO_01_031: [ If `size` is 0, `http_proxy_io_send` shall fail and return a non-zero value. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 835 | (size == 0)) |
XinZhangMS | 0:f7f1f0d76dd6 | 836 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 837 | result = __LINE__; |
XinZhangMS | 0:f7f1f0d76dd6 | 838 | LogError("Bad arguments: http_proxy_io = %p, buffer = %p.", |
XinZhangMS | 0:f7f1f0d76dd6 | 839 | http_proxy_io, buffer); |
XinZhangMS | 0:f7f1f0d76dd6 | 840 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 841 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 842 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 843 | HTTP_PROXY_IO_INSTANCE* http_proxy_io_instance = (HTTP_PROXY_IO_INSTANCE*)http_proxy_io; |
XinZhangMS | 0:f7f1f0d76dd6 | 844 | |
XinZhangMS | 0:f7f1f0d76dd6 | 845 | /* Codes_SRS_HTTP_PROXY_IO_01_034: [ If `http_proxy_io_send` is called when the IO is not open, `http_proxy_io_send` shall fail and return a non-zero value. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 846 | /* Codes_SRS_HTTP_PROXY_IO_01_035: [ If the IO is in an error state (an error was reported through the `on_io_error` callback), `http_proxy_io_send` shall fail and return a non-zero value. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 847 | if (http_proxy_io_instance->http_proxy_io_state != HTTP_PROXY_IO_STATE_OPEN) |
XinZhangMS | 0:f7f1f0d76dd6 | 848 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 849 | result = __LINE__; |
XinZhangMS | 0:f7f1f0d76dd6 | 850 | LogError("Invalid HTTP proxy IO state. Expected state is HTTP_PROXY_IO_STATE_OPEN."); |
XinZhangMS | 0:f7f1f0d76dd6 | 851 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 852 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 853 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 854 | /* Codes_SRS_HTTP_PROXY_IO_01_033: [ `http_proxy_io_send` shall send the bytes by calling `xio_send` on the underlying IO created in `http_proxy_io_create` and passing `buffer` and `size` as arguments. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 855 | if (xio_send(http_proxy_io_instance->underlying_io, buffer, size, on_send_complete, on_send_complete_context) != 0) |
XinZhangMS | 0:f7f1f0d76dd6 | 856 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 857 | /* Codes_SRS_HTTP_PROXY_IO_01_055: [ If `xio_send` fails, `http_proxy_io_send` shall fail and return a non-zero value. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 858 | result = __LINE__; |
XinZhangMS | 0:f7f1f0d76dd6 | 859 | LogError("Underlying xio_send failed."); |
XinZhangMS | 0:f7f1f0d76dd6 | 860 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 861 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 862 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 863 | /* Codes_SRS_HTTP_PROXY_IO_01_029: [ `http_proxy_io_send` shall send the `size` bytes pointed to by `buffer` and on success it shall return 0. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 864 | result = 0; |
XinZhangMS | 0:f7f1f0d76dd6 | 865 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 866 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 867 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 868 | |
XinZhangMS | 0:f7f1f0d76dd6 | 869 | return result; |
XinZhangMS | 0:f7f1f0d76dd6 | 870 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 871 | |
XinZhangMS | 0:f7f1f0d76dd6 | 872 | static void http_proxy_io_dowork(CONCRETE_IO_HANDLE http_proxy_io) |
XinZhangMS | 0:f7f1f0d76dd6 | 873 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 874 | if (http_proxy_io == NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 875 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 876 | /* Codes_SRS_HTTP_PROXY_IO_01_038: [ If the `http_proxy_io` argument is NULL, `http_proxy_io_dowork` shall do nothing. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 877 | LogError("NULL http_proxy_io."); |
XinZhangMS | 0:f7f1f0d76dd6 | 878 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 879 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 880 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 881 | HTTP_PROXY_IO_INSTANCE* http_proxy_io_instance = (HTTP_PROXY_IO_INSTANCE*)http_proxy_io; |
XinZhangMS | 0:f7f1f0d76dd6 | 882 | |
XinZhangMS | 0:f7f1f0d76dd6 | 883 | if (http_proxy_io_instance->http_proxy_io_state != HTTP_PROXY_IO_STATE_CLOSED) |
XinZhangMS | 0:f7f1f0d76dd6 | 884 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 885 | /* Codes_SRS_HTTP_PROXY_IO_01_037: [ `http_proxy_io_dowork` shall call `xio_dowork` on the underlying IO created in `http_proxy_io_create`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 886 | xio_dowork(http_proxy_io_instance->underlying_io); |
XinZhangMS | 0:f7f1f0d76dd6 | 887 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 888 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 889 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 890 | |
XinZhangMS | 0:f7f1f0d76dd6 | 891 | static int http_proxy_io_set_option(CONCRETE_IO_HANDLE http_proxy_io, const char* option_name, const void* value) |
XinZhangMS | 0:f7f1f0d76dd6 | 892 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 893 | int result; |
XinZhangMS | 0:f7f1f0d76dd6 | 894 | |
XinZhangMS | 0:f7f1f0d76dd6 | 895 | if ((http_proxy_io == NULL) || (option_name == NULL)) |
XinZhangMS | 0:f7f1f0d76dd6 | 896 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 897 | /* Codes_SRS_HTTP_PROXY_IO_01_040: [ If any of the arguments `http_proxy_io` or `option_name` is NULL, `http_proxy_io_set_option` shall return a non-zero value. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 898 | LogError("Bad arguments: http_proxy_io = %p, option_name = %p", |
XinZhangMS | 0:f7f1f0d76dd6 | 899 | http_proxy_io, option_name); |
XinZhangMS | 0:f7f1f0d76dd6 | 900 | result = __LINE__; |
XinZhangMS | 0:f7f1f0d76dd6 | 901 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 902 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 903 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 904 | HTTP_PROXY_IO_INSTANCE* http_proxy_io_instance = (HTTP_PROXY_IO_INSTANCE*)http_proxy_io; |
XinZhangMS | 0:f7f1f0d76dd6 | 905 | |
XinZhangMS | 0:f7f1f0d76dd6 | 906 | /* Codes_SRS_HTTP_PROXY_IO_01_045: [ None. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 907 | |
XinZhangMS | 0:f7f1f0d76dd6 | 908 | /* Codes_SRS_HTTP_PROXY_IO_01_043: [ If the `option_name` argument indicates an option that is not handled by `http_proxy_io_set_option`, then `xio_setoption` shall be called on the underlying IO created in `http_proxy_io_create`, passing the option name and value to it. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 909 | /* Codes_SRS_HTTP_PROXY_IO_01_056: [ The `value` argument shall be allowed to be NULL. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 910 | if (xio_setoption(http_proxy_io_instance->underlying_io, option_name, value) != 0) |
XinZhangMS | 0:f7f1f0d76dd6 | 911 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 912 | /* Codes_SRS_HTTP_PROXY_IO_01_044: [ if `xio_setoption` fails, `http_proxy_io_set_option` shall return a non-zero value. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 913 | LogError("Unrecognized option"); |
XinZhangMS | 0:f7f1f0d76dd6 | 914 | result = __LINE__; |
XinZhangMS | 0:f7f1f0d76dd6 | 915 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 916 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 917 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 918 | /* Codes_SRS_HTTP_PROXY_IO_01_042: [ If the option was handled by `http_proxy_io_set_option` or the underlying IO, then `http_proxy_io_set_option` shall return 0. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 919 | result = 0; |
XinZhangMS | 0:f7f1f0d76dd6 | 920 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 921 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 922 | |
XinZhangMS | 0:f7f1f0d76dd6 | 923 | return result; |
XinZhangMS | 0:f7f1f0d76dd6 | 924 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 925 | |
XinZhangMS | 0:f7f1f0d76dd6 | 926 | static OPTIONHANDLER_HANDLE http_proxy_io_retrieve_options(CONCRETE_IO_HANDLE http_proxy_io) |
XinZhangMS | 0:f7f1f0d76dd6 | 927 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 928 | OPTIONHANDLER_HANDLE result; |
XinZhangMS | 0:f7f1f0d76dd6 | 929 | |
XinZhangMS | 0:f7f1f0d76dd6 | 930 | if (http_proxy_io == NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 931 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 932 | /* Codes_SRS_HTTP_PROXY_IO_01_047: [ If the parameter `http_proxy_io` is NULL then `http_proxy_io_retrieve_options` shall fail and return NULL. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 933 | LogError("invalid parameter detected: CONCRETE_IO_HANDLE handle=%p", http_proxy_io); |
XinZhangMS | 0:f7f1f0d76dd6 | 934 | result = NULL; |
XinZhangMS | 0:f7f1f0d76dd6 | 935 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 936 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 937 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 938 | HTTP_PROXY_IO_INSTANCE* http_proxy_io_instance = (HTTP_PROXY_IO_INSTANCE*)http_proxy_io; |
XinZhangMS | 0:f7f1f0d76dd6 | 939 | |
XinZhangMS | 0:f7f1f0d76dd6 | 940 | /* Codes_SRS_HTTP_PROXY_IO_01_046: [ `http_proxy_io_retrieve_options` shall return an `OPTIONHANDLER_HANDLE` obtained by calling `xio_retrieveoptions` on the underlying IO created in `http_proxy_io_create`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 941 | result = xio_retrieveoptions(http_proxy_io_instance->underlying_io); |
XinZhangMS | 0:f7f1f0d76dd6 | 942 | if (result == NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 943 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 944 | /* Codes_SRS_HTTP_PROXY_IO_01_048: [ If `xio_retrieveoptions` fails, `http_proxy_io_retrieve_options` shall return NULL. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 945 | LogError("unable to create option handler"); |
XinZhangMS | 0:f7f1f0d76dd6 | 946 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 947 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 948 | return result; |
XinZhangMS | 0:f7f1f0d76dd6 | 949 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 950 | |
XinZhangMS | 0:f7f1f0d76dd6 | 951 | static const IO_INTERFACE_DESCRIPTION http_proxy_io_interface_description = |
XinZhangMS | 0:f7f1f0d76dd6 | 952 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 953 | http_proxy_io_retrieve_options, |
XinZhangMS | 0:f7f1f0d76dd6 | 954 | http_proxy_io_create, |
XinZhangMS | 0:f7f1f0d76dd6 | 955 | http_proxy_io_destroy, |
XinZhangMS | 0:f7f1f0d76dd6 | 956 | http_proxy_io_open, |
XinZhangMS | 0:f7f1f0d76dd6 | 957 | http_proxy_io_close, |
XinZhangMS | 0:f7f1f0d76dd6 | 958 | http_proxy_io_send, |
XinZhangMS | 0:f7f1f0d76dd6 | 959 | http_proxy_io_dowork, |
XinZhangMS | 0:f7f1f0d76dd6 | 960 | http_proxy_io_set_option |
XinZhangMS | 0:f7f1f0d76dd6 | 961 | }; |
XinZhangMS | 0:f7f1f0d76dd6 | 962 | |
XinZhangMS | 0:f7f1f0d76dd6 | 963 | const IO_INTERFACE_DESCRIPTION* http_proxy_io_get_interface_description(void) |
XinZhangMS | 0:f7f1f0d76dd6 | 964 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 965 | /* Codes_SRS_HTTP_PROXY_IO_01_049: [ `http_proxy_io_get_interface_description` shall return a pointer to an `IO_INTERFACE_DESCRIPTION` structure that contains pointers to the functions: `http_proxy_io_retrieve_options`, `http_proxy_io_retrieve_create`, `http_proxy_io_destroy`, `http_proxy_io_open`, `http_proxy_io_close`, `http_proxy_io_send` and `http_proxy_io_dowork`. ]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 966 | return &http_proxy_io_interface_description; |
XinZhangMS | 0:f7f1f0d76dd6 | 967 | } |