Skip to content

Commit 5ffe9b3

Browse files
committed
wip: add slow connection tests; fix req chunked issues
1 parent 98ca0ac commit 5ffe9b3

File tree

9 files changed

+330
-43
lines changed

9 files changed

+330
-43
lines changed

cadente/Sisk.Cadente.CoreEngine/Sisk.Cadente.CoreEngine.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
<PropertyGroup>
4848
<AssemblyVersion>1.6.0</AssemblyVersion>
4949
<FileVersion>1.6.0</FileVersion>
50-
<Version>1.6.0-beta7</Version>
50+
<Version>1.6.0-beta8</Version>
5151
</PropertyGroup>
5252

5353
<!-- licensing, readme, signing -->

cadente/Sisk.Cadente/Sisk.Cadente.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
<PropertyGroup>
4848
<AssemblyVersion>1.0</AssemblyVersion>
4949
<FileVersion>1.0</FileVersion>
50-
<Version>1.0-beta7</Version>
50+
<Version>1.0-beta8</Version>
5151
</PropertyGroup>
5252

5353
<!-- licensing, readme, signing -->

cadente/Sisk.Cadente/Streams/HttpChunkedReadStream2.cs

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -47,46 +47,54 @@ public override int Read ( byte [] buffer, int offset, int count ) {
4747
if (currentBlockSize == 0) {
4848
return 0;
4949
}
50-
else if (currentBlockSize > 0) {
51-
var expected = Math.Min ( count, currentBlockSize - currentBlockRead );
52-
var read = _s.Read ( buffer, offset, expected );
5350

54-
currentBlockRead += read;
55-
56-
if (currentBlockRead == currentBlockSize) {
57-
// read trailing \r\n
58-
_ = _s.Read ( _buffer, 0, 2 );
59-
currentBlockSize = -1;
60-
currentBlockRead = 0;
51+
if (currentBlockSize == -1) {
52+
// read next chunked header
53+
int ptr = 0;
54+
while (true) {
55+
int b = _s.ReadByte ();
56+
if (b == -1) break;
57+
_buffer [ ptr++ ] = (byte) b;
58+
59+
if (ptr >= 2 && _buffer [ ptr - 1 ] == '\n' && _buffer [ ptr - 2 ] == '\r') {
60+
break;
61+
}
62+
if (ptr >= _buffer.Length) throw new InvalidOperationException ( "Chunk header too long" );
6163
}
6264

63-
return read;
64-
}
65-
else if (currentBlockSize == -1) {
66-
// read next chunked header
67-
int read = _s.Read ( _buffer, 0, 16 );
68-
var headerLine = Encoding.ASCII.GetString ( _buffer, 0, read );
65+
if (ptr == 0) return 0;
6966

70-
var numEnd = headerLine.IndexOf ( '\r' );
71-
var numberString = headerLine.Substring ( 0, numEnd );
67+
var headerLine = Encoding.ASCII.GetString ( _buffer, 0, ptr - 2 );
68+
var extIndex = headerLine.IndexOf ( ';' );
69+
var numberString = extIndex > -1 ? headerLine.Substring ( 0, extIndex ) : headerLine;
7270

7371
if (numberString == "0") {
7472
currentBlockSize = 0;
7573
return 0;
7674
}
7775

78-
var number = Convert.ToInt32 ( numberString, 16 );
76+
currentBlockSize = Convert.ToInt32 ( numberString, 16 );
77+
currentBlockRead = 0;
78+
}
7979

80-
var current = _buffer [ 0..read ].AsSpan () [ (numEnd + 2).. ];
81-
current.CopyTo ( buffer.AsSpan () [ offset.. ] );
80+
var expected = Math.Min ( count, currentBlockSize - currentBlockRead );
81+
var read = _s.Read ( buffer, offset, expected );
8282

83-
currentBlockSize = number;
84-
currentBlockRead = current.Length;
83+
currentBlockRead += read;
8584

86-
return current.Length;
85+
if (currentBlockRead == currentBlockSize) {
86+
// read trailing \r\n
87+
int r = 0;
88+
while (r < 2) {
89+
int x = _s.Read ( _buffer, 0, 2 - r );
90+
if (x == 0) break;
91+
r += x;
92+
}
93+
currentBlockSize = -1;
94+
currentBlockRead = 0;
8795
}
8896

89-
return 1;
97+
return read;
9098
}
9199

92100
public override long Seek ( long offset, SeekOrigin origin ) {

src/Http/HttpRequest.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
using System.Globalization;
1313
using System.Net;
1414
using System.Net.Http.Headers;
15-
using System.Net.WebSockets;
1615
using System.Reflection;
1716
using System.Runtime.CompilerServices;
1817
using System.Text;

src/Http/HttpServerExecutionResult.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ namespace Sisk.Core.Http {
1212
/// Represents the results of an request execution on the HTTP server.
1313
/// </summary>
1414
public sealed class HttpServerExecutionResult {
15+
1516
/// <summary>
1617
/// Gets the <see cref="HttpRequest"/> received in this diagnosis.
1718
/// </summary>

src/Internal/LogFormatter.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
namespace Sisk.Core.Internal;
1717

1818
static class LogFormatter {
19+
1920
public static string FormatExceptionEntr ( HttpServerExecutionResult executionResult ) {
2021
StringBuilder errLineBuilder = new StringBuilder ( 128 );
2122
errLineBuilder.Append ( '[' );

tests/Sisk.Core/Server.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,13 @@ public static void AssemblyInit ( TestContext testContext ) {
299299
router.SetRoute ( RouteMethod.Get, "/tests/sse/cors", ( req ) => { var es = req.GetEventSource (); es.AppendHeader ( "X-Test-SSE", "cors" ); es.Send ( "cors message 1" ); return es.Close (); } );
300300
router.SetRoute ( RouteMethod.Get, "/tests/sse/empty", ( req ) => { var es = req.GetEventSource (); es.Send ( "" ); es.Send ( null ); es.Send ( "", fieldName: "customEmpty" ); es.Send ( null, fieldName: "customNull" ); return es.Close (); } );
301301

302+
router.SetRoute ( RouteMethod.Get, "/tests/headers/repeated", ( req ) => {
303+
var resp = new HttpResponse ( "ok" );
304+
resp.Headers.Add ( "X-Custom-Header", "value1" );
305+
resp.Headers.Add ( "X-Custom-Header", "value2" );
306+
return resp;
307+
} );
308+
302309
// WebSocket routes
303310
router.SetRoute ( RouteMethod.Get, "/tests/ws/echo", async ( HttpRequest request ) => {
304311
HttpWebSocket client = await request.GetWebSocketAsync ();

tests/Sisk.Core/Tests/CadenteEngineRareTests.cs renamed to tests/Sisk.Core/Tests/EngineRareTests.cs

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,19 @@
44
// The code below is licensed under the MIT license as
55
// of the date of its publication, available at
66
//
7-
// File name: CadenteEngineRareTests.cs
7+
// File name: EngineRareTests.cs
88
// Repository: https://github.com/sisk-http/core
99

1010
using System.Net.Http.Json;
1111
using System.Text;
12-
using Sisk.Cadente.CoreEngine;
1312

1413
namespace tests.Tests;
1514

1615
[TestClass]
17-
public sealed class CadenteEngineRareTests {
18-
private static void AssumeCadenteEngine () {
19-
if (Server.Instance.HttpServer.ServerConfiguration.Engine is not CadenteHttpServerEngine) {
20-
Assert.Inconclusive ( "Cadente HTTP engine is not active for this test run." );
21-
}
22-
}
16+
public sealed class EngineRareTests {
2317

2418
[TestMethod]
2519
public async Task ExpectContinue_LargePayload_Succeeds () {
26-
AssumeCadenteEngine ();
2720
using var client = Server.GetHttpClient ();
2821
client.DefaultRequestHeaders.ExpectContinue = true;
2922

@@ -44,7 +37,6 @@ public async Task ExpectContinue_LargePayload_Succeeds () {
4437

4538
[TestMethod]
4639
public async Task FormContent_ThousandFields_RoundTrips () {
47-
AssumeCadenteEngine ();
4840
using var client = Server.GetHttpClient ();
4941
var formData = Enumerable.Range ( 0, 1000 ).ToDictionary ( i => $"field{i:0000}", i => $"value-{i}" );
5042
using var content = new FormUrlEncodedContent ( formData );
@@ -62,7 +54,6 @@ public async Task FormContent_ThousandFields_RoundTrips () {
6254

6355
[TestMethod]
6456
public async Task JsonContent_LargeStringPayload_RoundTrips () {
65-
AssumeCadenteEngine ();
6657
using var client = Server.GetHttpClient ();
6758
var nameBuilder = new StringBuilder ( 128 * 1024 );
6859
for (int i = 0; i < 2048; i++) {
@@ -81,7 +72,6 @@ public async Task JsonContent_LargeStringPayload_RoundTrips () {
8172

8273
[TestMethod]
8374
public async Task ResponseStreamChunked_ReadIncrementally () {
84-
AssumeCadenteEngine ();
8575
using var client = Server.GetHttpClient ();
8676

8777
using var response = await client.GetAsync ( "tests/responsestream/chunked", HttpCompletionOption.ResponseHeadersRead );
@@ -106,7 +96,6 @@ public async Task ResponseStreamChunked_ReadIncrementally () {
10696

10797
[TestMethod]
10898
public async Task ServerSentEvents_CancelAfterFirstEvent () {
109-
AssumeCadenteEngine ();
11099
using var client = Server.GetHttpClient ();
111100
using var cts = new CancellationTokenSource ( TimeSpan.FromSeconds ( 5 ) );
112101

@@ -141,7 +130,6 @@ public async Task ServerSentEvents_CancelAfterFirstEvent () {
141130

142131
[TestMethod]
143132
public async Task Plaintext_ManyConcurrentRequests_Succeed () {
144-
AssumeCadenteEngine ();
145133
using var client = Server.GetHttpClient ();
146134

147135
var tasks = Enumerable.Range ( 0, 12 ).Select ( async _ => {
@@ -156,7 +144,6 @@ public async Task Plaintext_ManyConcurrentRequests_Succeed () {
156144

157145
[TestMethod]
158146
public async Task Plaintext_LongQueryString_Succeeds () {
159-
AssumeCadenteEngine ();
160147
using var client = Server.GetHttpClient ();
161148
var uriBuilder = new StringBuilder ( "tests/plaintext?" );
162149
for (int i = 0; i < 200; i++) {

0 commit comments

Comments
 (0)