diff --git a/src/Flurl.Http/Flurl.Http.csproj b/src/Flurl.Http/Flurl.Http.csproj
index d130829f..38ab7bc4 100644
--- a/src/Flurl.Http/Flurl.Http.csproj
+++ b/src/Flurl.Http/Flurl.Http.csproj
@@ -3,7 +3,7 @@
netstandard2.0;net461;net472
True
Flurl.Http
- 3.2.4
+ 3.2.5
Todd Menier
A fluent, portable, testable HTTP client library.
https://flurl.dev
diff --git a/src/Flurl.Http/FlurlRequest.cs b/src/Flurl.Http/FlurlRequest.cs
index a340114c..e54e67d2 100644
--- a/src/Flurl.Http/FlurlRequest.cs
+++ b/src/Flurl.Http/FlurlRequest.cs
@@ -180,13 +180,14 @@ public async Task SendAsync(HttpMethod verb, HttpContent content
var ct = GetCancellationTokenWithTimeout(cancellationToken, out var cts);
try {
+ var cloneContent = await content.CloneAsync().ConfigureAwait(false);
var response = await Client.HttpClient.SendAsync(request, completionOption, ct).ConfigureAwait(false);
call.HttpResponseMessage = response;
call.HttpResponseMessage.RequestMessage = request;
call.Response = new FlurlResponse(call.HttpResponseMessage, CookieJar);
if (call.Succeeded) {
- var redirResponse = await ProcessRedirectAsync(call, cancellationToken, completionOption).ConfigureAwait(false);
+ var redirResponse = await ProcessRedirectAsync(call, cloneContent, cancellationToken, completionOption).ConfigureAwait(false);
return redirResponse ?? call.Response;
}
else
@@ -231,7 +232,7 @@ private CancellationToken GetCancellationTokenWithTimeout(CancellationToken orig
}
}
- private async Task ProcessRedirectAsync(FlurlCall call, CancellationToken cancellationToken, HttpCompletionOption completionOption) {
+ private async Task ProcessRedirectAsync(FlurlCall call, HttpContent content, CancellationToken cancellationToken, HttpCompletionOption completionOption) {
if (Settings.Redirects.Enabled)
call.Redirect = GetRedirect(call);
@@ -266,7 +267,7 @@ private async Task ProcessRedirectAsync(FlurlCall call, Cancella
try {
return await redir.SendAsync(
changeToGet ? HttpMethod.Get : call.HttpRequestMessage.Method,
- changeToGet ? null : call.HttpRequestMessage.Content,
+ changeToGet ? null : content,
ct,
completionOption).ConfigureAwait(false);
}
diff --git a/src/Flurl.Http/HttpContentExtensions.cs b/src/Flurl.Http/HttpContentExtensions.cs
new file mode 100644
index 00000000..7a530f9a
--- /dev/null
+++ b/src/Flurl.Http/HttpContentExtensions.cs
@@ -0,0 +1,38 @@
+using System.IO;
+using System.Net.Http;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Flurl.Http
+{
+ ///
+ /// Extension methods of HttpContent
+ ///
+ public static class HttpContentExtensions
+ {
+ /// Get a copy of the request content.
+ /// The content to copy.
+ /// The cancellation token.
+ /// Note that cloning content isn't possible after it's dispatched, because the stream is automatically disposed after the request.
+ internal static async Task CloneAsync(this HttpContent content, CancellationToken cancellationToken = default) {
+ if (content == null)
+ return null;
+
+ Stream stream = new MemoryStream();
+ await content
+ .CopyToAsync(stream
+#if NET5_0_OR_GREATER
+ , cancellationToken
+#endif
+ )
+ .ConfigureAwait(false);
+ stream.Position = 0;
+
+ StreamContent clone = new StreamContent(stream);
+ foreach (var header in content.Headers)
+ clone.Headers.Add(header.Key, header.Value);
+
+ return clone;
+ }
+ }
+}