Skip to content

fix(services/azblob): carry content type and user metadata on Put Block List - #8148

Merged
Xuanwo merged 1 commit into
apache:mainfrom
PDGGK:fix-azblob-block-list-properties
Aug 26, 2026
Merged

fix(services/azblob): carry content type and user metadata on Put Block List#8148
Xuanwo merged 1 commit into
apache:mainfrom
PDGGK:fix-azblob-block-list-properties

Conversation

@PDGGK

@PDGGK PDGGK commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

None.

Rationale for this change

azblob declares both capabilities:

// backend.rs:409, :413
write_with_content_type: true,
write_with_user_metadata: true,

but only azblob_put_blob_request honours them — it sets CONTENT_TYPE at
core.rs:295 and x-ms-meta-* at :320-323. oio::BlockWrite reaches that
request only through write_once. A write that arrives in more than one chunk
goes Put Block per chunk and commits with Put Block List, and that builder set
the SSE headers, x-ms-blob-cache-control and 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:

// Put Block List is the request that actually commits a blocked write, so the
// write's preconditions have to be evaluated here rather than on Put Block.

The properties simply were not carried across with them.

What makes it easy to miss: azblob_put_block_request (core.rs:482-492) does
set CONTENT_TYPE and X_MS_BLOB_CACHE_CONTROL. Azure ignores blob-property
headers 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_TYPE constant is added next
to the existing X_MS_BLOB_CACHE_CONTROL.

Are there any user-facing changes?

Yes. A chunked write with .content_type(..) or .user_metadata(..) now
produces a blob carrying them, instead of application/octet-stream and no
metadata. 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: true with no write_multi_min_size or
write_multi_max_size, so WriteContext::calculate_chunk_size yields no chunk
size and op.write_with(path, data) forwards the whole buffer in a single
write() call at any size — BlockWriter then takes the write_once branch and
Put Blob carries everything correctly. The path that loses the properties is an
explicit op.writer_with(path).chunk(n), or two or more write() calls on the
writer.

The existing behavior tests match that shape: async_write.rs:163 and :233
assert content type and user metadata only on one-shot write_with, while the
chunked cases at :416, :460, :498 and :533 assert 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.

…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.
@PDGGK
PDGGK requested a review from Xuanwo as a code owner August 26, 2026 01:29
@dosubot dosubot Bot added size:M This PR changes 30-99 lines, ignoring generated files. releases-note/fix The PR fixes a bug or has a title that begins with "fix" labels Aug 26, 2026
@dosubot dosubot Bot added the lgtm This PR has been approved by a maintainer label Aug 26, 2026
@Xuanwo
Xuanwo merged commit e7988f7 into apache:main Aug 26, 2026
104 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm This PR has been approved by a maintainer releases-note/fix The PR fixes a bug or has a title that begins with "fix" size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants