Skip to content

Commit

Permalink
fix httpreader to correctly realloc input buffers
Browse files Browse the repository at this point in the history
  • Loading branch information
CypherPotato committed Dec 21, 2024
1 parent fc29f26 commit 002f2b8
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 41 deletions.
6 changes: 3 additions & 3 deletions tcp/Sisk.ManagedHttpListener/HttpConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
// File name: HttpConnection.cs
// Repository: https://github.com/sisk-http/core

using System.Buffers;
using Sisk.ManagedHttpListener.HttpSerializer;

namespace Sisk.ManagedHttpListener;
Expand Down Expand Up @@ -76,11 +77,10 @@ public int HandleConnectionEvents () {
break;
}
}
catch (Exception) {
;
}
finally {
responseStream?.Dispose ();
if (nextRequest is not null)
ArrayPool<byte>.Shared.Return ( nextRequest.BufferedContent );
}
}

Expand Down
14 changes: 9 additions & 5 deletions tcp/Sisk.ManagedHttpListener/HttpHeaderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,20 @@
// File name: HttpHeaderExtensions.cs
// Repository: https://github.com/sisk-http/core

using System.Collections;

namespace Sisk.ManagedHttpListener;

internal static class HttpHeaderExtensions {
public static void Set ( this List<(string, string)> headers, (string, string) header ) {
for (int i = headers.Count - 1; i >= 0; i--) {
if (StringComparer.OrdinalIgnoreCase.Compare ( headers [ i ].Item1, header.Item1 ) == 0) {
headers.RemoveAt ( i );
lock (((ICollection) headers).SyncRoot) {
for (int i = headers.Count - 1; i >= 0; i--) {
if (StringComparer.OrdinalIgnoreCase.Compare ( headers [ i ].Item1, header.Item1 ) == 0) {
headers.RemoveAt ( i );
}
}
}

headers.Add ( header );
headers.Add ( header );
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class HttpRequestBase {

public byte [] BufferedContent;

public HttpRequestBase ( string method, string path, string version, List<(string, string)> headers, int headerEnd, long contentLength, byte [] bufferedContent ) {
public HttpRequestBase ( string method, string path, string version, List<(string, string)> headers, int headerEnd, long contentLength, ref byte [] bufferedContent ) {
this.Method = method ?? throw new ArgumentNullException ( nameof ( method ) );
this.Path = path ?? throw new ArgumentNullException ( nameof ( path ) );
this.Version = version ?? throw new ArgumentNullException ( nameof ( version ) );
Expand Down
60 changes: 28 additions & 32 deletions tcp/Sisk.ManagedHttpListener/HttpSerializer/HttpRequestReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,43 +15,38 @@

namespace Sisk.ManagedHttpListener.HttpSerializer;

public sealed class HttpRequestReader {
public sealed class HttpRequestReader ( Stream _stream ) {

const int BUFFER_SIZE = 512;
const int BUFFER_LOOKAHEAD_OFFSET = 64;

const byte SPACE = 0x20;
const byte CARRIAGE_RETURN = 0x0D; //\r
const byte DOUBLE_DOTS = 0x3A; // :

const int BUFFER_LOOKAHEAD_OFFSET = 64;

// do not dispose
private readonly Stream _stream;

static Encoding HeaderEncoding = Encoding.UTF8;

public HttpRequestReader ( Stream stream ) {
this._stream = stream;
}

public HttpRequestBase? ReadHttpRequest () {
byte [] buffer = ArrayPool<byte>.Shared.Rent ( BUFFER_SIZE );
try {
int read = this._stream.Read ( buffer );
int read = _stream.Read ( buffer );
if (read == 0)
return null;

return ParseHttpRequest ( ref buffer, read, this._stream );
return this.ParseHttpRequest ( ref buffer, read );
}
catch {
return null;
}
finally {
ArrayPool<byte>.Shared.Return ( buffer );
// return the rented buffer on HttpConnection connection close
}
}

[MethodImpl ( MethodImplOptions.AggressiveOptimization )]
public static unsafe HttpRequestBase? ParseHttpRequest ( ref byte [] inputBuffer, int length, Stream requestStream ) {
//
bool requestStreamReturnedZero = false;
public HttpRequestBase? ParseHttpRequest ( ref byte [] inputBuffer, int length ) {
;
bool requestStreamFinished = false;

ReadOnlySpan<byte> buffer = inputBuffer;

Expand Down Expand Up @@ -110,6 +105,22 @@ public HttpRequestReader ( Stream stream ) {
break;

case 3:
// checks whether the current buffer has all the request headers. if not, read more data from the buffer
int bufferLength = buffer.Length;
if (i + BUFFER_LOOKAHEAD_OFFSET > bufferLength && !requestStreamFinished) {
ArrayPoolExtensions.Resize ( ArrayPool<byte>.Shared, ref inputBuffer, bufferLength * 2, clearArray: false );
int count = inputBuffer.Length - bufferLength;
int read = _stream.Read ( inputBuffer, bufferLength - 1, count );
if (read > 0) {
buffer = inputBuffer; // recreate the span over the input buffer
firstByte = ref MemoryMarshal.GetReference ( buffer );
length += read;
}
if (read < count) {
requestStreamFinished = true;
}
}

if (b == CARRIAGE_RETURN) {
headerLine = buffer [ (headerLineIndex + 1)..i ];
headerLineIndex = i + 1; //+1 includes \LF
Expand All @@ -134,21 +145,6 @@ public HttpRequestReader ( Stream stream ) {
headers.Add ( (headerName, headerValue) );
}

// checks whether the current buffer has all the request headers. if not, read more data from the buffer
int bufferLength = buffer.Length;
if (i + BUFFER_LOOKAHEAD_OFFSET > bufferLength && !requestStreamReturnedZero) {
ArrayPoolExtensions.Resize ( ArrayPool<byte>.Shared, ref inputBuffer, bufferLength * 2, clearArray: false );
int nextRead = requestStream.Read ( inputBuffer, bufferLength - 1, inputBuffer.Length - bufferLength );
if (nextRead > 0) {
buffer = inputBuffer; // recreate the span over the input buffer
firstByte = ref MemoryMarshal.GetReference ( buffer );
length += nextRead;
}
else {
requestStreamReturnedZero = true;
}
}

break;
}

Expand All @@ -162,7 +158,7 @@ public HttpRequestReader ( Stream stream ) {
version: HeaderEncoding.GetString ( version ),
headerEnd: headerSize,
headers: headers,
bufferedContent: inputBuffer,
bufferedContent: ref inputBuffer,
contentLength: contentLength
);
}
Expand Down

0 comments on commit 002f2b8

Please sign in to comment.