Skip to content
This repository has been archived by the owner on Jul 9, 2023. It is now read-only.

Commit

Permalink
Merge pull request #656 from justcoding121/master
Browse files Browse the repository at this point in the history
better uri handling
  • Loading branch information
honfika authored Nov 16, 2019
2 parents 183f960 + 1b0bfec commit e24f3cc
Show file tree
Hide file tree
Showing 36 changed files with 415 additions and 174 deletions.
8 changes: 4 additions & 4 deletions src/Titanium.Web.Proxy/Compression/CompressionFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ namespace Titanium.Web.Proxy.Compression
/// </summary>
internal static class CompressionFactory
{
internal static Stream Create(string type, Stream stream, bool leaveOpen = true)
internal static Stream Create(HttpCompression type, Stream stream, bool leaveOpen = true)
{
switch (type)
{
case KnownHeaders.ContentEncodingGzip:
case HttpCompression.Gzip:
return new GZipStream(stream, CompressionMode.Compress, leaveOpen);
case KnownHeaders.ContentEncodingDeflate:
case HttpCompression.Deflate:
return new DeflateStream(stream, CompressionMode.Compress, leaveOpen);
case KnownHeaders.ContentEncodingBrotli:
case HttpCompression.Brotli:
return new BrotliSharpLib.BrotliStream(stream, CompressionMode.Compress, leaveOpen);
default:
throw new Exception($"Unsupported compression mode: {type}");
Expand Down
22 changes: 22 additions & 0 deletions src/Titanium.Web.Proxy/Compression/CompressionUtil.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;
using Titanium.Web.Proxy.Http;

namespace Titanium.Web.Proxy.Compression
{
internal static class CompressionUtil
{
public static HttpCompression CompressionNameToEnum(string name)
{
if (KnownHeaders.ContentEncodingGzip.Equals(name.AsSpan()))
return HttpCompression.Gzip;

if (KnownHeaders.ContentEncodingDeflate.Equals(name.AsSpan()))
return HttpCompression.Deflate;

if (KnownHeaders.ContentEncodingBrotli.Equals(name.AsSpan()))
return HttpCompression.Brotli;

return HttpCompression.Unsupported;
}
}
}
8 changes: 4 additions & 4 deletions src/Titanium.Web.Proxy/Compression/DecompressionFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ namespace Titanium.Web.Proxy.Compression
/// </summary>
internal class DecompressionFactory
{
internal static Stream Create(string type, Stream stream, bool leaveOpen = true)
internal static Stream Create(HttpCompression type, Stream stream, bool leaveOpen = true)
{
switch (type)
{
case KnownHeaders.ContentEncodingGzip:
case HttpCompression.Gzip:
return new GZipStream(stream, CompressionMode.Decompress, leaveOpen);
case KnownHeaders.ContentEncodingDeflate:
case HttpCompression.Deflate:
return new DeflateStream(stream, CompressionMode.Decompress, leaveOpen);
case KnownHeaders.ContentEncodingBrotli:
case HttpCompression.Brotli:
return new BrotliSharpLib.BrotliStream(stream, CompressionMode.Decompress, leaveOpen);
default:
throw new Exception($"Unsupported decompression mode: {type}");
Expand Down
12 changes: 12 additions & 0 deletions src/Titanium.Web.Proxy/Compression/HttpCompression.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.IO.Compression;

namespace Titanium.Web.Proxy.Compression
{
internal enum HttpCompression
{
Unsupported,
Gzip,
Deflate,
Brotli,
}
}
2 changes: 1 addition & 1 deletion src/Titanium.Web.Proxy/EventArguments/LimitedStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ private void getNextChunk()

readChunkTrail = true;

string? chunkHead = baseStream.ReadLineAsync().Result;
string? chunkHead = baseStream.ReadLineAsync().Result!;
int idx = chunkHead.IndexOf(";", StringComparison.Ordinal);
if (idx >= 0)
{
Expand Down
4 changes: 2 additions & 2 deletions src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public class SessionEventArgs : SessionEventArgsBase
/// Constructor to initialize the proxy
/// </summary>
internal SessionEventArgs(ProxyServer server, ProxyEndPoint endPoint, ProxyClient proxyClient, ConnectRequest? connectRequest, CancellationTokenSource cancellationTokenSource)
: base(server, endPoint, proxyClient, connectRequest, null, cancellationTokenSource)
: base(server, endPoint, proxyClient, connectRequest, new Request(), cancellationTokenSource)
{
}

Expand Down Expand Up @@ -304,7 +304,7 @@ private async Task copyBodyAsync(bool isRequest, bool useOriginalHeaderValues, H

if (transformation == TransformationMode.Uncompress && contentEncoding != null)
{
s = decompressStream = DecompressionFactory.Create(contentEncoding, s);
s = decompressStream = DecompressionFactory.Create(CompressionUtil.CompressionNameToEnum(contentEncoding), s);
}

try
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public abstract class SessionEventArgsBase : EventArgs, IDisposable
/// Initializes a new instance of the <see cref="SessionEventArgsBase" /> class.
/// </summary>
private protected SessionEventArgsBase(ProxyServer server, ProxyEndPoint endPoint,
ProxyClient proxyClient, ConnectRequest? connectRequest, Request? request, CancellationTokenSource cancellationTokenSource)
ProxyClient proxyClient, ConnectRequest? connectRequest, Request request, CancellationTokenSource cancellationTokenSource)
{
BufferPool = server.BufferPool;
ExceptionFunc = server.ExceptionFunc;
Expand Down
15 changes: 9 additions & 6 deletions src/Titanium.Web.Proxy/ExplicitClientHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,15 @@ private async Task handleClient(ExplicitProxyEndPoint endPoint, TcpClientConnect

Request.ParseRequestLine(httpCmd!, out string _, out string httpUrl, out var version);

var httpRemoteUri = new Uri("http://" + httpUrl);
connectHostname = httpRemoteUri.Host;
connectHostname = httpUrl;
int idx = connectHostname.IndexOf(":");
if (idx >= 0)
{
connectHostname = connectHostname.Substring(0, idx);
}

var connectRequest = new ConnectRequest
var connectRequest = new ConnectRequest(connectHostname)
{
RequestUri = httpRemoteUri,
OriginalUrlData = HttpHeader.Encoding.GetBytes(httpUrl),
HttpVersion = version
};
Expand Down Expand Up @@ -127,6 +130,7 @@ await clientStreamWriter.WriteResponseAsync(connectArgs.HttpClient.Response,
bool isClientHello = clientHelloInfo != null;
if (clientHelloInfo != null)
{
connectRequest.Scheme = ProxyServer.UriSchemeHttps;
connectRequest.TunnelType = TunnelType.Https;
connectRequest.ClientHelloInfo = clientHelloInfo;
}
Expand All @@ -136,7 +140,6 @@ await clientStreamWriter.WriteResponseAsync(connectArgs.HttpClient.Response,
if (decryptSsl && clientHelloInfo != null)
{
clientConnection.SslProtocol = clientHelloInfo.SslProtocol;
connectRequest.RequestUri = new Uri("https://" + httpUrl);

bool http2Supported = false;

Expand Down Expand Up @@ -355,7 +358,7 @@ await Http2Helper.SendHttp2(clientStream, connection.Stream,

// Now create the request
await handleHttpSessionRequest(endPoint, clientConnection, clientStream, clientStreamWriter,
cancellationTokenSource, connectHostname, connectArgs, prefetchConnectionTask);
cancellationTokenSource, connectArgs, prefetchConnectionTask);
}
catch (ProxyException e)
{
Expand Down
2 changes: 1 addition & 1 deletion src/Titanium.Web.Proxy/Extensions/StreamExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ internal static async Task CopyToAsync(this Stream input, Stream output, Action<
}
}

private static async Task<T> withCancellation<T>(this Task<T> task, CancellationToken cancellationToken)
private static async Task<T> withCancellation<T>(this Task<T> task, CancellationToken cancellationToken) where T : struct
{
var tcs = new TaskCompletionSource<bool>();
using (cancellationToken.Register(s => ((TaskCompletionSource<bool>)s).TrySetResult(true), tcs))
Expand Down
4 changes: 2 additions & 2 deletions src/Titanium.Web.Proxy/Helpers/HttpHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ internal static Encoding GetEncodingFromContentType(string? contentType)
{
var parameter = p.Span;
int equalsIndex = parameter.IndexOf('=');
if (equalsIndex != -1 && parameter.Slice(0, equalsIndex).TrimStart().EqualsIgnoreCase(KnownHeaders.ContentTypeCharset.AsSpan()))
if (equalsIndex != -1 && KnownHeaders.ContentTypeCharset.Equals(parameter.Slice(0, equalsIndex).TrimStart()))
{
var value = parameter.Slice(equalsIndex + 1);
if (value.EqualsIgnoreCase("x-user-defined".AsSpan()))
Expand Down Expand Up @@ -113,7 +113,7 @@ internal static ReadOnlyMemory<char> GetBoundaryFromContentType(string? contentT
foreach (var parameter in new SemicolonSplitEnumerator(contentType))
{
int equalsIndex = parameter.Span.IndexOf('=');
if (equalsIndex != -1 && parameter.Span.Slice(0, equalsIndex).TrimStart().EqualsIgnoreCase(KnownHeaders.ContentTypeBoundary.AsSpan()))
if (equalsIndex != -1 && KnownHeaders.ContentTypeBoundary.Equals(parameter.Span.Slice(0, equalsIndex).TrimStart()))
{
var value = parameter.Slice(equalsIndex + 1);
if (value.Length > 2 && value.Span[0] == '"' && value.Span[value.Length - 1] == '"')
Expand Down
2 changes: 1 addition & 1 deletion src/Titanium.Web.Proxy/Helpers/HttpWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ private async Task copyBodyChunkedAsync(CustomBufferedStream reader, Action<byte
{
while (true)
{
string? chunkHead = await reader.ReadLineAsync(cancellationToken);
string chunkHead = (await reader.ReadLineAsync(cancellationToken))!;
int idx = chunkHead.IndexOf(";");
if (idx >= 0)
{
Expand Down
14 changes: 11 additions & 3 deletions src/Titanium.Web.Proxy/Helpers/ProxyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ internal ProxyInfo(bool? autoDetect, string? autoConfigUrl, int? proxyEnable, st

internal bool BypassOnLocal { get; }

internal Dictionary<ProxyProtocolType, HttpSystemProxyValue> Proxies { get; }
internal Dictionary<ProxyProtocolType, HttpSystemProxyValue>? Proxies { get; }

internal string[] BypassList { get; }
internal string[]? BypassList { get; }

private static string bypassStringEscape(string rawString)
{
Expand Down Expand Up @@ -171,7 +171,15 @@ internal static List<HttpSystemProxyValue> GetSystemProxyValues(string? proxySer

if (proxyValues.Length > 0)
{
result.AddRange(proxyValues.Select(parseProxyValue).Where(parsedValue => parsedValue != null));
foreach (string str in proxyValues)
{
var proxyValue = parseProxyValue(str);
if (proxyValue != null)
{
result.Add(proxyValue);
}

}
}
else
{
Expand Down
9 changes: 6 additions & 3 deletions src/Titanium.Web.Proxy/Http/ConnectRequest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Titanium.Web.Proxy.StreamExtended;
using System;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.StreamExtended;

namespace Titanium.Web.Proxy.Http
{
Expand All @@ -7,13 +9,14 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
public class ConnectRequest : Request
{
public ConnectRequest()
public ConnectRequest(string hostname)
{
Method = "CONNECT";
Hostname = hostname;
}

public TunnelType TunnelType { get; internal set; }

public ClientHelloInfo ClientHelloInfo { get; set; }
public ClientHelloInfo? ClientHelloInfo { get; set; }
}
}
2 changes: 1 addition & 1 deletion src/Titanium.Web.Proxy/Http/HeaderBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public void Write(string str)
var encoding = HttpHeader.Encoding;

#if NETSTANDARD2_1
var buf = ArrayPool<byte>.Shared.Rent(str.Length * 4);
var buf = ArrayPool<byte>.Shared.Rent(encoding.GetMaxByteCount(str.Length));
var span = new Span<byte>(buf);

int bytes = encoding.GetBytes(str.AsSpan(), span);
Expand Down
70 changes: 64 additions & 6 deletions src/Titanium.Web.Proxy/Http/HeaderCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,21 @@ public bool HeaderExists(string name)
return null;
}

internal HttpHeader? GetFirstHeader(KnownHeader name)
{
if (headers.TryGetValue(name.String, out var header))
{
return header;
}

if (nonUniqueHeaders.TryGetValue(name.String, out var h))
{
return h.FirstOrDefault();
}

return null;
}

/// <summary>
/// Returns all headers
/// </summary>
Expand All @@ -129,6 +144,16 @@ public void AddHeader(string name, string value)
AddHeader(new HttpHeader(name, value));
}

internal void AddHeader(KnownHeader name, string value)
{
AddHeader(new HttpHeader(name, value));
}

internal void AddHeader(KnownHeader name, KnownHeader value)
{
AddHeader(new HttpHeader(name, value));
}

/// <summary>
/// Adds the given header object to Request
/// </summary>
Expand Down Expand Up @@ -239,6 +264,27 @@ public bool RemoveHeader(string headerName)
return result;
}

/// <summary>
/// removes all headers with given name
/// </summary>
/// <param name="headerName"></param>
/// <returns>
/// True if header was removed
/// False if no header exists with given name
/// </returns>
public bool RemoveHeader(KnownHeader headerName)
{
bool result = headers.Remove(headerName.String);

// do not convert to '||' expression to avoid lazy evaluation
if (nonUniqueHeaders.Remove(headerName.String))
{
result = true;
}

return result;
}

/// <summary>
/// Removes given header object if it exist
/// </summary>
Expand Down Expand Up @@ -273,31 +319,43 @@ public void Clear()
nonUniqueHeaders.Clear();
}

internal string? GetHeaderValueOrNull(string headerName)
internal string? GetHeaderValueOrNull(KnownHeader headerName)
{
if (headers.TryGetValue(headerName, out var header))
if (headers.TryGetValue(headerName.String, out var header))
{
return header.Value;
}

return null;
}

internal void SetOrAddHeaderValue(string headerName, string? value)
internal void SetOrAddHeaderValue(KnownHeader headerName, string? value)
{
if (value == null)
{
RemoveHeader(headerName);
return;
}

if (headers.TryGetValue(headerName, out var header))
if (headers.TryGetValue(headerName.String, out var header))
{
header.SetValue(value);
}
else
{
headers.Add(headerName.String, new HttpHeader(headerName, value));
}
}

internal void SetOrAddHeaderValue(KnownHeader headerName, KnownHeader value)
{
if (headers.TryGetValue(headerName.String, out var header))
{
header.ValueData = value.GetByteString();
header.SetValue(value);
}
else
{
headers.Add(headerName, new HttpHeader(headerName, value));
headers.Add(headerName.String, new HttpHeader(headerName, value));
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/Titanium.Web.Proxy/Http/HttpWebClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ public class HttpWebClient
{
private TcpServerConnection? connection;

internal HttpWebClient(ConnectRequest? connectRequest, Request? request, Lazy<int> processIdFunc)
internal HttpWebClient(ConnectRequest? connectRequest, Request request, Lazy<int> processIdFunc)
{
ConnectRequest = connectRequest;
Request = request ?? new Request();
Request = request;
Response = new Response();
ProcessId = processIdFunc;
}
Expand Down Expand Up @@ -141,7 +141,7 @@ internal async Task SendRequest(bool enable100ContinueBehaviour, bool isTranspar
// write request headers
foreach (var header in Request.Headers)
{
if (isTransparent || header.Name != KnownHeaders.ProxyAuthorization)
if (isTransparent || header.Name != KnownHeaders.ProxyAuthorization.String)
{
headerBuilder.WriteHeader(header);
}
Expand Down
Loading

0 comments on commit e24f3cc

Please sign in to comment.