[Core] Refactor RequestFailedException with Http information (#2026)
* KeyVault Exception
This commit is contained in:
parent
a7fdea42e6
commit
dfdaf25223
@ -49,7 +49,9 @@ set(
|
||||
inc/azure/core/credentials/token_credential_options.hpp
|
||||
inc/azure/core/cryptography/hash.hpp
|
||||
inc/azure/core/diagnostics/logger.hpp
|
||||
inc/azure/core/http/http_status_code.hpp
|
||||
inc/azure/core/http/http.hpp
|
||||
inc/azure/core/http/raw_response.hpp
|
||||
inc/azure/core/http/policies/policy.hpp
|
||||
inc/azure/core/http/transport.hpp
|
||||
inc/azure/core/internal/client_options.hpp
|
||||
@ -104,6 +106,7 @@ set(
|
||||
src/datetime.cpp
|
||||
src/environment_log_level_listener.cpp
|
||||
src/environment_log_level_listener_private.hpp
|
||||
src/exception.cpp
|
||||
src/logger.cpp
|
||||
src/operation_status.cpp
|
||||
src/strings.cpp
|
||||
|
||||
@ -8,7 +8,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "azure/core/http/http_status_code.hpp"
|
||||
#include "azure/core/http/raw_response.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Azure { namespace Core {
|
||||
/**
|
||||
@ -17,11 +23,74 @@ namespace Azure { namespace Core {
|
||||
*/
|
||||
class RequestFailedException : public std::runtime_error {
|
||||
public:
|
||||
/**
|
||||
* @brief The Http response code.
|
||||
*
|
||||
*/
|
||||
Azure::Core::Http::HttpStatusCode StatusCode = Azure::Core::Http::HttpStatusCode::None;
|
||||
|
||||
/**
|
||||
* @brief The Http reason phrase from the response.
|
||||
*
|
||||
*/
|
||||
std::string ReasonPhrase;
|
||||
|
||||
/**
|
||||
* @brief The client request header from the Http response.
|
||||
*
|
||||
*/
|
||||
std::string ClientRequestId;
|
||||
|
||||
/**
|
||||
* @brief The request id header from the Http response.
|
||||
*
|
||||
*/
|
||||
std::string RequestId;
|
||||
|
||||
/**
|
||||
* @brief The error code from service returned in the Http response.
|
||||
*
|
||||
*/
|
||||
std::string ErrorCode;
|
||||
|
||||
/**
|
||||
* @brief The error message from the service returned in the Http response.
|
||||
*
|
||||
*/
|
||||
std::string Message;
|
||||
|
||||
/**
|
||||
* @brief The entire Http raw response.
|
||||
*
|
||||
*/
|
||||
std::unique_ptr<Azure::Core::Http::RawResponse> RawResponse;
|
||||
|
||||
/**
|
||||
* @brief Construct a new Request Failed Exception object.
|
||||
*
|
||||
* @remark An Exception without an Http raw response represent an exception happend
|
||||
* before sending the request to the server. There is no response yet.
|
||||
*
|
||||
* @param message The error description.
|
||||
*/
|
||||
explicit RequestFailedException(std::string const& message) : std::runtime_error(message) {}
|
||||
explicit RequestFailedException(std::string const& message)
|
||||
: std::runtime_error(message), Message(message)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a new Request Failed Exception object with an Http raw response.
|
||||
*
|
||||
* @remark The Http raw response is parsed to get the always expected information for all Azure
|
||||
* Services like the status code, reason phrase and some headers like the request id. A concrete
|
||||
* Service exception which derives from this exception uses its constructor to parse the Http
|
||||
* raw response and assing the service specific values to the exception.
|
||||
*
|
||||
* @param message The error description.
|
||||
* @param rawResponse The Http raw response from the service.
|
||||
*/
|
||||
explicit RequestFailedException(
|
||||
const std::string& message,
|
||||
std::unique_ptr<Azure::Core::Http::RawResponse> rawResponse);
|
||||
};
|
||||
}} // namespace Azure::Core
|
||||
|
||||
@ -9,7 +9,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "azure/core/case_insensitive_containers.hpp"
|
||||
#include "azure/core/dll_import_export.hpp"
|
||||
#include "azure/core/exception.hpp"
|
||||
#include "azure/core/http/http_status_code.hpp"
|
||||
#include "azure/core/http/raw_response.hpp"
|
||||
#include "azure/core/internal/contract.hpp"
|
||||
#include "azure/core/io/body_stream.hpp"
|
||||
#include "azure/core/nullable.hpp"
|
||||
@ -58,86 +61,6 @@ namespace Azure { namespace Core { namespace Http {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Defines the possible HTTP status codes.
|
||||
*/
|
||||
enum class HttpStatusCode
|
||||
{
|
||||
/// No HTTP status code.
|
||||
None = 0,
|
||||
|
||||
// === 1xx (information) Status Codes: ===
|
||||
Continue = 100, ///< HTTP 100 Continue.
|
||||
SwitchingProtocols = 101, ///< HTTP 101 Switching Protocols.
|
||||
Processing = 102, ///< HTTP 102 Processing.
|
||||
EarlyHints = 103, ///< HTTP 103 Early Hints.
|
||||
|
||||
// === 2xx (successful) Status Codes: ===
|
||||
Ok = 200, ///< HTTP 200 OK.
|
||||
Created = 201, ///< HTTP 201 Created.
|
||||
Accepted = 202, ///< HTTP 202 Accepted.
|
||||
NonAuthoritativeInformation = 203, ///< HTTP 203 Non-Authoritative Information.
|
||||
NoContent = 204, ///< HTTP 204 No Content.
|
||||
ResetContent = 205, ///< HTTP 205 Rest Content.
|
||||
PartialContent = 206, ///< HTTP 206 Partial Content.
|
||||
MultiStatus = 207, ///< HTTP 207 Multi-Status.
|
||||
AlreadyReported = 208, ///< HTTP 208 Already Reported.
|
||||
IMUsed = 226, ///< HTTP 226 IM Used.
|
||||
|
||||
// === 3xx (redirection) Status Codes: ===
|
||||
MultipleChoices = 300, ///< HTTP 300 Multiple Choices.
|
||||
MovedPermanently = 301, ///< HTTP 301 Moved Permanently.
|
||||
Found = 302, ///< HTTP 302 Found.
|
||||
SeeOther = 303, ///< HTTP 303 See Other.
|
||||
NotModified = 304, ///< HTTP 304 Not Modified.
|
||||
UseProxy = 305, ///< HTTP 305 Use Proxy.
|
||||
TemporaryRedirect = 307, ///< HTTP 307 Temporary Redirect.
|
||||
PermanentRedirect = 308, ///< HTTP 308 Permanent Redirect.
|
||||
|
||||
// === 4xx (client error) Status Codes: ===
|
||||
BadRequest = 400, ///< HTTP 400 Bad Request.
|
||||
Unauthorized = 401, ///< HTTP 401 Unauthorized.
|
||||
PaymentRequired = 402, ///< HTTP 402 Payment Required.
|
||||
Forbidden = 403, ///< HTTP 403 Forbidden.
|
||||
NotFound = 404, ///< HTTP 404 Not Found.
|
||||
MethodNotAllowed = 405, ///< HTTP 405 Method Not Allowed.
|
||||
NotAcceptable = 406, ///< HTTP 406 Not Acceptable.
|
||||
ProxyAuthenticationRequired = 407, ///< HTTP 407 Proxy Authentication Required.
|
||||
RequestTimeout = 408, ///< HTTP 408 Request Timeout.
|
||||
Conflict = 409, ///< HTTP 409 Conflict.
|
||||
Gone = 410, ///< HTTP 410 Gone.
|
||||
LengthRequired = 411, ///< HTTP 411 Length Required.
|
||||
PreconditionFailed = 412, ///< HTTP 412 Precondition Failed.
|
||||
PayloadTooLarge = 413, ///< HTTP 413 Payload Too Large.
|
||||
UriTooLong = 414, ///< HTTP 414 URI Too Long.
|
||||
UnsupportedMediaType = 415, ///< HTTP 415 Unsupported Media Type.
|
||||
RangeNotSatisfiable = 416, ///< HTTP 416 Range Not Satisfiable.
|
||||
ExpectationFailed = 417, ///< HTTP 417 Expectation Failed.
|
||||
MisdirectedRequest = 421, ///< HTTP 421 Misdirected Request.
|
||||
UnprocessableEntity = 422, ///< HTTP 422 Unprocessable Entity.
|
||||
Locked = 423, ///< HTTP 423 Locked.
|
||||
FailedDependency = 424, ///< HTTP 424 Failed Dependency.
|
||||
TooEarly = 425, ///< HTTP 425 Too Early.
|
||||
UpgradeRequired = 426, ///< HTTP 426 Upgrade Required.
|
||||
PreconditionRequired = 428, ///< HTTP 428 Precondition Required.
|
||||
TooManyRequests = 429, ///< HTTP 429 Too Many Requests.
|
||||
RequestHeaderFieldsTooLarge = 431, ///< HTTP 431 Request Header Fields Too Large.
|
||||
UnavailableForLegalReasons = 451, ///< HTTP 451 Unavailable For Legal Reasons.
|
||||
|
||||
// === 5xx (server error) Status Codes: ===
|
||||
InternalServerError = 500, ///< HTTP 500 Internal Server Error.
|
||||
NotImplemented = 501, ///< HTTP 501 Not Implemented.
|
||||
BadGateway = 502, ///< HTTP 502 Bad Gateway.
|
||||
ServiceUnavailable = 503, ///< HTTP 503 Unavailable.
|
||||
GatewayTimeout = 504, ///< HTTP 504 Gateway Timeout.
|
||||
HttpVersionNotSupported = 505, ///< HTTP 505 HTTP Version Not Supported.
|
||||
VariantAlsoNegotiates = 506, ///< HTTP 506 Variant Also Negotiates.
|
||||
InsufficientStorage = 507, ///< HTTP 507 Insufficient Storage.
|
||||
LoopDetected = 508, ///< HTTP 508 Loop Detected.
|
||||
NotExtended = 510, ///< HTTP 510 Not Extended.
|
||||
NetworkAuthenticationRequired = 511, ///< HTTP 511 Network Authentication Required.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Defines a range of bytes within an HTTP resource, starting at an `Offset` and ending at
|
||||
* `Offset + Length - 1` inclusively.
|
||||
@ -340,134 +263,6 @@ namespace Azure { namespace Core { namespace Http {
|
||||
Url const& GetUrl() const { return this->m_url; }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Raw HTTP response.
|
||||
*/
|
||||
class RawResponse {
|
||||
|
||||
private:
|
||||
int32_t m_majorVersion;
|
||||
int32_t m_minorVersion;
|
||||
HttpStatusCode m_statusCode;
|
||||
std::string m_reasonPhrase;
|
||||
CaseInsensitiveMap m_headers;
|
||||
|
||||
std::unique_ptr<Azure::Core::IO::BodyStream> m_bodyStream;
|
||||
std::vector<uint8_t> m_body;
|
||||
|
||||
explicit RawResponse(
|
||||
int32_t majorVersion,
|
||||
int32_t minorVersion,
|
||||
HttpStatusCode statusCode,
|
||||
std::string const& reasonPhrase,
|
||||
std::unique_ptr<Azure::Core::IO::BodyStream> BodyStream)
|
||||
: m_majorVersion(majorVersion), m_minorVersion(minorVersion), m_statusCode(statusCode),
|
||||
m_reasonPhrase(reasonPhrase), m_bodyStream(std::move(BodyStream))
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Construct raw HTTP response.
|
||||
*
|
||||
* @param majorVersion HTTP protocol version major number.
|
||||
* @param minorVersion HTTP protocol version minor number.
|
||||
* @param statusCode HTTP status code.
|
||||
* @param reasonPhrase HTP reason phrase.
|
||||
*/
|
||||
explicit RawResponse(
|
||||
int32_t majorVersion,
|
||||
int32_t minorVersion,
|
||||
HttpStatusCode statusCode,
|
||||
std::string const& reasonPhrase)
|
||||
: RawResponse(majorVersion, minorVersion, statusCode, reasonPhrase, nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy a raw response to construct a new one.
|
||||
*
|
||||
* @remark The body stream won't be copied.
|
||||
*
|
||||
* @param response A reference for copying the raw response.
|
||||
*/
|
||||
RawResponse(RawResponse const& response)
|
||||
: RawResponse(
|
||||
response.m_majorVersion,
|
||||
response.m_minorVersion,
|
||||
response.m_statusCode,
|
||||
response.m_reasonPhrase)
|
||||
{
|
||||
// Copy body
|
||||
m_body = response.GetBody();
|
||||
}
|
||||
|
||||
// ===== Methods used to build HTTP response =====
|
||||
|
||||
/**
|
||||
* @brief Set an HTTP header to the #RawResponse.
|
||||
*
|
||||
* @remark The \p name must contain valid header name characters (RFC 7230).
|
||||
*
|
||||
* @param name The name for the header to be set or added.
|
||||
* @param value The value for the header to be set or added.
|
||||
*
|
||||
* @throw if \p name contains invalid characters.
|
||||
*/
|
||||
void SetHeader(std::string const& name, std::string const& value);
|
||||
|
||||
/**
|
||||
* @brief Set #Azure::Core::IO::BodyStream for this HTTP response.
|
||||
*
|
||||
* @param stream #Azure::Core::IO::BodyStream.
|
||||
*/
|
||||
void SetBodyStream(std::unique_ptr<Azure::Core::IO::BodyStream> stream);
|
||||
|
||||
/**
|
||||
* @brief Set HTTP response body for this HTTP response.
|
||||
*
|
||||
* @param body HTTP response body bytes.
|
||||
*/
|
||||
void SetBody(std::vector<uint8_t> body) { this->m_body = std::move(body); }
|
||||
|
||||
// adding getters for version and stream body. Clang will complain on Mac if we have unused
|
||||
// fields in a class
|
||||
|
||||
/**
|
||||
* @brief Get HTTP status code of the HTTP response.
|
||||
*/
|
||||
HttpStatusCode GetStatusCode() const;
|
||||
|
||||
/**
|
||||
* @brief Get HTTP reason phrase code of the HTTP response.
|
||||
*/
|
||||
std::string const& GetReasonPhrase() const;
|
||||
|
||||
/**
|
||||
* @brief Get HTTP response headers.
|
||||
*/
|
||||
CaseInsensitiveMap const& GetHeaders() const;
|
||||
|
||||
/**
|
||||
* @brief Get HTTP response body as #Azure::Core::IO::BodyStream.
|
||||
*/
|
||||
std::unique_ptr<Azure::Core::IO::BodyStream> ExtractBodyStream()
|
||||
{
|
||||
// If m_bodyStream was moved before. nullptr is returned
|
||||
return std::move(this->m_bodyStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get HTTP response body as vector of bytes.
|
||||
*/
|
||||
std::vector<uint8_t>& GetBody() { return this->m_body; }
|
||||
|
||||
/**
|
||||
* @brief Get HTTP response body as vector of bytes.
|
||||
*/
|
||||
std::vector<uint8_t> const& GetBody() const { return this->m_body; }
|
||||
};
|
||||
|
||||
namespace _detail {
|
||||
struct RawResponseHelpers
|
||||
{
|
||||
@ -517,4 +312,28 @@ namespace Azure { namespace Core { namespace Http {
|
||||
};
|
||||
} // namespace _detail
|
||||
|
||||
namespace _internal {
|
||||
|
||||
struct HttpShared
|
||||
{
|
||||
AZ_CORE_DLLEXPORT static char const ContentType[];
|
||||
AZ_CORE_DLLEXPORT static char const ApplicationJson[];
|
||||
AZ_CORE_DLLEXPORT static char const Accept[];
|
||||
AZ_CORE_DLLEXPORT static char const MsRequestId[];
|
||||
AZ_CORE_DLLEXPORT static char const MsClientRequestId[];
|
||||
|
||||
static inline std::string GetHeaderOrEmptyString(
|
||||
Azure::Core::CaseInsensitiveMap const& headers,
|
||||
std::string const& headerName)
|
||||
{
|
||||
auto header = headers.find(headerName);
|
||||
if (header != headers.end())
|
||||
{
|
||||
return header->second; // second is the header value.
|
||||
}
|
||||
return {}; // empty string
|
||||
}
|
||||
};
|
||||
} // namespace _internal
|
||||
|
||||
}}} // namespace Azure::Core::Http
|
||||
|
||||
94
sdk/core/azure-core/inc/azure/core/http/http_status_code.hpp
Normal file
94
sdk/core/azure-core/inc/azure/core/http/http_status_code.hpp
Normal file
@ -0,0 +1,94 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief HTTP status code definition.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Azure { namespace Core { namespace Http {
|
||||
/**
|
||||
* @brief Defines the possible HTTP status codes.
|
||||
*/
|
||||
enum class HttpStatusCode
|
||||
{
|
||||
/// No HTTP status code.
|
||||
None = 0,
|
||||
|
||||
// === 1xx (information) Status Codes: ===
|
||||
Continue = 100, ///< HTTP 100 Continue.
|
||||
SwitchingProtocols = 101, ///< HTTP 101 Switching Protocols.
|
||||
Processing = 102, ///< HTTP 102 Processing.
|
||||
EarlyHints = 103, ///< HTTP 103 Early Hints.
|
||||
|
||||
// === 2xx (successful) Status Codes: ===
|
||||
Ok = 200, ///< HTTP 200 OK.
|
||||
Created = 201, ///< HTTP 201 Created.
|
||||
Accepted = 202, ///< HTTP 202 Accepted.
|
||||
NonAuthoritativeInformation = 203, ///< HTTP 203 Non-Authoritative Information.
|
||||
NoContent = 204, ///< HTTP 204 No Content.
|
||||
ResetContent = 205, ///< HTTP 205 Rest Content.
|
||||
PartialContent = 206, ///< HTTP 206 Partial Content.
|
||||
MultiStatus = 207, ///< HTTP 207 Multi-Status.
|
||||
AlreadyReported = 208, ///< HTTP 208 Already Reported.
|
||||
IMUsed = 226, ///< HTTP 226 IM Used.
|
||||
|
||||
// === 3xx (redirection) Status Codes: ===
|
||||
MultipleChoices = 300, ///< HTTP 300 Multiple Choices.
|
||||
MovedPermanently = 301, ///< HTTP 301 Moved Permanently.
|
||||
Found = 302, ///< HTTP 302 Found.
|
||||
SeeOther = 303, ///< HTTP 303 See Other.
|
||||
NotModified = 304, ///< HTTP 304 Not Modified.
|
||||
UseProxy = 305, ///< HTTP 305 Use Proxy.
|
||||
TemporaryRedirect = 307, ///< HTTP 307 Temporary Redirect.
|
||||
PermanentRedirect = 308, ///< HTTP 308 Permanent Redirect.
|
||||
|
||||
// === 4xx (client error) Status Codes: ===
|
||||
BadRequest = 400, ///< HTTP 400 Bad Request.
|
||||
Unauthorized = 401, ///< HTTP 401 Unauthorized.
|
||||
PaymentRequired = 402, ///< HTTP 402 Payment Required.
|
||||
Forbidden = 403, ///< HTTP 403 Forbidden.
|
||||
NotFound = 404, ///< HTTP 404 Not Found.
|
||||
MethodNotAllowed = 405, ///< HTTP 405 Method Not Allowed.
|
||||
NotAcceptable = 406, ///< HTTP 406 Not Acceptable.
|
||||
ProxyAuthenticationRequired = 407, ///< HTTP 407 Proxy Authentication Required.
|
||||
RequestTimeout = 408, ///< HTTP 408 Request Timeout.
|
||||
Conflict = 409, ///< HTTP 409 Conflict.
|
||||
Gone = 410, ///< HTTP 410 Gone.
|
||||
LengthRequired = 411, ///< HTTP 411 Length Required.
|
||||
PreconditionFailed = 412, ///< HTTP 412 Precondition Failed.
|
||||
PayloadTooLarge = 413, ///< HTTP 413 Payload Too Large.
|
||||
UriTooLong = 414, ///< HTTP 414 URI Too Long.
|
||||
UnsupportedMediaType = 415, ///< HTTP 415 Unsupported Media Type.
|
||||
RangeNotSatisfiable = 416, ///< HTTP 416 Range Not Satisfiable.
|
||||
ExpectationFailed = 417, ///< HTTP 417 Expectation Failed.
|
||||
MisdirectedRequest = 421, ///< HTTP 421 Misdirected Request.
|
||||
UnprocessableEntity = 422, ///< HTTP 422 Unprocessable Entity.
|
||||
Locked = 423, ///< HTTP 423 Locked.
|
||||
FailedDependency = 424, ///< HTTP 424 Failed Dependency.
|
||||
TooEarly = 425, ///< HTTP 425 Too Early.
|
||||
UpgradeRequired = 426, ///< HTTP 426 Upgrade Required.
|
||||
PreconditionRequired = 428, ///< HTTP 428 Precondition Required.
|
||||
TooManyRequests = 429, ///< HTTP 429 Too Many Requests.
|
||||
RequestHeaderFieldsTooLarge = 431, ///< HTTP 431 Request Header Fields Too Large.
|
||||
UnavailableForLegalReasons = 451, ///< HTTP 451 Unavailable For Legal Reasons.
|
||||
|
||||
// === 5xx (server error) Status Codes: ===
|
||||
InternalServerError = 500, ///< HTTP 500 Internal Server Error.
|
||||
NotImplemented = 501, ///< HTTP 501 Not Implemented.
|
||||
BadGateway = 502, ///< HTTP 502 Bad Gateway.
|
||||
ServiceUnavailable = 503, ///< HTTP 503 Unavailable.
|
||||
GatewayTimeout = 504, ///< HTTP 504 Gateway Timeout.
|
||||
HttpVersionNotSupported = 505, ///< HTTP 505 HTTP Version Not Supported.
|
||||
VariantAlsoNegotiates = 506, ///< HTTP 506 Variant Also Negotiates.
|
||||
InsufficientStorage = 507, ///< HTTP 507 Insufficient Storage.
|
||||
LoopDetected = 508, ///< HTTP 508 Loop Detected.
|
||||
NotExtended = 510, ///< HTTP 510 Not Extended.
|
||||
NetworkAuthenticationRequired = 511, ///< HTTP 511 Network Authentication Required.
|
||||
};
|
||||
|
||||
}}} // namespace Azure::Core::Http
|
||||
147
sdk/core/azure-core/inc/azure/core/http/raw_response.hpp
Normal file
147
sdk/core/azure-core/inc/azure/core/http/raw_response.hpp
Normal file
@ -0,0 +1,147 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Define the Http raw response.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "azure/core/case_insensitive_containers.hpp"
|
||||
#include "azure/core/http/http_status_code.hpp"
|
||||
#include "azure/core/io/body_stream.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Azure { namespace Core { namespace Http {
|
||||
/**
|
||||
* @brief Raw HTTP response.
|
||||
*/
|
||||
class RawResponse {
|
||||
|
||||
private:
|
||||
int32_t m_majorVersion;
|
||||
int32_t m_minorVersion;
|
||||
HttpStatusCode m_statusCode;
|
||||
std::string m_reasonPhrase;
|
||||
CaseInsensitiveMap m_headers;
|
||||
|
||||
std::unique_ptr<Azure::Core::IO::BodyStream> m_bodyStream;
|
||||
std::vector<uint8_t> m_body;
|
||||
|
||||
explicit RawResponse(
|
||||
int32_t majorVersion,
|
||||
int32_t minorVersion,
|
||||
HttpStatusCode statusCode,
|
||||
std::string const& reasonPhrase,
|
||||
std::unique_ptr<Azure::Core::IO::BodyStream> BodyStream)
|
||||
: m_majorVersion(majorVersion), m_minorVersion(minorVersion), m_statusCode(statusCode),
|
||||
m_reasonPhrase(reasonPhrase), m_bodyStream(std::move(BodyStream))
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Construct raw HTTP response.
|
||||
*
|
||||
* @param majorVersion HTTP protocol version major number.
|
||||
* @param minorVersion HTTP protocol version minor number.
|
||||
* @param statusCode HTTP status code.
|
||||
* @param reasonPhrase HTP reason phrase.
|
||||
*/
|
||||
explicit RawResponse(
|
||||
int32_t majorVersion,
|
||||
int32_t minorVersion,
|
||||
HttpStatusCode statusCode,
|
||||
std::string const& reasonPhrase)
|
||||
: RawResponse(majorVersion, minorVersion, statusCode, reasonPhrase, nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy a raw response to construct a new one.
|
||||
*
|
||||
* @remark The body stream won't be copied.
|
||||
*
|
||||
* @param response A reference for copying the raw response.
|
||||
*/
|
||||
RawResponse(RawResponse const& response)
|
||||
: RawResponse(
|
||||
response.m_majorVersion,
|
||||
response.m_minorVersion,
|
||||
response.m_statusCode,
|
||||
response.m_reasonPhrase)
|
||||
{
|
||||
// Copy body
|
||||
m_body = response.GetBody();
|
||||
}
|
||||
|
||||
// ===== Methods used to build HTTP response =====
|
||||
|
||||
/**
|
||||
* @brief Set an HTTP header to the #RawResponse.
|
||||
*
|
||||
* @remark The \p name must contain valid header name characters (RFC 7230).
|
||||
*
|
||||
* @param name The name for the header to be set or added.
|
||||
* @param value The value for the header to be set or added.
|
||||
*
|
||||
* @throw if \p name contains invalid characters.
|
||||
*/
|
||||
void SetHeader(std::string const& name, std::string const& value);
|
||||
|
||||
/**
|
||||
* @brief Set #Azure::Core::IO::BodyStream for this HTTP response.
|
||||
*
|
||||
* @param stream #Azure::Core::IO::BodyStream.
|
||||
*/
|
||||
void SetBodyStream(std::unique_ptr<Azure::Core::IO::BodyStream> stream);
|
||||
|
||||
/**
|
||||
* @brief Set HTTP response body for this HTTP response.
|
||||
*
|
||||
* @param body HTTP response body bytes.
|
||||
*/
|
||||
void SetBody(std::vector<uint8_t> body) { this->m_body = std::move(body); }
|
||||
|
||||
// adding getters for version and stream body. Clang will complain on Mac if we have unused
|
||||
// fields in a class
|
||||
|
||||
/**
|
||||
* @brief Get HTTP status code of the HTTP response.
|
||||
*/
|
||||
HttpStatusCode GetStatusCode() const;
|
||||
|
||||
/**
|
||||
* @brief Get HTTP reason phrase code of the HTTP response.
|
||||
*/
|
||||
std::string const& GetReasonPhrase() const;
|
||||
|
||||
/**
|
||||
* @brief Get HTTP response headers.
|
||||
*/
|
||||
CaseInsensitiveMap const& GetHeaders() const;
|
||||
|
||||
/**
|
||||
* @brief Get HTTP response body as #Azure::Core::IO::BodyStream.
|
||||
*/
|
||||
std::unique_ptr<Azure::Core::IO::BodyStream> ExtractBodyStream()
|
||||
{
|
||||
// If m_bodyStream was moved before. nullptr is returned
|
||||
return std::move(this->m_bodyStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get HTTP response body as vector of bytes.
|
||||
*/
|
||||
std::vector<uint8_t>& GetBody() { return this->m_body; }
|
||||
|
||||
/**
|
||||
* @brief Get HTTP response body as vector of bytes.
|
||||
*/
|
||||
std::vector<uint8_t> const& GetBody() const { return this->m_body; }
|
||||
};
|
||||
}}} // namespace Azure::Core::Http
|
||||
31
sdk/core/azure-core/src/exception.cpp
Normal file
31
sdk/core/azure-core/src/exception.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "azure/core/exception.hpp"
|
||||
#include "azure/core/http/http.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace Azure::Core::Http::_internal;
|
||||
|
||||
namespace Azure { namespace Core {
|
||||
|
||||
RequestFailedException::RequestFailedException(
|
||||
const std::string& message,
|
||||
std::unique_ptr<Azure::Core::Http::RawResponse> rawResponse)
|
||||
: std::runtime_error(message), Message(message)
|
||||
{
|
||||
auto const& headers = rawResponse->GetHeaders();
|
||||
|
||||
StatusCode = rawResponse->GetStatusCode();
|
||||
ReasonPhrase = rawResponse->GetReasonPhrase();
|
||||
RequestId = HttpShared::GetHeaderOrEmptyString(headers, HttpShared::MsRequestId);
|
||||
ClientRequestId = HttpShared::GetHeaderOrEmptyString(headers, HttpShared::MsClientRequestId);
|
||||
Message = message;
|
||||
RawResponse = std::move(rawResponse);
|
||||
}
|
||||
|
||||
}} // namespace Azure::Core
|
||||
@ -12,6 +12,12 @@ using namespace Azure::Core;
|
||||
using namespace Azure::Core::Http;
|
||||
using namespace Azure::Core::IO::_internal;
|
||||
|
||||
char const Azure::Core::Http::_internal::HttpShared::ContentType[] = "content-type";
|
||||
char const Azure::Core::Http::_internal::HttpShared::ApplicationJson[] = "application/json";
|
||||
char const Azure::Core::Http::_internal::HttpShared::Accept[] = "accept";
|
||||
char const Azure::Core::Http::_internal::HttpShared::MsRequestId[] = "x-ms-request-id";
|
||||
char const Azure::Core::Http::_internal::HttpShared::MsClientRequestId[] = "x-ms-client-request-id";
|
||||
|
||||
void Azure::Core::Http::_detail::RawResponseHelpers::InsertHeaderWithValidation(
|
||||
Azure::Core::CaseInsensitiveMap& headers,
|
||||
std::string const& headerName,
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "azure/core/http/raw_response.hpp"
|
||||
#include "azure/core/http/http.hpp"
|
||||
#include "azure/core/internal/strings.hpp"
|
||||
|
||||
|
||||
@ -9,12 +9,6 @@
|
||||
#pragma once
|
||||
|
||||
namespace Azure { namespace Security { namespace KeyVault { namespace _detail {
|
||||
/***************** KeyVault headers *****************/
|
||||
static constexpr char const ContentType[] = "content-type";
|
||||
static constexpr char const ApplicationJson[] = "application/json";
|
||||
static constexpr char const Accept[] = "accept";
|
||||
static constexpr char const MsRequestId[] = "x-ms-request-id";
|
||||
static constexpr char const MsClientRequestId[] = "x-ms-client-request-id";
|
||||
|
||||
/**************** KeyVault QueryParameters *********/
|
||||
static constexpr char const ApiVersion[] = "api-version";
|
||||
|
||||
@ -11,7 +11,6 @@
|
||||
#include <azure/core/exception.hpp>
|
||||
#include <azure/core/http/http.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
@ -21,74 +20,26 @@ namespace Azure { namespace Security { namespace KeyVault {
|
||||
* @brief The general exception thrown by the Key Vault SDK clients.
|
||||
*
|
||||
*/
|
||||
struct KeyVaultException : public Azure::Core::RequestFailedException
|
||||
{
|
||||
class KeyVaultException : public Azure::Core::RequestFailedException {
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new Key Vault Exception object.
|
||||
* @brief Construct a new Key Vault Exception object without an Http raw response.
|
||||
*
|
||||
* @param message
|
||||
* @remark A Key Vault Exception without an Http raw response represent an exception happend
|
||||
* before sending the request to the server. There is no response yet.
|
||||
*
|
||||
* @param message An error message for the exception.
|
||||
*/
|
||||
explicit KeyVaultException(const std::string& message) : RequestFailedException(message) {}
|
||||
|
||||
/**
|
||||
* @brief The Http response code.
|
||||
* @brief Construct a new Key Vault Exception object with an Http raw response.
|
||||
*
|
||||
* @param message An error message for the exception.
|
||||
* @param rawResponse The Http raw response from the service.
|
||||
*/
|
||||
Azure::Core::Http::HttpStatusCode StatusCode = Azure::Core::Http::HttpStatusCode::None;
|
||||
|
||||
/**
|
||||
* @brief The Http reason phrase from the response.
|
||||
*
|
||||
*/
|
||||
std::string ReasonPhrase;
|
||||
|
||||
/**
|
||||
* @brief The client request header from the Http response.
|
||||
*
|
||||
*/
|
||||
std::string ClientRequestId;
|
||||
|
||||
/**
|
||||
* @brief The request id header from the Http response.
|
||||
*
|
||||
*/
|
||||
std::string RequestId;
|
||||
|
||||
/**
|
||||
* @brief The error code from the Key Vault service returned in the Http response.
|
||||
*
|
||||
*/
|
||||
std::string ErrorCode;
|
||||
|
||||
/**
|
||||
* @brief The error message from the Key Vault service returned in the Http response.
|
||||
*
|
||||
*/
|
||||
std::string Message;
|
||||
|
||||
/**
|
||||
* @brief The entire Http raw response.
|
||||
*
|
||||
*/
|
||||
std::unique_ptr<Azure::Core::Http::RawResponse> RawResponse;
|
||||
|
||||
/**
|
||||
* @brief Create a #Azure::Security::KeyVault::KeyVaultException by parsing the \p
|
||||
* response.
|
||||
*
|
||||
* @param response The Http raw response from the network.
|
||||
* @return KeyVaultException.
|
||||
*/
|
||||
static KeyVaultException CreateFromResponse(
|
||||
std::unique_ptr<Azure::Core::Http::RawResponse> response);
|
||||
|
||||
/**
|
||||
* @brief Create #Azure::Security::KeyVault::KeyVaultException by parsing the \p
|
||||
* response reference.
|
||||
*
|
||||
* @param response The Http raw response from the network.
|
||||
* @return KeyVaultException.
|
||||
*/
|
||||
static KeyVaultException CreateFromResponse(Azure::Core::Http::RawResponse const& response);
|
||||
explicit KeyVaultException(
|
||||
const std::string& message,
|
||||
std::unique_ptr<Azure::Core::Http::RawResponse> rawResponse);
|
||||
};
|
||||
}}} // namespace Azure::Security::KeyVault
|
||||
|
||||
@ -10,64 +10,26 @@
|
||||
#include <type_traits>
|
||||
|
||||
using namespace Azure::Security::KeyVault;
|
||||
using namespace Azure::Core::Http::_internal;
|
||||
|
||||
namespace {
|
||||
|
||||
inline std::string GetHeaderOrEmptyString(
|
||||
Azure::Core::CaseInsensitiveMap const& headers,
|
||||
std::string const& headerName)
|
||||
KeyVaultException::KeyVaultException(
|
||||
const std::string& message,
|
||||
std::unique_ptr<Azure::Core::Http::RawResponse> rawResponse)
|
||||
: RequestFailedException(message, std::move(rawResponse))
|
||||
{
|
||||
auto header = headers.find(headerName);
|
||||
if (header != headers.end())
|
||||
{
|
||||
return header->second; // second is the header value.
|
||||
}
|
||||
return {}; // empty string
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
KeyVaultException KeyVaultException::CreateFromResponse(
|
||||
std::unique_ptr<Azure::Core::Http::RawResponse> response)
|
||||
{
|
||||
return CreateFromResponse(*response);
|
||||
}
|
||||
|
||||
KeyVaultException KeyVaultException::CreateFromResponse(
|
||||
Azure::Core::Http::RawResponse const& response)
|
||||
{
|
||||
std::vector<uint8_t> bodyBuffer = std::move(response.GetBody());
|
||||
|
||||
auto httpStatusCode = response.GetStatusCode();
|
||||
std::string reasonPhrase = response.GetReasonPhrase();
|
||||
auto& headers = response.GetHeaders();
|
||||
std::string requestId = GetHeaderOrEmptyString(headers, _detail::MsRequestId);
|
||||
std::string clientRequestId = GetHeaderOrEmptyString(headers, _detail::MsClientRequestId);
|
||||
std::string contentType = GetHeaderOrEmptyString(headers, _detail::ContentType);
|
||||
std::string errorCode;
|
||||
std::string message;
|
||||
std::vector<uint8_t> bodyBuffer = std::move(RawResponse->GetBody());
|
||||
auto& headers = RawResponse->GetHeaders();
|
||||
std::string contentType = HttpShared::GetHeaderOrEmptyString(headers, HttpShared::ContentType);
|
||||
|
||||
if (contentType.find("json") != std::string::npos)
|
||||
{
|
||||
auto jsonParser = Azure::Core::Json::_internal::json::parse(bodyBuffer);
|
||||
auto& error = jsonParser["error"];
|
||||
errorCode = error["code"].get<std::string>();
|
||||
message = error["message"].get<std::string>();
|
||||
ErrorCode = error["code"].get<std::string>();
|
||||
Message = error["message"].get<std::string>();
|
||||
}
|
||||
else
|
||||
{
|
||||
message = std::string(bodyBuffer.begin(), bodyBuffer.end());
|
||||
Message = std::string(bodyBuffer.begin(), bodyBuffer.end());
|
||||
}
|
||||
|
||||
KeyVaultException result = KeyVaultException(
|
||||
std::to_string(static_cast<std::underlying_type<Azure::Core::Http::HttpStatusCode>::type>(
|
||||
httpStatusCode))
|
||||
+ " " + reasonPhrase + "\n" + message + "\nRequest ID: " + requestId);
|
||||
result.StatusCode = httpStatusCode;
|
||||
result.ReasonPhrase = std::move(reasonPhrase);
|
||||
result.RequestId = std::move(requestId);
|
||||
result.ErrorCode = std::move(errorCode);
|
||||
result.Message = std::move(message);
|
||||
result.RawResponse = std::make_unique<Azure::Core::Http::RawResponse>(response);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1,11 +1,14 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "azure/core/http/http.hpp"
|
||||
|
||||
#include "azure/keyvault/common/internal/keyvault_pipeline.hpp"
|
||||
#include "azure/keyvault/common/keyvault_constants.hpp"
|
||||
#include "azure/keyvault/common/keyvault_exception.hpp"
|
||||
|
||||
using namespace Azure::Security::KeyVault;
|
||||
using namespace Azure::Core::Http::_internal;
|
||||
|
||||
namespace {
|
||||
inline Azure::Core::Http::Request InitRequest(
|
||||
@ -29,8 +32,8 @@ Azure::Core::Http::Request _internal::KeyVaultPipeline::CreateRequest(
|
||||
|
||||
auto request = ::InitRequest(method, content, m_vaultUrl);
|
||||
|
||||
request.SetHeader(_detail::ContentType, _detail::ApplicationJson);
|
||||
request.SetHeader(_detail::Accept, _detail::ApplicationJson);
|
||||
request.SetHeader(HttpShared::ContentType, HttpShared::ApplicationJson);
|
||||
request.SetHeader(HttpShared::Accept, HttpShared::ApplicationJson);
|
||||
|
||||
request.GetUrl().AppendQueryParameter(_detail::ApiVersion, m_apiVersion);
|
||||
|
||||
@ -59,6 +62,7 @@ std::unique_ptr<Azure::Core::Http::RawResponse> _internal::KeyVaultPipeline::Sen
|
||||
auto responseCode = response->GetStatusCode();
|
||||
switch (responseCode)
|
||||
{
|
||||
|
||||
// 200, 2001, 202, 204 are accepted responses
|
||||
case Azure::Core::Http::HttpStatusCode::Ok:
|
||||
case Azure::Core::Http::HttpStatusCode::Created:
|
||||
@ -66,7 +70,7 @@ std::unique_ptr<Azure::Core::Http::RawResponse> _internal::KeyVaultPipeline::Sen
|
||||
case Azure::Core::Http::HttpStatusCode::NoContent:
|
||||
break;
|
||||
default:
|
||||
throw KeyVaultException::CreateFromResponse(std::move(response));
|
||||
throw KeyVaultException("Key Vault Keys error response received: ", std::move(response));
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
@ -1,32 +1,14 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "azure/keyvault/common/keyvault_exception.hpp"
|
||||
|
||||
#include "azure/keyvault/keys/delete_key_operation.hpp"
|
||||
#include "azure/keyvault/keys/details/key_constants.hpp"
|
||||
#include "azure/keyvault/keys/details/key_serializers.hpp"
|
||||
|
||||
using namespace Azure::Security::KeyVault::Keys;
|
||||
|
||||
namespace {
|
||||
|
||||
// For delete key, the LRO ends when we can retreive the Key from the deleted keys list from the
|
||||
// server.
|
||||
inline Azure::Core::OperationStatus CheckCompleted(Azure::Core::Http::RawResponse const& response)
|
||||
{
|
||||
auto code = response.GetStatusCode();
|
||||
switch (code)
|
||||
{
|
||||
case Azure::Core::Http::HttpStatusCode::Ok:
|
||||
case Azure::Core::Http::HttpStatusCode::Forbidden: // Access denied but proof the key was
|
||||
// deleted.
|
||||
return Azure::Core::OperationStatus::Succeeded;
|
||||
case Azure::Core::Http::HttpStatusCode::NotFound:
|
||||
return Azure::Core::OperationStatus::Running;
|
||||
default:
|
||||
throw Azure::Security::KeyVault::KeyVaultException::CreateFromResponse(response);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
using namespace Azure::Security::KeyVault;
|
||||
|
||||
std::unique_ptr<Azure::Core::Http::RawResponse>
|
||||
Azure::Security::KeyVault::Keys::DeleteKeyOperation::PollInternal(Azure::Core::Context& context)
|
||||
@ -36,7 +18,25 @@ Azure::Security::KeyVault::Keys::DeleteKeyOperation::PollInternal(Azure::Core::C
|
||||
{
|
||||
rawResponse = m_pipeline->Send(
|
||||
context, Azure::Core::Http::HttpMethod::Get, {_detail::DeletedKeysPath, m_value.Name()});
|
||||
m_status = CheckCompleted(*rawResponse);
|
||||
|
||||
switch (rawResponse->GetStatusCode())
|
||||
{
|
||||
case Azure::Core::Http::HttpStatusCode::Ok:
|
||||
case Azure::Core::Http::HttpStatusCode::Forbidden: // Access denied but proof the key was
|
||||
// deleted.
|
||||
{
|
||||
m_status = Azure::Core::OperationStatus::Succeeded;
|
||||
break;
|
||||
}
|
||||
case Azure::Core::Http::HttpStatusCode::NotFound: {
|
||||
m_status = Azure::Core::OperationStatus::Running;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw KeyVaultException(
|
||||
"Unexpected operation status from Service response.", std::move(rawResponse));
|
||||
}
|
||||
|
||||
if (m_status == Azure::Core::OperationStatus::Succeeded)
|
||||
{
|
||||
m_value = _detail::DeletedKeySerializer::DeletedKeyDeserialize(m_value.Name(), *rawResponse);
|
||||
|
||||
@ -1,32 +1,14 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "azure/keyvault/keys/recover_deleted_key_operation.hpp"
|
||||
#include "azure/keyvault/common/keyvault_exception.hpp"
|
||||
|
||||
#include "azure/keyvault/keys/details/key_constants.hpp"
|
||||
#include "azure/keyvault/keys/details/key_serializers.hpp"
|
||||
#include "azure/keyvault/keys/recover_deleted_key_operation.hpp"
|
||||
|
||||
using namespace Azure::Security::KeyVault::Keys;
|
||||
|
||||
namespace {
|
||||
|
||||
// For delete key, the LRO ends when we can retreive the Key from the deleted keys list from the
|
||||
// server.
|
||||
inline Azure::Core::OperationStatus CheckCompleted(Azure::Core::Http::RawResponse const& response)
|
||||
{
|
||||
auto const code = response.GetStatusCode();
|
||||
switch (code)
|
||||
{
|
||||
case Azure::Core::Http::HttpStatusCode::Ok:
|
||||
// Access denied but proof the key was deleted.
|
||||
case Azure::Core::Http::HttpStatusCode::Forbidden:
|
||||
return Azure::Core::OperationStatus::Succeeded;
|
||||
case Azure::Core::Http::HttpStatusCode::NotFound:
|
||||
return Azure::Core::OperationStatus::Running;
|
||||
default:
|
||||
throw Azure::Security::KeyVault::KeyVaultException::CreateFromResponse(response);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
using namespace Azure::Security::KeyVault;
|
||||
|
||||
std::unique_ptr<Azure::Core::Http::RawResponse>
|
||||
Azure::Security::KeyVault::Keys::RecoverDeletedKeyOperation::PollInternal(
|
||||
@ -39,7 +21,23 @@ Azure::Security::KeyVault::Keys::RecoverDeletedKeyOperation::PollInternal(
|
||||
context,
|
||||
Azure::Core::Http::HttpMethod::Get,
|
||||
{_detail::KeysPath, m_value.Name(), m_value.Properties.Version});
|
||||
m_status = CheckCompleted(*rawResponse);
|
||||
|
||||
switch (rawResponse->GetStatusCode())
|
||||
{
|
||||
case Azure::Core::Http::HttpStatusCode::Ok:
|
||||
// Access denied but proof the key was deleted.
|
||||
case Azure::Core::Http::HttpStatusCode::Forbidden: {
|
||||
m_status = Azure::Core::OperationStatus::Succeeded;
|
||||
break;
|
||||
}
|
||||
case Azure::Core::Http::HttpStatusCode::NotFound: {
|
||||
m_status = Azure::Core::OperationStatus::Running;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw KeyVaultException(
|
||||
"Unexpected operation status from Service response.", std::move(rawResponse));
|
||||
}
|
||||
if (m_status == Azure::Core::OperationStatus::Succeeded)
|
||||
{
|
||||
m_value
|
||||
|
||||
@ -17,14 +17,7 @@ namespace Azure { namespace Storage {
|
||||
{
|
||||
explicit StorageException(const std::string& message) : RequestFailedException(message) {}
|
||||
|
||||
Azure::Core::Http::HttpStatusCode StatusCode = Azure::Core::Http::HttpStatusCode::None;
|
||||
std::string ReasonPhrase;
|
||||
std::string ClientRequestId;
|
||||
std::string RequestId;
|
||||
std::string ErrorCode;
|
||||
std::string Message;
|
||||
std::map<std::string, std::string> AdditionalInformation;
|
||||
std::unique_ptr<Azure::Core::Http::RawResponse> RawResponse;
|
||||
|
||||
static StorageException CreateFromResponse(
|
||||
std::unique_ptr<Azure::Core::Http::RawResponse> response);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user