From 5a4c238c3f9b8fac1e833fd314e02acf0dba1755 Mon Sep 17 00:00:00 2001 From: Benziza Date: Sun, 27 Sep 2026 20:35:03 +0200 Subject: [PATCH 1/2] Expose HTTP response trailing headers --- src/RestSharp/Response/RestResponse.cs | 5 ++- src/RestSharp/Response/RestResponseBase.cs | 5 +++ test/RestSharp.Tests/ResponseTrailerTests.cs | 36 ++++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 test/RestSharp.Tests/ResponseTrailerTests.cs diff --git a/src/RestSharp/Response/RestResponse.cs b/src/RestSharp/Response/RestResponse.cs index d092271e6..a567f52fb 100644 --- a/src/RestSharp/Response/RestResponse.cs +++ b/src/RestSharp/Response/RestResponse.cs @@ -73,6 +73,9 @@ async Task GetDefaultResponse() { Server = httpResponse.Headers.Server.ToString(), StatusCode = httpResponse.StatusCode, StatusDescription = httpResponse.ReasonPhrase, +#if NET + TrailingHeaders = httpResponse.TrailingHeaders.GetHeaderParameters(), +#endif Version = httpResponse.RequestMessage?.Version }; } @@ -94,4 +97,4 @@ public RestResponse() : this(new()) { } } } -public delegate ResponseStatus CalculateResponseStatus(HttpResponseMessage httpResponse); \ No newline at end of file +public delegate ResponseStatus CalculateResponseStatus(HttpResponseMessage httpResponse); diff --git a/src/RestSharp/Response/RestResponseBase.cs b/src/RestSharp/Response/RestResponseBase.cs index 57b1f5c4a..8236c9163 100644 --- a/src/RestSharp/Response/RestResponseBase.cs +++ b/src/RestSharp/Response/RestResponseBase.cs @@ -111,6 +111,11 @@ protected RestResponseBase(RestRequest request) { /// public IReadOnlyCollection? ContentHeaders { get; set; } + /// + /// Trailer headers returned by server after the response content + /// + public IReadOnlyCollection TrailingHeaders { get; set; } = Array.Empty(); + /// /// Status of the request. Will return Error for transport errors. /// HTTP errors will still return ResponseStatus.Completed, check StatusCode instead diff --git a/test/RestSharp.Tests/ResponseTrailerTests.cs b/test/RestSharp.Tests/ResponseTrailerTests.cs new file mode 100644 index 000000000..5b3944001 --- /dev/null +++ b/test/RestSharp.Tests/ResponseTrailerTests.cs @@ -0,0 +1,36 @@ +using System.Net; + +namespace RestSharp.Tests; + +public class ResponseTrailerTests { +#if NET + [Fact] + public async Task Should_map_trailing_headers_separately_from_regular_headers() { + using var client = new RestClient( + new RestClientOptions("https://dummy.org") { ConfigureMessageHandler = _ => new TrailerResponseHandler() } + ); + + var response = await client.ExecuteAsync(new RestRequest()); + + response.TrailingHeaders.Should().BeEquivalentTo( + new[] { + new HeaderParameter("Digest", "sha-256=abc"), + new HeaderParameter("Digest", "sha-256=def"), + new HeaderParameter("X-Processing-Status", "complete") + } + ); + response.Headers.Should().ContainSingle(x => x.Name == "X-Regular-Header" && x.Value == "regular"); + response.Headers.Should().NotContain(x => x.Name == "Digest" || x.Name == "X-Processing-Status"); + } + + class TrailerResponseHandler : HttpMessageHandler { + protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { + var response = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent("{}") }; + response.Headers.TryAddWithoutValidation("X-Regular-Header", "regular"); + response.TrailingHeaders.TryAddWithoutValidation("Digest", ["sha-256=abc", "sha-256=def"]); + response.TrailingHeaders.TryAddWithoutValidation("X-Processing-Status", "complete"); + return Task.FromResult(response); + } + } +#endif +} From 07a52edf8e3b290a0c6b769ed82e091f3e0a9cb2 Mon Sep 17 00:00:00 2001 From: Benziza Date: Sun, 27 Sep 2026 20:43:44 +0200 Subject: [PATCH 2/2] Test trailer separation from content headers --- test/RestSharp.Tests/ResponseTrailerTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/test/RestSharp.Tests/ResponseTrailerTests.cs b/test/RestSharp.Tests/ResponseTrailerTests.cs index 5b3944001..457e65fb7 100644 --- a/test/RestSharp.Tests/ResponseTrailerTests.cs +++ b/test/RestSharp.Tests/ResponseTrailerTests.cs @@ -21,6 +21,7 @@ public async Task Should_map_trailing_headers_separately_from_regular_headers() ); response.Headers.Should().ContainSingle(x => x.Name == "X-Regular-Header" && x.Value == "regular"); response.Headers.Should().NotContain(x => x.Name == "Digest" || x.Name == "X-Processing-Status"); + response.ContentHeaders.Should().NotContain(x => x.Name == "Digest" || x.Name == "X-Processing-Status"); } class TrailerResponseHandler : HttpMessageHandler {