fix(services/azblob): carry content type and user metadata on Put Block List - #8148
Merged
Merged
Conversation
…ck List azblob declares write_with_content_type and write_with_user_metadata, but only azblob_put_blob_request honours them, and BlockWriter reaches that only for a one-shot write. A chunked write commits through Put Block List, which set cache-control and the conditional headers but neither the content type nor x-ms-meta-*, so both were dropped. Put Block List is where Azure applies blob properties; the same headers on the individual Put Block requests are ignored, which is why setting them there looked like coverage without being any. Adds a test asserting both headers on the built request.
Xuanwo
approved these changes
Aug 26, 2026
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.
Which issue does this PR close?
None.
Rationale for this change
azblob declares both capabilities:
but only
azblob_put_blob_requesthonours them — it setsCONTENT_TYPEatcore.rs:295andx-ms-meta-*at:320-323.oio::BlockWritereaches thatrequest only through
write_once. A write that arrives in more than one chunkgoes Put Block per chunk and commits with Put Block List, and that builder set
the SSE headers,
x-ms-blob-cache-controland the three conditional headers —but neither the content type nor any user metadata.
Put Block List is the request where Azure applies blob properties and
metadata. The function already knew that for the preconditions; its own
comment says so:
The properties simply were not carried across with them.
What makes it easy to miss:
azblob_put_block_request(core.rs:482-492) doesset
CONTENT_TYPEandX_MS_BLOB_CACHE_CONTROL. Azure ignores blob-propertyheaders on Put Block, so those two lines look like coverage while going nowhere.
For contrast, s3, cos and gcs all put content type and user metadata on their
initiate request, where the service does honour them.
What changes are included in this PR?
Put Block List now carries the content type and the user metadata, alongside the
cache control it already sent. A
X_MS_BLOB_CONTENT_TYPEconstant is added nextto the existing
X_MS_BLOB_CACHE_CONTROL.Are there any user-facing changes?
Yes. A chunked write with
.content_type(..)or.user_metadata(..)nowproduces a blob carrying them, instead of
application/octet-streamand nometadata. Nothing changes for a one-shot write, which already worked.
Note on reachability and on testing
Worth being precise, because the obvious reproduction does not trigger it.
azblob declares
write_can_multi: truewith nowrite_multi_min_sizeorwrite_multi_max_size, soWriteContext::calculate_chunk_sizeyields no chunksize and
op.write_with(path, data)forwards the whole buffer in a singlewrite()call at any size —BlockWriterthen takes thewrite_oncebranch andPut Blob carries everything correctly. The path that loses the properties is an
explicit
op.writer_with(path).chunk(n), or two or morewrite()calls on thewriter.
The existing behavior tests match that shape:
async_write.rs:163and:233assert content type and user metadata only on one-shot
write_with, while thechunked cases at
:416,:460,:498and:533assert neither.The added test builds the request directly and asserts both headers, so it needs
no account and no transport. I do not have an Azure Storage account and have not
run this against one; the Azure-side claim here is the documented behaviour that
blob properties are set by Put Block List and ignored on Put Block.