Skip to content

Commit 0165800

Browse files
authored
Fix HTTP request message being marked as completed too early (#63)
1 parent 41b2f46 commit 0165800

File tree

5 files changed

+63
-6
lines changed

5 files changed

+63
-6
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
example.db
2+
example.db-*

examples/Passwordless.AspNetIdentity.Example/appsettings.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
},
88
"AllowedHosts": "*",
99
"Passwordless": {
10-
"ApiKey": "YOUR_API_SECRET",
11-
"ApiSecret": "YOUR_API_KEY",
10+
"ApiKey": "YOUR_API_KEY",
11+
"ApiSecret": "YOUR_API_SECRET",
1212
"Register": {
1313
"Discoverable": true
1414
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
using System.Net;
2+
3+
namespace Passwordless.Helpers.Extensions;
4+
5+
internal static class HttpExtensions
6+
{
7+
private class NonDisposableHttpContent : HttpContent
8+
{
9+
private readonly HttpContent _content;
10+
11+
public NonDisposableHttpContent(HttpContent content) => _content = content;
12+
13+
protected override async Task SerializeToStreamAsync(
14+
Stream stream,
15+
TransportContext? context
16+
) => await _content.CopyToAsync(stream);
17+
18+
protected override bool TryComputeLength(out long length)
19+
{
20+
length = default;
21+
return false;
22+
}
23+
}
24+
25+
public static HttpRequestMessage Clone(this HttpRequestMessage request)
26+
{
27+
var clonedRequest = new HttpRequestMessage(request.Method, request.RequestUri)
28+
{
29+
Version = request.Version,
30+
// Don't dispose the original request's content
31+
Content = request.Content is not null
32+
? new NonDisposableHttpContent(request.Content)
33+
: null
34+
};
35+
36+
foreach (var header in request.Headers)
37+
clonedRequest.Headers.TryAddWithoutValidation(header.Key, header.Value);
38+
39+
if (request.Content is not null && clonedRequest.Content is not null)
40+
{
41+
foreach (var header in request.Content.Headers)
42+
clonedRequest.Content.Headers.TryAddWithoutValidation(header.Key, header.Value);
43+
}
44+
45+
return clonedRequest;
46+
}
47+
}

src/Passwordless/PasswordlessHttpHandler.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Net.Http.Json;
22
using Passwordless.Helpers;
3+
using Passwordless.Helpers.Extensions;
34

45
namespace Passwordless;
56

@@ -16,10 +17,18 @@ public PasswordlessHttpHandler(HttpClient http, bool disposeClient = false)
1617
}
1718

1819
protected override async Task<HttpResponseMessage> SendAsync(
19-
HttpRequestMessage request,
20+
HttpRequestMessage providedRequest,
2021
CancellationToken cancellationToken)
2122
{
22-
var response = await _http.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
23+
// Clone the request to reset its completion status, which is required
24+
// because we're crossing the boundary between two HTTP clients.
25+
using var request = providedRequest.Clone();
26+
27+
var response = await _http.SendAsync(
28+
request,
29+
HttpCompletionOption.ResponseHeadersRead,
30+
cancellationToken
31+
);
2332

2433
// On failed requests, check if responded with ProblemDetails and provide a nicer error if so
2534
if (!request.ShouldSkipErrorHandling() &&

src/Passwordless/PasswordlessHttpRequestExtensions.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ internal static bool ShouldSkipErrorHandling(this HttpRequestMessage request)
2424
return request.Options.TryGetValue(SkipErrorHandlingOption, out var doNotErrorHandle) && doNotErrorHandle;
2525
#elif NET462 || NETSTANDARD2_0
2626
return request.Properties.TryGetValue(SkipErrorHandlingOption, out var shouldSkipOptionObject)
27-
&& shouldSkipOptionObject is bool shouldSkipOption
28-
&& shouldSkipOption;
27+
&& shouldSkipOptionObject is true;
2928
#endif
3029
}
3130
}

0 commit comments

Comments
 (0)