Skip to content

Instantly share code, notes, and snippets.

@andrewabest
Created February 7, 2015 04:10
Show Gist options
  • Save andrewabest/8300674785c84e139263 to your computer and use it in GitHub Desktop.
Save andrewabest/8300674785c84e139263 to your computer and use it in GitHub Desktop.
Example Proxy Handling from ServiceBus
// Generated by .NET Reflector from C:\projects\nextgen\packages\WindowsAzure.ServiceBus.2.1.4.0\lib\net40-full\Microsoft.ServiceBus.dll
namespace Microsoft.ServiceBus
{
using Microsoft.ServiceBus.Common;
using Microsoft.ServiceBus.Tracing;
using System;
using System.Globalization;
using System.IO;
using System.Net;
using System.Net.Cache;
using System.Net.Security;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.Text;
internal class WebStream : CompositeDuplexStream
{
private const string BasicAuthType = "basic";
private readonly string connectionGroupId;
private static bool customizedCertificateValidatorAdded;
private const string DigestAuthType = "digest";
private volatile bool disposed;
private HttpWebRequest downstreamRequest;
private readonly Uri factoryEndpointUri;
private const string KerberosAuthType = "kerberos";
private static readonly TimeSpan NaglingDelay = TimeSpan.FromMilliseconds(10.0);
private const string NtlmAuthType = "ntlm";
private const int PingFrequency = 0x1388;
private ProxyAuthMode proxyAuthMode;
private readonly Uri sbUri;
private ServicePoint sessionServicePoint;
private volatile bool shutdownRead;
private volatile bool shutdownWrite;
private readonly object thisLock;
private const int ThrottleCapacity = 0x19;
private const int TimeoutForHttpTestingInMiliSecond = 0x7530;
private readonly int timeoutForUpDownRequestInMiliSecond;
private HttpWebRequest upstreamRequest;
private readonly string webSocketRole;
private WebStream(Uri factoryEndpointUri, string webSocketRole, EventTraceActivity activity) : base(activity)
{
this.timeoutForUpDownRequestInMiliSecond = -1;
this.factoryEndpointUri = factoryEndpointUri;
this.webSocketRole = webSocketRole;
this.connectionGroupId = "WebStream" + Guid.NewGuid().ToString();
this.thisLock = new object();
UriBuilder builder = new UriBuilder(this.factoryEndpointUri);
if (factoryEndpointUri.Scheme == Uri.UriSchemeHttps)
{
builder.Scheme = Uri.UriSchemeHttps;
builder.Port = RelayEnvironment.RelayHttpsPort;
}
else
{
builder.Scheme = Uri.UriSchemeHttp;
builder.Port = RelayEnvironment.RelayHttpPort;
this.timeoutForUpDownRequestInMiliSecond = 0x7530;
}
this.factoryEndpointUri = builder.Uri;
this.sbUri = this.factoryEndpointUri;
}
public WebStream(Uri factoryEndpointUri, string webSocketRole, bool useHttpsMode, EventTraceActivity activity, Uri sbUri) : base(activity)
{
this.timeoutForUpDownRequestInMiliSecond = -1;
this.factoryEndpointUri = factoryEndpointUri;
this.webSocketRole = webSocketRole;
this.connectionGroupId = "WebStream" + Guid.NewGuid().ToString();
this.thisLock = new object();
Exception lastException = null;
int num = 5;
if (this.factoryEndpointUri.Scheme == "sb")
{
UriBuilder builder = new UriBuilder(this.factoryEndpointUri);
if (useHttpsMode)
{
builder.Scheme = Uri.UriSchemeHttps;
builder.Port = RelayEnvironment.RelayHttpsPort;
}
else
{
builder.Scheme = Uri.UriSchemeHttp;
builder.Port = RelayEnvironment.RelayHttpPort;
}
this.factoryEndpointUri = builder.Uri;
}
this.sbUri = sbUri;
while (true)
{
Action action = null;
Action action2 = null;
int retries = num - 1;
try
{
if (action == null)
{
action = () => MessagingClientEtwProvider.Provider.WebStreamConnecting(this.Activity, this.factoryEndpointUri.AbsoluteUri, this.sbUri.AbsoluteUri, retries);
}
MessagingClientEtwProvider.TraceClient(action);
if (this.Connect())
{
if (action2 == null)
{
action2 = () => MessagingClientEtwProvider.Provider.WebStreamConnectCompleted(this.Activity, this.factoryEndpointUri.AbsoluteUri, this.sbUri.AbsoluteUri, retries);
}
MessagingClientEtwProvider.TraceClient(action2);
return;
}
}
catch (WebException exception)
{
if (Fx.IsFatal(exception))
{
throw;
}
string str = CloseResponseInWebException(exception);
lastException = new CommunicationException(exception.Message + str, exception);
}
catch (Exception exception2)
{
if (Fx.IsFatal(exception2))
{
throw;
}
lastException = exception2;
}
MessagingClientEtwProvider.TraceClient(() => MessagingClientEtwProvider.Provider.WebStreamConnectFailed(this.Activity, this.factoryEndpointUri.AbsoluteUri, this.sbUri.AbsoluteUri, retries, lastException.ToString()));
this.Reset();
this.disposed = false;
if (--num <= 0)
{
this.disposed = true;
throw Fx.Exception.AsError(new CommunicationException(SRClient.HTTPConnectivityMode, lastException), null);
}
}
}
public override void Close()
{
MessagingClientEtwProvider.TraceClient(() => MessagingClientEtwProvider.Provider.WebStreamClose(base.Activity, this.factoryEndpointUri.AbsoluteUri, this.sbUri.AbsoluteUri));
base.Close();
}
private static string CloseResponseInWebException(Exception e)
{
WebException exception = e as WebException;
if ((exception != null) && (exception.Response != null))
{
try
{
using (WebResponse response = exception.Response)
{
using (Stream stream = response.GetResponseStream())
{
using (StreamReader reader = new StreamReader(stream))
{
return (" -- Response:" + reader.ReadToEnd());
}
}
}
}
catch (Exception exception2)
{
if (Fx.IsFatal(exception2))
{
throw;
}
Fx.Exception.TraceHandled(e, "WebStream.CloseResponseInWebException", null);
}
}
return string.Empty;
}
private void ConfigurePreauthorizationRequest(HttpWebRequest request, ProxyAuthMode authMode)
{
switch (authMode)
{
case ProxyAuthMode.Kerberos:
request.PreAuthenticate = true;
request.UnsafeAuthenticatedConnectionSharing = true;
return;
case ProxyAuthMode.Ntlm:
request.UnsafeAuthenticatedConnectionSharing = true;
return;
}
}
private void ConfigureProxy(HttpWebRequest request, ProxyAuthMode mode)
{
IWebProxy proxy = request.Proxy;
Uri uriPrefix = request.Proxy.GetProxy(request.RequestUri);
switch (mode)
{
case ProxyAuthMode.None:
request.Proxy = new ForcedCredentialWebProxy(proxy, null);
return;
case ProxyAuthMode.Kerberos:
{
CredentialCache credentials = new CredentialCache();
credentials.Add(uriPrefix, "kerberos", proxy.Credentials.GetCredential(uriPrefix, "kerberos"));
request.Proxy = new ForcedCredentialWebProxy(proxy, credentials);
request.PreAuthenticate = true;
return;
}
case ProxyAuthMode.Ntlm:
{
CredentialCache cache2 = new CredentialCache();
cache2.Add(uriPrefix, "ntlm", proxy.Credentials.GetCredential(uriPrefix, "ntlm"));
request.Proxy = new ForcedCredentialWebProxy(proxy, cache2);
return;
}
case ProxyAuthMode.Other:
{
CredentialCache cache3 = new CredentialCache();
cache3.Add(uriPrefix, "basic", proxy.Credentials.GetCredential(uriPrefix, "basic"));
cache3.Add(uriPrefix, "digest", proxy.Credentials.GetCredential(uriPrefix, "digest"));
request.Proxy = new ForcedCredentialWebProxy(proxy, cache3);
return;
}
}
}
private bool Connect()
{
Uri uri;
Uri uri2;
this.CreateSession(out uri, out uri2);
this.StartSession(uri, uri2);
if (uri.Scheme == Uri.UriSchemeHttp)
{
return this.VerifySession();
}
return true;
}
private PumpStream CreateDownStreamRequest(Uri endpointLocation)
{
PumpStream stream4;
try
{
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(endpointLocation);
request.Method = "GET";
request.ConnectionGroupName = this.connectionGroupId;
request.SendChunked = false;
request.Timeout = this.timeoutForUpDownRequestInMiliSecond;
request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);
request.Headers.Add("X-WSCONNECT", this.webSocketRole);
request.Headers.Add("X-PROCESS-AT", "http://schemas.microsoft.com/netservices/2009/05/servicebus/connect/roles/relay");
this.ConfigureProxy(request, this.proxyAuthMode);
request.ServicePoint.UseNagleAlgorithm = false;
request.ServicePoint.Expect100Continue = false;
request.ServicePoint.ConnectionLimit = 0x800;
this.downstreamRequest = request;
Stream responseStream = ((HttpWebResponse) request.GetResponse()).GetResponseStream();
ThrottledPipeStream output = new ThrottledPipeStream(0x19, NaglingDelay);
FramingInputPump pump = new FramingInputPump(new BufferRead(responseStream.Read), new BufferWrite(output.Write), new Action(output.WriteEndOfStream), base.Activity, this.factoryEndpointUri);
ReadPumpStream stream3 = new ReadPumpStream(responseStream, output, pump) {
PumpCompletedEvent = new Action(this.OnReadStreamCompleted)
};
stream3.BeginRunPump();
stream4 = stream3;
}
catch (Exception exception)
{
if (Fx.IsFatal(exception))
{
throw;
}
throw Fx.Exception.AsError(new CommunicationException(SRClient.DownstreamConnection, exception), null);
}
return stream4;
}
private void CreateSession(out Uri endpointLocation1, out Uri endpointLocation2)
{
ProxyAuthMode[] modeArray2 = new ProxyAuthMode[4];
modeArray2[1] = ProxyAuthMode.Kerberos;
modeArray2[2] = ProxyAuthMode.Ntlm;
modeArray2[3] = ProxyAuthMode.Other;
ProxyAuthMode[] modeArray = modeArray2;
this.proxyAuthMode = ProxyAuthMode.None;
string str = string.Empty;
foreach (ProxyAuthMode mode in modeArray)
{
switch (mode)
{
case ProxyAuthMode.Kerberos:
{
if (str.Contains("KERBEROS"))
{
break;
}
continue;
}
case ProxyAuthMode.Ntlm:
if (!str.Contains("NTLM"))
{
continue;
}
break;
}
try
{
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(this.factoryEndpointUri);
request.KeepAlive = false;
request.Method = "POST";
request.ContentType = "text/plain";
request.Headers.Add("X-WSCREATE", this.webSocketRole);
request.Headers.Add("X-PROCESS-AT", "http://schemas.microsoft.com/netservices/2009/05/servicebus/connect/roles/relay");
this.ConfigureProxy(request, mode);
request.ServicePoint.ConnectionLimit = 0x800;
using (Stream stream = request.GetRequestStream())
{
using (StreamWriter writer = new StreamWriter(stream, Encoding.UTF8))
{
writer.Write(string.Empty);
writer.Flush();
}
}
HttpWebResponse response = (HttpWebResponse) request.GetResponse();
if (((response.StatusCode != HttpStatusCode.Created) || (response.Headers["X-WSENDPT1"] == null)) || (response.Headers["X-WSENDPT2"] == null))
{
throw Fx.Exception.AsWarning(new CommunicationException(SRClient.FaultyEndpointResponse), null);
}
if (!Uri.TryCreate(response.Headers["X-WSENDPT1"], UriKind.Absolute, out endpointLocation1))
{
throw Fx.Exception.AsWarning(new CommunicationException(SRClient.URIEndpoint), null);
}
if (!Uri.TryCreate(response.Headers["X-WSENDPT2"], UriKind.Absolute, out endpointLocation2))
{
throw Fx.Exception.AsWarning(new CommunicationException(SRClient.URIEndpoint), null);
}
response.Close();
this.proxyAuthMode = mode;
return;
}
catch (WebException exception)
{
HttpWebResponse response2 = exception.Response as HttpWebResponse;
if ((response2 != null) && (response2.StatusCode == HttpStatusCode.ProxyAuthenticationRequired))
{
str = response2.Headers["Proxy-Authenticate"].ToUpperInvariant();
}
else
{
string str2 = CloseResponseInWebException(exception);
throw Fx.Exception.AsWarning(new CommunicationException(SRClient.FactoryEndpoint + str2, exception), null);
}
}
catch (Exception exception2)
{
if (Fx.IsFatal(exception2))
{
throw;
}
throw Fx.Exception.AsError(new CommunicationException(SRClient.FactoryEndpoint, exception2), null);
}
}
throw Fx.Exception.AsError(new CommunicationException(string.Format(CultureInfo.InvariantCulture, "Failed to authenticate with proxy supporting modes '{0}'.", new object[] { str })), null);
}
private PumpStream CreateUpStreamRequest(Uri endpointLocation)
{
PumpStream stream4;
try
{
this.PreauthorizeUpStreamRequestIfNeeded(endpointLocation, this.proxyAuthMode);
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(endpointLocation);
request.Method = "POST";
request.ConnectionGroupName = this.connectionGroupId;
request.SendChunked = true;
request.Timeout = this.timeoutForUpDownRequestInMiliSecond;
request.ServicePoint.ConnectionLimit = 0x800;
if ((endpointLocation.Scheme == Uri.UriSchemeHttps) && (request.ServicePoint.ProtocolVersion != HttpVersion.Version11))
{
try
{
typeof(ServicePoint).GetProperty("HttpBehaviour", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(request.ServicePoint, (byte) 0, null);
}
catch (Exception exception)
{
if (Fx.IsFatal(exception))
{
throw;
}
throw Fx.Exception.AsError(new CommunicationException(SRClient.UpstreamConnection, exception), null);
}
}
request.ServicePoint.UseNagleAlgorithm = false;
request.ServicePoint.Expect100Continue = false;
request.ContentType = "application/octet-stream";
request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);
request.AllowWriteStreamBuffering = false;
request.Headers.Add("X-WSCONNECT", this.webSocketRole);
request.Headers.Add("X-PROCESS-AT", "http://schemas.microsoft.com/netservices/2009/05/servicebus/connect/roles/relay");
this.ConfigureProxy(request, this.proxyAuthMode);
this.ConfigurePreauthorizationRequest(request, this.proxyAuthMode);
request.ServicePoint.UseNagleAlgorithm = false;
request.ServicePoint.Expect100Continue = false;
request.ServicePoint.ConnectionLimit = 0x800;
this.sessionServicePoint = request.ServicePoint;
this.upstreamRequest = request;
Stream requestStream = request.GetRequestStream();
ThrottledPipeStream input = new ThrottledPipeStream(0x19, NaglingDelay);
FramingOutputPump pump = new FramingOutputPump(new BufferRead(input.Read), new BufferWrite(requestStream.Write), 0x1388, base.Activity, this.factoryEndpointUri);
PumpStream stream3 = new WritePumpStream(input, requestStream, pump) {
PumpCompletedEvent = new Action(this.OnWriteStreamCompleted)
};
stream3.BeginRunPump();
stream4 = stream3;
}
catch (Exception exception2)
{
if (Fx.IsFatal(exception2))
{
throw;
}
string str = CloseResponseInWebException(exception2);
throw Fx.Exception.AsError(new CommunicationException(SRClient.UpstreamConnection + str, exception2), null);
}
return stream4;
}
private static bool CustomizedCertificateValidator(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
return SecureSocketUtil.CustomizedCertificateValidator(sender, certificate, chain, sslPolicyErrors, RelayEnvironment.RelayHostRootName);
}
protected override void Dispose(bool disposing)
{
MessagingClientEtwProvider.TraceClient(() => MessagingClientEtwProvider.Provider.WebStreamDispose(base.Activity, this.factoryEndpointUri.AbsoluteUri, this.sbUri.AbsoluteUri));
try
{
if (disposing)
{
this.Reset();
if (this.sessionServicePoint != null)
{
this.sessionServicePoint.CloseConnectionGroup(this.connectionGroupId);
}
}
}
finally
{
base.Dispose(disposing);
}
}
public static bool IsSupportingScheme(Uri factoryEndpointUri, out Exception exception)
{
bool flag;
exception = null;
try
{
EventTraceActivity activity = new EventTraceActivity();
using (WebStream stream = new WebStream(factoryEndpointUri, "connection", activity))
{
flag = stream.Connect();
}
}
catch (WebException exception2)
{
string str = CloseResponseInWebException(exception2);
exception = new CommunicationException(exception2.Message + str, exception2);
flag = false;
}
catch (Exception exception3)
{
if (Fx.IsFatal(exception3))
{
throw;
}
exception = exception3;
flag = false;
}
return flag;
}
private void OnReadStreamCompleted()
{
MessagingClientEtwProvider.TraceClient(() => MessagingClientEtwProvider.Provider.WebStreamReadStreamCompleted(base.Activity, this.factoryEndpointUri.AbsoluteUri, this.sbUri.AbsoluteUri));
this.OnStreamCompleted();
}
private void OnStreamCompleted()
{
try
{
this.Reset();
}
catch (WebException exception)
{
Fx.Exception.TraceHandled(exception, string.Concat(new object[] { "WebStream.OnStreamCompleted uri: ", this.factoryEndpointUri.AbsoluteUri, " sbUri: ", this.sbUri }), base.Activity);
}
catch (Exception exception2)
{
if (Fx.IsFatal(exception2))
{
throw;
}
Fx.Exception.TraceHandled(exception2, string.Concat(new object[] { "WebStream.OnStreamCompleted uri: ", this.factoryEndpointUri.AbsoluteUri, " sbUri: ", this.sbUri }), base.Activity);
}
}
private void OnWriteStreamCompleted()
{
MessagingClientEtwProvider.TraceClient(() => MessagingClientEtwProvider.Provider.WebStreamWriteStreamCompleted(base.Activity, this.factoryEndpointUri.AbsoluteUri, this.sbUri.AbsoluteUri));
this.OnStreamCompleted();
}
private void PreauthorizeUpStreamRequestIfNeeded(Uri endpointLocation, ProxyAuthMode authMode)
{
switch (authMode)
{
case ProxyAuthMode.Kerberos:
case ProxyAuthMode.Ntlm:
try
{
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(endpointLocation);
request.Method = "HEAD";
request.ConnectionGroupName = this.connectionGroupId;
request.Timeout = -1;
request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);
request.AllowWriteStreamBuffering = false;
request.Headers.Add("X-WSCONNECT", this.webSocketRole);
request.Headers.Add("X-PROCESS-AT", "http://schemas.microsoft.com/netservices/2009/05/servicebus/connect/roles/relay");
this.ConfigureProxy(request, authMode);
this.ConfigurePreauthorizationRequest(request, authMode);
request.ServicePoint.UseNagleAlgorithm = false;
request.ServicePoint.Expect100Continue = false;
request.GetResponse();
}
catch (WebException)
{
}
return;
}
}
public override int Read(byte[] buffer, int offset, int count)
{
if (!this.shutdownRead)
{
return base.Read(buffer, offset, count);
}
MessagingClientEtwProvider.TraceClient(delegate {
MessagingClientEtwProvider.Provider.WebStreamReturningZero(base.Activity, this.factoryEndpointUri.AbsoluteUri, this.sbUri.AbsoluteUri);
});
return 0;
}
private void Reset()
{
MessagingClientEtwProvider.TraceClient(() => MessagingClientEtwProvider.Provider.WebStreamReset(base.Activity, this.factoryEndpointUri.AbsoluteUri, this.sbUri.AbsoluteUri));
if (!this.disposed)
{
lock (this.thisLock)
{
if (!this.disposed)
{
this.disposed = true;
this.Shutdown();
this.shutdownRead = this.shutdownWrite = false;
}
}
}
}
public override void Shutdown()
{
MessagingClientEtwProvider.TraceClient(() => MessagingClientEtwProvider.Provider.WebStreamShutdown(base.Activity, this.factoryEndpointUri.AbsoluteUri, this.sbUri.AbsoluteUri));
lock (this.thisLock)
{
if (!this.shutdownWrite)
{
this.shutdownWrite = true;
if (this.upstreamRequest != null)
{
this.upstreamRequest.Abort();
this.upstreamRequest = null;
if (base.outputStream != null)
{
((PumpStream) base.outputStream).Shutdown();
base.outputStream = null;
}
}
}
if (!this.shutdownRead)
{
this.shutdownRead = true;
if (this.downstreamRequest != null)
{
this.downstreamRequest.Abort();
this.downstreamRequest = null;
base.inputStream = null;
}
}
}
}
private void StartSession(Uri readEndpoint, Uri writeEndpoint)
{
if ((readEndpoint.Scheme == Uri.UriSchemeHttps) && !customizedCertificateValidatorAdded)
{
customizedCertificateValidatorAdded = true;
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(WebStream.CustomizedCertificateValidator);
}
lock (this.thisLock)
{
this.RemoteReadEndpoint = readEndpoint;
this.RemoteWriteEndpoint = writeEndpoint;
}
base.outputStream = this.CreateUpStreamRequest(writeEndpoint);
base.inputStream = this.CreateDownStreamRequest(readEndpoint);
}
private bool VerifySession()
{
byte[] buffer = new byte[] { 1, 2, 3, 4 };
byte[] buffer2 = new byte[buffer.Length];
int readTimeout = this.ReadTimeout;
int writeTimeout = this.WriteTimeout;
this.ReadTimeout = (int) TimeSpan.FromSeconds(30.0).TotalMilliseconds;
this.WriteTimeout = (int) TimeSpan.FromSeconds(30.0).TotalMilliseconds;
this.Write(buffer, 0, buffer.Length);
if (this.Read(buffer2, 0, buffer2.Length) < buffer2.Length)
{
return false;
}
for (int i = 0; i < buffer.Length; i++)
{
if (buffer[i] != buffer2[i])
{
return false;
}
}
this.Write(buffer, 0, buffer.Length);
if (this.Read(buffer2, 0, buffer2.Length) < buffer2.Length)
{
return false;
}
for (int j = 0; j < buffer.Length; j++)
{
if (buffer[j] != buffer2[j])
{
return false;
}
}
this.ReadTimeout = readTimeout;
this.WriteTimeout = writeTimeout;
return true;
}
public override void Write(byte[] buffer, int offset, int count)
{
if (this.shutdownWrite)
{
throw Fx.Exception.AsWarning(new CommunicationException(SRClient.WebStreamShutdown), null);
}
base.Write(buffer, offset, count);
}
public Uri RemoteReadEndpoint { get; private set; }
public Uri RemoteWriteEndpoint { get; private set; }
private class ForcedCredentialWebProxy : IWebProxy
{
private readonly ICredentials innerCredentials;
private readonly IWebProxy innerProxy;
public ForcedCredentialWebProxy(IWebProxy proxy, ICredentials credentials)
{
this.innerProxy = proxy;
this.innerCredentials = credentials;
}
public Uri GetProxy(Uri destination)
{
return this.innerProxy.GetProxy(destination);
}
public bool IsBypassed(Uri host)
{
return this.innerProxy.IsBypassed(host);
}
public ICredentials Credentials
{
get
{
return this.innerCredentials;
}
set
{
throw Fx.Exception.AsError(new NotImplementedException(), null);
}
}
}
private enum ProxyAuthMode
{
None,
Kerberos,
Ntlm,
Other
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment