in src/Microsoft.Azure.Relay/WebSockets/NetStandard20/WebSocketHandle.Managed.cs [222:304]
private async Task ConnectWithProxyAsync(Uri uri, ClientWebSocketOptions options, Stream stream, CancellationToken cancellationToken)
{
const string successStatusCode = "HTTP/1.1 200";
const string proxyAuthenticationStatusCode = "HTTP/1.1 407";
const string Basic = "Basic ";
const string Digest = "Digest ";
AuthenticationHeaderValue ahv = null;
string statusLine = await SendRequestToProxyAsync(uri, options, stream, ahv, cancellationToken).ConfigureAwait(false);
if (statusLine == successStatusCode)
{
// Proxy connection succeeded.
return;
}
// Proxy requires authentication.
if (statusLine.StartsWith(proxyAuthenticationStatusCode))
{
if (statusLine.Length > proxyAuthenticationStatusCode.Length &&
!char.IsWhiteSpace(statusLine[proxyAuthenticationStatusCode.Length]))
{
throw new WebSocketException(SR.net_webstatus_ConnectFailure);
}
string line;
int contentLength = 0;
while (!string.IsNullOrEmpty((line = await ReadResponseHeaderLineAsync(stream, cancellationToken).ConfigureAwait(false))))
{
if (line.StartsWith("Proxy-Authenticate", StringComparison.OrdinalIgnoreCase))
{
int colon = line.IndexOf(':');
if (colon == -1 || colon == line.Length - 1)
{
throw new WebSocketException(SR.Format(SR.net_WebSockets_InvalidResponseHeader, "Proxy-Authenticate", line));
}
string authenticateString = line.Substring(colon + 1);
string authHeader = GetParameterForScheme(authenticateString, Digest) ?? GetParameterForScheme(authenticateString, Basic);
if (authHeader != null)
{
ahv = AuthenticationHeaderValue.Parse(authHeader);
}
}
else if (line.StartsWith("Content-Length", StringComparison.OrdinalIgnoreCase))
{
int colon = line.IndexOf(':');
if (colon == -1 || colon == line.Length - 1)
{
throw new WebSocketException(SR.Format(SR.net_WebSockets_InvalidResponseHeader, "Content-Length", line));
}
int.TryParse(line.Substring(colon + 1), out contentLength);
}
else if (line.StartsWith("Transfer-Encoding:", StringComparison.OrdinalIgnoreCase))
{
int nextValidIndex = line.IndexOf(':') + 1;
if (nextValidIndex < line.Length && line.SubstringTrim(nextValidIndex).Equals("chunked", StringComparison.OrdinalIgnoreCase))
{
throw new WebSocketException(SR.net_webstatus_ConnectFailure + " " + line);
}
}
}
if (ahv == null)
{
throw new WebSocketException(SR.net_webstatus_ConnectFailure);
}
// Read any response content from proxy.
await ReadResponseContent(stream, contentLength, cancellationToken).ConfigureAwait(false);
// Retry request to proxy with authorization header.
statusLine = await SendRequestToProxyAsync(uri, options, stream, ahv, cancellationToken).ConfigureAwait(false);
if (statusLine == successStatusCode)
{
return;
}
}
// Failed to connect to proxy.
throw new WebSocketException(SR.net_webstatus_ConnectFailure);
}