diff --git a/sdk/core/azure-core/CHANGELOG.md b/sdk/core/azure-core/CHANGELOG.md index d444082a5..1a4d9aca8 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 72c75b723..5e88b9d99 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 f11dc2d21..e48489636 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 84c521687..a2b55c9fe 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::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 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 28e08cf7b..dc73ddd28 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,32 @@ 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 + transform: > + $["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: > + $.schema = {"$ref": "#/definitions/SubmitBatchResult"}; ``` \ No newline at end of file