Skip to content

Conversation

@GarrettBeatty
Copy link
Contributor

@GarrettBeatty GarrettBeatty commented Dec 10, 2025

Description

This PR fixes two issues related to the Content-Language HTTP header in the AWS SDK for .NET:

  1. Request Signing Issue: The Content-Language header was not properly handled as a content header in HttpRequestMessageFactory, causing signature mismatch errors. This was is also happening on development branch too.

  2. GetObjectMetadataResponse Backing Field Consistency: Changed GetObjectMetadataResponse.ContentLanguage to use Headers.ContentLanguage as the backing field, matching the pattern used by GetObjectResponse.ContentLanguage.

Request Signing Fix

Symptom:
When setting Content-Language on a PutObject request, the SDK throws SignatureDoesNotMatch:

Root Cause:
The SDK includes Content-Language in signature calculation, but .NET's HttpClient wasn't actually sending it because the header wasn't being placed on HttpContent.Headers.

Evidence from AWS error response:

Component Canonical Request Content
SDK signed with content-language:en-US
AWS received content-language: (empty)

The Content-Language header value was lost because:

  1. HttpWebRequestMessage.ContentHeaderNames didn't include Content-Language
  2. SetRequestHeaders() attempted to add it to HttpRequestMessage.Headers (request headers)
  3. Per RFC 7231, Content-Language is a content header - .NET's HttpClient rejects it as a request header
  4. WriteContentHeaders() had no code to add Content-Language to HttpContent.Headers
  5. Result: Header signed but never sent → signature mismatch

Fix:

  1. Added HeaderKeys.ContentLanguageHeader to ContentHeaderNames HashSet
  2. Added Content-Language handling in WriteContentHeaders() method

GetObjectMetadataResponse Backing Field Fix

Changed GetObjectMetadataResponse.ContentLanguage to delegate to Headers.ContentLanguage as the backing store instead of a private field, matching the pattern in GetObjectResponse.ContentLanguage.

Testing

  1. Integ Test
  2. Dry run e27c9b4e-0984-4201-9fc9-fb5ab5f28ac0

Checklist

  • My code follows the code style of this project
  • My change requires a change to the documentation
  • I have updated the documentation accordingly
  • I have read the README document
  • I have added tests to cover my changes
  • All new and existing tests passed

License

  • I confirm that this pull request can be released under the Apache 2 license

GarrettBeatty added a commit that referenced this pull request Dec 10, 2025
stack-info: PR: #4224, branch: GarrettBeatty/gcbeatty/taskoptimization/5
@GarrettBeatty GarrettBeatty force-pushed the GarrettBeatty/gcbeatty/taskoptimization/5 branch from 2750531 to c331621 Compare December 10, 2025 22:39
@GarrettBeatty GarrettBeatty changed the base branch from GarrettBeatty/gcbeatty/taskoptimization/3 to feature/transfermanager December 11, 2025 14:27
GarrettBeatty added a commit that referenced this pull request Dec 11, 2025
stack-info: PR: #4224, branch: GarrettBeatty/gcbeatty/taskoptimization/5
@GarrettBeatty GarrettBeatty force-pushed the GarrettBeatty/gcbeatty/taskoptimization/5 branch from c331621 to e073b2e Compare December 11, 2025 14:27
@GarrettBeatty GarrettBeatty changed the base branch from feature/transfermanager to GarrettBeatty/gcbeatty/taskoptimization/3 December 11, 2025 14:27
@GarrettBeatty GarrettBeatty changed the base branch from GarrettBeatty/gcbeatty/taskoptimization/3 to feature/transfermanager December 11, 2025 14:28
GarrettBeatty added a commit that referenced this pull request Dec 11, 2025
stack-info: PR: #4224, branch: GarrettBeatty/gcbeatty/taskoptimization/5
@GarrettBeatty GarrettBeatty force-pushed the GarrettBeatty/gcbeatty/taskoptimization/5 branch from e073b2e to f6c7aee Compare December 11, 2025 14:28
@GarrettBeatty GarrettBeatty changed the base branch from feature/transfermanager to GarrettBeatty/gcbeatty/taskoptimization/3 December 11, 2025 14:29
Base automatically changed from GarrettBeatty/gcbeatty/taskoptimization/3 to feature/transfermanager December 11, 2025 14:29
stack-info: PR: #4224, branch: GarrettBeatty/gcbeatty/taskoptimization/5
@GarrettBeatty GarrettBeatty force-pushed the GarrettBeatty/gcbeatty/taskoptimization/5 branch from 89431b0 to 0ad16d4 Compare December 15, 2025 19:50
@GarrettBeatty GarrettBeatty changed the title content language bug fix Content Language Bug Fix Dec 15, 2025
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a Content-Language header handling issue that caused signature mismatch errors in S3 requests. The root cause was that the SDK signed requests with Content-Language but didn't actually send the header because it wasn't properly configured as a content header in HttpClient. The PR also standardizes GetObjectMetadataResponse.ContentLanguage to use the Headers collection as its backing store, matching the pattern used in GetObjectResponse.

Key Changes:

  • Added Content-Language to the list of content headers in HttpRequestMessageFactory so it's correctly placed on HttpContent.Headers
  • Refactored GetObjectMetadataResponse.ContentLanguage to delegate to Headers.ContentLanguage instead of using a private field
  • Added integration test to verify Content-Language header is correctly sent and retrieved

Reviewed changes

Copilot reviewed 7 out of 9 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
sdk/src/Core/Amazon.Util/HeaderKeys.cs Added ContentLanguageHeader constant for consistent header name reference
sdk/src/Core/Amazon.Runtime/Pipeline/HttpHandler/_netstandard/HttpRequestMessageFactory.cs Added Content-Language to ContentHeaderNames HashSet and WriteContentHeaders method to fix signing/sending mismatch
sdk/src/Services/S3/Generated/Model/GetObjectMetadataResponse.cs Removed auto-generated ContentLanguage property and private field (moved to custom implementation)
sdk/src/Services/S3/Generated/Model/Internal/MarshallTransformations/GetObjectMetadataResponseUnmarshaller.cs Removed auto-generated unmarshalling code for ContentLanguage (moved to custom implementation)
sdk/src/Services/S3/Custom/Model/GetObjectMetadataResponse.cs Added custom ContentLanguage property that delegates to Headers.ContentLanguage
sdk/src/Services/S3/Custom/Model/Internal/MarshallTransformations/GetObjectMetadataResponseUnmarshaller.cs Added custom unmarshalling code that populates Headers.ContentLanguage
generator/ServiceModels/s3/s3.customizations.json Excluded ContentLanguage from HeadObjectOutput generation to enable custom implementation
sdk/test/Services/S3/IntegrationTests/PutObjectTests.cs Added integration test verifying Content-Language header round-trip through PutObject and GetObject/GetObjectMetadata
generator/.DevConfigs/19ed68ce-9f46-4e1e-a0ff-45a2b3641947.json Dev config with patch version bump and changelog message

GarrettBeatty and others added 3 commits December 15, 2025 15:38
@GarrettBeatty GarrettBeatty marked this pull request as ready for review December 15, 2025 21:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant