diff --git a/packages/Storage/Storage.Tests/Files/StorageFileApiContractTests.cs b/packages/Storage/Storage.Tests/Files/StorageFileApiContractTests.cs index 9f37c2d3..55d7a5b7 100644 --- a/packages/Storage/Storage.Tests/Files/StorageFileApiContractTests.cs +++ b/packages/Storage/Storage.Tests/Files/StorageFileApiContractTests.cs @@ -392,6 +392,62 @@ public async Task List_ShouldSurfaceStorageException_GivenNonJsonError() } } + [TestMethod] + public async Task UploadToSignedUrl_ShouldForwardMetadataAndCustomHeaders_GivenFileOptions() + { + var signedUrl = new UploadSignedUrl( + new Uri($"{this.server.Url}/storage/v1/object/upload/sign/{Bucket}/file.bin?token=abc"), + "abc", + "file.bin"); + this.Respond($"/storage/v1/object/upload/sign/{Bucket}/file.bin", "POST", 200, "{\"Key\":\"x\"}"); + var options = new FileOptions + { + ContentType = "image/png", + Metadata = new Dictionary { ["k"] = "v" }, + Headers = new Dictionary { ["x-version"] = "123" } + }; + await this.client.From(Bucket).UploadToSignedUrl(Encoding.UTF8.GetBytes("data"), signedUrl, options, inferContentType: false); + var request = this.SingleRequest(); + using (new AssertionScope()) + { + this.HeaderOf(request, "x-metadata").Should().NotBeNullOrEmpty("metadata must ride the signed-URL upload (issue #252)"); + this.HeaderOf(request, "x-version").Should().Be("123", "custom headers must merge into the signed-URL upload (issue #252)"); + } + } + + [TestMethod] + public async Task UploadToSignedUrlFromDisk_ShouldForwardMetadataAndCustomHeaders_GivenFileOptions() + { + var signedUrl = new UploadSignedUrl( + new Uri($"{this.server.Url}/storage/v1/object/upload/sign/{Bucket}/file.bin?token=abc"), + "abc", + "file.bin"); + this.Respond($"/storage/v1/object/upload/sign/{Bucket}/file.bin", "POST", 200, "{\"Key\":\"x\"}"); + var localPath = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.bin"); + await File.WriteAllBytesAsync(localPath, new byte[] { 0x1, 0x2 }); + try + { + var options = new FileOptions + { + ContentType = "image/png", + Metadata = new Dictionary { ["k"] = "v" }, + Headers = new Dictionary { ["x-version"] = "123" } + }; + await this.client.From(Bucket).UploadToSignedUrl(localPath, signedUrl, options, inferContentType: false); + var request = this.SingleRequest(); + using (new AssertionScope()) + { + this.HeaderOf(request, "x-metadata").Should().NotBeNullOrEmpty("metadata must ride the from-disk signed-URL upload (issue #252)"); + this.HeaderOf(request, "x-version").Should().Be("123", "custom headers must merge into the from-disk signed-URL upload (issue #252)"); + } + } + finally + { + if (File.Exists(localPath)) + File.Delete(localPath); + } + } + private void Respond(string path, string method, int statusCode, string body) => this.server.Given(Request.Create().WithPath(path).UsingMethod(method)) .RespondWith(Response.Create().WithStatusCode(statusCode) diff --git a/packages/Storage/Storage/StorageFileApi.cs b/packages/Storage/Storage/StorageFileApi.cs index 38a9c673..094b4ee4 100644 --- a/packages/Storage/Storage/StorageFileApi.cs +++ b/packages/Storage/Storage/StorageFileApi.cs @@ -399,6 +399,11 @@ public async Task UploadToSignedUrl( if (options.Upsert) this.StorageHeader.Add("x-upsert", options.Upsert.ToString().ToLower()); + if (options.Metadata != null) + this.StorageHeader.Add("x-metadata", ParseMetadata(options.Metadata)); + + options.Headers?.ToList().ForEach(x => this.StorageHeader.Add(x.Key, x.Value)); + var progress = new Progress(); if (onProgress != null) @@ -446,6 +451,8 @@ public async Task UploadToSignedUrl( if (options.Metadata != null) this.StorageHeader.Add("x-metadata", ParseMetadata(options.Metadata)); + options.Headers?.ToList().ForEach(x => this.StorageHeader.Add(x.Key, x.Value)); + var progress = new Progress(); if (onProgress != null)