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

better uri handling #656

Merged
merged 1 commit into from
Nov 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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