From 1ef05fe0c38c257e0ddb9c1f169ee62079cfc8e7 Mon Sep 17 00:00:00 2001 From: sta Date: Sat, 19 Jul 2014 21:23:31 +0900 Subject: [PATCH] Enable to connect through the HTTP Proxy server --- Example/Program.cs | 3 ++ websocket-sharp/HttpRequest.cs | 6 ++- websocket-sharp/WebSocket.cs | 70 +++++++++++++++++++++++++++--- websocket-sharp/WebSocketStream.cs | 19 ++++++-- 4 files changed, 87 insertions(+), 11 deletions(-) diff --git a/Example/Program.cs b/Example/Program.cs index 2fcb40c5..c81c3691 100644 --- a/Example/Program.cs +++ b/Example/Program.cs @@ -63,6 +63,9 @@ namespace Example // For HTTP Authentication (Basic/Digest) //ws.SetCredentials ("nobita", "password", false); + // For HTTP Proxy + //ws.SetHttpProxy ("http://localhost:3128", "nobita", "password"); + // Setting Origin header //ws.Origin = "http://echo.websocket.org"; //ws.Origin = "http://localhost:4649"; diff --git a/websocket-sharp/HttpRequest.cs b/websocket-sharp/HttpRequest.cs index b75475ff..4421d98f 100644 --- a/websocket-sharp/HttpRequest.cs +++ b/websocket-sharp/HttpRequest.cs @@ -116,9 +116,11 @@ namespace WebSocketSharp internal static HttpRequest CreateConnectRequest (Uri uri) { - var authority = uri.Authority; + var host = uri.DnsSafeHost; + var port = uri.Port; + var authority = String.Format ("{0}:{1}", host, port); var req = new HttpRequest ("CONNECT", authority); - req.Headers["Host"] = uri.Port == 80 ? uri.DnsSafeHost : authority; + req.Headers["Host"] = port == 80 ? host : authority; return req; } diff --git a/websocket-sharp/WebSocket.cs b/websocket-sharp/WebSocket.cs index 3e4d2bb3..baa2a429 100644 --- a/websocket-sharp/WebSocket.cs +++ b/websocket-sharp/WebSocket.cs @@ -1250,13 +1250,8 @@ namespace WebSocketSharp // As client private void setClientStream () { - var proxy = _proxyUri != null; - _tcpClient = proxy - ? new TcpClient (_proxyUri.DnsSafeHost, _proxyUri.Port) - : new TcpClient (_uri.DnsSafeHost, _uri.Port); - _stream = WebSocketStream.CreateClientStream ( - _tcpClient, proxy, _uri, _proxyCredentials, _secure, _certValidationCallback); + _uri, _proxyUri, _proxyCredentials, _secure, _certValidationCallback, out _tcpClient); } private void startReceiving () @@ -2139,6 +2134,69 @@ namespace WebSocketSharp } } + /// + /// Sets the HTTP Proxy server URL to connect through, and a pair of + /// and for the proxy server authentication (Basic/Digest). + /// + /// + /// A that represents the HTTP Proxy server URL to connect through. + /// + /// + /// A that represents the user name used to authenticate. + /// + /// + /// A that represents the password for + /// used to authenticate. + /// + public void SetHttpProxy (string url, string username, string password) + { + lock (_forConn) { + var msg = checkIfAvailable ("SetHttpProxy", false, false); + if (msg == null) { + if (url.IsNullOrEmpty ()) { + _proxyUri = null; + _proxyCredentials = null; + _logger.Warn ("Proxy url and credentials were set back to the default."); + + return; + } + + Uri uri; + if (!Uri.TryCreate (url, UriKind.Absolute, out uri) || + uri.Scheme != "http" || + uri.Segments.Length > 1) { + msg = "The syntax of proxy url must be 'http://[:]'."; + } + else { + _proxyUri = uri; + + if (username.IsNullOrEmpty ()) { + _proxyCredentials = null; + _logger.Warn ("Proxy credentials was set back to the default."); + + return; + } + + msg = username.Contains (':') || !username.IsText () + ? "'username' contains an invalid character." + : !password.IsNullOrEmpty () && !password.IsText () + ? "'password' contains an invalid character." + : null; + } + } + + if (msg != null) { + _logger.Error (msg); + error (msg); + + return; + } + + _proxyCredentials = new NetworkCredential ( + username, password, String.Format ("{0}:{1}", _uri.DnsSafeHost, _uri.Port)); + } + } + #endregion #region Explicit Interface Implementation diff --git a/websocket-sharp/WebSocketStream.cs b/websocket-sharp/WebSocketStream.cs index bf61a95d..dbed6bc0 100644 --- a/websocket-sharp/WebSocketStream.cs +++ b/websocket-sharp/WebSocketStream.cs @@ -198,13 +198,18 @@ namespace WebSocketSharp #region Internal Methods internal static WebSocketStream CreateClientStream ( - TcpClient tcpClient, - bool proxy, Uri targetUri, + Uri proxyUri, NetworkCredential proxyCredentials, bool secure, - System.Net.Security.RemoteCertificateValidationCallback validationCallback) + System.Net.Security.RemoteCertificateValidationCallback validationCallback, + out TcpClient tcpClient) { + var proxy = proxyUri != null; + tcpClient = proxy + ? new TcpClient (proxyUri.DnsSafeHost, proxyUri.Port) + : new TcpClient (targetUri.DnsSafeHost, targetUri.Port); + var netStream = tcpClient.GetStream (); if (proxy) { var req = HttpRequest.CreateConnectRequest (targetUri); @@ -212,6 +217,14 @@ namespace WebSocketSharp if (res.IsProxyAuthenticationRequired) { var authChal = res.ProxyAuthenticationChallenge; if (authChal != null && proxyCredentials != null) { + if (res.Headers.Contains ("Connection", "close")) { + netStream.Dispose (); + tcpClient.Close (); + + tcpClient = new TcpClient (proxyUri.DnsSafeHost, proxyUri.Port); + netStream = tcpClient.GetStream (); + } + var authRes = new AuthenticationResponse (authChal, proxyCredentials, 0); req.Headers["Proxy-Authorization"] = authRes.ToString (); res = sendHttpRequest (netStream, req, 15000);