Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/RestSharp/Response/RestResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ async Task<RestResponse> GetDefaultResponse() {
Server = httpResponse.Headers.Server.ToString(),
StatusCode = httpResponse.StatusCode,
StatusDescription = httpResponse.ReasonPhrase,
#if NET
TrailingHeaders = httpResponse.TrailingHeaders.GetHeaderParameters(),
#endif
Version = httpResponse.RequestMessage?.Version
};
}
Expand Down
5 changes: 5 additions & 0 deletions src/RestSharp/Response/RestResponseBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ protected RestResponseBase(RestRequest request) {
/// </summary>
public IReadOnlyCollection<HeaderParameter>? ContentHeaders { get; set; }

/// <summary>
/// Trailer headers returned by server with the response
/// </summary>
public IReadOnlyCollection<HeaderParameter>? TrailingHeaders { get; set; }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

1. Older targets return null for trailers 🐞 Bug ≡ Correctness

TrailingHeaders has no empty default, and its only assignment in GetDefaultResponse is excluded
from non-NET builds. Successful responses on .NET Framework and .NET Standard therefore leave the
property null, unlike modern targets, where responses without trailers expose an empty collection.
Agent Prompt
## Issue description
Successful responses on older targets leave `TrailingHeaders` null because their builds exclude its only assignment.
## Fix Focus Areas
- src/RestSharp/Response/RestResponseBase.cs[114-117]
- src/RestSharp/Response/RestResponse.cs[76-78]
## Recommended Fix
Initialize `TrailingHeaders` to an empty collection for targets without trailer support, while preserving the populated collection on supported targets.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


/// <summary>
/// Status of the request. Will return Error for transport errors.
/// HTTP errors will still return ResponseStatus.Completed, check StatusCode instead
Expand Down
29 changes: 29 additions & 0 deletions test/RestSharp.Tests.Integrated/ResponseTrailerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#if NET8_0_OR_GREATER
using System.Net;
using System.Net.Http;

namespace RestSharp.Tests.Integrated;

public class ResponseTrailerTests {
[Fact]
public async Task Response_trailers_are_preserved_separately_from_headers() {
using var client = new RestClient(new TrailerResponseHandler());

var response = await client.ExecuteAsync(new RestRequest("https://example.test/"));

response.TrailingHeaders.Should().ContainSingle(header => header.Name == "Checksum" && header.Value == "abc123");

Check warning on line 14 in test/RestSharp.Tests.Integrated/ResponseTrailerTests.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of using this literal 'Checksum' 4 times.

See more on https://sonarcloud.io/project/issues?id=restsharp_RestSharp&issues=AaFEs9o2mFBUDu2yz43e&open=AaFEs9o2mFBUDu2yz43e&pullRequest=2417
response.Headers.Should().NotContain(header => header.Name == "Checksum");
response.ContentHeaders.Should().NotContain(header => header.Name == "Checksum");
}

sealed class TrailerResponseHandler : HttpMessageHandler {
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
var response = new HttpResponseMessage(HttpStatusCode.OK) {
Content = new StringContent("body")
};
response.TrailingHeaders.TryAddWithoutValidation("Checksum", "abc123");
return Task.FromResult(response);
}
}
}
#endif