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