diff --git a/.build/default.ps1 b/.build/default.ps1 index 80b56c775..aee16a027 100644 --- a/.build/default.ps1 +++ b/.build/default.ps1 @@ -56,7 +56,7 @@ Task Restore-Packages { } Task Install-MSBuild { - if(!(Test-Path "${env:ProgramFiles(x86)}\MSBuild\12.0\Bin\msbuild.exe")) + if(!(Test-Path "${env:ProgramFiles(x86)}\MSBuild\14.0\Bin\msbuild.exe")) { cinst microsoft-build-tools -y } diff --git a/README.md b/README.md index 44604f243..ca1ebc604 100644 --- a/README.md +++ b/README.md @@ -35,12 +35,12 @@ After installing nuget package mark following files to be copied to app director Setup HTTP proxy: ```csharp - var ProxyServer = new ProxyServer(); + var proxyServer = new ProxyServer(); - ProxyServer.BeforeRequest += OnRequest; - ProxyServer.BeforeResponse += OnResponse; - ProxyServer.ServerCertificateValidationCallback += OnCertificateValidation; - ProxyServer.ClientCertificateSelectionCallback += OnCertificateSelection; + proxyServer.BeforeRequest += OnRequest; + proxyServer.BeforeResponse += OnResponse; + proxyServer.ServerCertificateValidationCallback += OnCertificateValidation; + proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection; //Exclude Https addresses you don't want to proxy @@ -53,8 +53,8 @@ Setup HTTP proxy: //An explicit endpoint is where the client knows about the existance of a proxy //So client sends request in a proxy friendly manner - ProxyServer.AddEndPoint(explicitEndPoint); - ProxyServer.Start(); + proxyServer.AddEndPoint(explicitEndPoint); + proxyServer.Start(); //Transparent endpoint is usefull for reverse proxying (client is not aware of the existance of proxy) @@ -67,26 +67,29 @@ Setup HTTP proxy: { GenericCertificateName = "google.com" }; - ProxyServer.AddEndPoint(transparentEndPoint); + proxyServer.AddEndPoint(transparentEndPoint); - //ProxyServer.UpStreamHttpProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 }; - //ProxyServer.UpStreamHttpsProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 }; + //proxyServer.UpStreamHttpProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 }; + //proxyServer.UpStreamHttpsProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 }; - foreach (var endPoint in ProxyServer.ProxyEndPoints) + foreach (var endPoint in proxyServer.ProxyEndPoints) Console.WriteLine("Listening on '{0}' endpoint at Ip {1} and port: {2} ", endPoint.GetType().Name, endPoint.IpAddress, endPoint.Port); //Only explicit proxies can be set as system proxy! - ProxyServer.SetAsSystemHttpProxy(explicitEndPoint); - ProxyServer.SetAsSystemHttpsProxy(explicitEndPoint); + proxyServer.SetAsSystemHttpProxy(explicitEndPoint); + proxyServer.SetAsSystemHttpsProxy(explicitEndPoint); //wait here (You can use something else as a wait function, I am using this as a demo) Console.Read(); //Unsubscribe & Quit - ProxyServer.BeforeRequest -= OnRequest; - ProxyServer.BeforeResponse -= OnResponse; - ProxyServer.Stop(); + proxyServer.BeforeRequest -= OnRequest; + proxyServer.BeforeResponse -= OnResponse; + proxyServer.ServerCertificateValidationCallback -= OnCertificateValidation; + proxyServer.ClientCertificateSelectionCallback -= OnCertificateSelection; + + proxyServer.Stop(); ``` Sample request and response event handlers diff --git a/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs b/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs index 977404367..f54881369 100644 --- a/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs +++ b/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs @@ -62,8 +62,7 @@ internal SessionEventArgs(int bufferSize, Func httpRespo ProxyClient = new ProxyClient(); WebSession = new HttpWebClient(); } - - + /// /// Read request body content as bytes[] for current session /// @@ -98,7 +97,7 @@ private async Task ReadRequestBody() await this.ProxyClient.ClientStreamReader.CopyBytesToStream(bufferSize, requestBodyStream, WebSession.Request.ContentLength); } - else if(WebSession.Request.HttpVersion.Major == 1 && WebSession.Request.HttpVersion.Minor == 0) + else if (WebSession.Request.HttpVersion.Major == 1 && WebSession.Request.HttpVersion.Minor == 0) await WebSession.ServerConnection.StreamReader.CopyBytesToStream(bufferSize, requestBodyStream, long.MaxValue); } WebSession.Request.RequestBody = await GetDecompressedResponseBody(WebSession.Request.ContentEncoding, requestBodyStream.ToArray()); @@ -108,7 +107,7 @@ private async Task ReadRequestBody() //So that next time we can deliver body from cache WebSession.Request.RequestBodyRead = true; } - + } /// @@ -134,7 +133,7 @@ private async Task ReadResponseBody() await WebSession.ServerConnection.StreamReader.CopyBytesToStream(bufferSize, responseBodyStream, WebSession.Response.ContentLength); } - else if(WebSession.Response.HttpVersion.Major == 1 && WebSession.Response.HttpVersion.Minor == 0) + else if (WebSession.Response.HttpVersion.Major == 1 && WebSession.Response.HttpVersion.Minor == 0) await WebSession.ServerConnection.StreamReader.CopyBytesToStream(bufferSize, responseBodyStream, long.MaxValue); } @@ -152,10 +151,13 @@ private async Task ReadResponseBody() /// public async Task GetRequestBody() { - if (WebSession.Request.RequestLocked) - throw new Exception("You cannot call this function after request is made to server."); + if (!WebSession.Request.RequestBodyRead) + { + if (WebSession.Request.RequestLocked) + throw new Exception("You cannot call this function after request is made to server."); - await ReadRequestBody(); + await ReadRequestBody(); + } return WebSession.Request.RequestBody; } /// @@ -164,12 +166,13 @@ public async Task GetRequestBody() /// public async Task GetRequestBodyAsString() { - if (WebSession.Request.RequestLocked) - throw new Exception("You cannot call this function after request is made to server."); - - - await ReadRequestBody(); + if (!WebSession.Request.RequestBodyRead) + { + if (WebSession.Request.RequestLocked) + throw new Exception("You cannot call this function after request is made to server."); + await ReadRequestBody(); + } //Use the encoding specified in request to decode the byte[] data to string return WebSession.Request.RequestBodyString ?? (WebSession.Request.RequestBodyString = WebSession.Request.Encoding.GetString(WebSession.Request.RequestBody)); } @@ -285,7 +288,7 @@ public async Task SetResponseBodyString(string body) var bodyBytes = WebSession.Response.Encoding.GetBytes(body); await SetResponseBody(bodyBytes); - } + } private async Task GetDecompressedResponseBody(string encodingType, byte[] responseBodyStream) { @@ -345,7 +348,7 @@ public async Task Redirect(string url) WebSession.Request.CancelRequest = true; } - + /// a generic responder method public async Task Respond(Response response) { diff --git a/Titanium.Web.Proxy/Http/HttpWebClient.cs b/Titanium.Web.Proxy/Http/HttpWebClient.cs index a229af903..6a4e42536 100644 --- a/Titanium.Web.Proxy/Http/HttpWebClient.cs +++ b/Titanium.Web.Proxy/Http/HttpWebClient.cs @@ -115,8 +115,10 @@ internal async Task ReceiveResponse() if (string.IsNullOrEmpty(httpResult[0])) { - await ServerConnection.StreamReader.ReadLineAsync(); + //Empty content in first-line, try again + httpResult = (await ServerConnection.StreamReader.ReadLineAsync()).Split(ProxyConstants.SpaceSplit, 3); } + var httpVersion = httpResult[0].Trim().ToLower(); var version = new Version(1,1); diff --git a/Titanium.Web.Proxy/ProxyServer.cs b/Titanium.Web.Proxy/ProxyServer.cs index 698d094c3..5a701803f 100644 --- a/Titanium.Web.Proxy/ProxyServer.cs +++ b/Titanium.Web.Proxy/ProxyServer.cs @@ -186,7 +186,7 @@ public void SetAsSystemHttpProxy(ExplicitProxyEndPoint endPoint) #if !DEBUG firefoxProxySettingsManager.AddFirefox(); #endif - Console.WriteLine("Set endpoint at Ip {1} and port: {2} as System HTTPS Proxy", endPoint.GetType().Name, endPoint.IpAddress, endPoint.Port); + Console.WriteLine("Set endpoint at Ip {1} and port: {2} as System HTTP Proxy", endPoint.GetType().Name, endPoint.IpAddress, endPoint.Port); } diff --git a/Titanium.Web.Proxy/ResponseHandler.cs b/Titanium.Web.Proxy/ResponseHandler.cs index 37a90fefc..ca0cb9501 100644 --- a/Titanium.Web.Proxy/ResponseHandler.cs +++ b/Titanium.Web.Proxy/ResponseHandler.cs @@ -181,14 +181,28 @@ private void FixResponseProxyHeaders(List headers) /// /// Handle dispose of a client/server session /// - /// + /// /// /// /// /// - private void Dispose(TcpClient client, IDisposable clientStream, IDisposable clientStreamReader, + private void Dispose(TcpClient tcpClient, IDisposable clientStream, IDisposable clientStreamReader, IDisposable clientStreamWriter, IDisposable args) { + + if (clientStream != null) + { + (clientStream as Stream).Close(); + (clientStream as Stream).Dispose(); + } + + if (tcpClient != null) + { + tcpClient.Client.Close(); + tcpClient.Close(); + tcpClient.Client.Dispose(); + } + if (args != null) args.Dispose(); @@ -198,11 +212,7 @@ private void Dispose(TcpClient client, IDisposable clientStream, IDisposable cl if (clientStreamWriter != null) clientStreamWriter.Dispose(); - if (clientStream != null) - clientStream.Dispose(); - if (client != null) - client.Close(); } } } \ No newline at end of file