void session_PlayTokenLost(ISession sender, SessionEventArgs e) { this.ParentForm.BeginInvoke(new MethodInvoker(delegate() { CF_displayMessage("Play token lost! What do we do???" + Environment.NewLine + e.Status.ToString() + Environment.NewLine + e.Message); })); }
//Test On Request, intecept requests //Read browser URL send back to proxy by the injection script in OnResponse event public void OnRequest(object sender, SessionEventArgs e) { Console.WriteLine(e.ProxySession.Request.Url); ////read request headers //var requestHeaders = e.ProxySession.Request.RequestHeaders; //if ((e.RequestMethod.ToUpper() == "POST" || e.RequestMethod.ToUpper() == "PUT")) //{ // //Get/Set request body bytes // byte[] bodyBytes = e.GetRequestBody(); // e.SetRequestBody(bodyBytes); // //Get/Set request body as string // string bodyString = e.GetRequestBodyAsString(); // e.SetRequestBodyString(bodyString); //} ////To cancel a request with a custom HTML content ////Filter URL //if (e.ProxySession.Request.RequestUrl.Contains("google.com")) //{ // e.Ok("<!DOCTYPE html><html><body><h1>Website Blocked</h1><p>Blocked by titanium web proxy.</p></body></html>"); //} }
void session_MessageToUser(ISession sender, SessionEventArgs e) { this.ParentForm.BeginInvoke(new MethodInvoker(delegate() { CF_displayMessage(e.Message); })); }
public void Session() { Mocks mocks = new Mocks(); SessionEventArgs s = new SessionEventArgs(mocks.Session.Object); Assert.Equal(s.Session, mocks.Session.Object); }
void session_Exception(ISession sender, SessionEventArgs e) { this.ParentForm.BeginInvoke(new MethodInvoker(delegate() { WriteError(e.Message); CF_displayMessage(e.Status.ToString() + Environment.NewLine + e.Message); })); }
private void OnConnectionError(object sender, SessionEventArgs e) { if (e.Status != Error.OK) { _logger.Log("Connection error " + e.Message + "[" + e.Status + "]", Category.Exception, Priority.High); } else { _logger.Log("Connected", Category.Info, Priority.Low); } }
void session_LoginComplete(ISession sender, SessionEventArgs e) { this.ParentForm.BeginInvoke(new MethodInvoker(() => { if (e.Status != sp_error.OK) { CF_displayMessage("Login Failed: " + e.Status + Environment.NewLine + e.Message); } else { OnLoginComplete(); } })); }
private static void Dispose(TcpClient client, Stream clientStream, CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, SessionEventArgs args) { if (args != null) args.Dispose(); if (clientStreamReader != null) clientStreamReader.Dispose(); if (clientStreamWriter != null) clientStreamWriter.Dispose(); if (clientStream != null) clientStream.Dispose(); if (client != null) client.Close(); }
//Test script injection //Insert script to read the Browser URL and send it back to proxy public void OnResponse(object sender, SessionEventArgs e) { ////read response headers // var responseHeaders = e.ProxySession.Response.ResponseHeaders; //if (!e.ProxySession.Request.Hostname.Equals("medeczane.sgk.gov.tr")) return; //if (e.RequestMethod == "GET" || e.RequestMethod == "POST") //{ // if (e.ProxySession.Response.ResponseStatusCode == "200") // { // if (e.ProxySession.Response.ContentType.Trim().ToLower().Contains("text/html")) // { // string body = e.GetResponseBodyAsString(); // } // } //} }
//Called asynchronously when a request was successfully and we received the response private static void HandleHttpSessionResponse(SessionEventArgs args) { args.ProxySession.ReceiveResponse(); try { args.ProxySession.Response.ResponseHeaders = ReadResponseHeaders(args.ProxySession); args.ProxySession.Response.ResponseStream = args.ProxySession.ProxyClient.ServerStreamReader.BaseStream; if (BeforeResponse != null) { args.ProxySession.Response.Encoding = args.ProxySession.GetResponseEncoding(); BeforeResponse(null, args); } args.ProxySession.Response.ResponseLocked = true; if (args.ProxySession.Response.ResponseBodyRead) { var isChunked = args.ProxySession.Response.IsChunked; var contentEncoding = args.ProxySession.Response.ContentEncoding; if(contentEncoding!=null) switch (contentEncoding) { case "gzip": args.ProxySession.Response.ResponseBody = CompressionHelper.CompressGzip(args.ProxySession.Response.ResponseBody); break; case "deflate": args.ProxySession.Response.ResponseBody = CompressionHelper.CompressDeflate(args.ProxySession.Response.ResponseBody); break; case "zlib": args.ProxySession.Response.ResponseBody = CompressionHelper.CompressZlib(args.ProxySession.Response.ResponseBody); break; } WriteResponseStatus(args.ProxySession.Response.HttpVersion, args.ProxySession.Response.ResponseStatusCode, args.ProxySession.Response.ResponseStatusDescription, args.Client.ClientStreamWriter); WriteResponseHeaders(args.Client.ClientStreamWriter, args.ProxySession.Response.ResponseHeaders, args.ProxySession.Response.ResponseBody.Length, isChunked); WriteResponseBody(args.Client.ClientStream, args.ProxySession.Response.ResponseBody, isChunked); } else { WriteResponseStatus(args.ProxySession.Response.HttpVersion, args.ProxySession.Response.ResponseStatusCode, args.ProxySession.Response.ResponseStatusDescription, args.Client.ClientStreamWriter); WriteResponseHeaders(args.Client.ClientStreamWriter, args.ProxySession.Response.ResponseHeaders); if (args.ProxySession.Response.IsChunked || args.ProxySession.Response.ContentLength > 0) WriteResponseBody(args.ProxySession.ProxyClient.ServerStreamReader, args.Client.ClientStream, args.ProxySession.Response.IsChunked, args.ProxySession.Response.ContentLength); } args.Client.ClientStream.Flush(); } catch { Dispose(args.Client.TcpClient, args.Client.ClientStream, args.Client.ClientStreamReader, args.Client.ClientStreamWriter, args); } finally { args.Dispose(); } }
private void session_SessionStarted(object sender, SessionEventArgs e) { this.OnSesstionStarted(e.Session); }
public async Task OnRequest(object sender, SessionEventArgs e) { #if DEBUG #region 测试用 /* * if (e.HttpClient.Request.RequestUri.AbsoluteUri.Contains("steampowered.com")) * { * var ip = Dns.GetHostAddresses("steampowered.com"); * e.HttpClient.UpStreamEndPoint = new IPEndPoint(IPAddress.Parse(ip[0].ToString()), 443); * if (e.HttpClient.ConnectRequest?.ClientHelloInfo != null) * { * e.HttpClient.ConnectRequest.ClientHelloInfo.Extensions.Remove("server_name"); * } * } * * if (e.HttpClient.Request.RequestUri.AbsoluteUri.Contains("steamcommunity.com")) * { * var ip = Dns.GetHostAddresses("steamcommunity-a.akamaihd.net"); * e.HttpClient.UpStreamEndPoint = new IPEndPoint(IPAddress.Parse(ip[0].ToString()), 443); * if (e.HttpClient.ConnectRequest?.ClientHelloInfo != null) * { * e.HttpClient.ConnectRequest.ClientHelloInfo.Extensions.Remove("server_name"); * } * } */ #endregion Debug.WriteLine("OnRequest " + e.HttpClient.Request.RequestUri.AbsoluteUri); Debug.WriteLine("OnRequest HTTP " + e.HttpClient.Request.HttpVersion); Logger.Info("OnRequest" + e.HttpClient.Request.RequestUri.AbsoluteUri); #endif // Dns.GetHostAddressesAsync(e.HttpClient.Request.Host).ContinueWith(s => //{ // //部分运营商将奇怪的域名解析到127.0.0.1 再此排除这些不支持的代理域名 // if (IPAddress.IsLoopback(s.Result.FirstOrDefault()) // && ProxyDomains.Count(w => w.IsEnable && w.Hosts.Contains(e.HttpClient.Request.Host)) == 0) // { // e.Ok($"URL : {e.HttpClient.Request.RequestUri.AbsoluteUri} \r\n not support proxy"); // return; // } //}); foreach (var item in ProxyDomains) { if (!item.IsEnable) { continue; } foreach (var host in item.Domains) { if (e.HttpClient.Request.RequestUri.AbsoluteUri.Contains(host)) { IPAddress iP = null; if (!string.IsNullOrEmpty(item.ProxyIPAddres)) { iP = IPAddress.Parse(item.ProxyIPAddres); } else { var iPs = await Dns.GetHostAddressesAsync(item.ToDomain); iP = iPs.FirstOrDefault(); } if (iP != null) { e.HttpClient.UpStreamEndPoint = new IPEndPoint(IPAddress.Parse(iP.ToString()), item.Port); } if (e.HttpClient.ConnectRequest?.ClientHelloInfo != null) { if (!string.IsNullOrEmpty(item.ServerName)) { var sni = e.HttpClient.ConnectRequest.ClientHelloInfo.Extensions["server_name"]; e.HttpClient.ConnectRequest.ClientHelloInfo.Extensions["server_name"] = new Titanium.Web.Proxy.StreamExtended.Models.SslExtension(sni.Value, sni.Name, item.ServerName, sni.Position); } else { e.HttpClient.ConnectRequest.ClientHelloInfo.Extensions.Remove("server_name"); } } return; } } } //没有匹配到的结果直接返回不支持,避免出现Loopback死循环内存溢出 e.Ok($"URL : {e.HttpClient.Request.RequestUri.AbsoluteUri} {Environment.NewLine} not support proxy"); return; }
void session_LogoutComplete(ISession sender, SessionEventArgs e) { loginComplete = false; }
private void OnSessionStopPlayback(object sender, SessionEventArgs e) { _logger.Log("Session - Stop playback recevied", Category.Info, Priority.Low); }
private void UserLoggedIn(object sender, SessionEventArgs e) { if (e.Status == Error.OK) { ConsoleEx.WriteLine("Successfully logged in", ConsoleColor.Yellow); } else { ConsoleEx.WriteLine("Unable to log in: " + e.Status.GetMessage(), ConsoleColor.Red); Console.ReadLine(); Environment.Exit(-1); } _logInEvent.Set(); }
protected virtual void OnStarted(ISession session) { var e = new SessionEventArgs(new ImmutableProxiedSession(session)); OnStarted(e); }
private void HandshakeOnCreate(object sender, SessionEventArgs e) { e.Session.Handshake(e.Session.RemoteNodeId); }
/// <summary> /// This is the core request handler method for a particular connection from client. /// Will create new session (request/response) sequence until /// client/server abruptly terminates connection or by normal HTTP termination. /// </summary> /// <param name="endPoint">The proxy endpoint.</param> /// <param name="clientConnection">The client connection.</param> /// <param name="clientStream">The client stream.</param> /// <param name="clientStreamWriter">The client stream writer.</param> /// <param name="cancellationTokenSource">The cancellation token source for this async task.</param> /// <param name="httpsConnectHostname"> /// The https hostname as appeared in CONNECT request if this is a HTTPS request from /// explicit endpoint. /// </param> /// <param name="connectArgs">The Connect request if this is a HTTPS request from explicit endpoint.</param> /// <param name="prefetchConnectionTask">Prefetched server connection for current client using Connect/SNI headers.</param> private async Task handleHttpSessionRequest(ProxyEndPoint endPoint, TcpClientConnection clientConnection, CustomBufferedStream clientStream, HttpResponseWriter clientStreamWriter, CancellationTokenSource cancellationTokenSource, string httpsConnectHostname, TunnelConnectSessionEventArgs connectArgs, Task <TcpServerConnection> prefetchConnectionTask = null) { var connectRequest = connectArgs?.HttpClient.ConnectRequest; var prefetchTask = prefetchConnectionTask; TcpServerConnection connection = null; bool closeServerConnection = false; try { var cancellationToken = cancellationTokenSource.Token; // Loop through each subsequent request on this particular client connection // (assuming HTTP connection is kept alive by client) while (true) { if (clientStream.IsClosed) { return; } // read the request line string httpCmd = await clientStream.ReadLineAsync(cancellationToken); if (string.IsNullOrEmpty(httpCmd)) { return; } var args = new SessionEventArgs(this, endPoint, cancellationTokenSource) { ProxyClient = { Connection = clientConnection }, HttpClient = { ConnectRequest = connectRequest }, UserData = connectArgs?.UserData }; try { try { Request.ParseRequestLine(httpCmd, out string httpMethod, out string httpUrl, out var version); // Read the request headers in to unique and non-unique header collections await HeaderParser.ReadHeaders(clientStream, args.HttpClient.Request.Headers, cancellationToken); Uri httpRemoteUri; if (ProxyConstants.UriSchemeRegex.IsMatch(httpUrl)) { try { httpRemoteUri = new Uri(httpUrl); } catch (Exception ex) { throw new Exception($"Invalid URI: '{httpUrl}'", ex); } } else { string host = args.HttpClient.Request.Host ?? httpsConnectHostname; string hostAndPath = host; if (httpUrl.StartsWith("/")) { hostAndPath += httpUrl; } string url = string.Concat(httpsConnectHostname == null ? "http://" : "https://", hostAndPath); try { httpRemoteUri = new Uri(url); } catch (Exception ex) { throw new Exception($"Invalid URI: '{url}'", ex); } } var request = args.HttpClient.Request; request.RequestUri = httpRemoteUri; request.OriginalUrl = httpUrl; request.Method = httpMethod; request.HttpVersion = version; args.ProxyClient.ClientStream = clientStream; args.ProxyClient.ClientStreamWriter = clientStreamWriter; if (!args.IsTransparent) { // proxy authorization check if (httpsConnectHostname == null && await checkAuthorization(args) == false) { await invokeBeforeResponse(args); // send the response await clientStreamWriter.WriteResponseAsync(args.HttpClient.Response, cancellationToken : cancellationToken); return; } prepareRequestHeaders(request.Headers); request.Host = request.RequestUri.Authority; } // if win auth is enabled // we need a cache of request body // so that we can send it after authentication in WinAuthHandler.cs if (isWindowsAuthenticationEnabledAndSupported && request.HasBody) { await args.GetRequestBody(cancellationToken); } //we need this to syphon out data from connection if API user changes them. request.SetOriginalHeaders(); args.TimeLine["Request Received"] = DateTime.Now; // If user requested interception do it await invokeBeforeRequest(args); var response = args.HttpClient.Response; if (request.CancelRequest) { if (!(Enable100ContinueBehaviour && request.ExpectContinue)) { // syphon out the request body from client before setting the new body await args.SyphonOutBodyAsync(true, cancellationToken); } await handleHttpSessionResponse(args); if (!response.KeepAlive) { return; } continue; } //If prefetch task is available. if (connection == null && prefetchTask != null) { try { connection = await prefetchTask; } catch (SocketException e) { if (e.SocketErrorCode != SocketError.HostNotFound) { throw; } } prefetchTask = null; } // create a new connection if cache key changes. // only gets hit when connection pool is disabled. // or when prefetch task has a unexpectedly different connection. if (connection != null && (await tcpConnectionFactory.GetConnectionCacheKey(this, args, clientConnection.NegotiatedApplicationProtocol) != connection.CacheKey)) { await tcpConnectionFactory.Release(connection); connection = null; } var result = await handleHttpSessionRequest(httpCmd, args, connection, clientConnection.NegotiatedApplicationProtocol, cancellationToken, cancellationTokenSource); //update connection to latest used connection = result.LatestConnection; closeServerConnection = !result.Continue; //throw if exception happened if (!result.IsSuccess) { throw result.Exception; } if (!result.Continue) { return; } //user requested if (args.HttpClient.CloseServerConnection) { closeServerConnection = true; return; } // if connection is closing exit if (!response.KeepAlive) { closeServerConnection = true; return; } if (cancellationTokenSource.IsCancellationRequested) { throw new Exception("Session was terminated by user."); } // Release server connection for each HTTP session instead of per client connection. // This will be more efficient especially when client is idly holding server connection // between sessions without using it. // Do not release authenticated connections for performance reasons. // Otherwise it will keep authenticating per session. if (EnableConnectionPool && connection != null && !connection.IsWinAuthenticated) { await tcpConnectionFactory.Release(connection); connection = null; } } catch (Exception e) when(!(e is ProxyHttpException)) { throw new ProxyHttpException("Error occured whilst handling session request", e, args); } } catch (Exception e) { args.Exception = e; closeServerConnection = true; throw; } finally { await invokeAfterResponse(args); args.Dispose(); } } } finally { await tcpConnectionFactory.Release(connection, closeServerConnection); await tcpConnectionFactory.Release(prefetchTask, closeServerConnection); } }
/// <summary> /// Handle windows NTLM/Kerberos authentication. /// Note: NTLM/Kerberos cannot do a man in middle operation /// we do for HTTPS requests. /// As such we will be sending local credentials of current /// User to server to authenticate requests. /// To disable this set ProxyServer.EnableWinAuth to false. /// </summary> private async Task handle401UnAuthorized(SessionEventArgs args) { string? headerName = null; HttpHeader?authHeader = null; var response = args.HttpClient.Response; // check in non-unique headers first var header = response.Headers.NonUniqueHeaders.FirstOrDefault(x => authHeaderNames.Contains(x.Key)); if (!header.Equals(new KeyValuePair <string, List <HttpHeader> >())) { headerName = header.Key; } if (headerName != null) { authHeader = response.Headers.NonUniqueHeaders[headerName] .FirstOrDefault( x => authSchemes.Any(y => x.Value.StartsWith(y, StringComparison.OrdinalIgnoreCase))); } // check in unique headers if (authHeader == null) { headerName = null; // check in non-unique headers first var uHeader = response.Headers.Headers.FirstOrDefault(x => authHeaderNames.Contains(x.Key)); if (!uHeader.Equals(new KeyValuePair <string, HttpHeader>())) { headerName = uHeader.Key; } if (headerName != null) { authHeader = authSchemes.Any(x => response.Headers.Headers[headerName].Value .StartsWith(x, StringComparison.OrdinalIgnoreCase)) ? response.Headers.Headers[headerName] : null; } } if (authHeader != null) { string?scheme = authSchemes.Contains(authHeader.Value) ? authHeader.Value : null; var expectedAuthState = scheme == null ? State.WinAuthState.INITIAL_TOKEN : State.WinAuthState.UNAUTHORIZED; if (!WinAuthEndPoint.ValidateWinAuthState(args.HttpClient.Data, expectedAuthState)) { // Invalid state, create proper error message to client await rewriteUnauthorizedResponse(args); return; } var request = args.HttpClient.Request; // clear any existing headers to avoid confusing bad servers request.Headers.RemoveHeader(KnownHeaders.Authorization); // initial value will match exactly any of the schemes if (scheme != null) { string clientToken = WinAuthHandler.GetInitialAuthToken(request.Host !, scheme, args.HttpClient.Data); string auth = string.Concat(scheme, clientToken); // replace existing authorization header if any request.Headers.SetOrAddHeaderValue(KnownHeaders.Authorization, auth); // don't need to send body for Authorization request if (request.HasBody) { request.ContentLength = 0; } } else { // challenge value will start with any of the scheme selected scheme = authSchemes.First(x => authHeader.Value.StartsWith(x, StringComparison.OrdinalIgnoreCase) && authHeader.Value.Length > x.Length + 1); string serverToken = authHeader.Value.Substring(scheme.Length + 1); string clientToken = WinAuthHandler.GetFinalAuthToken(request.Host, serverToken, args.HttpClient.Data); string auth = string.Concat(scheme, clientToken); // there will be an existing header from initial client request request.Headers.SetOrAddHeaderValue(KnownHeaders.Authorization, auth); // send body for final auth request if (request.OriginalHasBody) { request.ContentLength = request.Body.Length; } args.HttpClient.Connection.IsWinAuthenticated = true; } // Need to revisit this. // Should we cache all Set-Cookie headers from server during auth process // and send it to client after auth? // Let ResponseHandler send the updated request args.ReRequest = true; } }
private async void OnSessionManagerSessionStarted(object sender, SessionEventArgs e) { await SendData(true).ConfigureAwait(false); }
private async void OnSessionManagerCapabilitiesChanged(object sender, SessionEventArgs e) { await SendData(true).ConfigureAwait(false); }
private async void OnSessionManagerSessionActivity(object sender, SessionEventArgs e) { await SendData(false).ConfigureAwait(false); }
private void SessionStoppedHandler(object sender, SessionEventArgs e) { Debug.Log("SessionStoppedHandler called"); recognizer = null; }
public virtual void sessionClosed(SessionEventArgs e) { }
//This is called when the request is PUT/POST to read the body private static void SendClientRequestBody(SessionEventArgs args) { // End the operation var postStream = args.ProxySession.ProxyClient.Stream; if (args.ProxySession.Request.ContentLength > 0) { //args.ProxyRequest.AllowWriteStreamBuffering = true; try { var totalbytesRead = 0; int bytesToRead; if (args.ProxySession.Request.ContentLength < BUFFER_SIZE) { bytesToRead = (int)args.ProxySession.Request.ContentLength; } else bytesToRead = BUFFER_SIZE; while (totalbytesRead < (int)args.ProxySession.Request.ContentLength) { var buffer = args.Client.ClientStreamReader.ReadBytes(bytesToRead); totalbytesRead += buffer.Length; var remainingBytes = (int)args.ProxySession.Request.ContentLength - totalbytesRead; if (remainingBytes < bytesToRead) { bytesToRead = remainingBytes; } postStream.Write(buffer, 0, buffer.Length); } } catch { throw; } } //Need to revist, find any potential bugs else if (args.ProxySession.Request.SendChunked) { try { while (true) { var chuchkHead = args.Client.ClientStreamReader.ReadLine(); var chunkSize = int.Parse(chuchkHead, NumberStyles.HexNumber); if (chunkSize != 0) { var buffer = args.Client.ClientStreamReader.ReadBytes(chunkSize); postStream.Write(buffer, 0, buffer.Length); //chunk trail args.Client.ClientStreamReader.ReadLine(); } else { args.Client.ClientStreamReader.ReadLine(); break; } } } catch { throw; } } }
private async Task handleClient(TransparentBaseProxyEndPoint endPoint, TcpClientConnection clientConnection, int port, CancellationTokenSource cancellationTokenSource, CancellationToken cancellationToken) { bool isHttps = false; var clientStream = new HttpClientStream(clientConnection, clientConnection.GetStream(), BufferPool, cancellationToken); try { var clientHelloInfo = await SslTools.PeekClientHello(clientStream, BufferPool, cancellationToken); if (clientHelloInfo != null) { var httpsHostName = clientHelloInfo.GetServerName() ?? endPoint.GenericCertificateName; var args = new BeforeSslAuthenticateEventArgs(clientConnection, cancellationTokenSource, httpsHostName); await endPoint.InvokeBeforeSslAuthenticate(this, args, ExceptionFunc); if (cancellationTokenSource.IsCancellationRequested) { throw new Exception("Session was terminated by user."); } if (endPoint.DecryptSsl && args.DecryptSsl) { clientStream.Connection.SslProtocol = clientHelloInfo.SslProtocol; // do client authentication using certificate X509Certificate2?certificate = null; SslStream? sslStream = null; try { sslStream = new SslStream(clientStream, false); string certName = HttpHelper.GetWildCardDomainName(httpsHostName); certificate = endPoint.GenericCertificate ?? await CertificateManager.CreateServerCertificate(certName); // Successfully managed to authenticate the client using the certificate await sslStream.AuthenticateAsServerAsync(certificate, false, SslProtocols.Tls, false); // HTTPS server created - we can now decrypt the client's traffic clientStream = new HttpClientStream(clientStream.Connection, sslStream, BufferPool, cancellationToken); sslStream = null; // clientStream was created, no need to keep SSL stream reference isHttps = true; } catch (Exception e) { sslStream?.Dispose(); var certName = certificate?.GetNameInfo(X509NameType.SimpleName, false); var session = new SessionEventArgs(this, endPoint, clientStream, null, cancellationTokenSource); throw new ProxyConnectException( $"Couldn't authenticate host '{httpsHostName}' with certificate '{certName}'.", e, session); } } else { var sessionArgs = new SessionEventArgs(this, endPoint, clientStream, null, cancellationTokenSource); var connection = await tcpConnectionFactory.GetServerConnection(this, httpsHostName, port, HttpHeader.VersionUnknown, false, null, true, sessionArgs, UpStreamEndPoint, UpStreamHttpsProxy, true, cancellationToken); try { int available = clientStream.Available; if (available > 0) { // send the buffered data var data = BufferPool.GetBuffer(); try { // clientStream.Available should be at most BufferSize because it is using the same buffer size await clientStream.ReadAsync(data, 0, available, cancellationToken); await connection.Stream.WriteAsync(data, 0, available, true, cancellationToken); } finally { BufferPool.ReturnBuffer(data); } } if (!clientStream.IsClosed && !connection.Stream.IsClosed) { await TcpHelper.SendRaw(clientStream, connection.Stream, BufferPool, null, null, cancellationTokenSource, ExceptionFunc); } } finally { await tcpConnectionFactory.Release(connection, true); } return; } } // HTTPS server created - we can now decrypt the client's traffic // Now create the request await handleHttpSessionRequest(endPoint, clientStream, cancellationTokenSource, isHttps : isHttps); } catch (ProxyException e) { onException(clientStream, e); } catch (IOException e) { onException(clientStream, new Exception("Connection was aborted", e)); } catch (SocketException e) { onException(clientStream, new Exception("Could not connect", e)); } catch (Exception e) { onException(clientStream, new Exception("Error occured in whilst handling the client", e)); } finally { clientStream.Dispose(); } }
protected void OnStopped(SessionEventArgs e) { if (Stopped == null) { return; } Stopped(this, e); }
/// <summary> /// This is the core request handler method for a particular connection from client /// Will create new session (request/response) sequence until /// client/server abruptly terminates connection or by normal HTTP termination /// </summary> /// <param name="client"></param> /// <param name="httpCmd"></param> /// <param name="clientStream"></param> /// <param name="clientStreamReader"></param> /// <param name="clientStreamWriter"></param> /// <param name="httpsConnectHostname"></param> /// <param name="endPoint"></param> /// <param name="connectRequest"></param> /// <param name="isTransparentEndPoint"></param> /// <returns></returns> private async Task <bool> HandleHttpSessionRequest(TcpClient client, string httpCmd, CustomBufferedStream clientStream, CustomBinaryReader clientStreamReader, HttpResponseWriter clientStreamWriter, string httpsConnectHostname, ProxyEndPoint endPoint, ConnectRequest connectRequest, bool isTransparentEndPoint = false) { bool disposed = false; TcpConnection connection = null; //Loop through each subsequest request on this particular client connection //(assuming HTTP connection is kept alive by client) while (true) { if (string.IsNullOrEmpty(httpCmd)) { break; } var args = new SessionEventArgs(BufferSize, endPoint, HandleHttpSessionResponse) { ProxyClient = { TcpClient = client }, WebSession = { ConnectRequest = connectRequest } }; try { string httpMethod; string httpUrl; Version version; Request.ParseRequestLine(httpCmd, out httpMethod, out httpUrl, out version); //Read the request headers in to unique and non-unique header collections await HeaderParser.ReadHeaders(clientStreamReader, args.WebSession.Request.Headers); var httpRemoteUri = new Uri(httpsConnectHostname == null ? isTransparentEndPoint ? string.Concat("http://", args.WebSession.Request.Host, httpUrl) : httpUrl : string.Concat("https://", args.WebSession.Request.Host ?? httpsConnectHostname, httpUrl)); args.WebSession.Request.RequestUri = httpRemoteUri; args.WebSession.Request.OriginalUrl = httpUrl; args.WebSession.Request.Method = httpMethod; args.WebSession.Request.HttpVersion = version; args.ProxyClient.ClientStream = clientStream; args.ProxyClient.ClientStreamReader = clientStreamReader; args.ProxyClient.ClientStreamWriter = clientStreamWriter; //proxy authorization check if (httpsConnectHostname == null && await CheckAuthorization(clientStreamWriter, args) == false) { args.Dispose(); break; } PrepareRequestHeaders(args.WebSession.Request.Headers); args.WebSession.Request.Host = args.WebSession.Request.RequestUri.Authority; //if win auth is enabled //we need a cache of request body //so that we can send it after authentication in WinAuthHandler.cs if (isWindowsAuthenticationEnabledAndSupported && args.WebSession.Request.HasBody) { await args.GetRequestBody(); } //If user requested interception do it if (BeforeRequest != null) { await BeforeRequest.InvokeParallelAsync(this, args, ExceptionFunc); } if (args.WebSession.Request.CancelRequest) { args.Dispose(); break; } //create a new connection if hostname/upstream end point changes if (connection != null && (!connection.HostName.Equals(args.WebSession.Request.RequestUri.Host, StringComparison.OrdinalIgnoreCase) || (args.WebSession.UpStreamEndPoint != null && !args.WebSession.UpStreamEndPoint.Equals(connection.UpStreamEndPoint)))) { connection.Dispose(); connection = null; UpdateServerConnectionCount(false); } if (connection == null) { connection = await GetServerConnection(args, false); } //if upgrading to websocket then relay the requet without reading the contents if (args.WebSession.Request.UpgradeToWebSocket) { //prepare the prefix content var requestHeaders = args.WebSession.Request.Headers; byte[] requestBytes; using (var ms = new MemoryStream()) using (var writer = new HttpRequestWriter(ms, BufferSize)) { writer.WriteLine(httpCmd); writer.WriteHeaders(requestHeaders); requestBytes = ms.ToArray(); } await connection.Stream.WriteAsync(requestBytes, 0, requestBytes.Length); string httpStatus = await connection.StreamReader.ReadLineAsync(); Version responseVersion; int responseStatusCode; string responseStatusDescription; Response.ParseResponseLine(httpStatus, out responseVersion, out responseStatusCode, out responseStatusDescription); args.WebSession.Response.HttpVersion = responseVersion; args.WebSession.Response.StatusCode = responseStatusCode; args.WebSession.Response.StatusDescription = responseStatusDescription; await HeaderParser.ReadHeaders(connection.StreamReader, args.WebSession.Response.Headers); await clientStreamWriter.WriteResponseAsync(args.WebSession.Response); //If user requested call back then do it if (BeforeResponse != null && !args.WebSession.Response.ResponseLocked) { await BeforeResponse.InvokeParallelAsync(this, args, ExceptionFunc); } await TcpHelper.SendRaw(clientStream, connection.Stream, BufferSize, (buffer, offset, count) => { args.OnDataSent(buffer, offset, count); }, (buffer, offset, count) => { args.OnDataReceived(buffer, offset, count); }); args.Dispose(); break; } //construct the web request that we are going to issue on behalf of the client. disposed = await HandleHttpSessionRequestInternal(connection, args, false); if (disposed) { //already disposed inside above method args.Dispose(); break; } //if connection is closing exit if (args.WebSession.Response.KeepAlive == false) { args.Dispose(); break; } args.Dispose(); // read the next request httpCmd = await clientStreamReader.ReadLineAsync(); } catch (Exception e) { ExceptionFunc(new ProxyHttpException("Error occured whilst handling session request", e, args)); break; } } if (!disposed) { Dispose(clientStream, clientStreamReader, clientStreamWriter, connection); } return(true); }
private void OnSessionEndOfTrack(object sender, SessionEventArgs e) { if (Playlist.CanGoNext) { Playlist.Next(); } }
/// <summary> /// Handle a specific session (request/response sequence) /// </summary> /// <param name="connection"></param> /// <param name="args"></param> /// <param name="closeConnection"></param> /// <returns></returns> private async Task <bool> HandleHttpSessionRequestInternal(TcpConnection connection, SessionEventArgs args, bool closeConnection) { bool disposed = false; bool keepAlive = false; try { args.WebSession.Request.RequestLocked = true; //if expect continue is enabled then send the headers first //and see if server would return 100 conitinue if (args.WebSession.Request.ExpectContinue) { args.WebSession.SetConnection(connection); await args.WebSession.SendRequest(Enable100ContinueBehaviour); } //If 100 continue was the response inform that to the client if (Enable100ContinueBehaviour) { if (args.WebSession.Request.Is100Continue) { await args.ProxyClient.ClientStreamWriter.WriteResponseStatusAsync(args.WebSession.Response.HttpVersion, (int)HttpStatusCode.Continue, "Continue"); await args.ProxyClient.ClientStreamWriter.WriteLineAsync(); } else if (args.WebSession.Request.ExpectationFailed) { await args.ProxyClient.ClientStreamWriter.WriteResponseStatusAsync(args.WebSession.Response.HttpVersion, (int)HttpStatusCode.ExpectationFailed, "Expectation Failed"); await args.ProxyClient.ClientStreamWriter.WriteLineAsync(); } } //If expect continue is not enabled then set the connectio and send request headers if (!args.WebSession.Request.ExpectContinue) { args.WebSession.SetConnection(connection); await args.WebSession.SendRequest(Enable100ContinueBehaviour); } //check if content-length is > 0 if (args.WebSession.Request.ContentLength > 0) { //If request was modified by user if (args.WebSession.Request.IsBodyRead) { if (args.WebSession.Request.ContentEncoding != null) { args.WebSession.Request.Body = await GetCompressedResponseBody(args.WebSession.Request.ContentEncoding, args.WebSession.Request.Body); } var body = args.WebSession.Request.Body; //chunked send is not supported as of now args.WebSession.Request.ContentLength = body.Length; var newStream = args.WebSession.ServerConnection.Stream; await newStream.WriteAsync(body, 0, body.Length); } else { if (!args.WebSession.Request.ExpectationFailed) { //If its a post/put/patch request, then read the client html body and send it to server if (args.WebSession.Request.HasBody) { await SendClientRequestBody(args); } } } } //If not expectation failed response was returned by server then parse response if (!args.WebSession.Request.ExpectationFailed) { disposed = await HandleHttpSessionResponse(args); //already disposed inside above method if (disposed) { return(true); } } //if connection is closing exit if (args.WebSession.Response.KeepAlive == false) { return(true); } if (!closeConnection) { keepAlive = true; return(false); } } catch (Exception e) { ExceptionFunc(new ProxyHttpException("Error occured whilst handling session request (internal)", e, args)); return(true); } finally { if (!disposed && !keepAlive) { //dispose Dispose(args.ProxyClient.ClientStream, args.ProxyClient.ClientStreamReader, args.ProxyClient.ClientStreamWriter, args.WebSession.ServerConnection); } } return(true); }
public async Task OnResponse(object sender, SessionEventArgs e) { #if DEBUG Debug.WriteLine("OnResponse" + e.HttpClient.Request.RequestUri.AbsoluteUri); Logger.Info("OnResponse" + e.HttpClient.Request.RequestUri.AbsoluteUri); #endif if (IsEnableScript) { if (IsOnlyWorkSteamBrowser) { var ua = e.HttpClient.Request.Headers.GetHeaders("User-Agent"); if (ua.Any()) { if (!ua.First().Value.Contains("Valve Steam")) { return; } } else { return; } } foreach (var script in Scripts) { if (script.Enable) { if (e.HttpClient.Request.Method == "GET") { if (e.HttpClient.Response.StatusCode == 200) { if (e.HttpClient.Response.ContentType != null && e.HttpClient.Response.ContentType.Trim().ToLower().Contains("text/html")) { foreach (var host in script.Exclude) { if (e.HttpClient.Request.RequestUri.AbsoluteUri.IsWildcard(host)) { goto close; } } foreach (var host in script.Match) { if (e.HttpClient.Request.RequestUri.AbsoluteUri.IsWildcard(host)) { var doc = await e.GetResponseBodyAsString(); if (script.Require.Length > 0) { //var headIndex = doc.LastIndexOf("</head>", StringComparison.OrdinalIgnoreCase); //doc = doc.Insert(headIndex, "<meta http-equiv=\"Content-Security-Policy\" content=\"default - src 'self' data: gap: https://ssl.gstatic.com 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *\">"); var t = e.HttpClient.Response.Headers.GetFirstHeader("Content-Security-Policy"); if (!string.IsNullOrEmpty(t.Value)) { //var tt = t.Value.Split(';'); //for (var i = 0; i < tt.Length; i++) //{ // if (tt[i].Contains("script-src")) // { // var cc = tt[i].Split(' ').ToList(); // foreach (var req in script.Require) // { // var u = new Uri(req); // cc.Add($"{u.Scheme}://{u.Host}/"); // } // tt[i] = string.Join(" ", cc); // } //} //var result = string.Join(";", tt); e.HttpClient.Response.Headers.RemoveHeader(t); //e.HttpClient.Response.Headers.AddHeader("Content-Security-Policy", result); } #if DEBUG Debug.WriteLine(e.HttpClient.Request.RequestUri.AbsoluteUri); #endif foreach (var req in script.Require) { var headIndex = doc.LastIndexOf("</head>", StringComparison.OrdinalIgnoreCase); //<script type="text/javascript" src=""></script> //var result = await httpServices.Get(req); var temp1 = $"<script type=\"text/javascript\" src=\"{req}\"></script>\n"; doc = doc.Insert(headIndex, temp1); } } var index = doc.LastIndexOf("</body>", StringComparison.OrdinalIgnoreCase); var temp = $"<script type=\"text/javascript\">{script.@Content}</script>"; doc = doc.Insert(index, temp); e.SetResponseBodyString(doc); } } } } } } close :; } } }
/// <summary> /// Session started event handler. /// </summary> private void SessionStartedEventHandler(SessionEventArgs e, RecoType rt) { var log = (rt == RecoType.Base) ? this.baseModelLogText : this.customModelLogText; this.WriteLine(log, String.Format(CultureInfo.InvariantCulture, "Speech recognition: Session started event: {0}.", e.ToString())); }
private void SessionStartedHandler(object sender, SessionEventArgs e) { Debug.Log("SessionStartedHandler called"); }
/// <summary> /// This is the core request handler method for a particular connection from client /// Will create new session (request/response) sequence until /// client/server abruptly terminates connection or by normal HTTP termination /// </summary> /// <param name="client"></param> /// <param name="clientStream"></param> /// <param name="clientStreamReader"></param> /// <param name="clientStreamWriter"></param> /// <param name="httpsConnectHostname"></param> /// <param name="endPoint"></param> /// <param name="connectRequest"></param> /// <param name="isTransparentEndPoint"></param> /// <returns></returns> private async Task HandleHttpSessionRequest(TcpClient client, CustomBufferedStream clientStream, CustomBinaryReader clientStreamReader, HttpResponseWriter clientStreamWriter, string httpsConnectHostname, ProxyEndPoint endPoint, ConnectRequest connectRequest, bool isTransparentEndPoint = false) { TcpConnection connection = null; try { //Loop through each subsequest request on this particular client connection //(assuming HTTP connection is kept alive by client) while (true) { // read the request line string httpCmd = await clientStreamReader.ReadLineAsync(); if (string.IsNullOrEmpty(httpCmd)) { break; } var args = new SessionEventArgs(BufferSize, endPoint, ExceptionFunc) { ProxyClient = { TcpClient = client }, WebSession = { ConnectRequest = connectRequest } }; try { Request.ParseRequestLine(httpCmd, out string httpMethod, out string httpUrl, out var version); //Read the request headers in to unique and non-unique header collections await HeaderParser.ReadHeaders(clientStreamReader, args.WebSession.Request.Headers); Uri httpRemoteUri; if (uriSchemeRegex.IsMatch(httpUrl)) { try { httpRemoteUri = new Uri(httpUrl); } catch (Exception ex) { throw new Exception($"Invalid URI: '{httpUrl}'", ex); } } else { string host = args.WebSession.Request.Host ?? httpsConnectHostname; string hostAndPath = host; if (httpUrl.StartsWith("/")) { hostAndPath += httpUrl; } string url = string.Concat(httpsConnectHostname == null ? "http://" : "https://", hostAndPath); try { httpRemoteUri = new Uri(url); } catch (Exception ex) { throw new Exception($"Invalid URI: '{url}'", ex); } } args.WebSession.Request.RequestUri = httpRemoteUri; args.WebSession.Request.OriginalUrl = httpUrl; args.WebSession.Request.Method = httpMethod; args.WebSession.Request.HttpVersion = version; args.ProxyClient.ClientStream = clientStream; args.ProxyClient.ClientStreamReader = clientStreamReader; args.ProxyClient.ClientStreamWriter = clientStreamWriter; //proxy authorization check if (!args.IsTransparent && httpsConnectHostname == null && await CheckAuthorization(clientStreamWriter, args) == false) { break; } if (!isTransparentEndPoint) { PrepareRequestHeaders(args.WebSession.Request.Headers); args.WebSession.Request.Host = args.WebSession.Request.RequestUri.Authority; } //if win auth is enabled //we need a cache of request body //so that we can send it after authentication in WinAuthHandler.cs if (isWindowsAuthenticationEnabledAndSupported && args.WebSession.Request.HasBody) { await args.GetRequestBody(); } //If user requested interception do it if (BeforeRequest != null) { await BeforeRequest.InvokeAsync(this, args, ExceptionFunc); } var response = args.WebSession.Response; if (args.WebSession.Request.CancelRequest) { await HandleHttpSessionResponse(args); if (!response.KeepAlive) { break; } continue; } //create a new connection if hostname/upstream end point changes if (connection != null && (!connection.HostName.Equals(args.WebSession.Request.RequestUri.Host, StringComparison.OrdinalIgnoreCase) || (args.WebSession.UpStreamEndPoint != null && !args.WebSession.UpStreamEndPoint.Equals(connection.UpStreamEndPoint)))) { connection.Dispose(); connection = null; } if (connection == null) { connection = await GetServerConnection(args, false); } //if upgrading to websocket then relay the requet without reading the contents if (args.WebSession.Request.UpgradeToWebSocket) { //prepare the prefix content var requestHeaders = args.WebSession.Request.Headers; await connection.StreamWriter.WriteLineAsync(httpCmd); await connection.StreamWriter.WriteHeadersAsync(requestHeaders); string httpStatus = await connection.StreamReader.ReadLineAsync(); Response.ParseResponseLine(httpStatus, out var responseVersion, out int responseStatusCode, out string responseStatusDescription); response.HttpVersion = responseVersion; response.StatusCode = responseStatusCode; response.StatusDescription = responseStatusDescription; await HeaderParser.ReadHeaders(connection.StreamReader, response.Headers); if (!args.IsTransparent) { await clientStreamWriter.WriteResponseAsync(response); } //If user requested call back then do it if (BeforeResponse != null && !args.WebSession.Response.ResponseLocked) { await BeforeResponse.InvokeAsync(this, args, ExceptionFunc); } await TcpHelper.SendRaw(clientStream, connection.Stream, BufferSize, (buffer, offset, count) => { args.OnDataSent(buffer, offset, count); }, (buffer, offset, count) => { args.OnDataReceived(buffer, offset, count); }, ExceptionFunc); break; } //construct the web request that we are going to issue on behalf of the client. await HandleHttpSessionRequestInternal(connection, args); //if connection is closing exit if (!response.KeepAlive) { break; } } catch (Exception e) when(!(e is ProxyHttpException)) { throw new ProxyHttpException("Error occured whilst handling session request", e, args); } finally { args.Dispose(); } } } finally { connection?.Dispose(); } }
private void session_SessionException(object sender, SessionEventArgs e) { this.OnSessionException(e.Session, e.SessionException); }
/// <summary> /// Handle a specific session (request/response sequence) /// </summary> /// <param name="connection"></param> /// <param name="args"></param> /// <returns>True if close the connection</returns> private async Task HandleHttpSessionRequestInternal(TcpConnection connection, SessionEventArgs args) { try { var request = args.WebSession.Request; request.RequestLocked = true; //if expect continue is enabled then send the headers first //and see if server would return 100 conitinue if (request.ExpectContinue) { args.WebSession.SetConnection(connection); await args.WebSession.SendRequest(Enable100ContinueBehaviour, args.IsTransparent); } //If 100 continue was the response inform that to the client if (Enable100ContinueBehaviour) { var clientStreamWriter = args.ProxyClient.ClientStreamWriter; if (request.Is100Continue) { await clientStreamWriter.WriteResponseStatusAsync(args.WebSession.Response.HttpVersion, (int)HttpStatusCode.Continue, "Continue"); await clientStreamWriter.WriteLineAsync(); } else if (request.ExpectationFailed) { await clientStreamWriter.WriteResponseStatusAsync(args.WebSession.Response.HttpVersion, (int)HttpStatusCode.ExpectationFailed, "Expectation Failed"); await clientStreamWriter.WriteLineAsync(); } } //If expect continue is not enabled then set the connectio and send request headers if (!request.ExpectContinue) { args.WebSession.SetConnection(connection); await args.WebSession.SendRequest(Enable100ContinueBehaviour, args.IsTransparent); } //check if content-length is > 0 if (request.ContentLength > 0) { //If request was modified by user if (request.IsBodyRead) { if (request.ContentEncoding != null) { request.Body = await GetCompressedResponseBody(request.ContentEncoding, request.Body); } var body = request.Body; //chunked send is not supported as of now request.ContentLength = body.Length; await args.WebSession.ServerConnection.StreamWriter.WriteAsync(body); } else { if (!request.ExpectationFailed) { //If its a post/put/patch request, then read the client html body and send it to server if (request.HasBody) { HttpWriter writer = args.WebSession.ServerConnection.StreamWriter; await args.CopyRequestBodyAsync(writer, false); } } } } //If not expectation failed response was returned by server then parse response if (!request.ExpectationFailed) { await HandleHttpSessionResponse(args); } } catch (Exception e) when(!(e is ProxyHttpException)) { throw new ProxyHttpException("Error occured whilst handling session request (internal)", e, args); } }
void session_StreamingError(ISession sender, SessionEventArgs e) { this.ParentForm.BeginInvoke(new MethodInvoker(delegate() { WriteError(e.Message); CF_displayMessage("Streaming Error:" + Environment.NewLine + e.Message); })); }
/// <summary> /// Called asynchronously when a request was successful and we received the response. /// </summary> /// <param name="args">The session event arguments.</param> /// <returns> The task.</returns> private async Task handleHttpSessionResponse(SessionEventArgs args) { var cancellationToken = args.CancellationTokenSource.Token; // read response & headers from server await args.HttpClient.ReceiveResponse(cancellationToken); // Server may send expect-continue even if not asked for it in request. // According to spec "the client can simply discard this interim response." if (args.HttpClient.Response.StatusCode == (int)HttpStatusCode.Continue) { await args.ClearResponse(cancellationToken); await args.HttpClient.ReceiveResponse(cancellationToken); } args.TimeLine["Response Received"] = DateTime.UtcNow; var response = args.HttpClient.Response; args.ReRequest = false; // check for windows authentication if (args.EnableWinAuth) { if (response.StatusCode == (int)HttpStatusCode.Unauthorized) { await handle401UnAuthorized(args); } else { WinAuthEndPoint.AuthenticatedResponse(args.HttpClient.Data); } } // save original values so that if user changes them // we can still use original values when syphoning out data from attached tcp connection. response.SetOriginalHeaders(); // if user requested call back then do it if (!response.Locked) { await onBeforeResponse(args); } // it may changed in the user event response = args.HttpClient.Response; var clientStream = args.ClientStream; // user set custom response by ignoring original response from server. if (response.Locked) { // write custom user response with body and return. await clientStream.WriteResponseAsync(response, cancellationToken); if (args.HttpClient.HasConnection && !args.HttpClient.CloseServerConnection) { // syphon out the original response body from server connection // so that connection will be good to be reused. await args.SyphonOutBodyAsync(false, cancellationToken); } return; } // if user requested to send request again // likely after making modifications from User Response Handler if (args.ReRequest) { if (args.HttpClient.HasConnection) { await tcpConnectionFactory.Release(args.HttpClient.Connection); } // clear current response await args.ClearResponse(cancellationToken); await handleHttpSessionRequest(args, null, args.ClientConnection.NegotiatedApplicationProtocol, cancellationToken, args.CancellationTokenSource); return; } response.Locked = true; if (!args.IsTransparent && !args.IsSocks) { response.Headers.FixProxyHeaders(); } await clientStream.WriteResponseAsync(response, cancellationToken); if (response.OriginalHasBody) { if (response.IsBodySent) { // syphon out body await args.SyphonOutBodyAsync(false, cancellationToken); } else { // Copy body if exists var serverStream = args.HttpClient.Connection.Stream; await serverStream.CopyBodyAsync(response, false, clientStream, TransformationMode.None, args.OnDataReceived, cancellationToken); } } args.TimeLine["Response Sent"] = DateTime.UtcNow; }
public virtual void greetingReceived(SessionEventArgs e) { }
/// <summary> /// Handle windows NTLM authentication /// Can expand this for Kerberos in future /// Note: NTLM/Kerberos cannot do a man in middle operation /// we do for HTTPS requests. /// As such we will be sending local credentials of current /// User to server to authenticate requests. /// To disable this set ProxyServer.EnableWinAuth to false /// </summary> internal async Task <bool> Handle401UnAuthorized(SessionEventArgs args) { string headerName = null; HttpHeader authHeader = null; //check in non-unique headers first var header = args.WebSession.Response.Headers.NonUniqueHeaders.FirstOrDefault( x => authHeaderNames.Any(y => x.Key.Equals(y, StringComparison.OrdinalIgnoreCase))); if (!header.Equals(new KeyValuePair <string, List <HttpHeader> >())) { headerName = header.Key; } if (headerName != null) { authHeader = args.WebSession.Response.Headers.NonUniqueHeaders[headerName] .FirstOrDefault(x => authSchemes.Any(y => x.Value.StartsWith(y, StringComparison.OrdinalIgnoreCase))); } //check in unique headers if (authHeader == null) { //check in non-unique headers first var uHeader = args.WebSession.Response.Headers.Headers.FirstOrDefault(x => authHeaderNames.Any(y => x.Key.Equals(y, StringComparison.OrdinalIgnoreCase))); if (!uHeader.Equals(new KeyValuePair <string, HttpHeader>())) { headerName = uHeader.Key; } if (headerName != null) { authHeader = authSchemes.Any(x => args.WebSession.Response.Headers.Headers[headerName].Value .StartsWith(x, StringComparison.OrdinalIgnoreCase)) ? args.WebSession.Response.Headers.Headers[headerName] : null; } } if (authHeader != null) { string scheme = authSchemes.FirstOrDefault(x => authHeader.Value.Equals(x, StringComparison.OrdinalIgnoreCase)); //clear any existing headers to avoid confusing bad servers if (args.WebSession.Request.Headers.NonUniqueHeaders.ContainsKey("Authorization")) { args.WebSession.Request.Headers.NonUniqueHeaders.Remove("Authorization"); } //initial value will match exactly any of the schemes if (scheme != null) { string clientToken = WinAuthHandler.GetInitialAuthToken(args.WebSession.Request.Host, scheme, args.Id); var auth = new HttpHeader("Authorization", string.Concat(scheme, clientToken)); //replace existing authorization header if any if (args.WebSession.Request.Headers.Headers.ContainsKey("Authorization")) { args.WebSession.Request.Headers.Headers["Authorization"] = auth; } else { args.WebSession.Request.Headers.Headers.Add("Authorization", auth); } //don't need to send body for Authorization request if (args.WebSession.Request.HasBody) { args.WebSession.Request.ContentLength = 0; } } //challenge value will start with any of the scheme selected else { scheme = authSchemes.FirstOrDefault(x => authHeader.Value.StartsWith(x, StringComparison.OrdinalIgnoreCase) && authHeader.Value.Length > x.Length + 1); string serverToken = authHeader.Value.Substring(scheme.Length + 1); string clientToken = WinAuthHandler.GetFinalAuthToken(args.WebSession.Request.Host, serverToken, args.Id); //there will be an existing header from initial client request args.WebSession.Request.Headers.Headers["Authorization"] = new HttpHeader("Authorization", string.Concat(scheme, clientToken)); //send body for final auth request if (args.WebSession.Request.HasBody) { args.WebSession.Request.ContentLength = args.WebSession.Request.Body.Length; } } //Need to revisit this. //Should we cache all Set-Cokiee headers from server during auth process //and send it to client after auth? //clear current server response await args.ClearResponse(); //request again with updated authorization header //and server cookies bool disposed = await HandleHttpSessionRequestInternal(args.WebSession.ServerConnection, args, false); return(disposed); } return(false); }
private static void HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream, CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, string secureTunnelHostName) { TcpConnection connection = null; string lastRequestHostName = null; while (true) { if (string.IsNullOrEmpty(httpCmd)) { Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null); break; } var args = new SessionEventArgs(BUFFER_SIZE); args.Client.TcpClient = client; try { //break up the line into three components (method, remote URL & Http Version) var httpCmdSplit = httpCmd.Split(SpaceSplit, 3); var httpMethod = httpCmdSplit[0]; var httpRemoteUri = new Uri(secureTunnelHostName == null ? httpCmdSplit[1] : (secureTunnelHostName + httpCmdSplit[1])); var httpVersion = httpCmdSplit[2]; Version version; if (httpVersion == "HTTP/1.1") { version = new Version(1, 1); } else { version = new Version(1, 0); } if (httpRemoteUri.Scheme == Uri.UriSchemeHttps) { args.IsHttps = true; } args.ProxySession.Request.RequestHeaders = new List<HttpHeader>(); string tmpLine; while (!string.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine())) { var header = tmpLine.Split(new char[] { ':' }, 2); args.ProxySession.Request.RequestHeaders.Add(new HttpHeader(header[0], header[1])); } SetRequestHeaders(args.ProxySession.Request.RequestHeaders, args.ProxySession); if (args.ProxySession.Request.UpgradeToWebSocket) { TcpHelper.SendRaw(clientStreamReader.BaseStream, httpCmd, args.ProxySession.Request.RequestHeaders, httpRemoteUri.Host, httpRemoteUri.Port, httpRemoteUri.Scheme == Uri.UriSchemeHttps); Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args); return; } args.ProxySession.Request.RequestUri = httpRemoteUri; args.ProxySession.Request.Method = httpMethod; args.ProxySession.Request.HttpVersion = httpVersion; args.Client.ClientStream = clientStream; args.Client.ClientStreamReader = clientStreamReader; args.Client.ClientStreamWriter = clientStreamWriter; args.ProxySession.Request.Hostname = args.ProxySession.Request.RequestUri.Host; args.ProxySession.Request.Url = args.ProxySession.Request.RequestUri.OriginalString; args.Client.ClientPort = ((IPEndPoint)client.Client.RemoteEndPoint).Port; args.Client.ClientIpAddress = ((IPEndPoint)client.Client.RemoteEndPoint).Address; //If requested interception if (BeforeRequest != null) { args.ProxySession.Request.Encoding = args.ProxySession.GetEncoding(); BeforeRequest(null, args); } args.ProxySession.Request.RequestLocked = true; if (args.ProxySession.Request.CancelRequest) { Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args); break; } //construct the web request that we are going to issue on behalf of the client. connection = connection == null ? TcpConnectionManager.GetClient(args.ProxySession.Request.RequestUri.Host, args.ProxySession.Request.RequestUri.Port, args.IsHttps) : lastRequestHostName != args.ProxySession.Request.Hostname ? TcpConnectionManager.GetClient(args.ProxySession.Request.RequestUri.Host, args.ProxySession.Request.RequestUri.Port, args.IsHttps) : connection; lastRequestHostName = args.ProxySession.Request.Hostname; args.ProxySession.SetConnection(connection); args.ProxySession.SendRequest(); //If request was modified by user if (args.ProxySession.Request.RequestBodyRead) { args.ProxySession.Request.ContentLength = args.ProxySession.Request.RequestBody.Length; var newStream = args.ProxySession.ProxyClient.ServerStreamReader.BaseStream; newStream.Write(args.ProxySession.Request.RequestBody, 0, args.ProxySession.Request.RequestBody.Length); } else { //If its a post/put request, then read the client html body and send it to server if (httpMethod.ToUpper() == "POST" || httpMethod.ToUpper() == "PUT") { SendClientRequestBody(args); } } HandleHttpSessionResponse(args); //if connection is closing exit if (args.ProxySession.Response.ResponseKeepAlive == false) { connection.TcpClient.Close(); Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args); return; } // read the next request httpCmd = clientStreamReader.ReadLine(); } catch { Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args); break; } } if (connection != null) TcpConnectionManager.ReleaseClient(connection); }
//Test script injection //Insert script to read the Browser URL and send it back to proxy public void OnResponse(object sender, SessionEventArgs e) { try { if (e.ProxyRequest.Method == "GET" || e.ProxyRequest.Method == "POST") { if (e.ServerResponse.StatusCode == HttpStatusCode.OK) { if (e.ServerResponse.ContentType.Trim().ToLower().Contains("text/html")) { string c = e.ServerResponse.GetResponseHeader("X-Requested-With"); if (e.ServerResponse.GetResponseHeader("X-Requested-With") == "") { e.GetResponseBody(); string functioname = "fr" + RandomString(10); string VisitedURL = RandomString(5); string RequestVariable = "c" + RandomString(5); string RandomURLEnding = RandomString(25); string RandomLastRequest = RandomString(10); string LocalRequest; if (e.IsSecure) { LocalRequest = "https://" + e.Hostname + "/" + RandomURLEnding; } else { LocalRequest = "http://" + e.Hostname + "/" + RandomURLEnding; } string script = "var " + RandomLastRequest + " = null;" + "if(window.top==self) { " + "\n" + " " + functioname + "();" + "setInterval(" + functioname + ",500); " + "\n" + "}" + "function " + functioname + "(){ " + "\n" + "var " + RequestVariable + " = new XMLHttpRequest(); " + "\n" + "var " + VisitedURL + " = null;" + "\n" + "if(window.top.location.href!=null) " + "\n" + "" + VisitedURL + " = window.top.location.href; else " + "\n" + "" + VisitedURL + " = document.referrer; " + "if(" + RandomLastRequest + "!= " + VisitedURL + ") {" + RequestVariable + ".open(\"POST\",\"" + LocalRequest + "\", true); " + "\n" + RequestVariable + ".send(" + VisitedURL + ");} " + RandomLastRequest + " = " + VisitedURL + "}"; string response = e.ResponseString; Regex RE = new Regex("</body>", RegexOptions.RightToLeft | RegexOptions.IgnoreCase | RegexOptions.Multiline); string replaced = RE.Replace(response, "<script type =\"text/javascript\">" + script + "</script></body>", 1); if (replaced.Length != response.Length) { e.ResponseString = replaced; _URLList.Add(RandomURLEnding); } } } } } } catch { } }
protected void OnExpired(SessionEventArgs e) { if (Expired == null) { return; } Expired(this, e); }
private static async Task OnResponseCaptureTrafficEventHandler(object sender, SessionEventArgs e) => await Task.Run( () => { if (!_responsesHistory.ContainsKey(e.HttpClient.Response.GetHashCode()) && e.HttpClient.Response != null) { _responsesHistory.Add(e.HttpClient.Response.GetHashCode(), e.HttpClient.Response); } });
protected virtual void OnStopped(ISession session) { AfterChanged(session); var e = new SessionEventArgs(new ImmutableProxiedSession(session)); OnStopped(e); }
void _sessionManager_SessionActivity(object sender, SessionEventArgs e) { SendData(false); }
private void ConnectionError(object sender, SessionEventArgs e) { if (e.Status != Error.OK) { ConsoleEx.WriteLine("Connection error: " + e.Message, ConsoleColor.Red); } }
void _sessionManager_CapabilitiesChanged(object sender, SessionEventArgs e) { SendData(true); }
private void UserLoggedOut(object sender, SessionEventArgs e) { ConsoleEx.WriteLine("Logged out..", ConsoleColor.Yellow); }
/// <summary> /// Invocator for BeforeRequest event. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected virtual void OnBeforeRequest(object sender, SessionEventArgs e) { BeforeRequest?.Invoke(sender, e); }
private void OnSessionPlayerTokenLost(object sender, SessionEventArgs e) { Pause(); _eventAggregator .GetEvent<NotificationEvent>() .Publish(new NotificationMessage("torshify has been paused because your account is used somewhere else")); }
static void OnSessionCompleted(object sender, SessionEventArgs e) { Console.WriteLine("SessionCompleted: {0}", e.Context.Properties[EndpointListener.RemoteEndPointKey]); e.Context.CommandExecuting -= OnCommandExecuting; }
void session_ConnectionError(ISession sender, SessionEventArgs e) { }
/// <summary> /// This is the core request handler method for a particular connection from client. /// Will create new session (request/response) sequence until /// client/server abruptly terminates connection or by normal HTTP termination. /// </summary> /// <param name="endPoint">The proxy endpoint.</param> /// <param name="clientStream">The client stream.</param> /// <param name="cancellationTokenSource">The cancellation token source for this async task.</param> /// <param name="connectArgs">The Connect request if this is a HTTPS request from explicit endpoint.</param> /// <param name="prefetchConnectionTask">Prefetched server connection for current client using Connect/SNI headers.</param> /// <param name="isHttps">Is HTTPS</param> private async Task handleHttpSessionRequest(ProxyEndPoint endPoint, HttpClientStream clientStream, CancellationTokenSource cancellationTokenSource, TunnelConnectSessionEventArgs?connectArgs = null, Task <TcpServerConnection?>?prefetchConnectionTask = null, bool isHttps = false) { var connectRequest = connectArgs?.HttpClient.ConnectRequest; var prefetchTask = prefetchConnectionTask; TcpServerConnection?connection = null; bool closeServerConnection = false; try { var cancellationToken = cancellationTokenSource.Token; // Loop through each subsequent request on this particular client connection // (assuming HTTP connection is kept alive by client) while (true) { if (clientStream.IsClosed) { return; } // read the request line var requestLine = await clientStream.ReadRequestLine(cancellationToken); if (requestLine.IsEmpty()) { return; } var args = new SessionEventArgs(this, endPoint, clientStream, connectRequest, cancellationTokenSource) { UserData = connectArgs?.UserData }; var request = args.HttpClient.Request; if (isHttps) { request.IsHttps = true; } try { try { // Read the request headers in to unique and non-unique header collections await HeaderParser.ReadHeaders(clientStream, args.HttpClient.Request.Headers, cancellationToken); if (connectRequest != null) { request.IsHttps = connectRequest.IsHttps; request.Authority = connectRequest.Authority; } request.RequestUriString8 = requestLine.RequestUri; request.Method = requestLine.Method; request.HttpVersion = requestLine.Version; // we need this to syphon out data from connection if API user changes them. request.SetOriginalHeaders(); // If user requested interception do it await onBeforeRequest(args); if (!args.IsTransparent && !args.IsSocks) { // proxy authorization check if (connectRequest == null && await checkAuthorization(args) == false) { await onBeforeResponse(args); // send the response await clientStream.WriteResponseAsync(args.HttpClient.Response, cancellationToken); return; } prepareRequestHeaders(request.Headers); request.Host = request.RequestUri.Authority; } // if win auth is enabled // we need a cache of request body // so that we can send it after authentication in WinAuthHandler.cs if (args.EnableWinAuth && request.HasBody) { await args.GetRequestBody(cancellationToken); } var response = args.HttpClient.Response; if (request.CancelRequest) { if (!(Enable100ContinueBehaviour && request.ExpectContinue)) { // syphon out the request body from client before setting the new body await args.SyphonOutBodyAsync(true, cancellationToken); } await handleHttpSessionResponse(args); if (!response.KeepAlive) { return; } continue; } // If prefetch task is available. if (connection == null && prefetchTask != null) { try { connection = await prefetchTask; } catch (SocketException e) { if (e.SocketErrorCode != SocketError.HostNotFound) { throw; } } prefetchTask = null; } if (connection != null) { var socket = connection.TcpSocket; bool part1 = socket.Poll(1000, SelectMode.SelectRead); bool part2 = socket.Available == 0; if (part1 & part2) { //connection is closed await tcpConnectionFactory.Release(connection, true); connection = null; } } // create a new connection if cache key changes. // only gets hit when connection pool is disabled. // or when prefetch task has a unexpectedly different connection. if (connection != null && (await tcpConnectionFactory.GetConnectionCacheKey(this, args, clientStream.Connection.NegotiatedApplicationProtocol) != connection.CacheKey)) { await tcpConnectionFactory.Release(connection); connection = null; } var result = await handleHttpSessionRequest(args, connection, clientStream.Connection.NegotiatedApplicationProtocol, cancellationToken, cancellationTokenSource); // update connection to latest used connection = result.LatestConnection; closeServerConnection = !result.Continue; // throw if exception happened if (result.Exception != null) { throw result.Exception; } if (!result.Continue) { return; } // user requested if (args.HttpClient.CloseServerConnection) { closeServerConnection = true; return; } // if connection is closing exit if (!response.KeepAlive) { closeServerConnection = true; return; } if (cancellationTokenSource.IsCancellationRequested) { throw new Exception("Session was terminated by user."); } // Release server connection for each HTTP session instead of per client connection. // This will be more efficient especially when client is idly holding server connection // between sessions without using it. // Do not release authenticated connections for performance reasons. // Otherwise it will keep authenticating per session. if (EnableConnectionPool && connection != null && !connection.IsWinAuthenticated) { await tcpConnectionFactory.Release(connection); connection = null; } } catch (Exception e) when(!(e is ProxyHttpException)) { throw new ProxyHttpException("Error occured whilst handling session request", e, args); } } catch (Exception e) { args.Exception = e; closeServerConnection = true; throw; } finally { await onAfterResponse(args); args.Dispose(); } } } finally { if (connection != null) { await tcpConnectionFactory.Release(connection, closeServerConnection); } await tcpConnectionFactory.Release(prefetchTask, closeServerConnection); } }
private static async Task OnRequestRedirectTrafficEventHandler(object sender, SessionEventArgs e) => await Task.Run( () => { if (_redirectUrls.Keys.Count > 0) { foreach (var redirectUrlPair in _redirectUrls) { if (e.HttpClient.Request.RequestUri.AbsoluteUri.Contains(redirectUrlPair.Key)) { e.Redirect(redirectUrlPair.Value); } } } }).ConfigureAwait(false);
/// <summary> /// Called asynchronously when a request was successfully and we received the response. /// </summary> /// <param name="args">The session event arguments.</param> /// <returns> The task.</returns> private async Task HandleHttpSessionResponse(SessionEventArgs args) { try { var cancellationToken = args.CancellationTokenSource.Token; // read response & headers from server await args.WebSession.ReceiveResponse(cancellationToken); var response = args.WebSession.Response; args.ReRequest = false; // check for windows authentication if (isWindowsAuthenticationEnabledAndSupported) { if (response.StatusCode == (int)HttpStatusCode.Unauthorized) { await Handle401UnAuthorized(args); } else { WinAuthEndPoint.AuthenticatedResponse(args.WebSession.Data); } } response.OriginalHasBody = response.HasBody; // if user requested call back then do it if (!response.Locked) { await InvokeBeforeResponse(args); } // it may changed in the user event response = args.WebSession.Response; var clientStreamWriter = args.ProxyClient.ClientStreamWriter; if (response.TerminateResponse || response.Locked) { await clientStreamWriter.WriteResponseAsync(response, cancellationToken : cancellationToken); if (!response.TerminateResponse) { // syphon out the response body from server before setting the new body await args.SyphonOutBodyAsync(false, cancellationToken); } else { args.WebSession.ServerConnection.Dispose(); args.WebSession.ServerConnection = null; } return; } // if user requested to send request again // likely after making modifications from User Response Handler if (args.ReRequest) { // clear current response await args.ClearResponse(cancellationToken); await HandleHttpSessionRequestInternal(args.WebSession.ServerConnection, args); return; } response.Locked = true; // Write back to client 100-conitinue response if that's what server returned if (response.Is100Continue) { await clientStreamWriter.WriteResponseStatusAsync(response.HttpVersion, (int)HttpStatusCode.Continue, "Continue", cancellationToken); await clientStreamWriter.WriteLineAsync(cancellationToken); } else if (response.ExpectationFailed) { await clientStreamWriter.WriteResponseStatusAsync(response.HttpVersion, (int)HttpStatusCode.ExpectationFailed, "Expectation Failed", cancellationToken); await clientStreamWriter.WriteLineAsync(cancellationToken); } if (!args.IsTransparent) { response.Headers.FixProxyHeaders(); } if (response.IsBodyRead) { await clientStreamWriter.WriteResponseAsync(response, cancellationToken : cancellationToken); } else { // Write back response status to client await clientStreamWriter.WriteResponseStatusAsync(response.HttpVersion, response.StatusCode, response.StatusDescription, cancellationToken); await clientStreamWriter.WriteHeadersAsync(response.Headers, cancellationToken : cancellationToken); // Write body if exists if (response.HasBody) { await args.CopyResponseBodyAsync(clientStreamWriter, TransformationMode.None, cancellationToken); } } } catch (Exception e) when(!(e is ProxyHttpException)) { throw new ProxyHttpException("Error occured whilst handling session response", e, args); } }
void _sessionManager_SessionStarted(object sender, SessionEventArgs e) { SendData(true); }
/// <summary> /// Invocator for BeforeResponse event. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> /// <returns></returns> protected virtual void OnBeforeResponse(object sender, SessionEventArgs e) { BeforeResponse?.Invoke(sender, e); }
/// <summary> /// 实现对缓存数据的更新 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void _sc_OnUpdateCacheCompleted(object sender, SessionEventArgs e) { //SessionService.Instance.Update(e.SyncCache); }
private void Connector_SessionStarted(object sender, SessionEventArgs e) { this.UpdateStatus("Listening ..."); this.RunOnUiThread(() => this.ListeningState = ListenState.Listening); }