Unverified Commit 51e83bae authored by honfika's avatar honfika Committed by GitHub

Merge pull request #683 from justcoding121/master

beta
parents 35a48908 abf159fc
...@@ -4,12 +4,10 @@ using System.IO; ...@@ -4,12 +4,10 @@ using System.IO;
using System.Net; using System.Net;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Titanium.Web.Proxy.Compression;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Http.Responses; using Titanium.Web.Proxy.Http.Responses;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network;
using Titanium.Web.Proxy.Network.Tcp; using Titanium.Web.Proxy.Network.Tcp;
using Titanium.Web.Proxy.StreamExtended.Network; using Titanium.Web.Proxy.StreamExtended.Network;
......
...@@ -52,18 +52,16 @@ namespace Titanium.Web.Proxy ...@@ -52,18 +52,16 @@ namespace Titanium.Web.Proxy
if (await HttpHelper.IsConnectMethod(clientStream, BufferPool, cancellationToken) == 1) if (await HttpHelper.IsConnectMethod(clientStream, BufferPool, cancellationToken) == 1)
{ {
// read the first line HTTP command // read the first line HTTP command
string? httpCmd = await clientStream.ReadLineAsync(cancellationToken); var requestLine = await clientStream.ReadRequestLine(cancellationToken);
if (string.IsNullOrEmpty(httpCmd)) if (requestLine.IsEmpty())
{ {
return; return;
} }
Request.ParseRequestLine(httpCmd!, out string _, out var httpUrl, out var version); var connectRequest = new ConnectRequest(requestLine.RequestUri.GetString())
var connectRequest = new ConnectRequest(httpUrl.GetString())
{ {
RequestUriString8 = httpUrl, RequestUriString8 = requestLine.RequestUri,
HttpVersion = version HttpVersion = requestLine.Version
}; };
await HeaderParser.ReadHeaders(clientStream, connectRequest.Headers, cancellationToken); await HeaderParser.ReadHeaders(clientStream, connectRequest.Headers, cancellationToken);
...@@ -105,7 +103,7 @@ namespace Titanium.Web.Proxy ...@@ -105,7 +103,7 @@ namespace Titanium.Web.Proxy
} }
// write back successful CONNECT response // write back successful CONNECT response
var response = ConnectResponse.CreateSuccessfulConnectResponse(version); var response = ConnectResponse.CreateSuccessfulConnectResponse(requestLine.Version);
// Set ContentLength explicitly to properly handle HTTP 1.0 // Set ContentLength explicitly to properly handle HTTP 1.0
response.ContentLength = 0; response.ContentLength = 0;
...@@ -175,7 +173,7 @@ namespace Titanium.Web.Proxy ...@@ -175,7 +173,7 @@ namespace Titanium.Web.Proxy
} }
} }
string connectHostname = httpUrl.GetString(); string connectHostname = requestLine.RequestUri.GetString();
int idx = connectHostname.IndexOf(":"); int idx = connectHostname.IndexOf(":");
if (idx >= 0) if (idx >= 0)
{ {
...@@ -214,6 +212,8 @@ namespace Titanium.Web.Proxy ...@@ -214,6 +212,8 @@ namespace Titanium.Web.Proxy
// HTTPS server created - we can now decrypt the client's traffic // HTTPS server created - we can now decrypt the client's traffic
clientStream = new HttpClientStream(sslStream, BufferPool); clientStream = new HttpClientStream(sslStream, BufferPool);
sslStream = null; // clientStream was created, no need to keep SSL stream reference
clientStream.DataRead += (o, args) => connectArgs.OnDecryptedDataSent(args.Buffer, args.Offset, args.Count); clientStream.DataRead += (o, args) => connectArgs.OnDecryptedDataSent(args.Buffer, args.Offset, args.Count);
clientStream.DataWrite += (o, args) => connectArgs.OnDecryptedDataReceived(args.Buffer, args.Offset, args.Count); clientStream.DataWrite += (o, args) => connectArgs.OnDecryptedDataReceived(args.Buffer, args.Offset, args.Count);
} }
......
...@@ -29,5 +29,19 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -29,5 +29,19 @@ namespace Titanium.Web.Proxy.Helpers
await WriteAsync(response, headerBuilder, cancellationToken); await WriteAsync(response, headerBuilder, cancellationToken);
} }
internal async ValueTask<RequestStatusInfo> ReadRequestLine(CancellationToken cancellationToken = default)
{
// read the first line HTTP command
string? httpCmd = await ReadLineAsync(cancellationToken);
if (string.IsNullOrEmpty(httpCmd))
{
return default;
}
Request.ParseRequestLine(httpCmd!, out string method, out var requestUri, out var version);
return new RequestStatusInfo { Method = method, RequestUri = requestUri, Version = version };
}
} }
} }
using System;
using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.Helpers
{
struct RequestStatusInfo
{
public string Method { get; set; }
public ByteString RequestUri { get; set; }
public Version Version { get; set; }
public bool IsEmpty()
{
return Method == null && RequestUri.Length == 0 && Version == null;
}
}
}
...@@ -100,12 +100,10 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -100,12 +100,10 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="onDataSend"></param> /// <param name="onDataSend"></param>
/// <param name="onDataReceive"></param> /// <param name="onDataReceive"></param>
/// <param name="cancellationTokenSource"></param> /// <param name="cancellationTokenSource"></param>
/// <param name="exceptionFunc"></param>
/// <returns></returns> /// <returns></returns>
private static async Task sendRawTap(Stream clientStream, Stream serverStream, IBufferPool bufferPool, private static async Task sendRawTap(Stream clientStream, Stream serverStream, IBufferPool bufferPool,
Action<byte[], int, int>? onDataSend, Action<byte[], int, int>? onDataReceive, Action<byte[], int, int>? onDataSend, Action<byte[], int, int>? onDataReceive,
CancellationTokenSource cancellationTokenSource, CancellationTokenSource cancellationTokenSource)
ExceptionHandler exceptionFunc)
{ {
// Now async relay all server=>client & client=>server data // Now async relay all server=>client & client=>server data
var sendRelay = var sendRelay =
...@@ -139,8 +137,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -139,8 +137,7 @@ namespace Titanium.Web.Proxy.Helpers
{ {
// todo: fix APM mode // todo: fix APM mode
return sendRawTap(clientStream, serverStream, bufferPool, onDataSend, onDataReceive, return sendRawTap(clientStream, serverStream, bufferPool, onDataSend, onDataReceive,
cancellationTokenSource, cancellationTokenSource);
exceptionFunc);
} }
} }
} }
...@@ -254,7 +254,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -254,7 +254,7 @@ namespace Titanium.Web.Proxy.Http
} }
} }
internal static void ParseRequestLine(string httpCmd, out string httpMethod, out ByteString httpUrl, internal static void ParseRequestLine(string httpCmd, out string method, out ByteString requestUri,
out Version version) out Version version)
{ {
int firstSpace = httpCmd.IndexOf(' '); int firstSpace = httpCmd.IndexOf(' ');
...@@ -269,21 +269,21 @@ namespace Titanium.Web.Proxy.Http ...@@ -269,21 +269,21 @@ namespace Titanium.Web.Proxy.Http
// break up the line into three components (method, remote URL & Http Version) // break up the line into three components (method, remote URL & Http Version)
// Find the request Verb // Find the request Verb
httpMethod = httpCmd.Substring(0, firstSpace); method = httpCmd.Substring(0, firstSpace);
if (!isAllUpper(httpMethod)) if (!isAllUpper(method))
{ {
httpMethod = httpMethod.ToUpper(); method = method.ToUpper();
} }
version = HttpHeader.Version11; version = HttpHeader.Version11;
if (firstSpace == lastSpace) if (firstSpace == lastSpace)
{ {
httpUrl = (ByteString)httpCmd.AsSpan(firstSpace + 1).ToString(); requestUri = (ByteString)httpCmd.AsSpan(firstSpace + 1).ToString();
} }
else else
{ {
httpUrl = (ByteString)httpCmd.AsSpan(firstSpace + 1, lastSpace - firstSpace - 1).ToString(); requestUri = (ByteString)httpCmd.AsSpan(firstSpace + 1, lastSpace - firstSpace - 1).ToString();
// parse the HTTP version // parse the HTTP version
var httpVersion = httpCmd.AsSpan(lastSpace + 1); var httpVersion = httpCmd.AsSpan(lastSpace + 1);
......
...@@ -196,7 +196,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -196,7 +196,7 @@ namespace Titanium.Web.Proxy.Http
/// Use the encoding specified to decode the byte[] data to string /// Use the encoding specified to decode the byte[] data to string
/// </summary> /// </summary>
[Browsable(false)] [Browsable(false)]
public string BodyString => bodyString ?? (bodyString = Encoding.GetString(Body)); public string BodyString => bodyString ??= Encoding.GetString(Body);
/// <summary> /// <summary>
/// Was the body read by user? /// Was the body read by user?
......
using System; using System;
using System.IO; using System.IO;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Threading;
using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Pkcs; using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Asn1.X509;
...@@ -219,11 +218,9 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -219,11 +218,9 @@ namespace Titanium.Web.Proxy.Network.Certificate
/// <param name="subject">The s subject cn.</param> /// <param name="subject">The s subject cn.</param>
/// <param name="switchToMtaIfNeeded">if set to <c>true</c> [switch to MTA if needed].</param> /// <param name="switchToMtaIfNeeded">if set to <c>true</c> [switch to MTA if needed].</param>
/// <param name="signingCert">The signing cert.</param> /// <param name="signingCert">The signing cert.</param>
/// <param name="cancellationToken">Task cancellation token</param>
/// <returns>X509Certificate2.</returns> /// <returns>X509Certificate2.</returns>
private X509Certificate2 makeCertificateInternal(string subject, private X509Certificate2 makeCertificateInternal(string subject,
bool switchToMtaIfNeeded, X509Certificate2? signingCert = null, bool switchToMtaIfNeeded, X509Certificate2? signingCert = null)
CancellationToken cancellationToken = default)
{ {
return makeCertificateInternal(subject, $"CN={subject}", return makeCertificateInternal(subject, $"CN={subject}",
DateTime.UtcNow.AddDays(-certificateGraceDays), DateTime.UtcNow.AddDays(certificateValidDays), DateTime.UtcNow.AddDays(-certificateGraceDays), DateTime.UtcNow.AddDays(certificateValidDays),
......
...@@ -58,8 +58,8 @@ namespace Titanium.Web.Proxy ...@@ -58,8 +58,8 @@ namespace Titanium.Web.Proxy
} }
// read the request line // read the request line
string? httpCmd = await clientStream.ReadLineAsync(cancellationToken); var requestLine = await clientStream.ReadRequestLine(cancellationToken);
if (string.IsNullOrEmpty(httpCmd)) if (requestLine.IsEmpty())
{ {
return; return;
} }
...@@ -73,8 +73,6 @@ namespace Titanium.Web.Proxy ...@@ -73,8 +73,6 @@ namespace Titanium.Web.Proxy
{ {
try try
{ {
Request.ParseRequestLine(httpCmd!, out string httpMethod, out ByteString httpUrl, out var version);
// Read the request headers in to unique and non-unique header collections // Read the request headers in to unique and non-unique header collections
await HeaderParser.ReadHeaders(clientStream, args.HttpClient.Request.Headers, await HeaderParser.ReadHeaders(clientStream, args.HttpClient.Request.Headers,
cancellationToken); cancellationToken);
...@@ -86,10 +84,10 @@ namespace Titanium.Web.Proxy ...@@ -86,10 +84,10 @@ namespace Titanium.Web.Proxy
request.Authority = connectRequest.Authority; request.Authority = connectRequest.Authority;
} }
request.RequestUriString8 = httpUrl; request.RequestUriString8 = requestLine.RequestUri;
request.Method = httpMethod; request.Method = requestLine.Method;
request.HttpVersion = version; request.HttpVersion = requestLine.Version;
if (!args.IsTransparent) if (!args.IsTransparent)
{ {
...@@ -293,13 +291,13 @@ namespace Titanium.Web.Proxy ...@@ -293,13 +291,13 @@ namespace Titanium.Web.Proxy
} }
// construct the web request that we are going to issue on behalf of the client. // construct the web request that we are going to issue on behalf of the client.
await handleHttpSessionRequest(connection, args); await handleHttpSessionRequest(args);
return true; return true;
}, generator, serverConnection); }, generator, serverConnection);
} }
private async Task handleHttpSessionRequest(TcpServerConnection connection, SessionEventArgs args) private async Task handleHttpSessionRequest(SessionEventArgs args)
{ {
var cancellationToken = args.CancellationTokenSource.Token; var cancellationToken = args.CancellationTokenSource.Token;
var request = args.HttpClient.Request; var request = args.HttpClient.Request;
......
...@@ -154,7 +154,7 @@ namespace Titanium.Web.Proxy.StreamExtended ...@@ -154,7 +154,7 @@ namespace Titanium.Web.Proxy.StreamExtended
if(extensionsStartPosition < recordLength + 5) if(extensionsStartPosition < recordLength + 5)
{ {
extensions = await ReadExtensions(majorVersion, minorVersion, peekStream, bufferPool, cancellationToken); extensions = await ReadExtensions(majorVersion, minorVersion, peekStream, cancellationToken);
} }
var clientHelloInfo = new ClientHelloInfo(3, majorVersion, minorVersion, random, sessionId, ciphers, peekStream.Position) var clientHelloInfo = new ClientHelloInfo(3, majorVersion, minorVersion, random, sessionId, ciphers, peekStream.Position)
...@@ -292,7 +292,7 @@ namespace Titanium.Web.Proxy.StreamExtended ...@@ -292,7 +292,7 @@ namespace Titanium.Web.Proxy.StreamExtended
if (extensionsStartPosition < recordLength + 5) if (extensionsStartPosition < recordLength + 5)
{ {
extensions = await ReadExtensions(majorVersion, minorVersion, peekStream, bufferPool, cancellationToken); extensions = await ReadExtensions(majorVersion, minorVersion, peekStream, cancellationToken);
} }
var serverHelloInfo = new ServerHelloInfo(3, majorVersion, minorVersion, random, sessionId, cipherSuite, peekStream.Position) var serverHelloInfo = new ServerHelloInfo(3, majorVersion, minorVersion, random, sessionId, cipherSuite, peekStream.Position)
...@@ -308,7 +308,7 @@ namespace Titanium.Web.Proxy.StreamExtended ...@@ -308,7 +308,7 @@ namespace Titanium.Web.Proxy.StreamExtended
return null; return null;
} }
private static async Task<Dictionary<string, SslExtension>?> ReadExtensions(int majorVersion, int minorVersion, PeekStreamReader peekStreamReader, IBufferPool bufferPool, CancellationToken cancellationToken) private static async Task<Dictionary<string, SslExtension>?> ReadExtensions(int majorVersion, int minorVersion, PeekStreamReader peekStreamReader, CancellationToken cancellationToken)
{ {
Dictionary<string, SslExtension>? extensions = null; Dictionary<string, SslExtension>? extensions = null;
if (majorVersion > 3 || majorVersion == 3 && minorVersion >= 1) if (majorVersion > 3 || majorVersion == 3 && minorVersion >= 1)
......
...@@ -75,14 +75,15 @@ namespace Titanium.Web.Proxy ...@@ -75,14 +75,15 @@ namespace Titanium.Web.Proxy
// HTTPS server created - we can now decrypt the client's traffic // HTTPS server created - we can now decrypt the client's traffic
clientStream = new HttpClientStream(sslStream, BufferPool); clientStream = new HttpClientStream(sslStream, BufferPool);
sslStream = null; // clientStream was created, no need to keep SSL stream reference
} }
catch (Exception e) catch (Exception e)
{ {
var certname = certificate?.GetNameInfo(X509NameType.SimpleName, false); var certName = certificate?.GetNameInfo(X509NameType.SimpleName, false);
var session = new SessionEventArgs(this, endPoint, clientConnection, clientStream, null, var session = new SessionEventArgs(this, endPoint, clientConnection, clientStream, null,
cancellationTokenSource); cancellationTokenSource);
throw new ProxyConnectException( throw new ProxyConnectException(
$"Couldn't authenticate host '{httpsHostName}' with certificate '{certname}'.", e, session); $"Couldn't authenticate host '{httpsHostName}' with certificate '{certName}'.", e, session);
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment