From 81fb11ca80cdc4b4655a6cbd814b5f3d0d331973 Mon Sep 17 00:00:00 2001 From: arashnd Date: Tue, 3 Dec 2024 14:45:56 +0500 Subject: [PATCH 1/4] Add support for additional headers --- lib/azure_blob/client.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/azure_blob/client.rb b/lib/azure_blob/client.rb index c6235ba..6c64a42 100644 --- a/lib/azure_blob/client.rb +++ b/lib/azure_blob/client.rb @@ -323,6 +323,7 @@ def commit_blob_blocks(key, block_ids, options = {}) "Content-Type": options[:content_type], "x-ms-blob-content-md5": options[:content_md5], "x-ms-blob-content-disposition": options[:content_disposition], + **(options[:headers] || {}).map { |k, v| [ :"x-ms-#{k}", v.to_s ] }.to_h } Http.new(uri, headers, signer:, **options.slice(:metadata, :tags)).put(content) @@ -355,6 +356,7 @@ def put_blob_single(key, content, options = {}) "Content-Type": options[:content_type], "x-ms-blob-content-md5": options[:content_md5], "x-ms-blob-content-disposition": options[:content_disposition], + **(options[:headers] || {}).map { |k, v| [ :"x-ms-#{k}", v.to_s ] }.to_h } Http.new(uri, headers, signer:, **options.slice(:metadata, :tags)).put(content.read) From 937f5f3ab1cd818e9169bb121b7a97f497ee9f27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A9=20Dupuis?= Date: Mon, 19 May 2025 16:32:41 -0700 Subject: [PATCH 2/4] Add additional headers to all endpoints --- lib/azure_blob/client.rb | 38 ++++++++++++++++++++---------------- test/client/test_client.rb | 40 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 17 deletions(-) diff --git a/lib/azure_blob/client.rb b/lib/azure_blob/client.rb index a5ae49d..f368bcc 100644 --- a/lib/azure_blob/client.rb +++ b/lib/azure_blob/client.rb @@ -72,7 +72,7 @@ def get_blob(key, options = {}) headers = { "x-ms-range": options[:start] && "bytes=#{options[:start]}-#{options[:end]}", - } + }.merge(additional_headers(options)) Http.new(uri, headers, signer:).get end @@ -97,7 +97,7 @@ def copy_blob(key, source_key, options = {}) headers = { "x-ms-copy-source": source_uri.to_s, "x-ms-requires-sync": "true", - } + }.merge(additional_headers(options)) Http.new(uri, headers, signer:, **options.slice(:metadata, :tags)).put end @@ -116,7 +116,7 @@ def delete_blob(key, options = {}) headers = { "x-ms-delete-snapshots": options[:delete_snapshots] || "include", - } + }.merge(additional_headers(options)) Http.new(uri, headers, signer:).delete end @@ -157,7 +157,7 @@ def list_blobs(options = {}) query[:marker] = marker query.reject! { |key, value| value.to_s.empty? } uri.query = URI.encode_www_form(**query) - response = Http.new(uri, signer:).get + response = Http.new(uri, additional_headers(options), signer:).get end BlobList.new(fetcher) @@ -172,7 +172,7 @@ def list_blobs(options = {}) def get_blob_properties(key, options = {}) uri = generate_uri("#{container}/#{key}") - response = Http.new(uri, signer:).head + response = Http.new(uri, additional_headers(options), signer:).head Blob.new(response) end @@ -193,9 +193,9 @@ def blob_exist?(key, options = {}) # Takes a key (path) of the blob. # # Returns a hash of the blob's tags. - def get_blob_tags(key) + def get_blob_tags(key, options = {}) uri = generate_uri("#{container}/#{key}?comp=tags") - response = Http.new(uri, signer:).get + response = Http.new(uri, additional_headers(options), signer:).get Tags.from_response(response).to_h end @@ -208,7 +208,7 @@ def get_blob_tags(key) def get_container_properties(options = {}) uri = generate_uri(container) uri.query = URI.encode_www_form(restype: "container") - response = Http.new(uri, signer:, raise_on_error: false).head + response = Http.new(uri, additional_headers(options), signer:, raise_on_error: false).head Container.new(response) end @@ -228,6 +228,7 @@ def create_container(options = {}) headers = {} headers[:"x-ms-blob-public-access"] = "blob" if options[:public_access] headers[:"x-ms-blob-public-access"] = options[:public_access] if [ "container", "blob" ].include?(options[:public_access]) + headers.merge!(additional_headers(options)) uri.query = URI.encode_www_form(restype: "container") response = Http.new(uri, headers, signer:).put @@ -239,7 +240,7 @@ def create_container(options = {}) def delete_container(options = {}) uri = generate_uri(container) uri.query = URI.encode_www_form(restype: "container") - response = Http.new(uri, signer:).delete + response = Http.new(uri, additional_headers(options), signer:).delete end # Return a URI object to a resource in the container. Takes a path. @@ -282,7 +283,7 @@ def create_append_blob(key, options = {}) "Content-Type": options[:content_type], "Content-MD5": options[:content_md5], "x-ms-blob-content-disposition": options[:content_disposition], - } + }.merge(additional_headers(options)) Http.new(uri, headers, signer:, **options.slice(:metadata, :tags)).put(nil) end @@ -304,7 +305,7 @@ def append_blob_block(key, content, options = {}) "Content-Length": content.size, "Content-Type": options[:content_type], "Content-MD5": options[:content_md5], - } + }.merge(additional_headers(options)) Http.new(uri, headers, signer:).put(content) end @@ -328,7 +329,7 @@ def put_blob_block(key, index, content, options = {}) "Content-Length": content.size, "Content-Type": options[:content_type], "Content-MD5": options[:content_md5], - } + }.merge(additional_headers(options)) Http.new(uri, headers, signer:).put(content) @@ -357,13 +358,17 @@ def commit_blob_blocks(key, block_ids, options = {}) "Content-Type": options[:content_type], "x-ms-blob-content-md5": options[:content_md5], "x-ms-blob-content-disposition": options[:content_disposition], - **(options[:headers] || {}).map { |k, v| [ :"x-ms-#{k}", v.to_s ] }.to_h - } + }.merge(additional_headers(options)) Http.new(uri, headers, signer:, **options.slice(:metadata, :tags)).put(content) end - private + private + + def additional_headers(options) + (options[:headers] || {}).transform_keys { |k| "x-ms-#{k}".to_sym }. + transform_values(&:to_s) + end def generate_block_id(index) Base64.urlsafe_encode64(index.to_s.rjust(6, "0")) @@ -390,8 +395,7 @@ def put_blob_single(key, content, options = {}) "Content-Type": options[:content_type], "x-ms-blob-content-md5": options[:content_md5], "x-ms-blob-content-disposition": options[:content_disposition], - **(options[:headers] || {}).map { |k, v| [ :"x-ms-#{k}", v.to_s ] }.to_h - } + }.merge(additional_headers(options)) Http.new(uri, headers, signer:, **options.slice(:metadata, :tags)).put(content.read) end diff --git a/test/client/test_client.rb b/test/client/test_client.rb index 9fac222..4a6be72 100644 --- a/test/client/test_client.rb +++ b/test/client/test_client.rb @@ -432,4 +432,44 @@ def test_copy_between_containers rescue AzureBlob::Http::FileNotFoundError end end + + def test_get_blob_additional_headers + http_mock = Minitest::Mock.new + http_mock.expect :get, "" + + stubbed_new = lambda do |uri, headers = {}, signer: nil, **kwargs| + assert_equal "bar", headers[:"x-ms-foo"] + http_mock + end + + AzureBlob::Http.stub :new, stubbed_new do + custom_client = AzureBlob::Client.new(account_name: "foo", access_key: "bar", container: "cont") + custom_client.get_blob(key, headers: { foo: "bar" }) + end + + http_mock.verify + dummy = Minitest::Mock.new + dummy.expect :delete_blob, nil, [key] + @client = dummy + end + + def test_create_append_blob_additional_headers + http_mock = Minitest::Mock.new + http_mock.expect :put, true, [nil] + + stubbed_new = lambda do |uri, headers = {}, signer: nil, **kwargs| + assert_equal "bar", headers[:"x-ms-foo"] + http_mock + end + + AzureBlob::Http.stub :new, stubbed_new do + custom_client = AzureBlob::Client.new(account_name: "foo", access_key: "bar", container: "cont") + custom_client.create_append_blob(key, headers: { foo: "bar" }) + end + + http_mock.verify + dummy = Minitest::Mock.new + dummy.expect :delete_blob, nil, [key] + @client = dummy + end end From 01ce4fa9095d79c412336e1e60b314881d52adb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A9=20Dupuis?= Date: Mon, 19 May 2025 16:36:16 -0700 Subject: [PATCH 3/4] Add changelog entry for additional headers support --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e76dbd..1f5b3d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ ## [Unreleased] +- Add support for additional headers to all endpoints + ## [0.5.8] 2025-05-14 - Add support for copying blobs across containers (#24) From 5924c6183e77736d0f26a77a6e6616fc2023cf8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A9=20Dupuis?= Date: Mon, 19 May 2025 18:54:45 -0700 Subject: [PATCH 4/4] Lint --- test/client/test_client.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/client/test_client.rb b/test/client/test_client.rb index cbacf55..b16c1b9 100644 --- a/test/client/test_client.rb +++ b/test/client/test_client.rb @@ -449,13 +449,13 @@ def test_get_blob_additional_headers http_mock.verify dummy = Minitest::Mock.new - dummy.expect :delete_blob, nil, [key] + dummy.expect :delete_blob, nil, [ key ] @client = dummy end def test_create_append_blob_additional_headers http_mock = Minitest::Mock.new - http_mock.expect :put, true, [nil] + http_mock.expect :put, true, [ nil ] stubbed_new = lambda do |uri, headers = {}, signer: nil, **kwargs| assert_equal "bar", headers[:"x-ms-foo"] @@ -469,7 +469,7 @@ def test_create_append_blob_additional_headers http_mock.verify dummy = Minitest::Mock.new - dummy.expect :delete_blob, nil, [key] + dummy.expect :delete_blob, nil, [ key ] @client = dummy end end