in src/http_proxy_io.c [247:451]
static void on_underlying_io_open_complete(void* context, IO_OPEN_RESULT open_result)
{
if (context == NULL)
{
/* Codes_SRS_HTTP_PROXY_IO_01_081: [ on_underlying_io_open_complete called with NULL context shall do nothing. ]*/
LogError("NULL context in on_underlying_io_open_complete");
}
else
{
HTTP_PROXY_IO_INSTANCE* http_proxy_io_instance = (HTTP_PROXY_IO_INSTANCE*)context;
switch (http_proxy_io_instance->http_proxy_io_state)
{
default:
LogError("on_underlying_io_open_complete called in an unexpected state.");
break;
case HTTP_PROXY_IO_STATE_CLOSING:
case HTTP_PROXY_IO_STATE_OPEN:
/* 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. ]*/
http_proxy_io_instance->on_io_error(http_proxy_io_instance->on_io_error_context);
break;
case HTTP_PROXY_IO_STATE_WAITING_FOR_CONNECT_RESPONSE:
/* 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. ]*/
LogError("Open complete called again by underlying IO.");
indicate_open_complete_error_and_close(http_proxy_io_instance);
break;
case HTTP_PROXY_IO_STATE_OPENING_UNDERLYING_IO:
switch (open_result)
{
default:
case IO_OPEN_ERROR:
/* 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. ]*/
LogError("Underlying IO open failed");
indicate_open_complete_error_and_close(http_proxy_io_instance);
break;
case IO_OPEN_CANCELLED:
/* 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. ]*/
LogError("Underlying IO open failed");
http_proxy_io_instance->http_proxy_io_state = HTTP_PROXY_IO_STATE_CLOSED;
(void)xio_close(http_proxy_io_instance->underlying_io, NULL, NULL);
http_proxy_io_instance->on_io_open_complete(http_proxy_io_instance->on_io_open_complete_context, IO_OPEN_CANCELLED);
break;
case IO_OPEN_OK:
{
STRING_HANDLE encoded_auth_string;
/* 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: ]*/
http_proxy_io_instance->http_proxy_io_state = HTTP_PROXY_IO_STATE_WAITING_FOR_CONNECT_RESPONSE;
if (http_proxy_io_instance->username != NULL)
{
char* plain_auth_string_bytes;
/* Codes_SRS_HTTP_PROXY_IO_01_060: [ - The value of Proxy-Authorization shall be the constructed according to RFC 2617. ]*/
int plain_auth_string_length = (int)(strlen(http_proxy_io_instance->username)+1);
if (http_proxy_io_instance->password != NULL)
{
plain_auth_string_length += (int)strlen(http_proxy_io_instance->password);
}
if (plain_auth_string_length < 0)
{
/* 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. ]*/
encoded_auth_string = NULL;
indicate_open_complete_error_and_close(http_proxy_io_instance);
}
else
{
size_t malloc_size = safe_add_size_t((size_t)plain_auth_string_length, 1);
if (malloc_size == SIZE_MAX ||
(plain_auth_string_bytes = (char*)malloc(malloc_size)) == NULL)
{
/* 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. ]*/
encoded_auth_string = NULL;
plain_auth_string_bytes = NULL;
indicate_open_complete_error_and_close(http_proxy_io_instance);
}
else
{
/* 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. ]*/
/* 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. ]*/
/* Codes_SRS_HTTP_PROXY_IO_01_093: [ Userids might be case sensitive. ]*/
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)
{
/* 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. ]*/
encoded_auth_string = NULL;
indicate_open_complete_error_and_close(http_proxy_io_instance);
}
else
{
/* Codes_SRS_HTTP_PROXY_IO_01_061: [ Encoding to Base64 shall be done by calling Azure_Base64_Encode_Bytes. ]*/
encoded_auth_string = Azure_Base64_Encode_Bytes((const unsigned char*)plain_auth_string_bytes, plain_auth_string_length);
if (encoded_auth_string == NULL)
{
/* 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. ]*/
LogError("Cannot Base64 encode auth string");
indicate_open_complete_error_and_close(http_proxy_io_instance);
}
}
free(plain_auth_string_bytes);
}
}
}
else
{
encoded_auth_string = NULL;
}
if (http_proxy_io_instance->hostname == NULL ||
(http_proxy_io_instance->username != NULL && encoded_auth_string == NULL))
{
LogError("Cannot create authorization header");
}
else
{
int connect_request_length;
const char* auth_string_payload;
/* 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: ]*/
const char request_format[] = "CONNECT %s:%d HTTP/1.1\r\nHost:%s:%d%s%s\r\n\r\n";
const char proxy_basic[] = "\r\nProxy-authorization: Basic ";
if (http_proxy_io_instance->username != NULL)
{
auth_string_payload = STRING_c_str(encoded_auth_string);
}
else
{
auth_string_payload = "";
}
/* 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. ]*/
connect_request_length = (int)(strlen(request_format)+(strlen(http_proxy_io_instance->hostname)*2)+strlen(auth_string_payload)+10);
if (http_proxy_io_instance->username != NULL)
{
connect_request_length += (int)strlen(proxy_basic);
}
if (connect_request_length < 0)
{
/* 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. ]*/
LogError("Cannot encode the CONNECT request");
indicate_open_complete_error_and_close(http_proxy_io_instance);
}
else
{
char* connect_request;
size_t malloc_size = safe_add_size_t((size_t)connect_request_length, 1);
if (malloc_size == SIZE_MAX ||
(connect_request = (char*)malloc(malloc_size)) == NULL)
{
/* 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. ]*/
LogError("Cannot allocate memory for CONNECT request");
indicate_open_complete_error_and_close(http_proxy_io_instance);
}
else
{
/* 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. ]*/
connect_request_length = sprintf(connect_request, request_format,
http_proxy_io_instance->hostname,
http_proxy_io_instance->port,
http_proxy_io_instance->hostname,
http_proxy_io_instance->port,
(http_proxy_io_instance->username != NULL) ? proxy_basic : "",
auth_string_payload);
if (connect_request_length < 0)
{
/* 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. ]*/
LogError("Cannot encode the CONNECT request");
indicate_open_complete_error_and_close(http_proxy_io_instance);
}
else
{
/* Codes_SRS_HTTP_PROXY_IO_01_063: [ The request shall be sent by calling xio_send and passing NULL as on_send_complete callback. ]*/
if (xio_send(http_proxy_io_instance->underlying_io, connect_request, connect_request_length, unchecked_on_send_complete, NULL) != 0)
{
/* 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. ]*/
LogError("Could not send CONNECT request");
indicate_open_complete_error_and_close(http_proxy_io_instance);
}
}
free(connect_request);
}
}
}
if (encoded_auth_string != NULL)
{
STRING_delete(encoded_auth_string);
}
break;
}
}
break;
}
}
}