Commit 6f77c51d authored by Stéphane Graziano's avatar Stéphane Graziano Committed by Jehonathan Thomas

Mixed implementation for startWith + PeekBytesAsync with the use of bufferpool...

Mixed implementation for startWith + PeekBytesAsync with the use of bufferpool (to get the best of the two worlds)
parent f213048a
......@@ -55,9 +55,9 @@ namespace StreamExtended.Network
return reader.PeekByteAsync(index, cancellationToken);
}
public Task<byte[]> PeekBytesAsync(int index, int size, CancellationToken cancellationToken = default(CancellationToken))
public Task<int> PeekBytesAsync(byte[] buffer, int offset, int index, int size, CancellationToken cancellationToken = default(CancellationToken))
{
return reader.PeekBytesAsync(index, size, cancellationToken);
return reader.PeekBytesAsync(buffer, offset, index, size, cancellationToken);
}
public void Flush()
......
......@@ -88,12 +88,14 @@ namespace StreamExtended.Network
/// <summary>
/// Peeks bytes asynchronous.
/// </summary>
/// <param name="buffer">The buffer to copy.</param>
/// <param name="offset">The offset where copying.</param>
/// <param name="index">The index.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns></returns>
Task<byte[]> ICustomStreamReader.PeekBytesAsync(int index, int size, CancellationToken cancellationToken)
Task<int> ICustomStreamReader.PeekBytesAsync(byte[] buffer, int offset, int index, int size, CancellationToken cancellationToken)
{
return baseStream.PeekBytesAsync(index, size, cancellationToken);
return baseStream.PeekBytesAsync(buffer, offset, index, size, cancellationToken);
}
/// <summary>
......
......@@ -252,10 +252,12 @@ namespace StreamExtended.Network
/// <summary>
/// Peeks bytes asynchronous.
/// </summary>
/// <param name="buffer">The buffer to copy.</param>
/// <param name="offset">The offset where copying.</param>
/// <param name="index">The index.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns></returns>
public async Task<byte[]> PeekBytesAsync(int index, int size, CancellationToken cancellationToken = default(CancellationToken))
public async Task<int> PeekBytesAsync(byte[] buffer, int offset, int index, int size, CancellationToken cancellationToken = default(CancellationToken))
{
if (Available <= index)
{
......@@ -270,12 +272,12 @@ namespace StreamExtended.Network
if (Available <= (index + size))
{
return null;
return -1;
}
var vRet = new byte[size];
Array.Copy(streamBuffer, index, vRet, 0, size);
return vRet;
Buffer.BlockCopy(streamBuffer, index, buffer, offset, size);
return size;
}
/// <summary>
......
......@@ -40,10 +40,12 @@ namespace StreamExtended.Network
/// <summary>
/// Peeks bytes asynchronous.
/// </summary>
/// <param name="buffer">The buffer to copy.</param>
/// <param name="offset">The offset where copying.</param>
/// <param name="index">The index.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns></returns>
Task<byte[]> PeekBytesAsync(int index, int size, CancellationToken cancellationToken = default(CancellationToken));
Task<int> PeekBytesAsync(byte[] buffer, int offset, int index, int size, CancellationToken cancellationToken = default(CancellationToken));
byte ReadByteFromBuffer();
......
......@@ -49,7 +49,7 @@ namespace Titanium.Web.Proxy
TunnelConnectSessionEventArgs connectArgs = null;
// Client wants to create a secure tcp tunnel (probably its a HTTPS or Websocket request)
if (await HttpHelper.IsConnectMethod(clientStream, cancellationToken) == 1)
if (await HttpHelper.IsConnectMethod(clientStream, BufferPool, BufferSize, cancellationToken) == 1)
{
// read the first line HTTP command
string httpCmd = await clientStream.ReadLineAsync(cancellationToken);
......@@ -220,7 +220,7 @@ namespace Titanium.Web.Proxy
$"Couldn't authenticate host '{connectHostname}' with certificate '{certName}'.", e, connectArgs);
}
if (await HttpHelper.IsConnectMethod(clientStream) == -1)
if (await HttpHelper.IsConnectMethod(clientStream, BufferPool, BufferSize, cancellationToken) == -1)
{
decryptSsl = false;
}
......@@ -292,7 +292,7 @@ namespace Titanium.Web.Proxy
}
}
if (connectArgs != null && await HttpHelper.IsPriMethod(clientStream) == 1)
if (connectArgs != null && await HttpHelper.IsPriMethod(clientStream, BufferPool, BufferSize, cancellationToken) == 1)
{
// todo
string httpCmd = await clientStream.ReadLineAsync(cancellationToken);
......
......@@ -3,6 +3,7 @@ using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using StreamExtended;
using StreamExtended.Network;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Http;
......@@ -122,9 +123,9 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary>
/// <param name="clientStreamReader">The client stream reader.</param>
/// <returns>1: when CONNECT, 0: when valid HTTP method, -1: otherwise</returns>
internal static Task<int> IsConnectMethod(ICustomStreamReader clientStreamReader, CancellationToken cancellationToken = default(CancellationToken))
internal static Task<int> IsConnectMethod(ICustomStreamReader clientStreamReader, IBufferPool bufferPool, int bufferSize, CancellationToken cancellationToken = default(CancellationToken))
{
return startsWith(clientStreamReader, "CONNECT", cancellationToken);
return startsWith(clientStreamReader, bufferPool, bufferSize, "CONNECT", cancellationToken);
}
/// <summary>
......@@ -132,9 +133,9 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary>
/// <param name="clientStreamReader">The client stream reader.</param>
/// <returns>1: when PRI, 0: when valid HTTP method, -1: otherwise</returns>
internal static Task<int> IsPriMethod(ICustomStreamReader clientStreamReader, CancellationToken cancellationToken = default(CancellationToken))
internal static Task<int> IsPriMethod(ICustomStreamReader clientStreamReader, IBufferPool bufferPool, int bufferSize, CancellationToken cancellationToken = default(CancellationToken))
{
return startsWith(clientStreamReader, "PRI", cancellationToken);
return startsWith(clientStreamReader, bufferPool, bufferSize, "PRI", cancellationToken);
}
/// <summary>
......@@ -145,22 +146,46 @@ namespace Titanium.Web.Proxy.Helpers
/// <returns>
/// 1: when starts with the given string, 0: when valid HTTP method, -1: otherwise
/// </returns>
private static async Task<int> startsWith(ICustomStreamReader clientStreamReader, string expectedStart, CancellationToken cancellationToken = default(CancellationToken))
private static async Task<int> startsWith(ICustomStreamReader clientStreamReader, IBufferPool bufferPool, int bufferSize, string expectedStart, CancellationToken cancellationToken = default(CancellationToken))
{
int iRet = -1;
int lengthToCheck = 10;
var vBuffer = await clientStreamReader.PeekBytesAsync(0, lengthToCheck, cancellationToken);
if (vBuffer != null)
const int lengthToCheck = 10;
byte[] buffer = null;
try
{
var httpMethod = defaultEncoding.GetString(vBuffer);
buffer = bufferPool.GetBuffer(Math.Max(bufferSize, lengthToCheck));
if (httpMethod.StartsWith(expectedStart))
iRet = 1;
else if (Regex.Match(httpMethod, @"^[a-z]{3,} ", RegexOptions.IgnoreCase).Success) //valid HTTP requests start by at least 3 letters + space
iRet = 0;
}
int peeked = await clientStreamReader.PeekBytesAsync(buffer, 0, 0, lengthToCheck, cancellationToken);
if (peeked > 0)
{
bool isExpected = true;
for (int i = 0; i < lengthToCheck; i++)
{
int b = buffer[i];
if (b == ' ' && i > 2)
return isExpected ? 1 : 0;
else
{
char ch = (char)b;
if (!char.IsLetter(ch))
return -1;
else if (i >= expectedStart.Length || ch != expectedStart[i])
isExpected = false;
}
}
// only letters
iRet = isExpected ? 1 : 0;
}
}
finally
{
bufferPool.ReturnBuffer(buffer);
buffer = null;
}
return iRet;
}
}
......
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