Skip to content

Commit 8b0068c

Browse files
gscatgscat
authored andcommitted
wip: cadente coverage 91/95 tests
1 parent 4bb8628 commit 8b0068c

File tree

18 files changed

+302
-196
lines changed

18 files changed

+302
-196
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<!-- supported frameworks -->
44
<PropertyGroup>
5-
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
5+
<TargetFrameworks>net9.0</TargetFrameworks>
66
<RootNamespace>Sisk.Cadente.CoreEngine</RootNamespace>
77
<Configurations>Debug;Release</Configurations>
88
</PropertyGroup>

cadente/Sisk.Cadente/HttpConnection.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,11 @@ public async Task<HttpConnectionState> HandleConnectionEvents () {
5656
managedSession.Response.Headers.Set ( new HttpHeader ( HttpHeaderName.Connection, "close" ) );
5757
}
5858

59-
if (managedSession.ResponseHeadersAlreadySent == false && !managedSession.WriteHttpResponseHeaders ()) {
60-
return HttpConnectionState.ResponseWriteException;
59+
if (managedSession.ResponseHeadersAlreadySent == false) {
60+
managedSession.Response.Headers.Set ( new HttpHeader ( HttpHeaderName.ContentLength, "0" ) );
61+
62+
if (!managedSession.WriteHttpResponseHeaders ())
63+
return HttpConnectionState.ResponseWriteException;
6164
}
6265

6366
await _connectionStream.FlushAsync ();

cadente/Sisk.Cadente/HttpEventStreamWriter.cs

Lines changed: 0 additions & 45 deletions
This file was deleted.

cadente/Sisk.Cadente/HttpHeaderExtensions.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,29 @@ public static string [] Get ( this HttpHeader [] headers, string? name ) {
7878
return results.ToArray ();
7979
}
8080

81+
/// <summary>
82+
/// Determines whether the specified list of <see cref="HttpHeader"/> contains a header with the given name.
83+
/// </summary>
84+
/// <param name="headers">The list of <see cref="HttpHeader"/> to search.</param>
85+
/// <param name="name">The name of the header to search for. May be <see langword="null"/>.</param>
86+
/// <returns>
87+
/// <see langword="true"/> if the list contains a header with the specified name; otherwise, <see langword="false"/>.
88+
/// </returns>
89+
public static bool Contains ( this List<HttpHeader> headers, string? name ) {
90+
91+
List<string> results = new ();
92+
lock (((ICollection) headers).SyncRoot) {
93+
var span = CollectionsMarshal.AsSpan ( headers );
94+
for (int i = span.Length - 1; i >= 0; i--) {
95+
if (Ascii.EqualsIgnoreCase ( span [ i ].NameBytes.Span, name )) {
96+
return true;
97+
}
98+
}
99+
}
100+
101+
return false;
102+
}
103+
81104
/// <summary>
82105
/// Removes all <see cref="HttpHeader"/> with the given name from the list. Thread-safe.
83106
/// </summary>

cadente/Sisk.Cadente/HttpHostContext.cs

Lines changed: 14 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -104,14 +104,21 @@ public sealed class HttpRequest {
104104
/// </summary>
105105
public Stream GetRequestStream () {
106106

107+
if (ContentLength == 0) {
108+
return Stream.Null;
109+
}
110+
107111
if (_baseRequest.IsExpecting100 && !wasExpectationSent) {
108112
wasExpectationSent = HttpResponseSerializer.WriteExpectationContinue ( _requestStream );
109113

110114
if (!wasExpectationSent)
111115
throw new InvalidOperationException ( "Unable to obtain the input stream for the request." );
112116
}
113117

114-
return _requestStream;
118+
return _baseRequest.IsChunked switch {
119+
true => new HttpChunkedReadStream2 ( _requestStream ),
120+
false => _requestStream
121+
};
115122
}
116123

117124
internal HttpRequest ( HttpRequestBase request, HttpRequestStream requestStream ) {
@@ -126,7 +133,7 @@ internal HttpRequest ( HttpRequestBase request, HttpRequestStream requestStream
126133
public sealed class HttpResponse {
127134
private Stream _baseOutputStream;
128135
private HttpHostContext _session;
129-
private bool headersSent = false;
136+
internal bool headersSent = false;
130137

131138
/// <summary>
132139
/// Gets or sets the HTTP status code of the response.
@@ -143,34 +150,6 @@ public sealed class HttpResponse {
143150
/// </summary>
144151
public List<HttpHeader> Headers { get; set; }
145152

146-
/// <summary>
147-
/// Asynchronously gets an event stream writer with UTF-8 encoding.
148-
/// </summary>
149-
/// <returns>A task that represents the asynchronous operation, with a <see cref="HttpEventStreamWriter"/> as the result.</returns>
150-
public HttpEventStreamWriter GetEventStream () => GetEventStream ( Encoding.UTF8 );
151-
152-
/// <summary>
153-
/// Asynchronously gets an event stream writer with the specified encoding.
154-
/// </summary>
155-
/// <param name="encoding">The encoding to use for the event stream.</param>
156-
/// <returns>A task that represents the asynchronous operation, with a <see cref="HttpEventStreamWriter"/> as the result.</returns>
157-
/// <exception cref="InvalidOperationException">Thrown when unable to obtain an output stream for the response.</exception>
158-
public HttpEventStreamWriter GetEventStream ( Encoding encoding ) {
159-
if (headersSent) {
160-
throw new InvalidOperationException ( "Headers already sent for this HTTP response." );
161-
}
162-
163-
Headers.Set ( new HttpHeader ( "Content-Type", "text/event-stream" ) );
164-
Headers.Set ( new HttpHeader ( "Cache-Control", "no-cache" ) );
165-
166-
if (!_session.WriteHttpResponseHeaders ()) {
167-
throw new InvalidOperationException ( "Unable to obtain the output stream for the response." );
168-
}
169-
170-
headersSent = true;
171-
return new HttpEventStreamWriter ( _baseOutputStream, encoding );
172-
}
173-
174153
/// <summary>
175154
/// Gets the content stream for the response.
176155
/// </summary>
@@ -185,6 +164,11 @@ public Stream GetResponseStream ( bool chunked = false ) {
185164
Headers.Set ( new HttpHeader ( HttpHeaderName.TransferEncoding, "chunked" ) );
186165
Headers.Remove ( HttpHeaderName.ContentLength );
187166
}
167+
else {
168+
if (!Headers.Contains ( HttpHeaderName.ContentLength )) {
169+
throw new InvalidOperationException ( "Content-Length header must be set for non-chunked responses." );
170+
}
171+
}
188172

189173
if (!_session.WriteHttpResponseHeaders ()) {
190174
throw new InvalidOperationException ( "Unable to obtain an output stream for the response." );

cadente/Sisk.Cadente/HttpSerializer/HttpRequestBase.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ sealed class HttpRequestBase {
1818
private HttpHeader []? _headers;
1919

2020
public bool IsExpecting100;
21+
public bool IsChunked;
2122

2223
public long ContentLength;
2324
public bool CanKeepAlive;

cadente/Sisk.Cadente/HttpSerializer/HttpRequestReader.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ public bool TryReadHttpRequest ( [NotNullWhen ( true )] out HttpRequestBase? req
6060
long contentLength = 0;
6161
bool keepAliveEnabled = true;
6262
bool expect100 = false;
63+
bool isChunked = false;
6364

6465
List<HttpHeader> headers = new List<HttpHeader> ( 32 );
6566
while (reader.TryReadToAny ( out ReadOnlySpan<byte> headerLine, RequestLineDelimiters, advancePastDelimiter: true )) {
@@ -84,6 +85,9 @@ public bool TryReadHttpRequest ( [NotNullWhen ( true )] out HttpRequestBase? req
8485
else if (Ascii.EqualsIgnoreCase ( headerLineName, "Expect"u8 )) {
8586
expect100 = Ascii.Equals ( headerLineValue, "100-continue"u8 );
8687
}
88+
else if (Ascii.EqualsIgnoreCase ( headerLineName, "Transfer-Encoding"u8 )) {
89+
isChunked = Ascii.Equals ( headerLineValue, "chunked"u8 );
90+
}
8791

8892
headers.Add ( new HttpHeader ( headerLineName.ToArray (), headerLineValue.ToArray () ) );
8993
}
@@ -95,10 +99,14 @@ public bool TryReadHttpRequest ( [NotNullWhen ( true )] out HttpRequestBase? req
9599
MethodRef = method.ToArray (),
96100
PathRef = path.ToArray (),
97101

98-
ContentLength = contentLength,
102+
ContentLength = isChunked switch {
103+
true => -1,
104+
false => contentLength
105+
},
99106
CanKeepAlive = keepAliveEnabled,
100107

101-
IsExpecting100 = expect100
108+
IsExpecting100 = expect100,
109+
IsChunked = isChunked
102110
};
103111
}
104112
}

cadente/Sisk.Cadente/Sisk.Cadente.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<!-- supported frameworks -->
44
<PropertyGroup>
5-
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
5+
<TargetFrameworks>net9.0</TargetFrameworks>
66
<RootNamespace>Sisk.Cadente</RootNamespace>
77
<Configurations>Debug;Release</Configurations>
88
</PropertyGroup>

cadente/Sisk.Cadente/Streams/HttpChunkedReadStream.cs

Lines changed: 0 additions & 100 deletions
This file was deleted.

0 commit comments

Comments
 (0)