source: azure_iot_hub/trunk/azure_iothub/c-utility/src/http_proxy_io.c@ 389

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

ビルドが通るよう更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 50.4 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 <stdbool.h>
7#include <stdint.h>
8#include <limits.h>
9#include <stddef.h>
10#include "azure_c_shared_utility/gballoc.h"
11#include "azure_c_shared_utility/xio.h"
12#include "azure_c_shared_utility/socketio.h"
13#include "azure_c_shared_utility/crt_abstractions.h"
14#include "azure_c_shared_utility/http_proxy_io.h"
15#include "azure_c_shared_utility/azure_base64.h"
16
17typedef enum HTTP_PROXY_IO_STATE_TAG
18{
19 HTTP_PROXY_IO_STATE_CLOSED,
20 HTTP_PROXY_IO_STATE_OPENING_UNDERLYING_IO,
21 HTTP_PROXY_IO_STATE_WAITING_FOR_CONNECT_RESPONSE,
22 HTTP_PROXY_IO_STATE_OPEN,
23 HTTP_PROXY_IO_STATE_CLOSING,
24 HTTP_PROXY_IO_STATE_ERROR
25} HTTP_PROXY_IO_STATE;
26
27typedef struct HTTP_PROXY_IO_INSTANCE_TAG
28{
29 HTTP_PROXY_IO_STATE http_proxy_io_state;
30 ON_BYTES_RECEIVED on_bytes_received;
31 void* on_bytes_received_context;
32 ON_IO_ERROR on_io_error;
33 void* on_io_error_context;
34 ON_IO_OPEN_COMPLETE on_io_open_complete;
35 void* on_io_open_complete_context;
36 ON_IO_CLOSE_COMPLETE on_io_close_complete;
37 void* on_io_close_complete_context;
38 char* hostname;
39 int port;
40 char* proxy_hostname;
41 int proxy_port;
42 char* username;
43 char* password;
44 XIO_HANDLE underlying_io;
45 unsigned char* receive_buffer;
46 size_t receive_buffer_size;
47} HTTP_PROXY_IO_INSTANCE;
48
49static CONCRETE_IO_HANDLE http_proxy_io_create(void* io_create_parameters)
50{
51 HTTP_PROXY_IO_INSTANCE* result;
52
53 if (io_create_parameters == NULL)
54 {
55 /* Codes_SRS_HTTP_PROXY_IO_01_002: [ If io_create_parameters is NULL, http_proxy_io_create shall fail and return NULL. ]*/
56 result = NULL;
57 LogError("NULL io_create_parameters.");
58 }
59 else
60 {
61 /* Codes_SRS_HTTP_PROXY_IO_01_003: [ io_create_parameters shall be used as an HTTP_PROXY_IO_CONFIG*. ]*/
62 HTTP_PROXY_IO_CONFIG* http_proxy_io_config = (HTTP_PROXY_IO_CONFIG*)io_create_parameters;
63 if ((http_proxy_io_config->hostname == NULL) ||
64 (http_proxy_io_config->proxy_hostname == NULL))
65 {
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. ]*/
67 result = NULL;
68 LogError("Bad arguments: hostname = %p, proxy_hostname = %p",
69 http_proxy_io_config->hostname, http_proxy_io_config->proxy_hostname);
70 }
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. ]*/
72 else if (((http_proxy_io_config->username == NULL) && (http_proxy_io_config->password != NULL)) ||
73 ((http_proxy_io_config->username != NULL) && (http_proxy_io_config->password == NULL)))
74 {
75 result = NULL;
76 LogError("Bad arguments: username = %p, password = %p",
77 http_proxy_io_config->username, http_proxy_io_config->password);
78 }
79 else
80 {
81 /* Codes_SRS_HTTP_PROXY_IO_01_001: [ http_proxy_io_create shall create a new instance of the HTTP proxy IO. ]*/
82 result = (HTTP_PROXY_IO_INSTANCE*)malloc(sizeof(HTTP_PROXY_IO_INSTANCE));
83 if (result == NULL)
84 {
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. ]*/
86 LogError("Failed allocating HTTP proxy IO instance.");
87 }
88 else
89 {
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. ]*/
91 /* Codes_SRS_HTTP_PROXY_IO_01_006: [ hostname and proxy_hostname, username and password shall be copied by calling mallocAndStrcpy_s. ]*/
92 if (mallocAndStrcpy_s(&result->hostname, http_proxy_io_config->hostname) != 0)
93 {
94 /* Codes_SRS_HTTP_PROXY_IO_01_007: [ If mallocAndStrcpy_s fails then http_proxy_io_create shall fail and return NULL. ]*/
95 LogError("Failed to copy the hostname.");
96 /* Codes_SRS_HTTP_PROXY_IO_01_008: [ When http_proxy_io_create fails, all allocated resources up to that point shall be freed. ]*/
97 free(result);
98 result = NULL;
99 }
100 else
101 {
102 /* Codes_SRS_HTTP_PROXY_IO_01_006: [ hostname and proxy_hostname, username and password shall be copied by calling mallocAndStrcpy_s. ]*/
103 if (mallocAndStrcpy_s(&result->proxy_hostname, http_proxy_io_config->proxy_hostname) != 0)
104 {
105 /* Codes_SRS_HTTP_PROXY_IO_01_007: [ If mallocAndStrcpy_s fails then http_proxy_io_create shall fail and return NULL. ]*/
106 LogError("Failed to copy the proxy_hostname.");
107 /* Codes_SRS_HTTP_PROXY_IO_01_008: [ When http_proxy_io_create fails, all allocated resources up to that point shall be freed. ]*/
108 free(result->hostname);
109 free(result);
110 result = NULL;
111 }
112 else
113 {
114 result->username = NULL;
115 result->password = NULL;
116
117 /* Codes_SRS_HTTP_PROXY_IO_01_006: [ hostname and proxy_hostname, username and password shall be copied by calling mallocAndStrcpy_s. ]*/
118 /* Codes_SRS_HTTP_PROXY_IO_01_094: [ username and password shall be optional. ]*/
119 if ((http_proxy_io_config->username != NULL) && (mallocAndStrcpy_s(&result->username, http_proxy_io_config->username) != 0))
120 {
121 /* Codes_SRS_HTTP_PROXY_IO_01_007: [ If mallocAndStrcpy_s fails then http_proxy_io_create shall fail and return NULL. ]*/
122 LogError("Failed to copy the username.");
123 /* Codes_SRS_HTTP_PROXY_IO_01_008: [ When http_proxy_io_create fails, all allocated resources up to that point shall be freed. ]*/
124 free(result->proxy_hostname);
125 free(result->hostname);
126 free(result);
127 result = NULL;
128 }
129 else
130 {
131 /* Codes_SRS_HTTP_PROXY_IO_01_006: [ hostname and proxy_hostname, username and password shall be copied by calling mallocAndStrcpy_s. ]*/
132 /* Codes_SRS_HTTP_PROXY_IO_01_094: [ username and password shall be optional. ]*/
133 if ((http_proxy_io_config->password != NULL) && (mallocAndStrcpy_s(&result->password, http_proxy_io_config->password) != 0))
134 {
135 /* Codes_SRS_HTTP_PROXY_IO_01_007: [ If mallocAndStrcpy_s fails then http_proxy_io_create shall fail and return NULL. ]*/
136 LogError("Failed to copy the passowrd.");
137 /* Codes_SRS_HTTP_PROXY_IO_01_008: [ When http_proxy_io_create fails, all allocated resources up to that point shall be freed. ]*/
138 free(result->username);
139 free(result->proxy_hostname);
140 free(result->hostname);
141 free(result);
142 result = NULL;
143 }
144 else
145 {
146 /* Codes_SRS_HTTP_PROXY_IO_01_010: [ - io_interface_description shall be set to the result of socketio_get_interface_description. ]*/
147 const IO_INTERFACE_DESCRIPTION* underlying_io_interface = socketio_get_interface_description();
148 if (underlying_io_interface == NULL)
149 {
150 /* Codes_SRS_HTTP_PROXY_IO_01_050: [ If socketio_get_interface_description fails, http_proxy_io_create shall fail and return NULL. ]*/
151 LogError("Unable to get the socket IO interface description.");
152 /* Codes_SRS_HTTP_PROXY_IO_01_008: [ When http_proxy_io_create fails, all allocated resources up to that point shall be freed. ]*/
153 free(result->password);
154 free(result->username);
155 free(result->proxy_hostname);
156 free(result->hostname);
157 free(result);
158 result = NULL;
159 }
160 else
161 {
162 SOCKETIO_CONFIG socket_io_config;
163
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. ]*/
165 socket_io_config.hostname = http_proxy_io_config->proxy_hostname;
166 socket_io_config.port = http_proxy_io_config->proxy_port;
167 socket_io_config.accepted_socket = NULL;
168
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: ]*/
170 result->underlying_io = xio_create(underlying_io_interface, &socket_io_config);
171 if (result->underlying_io == NULL)
172 {
173 /* Codes_SRS_HTTP_PROXY_IO_01_012: [ If xio_create fails, http_proxy_io_create shall fail and return NULL. ]*/
174 LogError("Unable to create the underlying IO.");
175 /* Codes_SRS_HTTP_PROXY_IO_01_008: [ When http_proxy_io_create fails, all allocated resources up to that point shall be freed. ]*/
176 free(result->password);
177 free(result->username);
178 free(result->proxy_hostname);
179 free(result->hostname);
180 free(result);
181 result = NULL;
182 }
183 else
184 {
185 result->port = http_proxy_io_config->port;
186 result->proxy_port = http_proxy_io_config->proxy_port;
187 result->receive_buffer = NULL;
188 result->receive_buffer_size = 0;
189 result->http_proxy_io_state = HTTP_PROXY_IO_STATE_CLOSED;
190 }
191 }
192 }
193 }
194 }
195 }
196 }
197 }
198 }
199
200 return result;
201}
202
203static void http_proxy_io_destroy(CONCRETE_IO_HANDLE http_proxy_io)
204{
205 if (http_proxy_io == NULL)
206 {
207 /* Codes_SRS_HTTP_PROXY_IO_01_014: [ If http_proxy_io is NULL, http_proxy_io_destroy shall do nothing. ]*/
208 LogError("NULL http_proxy_io.");
209 }
210 else
211 {
212 HTTP_PROXY_IO_INSTANCE* http_proxy_io_instance = (HTTP_PROXY_IO_INSTANCE*)http_proxy_io;
213
214 /* Codes_SRS_HTTP_PROXY_IO_01_013: [ http_proxy_io_destroy shall free the HTTP proxy IO instance indicated by http_proxy_io. ]*/
215 if (http_proxy_io_instance->receive_buffer != NULL)
216 {
217 free(http_proxy_io_instance->receive_buffer);
218 }
219
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. ]*/
221 xio_destroy(http_proxy_io_instance->underlying_io);
222 free(http_proxy_io_instance->hostname);
223 free(http_proxy_io_instance->proxy_hostname);
224 free(http_proxy_io_instance->username);
225 free(http_proxy_io_instance->password);
226 free(http_proxy_io_instance);
227 }
228}
229
230static void indicate_open_complete_error_and_close(HTTP_PROXY_IO_INSTANCE* http_proxy_io_instance)
231{
232 http_proxy_io_instance->http_proxy_io_state = HTTP_PROXY_IO_STATE_CLOSED;
233 (void)xio_close(http_proxy_io_instance->underlying_io, NULL, NULL);
234 http_proxy_io_instance->on_io_open_complete(http_proxy_io_instance->on_io_open_complete_context, IO_OPEN_ERROR);
235}
236
237// This callback usage needs to be either verified and commented or integrated into
238// the state machine.
239static void unchecked_on_send_complete(void* context, IO_SEND_RESULT send_result)
240{
241 (void)context;
242 (void)send_result;
243}
244
245static void on_underlying_io_open_complete(void* context, IO_OPEN_RESULT open_result)
246{
247 if (context == NULL)
248 {
249 /* Codes_SRS_HTTP_PROXY_IO_01_081: [ on_underlying_io_open_complete called with NULL context shall do nothing. ]*/
250 LogError("NULL context in on_underlying_io_open_complete");
251 }
252 else
253 {
254 HTTP_PROXY_IO_INSTANCE* http_proxy_io_instance = (HTTP_PROXY_IO_INSTANCE*)context;
255 switch (http_proxy_io_instance->http_proxy_io_state)
256 {
257 default:
258 LogError("on_underlying_io_open_complete called in an unexpected state.");
259 break;
260
261 case HTTP_PROXY_IO_STATE_CLOSING:
262 case HTTP_PROXY_IO_STATE_OPEN:
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. ]*/
264 http_proxy_io_instance->on_io_error(http_proxy_io_instance->on_io_error_context);
265 break;
266
267 case HTTP_PROXY_IO_STATE_WAITING_FOR_CONNECT_RESPONSE:
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. ]*/
269 LogError("Open complete called again by underlying IO.");
270 indicate_open_complete_error_and_close(http_proxy_io_instance);
271 break;
272
273 case HTTP_PROXY_IO_STATE_OPENING_UNDERLYING_IO:
274 switch (open_result)
275 {
276 default:
277 case IO_OPEN_ERROR:
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. ]*/
279 LogError("Underlying IO open failed");
280 indicate_open_complete_error_and_close(http_proxy_io_instance);
281 break;
282
283 case IO_OPEN_CANCELLED:
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. ]*/
285 LogError("Underlying IO open failed");
286 http_proxy_io_instance->http_proxy_io_state = HTTP_PROXY_IO_STATE_CLOSED;
287 (void)xio_close(http_proxy_io_instance->underlying_io, NULL, NULL);
288 http_proxy_io_instance->on_io_open_complete(http_proxy_io_instance->on_io_open_complete_context, IO_OPEN_CANCELLED);
289 break;
290
291 case IO_OPEN_OK:
292 {
293 STRING_HANDLE encoded_auth_string;
294
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: ]*/
296 http_proxy_io_instance->http_proxy_io_state = HTTP_PROXY_IO_STATE_WAITING_FOR_CONNECT_RESPONSE;
297
298 if (http_proxy_io_instance->username != NULL)
299 {
300 char* plain_auth_string_bytes;
301
302 /* Codes_SRS_HTTP_PROXY_IO_01_060: [ - The value of Proxy-Authorization shall be the constructed according to RFC 2617. ]*/
303 int plain_auth_string_length = (int)(strlen(http_proxy_io_instance->username)+1);
304 if (http_proxy_io_instance->password != NULL)
305 {
306 plain_auth_string_length += (int)strlen(http_proxy_io_instance->password);
307 }
308
309 if (plain_auth_string_length < 0)
310 {
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. ]*/
312 encoded_auth_string = NULL;
313 indicate_open_complete_error_and_close(http_proxy_io_instance);
314 }
315 else
316 {
317 plain_auth_string_bytes = (char*)malloc(plain_auth_string_length + 1);
318 if (plain_auth_string_bytes == NULL)
319 {
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. ]*/
321 encoded_auth_string = NULL;
322 indicate_open_complete_error_and_close(http_proxy_io_instance);
323 }
324 else
325 {
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. ]*/
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. ]*/
328 /* Codes_SRS_HTTP_PROXY_IO_01_093: [ Userids might be case sensitive. ]*/
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)
330 {
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. ]*/
332 encoded_auth_string = NULL;
333 indicate_open_complete_error_and_close(http_proxy_io_instance);
334 }
335 else
336 {
337 /* Codes_SRS_HTTP_PROXY_IO_01_061: [ Encoding to Base64 shall be done by calling Base64_Encode_Bytes. ]*/
338 encoded_auth_string = Azure_Base64_Encode_Bytes((const unsigned char*)plain_auth_string_bytes, plain_auth_string_length);
339 if (encoded_auth_string == NULL)
340 {
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. ]*/
342 LogError("Cannot Base64 encode auth string");
343 indicate_open_complete_error_and_close(http_proxy_io_instance);
344 }
345 }
346
347 free(plain_auth_string_bytes);
348 }
349 }
350 }
351 else
352 {
353 encoded_auth_string = NULL;
354 }
355
356 if ((http_proxy_io_instance->username != NULL) &&
357 (encoded_auth_string == NULL))
358 {
359 LogError("Cannot create authorization header");
360 }
361 else
362 {
363 int connect_request_length;
364 const char* auth_string_payload;
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: ]*/
366 const char request_format[] = "CONNECT %s:%d HTTP/1.1\r\nHost:%s:%d%s%s\r\n\r\n";
367 const char proxy_basic[] = "\r\nProxy-authorization: Basic ";
368 if (http_proxy_io_instance->username != NULL)
369 {
370 auth_string_payload = STRING_c_str(encoded_auth_string);
371 }
372 else
373 {
374 auth_string_payload = "";
375 }
376
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. ]*/
378
379 connect_request_length = (int)(strlen(request_format)+(strlen(http_proxy_io_instance->hostname)*2)+strlen(auth_string_payload)+10);
380 if (http_proxy_io_instance->username != NULL)
381 {
382 connect_request_length += (int)strlen(proxy_basic);
383 }
384
385 if (connect_request_length < 0)
386 {
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. ]*/
388 LogError("Cannot encode the CONNECT request");
389 indicate_open_complete_error_and_close(http_proxy_io_instance);
390 }
391 else
392 {
393 char* connect_request = (char*)malloc(connect_request_length + 1);
394 if (connect_request == NULL)
395 {
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. ]*/
397 LogError("Cannot allocate memory for CONNECT request");
398 indicate_open_complete_error_and_close(http_proxy_io_instance);
399 }
400 else
401 {
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. ]*/
403 connect_request_length = sprintf(connect_request, request_format,
404 http_proxy_io_instance->hostname,
405 http_proxy_io_instance->port,
406 http_proxy_io_instance->hostname,
407 http_proxy_io_instance->port,
408 (http_proxy_io_instance->username != NULL) ? proxy_basic : "",
409 auth_string_payload);
410
411 if (connect_request_length < 0)
412 {
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. ]*/
414 LogError("Cannot encode the CONNECT request");
415 indicate_open_complete_error_and_close(http_proxy_io_instance);
416 }
417 else
418 {
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. ]*/
420 if (xio_send(http_proxy_io_instance->underlying_io, connect_request, connect_request_length, unchecked_on_send_complete, NULL) != 0)
421 {
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. ]*/
423 LogError("Could not send CONNECT request");
424 indicate_open_complete_error_and_close(http_proxy_io_instance);
425 }
426 }
427
428 free(connect_request);
429 }
430 }
431 }
432
433 if (encoded_auth_string != NULL)
434 {
435 STRING_delete(encoded_auth_string);
436 }
437
438 break;
439 }
440 }
441
442 break;
443 }
444 }
445}
446
447static void on_underlying_io_error(void* context)
448{
449 if (context == NULL)
450 {
451 /* Codes_SRS_HTTP_PROXY_IO_01_088: [ on_underlying_io_error called with NULL context shall do nothing. ]*/
452 LogError("NULL context in on_underlying_io_error");
453 }
454 else
455 {
456 HTTP_PROXY_IO_INSTANCE* http_proxy_io_instance = (HTTP_PROXY_IO_INSTANCE*)context;
457
458 switch (http_proxy_io_instance->http_proxy_io_state)
459 {
460 default:
461 LogError("on_underlying_io_error in invalid state");
462 break;
463
464 case HTTP_PROXY_IO_STATE_OPENING_UNDERLYING_IO:
465 case HTTP_PROXY_IO_STATE_WAITING_FOR_CONNECT_RESPONSE:
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. ]*/
467 indicate_open_complete_error_and_close(http_proxy_io_instance);
468 break;
469
470 case HTTP_PROXY_IO_STATE_OPEN:
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. ]*/
472 http_proxy_io_instance->http_proxy_io_state = HTTP_PROXY_IO_STATE_ERROR;
473 http_proxy_io_instance->on_io_error(http_proxy_io_instance->on_io_error_context);
474 break;
475 }
476 }
477}
478
479static void on_underlying_io_close_complete(void* context)
480{
481 if (context == NULL)
482 {
483 /* Cdoes_SRS_HTTP_PROXY_IO_01_084: [ on_underlying_io_close_complete called with NULL context shall do nothing. ]*/
484 LogError("NULL context in on_underlying_io_open_complete");
485 }
486 else
487 {
488 HTTP_PROXY_IO_INSTANCE* http_proxy_io_instance = (HTTP_PROXY_IO_INSTANCE*)context;
489
490 switch (http_proxy_io_instance->http_proxy_io_state)
491 {
492 default:
493 LogError("on_underlying_io_close_complete called in an invalid state");
494 break;
495
496 case HTTP_PROXY_IO_STATE_CLOSING:
497 http_proxy_io_instance->http_proxy_io_state = HTTP_PROXY_IO_STATE_CLOSED;
498
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. ]*/
500 if (http_proxy_io_instance->on_io_close_complete != NULL)
501 {
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. ]*/
503 http_proxy_io_instance->on_io_close_complete(http_proxy_io_instance->on_io_close_complete_context);
504 }
505
506 break;
507 }
508 }
509}
510
511/*the following function does the same as sscanf(pos2, "%d", &sec)*/
512/*this function only exists because some of platforms do not have sscanf. */
513static int ParseStringToDecimal(const char *src, int* dst)
514{
515 int result;
516 char* next;
517
518 (*dst) = (int)strtol(src, &next, 0);
519 if ((src == next) || ((((*dst) == INT_MAX) || ((*dst) == INT_MIN)) && (errno != 0)))
520 {
521 result = __LINE__;
522 }
523 else
524 {
525 result = 0;
526 }
527
528 return result;
529}
530
531/*the following function does the same as sscanf(buf, "HTTP/%*d.%*d %d %*[^\r\n]", &ret) */
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. */
533static int ParseHttpResponse(const char* src, int* dst)
534{
535 int result;
536 static const char HTTPPrefix[] = "HTTP/";
537 bool fail;
538 const char* runPrefix;
539
540 if ((src == NULL) || (dst == NULL))
541 {
542 result = __LINE__;
543 }
544 else
545 {
546 fail = false;
547 runPrefix = HTTPPrefix;
548
549 while ((*runPrefix) != '\0')
550 {
551 if ((*runPrefix) != (*src))
552 {
553 fail = true;
554 break;
555 }
556 src++;
557 runPrefix++;
558 }
559
560 if (!fail)
561 {
562 while ((*src) != '.')
563 {
564 if ((*src) == '\0')
565 {
566 fail = true;
567 break;
568 }
569 src++;
570 }
571 }
572
573 if (!fail)
574 {
575 while ((*src) != ' ')
576 {
577 if ((*src) == '\0')
578 {
579 fail = true;
580 break;
581 }
582 src++;
583 }
584 }
585
586 if (fail)
587 {
588 result = __LINE__;
589 }
590 else
591 {
592 if (ParseStringToDecimal(src, dst) != 0)
593 {
594 result = __LINE__;
595 }
596 else
597 {
598 result = 0;
599 }
600 }
601 }
602
603 return result;
604}
605
606static void on_underlying_io_bytes_received(void* context, const unsigned char* buffer, size_t size)
607{
608 if (context == NULL)
609 {
610 /* Codes_SRS_HTTP_PROXY_IO_01_082: [ on_underlying_io_bytes_received called with NULL context shall do nothing. ]*/
611 LogError("NULL context in on_underlying_io_bytes_received");
612 }
613 else
614 {
615 HTTP_PROXY_IO_INSTANCE* http_proxy_io_instance = (HTTP_PROXY_IO_INSTANCE*)context;
616
617 switch (http_proxy_io_instance->http_proxy_io_state)
618 {
619 default:
620 case HTTP_PROXY_IO_STATE_CLOSING:
621 LogError("Bytes received in invalid state");
622 break;
623
624 case HTTP_PROXY_IO_STATE_OPENING_UNDERLYING_IO:
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. ]*/
626 LogError("Bytes received while opening underlying IO");
627 indicate_open_complete_error_and_close(http_proxy_io_instance);
628 break;
629
630 case HTTP_PROXY_IO_STATE_WAITING_FOR_CONNECT_RESPONSE:
631 {
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. ]*/
633 unsigned char* new_receive_buffer = (unsigned char*)realloc(http_proxy_io_instance->receive_buffer, http_proxy_io_instance->receive_buffer_size + size + 1);
634 if (new_receive_buffer == NULL)
635 {
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. ]*/
637 LogError("Cannot allocate memory for received data");
638 indicate_open_complete_error_and_close(http_proxy_io_instance);
639 }
640 else
641 {
642 http_proxy_io_instance->receive_buffer = new_receive_buffer;
643 memcpy(http_proxy_io_instance->receive_buffer + http_proxy_io_instance->receive_buffer_size, buffer, size);
644 http_proxy_io_instance->receive_buffer_size += size;
645 }
646
647 if (http_proxy_io_instance->receive_buffer_size >= 4)
648 {
649 const char* request_end_ptr;
650
651 http_proxy_io_instance->receive_buffer[http_proxy_io_instance->receive_buffer_size] = 0;
652
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. ]*/
654 if ((http_proxy_io_instance->receive_buffer_size >= 4) &&
655 ((request_end_ptr = strstr((const char*)http_proxy_io_instance->receive_buffer, "\r\n\r\n")) != NULL))
656 {
657 int status_code;
658
659 /* This part should really be done with the HTTPAPI, but that has to be done as a separate step
660 as the HTTPAPI has to expose somehow the underlying IO and currently this would be a too big of a change. */
661
662 if (ParseHttpResponse((const char*)http_proxy_io_instance->receive_buffer, &status_code) != 0)
663 {
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. ]*/
665 LogError("Cannot decode HTTP response");
666 indicate_open_complete_error_and_close(http_proxy_io_instance);
667 }
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. ]*/
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. ]*/
670 else if ((status_code < 200) || (status_code > 299))
671 {
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. ]*/
673 LogError("Bad status (%d) received in CONNECT response", status_code);
674 indicate_open_complete_error_and_close(http_proxy_io_instance);
675 }
676 else
677 {
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);
679
680 /* Codes_SRS_HTTP_PROXY_IO_01_073: [ Once a success status code was parsed, the IO shall be OPEN. ]*/
681 http_proxy_io_instance->http_proxy_io_state = HTTP_PROXY_IO_STATE_OPEN;
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. ]*/
683 http_proxy_io_instance->on_io_open_complete(http_proxy_io_instance->on_io_open_complete_context, IO_OPEN_OK);
684
685 if (length_remaining > 0)
686 {
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. ]*/
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);
689 }
690 }
691 }
692 }
693 break;
694 }
695 case HTTP_PROXY_IO_STATE_OPEN:
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. ]*/
697 http_proxy_io_instance->on_bytes_received(http_proxy_io_instance->on_bytes_received_context, buffer, size);
698 break;
699 }
700 }
701}
702
703static 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)
704{
705 int result;
706
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. ]*/
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. ]*/
709 if ((http_proxy_io == NULL) ||
710 (on_io_open_complete == NULL) ||
711 (on_bytes_received == NULL) ||
712 (on_io_error == NULL))
713 {
714 LogError("Bad arguments: http_proxy_io = %p, on_io_open_complete = %p, on_bytes_received = %p, on_io_error_context = %p.",
715 http_proxy_io,
716 on_io_open_complete,
717 on_bytes_received,
718 on_io_error);
719 result = __LINE__;
720 }
721 else
722 {
723 HTTP_PROXY_IO_INSTANCE* http_proxy_io_instance = (HTTP_PROXY_IO_INSTANCE*)http_proxy_io;
724
725 if (http_proxy_io_instance->http_proxy_io_state != HTTP_PROXY_IO_STATE_CLOSED)
726 {
727 LogError("Invalid tlsio_state. Expected state is HTTP_PROXY_IO_STATE_CLOSED.");
728 result = __LINE__;
729 }
730 else
731 {
732 http_proxy_io_instance->on_bytes_received = on_bytes_received;
733 http_proxy_io_instance->on_bytes_received_context = on_bytes_received_context;
734
735 http_proxy_io_instance->on_io_error = on_io_error;
736 http_proxy_io_instance->on_io_error_context = on_io_error_context;
737
738 http_proxy_io_instance->on_io_open_complete = on_io_open_complete;
739 http_proxy_io_instance->on_io_open_complete_context = on_io_open_complete_context;
740
741 http_proxy_io_instance->http_proxy_io_state = HTTP_PROXY_IO_STATE_OPENING_UNDERLYING_IO;
742
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. ]*/
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)
745 {
746 /* Codes_SRS_HTTP_PROXY_IO_01_020: [ If xio_open fails, then http_proxy_io_open shall return a non-zero value. ]*/
747 http_proxy_io_instance->http_proxy_io_state = HTTP_PROXY_IO_STATE_CLOSED;
748 LogError("Cannot open the underlying IO.");
749 result = __LINE__;
750 }
751 else
752 {
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. ]*/
754 result = 0;
755 }
756 }
757 }
758
759 return result;
760}
761
762static 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)
763{
764 int result = 0;
765
766 /* Codes_SRS_HTTP_PROXY_IO_01_052: [ on_io_close_complete_context shall be allowed to be NULL. ]*/
767 /* Codes_SRS_HTTP_PROXY_IO_01_028: [ on_io_close_complete shall be allowed to be NULL. ]*/
768 if (http_proxy_io == NULL)
769 {
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. ]*/
771 result = __LINE__;
772 LogError("NULL http_proxy_io.");
773 }
774 else
775 {
776 HTTP_PROXY_IO_INSTANCE* http_proxy_io_instance = (HTTP_PROXY_IO_INSTANCE*)http_proxy_io;
777
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. ]*/
779 if ((http_proxy_io_instance->http_proxy_io_state == HTTP_PROXY_IO_STATE_CLOSED) ||
780 /* Codes_SRS_HTTP_PROXY_IO_01_054: [ http_proxy_io_close while OPENING shall fail and return a non-zero value. ]*/
781 (http_proxy_io_instance->http_proxy_io_state == HTTP_PROXY_IO_STATE_CLOSING))
782 {
783 result = __LINE__;
784 LogError("Invalid tlsio_state. Expected state is HTTP_PROXY_IO_STATE_OPEN.");
785 }
786 else if ((http_proxy_io_instance->http_proxy_io_state == HTTP_PROXY_IO_STATE_OPENING_UNDERLYING_IO) ||
787 (http_proxy_io_instance->http_proxy_io_state == HTTP_PROXY_IO_STATE_WAITING_FOR_CONNECT_RESPONSE))
788 {
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. ]*/
790 http_proxy_io_instance->http_proxy_io_state = HTTP_PROXY_IO_STATE_CLOSED;
791 (void)xio_close(http_proxy_io_instance->underlying_io, NULL, NULL);
792 http_proxy_io_instance->on_io_open_complete(http_proxy_io_instance->on_io_open_complete_context, IO_OPEN_CANCELLED);
793
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. ]*/
795 result = 0;
796 }
797 else
798 {
799 HTTP_PROXY_IO_STATE previous_state = http_proxy_io_instance->http_proxy_io_state;
800
801 http_proxy_io_instance->http_proxy_io_state = HTTP_PROXY_IO_STATE_CLOSING;
802
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. ]*/
804 http_proxy_io_instance->on_io_close_complete = on_io_close_complete;
805 http_proxy_io_instance->on_io_close_complete_context = on_io_close_complete_context;
806
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. ]*/
808 if (xio_close(http_proxy_io_instance->underlying_io, on_underlying_io_close_complete, http_proxy_io_instance) != 0)
809 {
810 /* Codes_SRS_HTTP_PROXY_IO_01_025: [ If xio_close fails, http_proxy_io_close shall fail and return a non-zero value. ]*/
811 result = __LINE__;
812 http_proxy_io_instance->http_proxy_io_state = previous_state;
813 LogError("Cannot close underlying IO.");
814 }
815 else
816 {
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. ]*/
818 result = 0;
819 }
820 }
821 }
822
823 return result;
824}
825
826static 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)
827{
828 int result;
829
830 /* Codes_SRS_HTTP_PROXY_IO_01_032: [ on_send_complete shall be allowed to be NULL. ]*/
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. ]*/
832 if ((http_proxy_io == NULL) ||
833 (buffer == NULL) ||
834 /* Codes_SRS_HTTP_PROXY_IO_01_031: [ If size is 0, http_proxy_io_send shall fail and return a non-zero value. ]*/
835 (size == 0))
836 {
837 result = __LINE__;
838 LogError("Bad arguments: http_proxy_io = %p, buffer = %p.",
839 http_proxy_io, buffer);
840 }
841 else
842 {
843 HTTP_PROXY_IO_INSTANCE* http_proxy_io_instance = (HTTP_PROXY_IO_INSTANCE*)http_proxy_io;
844
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. ]*/
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. ]*/
847 if (http_proxy_io_instance->http_proxy_io_state != HTTP_PROXY_IO_STATE_OPEN)
848 {
849 result = __LINE__;
850 LogError("Invalid HTTP proxy IO state. Expected state is HTTP_PROXY_IO_STATE_OPEN.");
851 }
852 else
853 {
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. ]*/
855 if (xio_send(http_proxy_io_instance->underlying_io, buffer, size, on_send_complete, on_send_complete_context) != 0)
856 {
857 /* Codes_SRS_HTTP_PROXY_IO_01_055: [ If xio_send fails, http_proxy_io_send shall fail and return a non-zero value. ]*/
858 result = __LINE__;
859 LogError("Underlying xio_send failed.");
860 }
861 else
862 {
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. ]*/
864 result = 0;
865 }
866 }
867 }
868
869 return result;
870}
871
872static void http_proxy_io_dowork(CONCRETE_IO_HANDLE http_proxy_io)
873{
874 if (http_proxy_io == NULL)
875 {
876 /* Codes_SRS_HTTP_PROXY_IO_01_038: [ If the http_proxy_io argument is NULL, http_proxy_io_dowork shall do nothing. ]*/
877 LogError("NULL http_proxy_io.");
878 }
879 else
880 {
881 HTTP_PROXY_IO_INSTANCE* http_proxy_io_instance = (HTTP_PROXY_IO_INSTANCE*)http_proxy_io;
882
883 if (http_proxy_io_instance->http_proxy_io_state != HTTP_PROXY_IO_STATE_CLOSED)
884 {
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. ]*/
886 xio_dowork(http_proxy_io_instance->underlying_io);
887 }
888 }
889}
890
891static int http_proxy_io_set_option(CONCRETE_IO_HANDLE http_proxy_io, const char* option_name, const void* value)
892{
893 int result;
894
895 if ((http_proxy_io == NULL) || (option_name == NULL))
896 {
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. ]*/
898 LogError("Bad arguments: http_proxy_io = %p, option_name = %p",
899 http_proxy_io, option_name);
900 result = __LINE__;
901 }
902 else
903 {
904 HTTP_PROXY_IO_INSTANCE* http_proxy_io_instance = (HTTP_PROXY_IO_INSTANCE*)http_proxy_io;
905
906 /* Codes_SRS_HTTP_PROXY_IO_01_045: [ None. ]*/
907
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. ]*/
909 /* Codes_SRS_HTTP_PROXY_IO_01_056: [ The value argument shall be allowed to be NULL. ]*/
910 if (xio_setoption(http_proxy_io_instance->underlying_io, option_name, value) != 0)
911 {
912 /* Codes_SRS_HTTP_PROXY_IO_01_044: [ if xio_setoption fails, http_proxy_io_set_option shall return a non-zero value. ]*/
913 LogError("Unrecognized option");
914 result = __LINE__;
915 }
916 else
917 {
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. ]*/
919 result = 0;
920 }
921 }
922
923 return result;
924}
925
926static OPTIONHANDLER_HANDLE http_proxy_io_retrieve_options(CONCRETE_IO_HANDLE http_proxy_io)
927{
928 OPTIONHANDLER_HANDLE result;
929
930 if (http_proxy_io == NULL)
931 {
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. ]*/
933 LogError("invalid parameter detected: CONCRETE_IO_HANDLE handle=%p", http_proxy_io);
934 result = NULL;
935 }
936 else
937 {
938 HTTP_PROXY_IO_INSTANCE* http_proxy_io_instance = (HTTP_PROXY_IO_INSTANCE*)http_proxy_io;
939
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. ]*/
941 result = xio_retrieveoptions(http_proxy_io_instance->underlying_io);
942 if (result == NULL)
943 {
944 /* Codes_SRS_HTTP_PROXY_IO_01_048: [ If xio_retrieveoptions fails, http_proxy_io_retrieve_options shall return NULL. ]*/
945 LogError("unable to create option handler");
946 }
947 }
948 return result;
949}
950
951static const IO_INTERFACE_DESCRIPTION http_proxy_io_interface_description =
952{
953 http_proxy_io_retrieve_options,
954 http_proxy_io_create,
955 http_proxy_io_destroy,
956 http_proxy_io_open,
957 http_proxy_io_close,
958 http_proxy_io_send,
959 http_proxy_io_dowork,
960 http_proxy_io_set_option
961};
962
963const IO_INTERFACE_DESCRIPTION* http_proxy_io_get_interface_description(void)
964{
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. ]*/
966 return &http_proxy_io_interface_description;
967}
Note: See TracBrowser for help on using the repository browser.