Auto-generated protocol layer of Container and BlockBlob (#144)
* add blob service auto generated protocol layer * Add storage uri builder * integrate with pipeline * Add libxml2 dependency * Fix variables name * Rename variable and function name * Move xxx_options.hpp out of internal directory * Rename FromConnectionString -> CreateFromConnectionString
This commit is contained in:
parent
502d3f15a9
commit
5fc6fea9f4
@ -38,3 +38,4 @@ include(global_compile_options)
|
||||
# sub-projects
|
||||
add_subdirectory(sdk/core/azure-core)
|
||||
add_subdirectory(sdk/samples/http_client/curl) # will work only if BUILD_CURL_TRANSPORT=ON
|
||||
add_subdirectory(sdk/storage)
|
||||
|
||||
@ -9,48 +9,48 @@ jobs:
|
||||
matrix:
|
||||
Linux_x64:
|
||||
vm.image: 'ubuntu-18.04'
|
||||
vcpkg.deps: 'curl[ssl]'
|
||||
vcpkg.deps: 'curl[ssl] libxml2'
|
||||
VCPKG_DEFAULT_TRIPLET: 'x64-linux'
|
||||
Win_x86:
|
||||
vm.image: 'windows-2019'
|
||||
vcpkg.deps: 'curl[winssl]'
|
||||
vcpkg.deps: 'curl[winssl] libxml2'
|
||||
VCPKG_DEFAULT_TRIPLET: 'x86-windows-static'
|
||||
CMAKE_GENERATOR: 'Visual Studio 16 2019'
|
||||
CMAKE_GENERATOR_PLATFORM: Win32
|
||||
Win_x64:
|
||||
vm.image: 'windows-2019'
|
||||
vcpkg.deps: 'curl[winssl]'
|
||||
vcpkg.deps: 'curl[winssl] libxml2'
|
||||
VCPKG_DEFAULT_TRIPLET: 'x64-windows-static'
|
||||
CMAKE_GENERATOR: 'Visual Studio 16 2019'
|
||||
CMAKE_GENERATOR_PLATFORM: x64
|
||||
MacOS_x64:
|
||||
vm.image: 'macOS-10.14'
|
||||
vcpkg.deps: 'curl[ssl]'
|
||||
vcpkg.deps: 'curl[ssl] libxml2'
|
||||
VCPKG_DEFAULT_TRIPLET: 'x64-osx'
|
||||
|
||||
# Unit testing ON
|
||||
Linux_x64_with_unit_test:
|
||||
vm.image: 'ubuntu-18.04'
|
||||
vcpkg.deps: 'curl[ssl]'
|
||||
vcpkg.deps: 'curl[ssl] libxml2'
|
||||
VCPKG_DEFAULT_TRIPLET: 'x64-linux'
|
||||
build.args: ' -DBUILD_TESTING=ON'
|
||||
Win_x86_with_unit_test:
|
||||
vm.image: 'windows-2019'
|
||||
vcpkg.deps: 'curl[winssl]'
|
||||
vcpkg.deps: 'curl[winssl] libxml2'
|
||||
VCPKG_DEFAULT_TRIPLET: 'x86-windows-static'
|
||||
CMAKE_GENERATOR: 'Visual Studio 16 2019'
|
||||
CMAKE_GENERATOR_PLATFORM: Win32
|
||||
build.args: ' -DBUILD_TESTING=ON'
|
||||
Win_x64_with_unit_test:
|
||||
vm.image: 'windows-2019'
|
||||
vcpkg.deps: 'curl[winssl]'
|
||||
vcpkg.deps: 'curl[winssl] libxml2'
|
||||
VCPKG_DEFAULT_TRIPLET: 'x64-windows-static'
|
||||
CMAKE_GENERATOR: 'Visual Studio 16 2019'
|
||||
CMAKE_GENERATOR_PLATFORM: x64
|
||||
build.args: ' -DBUILD_TESTING=ON'
|
||||
MacOS_x64_with_unit_test:
|
||||
vm.image: 'macOS-10.14'
|
||||
vcpkg.deps: 'curl[ssl]'
|
||||
vcpkg.deps: 'curl[ssl] libxml2'
|
||||
VCPKG_DEFAULT_TRIPLET: 'x64-osx'
|
||||
build.args: ' -DBUILD_TESTING=ON'
|
||||
pool:
|
||||
|
||||
65
sdk/storage/CMakeLists.txt
Normal file
65
sdk/storage/CMakeLists.txt
Normal file
@ -0,0 +1,65 @@
|
||||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
cmake_minimum_required (VERSION 3.12)
|
||||
|
||||
project (azure-storage LANGUAGES CXX)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
|
||||
option(BUILD_STORAGE_SAMPLES "Build sample codes" ON)
|
||||
|
||||
set(AZURE_STORAGE_HEADER
|
||||
inc/common/storage_common.hpp
|
||||
inc/common/storage_credential.hpp
|
||||
inc/common/storage_url_builder.hpp
|
||||
inc/blobs/blob.hpp
|
||||
inc/blobs/blob_client.hpp
|
||||
inc/blobs/block_blob_client.hpp
|
||||
inc/blobs/blob_container_client.hpp
|
||||
inc/blobs/blob_client_options.hpp
|
||||
inc/blobs/blob_container_client_options.hpp
|
||||
inc/blobs/internal/protocol/blob_rest_client.hpp
|
||||
)
|
||||
|
||||
set(AZURE_STORAGE_SOURCE
|
||||
src/blobs/blob_client.cpp
|
||||
src/blobs/block_blob_client.cpp
|
||||
src/blobs/blob_container_client.cpp
|
||||
src/common/storage_credential.cpp
|
||||
src/common/storage_url_builder.cpp
|
||||
)
|
||||
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
||||
add_library(azure-storage ${AZURE_STORAGE_HEADER} ${AZURE_STORAGE_SOURCE})
|
||||
|
||||
find_package(LibXml2 REQUIRED)
|
||||
|
||||
target_include_directories(azure-storage PUBLIC ${LIBXML2_INCLUDE_DIR} $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/inc> $<INSTALL_INTERFACE:include/azure_storage>)
|
||||
|
||||
target_link_libraries(azure-storage azure-core ${LIBXML2_LIBRARIES})
|
||||
|
||||
if(MSVC)
|
||||
target_compile_definitions(azure-storage PRIVATE NOMINMAX)
|
||||
endif()
|
||||
|
||||
# Set version numbers centralized
|
||||
set(AZURE_STORAGE_VERSION_MAJOR 0)
|
||||
set(AZURE_STORAGE_VERSION_MINOR 1)
|
||||
set(AZURE_STORAGE_VERSION_REVISION 0)
|
||||
|
||||
#install(DIRECTORY include/ DESTINATION include)
|
||||
#install(TARGETS azure-storage
|
||||
# ARCHIVE DESTINATION lib
|
||||
# LIBRARY DESTINATION lib
|
||||
# RUNTIME DESTINATION bin)
|
||||
|
||||
if(BUILD_STORAGE_SAMPLES)
|
||||
add_subdirectory(sample)
|
||||
endif()
|
||||
|
||||
# make sure that users can consume the project as a library.
|
||||
add_library (azure::storage ALIAS azure-storage)
|
||||
8
sdk/storage/inc/blobs/blob.hpp
Normal file
8
sdk/storage/inc/blobs/blob.hpp
Normal file
@ -0,0 +1,8 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "blobs/blob_container_client.hpp"
|
||||
#include "blobs/blob_client.hpp"
|
||||
#include "blobs/block_blob_client.hpp"
|
||||
63
sdk/storage/inc/blobs/blob_client.hpp
Normal file
63
sdk/storage/inc/blobs/blob_client.hpp
Normal file
@ -0,0 +1,63 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "common/storage_url_builder.hpp"
|
||||
#include "common/storage_credential.hpp"
|
||||
#include "blob_client_options.hpp"
|
||||
#include "internal/protocol/blob_rest_client.hpp"
|
||||
|
||||
namespace Azure { namespace Storage { namespace Blobs {
|
||||
|
||||
class BlobClient {
|
||||
public:
|
||||
// connection string
|
||||
static BlobClient CreateFromConnectionString(
|
||||
const std::string& connectionString,
|
||||
const std::string& containerName,
|
||||
const std::string& blobName,
|
||||
const BlobClientOptions& options = BlobClientOptions());
|
||||
|
||||
// shared key auth
|
||||
explicit BlobClient(
|
||||
const std::string& blobUri,
|
||||
std::shared_ptr<SharedKeyCredential> credential,
|
||||
const BlobClientOptions& options = BlobClientOptions());
|
||||
|
||||
// token auth
|
||||
explicit BlobClient(
|
||||
const std::string& blobUri,
|
||||
std::shared_ptr<TokenCredential> credential,
|
||||
const BlobClientOptions& options = BlobClientOptions());
|
||||
|
||||
// anonymous/SAS/customized pipeline auth
|
||||
explicit BlobClient(
|
||||
const std::string& blobUri,
|
||||
const BlobClientOptions& options = BlobClientOptions());
|
||||
|
||||
BlobClient WithSnapshot(const std::string& snapshot);
|
||||
|
||||
BlobProperties GetProperties(
|
||||
const GetBlobPropertiesOptions& options = GetBlobPropertiesOptions());
|
||||
|
||||
BlobInfo SetHttpHeaders(const SetBlobHttpHeadersOptions& options = SetBlobHttpHeadersOptions());
|
||||
|
||||
BlobInfo SetMetadata(
|
||||
std::map<std::string, std::string> metadata,
|
||||
const SetBlobMetadataOptions& options = SetBlobMetadataOptions());
|
||||
|
||||
FlattenedDownloadProperties Download(
|
||||
const DownloadBlobOptions& options = DownloadBlobOptions());
|
||||
|
||||
BasicResponse Delete(const DeleteBlobOptions& options = DeleteBlobOptions());
|
||||
|
||||
protected:
|
||||
UrlBuilder m_blobUrl;
|
||||
std::shared_ptr<Azure::Core::Http::HttpPipeline> m_pipeline;
|
||||
};
|
||||
}}} // namespace Azure::Storage::Blobs
|
||||
89
sdk/storage/inc/blobs/blob_client_options.hpp
Normal file
89
sdk/storage/inc/blobs/blob_client_options.hpp
Normal file
@ -0,0 +1,89 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
|
||||
#include "internal/protocol/blob_rest_client.hpp"
|
||||
|
||||
namespace Azure { namespace Storage { namespace Blobs {
|
||||
|
||||
struct BlobClientOptions
|
||||
{
|
||||
std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> policies;
|
||||
};
|
||||
|
||||
struct BlockBlobClientOptions : public BlobClientOptions
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
struct GetBlobPropertiesOptions
|
||||
{
|
||||
Azure::Core::Context Context;
|
||||
};
|
||||
|
||||
struct SetBlobHttpHeadersOptions
|
||||
{
|
||||
Azure::Core::Context Context;
|
||||
std::string ContentType;
|
||||
std::string ContentEncoding;
|
||||
std::string ContentLanguage;
|
||||
std::string ContentMD5;
|
||||
std::string CacheControl;
|
||||
std::string ContentDisposition;
|
||||
};
|
||||
|
||||
struct SetBlobMetadataOptions
|
||||
{
|
||||
Azure::Core::Context Context;
|
||||
};
|
||||
|
||||
struct DownloadBlobOptions
|
||||
{
|
||||
Azure::Core::Context Context;
|
||||
uint64_t Offset = std::numeric_limits<uint64_t>::max();
|
||||
uint64_t Length = 0;
|
||||
};
|
||||
|
||||
struct DeleteBlobOptions
|
||||
{
|
||||
Azure::Core::Context Context;
|
||||
DeleteSnapshotsOption DeleteSnapshots = DeleteSnapshotsOption::None;
|
||||
};
|
||||
|
||||
struct UploadBlobOptions
|
||||
{
|
||||
Azure::Core::Context Context;
|
||||
std::string ContentMD5;
|
||||
std::string ContentCRC64;
|
||||
BlobHttpHeaders Properties;
|
||||
std::map<std::string, std::string> Metadata;
|
||||
AccessTier Tier = AccessTier::Unknown;
|
||||
};
|
||||
|
||||
struct StageBlockOptions
|
||||
{
|
||||
Azure::Core::Context Context;
|
||||
std::string ContentMD5;
|
||||
std::string ContentCRC64;
|
||||
};
|
||||
|
||||
struct CommitBlockListOptions
|
||||
{
|
||||
Azure::Core::Context Context;
|
||||
BlobHttpHeaders Properties;
|
||||
std::map<std::string, std::string> Metadata;
|
||||
AccessTier Tier = AccessTier::Unknown;
|
||||
};
|
||||
|
||||
struct GetBlockListOptions
|
||||
{
|
||||
Azure::Core::Context Context;
|
||||
BlockListTypeOption ListType = BlockListTypeOption::All;
|
||||
};
|
||||
|
||||
}}} // namespace Azure::Storage::Blobs
|
||||
64
sdk/storage/inc/blobs/blob_container_client.hpp
Normal file
64
sdk/storage/inc/blobs/blob_container_client.hpp
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
#include "blobs/blob_client.hpp"
|
||||
#include "common/storage_url_builder.hpp"
|
||||
#include "common/storage_credential.hpp"
|
||||
#include "blob_container_client_options.hpp"
|
||||
#include "internal/protocol/blob_rest_client.hpp"
|
||||
|
||||
namespace Azure { namespace Storage { namespace Blobs {
|
||||
|
||||
class BlobContainerClient {
|
||||
public:
|
||||
// connection string
|
||||
static BlobContainerClient CreateFromConnectionString(
|
||||
const std::string& connectionString,
|
||||
const std::string& containerName,
|
||||
const BlobContainerClientOptions& options = BlobContainerClientOptions());
|
||||
|
||||
// shared key auth
|
||||
explicit BlobContainerClient(
|
||||
const std::string& containerUri,
|
||||
std::shared_ptr<SharedKeyCredential> credential,
|
||||
const BlobContainerClientOptions& options = BlobContainerClientOptions());
|
||||
|
||||
// token auth
|
||||
explicit BlobContainerClient(
|
||||
const std::string& containerUri,
|
||||
std::shared_ptr<TokenCredential> credential,
|
||||
const BlobContainerClientOptions& options = BlobContainerClientOptions());
|
||||
|
||||
// anonymous/SAS/customized pipeline auth
|
||||
explicit BlobContainerClient(
|
||||
const std::string& containerUri,
|
||||
const BlobContainerClientOptions& options = BlobContainerClientOptions());
|
||||
|
||||
BlobClient GetBlobClient(const std::string& blobName);
|
||||
|
||||
BlobContainerInfo Create(
|
||||
const CreateBlobContainerOptions& options = CreateBlobContainerOptions());
|
||||
|
||||
BasicResponse Delete(const DeleteBlobContainerOptions& options = DeleteBlobContainerOptions());
|
||||
|
||||
BlobContainerProperties GetProperties(
|
||||
const GetBlobContainerPropertiesOptions& options = GetBlobContainerPropertiesOptions());
|
||||
|
||||
BlobContainerInfo SetMetadata(
|
||||
std::map<std::string, std::string> metadata,
|
||||
SetBlobContainerMetadataOptions options = SetBlobContainerMetadataOptions());
|
||||
|
||||
BlobsFlatSegment ListBlobs(const ListBlobsOptions& options = ListBlobsOptions());
|
||||
|
||||
private:
|
||||
UrlBuilder m_ContainerUri;
|
||||
std::shared_ptr<Azure::Core::Http::HttpPipeline> m_pipeline;
|
||||
};
|
||||
|
||||
}}} // namespace Azure::Storage::Blobs
|
||||
51
sdk/storage/inc/blobs/blob_container_client_options.hpp
Normal file
51
sdk/storage/inc/blobs/blob_container_client_options.hpp
Normal file
@ -0,0 +1,51 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "internal/protocol/blob_rest_client.hpp"
|
||||
|
||||
namespace Azure { namespace Storage { namespace Blobs {
|
||||
|
||||
struct BlobContainerClientOptions
|
||||
{
|
||||
std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> policies;
|
||||
};
|
||||
|
||||
struct CreateBlobContainerOptions
|
||||
{
|
||||
Azure::Core::Context Context;
|
||||
PublicAccessType AccessType = PublicAccessType::Private;
|
||||
std::map<std::string, std::string> Metadata;
|
||||
};
|
||||
|
||||
struct DeleteBlobContainerOptions
|
||||
{
|
||||
Azure::Core::Context Context;
|
||||
};
|
||||
|
||||
struct GetBlobContainerPropertiesOptions
|
||||
{
|
||||
Azure::Core::Context Context;
|
||||
};
|
||||
|
||||
struct SetBlobContainerMetadataOptions
|
||||
{
|
||||
Azure::Core::Context Context;
|
||||
};
|
||||
|
||||
struct ListBlobsOptions
|
||||
{
|
||||
Azure::Core::Context Context;
|
||||
std::string Prefix;
|
||||
std::string Delimiter;
|
||||
std::string Marker;
|
||||
int MaxResults = 0;
|
||||
std::vector<ListBlobsIncludeItem> Include;
|
||||
};
|
||||
|
||||
}}} // namespace Azure::Storage::Blobs
|
||||
65
sdk/storage/inc/blobs/block_blob_client.hpp
Normal file
65
sdk/storage/inc/blobs/block_blob_client.hpp
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "blobs/blob_client.hpp"
|
||||
#include "common/storage_credential.hpp"
|
||||
#include "blob_client_options.hpp"
|
||||
#include "internal/protocol/blob_rest_client.hpp"
|
||||
|
||||
namespace Azure { namespace Storage { namespace Blobs {
|
||||
|
||||
class BlockBlobClient : public BlobClient {
|
||||
public:
|
||||
// connection string
|
||||
static BlockBlobClient CreateFromConnectionString(
|
||||
const std::string& connectionString,
|
||||
const std::string& containerName,
|
||||
const std::string& blobName,
|
||||
const BlockBlobClientOptions& options = BlockBlobClientOptions());
|
||||
|
||||
// shared key auth
|
||||
explicit BlockBlobClient(
|
||||
const std::string& blobUri,
|
||||
std::shared_ptr<SharedKeyCredential> credential,
|
||||
const BlockBlobClientOptions& options = BlockBlobClientOptions());
|
||||
|
||||
// token auth
|
||||
explicit BlockBlobClient(
|
||||
const std::string& blobUri,
|
||||
std::shared_ptr<TokenCredential> credential,
|
||||
const BlockBlobClientOptions& options = BlockBlobClientOptions());
|
||||
|
||||
// anonymous/SAS/customized pipeline auth
|
||||
explicit BlockBlobClient(
|
||||
const std::string& blobUri,
|
||||
const BlockBlobClientOptions& options = BlockBlobClientOptions());
|
||||
|
||||
BlockBlobClient WithSnapshot(const std::string& snapshot);
|
||||
|
||||
BlobContentInfo Upload(
|
||||
// TODO: We don't have BodyStream for now.
|
||||
std::vector<uint8_t> content,
|
||||
const UploadBlobOptions& options = UploadBlobOptions());
|
||||
|
||||
BlockInfo StageBlock(
|
||||
const std::string& blockId,
|
||||
// TODO: We don't have BodyStream for now.
|
||||
std::vector<uint8_t> content,
|
||||
const StageBlockOptions& options = StageBlockOptions());
|
||||
|
||||
BlobContentInfo CommitBlockList(
|
||||
const std::vector<std::pair<BlockType, std::string>>& blockIds,
|
||||
const CommitBlockListOptions& options = CommitBlockListOptions());
|
||||
|
||||
BlobBlockListInfo GetBlockList(const GetBlockListOptions& options = GetBlockListOptions());
|
||||
|
||||
private:
|
||||
explicit BlockBlobClient(BlobClient blobClient);
|
||||
};
|
||||
|
||||
}}} // namespace Azure::Storage::Blobs
|
||||
2630
sdk/storage/inc/blobs/internal/protocol/blob_rest_client.hpp
Normal file
2630
sdk/storage/inc/blobs/internal/protocol/blob_rest_client.hpp
Normal file
File diff suppressed because it is too large
Load Diff
12
sdk/storage/inc/common/storage_common.hpp
Normal file
12
sdk/storage/inc/common/storage_common.hpp
Normal file
@ -0,0 +1,12 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Azure { namespace Storage {
|
||||
|
||||
template <class... T> void unused(T&&...)
|
||||
{
|
||||
}
|
||||
|
||||
}} // namespace Azure::Storage
|
||||
62
sdk/storage/inc/common/storage_credential.hpp
Normal file
62
sdk/storage/inc/common/storage_credential.hpp
Normal file
@ -0,0 +1,62 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
namespace Azure { namespace Storage {
|
||||
|
||||
struct TokenCredential
|
||||
{
|
||||
explicit TokenCredential(std::string token) : Token(std::move(token))
|
||||
{
|
||||
}
|
||||
|
||||
void SetToken(std::string token)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(Mutex);
|
||||
Token = std::move(token);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string GetToken()
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(Mutex);
|
||||
return Token;
|
||||
}
|
||||
std::mutex Mutex;
|
||||
std::string Token;
|
||||
};
|
||||
|
||||
struct SharedKeyCredential
|
||||
{
|
||||
explicit SharedKeyCredential(std::string accountName, std::string accountKey)
|
||||
: AccountName(std::move(accountName)), AccountKey(std::move(accountKey))
|
||||
{
|
||||
}
|
||||
|
||||
void SetAccountKey(std::string accountKey)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(Mutex);
|
||||
AccountKey = std::move(accountKey);
|
||||
}
|
||||
|
||||
std::string AccountName;
|
||||
|
||||
private:
|
||||
std::string GetAccountKey()
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(Mutex);
|
||||
return AccountKey;
|
||||
}
|
||||
|
||||
std::mutex Mutex;
|
||||
std::string AccountKey;
|
||||
};
|
||||
|
||||
std::map<std::string, std::string> ParseConnectionString(const std::string& connectionString);
|
||||
|
||||
}} // namespace Azure::Storage
|
||||
92
sdk/storage/inc/common/storage_url_builder.hpp
Normal file
92
sdk/storage/inc/common/storage_url_builder.hpp
Normal file
@ -0,0 +1,92 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
namespace Azure { namespace Storage {
|
||||
|
||||
class UrlBuilder {
|
||||
public:
|
||||
UrlBuilder()
|
||||
{
|
||||
}
|
||||
|
||||
// url must be url-encoded
|
||||
explicit UrlBuilder(const std::string& url);
|
||||
|
||||
void SetScheme(const std::string& scheme)
|
||||
{
|
||||
m_scheme = scheme;
|
||||
}
|
||||
|
||||
void SetHost(const std::string& host, bool do_encoding = false)
|
||||
{
|
||||
m_host = do_encoding ? EncodeHost(host) : host;
|
||||
}
|
||||
|
||||
void SetPort(uint16_t port)
|
||||
{
|
||||
m_port = port;
|
||||
}
|
||||
|
||||
void SetPath(const std::string& path, bool do_encoding = false)
|
||||
{
|
||||
m_path = do_encoding ? EncodePath(path) : path;
|
||||
}
|
||||
|
||||
void AppendPath(const std::string& path, bool do_encoding = false)
|
||||
{
|
||||
if (!m_path.empty() && m_path.back() != '/')
|
||||
{
|
||||
m_path += '/';
|
||||
}
|
||||
m_path += do_encoding ? EncodePath(path) : path;
|
||||
}
|
||||
|
||||
// query must be encoded
|
||||
void SetQuery(const std::string& query);
|
||||
|
||||
void AppendQuery(const std::string& key, const std::string& value, bool do_encoding = false)
|
||||
{
|
||||
if (do_encoding)
|
||||
{
|
||||
m_query[EncodeQuery(key)] = EncodeQuery(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_query[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void RemoveQuery(const std::string& key)
|
||||
{
|
||||
m_query.erase(key);
|
||||
}
|
||||
|
||||
void SetFragment(const std::string& fragment, bool do_encoding = false)
|
||||
{
|
||||
m_fragment = do_encoding ? EncodeFragment(fragment) : fragment;
|
||||
}
|
||||
|
||||
std::string to_string() const;
|
||||
|
||||
private:
|
||||
static std::string EncodeHost(const std::string& host);
|
||||
static std::string EncodePath(const std::string& path);
|
||||
static std::string EncodeQuery(const std::string& query);
|
||||
static std::string EncodeFragment(const std::string& fragment);
|
||||
static std::string EncodeImpl(const std::string& source, const std::function<bool(int)>& should_encode);
|
||||
|
||||
std::string m_scheme;
|
||||
std::string m_host;
|
||||
int m_port{-1};
|
||||
std::string m_path; // encoded
|
||||
std::map<std::string, std::string> m_query; // encoded
|
||||
std::string m_fragment;
|
||||
};
|
||||
|
||||
}} // namespace Azure::Storage
|
||||
15
sdk/storage/sample/CMakeLists.txt
Normal file
15
sdk/storage/sample/CMakeLists.txt
Normal file
@ -0,0 +1,15 @@
|
||||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
cmake_minimum_required (VERSION 3.12)
|
||||
|
||||
if (BUILD_CURL_TRANSPORT)
|
||||
|
||||
add_executable (
|
||||
azure-storage-sample
|
||||
blob_getting_started.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(azure-storage-sample PRIVATE azure-storage)
|
||||
|
||||
endif()
|
||||
20
sdk/storage/sample/blob_getting_started.cpp
Normal file
20
sdk/storage/sample/blob_getting_started.cpp
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "blobs/blob.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace Azure::Storage::Blobs;
|
||||
BlobClient blob_client("https://targettest.blob.core.windows.net/container1/file_8M");
|
||||
auto properties = blob_client.GetProperties();
|
||||
std::cout << properties.ContentLength << std::endl;
|
||||
|
||||
auto downloaded_data = blob_client.Download();
|
||||
std::cout << downloaded_data.BodyBuffer.size() << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
179
sdk/storage/src/blobs/blob_client.cpp
Normal file
179
sdk/storage/src/blobs/blob_client.cpp
Normal file
@ -0,0 +1,179 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "blobs/blob_client.hpp"
|
||||
|
||||
#include "common/storage_common.hpp"
|
||||
#include "http/curl/curl.hpp"
|
||||
|
||||
namespace Azure { namespace Storage { namespace Blobs {
|
||||
|
||||
BlobClient BlobClient::CreateFromConnectionString(
|
||||
const std::string& connectionString,
|
||||
const std::string& containerName,
|
||||
const std::string& blobName,
|
||||
const BlobClientOptions& options)
|
||||
{
|
||||
auto parsedConnectionString = ParseConnectionString(connectionString);
|
||||
|
||||
std::string accountName;
|
||||
std::string accountKey;
|
||||
std::string blobEndpoint;
|
||||
std::string EndpointSuffix;
|
||||
std::string defaultEndpointsProtocol = ".core.windows.net";
|
||||
|
||||
auto ite = parsedConnectionString.find("AccountName");
|
||||
if (ite != parsedConnectionString.end())
|
||||
{
|
||||
accountName = ite->second;
|
||||
}
|
||||
ite = parsedConnectionString.find("AccountKey");
|
||||
if (ite != parsedConnectionString.end())
|
||||
{
|
||||
accountKey = ite->second;
|
||||
}
|
||||
ite = parsedConnectionString.find("BlobEndpoint");
|
||||
if (ite != parsedConnectionString.end())
|
||||
{
|
||||
blobEndpoint = ite->second;
|
||||
}
|
||||
ite = parsedConnectionString.find("EndpointSuffix");
|
||||
if (ite != parsedConnectionString.end())
|
||||
{
|
||||
EndpointSuffix = ite->second;
|
||||
}
|
||||
ite = parsedConnectionString.find("DefaultEndpointsProtocol");
|
||||
if (ite != parsedConnectionString.end())
|
||||
{
|
||||
defaultEndpointsProtocol = ite->second;
|
||||
}
|
||||
|
||||
UrlBuilder builder;
|
||||
builder.SetScheme(defaultEndpointsProtocol);
|
||||
if (!blobEndpoint.empty())
|
||||
{
|
||||
builder = UrlBuilder(blobEndpoint);
|
||||
}
|
||||
else if (!accountName.empty())
|
||||
{
|
||||
builder.SetHost(accountName + ".blob" + defaultEndpointsProtocol);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("invalid connection string");
|
||||
}
|
||||
builder.AppendPath(containerName, true);
|
||||
builder.AppendPath(blobName, true);
|
||||
|
||||
auto credential = std::make_shared<SharedKeyCredential>(accountName, accountKey);
|
||||
|
||||
return BlobClient(builder.to_string(), credential, options);
|
||||
}
|
||||
|
||||
BlobClient::BlobClient(
|
||||
const std::string& blobUri,
|
||||
std::shared_ptr<SharedKeyCredential> credential,
|
||||
const BlobClientOptions& options)
|
||||
: BlobClient(blobUri, options)
|
||||
{
|
||||
// not implemented yet
|
||||
unused(credential, options);
|
||||
}
|
||||
|
||||
BlobClient::BlobClient(
|
||||
const std::string& blobUri,
|
||||
std::shared_ptr<TokenCredential> credential,
|
||||
const BlobClientOptions& options)
|
||||
: BlobClient(blobUri, options)
|
||||
{
|
||||
// not implemented yet
|
||||
unused(credential);
|
||||
}
|
||||
|
||||
BlobClient::BlobClient(const std::string& blobUri, const BlobClientOptions& options)
|
||||
: m_blobUrl(blobUri)
|
||||
{
|
||||
std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> policies;
|
||||
for (const auto& p : options.policies)
|
||||
{
|
||||
policies.emplace_back(std::unique_ptr<Azure::Core::Http::HttpPolicy>(p->Clone()));
|
||||
}
|
||||
policies.emplace_back(std::make_unique<Azure::Core::Http::TransportPolicy>(
|
||||
std::make_shared<Azure::Core::Http::CurlTransport>()));
|
||||
m_pipeline = std::make_shared<Azure::Core::Http::HttpPipeline>(policies);
|
||||
}
|
||||
|
||||
BlobClient BlobClient::WithSnapshot(const std::string& snapshot)
|
||||
{
|
||||
BlobClient newClient(*this);
|
||||
if (snapshot.empty())
|
||||
{
|
||||
m_blobUrl.RemoveQuery("snapshot");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_blobUrl.AppendQuery("snapshot", snapshot);
|
||||
}
|
||||
return newClient;
|
||||
}
|
||||
|
||||
FlattenedDownloadProperties BlobClient::Download(const DownloadBlobOptions& options)
|
||||
{
|
||||
BlobRestClient::Blob::DownloadOptions protocolLayerOptions;
|
||||
if (options.Offset != std::numeric_limits<decltype(options.Offset)>::max())
|
||||
{
|
||||
protocolLayerOptions.Range
|
||||
= std::make_pair(options.Offset, options.Offset + options.Length - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
protocolLayerOptions.Range
|
||||
= std::make_pair(std::numeric_limits<uint64_t>::max(), uint64_t(0));
|
||||
}
|
||||
|
||||
return BlobRestClient::Blob::Download(
|
||||
options.Context, *m_pipeline, m_blobUrl.to_string(), protocolLayerOptions);
|
||||
}
|
||||
|
||||
BlobProperties BlobClient::GetProperties(const GetBlobPropertiesOptions& options)
|
||||
{
|
||||
unused(options);
|
||||
|
||||
BlobRestClient::Blob::GetPropertiesOptions protocolLayerOptions;
|
||||
return BlobRestClient::Blob::GetProperties(
|
||||
options.Context, *m_pipeline, m_blobUrl.to_string(), protocolLayerOptions);
|
||||
}
|
||||
|
||||
BlobInfo BlobClient::SetHttpHeaders(const SetBlobHttpHeadersOptions& options)
|
||||
{
|
||||
BlobRestClient::Blob::SetHttpHeadersOptions protocolLayerOptions;
|
||||
protocolLayerOptions.ContentType = options.ContentType;
|
||||
protocolLayerOptions.ContentEncoding = options.ContentEncoding;
|
||||
protocolLayerOptions.ContentLanguage = options.ContentLanguage;
|
||||
protocolLayerOptions.ContentMD5 = options.ContentMD5;
|
||||
protocolLayerOptions.CacheControl = options.CacheControl;
|
||||
protocolLayerOptions.ContentDisposition = options.ContentDisposition;
|
||||
return BlobRestClient::Blob::SetHttpHeaders(
|
||||
options.Context, *m_pipeline, m_blobUrl.to_string(), protocolLayerOptions);
|
||||
}
|
||||
|
||||
BlobInfo BlobClient::SetMetadata(
|
||||
std::map<std::string, std::string> metadata,
|
||||
const SetBlobMetadataOptions& options)
|
||||
{
|
||||
unused(options);
|
||||
BlobRestClient::Blob::SetMetadataOptions protocolLayerOptions;
|
||||
protocolLayerOptions.Metadata = std::move(metadata);
|
||||
return BlobRestClient::Blob::SetMetadata(
|
||||
options.Context, *m_pipeline, m_blobUrl.to_string(), protocolLayerOptions);
|
||||
}
|
||||
|
||||
BasicResponse BlobClient::Delete(const DeleteBlobOptions& options)
|
||||
{
|
||||
BlobRestClient::Blob::DeleteOptions protocolLayerOptions;
|
||||
protocolLayerOptions.DeleteSnapshots = options.DeleteSnapshots;
|
||||
return BlobRestClient::Blob::Delete(
|
||||
options.Context, *m_pipeline, m_blobUrl.to_string(), protocolLayerOptions);
|
||||
}
|
||||
|
||||
}}} // namespace Azure::Storage::Blobs
|
||||
155
sdk/storage/src/blobs/blob_container_client.cpp
Normal file
155
sdk/storage/src/blobs/blob_container_client.cpp
Normal file
@ -0,0 +1,155 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "blobs/blob_container_client.hpp"
|
||||
|
||||
#include "common/storage_common.hpp"
|
||||
#include "http/curl/curl.hpp"
|
||||
|
||||
namespace Azure { namespace Storage { namespace Blobs {
|
||||
|
||||
BlobContainerClient BlobContainerClient::CreateFromConnectionString(
|
||||
const std::string& connectionString,
|
||||
const std::string& containerName,
|
||||
const BlobContainerClientOptions& options)
|
||||
{
|
||||
auto parsedConnectionString = ParseConnectionString(connectionString);
|
||||
|
||||
std::string accountName;
|
||||
std::string accountKey;
|
||||
std::string blobEndpoint;
|
||||
std::string EndpointSuffix;
|
||||
std::string defaultEndpointsProtocol = ".core.windows.net";
|
||||
|
||||
auto ite = parsedConnectionString.find("AccountName");
|
||||
if (ite != parsedConnectionString.end())
|
||||
{
|
||||
accountName = ite->second;
|
||||
}
|
||||
ite = parsedConnectionString.find("AccountKey");
|
||||
if (ite != parsedConnectionString.end())
|
||||
{
|
||||
accountKey = ite->second;
|
||||
}
|
||||
ite = parsedConnectionString.find("BlobEndpoint");
|
||||
if (ite != parsedConnectionString.end())
|
||||
{
|
||||
blobEndpoint = ite->second;
|
||||
}
|
||||
ite = parsedConnectionString.find("EndpointSuffix");
|
||||
if (ite != parsedConnectionString.end())
|
||||
{
|
||||
EndpointSuffix = ite->second;
|
||||
}
|
||||
ite = parsedConnectionString.find("DefaultEndpointsProtocol");
|
||||
if (ite != parsedConnectionString.end())
|
||||
{
|
||||
defaultEndpointsProtocol = ite->second;
|
||||
}
|
||||
|
||||
UrlBuilder builder;
|
||||
builder.SetScheme(defaultEndpointsProtocol);
|
||||
if (!blobEndpoint.empty())
|
||||
{
|
||||
builder = UrlBuilder(blobEndpoint);
|
||||
}
|
||||
else if (!accountName.empty())
|
||||
{
|
||||
builder.SetHost(accountName + ".blob" + defaultEndpointsProtocol);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("invalid connection string");
|
||||
}
|
||||
builder.AppendPath(containerName, true);
|
||||
|
||||
auto credential = std::make_shared<SharedKeyCredential>(accountName, accountKey);
|
||||
|
||||
return BlobContainerClient(builder.to_string(), credential, options);
|
||||
}
|
||||
|
||||
BlobContainerClient::BlobContainerClient(
|
||||
const std::string& containerUri,
|
||||
std::shared_ptr<SharedKeyCredential> credential,
|
||||
const BlobContainerClientOptions& options)
|
||||
: BlobContainerClient(containerUri, options)
|
||||
{
|
||||
// not implemented yet
|
||||
unused(credential);
|
||||
}
|
||||
|
||||
BlobContainerClient::BlobContainerClient(
|
||||
const std::string& containerUri,
|
||||
std::shared_ptr<TokenCredential> credential,
|
||||
const BlobContainerClientOptions& options)
|
||||
: BlobContainerClient(containerUri, options)
|
||||
{
|
||||
// not implemented yet
|
||||
unused(credential);
|
||||
}
|
||||
|
||||
BlobContainerClient::BlobContainerClient(
|
||||
const std::string& containerUri,
|
||||
const BlobContainerClientOptions& options)
|
||||
: m_ContainerUri(containerUri)
|
||||
{
|
||||
std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> policies;
|
||||
for (const auto& p : options.policies)
|
||||
{
|
||||
policies.emplace_back(std::unique_ptr<Azure::Core::Http::HttpPolicy>(p->Clone()));
|
||||
}
|
||||
policies.emplace_back(std::make_unique<Azure::Core::Http::TransportPolicy>(
|
||||
std::make_shared<Azure::Core::Http::CurlTransport>()));
|
||||
m_pipeline = std::make_shared<Azure::Core::Http::HttpPipeline>(policies);
|
||||
}
|
||||
|
||||
BlobContainerInfo BlobContainerClient::Create(const CreateBlobContainerOptions& options)
|
||||
{
|
||||
BlobRestClient::Container::CreateOptions protocolLayerOptions;
|
||||
protocolLayerOptions.AccessType = options.AccessType;
|
||||
protocolLayerOptions.Metadata = options.Metadata;
|
||||
return BlobRestClient::Container::Create(
|
||||
options.Context, *m_pipeline, m_ContainerUri.to_string(), protocolLayerOptions);
|
||||
}
|
||||
|
||||
BasicResponse BlobContainerClient::Delete(const DeleteBlobContainerOptions& options)
|
||||
{
|
||||
unused(options);
|
||||
BlobRestClient::Container::DeleteOptions protocolLayerOptions;
|
||||
return BlobRestClient::Container::Delete(
|
||||
options.Context, *m_pipeline, m_ContainerUri.to_string(), protocolLayerOptions);
|
||||
}
|
||||
|
||||
BlobContainerProperties BlobContainerClient::GetProperties(
|
||||
const GetBlobContainerPropertiesOptions& options)
|
||||
{
|
||||
unused(options);
|
||||
BlobRestClient::Container::GetPropertiesOptions protocolLayerOptions;
|
||||
return BlobRestClient::Container::GetProperties(
|
||||
options.Context, *m_pipeline, m_ContainerUri.to_string(), protocolLayerOptions);
|
||||
}
|
||||
|
||||
BlobContainerInfo BlobContainerClient::SetMetadata(
|
||||
std::map<std::string, std::string> metadata,
|
||||
SetBlobContainerMetadataOptions options)
|
||||
{
|
||||
unused(options);
|
||||
BlobRestClient::Container::SetMetadataOptions protocolLayerOptions;
|
||||
protocolLayerOptions.Metadata = metadata;
|
||||
return BlobRestClient::Container::SetMetadata(
|
||||
options.Context, *m_pipeline, m_ContainerUri.to_string(), protocolLayerOptions);
|
||||
}
|
||||
|
||||
BlobsFlatSegment BlobContainerClient::ListBlobs(const ListBlobsOptions& options)
|
||||
{
|
||||
BlobRestClient::Container::ListBlobsOptions protocolLayerOptions;
|
||||
protocolLayerOptions.Prefix = options.Prefix;
|
||||
protocolLayerOptions.Delimiter = options.Delimiter;
|
||||
protocolLayerOptions.Marker = options.Marker;
|
||||
protocolLayerOptions.MaxResults = options.MaxResults;
|
||||
protocolLayerOptions.Include = options.Include;
|
||||
return BlobRestClient::Container::ListBlobs(
|
||||
options.Context, *m_pipeline, m_ContainerUri.to_string(), protocolLayerOptions);
|
||||
}
|
||||
|
||||
}}} // namespace Azure::Storage::Blobs
|
||||
115
sdk/storage/src/blobs/block_blob_client.cpp
Normal file
115
sdk/storage/src/blobs/block_blob_client.cpp
Normal file
@ -0,0 +1,115 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "blobs/block_blob_client.hpp"
|
||||
|
||||
#include "common/storage_common.hpp"
|
||||
|
||||
namespace Azure { namespace Storage { namespace Blobs {
|
||||
|
||||
BlockBlobClient BlockBlobClient::CreateFromConnectionString(
|
||||
const std::string& connectionString,
|
||||
const std::string& containerName,
|
||||
const std::string& blobName,
|
||||
const BlockBlobClientOptions& options)
|
||||
{
|
||||
BlockBlobClient newClient(
|
||||
BlobClient::CreateFromConnectionString(connectionString, containerName, blobName, options));
|
||||
return newClient;
|
||||
}
|
||||
|
||||
BlockBlobClient::BlockBlobClient(
|
||||
const std::string& blobUri,
|
||||
std::shared_ptr<SharedKeyCredential> credential,
|
||||
const BlockBlobClientOptions& options)
|
||||
: BlobClient(blobUri, std::move(credential), options)
|
||||
{
|
||||
}
|
||||
|
||||
BlockBlobClient::BlockBlobClient(
|
||||
const std::string& blobUri,
|
||||
std::shared_ptr<TokenCredential> credential,
|
||||
const BlockBlobClientOptions& options)
|
||||
: BlobClient(blobUri, std::move(credential), options)
|
||||
{
|
||||
}
|
||||
|
||||
BlockBlobClient::BlockBlobClient(
|
||||
const std::string& blobUri,
|
||||
const BlockBlobClientOptions& options)
|
||||
: BlobClient(blobUri, options)
|
||||
{
|
||||
}
|
||||
|
||||
BlockBlobClient::BlockBlobClient(BlobClient blobClient) : BlobClient(std::move(blobClient))
|
||||
{
|
||||
}
|
||||
|
||||
BlockBlobClient BlockBlobClient::WithSnapshot(const std::string& snapshot)
|
||||
{
|
||||
BlockBlobClient newClient(*this);
|
||||
if (snapshot.empty())
|
||||
{
|
||||
newClient.m_blobUrl.RemoveQuery("snapshot");
|
||||
}
|
||||
else
|
||||
{
|
||||
newClient.m_blobUrl.AppendQuery("snapshot", snapshot);
|
||||
}
|
||||
return newClient;
|
||||
}
|
||||
|
||||
BlobContentInfo BlockBlobClient::Upload(
|
||||
// TODO: We don't have BodyStream for now.
|
||||
std::vector<uint8_t> content,
|
||||
const UploadBlobOptions& options)
|
||||
{
|
||||
BlobRestClient::BlockBlob::UploadOptions protocolLayerOptions;
|
||||
protocolLayerOptions.BodyBuffer = &content;
|
||||
protocolLayerOptions.ContentMD5 = options.ContentMD5;
|
||||
protocolLayerOptions.ContentCRC64 = options.ContentCRC64;
|
||||
protocolLayerOptions.BlobType = BlobType::BlockBlob;
|
||||
protocolLayerOptions.Properties = options.Properties;
|
||||
protocolLayerOptions.Metadata = options.Metadata;
|
||||
protocolLayerOptions.Tier = options.Tier;
|
||||
return BlobRestClient::BlockBlob::Upload(
|
||||
options.Context, *m_pipeline, m_blobUrl.to_string(), protocolLayerOptions);
|
||||
}
|
||||
|
||||
BlockInfo BlockBlobClient::StageBlock(
|
||||
const std::string& blockId,
|
||||
// TODO: We don't have BodyStream for now.
|
||||
std::vector<uint8_t> content,
|
||||
const StageBlockOptions& options)
|
||||
{
|
||||
BlobRestClient::BlockBlob::StageBlockOptions protocolLayerOptions;
|
||||
protocolLayerOptions.BodyBuffer = &content;
|
||||
protocolLayerOptions.BlockId = blockId;
|
||||
protocolLayerOptions.ContentMD5 = options.ContentMD5;
|
||||
protocolLayerOptions.ContentCRC64 = options.ContentCRC64;
|
||||
return BlobRestClient::BlockBlob::StageBlock(
|
||||
options.Context, *m_pipeline, m_blobUrl.to_string(), protocolLayerOptions);
|
||||
}
|
||||
|
||||
BlobContentInfo BlockBlobClient::CommitBlockList(
|
||||
const std::vector<std::pair<BlockType, std::string>>& blockIds,
|
||||
const CommitBlockListOptions& options)
|
||||
{
|
||||
BlobRestClient::BlockBlob::CommitBlockListOptions protocolLayerOptions;
|
||||
protocolLayerOptions.BlockList = blockIds;
|
||||
protocolLayerOptions.Properties = options.Properties;
|
||||
protocolLayerOptions.Metadata = options.Metadata;
|
||||
protocolLayerOptions.Tier = options.Tier;
|
||||
return BlobRestClient::BlockBlob::CommitBlockList(
|
||||
options.Context, *m_pipeline, m_blobUrl.to_string(), protocolLayerOptions);
|
||||
}
|
||||
|
||||
BlobBlockListInfo BlockBlobClient::GetBlockList(const GetBlockListOptions& options)
|
||||
{
|
||||
BlobRestClient::BlockBlob::GetBlockListOptions protocolLayerOptions;
|
||||
protocolLayerOptions.ListType = options.ListType;
|
||||
return BlobRestClient::BlockBlob::GetBlockList(
|
||||
options.Context, *m_pipeline, m_blobUrl.to_string(), protocolLayerOptions);
|
||||
}
|
||||
|
||||
}}} // namespace Azure::Storage::Blobs
|
||||
45
sdk/storage/src/common/storage_credential.cpp
Normal file
45
sdk/storage/src/common/storage_credential.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "common/storage_credential.hpp"
|
||||
|
||||
namespace Azure { namespace Storage {
|
||||
|
||||
std::map<std::string, std::string> ParseConnectionString(const std::string& connectionString)
|
||||
{
|
||||
std::map<std::string, std::string> result;
|
||||
|
||||
std::string::const_iterator cur = connectionString.begin();
|
||||
|
||||
while (cur != connectionString.end())
|
||||
{
|
||||
auto key_begin = cur;
|
||||
auto key_end = std::find(cur, connectionString.end(), '=');
|
||||
std::string key = std::string(key_begin, key_end);
|
||||
cur = key_end;
|
||||
if (cur != connectionString.end())
|
||||
{
|
||||
++cur;
|
||||
}
|
||||
|
||||
auto value_begin = cur;
|
||||
auto value_end = std::find(cur, connectionString.end(), ';');
|
||||
std::string value = std::string(value_begin, value_end);
|
||||
cur = value_end;
|
||||
if (cur != connectionString.end())
|
||||
{
|
||||
++cur;
|
||||
}
|
||||
|
||||
if (!key.empty() || !value.empty())
|
||||
{
|
||||
result[std::move(key)] = std::move(value);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}} // namespace Azure::Storage
|
||||
220
sdk/storage/src/common/storage_url_builder.cpp
Normal file
220
sdk/storage/src/common/storage_url_builder.cpp
Normal file
@ -0,0 +1,220 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "common/storage_url_builder.hpp"
|
||||
|
||||
#include <locale>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
||||
namespace Azure { namespace Storage {
|
||||
|
||||
UrlBuilder::UrlBuilder(const std::string& url)
|
||||
{
|
||||
std::string::const_iterator pos = url.begin();
|
||||
|
||||
const std::string schemeEnd = "://";
|
||||
auto schemeIter = url.find(schemeEnd);
|
||||
if (schemeIter != std::string::npos)
|
||||
{
|
||||
std::transform(url.begin(), url.begin() + schemeIter, std::back_inserter(m_scheme), [](char c) {
|
||||
return static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
||||
});
|
||||
pos = url.begin() + schemeIter + schemeEnd.length();
|
||||
}
|
||||
|
||||
auto hostIter = std::find_if(pos, url.end(), [](char c) { return c == '/' || c == '?' || c == ':'; });
|
||||
m_host = std::string(pos, hostIter);
|
||||
pos = hostIter;
|
||||
|
||||
if (pos != url.end() && *pos == ':')
|
||||
{
|
||||
auto port_ite = std::find_if_not(pos + 1, url.end(), [](char c) { return std::isdigit(static_cast<unsigned char>(c)); });
|
||||
m_port = std::stoi(std::string(pos + 1, port_ite));
|
||||
pos = port_ite;
|
||||
}
|
||||
|
||||
if (pos != url.end() && *pos == '/')
|
||||
{
|
||||
auto pathIter = std::find(pos + 1, url.end(), '?');
|
||||
m_path = std::string(pos + 1, pathIter);
|
||||
pos = pathIter;
|
||||
}
|
||||
|
||||
if (pos != url.end() && *pos == '?')
|
||||
{
|
||||
auto queryIter = std::find(pos + 1, url.end(), '#');
|
||||
SetQuery(std::string(pos + 1, queryIter));
|
||||
pos = queryIter;
|
||||
}
|
||||
|
||||
if (pos != url.end() && *pos == '#')
|
||||
{
|
||||
m_fragment = std::string(pos + 1, url.end());
|
||||
}
|
||||
}
|
||||
|
||||
static const char* unreserved
|
||||
= "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~";
|
||||
static const char* subdelimiters = "!$&'()*+,;=";
|
||||
|
||||
std::string UrlBuilder::EncodeHost(const std::string& host)
|
||||
{
|
||||
return EncodeImpl(host, [](int c) { return c > 127; });
|
||||
}
|
||||
|
||||
std::string UrlBuilder::EncodePath(const std::string& path)
|
||||
{
|
||||
const static std::vector<bool> shouldEncodeTable = []() {
|
||||
const std::string pathCharacters
|
||||
= std::string(unreserved) + std::string(subdelimiters) + "%/:@";
|
||||
|
||||
std::vector<bool> ret(256, true);
|
||||
for (char c : pathCharacters)
|
||||
{
|
||||
ret[c] = false;
|
||||
}
|
||||
// we also encode % and +
|
||||
ret['%'] = true;
|
||||
ret['+'] = true;
|
||||
return ret;
|
||||
}();
|
||||
|
||||
return EncodeImpl(path, [](int c) { return shouldEncodeTable[c]; });
|
||||
}
|
||||
|
||||
std::string UrlBuilder::EncodeQuery(const std::string& query)
|
||||
{
|
||||
const static std::vector<bool> shouldEncodeTable = []() {
|
||||
std::string queryCharacters = std::string(unreserved) + std::string(subdelimiters) + "%/:@?";
|
||||
|
||||
std::vector<bool> ret(256, true);
|
||||
for (char c : queryCharacters)
|
||||
{
|
||||
ret[c] = false;
|
||||
}
|
||||
// we also encode % and +
|
||||
ret['%'] = true;
|
||||
ret['+'] = true;
|
||||
// Surprisingly, '=' also needs to be encoded because Azure Storage server side is so strict.
|
||||
// We are applying this function to query key and value respectively, so this won't affect
|
||||
// that = used to separate key and query.
|
||||
ret['='] = true;
|
||||
return ret;
|
||||
}();
|
||||
|
||||
return EncodeImpl(query, [](int c) { return shouldEncodeTable[c]; });
|
||||
}
|
||||
|
||||
std::string UrlBuilder::EncodeFragment(const std::string& fragment)
|
||||
{
|
||||
const static std::vector<bool> shouldEncodeTable = []() {
|
||||
std::string queryCharacters = std::string(unreserved) + std::string(subdelimiters) + "%/:@?";
|
||||
|
||||
std::vector<bool> ret(256, true);
|
||||
for (char c : queryCharacters)
|
||||
{
|
||||
ret[c] = false;
|
||||
}
|
||||
// we also encode % and +
|
||||
ret['%'] = true;
|
||||
ret['+'] = true;
|
||||
return ret;
|
||||
}();
|
||||
|
||||
return EncodeImpl(fragment, [](int c) { return shouldEncodeTable[c]; });
|
||||
}
|
||||
|
||||
std::string UrlBuilder::EncodeImpl(
|
||||
const std::string& source,
|
||||
const std::function<bool(int)>& shouldEncode)
|
||||
{
|
||||
const char* hex = "0123456789ABCDEF";
|
||||
|
||||
std::string encoded;
|
||||
for (char c : source)
|
||||
{
|
||||
unsigned char uc = c;
|
||||
if (shouldEncode(uc))
|
||||
{
|
||||
encoded += '%';
|
||||
encoded += hex[(uc >> 4) & 0x0f];
|
||||
encoded += hex[uc & 0x0f];
|
||||
}
|
||||
else
|
||||
{
|
||||
encoded += c;
|
||||
}
|
||||
}
|
||||
return encoded;
|
||||
}
|
||||
|
||||
void UrlBuilder::SetQuery(const std::string& query)
|
||||
{
|
||||
m_query.clear();
|
||||
|
||||
std::string::const_iterator cur = query.begin();
|
||||
if (cur != query.end() && *cur == '?')
|
||||
{
|
||||
++cur;
|
||||
}
|
||||
|
||||
while (cur != query.end())
|
||||
{
|
||||
auto key_end = std::find(cur, query.end(), '=');
|
||||
std::string query_key = std::string(cur, key_end);
|
||||
|
||||
cur = key_end;
|
||||
if (cur != query.end())
|
||||
{
|
||||
++cur;
|
||||
}
|
||||
|
||||
auto value_end = std::find(cur, query.end(), '&');
|
||||
std::string query_value = std::string(cur, value_end);
|
||||
|
||||
cur = value_end;
|
||||
if (cur != query.end())
|
||||
{
|
||||
++cur;
|
||||
}
|
||||
m_query[std::move(query_key)] = std::move(query_value);
|
||||
}
|
||||
}
|
||||
|
||||
std::string UrlBuilder::to_string() const
|
||||
{
|
||||
std::string full_url;
|
||||
if (!m_scheme.empty())
|
||||
{
|
||||
|
||||
full_url += m_scheme + "://";
|
||||
}
|
||||
full_url += m_host;
|
||||
if (m_port != -1)
|
||||
{
|
||||
full_url += ":" + std::to_string(m_port);
|
||||
}
|
||||
if (!m_path.empty())
|
||||
{
|
||||
full_url += "/" + m_path;
|
||||
}
|
||||
if (!m_query.empty())
|
||||
{
|
||||
bool first_query = true;
|
||||
for (const auto& q : m_query)
|
||||
{
|
||||
full_url += first_query ? "?" : "&";
|
||||
first_query = false;
|
||||
full_url += q.first + "=" + q.second;
|
||||
}
|
||||
}
|
||||
if (!m_fragment.empty())
|
||||
{
|
||||
full_url += "#" + m_fragment;
|
||||
}
|
||||
return full_url;
|
||||
}
|
||||
|
||||
}} // namespace Azure::Storage
|
||||
Loading…
Reference in New Issue
Block a user