From 5ca8c90399e807a6966898b743eaa489dd9b0376 Mon Sep 17 00:00:00 2001 From: Jinming Hu Date: Fri, 22 Apr 2022 11:27:12 +0800 Subject: [PATCH 1/2] Add batch protocol layer --- sdk/core/azure-core/CHANGELOG.md | 2 + .../azure-core/inc/azure/core/http/http.hpp | 2 +- .../inc/azure/storage/blobs/rest_client.hpp | 32 +++++++++++ .../azure-storage-blobs/src/rest_client.cpp | 55 +++++++++++++++++++ .../azure-storage-blobs/swagger/README.md | 28 +++++++++- 5 files changed, 116 insertions(+), 3 deletions(-) diff --git a/sdk/core/azure-core/CHANGELOG.md b/sdk/core/azure-core/CHANGELOG.md index 7d96da393c..bc75c45086 100644 --- a/sdk/core/azure-core/CHANGELOG.md +++ b/sdk/core/azure-core/CHANGELOG.md @@ -4,6 +4,8 @@ ### Features Added +- Add `Azure::Core::Http::Request` constructor overload to support payload and non-buffered response. + ### Breaking Changes ### Bugs Fixed diff --git a/sdk/core/azure-core/inc/azure/core/http/http.hpp b/sdk/core/azure-core/inc/azure/core/http/http.hpp index 72c75b7231..5e88b9d996 100644 --- a/sdk/core/azure-core/inc/azure/core/http/http.hpp +++ b/sdk/core/azure-core/inc/azure/core/http/http.hpp @@ -209,6 +209,7 @@ namespace Azure { namespace Core { namespace Http { // previously called void StartTry(); + public: /** * @brief Construct an #Azure::Core::Http::Request. * @@ -229,7 +230,6 @@ namespace Azure { namespace Core { namespace Http { AZURE_ASSERT_MSG(bodyStream, "The bodyStream pointer cannot be null."); } - public: /** * @brief Constructs a `%Request`. * diff --git a/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/rest_client.hpp b/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/rest_client.hpp index f11dc2d21a..e484896365 100644 --- a/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/rest_client.hpp +++ b/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/rest_client.hpp @@ -807,6 +807,18 @@ namespace Azure { namespace Storage { namespace Blobs { struct RenameBlobContainerResult final { }; + /** + * @brief Response type for #Azure::Storage::Blobs::BlobContainerClient::SubmitBatch. + */ + struct SubmitBatchResult final + { + std::unique_ptr BodyStream; + /** + * The media type of the body of the response. For batch requests, this is multipart/mixed; + * boundary=batchresponse_GUID. + */ + std::string ContentType; + }; /** * @brief Response type for #Azure::Storage::Blobs::BlobContainerClient::AcquireLease. */ @@ -2971,6 +2983,16 @@ namespace Azure { namespace Storage { namespace Blobs { const Core::Url& url, const GetServiceAccountInfoOptions& options, const Core::Context& context); + struct SubmitServiceBatchOptions final + { + std::string MultipartContentType; + }; + static Response SubmitBatch( + Core::Http::_internal::HttpPipeline& pipeline, + const Core::Url& url, + Core::IO::BodyStream& requestBody, + const SubmitServiceBatchOptions& options, + const Core::Context& context); struct FindServiceBlobsByTagsOptions final { Nullable Where; @@ -3070,6 +3092,16 @@ namespace Azure { namespace Storage { namespace Blobs { const Core::Url& url, const RenameBlobContainerOptions& options, const Core::Context& context); + struct SubmitBlobContainerBatchOptions final + { + std::string MultipartContentType; + }; + static Response SubmitBatch( + Core::Http::_internal::HttpPipeline& pipeline, + const Core::Url& url, + Core::IO::BodyStream& requestBody, + const SubmitBlobContainerBatchOptions& options, + const Core::Context& context); struct AcquireBlobContainerLeaseOptions final { Nullable Duration; diff --git a/sdk/storage/azure-storage-blobs/src/rest_client.cpp b/sdk/storage/azure-storage-blobs/src/rest_client.cpp index 84c521687f..740197a92e 100644 --- a/sdk/storage/azure-storage-blobs/src/rest_client.cpp +++ b/sdk/storage/azure-storage-blobs/src/rest_client.cpp @@ -1188,6 +1188,33 @@ namespace Azure { namespace Storage { namespace Blobs { = pRawResponse->GetHeaders().at("x-ms-is-hns-enabled") == std::string("true"); return Response(std::move(response), std::move(pRawResponse)); } + Response ServiceClient::SubmitBatch( + Core::Http::_internal::HttpPipeline& pipeline, + const Core::Url& url, + Core::IO::BodyStream& requestBody, + const SubmitServiceBatchOptions& options, + const Core::Context& context) + { + auto request = Core::Http::Request(Core::Http::HttpMethod::Post, url, &requestBody, false); + request.GetUrl().AppendQueryParameter("comp", "batch"); + request.SetHeader("Content-Length", std::to_string(requestBody.Length())); + if (!options.MultipartContentType.empty()) + { + request.SetHeader("Content-Type", options.MultipartContentType); + } + request.SetHeader("x-ms-version", "2020-08-04"); + auto pRawResponse = pipeline.Send(request, context); + auto httpStatusCode = pRawResponse->GetStatusCode(); + if (httpStatusCode != Core::Http::HttpStatusCode::Ok) + { + throw StorageException::CreateFromResponse(std::move(pRawResponse)); + } + Models::_detail::SubmitBatchResult response; + response.BodyStream = pRawResponse->ExtractBodyStream(); + response.ContentType = pRawResponse->GetHeaders().at("Content-Type"); + return Response( + std::move(response), std::move(pRawResponse)); + } Response ServiceClient::FindBlobsByTags( Core::Http::_internal::HttpPipeline& pipeline, const Core::Url& url, @@ -1769,6 +1796,34 @@ namespace Azure { namespace Storage { namespace Blobs { return Response( std::move(response), std::move(pRawResponse)); } + Response BlobContainerClient::SubmitBatch( + Core::Http::_internal::HttpPipeline& pipeline, + const Core::Url& url, + Core::IO::BodyStream& requestBody, + const SubmitBlobContainerBatchOptions& options, + const Core::Context& context) + { + auto request = Core::Http::Request(Core::Http::HttpMethod::Post, url, &requestBody, false); + request.GetUrl().AppendQueryParameter("restype", "container"); + request.GetUrl().AppendQueryParameter("comp", "batch"); + request.SetHeader("Content-Length", std::to_string(requestBody.Length())); + if (!options.MultipartContentType.empty()) + { + request.SetHeader("Content-Type", options.MultipartContentType); + } + request.SetHeader("x-ms-version", "2020-08-04"); + auto pRawResponse = pipeline.Send(request, context); + auto httpStatusCode = pRawResponse->GetStatusCode(); + if (httpStatusCode != Core::Http::HttpStatusCode::Accepted) + { + throw StorageException::CreateFromResponse(std::move(pRawResponse)); + } + Models::_detail::SubmitBatchResult response; + response.BodyStream = pRawResponse->ExtractBodyStream(); + response.ContentType = pRawResponse->GetHeaders().at("Content-Type"); + return Response( + std::move(response), std::move(pRawResponse)); + } Response BlobContainerClient::AcquireLease( Core::Http::_internal::HttpPipeline& pipeline, const Core::Url& url, diff --git a/sdk/storage/azure-storage-blobs/swagger/README.md b/sdk/storage/azure-storage-blobs/swagger/README.md index 28e08cf7bc..15637745ea 100644 --- a/sdk/storage/azure-storage-blobs/swagger/README.md +++ b/sdk/storage/azure-storage-blobs/swagger/README.md @@ -72,8 +72,6 @@ directive: transform: > delete $["/{containerName}?restype=account&comp=properties"]; delete $["/{containerName}/{blob}?restype=account&comp=properties"]; - delete $["/?comp=batch"]; - delete $["/{containerName}?restype=container&comp=batch"]; delete $["/{filesystem}/{path}?action=setAccessControl&blob"]; delete $["/{filesystem}/{path}?action=getAccessControl&blob"]; delete $["/{filesystem}/{path}?FileRename"]; @@ -1574,4 +1572,30 @@ directive: where: $["x-ms-paths"]["/{containerName}/{blob}?comp=legalhold"].put.responses["200"].headers transform: > $["x-ms-legal-hold"]["x-ms-client-name"] = "HasLegalHold"; +``` + + +### SubmitBatch + +```yaml +directive: + - from: swagger-document + where: $.definitions + transform: > + $.SubmitBatchResult = { + "type": "object", + "x-ms-sealed": false, + "x-namespace": "_detail", + "properties": { + "BodyStream": {"type": "object", "format": "file"} + } + }; + - from: swagger-document + where: $["x-ms-paths"]["/?comp=batch"].post.responses["200"] + transform: > + $.schema = {"$ref": "#/definitions/SubmitBatchResult"}; + - from: swagger-document + where: $["x-ms-paths"]["/{containerName}?restype=container&comp=batch"].post.responses["202"] + transform: > + $.schema = {"$ref": "#/definitions/SubmitBatchResult"}; ``` \ No newline at end of file From 169556b7ddef8428389d5abe95adf458ab8fbdb9 Mon Sep 17 00:00:00 2001 From: Jinming Hu Date: Sat, 23 Apr 2022 18:43:11 +0800 Subject: [PATCH 2/2] f --- sdk/storage/azure-storage-blobs/src/rest_client.cpp | 2 +- sdk/storage/azure-storage-blobs/swagger/README.md | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/sdk/storage/azure-storage-blobs/src/rest_client.cpp b/sdk/storage/azure-storage-blobs/src/rest_client.cpp index 740197a92e..a2b55c9fef 100644 --- a/sdk/storage/azure-storage-blobs/src/rest_client.cpp +++ b/sdk/storage/azure-storage-blobs/src/rest_client.cpp @@ -1205,7 +1205,7 @@ namespace Azure { namespace Storage { namespace Blobs { request.SetHeader("x-ms-version", "2020-08-04"); auto pRawResponse = pipeline.Send(request, context); auto httpStatusCode = pRawResponse->GetStatusCode(); - if (httpStatusCode != Core::Http::HttpStatusCode::Ok) + if (httpStatusCode != Core::Http::HttpStatusCode::Accepted) { throw StorageException::CreateFromResponse(std::move(pRawResponse)); } diff --git a/sdk/storage/azure-storage-blobs/swagger/README.md b/sdk/storage/azure-storage-blobs/swagger/README.md index 15637745ea..dc73ddd28e 100644 --- a/sdk/storage/azure-storage-blobs/swagger/README.md +++ b/sdk/storage/azure-storage-blobs/swagger/README.md @@ -1591,9 +1591,11 @@ directive: } }; - from: swagger-document - where: $["x-ms-paths"]["/?comp=batch"].post.responses["200"] + where: $["x-ms-paths"]["/?comp=batch"].post.responses transform: > - $.schema = {"$ref": "#/definitions/SubmitBatchResult"}; + $["202"] = $["200"]; + delete $["200"]; + $["202"].schema = {"$ref": "#/definitions/SubmitBatchResult"}; - from: swagger-document where: $["x-ms-paths"]["/{containerName}?restype=container&comp=batch"].post.responses["202"] transform: >