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

Commit e24f3cc

Browse files
authored
Merge pull request #656 from justcoding121/master
better uri handling
2 parents 183f960 + 1b0bfec commit e24f3cc

36 files changed

+415
-174
lines changed

src/Titanium.Web.Proxy/Compression/CompressionFactory.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ namespace Titanium.Web.Proxy.Compression
1010
/// </summary>
1111
internal static class CompressionFactory
1212
{
13-
internal static Stream Create(string type, Stream stream, bool leaveOpen = true)
13+
internal static Stream Create(HttpCompression type, Stream stream, bool leaveOpen = true)
1414
{
1515
switch (type)
1616
{
17-
case KnownHeaders.ContentEncodingGzip:
17+
case HttpCompression.Gzip:
1818
return new GZipStream(stream, CompressionMode.Compress, leaveOpen);
19-
case KnownHeaders.ContentEncodingDeflate:
19+
case HttpCompression.Deflate:
2020
return new DeflateStream(stream, CompressionMode.Compress, leaveOpen);
21-
case KnownHeaders.ContentEncodingBrotli:
21+
case HttpCompression.Brotli:
2222
return new BrotliSharpLib.BrotliStream(stream, CompressionMode.Compress, leaveOpen);
2323
default:
2424
throw new Exception($"Unsupported compression mode: {type}");
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System;
2+
using Titanium.Web.Proxy.Http;
3+
4+
namespace Titanium.Web.Proxy.Compression
5+
{
6+
internal static class CompressionUtil
7+
{
8+
public static HttpCompression CompressionNameToEnum(string name)
9+
{
10+
if (KnownHeaders.ContentEncodingGzip.Equals(name.AsSpan()))
11+
return HttpCompression.Gzip;
12+
13+
if (KnownHeaders.ContentEncodingDeflate.Equals(name.AsSpan()))
14+
return HttpCompression.Deflate;
15+
16+
if (KnownHeaders.ContentEncodingBrotli.Equals(name.AsSpan()))
17+
return HttpCompression.Brotli;
18+
19+
return HttpCompression.Unsupported;
20+
}
21+
}
22+
}

src/Titanium.Web.Proxy/Compression/DecompressionFactory.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ namespace Titanium.Web.Proxy.Compression
1010
/// </summary>
1111
internal class DecompressionFactory
1212
{
13-
internal static Stream Create(string type, Stream stream, bool leaveOpen = true)
13+
internal static Stream Create(HttpCompression type, Stream stream, bool leaveOpen = true)
1414
{
1515
switch (type)
1616
{
17-
case KnownHeaders.ContentEncodingGzip:
17+
case HttpCompression.Gzip:
1818
return new GZipStream(stream, CompressionMode.Decompress, leaveOpen);
19-
case KnownHeaders.ContentEncodingDeflate:
19+
case HttpCompression.Deflate:
2020
return new DeflateStream(stream, CompressionMode.Decompress, leaveOpen);
21-
case KnownHeaders.ContentEncodingBrotli:
21+
case HttpCompression.Brotli:
2222
return new BrotliSharpLib.BrotliStream(stream, CompressionMode.Decompress, leaveOpen);
2323
default:
2424
throw new Exception($"Unsupported decompression mode: {type}");
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using System.IO.Compression;
2+
3+
namespace Titanium.Web.Proxy.Compression
4+
{
5+
internal enum HttpCompression
6+
{
7+
Unsupported,
8+
Gzip,
9+
Deflate,
10+
Brotli,
11+
}
12+
}

src/Titanium.Web.Proxy/EventArguments/LimitedStream.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ private void getNextChunk()
5454

5555
readChunkTrail = true;
5656

57-
string? chunkHead = baseStream.ReadLineAsync().Result;
57+
string? chunkHead = baseStream.ReadLineAsync().Result!;
5858
int idx = chunkHead.IndexOf(";", StringComparison.Ordinal);
5959
if (idx >= 0)
6060
{

src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public class SessionEventArgs : SessionEventArgsBase
3838
/// Constructor to initialize the proxy
3939
/// </summary>
4040
internal SessionEventArgs(ProxyServer server, ProxyEndPoint endPoint, ProxyClient proxyClient, ConnectRequest? connectRequest, CancellationTokenSource cancellationTokenSource)
41-
: base(server, endPoint, proxyClient, connectRequest, null, cancellationTokenSource)
41+
: base(server, endPoint, proxyClient, connectRequest, new Request(), cancellationTokenSource)
4242
{
4343
}
4444

@@ -304,7 +304,7 @@ private async Task copyBodyAsync(bool isRequest, bool useOriginalHeaderValues, H
304304

305305
if (transformation == TransformationMode.Uncompress && contentEncoding != null)
306306
{
307-
s = decompressStream = DecompressionFactory.Create(contentEncoding, s);
307+
s = decompressStream = DecompressionFactory.Create(CompressionUtil.CompressionNameToEnum(contentEncoding), s);
308308
}
309309

310310
try

src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public abstract class SessionEventArgsBase : EventArgs, IDisposable
4141
/// Initializes a new instance of the <see cref="SessionEventArgsBase" /> class.
4242
/// </summary>
4343
private protected SessionEventArgsBase(ProxyServer server, ProxyEndPoint endPoint,
44-
ProxyClient proxyClient, ConnectRequest? connectRequest, Request? request, CancellationTokenSource cancellationTokenSource)
44+
ProxyClient proxyClient, ConnectRequest? connectRequest, Request request, CancellationTokenSource cancellationTokenSource)
4545
{
4646
BufferPool = server.BufferPool;
4747
ExceptionFunc = server.ExceptionFunc;

src/Titanium.Web.Proxy/ExplicitClientHandler.cs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,15 @@ private async Task handleClient(ExplicitProxyEndPoint endPoint, TcpClientConnect
6262

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

65-
var httpRemoteUri = new Uri("http://" + httpUrl);
66-
connectHostname = httpRemoteUri.Host;
65+
connectHostname = httpUrl;
66+
int idx = connectHostname.IndexOf(":");
67+
if (idx >= 0)
68+
{
69+
connectHostname = connectHostname.Substring(0, idx);
70+
}
6771

68-
var connectRequest = new ConnectRequest
72+
var connectRequest = new ConnectRequest(connectHostname)
6973
{
70-
RequestUri = httpRemoteUri,
7174
OriginalUrlData = HttpHeader.Encoding.GetBytes(httpUrl),
7275
HttpVersion = version
7376
};
@@ -127,6 +130,7 @@ await clientStreamWriter.WriteResponseAsync(connectArgs.HttpClient.Response,
127130
bool isClientHello = clientHelloInfo != null;
128131
if (clientHelloInfo != null)
129132
{
133+
connectRequest.Scheme = ProxyServer.UriSchemeHttps;
130134
connectRequest.TunnelType = TunnelType.Https;
131135
connectRequest.ClientHelloInfo = clientHelloInfo;
132136
}
@@ -136,7 +140,6 @@ await clientStreamWriter.WriteResponseAsync(connectArgs.HttpClient.Response,
136140
if (decryptSsl && clientHelloInfo != null)
137141
{
138142
clientConnection.SslProtocol = clientHelloInfo.SslProtocol;
139-
connectRequest.RequestUri = new Uri("https://" + httpUrl);
140143

141144
bool http2Supported = false;
142145

@@ -355,7 +358,7 @@ await Http2Helper.SendHttp2(clientStream, connection.Stream,
355358

356359
// Now create the request
357360
await handleHttpSessionRequest(endPoint, clientConnection, clientStream, clientStreamWriter,
358-
cancellationTokenSource, connectHostname, connectArgs, prefetchConnectionTask);
361+
cancellationTokenSource, connectArgs, prefetchConnectionTask);
359362
}
360363
catch (ProxyException e)
361364
{

src/Titanium.Web.Proxy/Extensions/StreamExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ internal static async Task CopyToAsync(this Stream input, Stream output, Action<
6262
}
6363
}
6464

65-
private static async Task<T> withCancellation<T>(this Task<T> task, CancellationToken cancellationToken)
65+
private static async Task<T> withCancellation<T>(this Task<T> task, CancellationToken cancellationToken) where T : struct
6666
{
6767
var tcs = new TaskCompletionSource<bool>();
6868
using (cancellationToken.Register(s => ((TaskCompletionSource<bool>)s).TrySetResult(true), tcs))

src/Titanium.Web.Proxy/Helpers/HttpHelper.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ internal static Encoding GetEncodingFromContentType(string? contentType)
7878
{
7979
var parameter = p.Span;
8080
int equalsIndex = parameter.IndexOf('=');
81-
if (equalsIndex != -1 && parameter.Slice(0, equalsIndex).TrimStart().EqualsIgnoreCase(KnownHeaders.ContentTypeCharset.AsSpan()))
81+
if (equalsIndex != -1 && KnownHeaders.ContentTypeCharset.Equals(parameter.Slice(0, equalsIndex).TrimStart()))
8282
{
8383
var value = parameter.Slice(equalsIndex + 1);
8484
if (value.EqualsIgnoreCase("x-user-defined".AsSpan()))
@@ -113,7 +113,7 @@ internal static ReadOnlyMemory<char> GetBoundaryFromContentType(string? contentT
113113
foreach (var parameter in new SemicolonSplitEnumerator(contentType))
114114
{
115115
int equalsIndex = parameter.Span.IndexOf('=');
116-
if (equalsIndex != -1 && parameter.Span.Slice(0, equalsIndex).TrimStart().EqualsIgnoreCase(KnownHeaders.ContentTypeBoundary.AsSpan()))
116+
if (equalsIndex != -1 && KnownHeaders.ContentTypeBoundary.Equals(parameter.Span.Slice(0, equalsIndex).TrimStart()))
117117
{
118118
var value = parameter.Slice(equalsIndex + 1);
119119
if (value.Length > 2 && value.Span[0] == '"' && value.Span[value.Length - 1] == '"')

src/Titanium.Web.Proxy/Helpers/HttpWriter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ private async Task copyBodyChunkedAsync(CustomBufferedStream reader, Action<byte
198198
{
199199
while (true)
200200
{
201-
string? chunkHead = await reader.ReadLineAsync(cancellationToken);
201+
string chunkHead = (await reader.ReadLineAsync(cancellationToken))!;
202202
int idx = chunkHead.IndexOf(";");
203203
if (idx >= 0)
204204
{

src/Titanium.Web.Proxy/Helpers/ProxyInfo.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,9 @@ internal ProxyInfo(bool? autoDetect, string? autoConfigUrl, int? proxyEnable, st
6666

6767
internal bool BypassOnLocal { get; }
6868

69-
internal Dictionary<ProxyProtocolType, HttpSystemProxyValue> Proxies { get; }
69+
internal Dictionary<ProxyProtocolType, HttpSystemProxyValue>? Proxies { get; }
7070

71-
internal string[] BypassList { get; }
71+
internal string[]? BypassList { get; }
7272

7373
private static string bypassStringEscape(string rawString)
7474
{
@@ -171,7 +171,15 @@ internal static List<HttpSystemProxyValue> GetSystemProxyValues(string? proxySer
171171

172172
if (proxyValues.Length > 0)
173173
{
174-
result.AddRange(proxyValues.Select(parseProxyValue).Where(parsedValue => parsedValue != null));
174+
foreach (string str in proxyValues)
175+
{
176+
var proxyValue = parseProxyValue(str);
177+
if (proxyValue != null)
178+
{
179+
result.Add(proxyValue);
180+
}
181+
182+
}
175183
}
176184
else
177185
{
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using Titanium.Web.Proxy.StreamExtended;
1+
using System;
2+
using Titanium.Web.Proxy.Extensions;
3+
using Titanium.Web.Proxy.StreamExtended;
24

35
namespace Titanium.Web.Proxy.Http
46
{
@@ -7,13 +9,14 @@ namespace Titanium.Web.Proxy.Http
79
/// </summary>
810
public class ConnectRequest : Request
911
{
10-
public ConnectRequest()
12+
public ConnectRequest(string hostname)
1113
{
1214
Method = "CONNECT";
15+
Hostname = hostname;
1316
}
1417

1518
public TunnelType TunnelType { get; internal set; }
1619

17-
public ClientHelloInfo ClientHelloInfo { get; set; }
20+
public ClientHelloInfo? ClientHelloInfo { get; set; }
1821
}
1922
}

src/Titanium.Web.Proxy/Http/HeaderBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public void Write(string str)
7070
var encoding = HttpHeader.Encoding;
7171

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

7676
int bytes = encoding.GetBytes(str.AsSpan(), span);

src/Titanium.Web.Proxy/Http/HeaderCollection.cs

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,21 @@ public bool HeaderExists(string name)
105105
return null;
106106
}
107107

108+
internal HttpHeader? GetFirstHeader(KnownHeader name)
109+
{
110+
if (headers.TryGetValue(name.String, out var header))
111+
{
112+
return header;
113+
}
114+
115+
if (nonUniqueHeaders.TryGetValue(name.String, out var h))
116+
{
117+
return h.FirstOrDefault();
118+
}
119+
120+
return null;
121+
}
122+
108123
/// <summary>
109124
/// Returns all headers
110125
/// </summary>
@@ -129,6 +144,16 @@ public void AddHeader(string name, string value)
129144
AddHeader(new HttpHeader(name, value));
130145
}
131146

147+
internal void AddHeader(KnownHeader name, string value)
148+
{
149+
AddHeader(new HttpHeader(name, value));
150+
}
151+
152+
internal void AddHeader(KnownHeader name, KnownHeader value)
153+
{
154+
AddHeader(new HttpHeader(name, value));
155+
}
156+
132157
/// <summary>
133158
/// Adds the given header object to Request
134159
/// </summary>
@@ -239,6 +264,27 @@ public bool RemoveHeader(string headerName)
239264
return result;
240265
}
241266

267+
/// <summary>
268+
/// removes all headers with given name
269+
/// </summary>
270+
/// <param name="headerName"></param>
271+
/// <returns>
272+
/// True if header was removed
273+
/// False if no header exists with given name
274+
/// </returns>
275+
public bool RemoveHeader(KnownHeader headerName)
276+
{
277+
bool result = headers.Remove(headerName.String);
278+
279+
// do not convert to '||' expression to avoid lazy evaluation
280+
if (nonUniqueHeaders.Remove(headerName.String))
281+
{
282+
result = true;
283+
}
284+
285+
return result;
286+
}
287+
242288
/// <summary>
243289
/// Removes given header object if it exist
244290
/// </summary>
@@ -273,31 +319,43 @@ public void Clear()
273319
nonUniqueHeaders.Clear();
274320
}
275321

276-
internal string? GetHeaderValueOrNull(string headerName)
322+
internal string? GetHeaderValueOrNull(KnownHeader headerName)
277323
{
278-
if (headers.TryGetValue(headerName, out var header))
324+
if (headers.TryGetValue(headerName.String, out var header))
279325
{
280326
return header.Value;
281327
}
282328

283329
return null;
284330
}
285331

286-
internal void SetOrAddHeaderValue(string headerName, string? value)
332+
internal void SetOrAddHeaderValue(KnownHeader headerName, string? value)
287333
{
288334
if (value == null)
289335
{
290336
RemoveHeader(headerName);
291337
return;
292338
}
293339

294-
if (headers.TryGetValue(headerName, out var header))
340+
if (headers.TryGetValue(headerName.String, out var header))
341+
{
342+
header.SetValue(value);
343+
}
344+
else
345+
{
346+
headers.Add(headerName.String, new HttpHeader(headerName, value));
347+
}
348+
}
349+
350+
internal void SetOrAddHeaderValue(KnownHeader headerName, KnownHeader value)
351+
{
352+
if (headers.TryGetValue(headerName.String, out var header))
295353
{
296-
header.ValueData = value.GetByteString();
354+
header.SetValue(value);
297355
}
298356
else
299357
{
300-
headers.Add(headerName, new HttpHeader(headerName, value));
358+
headers.Add(headerName.String, new HttpHeader(headerName, value));
301359
}
302360
}
303361

src/Titanium.Web.Proxy/Http/HttpWebClient.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ public class HttpWebClient
1818
{
1919
private TcpServerConnection? connection;
2020

21-
internal HttpWebClient(ConnectRequest? connectRequest, Request? request, Lazy<int> processIdFunc)
21+
internal HttpWebClient(ConnectRequest? connectRequest, Request request, Lazy<int> processIdFunc)
2222
{
2323
ConnectRequest = connectRequest;
24-
Request = request ?? new Request();
24+
Request = request;
2525
Response = new Response();
2626
ProcessId = processIdFunc;
2727
}
@@ -141,7 +141,7 @@ internal async Task SendRequest(bool enable100ContinueBehaviour, bool isTranspar
141141
// write request headers
142142
foreach (var header in Request.Headers)
143143
{
144-
if (isTransparent || header.Name != KnownHeaders.ProxyAuthorization)
144+
if (isTransparent || header.Name != KnownHeaders.ProxyAuthorization.String)
145145
{
146146
headerBuilder.WriteHeader(header);
147147
}

0 commit comments

Comments
 (0)