internal void InvokeBeforeRequest(Context ctx) => BeforeRequest?.Invoke(ctx);
private void OnBeforeRequest(IHttpRequest request) { Logger.BeforeRequest(request); BeforeRequest.Raise(this, new BeforeRequestEventArgs(request)); }
/// <summary> /// This is the core request handler method for a particular connection from client /// </summary> /// <param name="client"></param> /// <param name="httpCmd"></param> /// <param name="clientStream"></param> /// <param name="clientStreamReader"></param> /// <param name="clientStreamWriter"></param> /// <param name="httpsHostName"></param> /// <returns></returns> private async Task HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream, CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, string httpsHostName, ProxyEndPoint endPoint, List <HttpHeader> connectHeaders, ExternalProxy customUpStreamHttpProxy = null, ExternalProxy customUpStreamHttpsProxy = null) { 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)) { Dispose(clientStream, clientStreamReader, clientStreamWriter, null); break; } var args = new SessionEventArgs(BUFFER_SIZE, HandleHttpSessionResponse); args.ProxyClient.TcpClient = client; args.WebSession.ConnectHeaders = connectHeaders; args.WebSession.ProcessId = new Lazy <int>(() => { var remoteEndPoint = (IPEndPoint)args.ProxyClient.TcpClient.Client.RemoteEndPoint; //If client is localhost get the process id if (NetworkHelper.IsLocalIpAddress(remoteEndPoint.Address)) { return(NetworkHelper.GetProcessIdFromPort(remoteEndPoint.Port, endPoint.IpV6Enabled)); } //can't access process Id of remote request from remote machine return(-1); }); try { //break up the line into three components (method, remote URL & Http Version) var httpCmdSplit = httpCmd.Split(ProxyConstants.SpaceSplit, 3); var httpMethod = httpCmdSplit[0]; //find the request HTTP version Version httpVersion = new Version(1, 1); if (httpCmdSplit.Length == 3) { var httpVersionString = httpCmdSplit[2].ToLower().Trim(); if (httpVersionString == "http/1.0") { httpVersion = new Version(1, 0); } } //Read the request headers in to unique and non-unique header collections string tmpLine; while (!string.IsNullOrEmpty(tmpLine = await clientStreamReader.ReadLineAsync())) { var header = tmpLine.Split(ProxyConstants.ColonSplit, 2); var newHeader = new HttpHeader(header[0], header[1]); //if header exist in non-unique header collection add it there if (args.WebSession.Request.NonUniqueRequestHeaders.ContainsKey(newHeader.Name)) { args.WebSession.Request.NonUniqueRequestHeaders[newHeader.Name].Add(newHeader); } //if header is alread in unique header collection then move both to non-unique collection else if (args.WebSession.Request.RequestHeaders.ContainsKey(newHeader.Name)) { var existing = args.WebSession.Request.RequestHeaders[newHeader.Name]; var nonUniqueHeaders = new List <HttpHeader>(); nonUniqueHeaders.Add(existing); nonUniqueHeaders.Add(newHeader); args.WebSession.Request.NonUniqueRequestHeaders.Add(newHeader.Name, nonUniqueHeaders); args.WebSession.Request.RequestHeaders.Remove(newHeader.Name); } //add to unique header collection else { args.WebSession.Request.RequestHeaders.Add(newHeader.Name, newHeader); } } var httpRemoteUri = new Uri(httpsHostName == null ? httpCmdSplit[1] : (string.Concat("https://", args.WebSession.Request.Host == null ? httpsHostName : args.WebSession.Request.Host, httpCmdSplit[1]))); args.WebSession.Request.RequestUri = httpRemoteUri; args.WebSession.Request.Method = httpMethod.Trim().ToUpper(); args.WebSession.Request.HttpVersion = httpVersion; args.ProxyClient.ClientStream = clientStream; args.ProxyClient.ClientStreamReader = clientStreamReader; args.ProxyClient.ClientStreamWriter = clientStreamWriter; if (httpsHostName == null && (await CheckAuthorization(clientStreamWriter, args.WebSession.Request.RequestHeaders.Values) == false)) { Dispose(clientStream, clientStreamReader, clientStreamWriter, args); break; } PrepareRequestHeaders(args.WebSession.Request.RequestHeaders, args.WebSession); args.WebSession.Request.Host = args.WebSession.Request.RequestUri.Authority; //If user requested interception do it if (BeforeRequest != null) { Delegate[] invocationList = BeforeRequest.GetInvocationList(); Task[] handlerTasks = new Task[invocationList.Length]; for (int i = 0; i < invocationList.Length; i++) { handlerTasks[i] = ((Func <object, SessionEventArgs, Task>)invocationList[i])(null, args); } await Task.WhenAll(handlerTasks); } //if upgrading to websocket then relay the requet without reading the contents if (args.WebSession.Request.UpgradeToWebSocket) { await TcpHelper.SendRaw(BUFFER_SIZE, ConnectionTimeOutSeconds, httpRemoteUri.Host, httpRemoteUri.Port, httpCmd, httpVersion, args.WebSession.Request.RequestHeaders, args.IsHttps, SupportedSslProtocols, new RemoteCertificateValidationCallback(ValidateServerCertificate), new LocalCertificateSelectionCallback(SelectClientCertificate), clientStream, tcpConnectionFactory, UpStreamEndPoint); Dispose(clientStream, clientStreamReader, clientStreamWriter, args); break; } //construct the web request that we are going to issue on behalf of the client. await HandleHttpSessionRequestInternal(connection, args, customUpStreamHttpProxy, customUpStreamHttpsProxy, false).ConfigureAwait(false); if (args.WebSession.Request.CancelRequest) { break; } //if connection is closing exit if (args.WebSession.Response.ResponseKeepAlive == false) { break; } // read the next request httpCmd = await clientStreamReader.ReadLineAsync(); } catch (Exception e) { ExceptionFunc(new ProxyHttpException("Error occured whilst handling session request", e, args)); Dispose(clientStream, clientStreamReader, clientStreamWriter, args); break; } } if (connection != null) { //dispose connection.Dispose(); } }
/// <summary> /// This is the core request handler method for a particular connection from client /// </summary> /// <param name="client"></param> /// <param name="httpCmd"></param> /// <param name="clientStream"></param> /// <param name="clientStreamReader"></param> /// <param name="clientStreamWriter"></param> /// <param name="isHttps"></param> /// <returns></returns> private async Task HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream, CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, bool isHttps) { TcpConnectionCache 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)) { Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null); break; } var args = new SessionEventArgs(BUFFER_SIZE, HandleHttpSessionResponse); args.ProxyClient.TcpClient = client; try { //break up the line into three components (method, remote URL & Http Version) var httpCmdSplit = httpCmd.Split(ProxyConstants.SpaceSplit, 3); var httpMethod = httpCmdSplit[0]; //find the request HTTP version Version version = new Version(1, 1); if (httpCmdSplit.Length == 3) { var httpVersion = httpCmdSplit[2].ToLower().Trim(); if (httpVersion == "http/1.0") { version = new Version(1, 0); } } args.WebSession.Request.RequestHeaders = new List <HttpHeader>(); //Read the request headers string tmpLine; while (!string.IsNullOrEmpty(tmpLine = await clientStreamReader.ReadLineAsync())) { var header = tmpLine.Split(ProxyConstants.ColonSplit, 2); args.WebSession.Request.RequestHeaders.Add(new HttpHeader(header[0], header[1])); } var httpRemoteUri = new Uri(!isHttps ? httpCmdSplit[1] : (string.Concat("https://", args.WebSession.Request.Host, httpCmdSplit[1]))); #if DEBUG //Just ignore local requests while Debugging //Its annoying if (httpRemoteUri.Host.Contains("localhost")) { Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null); break; } #endif args.WebSession.Request.RequestUri = httpRemoteUri; args.WebSession.Request.Method = httpMethod; args.WebSession.Request.HttpVersion = version; args.ProxyClient.ClientStream = clientStream; args.ProxyClient.ClientStreamReader = clientStreamReader; args.ProxyClient.ClientStreamWriter = clientStreamWriter; PrepareRequestHeaders(args.WebSession.Request.RequestHeaders, args.WebSession); args.WebSession.Request.Host = args.WebSession.Request.RequestUri.Authority; //If user requested interception do it if (BeforeRequest != null) { Delegate[] invocationList = BeforeRequest.GetInvocationList(); Task[] handlerTasks = new Task[invocationList.Length]; for (int i = 0; i < invocationList.Length; i++) { handlerTasks[i] = ((Func <object, SessionEventArgs, Task>)invocationList[i])(null, args); } await Task.WhenAll(handlerTasks); } //if upgrading to websocket then relay the requet without reading the contents if (args.WebSession.Request.UpgradeToWebSocket) { await TcpHelper.SendRaw(clientStream, httpCmd, args.WebSession.Request.RequestHeaders, httpRemoteUri.Host, httpRemoteUri.Port, args.IsHttps, SupportedSslProtocols); Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args); return; } //construct the web request that we are going to issue on behalf of the client. connection = await tcpConnectionCacheManager.GetClient(args.WebSession.Request.RequestUri.Host, args.WebSession.Request.RequestUri.Port, args.IsHttps, version, UpStreamHttpProxy, UpStreamHttpsProxy, BUFFER_SIZE, SupportedSslProtocols, new RemoteCertificateValidationCallback(ValidateServerCertificate), new LocalCertificateSelectionCallback(SelectClientCertificate)); args.WebSession.Request.RequestLocked = true; //If request was cancelled by user then dispose the client if (args.WebSession.Request.CancelRequest) { Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args); break; } //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 WriteResponseStatus(args.WebSession.Response.HttpVersion, "100", "Continue", args.ProxyClient.ClientStreamWriter); await args.ProxyClient.ClientStreamWriter.WriteLineAsync(); } else if (args.WebSession.Request.ExpectationFailed) { await WriteResponseStatus(args.WebSession.Response.HttpVersion, "417", "Expectation Failed", args.ProxyClient.ClientStreamWriter); 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); } //If request was modified by user if (args.WebSession.Request.RequestBodyRead) { if (args.WebSession.Request.ContentEncoding != null) { args.WebSession.Request.RequestBody = await GetCompressedResponseBody(args.WebSession.Request.ContentEncoding, args.WebSession.Request.RequestBody); } //chunked send is not supported as of now args.WebSession.Request.ContentLength = args.WebSession.Request.RequestBody.Length; var newStream = args.WebSession.ServerConnection.Stream; await newStream.WriteAsync(args.WebSession.Request.RequestBody, 0, args.WebSession.Request.RequestBody.Length); } else { if (!args.WebSession.Request.ExpectationFailed) { //If its a post/put request, then read the client html body and send it to server if (httpMethod.ToUpper() == "POST" || httpMethod.ToUpper() == "PUT") { await SendClientRequestBody(args); } } } //If not expectation failed response was returned by server then parse response if (!args.WebSession.Request.ExpectationFailed) { await HandleHttpSessionResponse(args); } //if connection is closing exit if (args.WebSession.Response.ResponseKeepAlive == false) { Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args); return; } //send the tcp connection to server back to connection cache for reuse await tcpConnectionCacheManager.ReleaseClient(connection); // read the next request httpCmd = await clientStreamReader.ReadLineAsync(); } catch { Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args); break; } } }
async Task <string> IRCallbacks.ReadConsole(IReadOnlyList <IRContext> contexts, string prompt, int len, bool addToHistory, CancellationToken ct) { await TaskUtilities.SwitchToBackgroundThread(); if (!_initializedTcs.Task.IsCompleted) { await AfterHostStarted(_startupInfo); } var callback = _callback; if (!addToHistory && callback != null) { using (_readUserInputReentrancyCounter.Increment()) { return(await callback.ReadUserInput(prompt, len, ct)); } } var currentRequest = Interlocked.Exchange(ref _currentRequestSource, null); _contexts = contexts; Prompt = GetDefaultPrompt(prompt); MaxLength = len; IsProcessing = contexts.Count != 1; var requestEventArgs = new RBeforeRequestEventArgs(contexts, Prompt, len, addToHistory); BeforeRequest?.Invoke(this, requestEventArgs); OnMutated(); currentRequest?.CompleteResponse(); string consoleInput = null; do { ct.ThrowIfCancellationRequested(); try { consoleInput = await ReadNextRequest(Prompt, len, ct); } catch (OperationCanceledException ex) when(!(ex is CancelAllException)) { // If request was canceled through means other than our token, it indicates the refusal of // that requestor to respond to that particular prompt, so move on to the next requestor. // If it was canceled through the token, then host itself is shutting down, and cancellation // will be propagated on the entry to next iteration of this loop. // // If request was canceled due to CancelAllAsync, then we should not continue to process this // ReadConsole call at all. Under normal conditions, ct will also be marked as canceled; but // there is a potential for a race condition where we get a cancellation exception here, but // ct is not marked as canceled yet. Explicitly checking for CancelAllException handles this. } } while (consoleInput == null); // We only want to fire 'directory changed' events when it is initiated by the user _processingChangeDirectoryCommand = consoleInput.StartsWithOrdinal("setwd"); consoleInput = consoleInput.EnsureLineBreak(); AfterRequest?.Invoke(this, new RAfterRequestEventArgs(contexts, Prompt, consoleInput, addToHistory, currentRequest?.IsVisible ?? false)); IsProcessing = true; return(consoleInput); }
public Task <IRSessionInteraction> BeginInteractionAsync(bool isVisible = true, CancellationToken cancellationToken = default(CancellationToken)) { _inter = new RSessionInteractionMock(); BeforeRequest?.Invoke(this, new RRequestEventArgs(_inter.Contexts, Prompt, 4096, true)); return(Task.FromResult(_inter)); }
/// <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.RequestHeaders); 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.OriginalRequestUrl = 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.RequestHeaders); args.WebSession.Request.Host = args.WebSession.Request.RequestUri.Authority; #if NET45 //if win auth is enabled //we need a cache of request body //so that we can send it after authentication in WinAuthHandler.cs if (EnableWinAuth && !RunTime.IsRunningOnMono && args.WebSession.Request.HasBody) { await args.GetRequestBody(); } #endif //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 changes if (connection != null && !connection.HostName.Equals(args.WebSession.Request.RequestUri.Host, StringComparison.OrdinalIgnoreCase)) { connection.Dispose(); UpdateServerConnectionCount(false); 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.RequestHeaders; byte[] requestBytes; using (var ms = new MemoryStream()) using (var writer = new HttpRequestWriter(ms)) { 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.ResponseStatusCode = responseStatusCode; args.WebSession.Response.ResponseStatusDescription = responseStatusDescription; await HeaderParser.ReadHeaders(connection.StreamReader, args.WebSession.Response.ResponseHeaders); 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, (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.ResponseKeepAlive == 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 int onBeforeRequest(long handle) { return((int)BeforeRequest?.Invoke(new Session(handle, new Request(handle), new Response(handle)))); }
/// <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="httpsHostName"></param> /// <param name="endPoint"></param> /// <param name="connectHeaders"></param> /// <returns></returns> private async Task <bool> HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream, CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, string httpsHostName, ProxyEndPoint endPoint, List <HttpHeader> connectHeaders) { 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, HandleHttpSessionResponse) { ProxyClient = { TcpClient = client }, WebSession = { ConnectHeaders = connectHeaders } }; args.WebSession.ProcessId = new Lazy <int>(() => { var remoteEndPoint = (IPEndPoint)args.ProxyClient.TcpClient.Client.RemoteEndPoint; //If client is localhost get the process id if (NetworkHelper.IsLocalIpAddress(remoteEndPoint.Address)) { return(NetworkHelper.GetProcessIdFromPort(remoteEndPoint.Port, endPoint.IpV6Enabled)); } //can't access process Id of remote request from remote machine return(-1); }); try { //break up the line into three components (method, remote URL & Http Version) var httpCmdSplit = httpCmd.Split(ProxyConstants.SpaceSplit, 3); var httpMethod = httpCmdSplit[0]; //find the request HTTP version var httpVersion = HttpHeader.Version11; if (httpCmdSplit.Length == 3) { var httpVersionString = httpCmdSplit[2].Trim(); if (string.Equals(httpVersionString, "HTTP/1.0", StringComparison.OrdinalIgnoreCase)) { httpVersion = HttpHeader.Version10; } } //Read the request headers in to unique and non-unique header collections await HeaderParser.ReadHeaders(clientStreamReader, args.WebSession.Request.NonUniqueRequestHeaders, args.WebSession.Request.RequestHeaders); var httpRemoteUri = new Uri(httpsHostName == null ? httpCmdSplit[1] : string.Concat("https://", args.WebSession.Request.Host ?? httpsHostName, httpCmdSplit[1])); args.WebSession.Request.RequestUri = httpRemoteUri; args.WebSession.Request.Method = httpMethod.Trim().ToUpper(); args.WebSession.Request.HttpVersion = httpVersion; args.ProxyClient.ClientStream = clientStream; args.ProxyClient.ClientStreamReader = clientStreamReader; args.ProxyClient.ClientStreamWriter = clientStreamWriter; if (httpsHostName == null && await CheckAuthorization(clientStreamWriter, args.WebSession.Request.RequestHeaders.Values) == false) { args.Dispose(); break; } PrepareRequestHeaders(args.WebSession.Request.RequestHeaders, args.WebSession); 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 (EnableWinAuth && !RunTime.IsRunningOnMono && args.WebSession.Request.HasBody) { await args.GetRequestBody(); } //If user requested interception do it if (BeforeRequest != null) { await BeforeRequest.InvokeParallelAsync(this, args); } //if upgrading to websocket then relay the requet without reading the contents if (args.WebSession.Request.UpgradeToWebSocket) { await TcpHelper.SendRaw(this, httpRemoteUri.Host, httpRemoteUri.Port, httpCmd, httpVersion, args.WebSession.Request.RequestHeaders, args.IsHttps, clientStream, tcpConnectionFactory, connection); args.Dispose(); break; } if (connection == null) { connection = await GetServerConnection(args); } //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 (args.WebSession.Request.CancelRequest) { args.Dispose(); break; } //if connection is closing exit if (args.WebSession.Response.ResponseKeepAlive == 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 onBeforeRequest(long handle) { BeforeRequest?.Invoke(new Session(handle, new Request(handle), new Response(handle))); }
/// <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(); } }
public virtual void OnBeforeRequest(WebEventArgs e) { BeforeRequest?.Invoke(e.Context, e); }
protected virtual void OnBeforeRequest(ClientRequestEventArgs e) { BeforeRequest?.Invoke(this, e); }
/// <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); }