Repository navigation
Match metadata header names case-insensitively - #62
Open
fusionfoto wants to merge 1 commit into
Open
fusionfoto wants to merge 1 commit into
fusionfoto wants to merge 1 commit into
Conversation
fusionfoto
force-pushed
the
bugfix/case-insensitive-metadata-headers
branch
from
November 11, 2026 00:34
e62a232 to
6f9ad09
Compare
HTTP header names are case-insensitive (RFC 9110). Some reverse proxies forward them in lower case, so x-container-meta-* and x-object-meta-* headers were dropped from ContainerMetadata and ObjectMetadata, and lookups like containsKey(Constants.MANIFEST_HEADER) in Client#listObjectSegments missed x-object-manifest and x-static-large-object. - Match the X-Container-Meta- and X-Object-Meta- prefixes ignoring case. - Keep metadata in a case-insensitive map. Keys keep the header name as received. Contributed by AiNET (https://ai.net) and Blomp (https://www.blomp.com).
fusionfoto
force-pushed
the
bugfix/case-insensitive-metadata-headers
branch
from
November 11, 2026 00:36
6f9ad09 to
11c0591
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Lower-case metadata keys cause the case-sensitive update logic to duplicate container and object metadata prefixes, updating the wrong fields.
1 open issue
What changed in this PR
This PR makes Swift metadata handling case-insensitive so lower-cased response headers remain available for quota retrieval and large-object segment discovery.
Changes:
- Match container and object metadata prefixes without case sensitivity.
- Store metadata in case-insensitive maps while preserving header spelling, including when replacing metadata.
- Add regression tests for lower-case headers, canonical headers, manifest/SLO lookups, and null metadata replacement.
| File | Description |
|---|---|
src/test/java/ch/iterate/openstack/swift/handler/MetadataResponseHandlerCaseTest.java |
Tests case-insensitive metadata handling and map replacement. |
src/main/java/ch/iterate/openstack/swift/model/MetaData.java |
Uses case-insensitive maps and handles null replacement input. |
src/main/java/ch/iterate/openstack/swift/handler/ObjectMetadataResponseHandler.java |
Accepts object metadata prefixes regardless of case. |
src/main/java/ch/iterate/openstack/swift/handler/ContainerMetadataResponseHandler.java |
Accepts container metadata prefixes regardless of case. |
Review effort: Balanced
| // Header names are case-insensitive (RFC 9110) and proxies may send them in lower case | ||
| for(Header h : response.getAllHeaders()) { | ||
| if(h.getName().startsWith(Constants.X_CONTAINER_META) | ||
| if(h.getName().regionMatches(true, 0, Constants.X_CONTAINER_META, 0, Constants.X_CONTAINER_META.length()) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Contributed by AiNET and Blomp.
Hi there 👋, and thanks for maintaining this library!
The problem. HTTP header names are case-insensitive (RFC 9110 §5.1), but
ContainerMetadataResponseHandlerandObjectMetadataResponseHandlermatch theX-Container-Meta-/X-Object-Meta-prefixes with a case-sensitivestartsWith. When Swift sits behind a proxy that lower-cases header names (some reverse proxies do this, and HTTP/2 requires lower case), all of that metadata is silently dropped. We hit it at Blomp:X-Container-Meta-Quota-Bytesnever reached Cyberduck.A related case:
Client#listObjectSegmentslooks upConstants.MANIFEST_HEADERandConstants.X_STATIC_LARGE_OBJECTby exact name, so behind such a proxy it doesn't recognise existing large objects.Why it matters most.
listObjectSegmentsis what finds a large object's segments when it is deleted, so behind such a proxy deleting a large object with Cyberduck leaves all of its segments in storage. In a test with a segmented upload and delete through Cyberduck, 2.5.14 left every segment behind and this branch left none.The fix (small, no API change):
regionMatches(true, …), ignoring case.MetaDatakeeps its map asTreeMap(String.CASE_INSENSITIVE_ORDER), so lookups by the constants work whatever case the server used. Keys still keep the header name as received.setMetaDatacopies into the same kind of map, and anullargument now leaves the map empty.Tests. The new
MetadataResponseHandlerCaseTestcovers lower-case container and object headers, manifest/SLO lookups by constant, the canonical case, andsetMetaData.mvn verifypasses (20 tests). On unmodifiedmaster, 3 of the 4 new tests fail; the canonical-case one passes there too, as expected.Live check against the Blomp service:
getContainerMetaDatareturns the quota metadata with this branch, and nothing with 2.5.14.This is the library-side counterpart of iterate-ch/cyberduck#18688. That PR works around the issue for quota only, by reading the HEAD response headers directly; it can switch back to
getContainerMetaDataonce a release includes this fix. Happy to adjust anything. Thank you! 🙏