diff --git a/sdk/core/azure-core/inc/http/http.hpp b/sdk/core/azure-core/inc/http/http.hpp index 27b1705a0..84d4803ce 100644 --- a/sdk/core/azure-core/inc/http/http.hpp +++ b/sdk/core/azure-core/inc/http/http.hpp @@ -220,6 +220,7 @@ namespace Azure { namespace Core { namespace Http { // flag to know where to insert header bool m_retryModeEnabled; + bool m_isDownloadViaStream; // returns left map plus all items in right // when duplicates, left items are preferred @@ -234,15 +235,30 @@ namespace Azure { namespace Core { namespace Http { std::string GetQueryString() const; public: - explicit Request(HttpMethod httpMethod, std::string const& url, BodyStream* bodyStream) + explicit Request( + HttpMethod httpMethod, + std::string const& url, + BodyStream* bodyStream, + bool downloadViaStream) : m_method(std::move(httpMethod)), m_url(url), m_bodyStream(bodyStream), - m_retryModeEnabled(false) + m_retryModeEnabled(false), m_isDownloadViaStream(downloadViaStream) + { + } + + explicit Request(HttpMethod httpMethod, std::string const& url, BodyStream* bodyStream) + : Request(httpMethod, url, bodyStream, false) + { + } + + // Typically used for GET with no request body that can return bodyStream + explicit Request(HttpMethod httpMethod, std::string const& url, bool downloadViaStream) + : Request(httpMethod, url, NullBodyStream::GetNullBodyStream(), downloadViaStream) { } // Typically used for GET with no request body. explicit Request(HttpMethod httpMethod, std::string const& url) - : Request(httpMethod, url, NullBodyStream::GetNullBodyStream()) + : Request(httpMethod, url, NullBodyStream::GetNullBodyStream(), false) { } @@ -259,6 +275,7 @@ namespace Azure { namespace Core { namespace Http { std::map GetHeaders() const; BodyStream* GetBodyStream() { return this->m_bodyStream; } std::string GetHTTPMessagePreBody() const; + bool IsDownloadViaStream() { return m_isDownloadViaStream; } }; /* diff --git a/sdk/core/azure-core/inc/http/policy.hpp b/sdk/core/azure-core/inc/http/policy.hpp index 16976bee6..33611c8b8 100644 --- a/sdk/core/azure-core/inc/http/policy.hpp +++ b/sdk/core/azure-core/inc/http/policy.hpp @@ -13,10 +13,6 @@ namespace Azure { namespace Core { namespace Http { - namespace Details { - constexpr static const char* c_GetStreamForBody = "no-download"; - } // namespace Details - class NextHttpPolicy; class HttpPolicy { @@ -58,19 +54,6 @@ namespace Azure { namespace Core { namespace Http { std::shared_ptr m_transport; public: - /** - * @brief Creates a context with the required configuration to avoid transport policy to - * download a body payload from http response and return a BodyStream to read from the wire - * instead. - * - * @param ctx parent context to be used to create a context with specific settings - * @return Azure::Core::Context - */ - static Azure::Core::Context DownloadViaStream(Azure::Core::Context& ctx) - { - return ctx.WithValue(Details::c_GetStreamForBody, true); - } - explicit TransportPolicy(std::shared_ptr transport) : m_transport(std::move(transport)) { diff --git a/sdk/core/azure-core/src/credentials/credentials.cpp b/sdk/core/azure-core/src/credentials/credentials.cpp index 81e1ebf4a..3e97fba7d 100644 --- a/sdk/core/azure-core/src/credentials/credentials.cpp +++ b/sdk/core/azure-core/src/credentials/credentials.cpp @@ -103,16 +103,8 @@ AccessToken ClientSecretCredential::GetToken( throw AuthenticationException(errorMsg.str()); } - auto const responseStream = response->GetBodyStream(); - auto const responseStreamLength = responseStream->Length(); - - std::string responseBody(static_cast(responseStreamLength), 0); - - Azure::Core::Http::BodyStream::ReadToCount( - context, - *responseStream, - static_cast(static_cast(&responseBody[0])), - responseStreamLength); + auto const responseBodyVector = response->GetBody(); + std::string responseBody(responseBodyVector.begin(), responseBodyVector.end()); // TODO: use JSON parser. auto const responseBodySize = responseBody.size(); diff --git a/sdk/core/azure-core/src/http/transport_policy.cpp b/sdk/core/azure-core/src/http/transport_policy.cpp index 641cca1ec..bf79cda4d 100644 --- a/sdk/core/azure-core/src/http/transport_policy.cpp +++ b/sdk/core/azure-core/src/http/transport_policy.cpp @@ -16,7 +16,7 @@ std::unique_ptr TransportPolicy::Send( * Call the transport and return */ auto response = m_transport->Send(ctx, request); - if (ctx.HasKey(Details::c_GetStreamForBody)) + if (request. IsDownloadViaStream()) { // special case to return a response with BodyStream to read directly from socket return response; } diff --git a/sdk/core/azure-core/test/ut/transport_adapter.cpp b/sdk/core/azure-core/test/ut/transport_adapter.cpp index 973a707a2..138bf3164 100644 --- a/sdk/core/azure-core/test/ut/transport_adapter.cpp +++ b/sdk/core/azure-core/test/ut/transport_adapter.cpp @@ -3,6 +3,7 @@ #include "transport_adapter.hpp" #include +#include #include #include @@ -24,6 +25,16 @@ namespace Azure { namespace Core { namespace Test { Azure::Core::Http::HttpPipeline TransportAdapter::pipeline(policies); Azure::Core::Context TransportAdapter::context = Azure::Core::GetApplicationContext(); + static void checkResponseCode(Azure::Core::Http::HttpStatusCode code) + { + if (code != Azure::Core::Http::HttpStatusCode::Ok) + { + std::cout << static_cast::type>(code); + return; + } + EXPECT_TRUE(code == Azure::Core::Http::HttpStatusCode::Ok); + } + void TransportAdapter::CheckBodyFromBuffer( Azure::Core::Http::RawResponse& response, int64_t size, @@ -77,14 +88,14 @@ namespace Azure { namespace Core { namespace Test { auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host); auto response = pipeline.Send(context, request); - EXPECT_TRUE(response->GetStatusCode() == Azure::Core::Http::HttpStatusCode::Ok); + checkResponseCode(response->GetStatusCode()); auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length")); CheckBodyFromBuffer(*response, expectedResponseBodySize); // Add a header and send again. RawResponse should return that header in the body request.AddHeader("123", "456"); response = pipeline.Send(context, request); - EXPECT_TRUE(response->GetStatusCode() == Azure::Core::Http::HttpStatusCode::Ok); + checkResponseCode(response->GetStatusCode()); // header length is 6 (data) + 13 (formating) -> ` "123": "456"\r\n,` CheckBodyFromBuffer(*response, expectedResponseBodySize + 6 + 13); } @@ -100,7 +111,7 @@ namespace Azure { namespace Core { namespace Test { { auto response = pipeline.Send(context, request); auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length")); - EXPECT_TRUE(response->GetStatusCode() == Azure::Core::Http::HttpStatusCode::Ok); + checkResponseCode(response->GetStatusCode()); CheckBodyFromBuffer(*response, expectedResponseBodySize); } } @@ -112,7 +123,7 @@ namespace Azure { namespace Core { namespace Test { auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Head, host); auto response = pipeline.Send(context, request); - EXPECT_TRUE(response->GetStatusCode() == Azure::Core::Http::HttpStatusCode::Ok); + checkResponseCode(response->GetStatusCode()); CheckBodyFromBuffer(*response, expectedResponseBodySize); // Check content-length header to be greater than 0 @@ -124,13 +135,13 @@ namespace Azure { namespace Core { namespace Test { { std::string host("http://httpbin.org/put"); - // PUT 1MB - auto requestBodyVector = std::vector(1024 * 1024, 'x'); + // PUT 1K + auto requestBodyVector = std::vector(1024, 'x'); auto bodyRequest = Azure::Core::Http::MemoryBodyStream(requestBodyVector); auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, host, &bodyRequest); auto response = pipeline.Send(context, request); - EXPECT_TRUE(response->GetStatusCode() == Azure::Core::Http::HttpStatusCode::Ok); + checkResponseCode(response->GetStatusCode()); auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length")); CheckBodyFromBuffer(*response, expectedResponseBodySize); @@ -140,13 +151,13 @@ namespace Azure { namespace Core { namespace Test { { std::string host("http://httpbin.org/delete"); - // Delete with 1MB payload - auto requestBodyVector = std::vector(1024 * 1024, 'x'); + // Delete with 1k payload + auto requestBodyVector = std::vector(1024, 'x'); auto bodyRequest = Azure::Core::Http::MemoryBodyStream(requestBodyVector); auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Delete, host, &bodyRequest); auto response = pipeline.Send(context, request); - EXPECT_TRUE(response->GetStatusCode() == Azure::Core::Http::HttpStatusCode::Ok); + checkResponseCode(response->GetStatusCode()); auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length")); CheckBodyFromBuffer(*response, expectedResponseBodySize); @@ -162,7 +173,7 @@ namespace Azure { namespace Core { namespace Test { auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Patch, host, &bodyRequest); auto response = pipeline.Send(context, request); - EXPECT_TRUE(response->GetStatusCode() == Azure::Core::Http::HttpStatusCode::Ok); + checkResponseCode(response->GetStatusCode()); auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length")); CheckBodyFromBuffer(*response, expectedResponseBodySize); @@ -182,7 +193,7 @@ namespace Azure { namespace Core { namespace Test { auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host); auto response = pipeline.Send(context, request); - EXPECT_TRUE(response->GetStatusCode() == Azure::Core::Http::HttpStatusCode::Ok); + checkResponseCode(response->GetStatusCode()); CheckBodyFromBuffer(*response, expectedResponseBodySize, expectedChunkResponse); } @@ -194,17 +205,16 @@ namespace Azure { namespace Core { namespace Test { { std::string host("http://httpbin.org/get"); - auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host); - auto ctx = Azure::Core::Http::TransportPolicy::DownloadViaStream(context); - auto response = pipeline.Send(ctx, request); - EXPECT_TRUE(response->GetStatusCode() == Azure::Core::Http::HttpStatusCode::Ok); + auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host, true); + auto response = pipeline.Send(context, request); + checkResponseCode(response->GetStatusCode()); auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length")); CheckBodyFromStream(*response, expectedResponseBodySize); // Add a header and send again. Response should return that header in the body request.AddHeader("123", "456"); - response = pipeline.Send(ctx, request); - EXPECT_TRUE(response->GetStatusCode() == Azure::Core::Http::HttpStatusCode::Ok); + response = pipeline.Send(context, request); + checkResponseCode(response->GetStatusCode()); // header length is 6 (data) + 13 (formating) -> ` "123": "456"\r\n,` CheckBodyFromStream(*response, expectedResponseBodySize + 6 + 13); } @@ -213,15 +223,14 @@ namespace Azure { namespace Core { namespace Test { { std::string host("http://httpbin.org/get"); - auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host); + auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host, true); // loop sending request for (auto i = 0; i < 20; i++) { - auto ctx = Azure::Core::Http::TransportPolicy::DownloadViaStream(context); - auto response = pipeline.Send(ctx, request); + auto response = pipeline.Send(context, request); auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length")); - EXPECT_TRUE(response->GetStatusCode() == Azure::Core::Http::HttpStatusCode::Ok); + checkResponseCode(response->GetStatusCode()); CheckBodyFromStream(*response, expectedResponseBodySize); } } @@ -231,10 +240,9 @@ namespace Azure { namespace Core { namespace Test { std::string host("http://httpbin.org/get"); auto expectedResponseBodySize = 0; - auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Head, host); - auto ctx = Azure::Core::Http::TransportPolicy::DownloadViaStream(context); - auto response = pipeline.Send(ctx, request); - EXPECT_TRUE(response->GetStatusCode() == Azure::Core::Http::HttpStatusCode::Ok); + auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Head, host, true); + auto response = pipeline.Send(context, request); + checkResponseCode(response->GetStatusCode()); CheckBodyFromStream(*response, expectedResponseBodySize); // Check content-length header to be greater than 0 @@ -246,14 +254,13 @@ namespace Azure { namespace Core { namespace Test { { std::string host("http://httpbin.org/put"); - // PUT 1MB - auto requestBodyVector = std::vector(1024 * 1024, 'x'); + // PUT 1k + auto requestBodyVector = std::vector(1024, 'x'); auto bodyRequest = Azure::Core::Http::MemoryBodyStream(requestBodyVector); auto request - = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, host, &bodyRequest); - auto ctx = Azure::Core::Http::TransportPolicy::DownloadViaStream(context); - auto response = pipeline.Send(ctx, request); - EXPECT_TRUE(response->GetStatusCode() == Azure::Core::Http::HttpStatusCode::Ok); + = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, host, &bodyRequest, true); + auto response = pipeline.Send(context, request); + checkResponseCode(response->GetStatusCode()); auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length")); CheckBodyFromStream(*response, expectedResponseBodySize); @@ -263,14 +270,13 @@ namespace Azure { namespace Core { namespace Test { { std::string host("http://httpbin.org/delete"); - // Delete with 1MB payload - auto requestBodyVector = std::vector(1024 * 1024, 'x'); + // Delete with 1k payload + auto requestBodyVector = std::vector(1024, 'x'); auto bodyRequest = Azure::Core::Http::MemoryBodyStream(requestBodyVector); - auto request - = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Delete, host, &bodyRequest); - auto ctx = Azure::Core::Http::TransportPolicy::DownloadViaStream(context); - auto response = pipeline.Send(ctx, request); - EXPECT_TRUE(response->GetStatusCode() == Azure::Core::Http::HttpStatusCode::Ok); + auto request = Azure::Core::Http::Request( + Azure::Core::Http::HttpMethod::Delete, host, &bodyRequest, true); + auto response = pipeline.Send(context, request); + checkResponseCode(response->GetStatusCode()); auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length")); CheckBodyFromStream(*response, expectedResponseBodySize); @@ -283,11 +289,10 @@ namespace Azure { namespace Core { namespace Test { // Patch with 1kb payload auto requestBodyVector = std::vector(1024, 'x'); auto bodyRequest = Azure::Core::Http::MemoryBodyStream(requestBodyVector); - auto request - = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Patch, host, &bodyRequest); - auto ctx = Azure::Core::Http::TransportPolicy::DownloadViaStream(context); - auto response = pipeline.Send(ctx, request); - EXPECT_TRUE(response->GetStatusCode() == Azure::Core::Http::HttpStatusCode::Ok); + auto request = Azure::Core::Http::Request( + Azure::Core::Http::HttpMethod::Patch, host, &bodyRequest, true); + auto response = pipeline.Send(context, request); + checkResponseCode(response->GetStatusCode()); auto expectedResponseBodySize = std::stoull(response->GetHeaders().at("content-length")); CheckBodyFromStream(*response, expectedResponseBodySize); @@ -304,11 +309,10 @@ namespace Azure { namespace Core { namespace Test { "response after 1 second. The server should not close the stream before all chunks are " "sent to a client."); - auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host); - auto ctx = Azure::Core::Http::TransportPolicy::DownloadViaStream(context); - auto response = pipeline.Send(ctx, request); + auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host, true); + auto response = pipeline.Send(context, request); - EXPECT_TRUE(response->GetStatusCode() == Azure::Core::Http::HttpStatusCode::Ok); + checkResponseCode(response->GetStatusCode()); CheckBodyFromStream(*response, expectedResponseBodySize, expectedChunkResponse); } @@ -317,7 +321,7 @@ namespace Azure { namespace Core { namespace Test { std::string host("http://httpbin.org/get"); std::string expectedType("This is the Response Type"); - auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host); + auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, host, false); auto response = pipeline.Send(context, request); Azure::Core::Response responseT(expectedType, std::move(response));