Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,26 @@ public async Task Upload_ShouldComposeStorageHeadersFromFileOptions()
}
}

[TestMethod]
public async Task Upload_ShouldNotSendHeadersFromAnEarlierUpload()
{
var signedUrl = new UploadSignedUrl(
new Uri($"{this.server.Url}/storage/v1/object/upload/sign/{Bucket}/a.bin?token=abc"),
"abc",
"a.bin");
this.Respond($"/storage/v1/object/upload/sign/{Bucket}/a.bin", "POST", 200, "{\"Key\":\"x\"}");
this.Respond($"/storage/v1/object/{Bucket}/b.bin", "POST", 200, "{\"Key\":\"x\"}");
var bucket = this.client.From(Bucket);
await bucket.UploadToSignedUrl(new byte[] { 0x1 }, signedUrl, new FileOptions { Upsert = true });
await bucket.Upload(new byte[] { 0x1 }, "b.bin");
var request = this.server.LogEntries.Last().RequestMessage!;
using (new AssertionScope())
{
this.HeaderOf(request, "Authorization").Should().Be("Bearer test-key", "a signed upload's token must not replace the client's key on later uploads");
request.Headers.Should().NotContainKey("x-upsert", "an upsert on one upload must not make later uploads on the same bucket overwrite");
}
}

[TestMethod]
public async Task Upload_ShouldReportProgress_GivenAProgressHandler()
{
Expand Down
98 changes: 55 additions & 43 deletions packages/Storage/Storage/StorageFileApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -392,17 +392,19 @@ public async Task<string> UploadToSignedUrl(
if (inferContentType)
options.ContentType = MimeMapping.MimeUtility.GetMimeMapping(localFilePath);

this.StorageHeader.Add("Authorization", $"Bearer {signedUrl.Token}");
this.StorageHeader.Add("cache-control", $"max-age={options.CacheControl}");
this.StorageHeader.Add("content-type", options.ContentType);
var headers = new Header();
headers.Add(this.StorageHeader.Get());
headers.Add("Authorization", $"Bearer {signedUrl.Token}");
headers.Add("cache-control", $"max-age={options.CacheControl}");
headers.Add("content-type", options.ContentType);

if (options.Upsert)
this.StorageHeader.Add("x-upsert", options.Upsert.ToString().ToLower());
headers.Add("x-upsert", options.Upsert.ToString().ToLower());

if (options.Metadata != null)
this.StorageHeader.Add("x-metadata", ParseMetadata(options.Metadata));
headers.Add("x-metadata", ParseMetadata(options.Metadata));

options.Headers?.ToList().ForEach(x => this.StorageHeader.Add(x.Key, x.Value));
options.Headers?.ToList().ForEach(x => headers.Add(x.Key, x.Value));

var progress = new Progress<float>();

Expand All @@ -412,9 +414,9 @@ public async Task<string> UploadToSignedUrl(
await this.uploadClient.UploadFileAsync(
signedUrl.SignedUrl,
localFilePath,
this.StorageHeader.Get(),
headers.Get(),
progress
);
).ConfigureAwait(false);

return this.GetFinalPath(signedUrl.Key);
}
Expand All @@ -441,17 +443,19 @@ public async Task<string> UploadToSignedUrl(
if (inferContentType)
options.ContentType = MimeMapping.MimeUtility.GetMimeMapping(signedUrl.Key);

this.StorageHeader.Add("Authorization", $"Bearer {signedUrl.Token}");
this.StorageHeader.Add("cache-control", $"max-age={options.CacheControl}");
this.StorageHeader.Add("content-type", options.ContentType);
var headers = new Header();
headers.Add(this.StorageHeader.Get());
headers.Add("Authorization", $"Bearer {signedUrl.Token}");
headers.Add("cache-control", $"max-age={options.CacheControl}");
headers.Add("content-type", options.ContentType);

if (options.Upsert)
this.StorageHeader.Add("x-upsert", options.Upsert.ToString().ToLower());
headers.Add("x-upsert", options.Upsert.ToString().ToLower());

if (options.Metadata != null)
this.StorageHeader.Add("x-metadata", ParseMetadata(options.Metadata));
headers.Add("x-metadata", ParseMetadata(options.Metadata));

options.Headers?.ToList().ForEach(x => this.StorageHeader.Add(x.Key, x.Value));
options.Headers?.ToList().ForEach(x => headers.Add(x.Key, x.Value));

var progress = new Progress<float>();

Expand All @@ -461,9 +465,9 @@ public async Task<string> UploadToSignedUrl(
await this.uploadClient.UploadBytesAsync(
signedUrl.SignedUrl,
data,
this.StorageHeader.Get(),
headers.Get(),
progress
);
).ConfigureAwait(false);

return this.GetFinalPath(signedUrl.Key);
}
Expand Down Expand Up @@ -832,26 +836,28 @@ private async Task<string> UploadOrUpdate(
{
var uri = new Uri($"{this.Url}/object/{this.GetFinalPath(supabasePath)}");

this.StorageHeader.Add("cache-control", $"max-age={options.CacheControl}");
this.StorageHeader.Add("content-type", options.ContentType);
var headers = new Header();
headers.Add(this.StorageHeader.Get());
headers.Add("cache-control", $"max-age={options.CacheControl}");
headers.Add("content-type", options.ContentType);

if (options.Upsert)
this.StorageHeader.Add("x-upsert", options.Upsert.ToString().ToLower());
headers.Add("x-upsert", options.Upsert.ToString().ToLower());

if (options.Metadata != null)
this.StorageHeader.Add("x-metadata", ParseMetadata(options.Metadata));
headers.Add("x-metadata", ParseMetadata(options.Metadata));

options.Headers?.ToList().ForEach(x => this.StorageHeader.Add(x.Key, x.Value));
options.Headers?.ToList().ForEach(x => headers.Add(x.Key, x.Value));

if (options.Duplex != null)
this.StorageHeader.Add("x-duplex", options.Duplex.ToLower());
headers.Add("x-duplex", options.Duplex.ToLower());

var progress = new Progress<float>();

if (onProgress != null)
progress.ProgressChanged += onProgress;

await this.uploadClient.UploadFileAsync(uri, localPath, this.StorageHeader.Get(), progress, cancellationToken);
await this.uploadClient.UploadFileAsync(uri, localPath, headers.Get(), progress, cancellationToken).ConfigureAwait(false);

return this.GetFinalPath(supabasePath);
}
Expand All @@ -866,7 +872,9 @@ private async Task UploadOrContinue(
{
var uri = new Uri($"{this.Url}/upload/resumable");

this.StorageHeader.Add("cache-control", $"max-age={options.CacheControl}");
var headers = new Header();
headers.Add(this.StorageHeader.Get());
headers.Add("cache-control", $"max-age={options.CacheControl}");

var metadata = new MetadataCollection
{
Expand All @@ -876,15 +884,15 @@ private async Task UploadOrContinue(
};

if (options.Upsert)
this.StorageHeader.Add("x-upsert", options.Upsert.ToString().ToLower());
headers.Add("x-upsert", options.Upsert.ToString().ToLower());

if (options.Metadata != null)
this.StorageHeader.Add("x-metadata", ParseMetadata(options.Metadata));
headers.Add("x-metadata", ParseMetadata(options.Metadata));

options.Headers?.ToList().ForEach(x => this.StorageHeader.Add(x.Key, x.Value));
options.Headers?.ToList().ForEach(x => headers.Add(x.Key, x.Value));

if (options.Duplex != null)
this.StorageHeader.Add("x-duplex", options.Duplex.ToLower());
headers.Add("x-duplex", options.Duplex.ToLower());

var progress = new Progress<float>();

Expand All @@ -895,10 +903,10 @@ await this.uploadClient.UploadOrContinueFileAsync(
uri,
localPath,
metadata,
this.StorageHeader.Get(),
headers.Get(),
progress,
cancellationToken
);
).ConfigureAwait(false);
}

private async Task UploadOrContinue(
Expand All @@ -911,7 +919,9 @@ private async Task UploadOrContinue(
{
var uri = new Uri($"{this.Url}/upload/resumable");

this.StorageHeader.Add("cache-control", $"max-age={options.CacheControl}");
var headers = new Header();
headers.Add(this.StorageHeader.Get());
headers.Add("cache-control", $"max-age={options.CacheControl}");

var metadata = new MetadataCollection
{
Expand All @@ -921,15 +931,15 @@ private async Task UploadOrContinue(
};

if (options.Upsert)
this.StorageHeader.Add("x-upsert", options.Upsert.ToString().ToLower());
headers.Add("x-upsert", options.Upsert.ToString().ToLower());

if (options.Metadata != null)
metadata["metadata"] = JsonSerializer.Serialize(options.Metadata, Helpers.SerializerOptions);

options.Headers?.ToList().ForEach(x => this.StorageHeader.Add(x.Key, x.Value));
options.Headers?.ToList().ForEach(x => headers.Add(x.Key, x.Value));

if (options.Duplex != null)
this.StorageHeader.Add("x-duplex", options.Duplex.ToLower());
headers.Add("x-duplex", options.Duplex.ToLower());

var progress = new Progress<float>();

Expand All @@ -940,10 +950,10 @@ await this.uploadClient.UploadOrContinueByteAsync(
uri,
data,
metadata,
this.StorageHeader.Get(),
headers.Get(),
progress,
cancellationToken
);
).ConfigureAwait(false);
}

private static string ParseMetadata(Dictionary<string, string> metadata)
Expand All @@ -964,26 +974,28 @@ private async Task<string> UploadOrUpdate(
{
var uri = new Uri($"{this.Url}/object/{this.GetFinalPath(supabasePath)}");

this.StorageHeader.Add("cache-control", $"max-age={options.CacheControl}");
this.StorageHeader.Add("content-type", options.ContentType);
var headers = new Header();
headers.Add(this.StorageHeader.Get());
headers.Add("cache-control", $"max-age={options.CacheControl}");
headers.Add("content-type", options.ContentType);

if (options.Upsert)
this.StorageHeader.Add("x-upsert", options.Upsert.ToString().ToLower());
headers.Add("x-upsert", options.Upsert.ToString().ToLower());

if (options.Metadata != null)
this.StorageHeader.Add("x-metadata", ParseMetadata(options.Metadata));
headers.Add("x-metadata", ParseMetadata(options.Metadata));

options.Headers?.ToList().ForEach(x => this.StorageHeader.Add(x.Key, x.Value));
options.Headers?.ToList().ForEach(x => headers.Add(x.Key, x.Value));

if (options.Duplex != null)
this.StorageHeader.Add("x-duplex", options.Duplex.ToLower());
headers.Add("x-duplex", options.Duplex.ToLower());

var progress = new Progress<float>();

if (onProgress != null)
progress.ProgressChanged += onProgress;

await this.uploadClient.UploadBytesAsync(uri, data, this.StorageHeader.Get(), progress, cancellationToken);
await this.uploadClient.UploadBytesAsync(uri, data, headers.Get(), progress, cancellationToken).ConfigureAwait(false);

return this.GetFinalPath(supabasePath);
}
Expand Down
Loading