fix path encoding issue (#794)

This commit is contained in:
JinmingHu 2020-10-16 12:43:12 +08:00 committed by GitHub
parent fda43987e4
commit 5bad554a06
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 88 additions and 18 deletions

View File

@ -239,8 +239,8 @@ namespace Azure { namespace Storage { namespace Blobs {
requestBody += getBatchBoundary();
auto blobUrl = m_serviceUrl;
blobUrl.AppendPath(subrequest.ContainerName);
blobUrl.AppendPath(subrequest.BlobName);
blobUrl.AppendPath(Details::UrlEncodePath(subrequest.ContainerName));
blobUrl.AppendPath(Details::UrlEncodePath(subrequest.BlobName));
BlobRestClient::Blob::DeleteBlobOptions protocolLayerOptions;
protocolLayerOptions.DeleteSnapshots = subrequest.Options.DeleteSnapshots;
protocolLayerOptions.IfModifiedSince = subrequest.Options.AccessConditions.IfModifiedSince;
@ -261,8 +261,8 @@ namespace Azure { namespace Storage { namespace Blobs {
requestBody += getBatchBoundary();
auto blobUrl = m_serviceUrl;
blobUrl.AppendPath(subrequest.ContainerName);
blobUrl.AppendPath(subrequest.BlobName);
blobUrl.AppendPath(Details::UrlEncodePath(subrequest.ContainerName));
blobUrl.AppendPath(Details::UrlEncodePath(subrequest.BlobName));
BlobRestClient::Blob::SetBlobAccessTierOptions protocolLayerOptions;
protocolLayerOptions.Tier = subrequest.Tier;
protocolLayerOptions.RehydratePriority = subrequest.Options.RehydratePriority;

View File

@ -23,7 +23,7 @@ namespace Azure { namespace Storage { namespace Blobs {
{
auto parsedConnectionString = Details::ParseConnectionString(connectionString);
auto containerUri = std::move(parsedConnectionString.BlobServiceUri);
containerUri.AppendPath(containerName);
containerUri.AppendPath(Details::UrlEncodePath(containerName));
if (parsedConnectionString.KeyCredential)
{
@ -117,7 +117,7 @@ namespace Azure { namespace Storage { namespace Blobs {
BlobClient BlobContainerClient::GetBlobClient(const std::string& blobName) const
{
auto blobUri = m_containerUrl;
blobUri.AppendPath(blobName);
blobUri.AppendPath(Details::UrlEncodePath(blobName));
return BlobClient(std::move(blobUri), m_pipeline, m_customerProvidedKey, m_encryptionScope);
}

View File

@ -1,13 +1,13 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#include "blob_container_client_test.hpp"
#include "azure/storage/blobs/blob_sas_builder.hpp"
#include "azure/storage/common/crypt.hpp"
#include <chrono>
#include <thread>
#include "azure/storage/blobs/blob_sas_builder.hpp"
#include "azure/storage/common/crypt.hpp"
#include "blob_container_client_test.hpp"
namespace Azure { namespace Storage { namespace Blobs {
bool operator==(
@ -1048,4 +1048,39 @@ namespace Azure { namespace Storage { namespace Test {
}
}
TEST_F(BlobContainerClientTest, SpecialBlobName)
{
const std::string non_ascii_word = "\xE6\xB5\x8B\xE8\xAF\x95";
const std::string encoded_non_ascii_word = "%E6%B5%8B%E8%AF%95";
std::string baseBlobName = "a b c / !@#$%^&*() def" + non_ascii_word;
{
std::string blobName = baseBlobName + RandomString();
auto blobClient = m_blobContainerClient->GetAppendBlobClient(blobName);
EXPECT_NO_THROW(blobClient.Create());
auto blobUrl = blobClient.GetUri();
EXPECT_EQ(
blobUrl,
m_blobContainerClient->GetUri() + "/" + Storage::Details::UrlEncodePath(blobName));
}
{
std::string blobName = baseBlobName + RandomString();
auto blobClient = m_blobContainerClient->GetPageBlobClient(blobName);
EXPECT_NO_THROW(blobClient.Create(1024));
auto blobUrl = blobClient.GetUri();
EXPECT_EQ(
blobUrl,
m_blobContainerClient->GetUri() + "/" + Storage::Details::UrlEncodePath(blobName));
}
{
std::string blobName = baseBlobName + RandomString();
auto blobClient = m_blobContainerClient->GetBlockBlobClient(blobName);
EXPECT_NO_THROW(blobClient.UploadFrom(nullptr, 0));
auto blobUrl = blobClient.GetUri();
EXPECT_EQ(
blobUrl,
m_blobContainerClient->GetUri() + "/" + Storage::Details::UrlEncodePath(blobName));
}
}
}}} // namespace Azure::Storage::Test

View File

@ -64,5 +64,6 @@ namespace Azure { namespace Storage {
std::string Sha256(const std::string& text);
std::string HmacSha256(const std::string& text, const std::string& key);
std::string UrlEncodeQueryParameter(const std::string& value);
std::string UrlEncodePath(const std::string& value);
} // namespace Details
}} // namespace Azure::Storage

View File

@ -23,15 +23,16 @@
namespace Azure { namespace Storage {
namespace Details {
static const char* c_unreserved
= "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~";
static const char* c_subdelimiters = "!$&'()*+,;=";
const char* c_hex = "0123456789ABCDEF";
std::string UrlEncodeQueryParameter(const std::string& value)
{
static const char* unreserved
= "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~";
static const char* subdelimiters = "!$&'()*+,;=";
const static std::vector<bool> shouldEncodeTable = []() {
std::string queryCharacters
= std::string(unreserved) + std::string(subdelimiters) + "%/:@?";
= std::string(c_unreserved) + std::string(c_subdelimiters) + "%/:@?";
std::vector<bool> ret(256, true);
for (char c : queryCharacters)
@ -48,7 +49,40 @@ namespace Azure { namespace Storage {
return ret;
}();
const char* hex = "0123456789ABCDEF";
std::string encoded;
for (char c : value)
{
unsigned char uc = c;
if (shouldEncodeTable[uc])
{
encoded += '%';
encoded += c_hex[(uc >> 4) & 0x0f];
encoded += c_hex[uc & 0x0f];
}
else
{
encoded += c;
}
}
return encoded;
}
std::string UrlEncodePath(const std::string& value)
{
const static std::vector<bool> shouldEncodeTable = []() {
std::string pathCharacters
= std::string(c_unreserved) + std::string(c_subdelimiters) + "%/:@";
std::vector<bool> ret(256, true);
for (char c : pathCharacters)
{
ret[c] = false;
}
// we also encode % and +
ret['%'] = true;
ret['+'] = true;
return ret;
}();
std::string encoded;
for (char c : value)
@ -57,8 +91,8 @@ namespace Azure { namespace Storage {
if (shouldEncodeTable[uc])
{
encoded += '%';
encoded += hex[(uc >> 4) & 0x0f];
encoded += hex[uc & 0x0f];
encoded += c_hex[(uc >> 4) & 0x0f];
encoded += c_hex[uc & 0x0f];
}
else
{