Add doxygen comments (#611)
This commit is contained in:
parent
a4b1677c38
commit
949d143284
@ -1,11 +1,19 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Common definitions.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <azure/core/internal/contract.hpp>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* @brief Used in implementations to mark an unreferenced function parameter.
|
||||
*/
|
||||
#define AZURE_UNREFERENCED_PARAMETER(x) ((void)(x));
|
||||
|
||||
namespace Azure { namespace Core { namespace Details {
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Context for canceling long running operations.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
@ -12,23 +17,30 @@
|
||||
|
||||
namespace Azure { namespace Core {
|
||||
|
||||
/**
|
||||
* @ A base abstract class for the `std::unique_ptr` value representation in #ContextValue.
|
||||
*/
|
||||
struct ValueBase
|
||||
{
|
||||
virtual ~ValueBase() {}
|
||||
};
|
||||
|
||||
/*
|
||||
* @brief ContextValue exists as a substitute for variant which isn't available until C++17
|
||||
/**
|
||||
* @brief Represents a value that is associated with context.
|
||||
* @rmark Exists as a substitute for variant which isn't available until C++17.
|
||||
*/
|
||||
class ContextValue {
|
||||
public:
|
||||
/**
|
||||
* @brief A type of context value.
|
||||
*/
|
||||
enum class ContextValueType
|
||||
{
|
||||
Undefined,
|
||||
Bool,
|
||||
Int,
|
||||
StdString,
|
||||
UniquePtr
|
||||
Undefined, ///< Undefined.
|
||||
Bool, ///< `bool`.
|
||||
Int, ///< `int`.
|
||||
StdString, ///< `std::string`
|
||||
UniquePtr ///< `std::unique_ptr<ValueBase>`
|
||||
};
|
||||
|
||||
private:
|
||||
@ -47,26 +59,64 @@ namespace Azure { namespace Core {
|
||||
#pragma warning(disable : 26495)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Create a context value with undefined value type.
|
||||
*/
|
||||
ContextValue() noexcept : m_contextValueType(ContextValueType::Undefined) {}
|
||||
|
||||
/**
|
||||
* @brief Create a context value with `bool` value type.
|
||||
*
|
||||
* @param b Boolean value.
|
||||
*/
|
||||
ContextValue(bool b) noexcept : m_contextValueType(ContextValueType::Bool), m_b(b) {}
|
||||
|
||||
/**
|
||||
* @brief Create a context value with `int` value type.
|
||||
*
|
||||
* @param i Integer value.
|
||||
*/
|
||||
ContextValue(int i) noexcept : m_contextValueType(ContextValueType::Int), m_i(i) {}
|
||||
|
||||
/**
|
||||
* @brief Create a context value with `std::string` value type.
|
||||
*
|
||||
* @param s String value.
|
||||
*/
|
||||
ContextValue(const std::string& s) : m_contextValueType(ContextValueType::StdString), m_s(s) {}
|
||||
|
||||
ContextValue(const char* s)
|
||||
: m_contextValueType(ContextValueType::StdString), m_s(s)
|
||||
{
|
||||
}
|
||||
/**
|
||||
* @brief Create a context value with `std::string` value type.
|
||||
*
|
||||
* @param s String value represented as 0-terminated C-string.
|
||||
*/
|
||||
ContextValue(const char* s) : m_contextValueType(ContextValueType::StdString), m_s(s) {}
|
||||
|
||||
/**
|
||||
* @brief Create a context value with `std::string` value type, using `std::move` semantics.
|
||||
*
|
||||
* @param s String value.
|
||||
*/
|
||||
ContextValue(std::string&& s)
|
||||
: m_contextValueType(ContextValueType::StdString), m_s(std::move(s))
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a context value with `std::unique_ptr<ValueBase>` value type.
|
||||
*
|
||||
* @param p Smart pointer to #ValueBase.
|
||||
*/
|
||||
ContextValue(std::unique_ptr<ValueBase>&& p) noexcept
|
||||
: m_contextValueType(ContextValueType::UniquePtr), m_p(std::move(p))
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
*
|
||||
* @param other An rvalue reference to another instance of #ContextValue.
|
||||
*/
|
||||
ContextValue(ContextValue&& other) noexcept : m_contextValueType(other.m_contextValueType)
|
||||
{
|
||||
switch (m_contextValueType)
|
||||
@ -91,6 +141,9 @@ namespace Azure { namespace Core {
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief #ContextValue destructor.
|
||||
*/
|
||||
~ContextValue()
|
||||
{
|
||||
switch (m_contextValueType)
|
||||
@ -110,11 +163,22 @@ namespace Azure { namespace Core {
|
||||
|
||||
ContextValue& operator=(const ContextValue& other) = delete;
|
||||
|
||||
/**
|
||||
* @brief Get the context value.
|
||||
*
|
||||
* @tparam Expected The type of value to get.
|
||||
*/
|
||||
template <class ExpectedType> const ExpectedType& Get() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Get the context value type.
|
||||
*/
|
||||
ContextValueType Alternative() const noexcept { return m_contextValueType; }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Get the context value type as boolean (`bool`).
|
||||
*/
|
||||
template <> inline const bool& ContextValue::Get() const noexcept
|
||||
{
|
||||
if (m_contextValueType != ContextValueType::Bool)
|
||||
@ -124,6 +188,9 @@ namespace Azure { namespace Core {
|
||||
return m_b;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the context value type as integer (`int`).
|
||||
*/
|
||||
template <> inline const int& ContextValue::Get() const noexcept
|
||||
{
|
||||
if (m_contextValueType != ContextValueType::Int)
|
||||
@ -133,6 +200,9 @@ namespace Azure { namespace Core {
|
||||
return m_i;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the context value type as string (`std::string`).
|
||||
*/
|
||||
template <> inline const std::string& ContextValue::Get() const noexcept
|
||||
{
|
||||
if (m_contextValueType != ContextValueType::StdString)
|
||||
@ -142,6 +212,9 @@ namespace Azure { namespace Core {
|
||||
return m_s;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the context value type as a pointer (`std::unique_ptr<ValueBase>`).
|
||||
*/
|
||||
template <> inline const std::unique_ptr<ValueBase>& ContextValue::Get() const noexcept
|
||||
{
|
||||
if (m_contextValueType != ContextValueType::UniquePtr)
|
||||
@ -151,8 +224,14 @@ namespace Azure { namespace Core {
|
||||
return m_p;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A context is a node within a tree that represents expiration times and key/value pairs.
|
||||
*/
|
||||
class Context {
|
||||
public:
|
||||
/**
|
||||
* @brief A type used to provide a point in time for context expiration.
|
||||
*/
|
||||
using time_point = std::chrono::system_clock::time_point;
|
||||
|
||||
private:
|
||||
@ -195,24 +274,58 @@ namespace Azure { namespace Core {
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new context with no expiration, and no value associated.
|
||||
*/
|
||||
Context() : m_contextSharedState(std::make_shared<ContextSharedState>()) {}
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
*/
|
||||
Context& operator=(const Context&) = default;
|
||||
|
||||
/**
|
||||
* @brief Create a context with expiration.
|
||||
*
|
||||
* @param cancelWhen A point in time after which a context expires.
|
||||
*
|
||||
* @return A child context with expiration.
|
||||
*/
|
||||
Context WithDeadline(time_point cancelWhen) const
|
||||
{
|
||||
return Context{std::make_shared<ContextSharedState>(
|
||||
m_contextSharedState, cancelWhen, std::string(), ContextValue{})};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a context without an expiration, but with \p key and \p value associated with
|
||||
* it.
|
||||
*
|
||||
* @param key A key to associate with this context.
|
||||
* @param value A value to associate with this context.
|
||||
*
|
||||
* @return A child context with no expiration and the \p key and \p value associated with it.
|
||||
*/
|
||||
Context WithValue(const std::string& key, ContextValue&& value) const
|
||||
{
|
||||
return Context{std::make_shared<ContextSharedState>(
|
||||
m_contextSharedState, time_point::max(), key, std::move(value))};
|
||||
}
|
||||
|
||||
/**
|
||||
* @
|
||||
*/
|
||||
time_point CancelWhen() const;
|
||||
|
||||
/**
|
||||
* @brief Get a value associated with a \p key parameter within this context or the branch of
|
||||
* contexts this context belongs to.
|
||||
*
|
||||
* @param key A key assiciated with a context to find.
|
||||
*
|
||||
* @return A value associated with the context found; an empty value if a specific value can't
|
||||
* be found.
|
||||
*/
|
||||
const ContextValue& operator[](const std::string& key) const
|
||||
{
|
||||
if (!key.empty())
|
||||
@ -230,6 +343,15 @@ namespace Azure { namespace Core {
|
||||
return empty;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check whether the context has a key matching \p key parameter in it itself, or in the
|
||||
* branch the context belongs to.
|
||||
*
|
||||
* @param key A key assiciated with a context to find.
|
||||
*
|
||||
* @return `true` if this context, or the tree branch this context belongs to has a \p key
|
||||
* associsted with it. `false` otherwise.
|
||||
*/
|
||||
bool HasKey(const std::string& key) const
|
||||
{
|
||||
if (!key.empty())
|
||||
@ -245,12 +367,18 @@ namespace Azure { namespace Core {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cancels the context.
|
||||
*/
|
||||
void Cancel()
|
||||
{
|
||||
m_contextSharedState->CancelAtMsecSinceEpoch
|
||||
= ContextSharedState::ToMsecSinceEpoch(time_point::min());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Throw an exception if the context was canceled.
|
||||
*/
|
||||
void ThrowIfCanceled() const
|
||||
{
|
||||
if (CancelWhen() < std::chrono::system_clock::now())
|
||||
@ -261,5 +389,8 @@ namespace Azure { namespace Core {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Get the application context (root).
|
||||
*/
|
||||
Context& GetApplicationContext();
|
||||
}} // namespace Azure::Core
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Credentials used for authentication with many (not all) Azure SDK client libraries.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "azure/core/context.hpp"
|
||||
@ -14,17 +19,37 @@
|
||||
|
||||
namespace Azure { namespace Core { namespace Credentials {
|
||||
|
||||
/**
|
||||
* @brief Represents an access token.
|
||||
*/
|
||||
struct AccessToken
|
||||
{
|
||||
/**
|
||||
* @brief Token string.
|
||||
*/
|
||||
std::string Token;
|
||||
|
||||
/**
|
||||
* @brief Token expiration.
|
||||
*/
|
||||
std::chrono::system_clock::time_point ExpiresOn;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Token credential.
|
||||
*/
|
||||
class TokenCredential {
|
||||
public:
|
||||
/**
|
||||
* @brief Get an authentication token.
|
||||
*
|
||||
* @param context #Context so that operation can be canceled.
|
||||
* @param scopes Authentication scopes.
|
||||
*/
|
||||
virtual AccessToken GetToken(Context const& context, std::vector<std::string> const& scopes)
|
||||
const = 0;
|
||||
|
||||
/// Destructor.
|
||||
virtual ~TokenCredential() = default;
|
||||
|
||||
protected:
|
||||
@ -35,6 +60,10 @@ namespace Azure { namespace Core { namespace Credentials {
|
||||
void operator=(TokenCredential const&) = delete;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This class is used by Azure SDK clients to authenticate with the Azure service using a
|
||||
* tenant ID, client ID and client secret.
|
||||
*/
|
||||
class ClientSecretCredential : public TokenCredential {
|
||||
private:
|
||||
static std::string const g_aadGlobalAuthority;
|
||||
@ -45,6 +74,19 @@ namespace Azure { namespace Core { namespace Credentials {
|
||||
std::string m_authority;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a Client Secret credential.
|
||||
*
|
||||
* @param tenantId Tenant ID.
|
||||
* @param clientId Client ID.
|
||||
* @param clientSecret Client Secret.
|
||||
* @param authority Authentication authority URL to set. If omitted, initializes credential with
|
||||
* default authority (Azure AD global authority - "https://login.microsoftonline.com/").
|
||||
*
|
||||
* @note Example of a \p authority string: "https://login.microsoftonline.us/". See national
|
||||
* clouds' Azure AD authentication endpoints:
|
||||
* https://docs.microsoft.com/en-us/azure/active-directory/develop/authentication-national-cloud.
|
||||
*/
|
||||
explicit ClientSecretCredential(
|
||||
std::string tenantId,
|
||||
std::string clientId,
|
||||
@ -59,15 +101,24 @@ namespace Azure { namespace Core { namespace Credentials {
|
||||
const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An exception that gets thrown when authentication error occurs.
|
||||
*/
|
||||
class AuthenticationException : public std::runtime_error {
|
||||
public:
|
||||
explicit AuthenticationException(std::string const& msg) : std::runtime_error(msg) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An environment credential.
|
||||
*/
|
||||
class EnvironmentCredential : public TokenCredential {
|
||||
std::unique_ptr<TokenCredential> m_credentialImpl;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructs an environment credential.
|
||||
*/
|
||||
explicit EnvironmentCredential();
|
||||
|
||||
AccessToken GetToken(Context const& context, std::vector<std::string> const& scopes)
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Authentication policies.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <azure/core/credentials/credentials.hpp>
|
||||
@ -12,6 +17,9 @@
|
||||
|
||||
namespace Azure { namespace Core { namespace Credentials { namespace Policy {
|
||||
|
||||
/**
|
||||
* @brief Bearer Token authentication policy.
|
||||
*/
|
||||
class BearerTokenAuthenticationPolicy : public Http::HttpPolicy {
|
||||
private:
|
||||
std::shared_ptr<TokenCredential const> const m_credential;
|
||||
@ -24,6 +32,12 @@ namespace Azure { namespace Core { namespace Credentials { namespace Policy {
|
||||
void operator=(BearerTokenAuthenticationPolicy const&) = delete;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a Bearer Token authentication policy with single authentication scope.
|
||||
*
|
||||
* @param credential A #TokenCredential to use with this policy.
|
||||
* @param scope Authentication scope.
|
||||
*/
|
||||
explicit BearerTokenAuthenticationPolicy(
|
||||
std::shared_ptr<TokenCredential const> credential,
|
||||
std::string scope)
|
||||
@ -32,6 +46,12 @@ namespace Azure { namespace Core { namespace Credentials { namespace Policy {
|
||||
m_scopes.emplace_back(std::move(scope));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a Bearer Token authentication policy with multiple authentication scopes.
|
||||
*
|
||||
* @param credential A #TokenCredential to use with this policy.
|
||||
* @param scopes A vector of authentication scopes.
|
||||
*/
|
||||
explicit BearerTokenAuthenticationPolicy(
|
||||
std::shared_ptr<TokenCredential const> credential,
|
||||
std::vector<std::string> scopes)
|
||||
@ -39,6 +59,16 @@ namespace Azure { namespace Core { namespace Credentials { namespace Policy {
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a Bearer Token authentication policy with multiple authentication scopes.
|
||||
*
|
||||
* @tparam A type of scopes sequence iterator.
|
||||
*
|
||||
* @param credential A #TokenCredential to use with this policy.
|
||||
* @param scopesBegin An iterator pointing to begin of the sequence of scopes to use.
|
||||
* @param scopesEnd An iterator pointing to an element after the last element in sequence of
|
||||
* scopes to use.
|
||||
*/
|
||||
template <typename ScopesIterator>
|
||||
explicit BearerTokenAuthenticationPolicy(
|
||||
std::shared_ptr<TokenCredential const> credential,
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief BodyStream is used to read data to/from a service.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef POSIX
|
||||
@ -26,36 +31,74 @@
|
||||
|
||||
namespace Azure { namespace Core { namespace Http {
|
||||
|
||||
// BodyStream is used to read data to/from a service
|
||||
/**
|
||||
*@brief Used to read data to/from a service.
|
||||
*/
|
||||
class BodyStream {
|
||||
public:
|
||||
/// Destructor.
|
||||
virtual ~BodyStream() = default;
|
||||
|
||||
// Returns the length of the data; used with the HTTP Content-Length header
|
||||
/**
|
||||
* @brief Get the length of the data.
|
||||
* @remark Used with the HTTP `Content-Length` header.
|
||||
*/
|
||||
virtual int64_t Length() const = 0;
|
||||
|
||||
// Resets the stream back to the beginning (for retries)
|
||||
// Derived classes that send data in an HTTP request MUST override this and implement it
|
||||
// properly.
|
||||
/*
|
||||
* @brief Resets the stream back to the beginning (for retries).
|
||||
* @remark Derived classes that send data in an HTTP request MUST override this and implement it
|
||||
* properly.
|
||||
*/
|
||||
virtual void Rewind()
|
||||
{
|
||||
throw "Not Implemented"; // TODO: Replace with best practice as defined by guideline
|
||||
};
|
||||
|
||||
// Reads more data; throws if error/canceled
|
||||
// return copied size
|
||||
/**
|
||||
* @brief Read portion of data into a buffer.
|
||||
* @remark Throws if error/canceled.
|
||||
*
|
||||
* @param conntext #Context so that operation can be canceled.
|
||||
* @param buffer Pointer to a first byte of the byte buffer to read the data into.
|
||||
* @param count Size of the buffer to read the data into.
|
||||
*
|
||||
* @return Number of bytes read.
|
||||
*/
|
||||
virtual int64_t Read(Context const& context, uint8_t* buffer, int64_t count) = 0;
|
||||
|
||||
// Keep reading until buffer is all fill out of the end of stream content is reached
|
||||
/**
|
||||
* @brief Read #BodyStream into a buffer until the buffer is filled, or until the stream is read
|
||||
* to end.
|
||||
*
|
||||
* @param conntext #Context so that operation can be canceled.
|
||||
* @param body #BodyStream to read.
|
||||
* @param buffer Pointer to a first byte of the byte buffer to read the data into.
|
||||
* @param count Size of the buffer to read the data into.
|
||||
*
|
||||
* @return Number of bytes read.
|
||||
*/
|
||||
static int64_t ReadToCount(
|
||||
Context const& context,
|
||||
BodyStream& body,
|
||||
uint8_t* buffer,
|
||||
int64_t count);
|
||||
|
||||
/**
|
||||
* @brief Read #BodyStream until the stream is read to end, allocating memory for the entirety
|
||||
* of contents.
|
||||
*
|
||||
* @param conntext #Context so that operation can be canceled.
|
||||
* @param body #BodyStream to read.
|
||||
*
|
||||
* @return A vector of bytes containing the entirety of data read from the \p body.
|
||||
*/
|
||||
static std::vector<uint8_t> ReadToEnd(Context const& context, BodyStream& body);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief #BodyStream providing data from an initialized memory buffer.
|
||||
*/
|
||||
class MemoryBodyStream : public BodyStream {
|
||||
private:
|
||||
const uint8_t* m_data;
|
||||
@ -66,12 +109,23 @@ namespace Azure { namespace Core { namespace Http {
|
||||
// Forbid constructor for rval so we don't end up storing dangling ptr
|
||||
MemoryBodyStream(std::vector<uint8_t> const&&) = delete;
|
||||
|
||||
/**
|
||||
* @brief Construct using vector of bytes.
|
||||
*
|
||||
* @param buffer Vector of bytes with the contents to provide the data from to the readers.
|
||||
*/
|
||||
MemoryBodyStream(std::vector<uint8_t> const& buffer)
|
||||
: MemoryBodyStream(buffer.data(), static_cast<int64_t>(buffer.size()))
|
||||
{
|
||||
}
|
||||
|
||||
// cast as vector from ptr and length
|
||||
/**
|
||||
* @brief Construct using buffer pointer and its size.
|
||||
*
|
||||
* @param data Pointer to a first byte of the buffer with the contents to provide the data from
|
||||
* to the readers.
|
||||
* @param length Size of the buffer.
|
||||
*/
|
||||
explicit MemoryBodyStream(const uint8_t* data, int64_t length) : m_data(data), m_length(length)
|
||||
{
|
||||
}
|
||||
@ -83,9 +137,13 @@ namespace Azure { namespace Core { namespace Http {
|
||||
void Rewind() override { m_offset = 0; }
|
||||
};
|
||||
|
||||
// Use for request with no body
|
||||
/**
|
||||
* @brief Empty #BodyStream.
|
||||
* @remark Used for requests with no body.
|
||||
*/
|
||||
class NullBodyStream : public Azure::Core::Http::BodyStream {
|
||||
public:
|
||||
/// Constructor.
|
||||
explicit NullBodyStream() {}
|
||||
|
||||
int64_t Length() const override { return 0; }
|
||||
@ -100,6 +158,9 @@ namespace Azure { namespace Core { namespace Http {
|
||||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Gets a singleton instance of a #NullBodyStream.
|
||||
*/
|
||||
static NullBodyStream* GetNullBodyStream()
|
||||
{
|
||||
static NullBodyStream nullBodyStream;
|
||||
@ -108,6 +169,9 @@ namespace Azure { namespace Core { namespace Http {
|
||||
};
|
||||
|
||||
#ifdef POSIX
|
||||
/**
|
||||
* @brief #BodyStream providing its data from a file.
|
||||
*/
|
||||
class FileBodyStream : public BodyStream {
|
||||
private:
|
||||
// in mutable
|
||||
@ -118,6 +182,13 @@ namespace Azure { namespace Core { namespace Http {
|
||||
int64_t m_offset;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Construct from a file.
|
||||
*
|
||||
* @param fd File descriptor.
|
||||
* @param offset Offset in the file to start providing the data from.
|
||||
* @param length Length of the data, in bytes, to provide.
|
||||
*/
|
||||
FileBodyStream(int fd, int64_t offset, int64_t length)
|
||||
: m_fd(fd), m_baseOffset(offset), m_length(length), m_offset(0)
|
||||
{
|
||||
@ -133,6 +204,9 @@ namespace Azure { namespace Core { namespace Http {
|
||||
#endif
|
||||
|
||||
#ifdef WINDOWS
|
||||
/**
|
||||
* @brief #BodyStream providing its data from a file.
|
||||
*/
|
||||
class FileBodyStream : public BodyStream {
|
||||
private:
|
||||
// in mutable
|
||||
@ -143,6 +217,13 @@ namespace Azure { namespace Core { namespace Http {
|
||||
int64_t m_offset;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Construct from a file.
|
||||
*
|
||||
* @param hFile File handle.
|
||||
* @param offset Offset in the file to start providing the data from.
|
||||
* @param length Length of the data, in bytes, to provide.
|
||||
*/
|
||||
FileBodyStream(HANDLE hFile, int64_t offset, int64_t length)
|
||||
: m_hFile(hFile), m_baseOffset(offset), m_length(length), m_offset(0)
|
||||
{
|
||||
@ -157,6 +238,9 @@ namespace Azure { namespace Core { namespace Http {
|
||||
};
|
||||
#endif // Windows
|
||||
|
||||
/**
|
||||
* @brief #BodyStream that provides its data from another #BodyStream.
|
||||
*/
|
||||
class LimitBodyStream : public BodyStream {
|
||||
private:
|
||||
BodyStream* m_inner;
|
||||
@ -164,6 +248,12 @@ namespace Azure { namespace Core { namespace Http {
|
||||
int64_t m_bytesRead = 0;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Construct from another #BodyStream.
|
||||
*
|
||||
* @param inner #BodyStream to provide the data from to the readers.
|
||||
* @param max_length Maximum number of bytes to provide to the readers.
|
||||
*/
|
||||
LimitBodyStream(BodyStream* inner, int64_t max_length)
|
||||
: m_inner(inner), m_length(std::min(inner->Length(), max_length))
|
||||
{
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/**
|
||||
* @brief #HttpTransport implementation via CURL.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "azure/core/http/http.hpp"
|
||||
@ -41,6 +43,9 @@ namespace Azure { namespace Core { namespace Http {
|
||||
constexpr static int c_DefaultConnectionExpiredMilliseconds = 1000 * 60;
|
||||
} // namespace Details
|
||||
|
||||
/**
|
||||
* @brief CURL HTTP connection.
|
||||
*/
|
||||
class CurlConnection {
|
||||
private:
|
||||
CURL* m_handle;
|
||||
@ -48,16 +53,40 @@ namespace Azure { namespace Core { namespace Http {
|
||||
std::chrono::steady_clock::time_point m_lastUseTime;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @Brief Construct CURL HTTP connection.
|
||||
*
|
||||
* @param host HTTP connection host name.
|
||||
*/
|
||||
CurlConnection(std::string const& host) : m_handle(curl_easy_init()), m_host(host) {}
|
||||
|
||||
/**
|
||||
* @brief Destructor.
|
||||
* @detail Cleans up CURL (invokes `curl_easy_cleanup()`).
|
||||
*/
|
||||
~CurlConnection() { curl_easy_cleanup(this->m_handle); }
|
||||
|
||||
/**
|
||||
* @brief Get CURL handle.
|
||||
* @return CURL handle for the HTTP connection.
|
||||
*/
|
||||
CURL* GetHandle() { return this->m_handle; }
|
||||
|
||||
/**
|
||||
* @brief Get HTTP connection host.
|
||||
* @return HTTP connection host name.
|
||||
*/
|
||||
std::string GetHost() const { return this->m_host; }
|
||||
|
||||
/**
|
||||
* @brief Update last usage time for the connection.
|
||||
*/
|
||||
void updateLastUsageTime() { this->m_lastUseTime = std::chrono::steady_clock::now(); }
|
||||
|
||||
/**
|
||||
* @brief Checks whether this CURL connection is expired.
|
||||
* @return `true` if this connextion is onsidered expired, `false` oterwise.
|
||||
*/
|
||||
bool isExpired()
|
||||
{
|
||||
auto connectionOnWaitingTimeMs = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
@ -66,6 +95,9 @@ namespace Azure { namespace Core { namespace Http {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* CURL HTTP connection pool.
|
||||
*/
|
||||
struct CurlConnectionPool
|
||||
{
|
||||
#ifdef TESTING_BUILD
|
||||
@ -74,28 +106,36 @@ namespace Azure { namespace Core { namespace Http {
|
||||
friend class Azure::Core::Test::TransportAdapter_ConnectionPoolCleaner_Test;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Mutex for accessing connection pool for thread-safe reading and writing
|
||||
/**
|
||||
* @brief Mutex for accessing connection pool for thread-safe reading and writing.
|
||||
*/
|
||||
static std::mutex s_connectionPoolMutex;
|
||||
|
||||
/*
|
||||
* Keeps an unique key for each host and creates a connection pool for each key.
|
||||
* This way getting a connection for an specific host can be done in O(1) instead of looping a
|
||||
* single connection list to find the first connection for the required host.
|
||||
/**
|
||||
* @brief Keeps an unique key for each host and creates a connection pool for each key.
|
||||
*
|
||||
* There might be multiple connections for each host.
|
||||
* @detail This way getting a connection for an specific host can be done in O(1) instead of
|
||||
* looping a single connection list to find the first connection for the required host.
|
||||
*
|
||||
* @remark There might be multiple connections for each host.
|
||||
*/
|
||||
static std::map<std::string, std::list<std::unique_ptr<CurlConnection>>> s_connectionPoolIndex;
|
||||
|
||||
/*
|
||||
* Finds a connection to be re-used from the connection pool. If there is not any available
|
||||
* connection, a new connection is created.
|
||||
/**
|
||||
* @brief Finds a connection to be re-used from the connection pool.
|
||||
* @remark If there is not any available connection, a new connection is created.
|
||||
*
|
||||
* @param request HTTP request to get #CurlConnection for.
|
||||
*
|
||||
* @return #CurlConnection to use.
|
||||
*/
|
||||
static std::unique_ptr<CurlConnection> GetCurlConnection(Request& request);
|
||||
|
||||
/**
|
||||
* Moves a connection back to the pool to be re-used
|
||||
* @brief Moves a connection back to the pool to be re-used.
|
||||
*
|
||||
* @param connection CURL HTTP connection to add to the pool.
|
||||
* @param lastStatusCode The most recent HTTP status code received from the \p connection.
|
||||
*/
|
||||
static void MoveConnectionBackToPool(
|
||||
std::unique_ptr<CurlConnection> connection,
|
||||
@ -413,9 +453,19 @@ namespace Azure { namespace Core { namespace Http {
|
||||
* @brief Function used when working with Streams to manually write from the HTTP Request to
|
||||
* the wire.
|
||||
*
|
||||
* @param context #Context so that operation can be canceled.
|
||||
*
|
||||
* @return CURL_OK when response is sent successfully.
|
||||
*/
|
||||
CURLcode SendRawHttp(Context const& context);
|
||||
|
||||
/**
|
||||
* @brief Upload body.
|
||||
*
|
||||
* @param context #Context so that operation can be canceled.
|
||||
*
|
||||
* @return Curl code.
|
||||
*/
|
||||
CURLcode UploadBody(Context const& context);
|
||||
|
||||
/**
|
||||
@ -433,6 +483,8 @@ namespace Azure { namespace Core { namespace Http {
|
||||
* @brief This function is used after sending an HTTP request to the server to read the HTTP
|
||||
* RawResponse from wire until the end of headers only.
|
||||
*
|
||||
* @param reUseInternalBUffer Indicates whether the internal buffer should be reused.
|
||||
*
|
||||
* @return CURL_OK when an HTTP response is created.
|
||||
*/
|
||||
void ReadStatusLineAndHeadersFromRawResponse(bool reUseInternalBUffer = false);
|
||||
@ -456,8 +508,15 @@ namespace Azure { namespace Core { namespace Http {
|
||||
*/
|
||||
int64_t ReadFromSocket(uint8_t* buffer, int64_t bufferSize);
|
||||
|
||||
/**
|
||||
* @brief Last HTTP status code read.
|
||||
*/
|
||||
Http::HttpStatusCode m_lastStatusCode;
|
||||
|
||||
/**
|
||||
* @brief check whether an end of file has been reached.
|
||||
* @return `true` if end of file has been reached, `false` otherwise.
|
||||
*/
|
||||
bool IsEOF()
|
||||
{
|
||||
return this->m_isChunkedResponseType ? this->m_chunkSize == 0
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief HTTP request and response functionality.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "azure/core/http/body_stream.hpp"
|
||||
@ -37,99 +42,116 @@ namespace Azure { namespace Core { namespace Http {
|
||||
}
|
||||
} // namespace Details
|
||||
|
||||
/**
|
||||
* @brief HTTP transport implementation used.
|
||||
*/
|
||||
enum class TransportKind
|
||||
{
|
||||
// TODO move this to Factory
|
||||
Curl,
|
||||
WinHttp
|
||||
Curl, ///< CURL.
|
||||
WinHttp ///< WinHTTP.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Defines the possible HTTP status codes.
|
||||
*/
|
||||
enum class HttpStatusCode
|
||||
{
|
||||
/// No HTTP status code.
|
||||
None = 0,
|
||||
|
||||
// 1xx (information) Status Codes:
|
||||
Continue = 100,
|
||||
SwitchingProtocols = 101,
|
||||
Processing = 102,
|
||||
EarlyHints = 103,
|
||||
// === 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,
|
||||
Created = 201,
|
||||
Accepted = 202,
|
||||
NonAuthoritativeInformation = 203,
|
||||
NoContent = 204,
|
||||
ResetContent = 205,
|
||||
PartialContent = 206,
|
||||
MultiStatus = 207,
|
||||
AlreadyReported = 208,
|
||||
ImUsed = 226,
|
||||
// === 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,
|
||||
MovedPermanently = 301,
|
||||
Found = 302,
|
||||
SeeOther = 303,
|
||||
NotModified = 304,
|
||||
UseProxy = 305,
|
||||
TemporaryRedirect = 307,
|
||||
PermanentRedirect = 308,
|
||||
// === 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,
|
||||
Unauthorized = 401,
|
||||
PaymentRequired = 402,
|
||||
Forbidden = 403,
|
||||
NotFound = 404,
|
||||
MethodNotAllowed = 405,
|
||||
NotAcceptable = 406,
|
||||
ProxyAuthenticationRequired = 407,
|
||||
RequestTimeout = 408,
|
||||
Conflict = 409,
|
||||
Gone = 410,
|
||||
LengthRequired = 411,
|
||||
PreconditionFailed = 412,
|
||||
PayloadTooLarge = 413,
|
||||
UriTooLong = 414,
|
||||
UnsupportedMediaType = 415,
|
||||
RangeNotSatisfiable = 416,
|
||||
ExpectationFailed = 417,
|
||||
MisdirectedRequest = 421,
|
||||
UnprocessableEntity = 422,
|
||||
Locked = 423,
|
||||
FailedDependency = 424,
|
||||
TooEarly = 425,
|
||||
UpgradeRequired = 426,
|
||||
PreconditionRequired = 428,
|
||||
TooManyRequests = 429,
|
||||
RequestHeaderFieldsTooLarge = 431,
|
||||
UnavailableForLegalReasons = 451,
|
||||
// === 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,
|
||||
NotImplemented = 501,
|
||||
BadGateway = 502,
|
||||
ServiceUnavailable = 503,
|
||||
GatewayTimeout = 504,
|
||||
HttpVersionNotSupported = 505,
|
||||
VariantAlsoNegotiates = 506,
|
||||
InsufficientStorage = 507,
|
||||
LoopDetected = 508,
|
||||
NotExtended = 510,
|
||||
NetworkAuthenticationRequired = 511,
|
||||
// === 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.
|
||||
};
|
||||
|
||||
/**
|
||||
* HTTP request method.
|
||||
*/
|
||||
enum class HttpMethod
|
||||
{
|
||||
Get,
|
||||
Head,
|
||||
Post,
|
||||
Put,
|
||||
Delete,
|
||||
Patch,
|
||||
Get, ///< GET
|
||||
Head, ///< HEAD
|
||||
Post, ///< POST
|
||||
Put, ///< PUT
|
||||
Delete, ///< DELETE
|
||||
Patch, ///< PATCH
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Get a string representation for a value of #HttpMethod.
|
||||
*
|
||||
* @param method A value of #HttpMethod value.
|
||||
*
|
||||
* @return String name that corresponds to a value of #HttpMethod type.
|
||||
*/
|
||||
inline std::string HttpMethodToString(const HttpMethod& method)
|
||||
{
|
||||
switch (method)
|
||||
@ -151,15 +173,21 @@ namespace Azure { namespace Core { namespace Http {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Type of HTTP response body.
|
||||
*/
|
||||
enum class BodyType
|
||||
{
|
||||
Buffer,
|
||||
Stream,
|
||||
Buffer, ///< Buffer.
|
||||
Stream, ///< Stream.
|
||||
};
|
||||
|
||||
// Url represent the location where a request will be performed. It can be parsed and init from
|
||||
// a string that contains all Url parts (scheme, host, path, etc).
|
||||
// Authority is not currently supported.
|
||||
/**
|
||||
* @brief URL.
|
||||
*/
|
||||
class Url {
|
||||
// Let Request class to be able to set retry enabled ON
|
||||
friend class Request;
|
||||
@ -198,39 +226,76 @@ namespace Azure { namespace Core { namespace Http {
|
||||
}
|
||||
|
||||
public:
|
||||
// Create empty Url instance. Usually for building Url from scratch
|
||||
/**
|
||||
* @brief Construct an empty URL.
|
||||
*/
|
||||
Url() {}
|
||||
|
||||
// Create Url from an url-encoded string. Usually from pre-built url with query parameters (like
|
||||
// SaS) url is expected to be already url-encoded.
|
||||
/**
|
||||
* @brief Construct a URL from a URL-encoded string.
|
||||
*
|
||||
* @param encodedUrl URL string that has all its expected parts already URL-encoded.
|
||||
*/
|
||||
explicit Url(const std::string& encodedUrl);
|
||||
|
||||
/************* Builder Url functions ****************/
|
||||
/******** API for building Url from scratch. Override state ********/
|
||||
|
||||
/**
|
||||
* @brief Set URL scheme.
|
||||
*
|
||||
* @param scheme URL scheme.
|
||||
*/
|
||||
void SetScheme(const std::string& scheme) { m_scheme = scheme; }
|
||||
|
||||
/**
|
||||
* @brief Set URL host.
|
||||
*
|
||||
* @param host URL host.
|
||||
* @param isHostEncoded `true` if \p host is URL-encoded, `false` otherwise.
|
||||
*/
|
||||
void SetHost(const std::string& host, bool isHostEncoded = false)
|
||||
{
|
||||
m_host = isHostEncoded ? host : EncodeHost(host);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set URL port.
|
||||
*
|
||||
* @param port URL port.
|
||||
*/
|
||||
void SetPort(uint16_t port) { m_port = port; }
|
||||
|
||||
/**
|
||||
* @brief Set URL path.
|
||||
*
|
||||
* @param path URL path.
|
||||
* @param isPathEncoded `true` if \p fragment is URL-encoded, `false` otherwise.
|
||||
*/
|
||||
void SetPath(const std::string& path, bool isPathEncoded = false)
|
||||
{
|
||||
m_encodedPath = isPathEncoded ? path : EncodePath(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set URL fragment.
|
||||
*
|
||||
* @param fragment URL fragment.
|
||||
* @param isFragmentEncoded `true` if \p fragment is URL-encoded, `false` otherwise.
|
||||
*/
|
||||
void SetFragment(const std::string& fragment, bool isFragmentEncoded = false)
|
||||
{
|
||||
m_fragment = isFragmentEncoded ? fragment : EncodeFragment(fragment);
|
||||
}
|
||||
|
||||
/******** API for mutating Url state ********/
|
||||
// ===== APIs for mutating URL state: ======
|
||||
|
||||
// Path is mostly expected to be appended without url-encoding. Be default, path will be encoded
|
||||
// before it is added to Url. \p isPathEncoded can set to true to avoid encoding.
|
||||
/**
|
||||
* @brief Append an element of URL path.
|
||||
*
|
||||
* @param path URL path element to append.
|
||||
* @param isPathEncoded `true` if \p path is URL-encoded, `false` otherwise.
|
||||
*/
|
||||
void AppendPath(const std::string& path, bool isPathEncoded = false)
|
||||
{
|
||||
if (!m_encodedPath.empty() && m_encodedPath.back() != '/')
|
||||
@ -240,13 +305,16 @@ namespace Azure { namespace Core { namespace Http {
|
||||
m_encodedPath += isPathEncoded ? path : EncodePath(path);
|
||||
}
|
||||
|
||||
// the value from query parameter is mostly expected to be non-url-encoded and it will be
|
||||
// encoded before adding to url by default. Use \p isValueEncoded = true when the value is
|
||||
// already encoded.
|
||||
//
|
||||
// Note: a query key can't contain any chars that needs to be url-encoded. (by RFC).
|
||||
//
|
||||
// Note: AppendQuery override previous query parameters.
|
||||
/**
|
||||
* @brief Append an HTTP query parameter.
|
||||
*
|
||||
* @note Overrides previous query parameters.
|
||||
* @remark A query key can't contain any characters that need to be URL-encoded (per RFC).
|
||||
*
|
||||
* @param key HTTP query parameter.
|
||||
* @param value HTTP quary parameter value.
|
||||
* @param isValueEncoded `true` if \p value is URL-encoded, `false` otherwise.
|
||||
*/
|
||||
void AppendQuery(const std::string& key, const std::string& value, bool isValueEncoded = false)
|
||||
{
|
||||
std::string encoded_value = isValueEncoded ? Decode(value) : value;
|
||||
@ -260,10 +328,20 @@ namespace Azure { namespace Core { namespace Http {
|
||||
}
|
||||
}
|
||||
|
||||
// query must be encoded.
|
||||
/**
|
||||
* @brief Append a HTTP query.
|
||||
*
|
||||
* @note All the required HTTP query parts should be URL-encoded.
|
||||
*
|
||||
* @param encodedQueries HTTP query.
|
||||
*/
|
||||
void AppendQueries(const std::string& encodedQueries);
|
||||
|
||||
// removes a query parameter
|
||||
/**
|
||||
* @brief Removes a HTTP query parameter.
|
||||
*
|
||||
* @param key HTTP query parameter to remove.
|
||||
*/
|
||||
void RemoveQuery(const std::string& key)
|
||||
{
|
||||
m_queryParameters.erase(key);
|
||||
@ -271,27 +349,45 @@ namespace Azure { namespace Core { namespace Http {
|
||||
}
|
||||
|
||||
/************** API to read values from Url ***************/
|
||||
|
||||
/**
|
||||
* @brief Get URL host.
|
||||
*/
|
||||
std::string GetHost() const { return m_host; }
|
||||
|
||||
/**
|
||||
* @brief Get URL path.
|
||||
*/
|
||||
const std::string& GetPath() const { return m_encodedPath; }
|
||||
|
||||
// Copy from query parameters list. Query parameters from retry map have preference and will
|
||||
// override any value from the initial query parameters from the request
|
||||
//
|
||||
// Note: Query values added with url-encoding will be encoded in the list. No decoding is done
|
||||
// on values.
|
||||
/**
|
||||
* @brief Get all the query paramters in the URL.
|
||||
*
|
||||
* @note Retry parameters have preference and will override any value from the initial query
|
||||
* parameters.
|
||||
* @note All the values are URL-encoded.
|
||||
*
|
||||
* @return URL query parameters.
|
||||
*/
|
||||
const std::map<std::string, std::string> GetQuery() const
|
||||
{
|
||||
return Details::MergeMaps(m_retryQueryParameters, m_queryParameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get relative URL.
|
||||
*/
|
||||
std::string GetRelativeUrl() const;
|
||||
|
||||
// Url with encoded query parameters
|
||||
/**
|
||||
* @brief Get relative URL.
|
||||
* @remark All the query parameters are URL-encoded.
|
||||
*/
|
||||
std::string GetAbsoluteUrl() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief HTTP request.
|
||||
*/
|
||||
class Request {
|
||||
friend class RetryPolicy;
|
||||
#ifdef TESTING_BUILD
|
||||
@ -321,17 +417,39 @@ namespace Azure { namespace Core { namespace Http {
|
||||
void StopRetry(); // only called by retry policy
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Construct an HTTP request.
|
||||
*
|
||||
* @param httpMethod HTTP method.
|
||||
* @param url URL.
|
||||
* @param bodyStream HTTP #BodyStream.
|
||||
* @param downloadViaStream
|
||||
*/
|
||||
explicit Request(HttpMethod httpMethod, Url url, BodyStream* bodyStream, bool downloadViaStream)
|
||||
: m_method(std::move(httpMethod)), m_url(std::move(url)), m_bodyStream(bodyStream),
|
||||
m_retryModeEnabled(false), m_isDownloadViaStream(downloadViaStream)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct an HTTP request.
|
||||
*
|
||||
* @param httpMethod HTTP method.
|
||||
* @param url URL.
|
||||
* @param bodyStream HTTP #BodyStream.
|
||||
*/
|
||||
explicit Request(HttpMethod httpMethod, Url url, BodyStream* bodyStream)
|
||||
: Request(httpMethod, std::move(url), bodyStream, false)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct an HTTP request.
|
||||
*
|
||||
* @param httpMethod HTTP method.
|
||||
* @param url URL.
|
||||
* @param downloadViaStream
|
||||
*/
|
||||
// Typically used for GET with no request body that can return bodyStream
|
||||
explicit Request(HttpMethod httpMethod, Url url, bool downloadViaStream)
|
||||
: Request(
|
||||
@ -342,41 +460,105 @@ namespace Azure { namespace Core { namespace Http {
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct an HTTP request.
|
||||
*
|
||||
* @param httpMethod HTTP method.
|
||||
* @param url URL.
|
||||
*/
|
||||
// Typically used for GET with no request body.
|
||||
explicit Request(HttpMethod httpMethod, Url url)
|
||||
: Request(httpMethod, std::move(url), NullBodyStream::GetNullBodyStream(), false)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Add an HTTP header.
|
||||
*
|
||||
* @param name HTTP header name.
|
||||
* @param value HTTP header value.
|
||||
*/
|
||||
void AddHeader(std::string const& name, std::string const& value);
|
||||
|
||||
/**
|
||||
* @brief Remove an HTTP header.
|
||||
*
|
||||
* @param name HTTP header name.
|
||||
*/
|
||||
void RemoveHeader(std::string const& name);
|
||||
|
||||
/**
|
||||
* @brief Set upload chunk size.
|
||||
*
|
||||
* @param size Upload chunk size.
|
||||
*/
|
||||
void SetUploadChunkSize(int64_t size) { this->m_uploadChunkSize = size; }
|
||||
|
||||
// Methods used by transport layer (and logger) to send request
|
||||
/**
|
||||
* @brief Get HTTP method.
|
||||
*/
|
||||
HttpMethod GetMethod() const;
|
||||
|
||||
/**
|
||||
* @brief Get HTTP headers.
|
||||
*/
|
||||
std::map<std::string, std::string> GetHeaders() const;
|
||||
|
||||
/**
|
||||
* @brief Get HTTP body as #BodyStream.
|
||||
*/
|
||||
BodyStream* GetBodyStream() { return this->m_bodyStream; }
|
||||
|
||||
/**
|
||||
* @brief Get HTTP message prior to HTTP body.
|
||||
*/
|
||||
std::string GetHTTPMessagePreBody() const;
|
||||
|
||||
/**
|
||||
* @brief Get upload chunk size.
|
||||
*/
|
||||
int64_t GetUploadChunkSize() { return this->m_uploadChunkSize; }
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
bool IsDownloadViaStream() { return this->m_isDownloadViaStream; }
|
||||
|
||||
/**
|
||||
* @brief Get URL.
|
||||
*/
|
||||
Url& GetUrl() { return this->m_url; }
|
||||
|
||||
/**
|
||||
* @brief Get URL.
|
||||
*/
|
||||
Url const& GetUrl() const { return this->m_url; }
|
||||
};
|
||||
|
||||
/*
|
||||
* RawResponse exceptions
|
||||
*/
|
||||
/**
|
||||
* @brief Couldn't resolve HTTP host.
|
||||
*/
|
||||
struct CouldNotResolveHostException : public std::runtime_error
|
||||
{
|
||||
explicit CouldNotResolveHostException(std::string const& msg) : std::runtime_error(msg) {}
|
||||
};
|
||||
|
||||
// Any other excpetion from transport layer without an specific exception defined above
|
||||
// Any other exception from transport layer without an specific exception defined above
|
||||
/**
|
||||
* @brief HTTP transport layer error.
|
||||
*/
|
||||
struct TransportException : public std::runtime_error
|
||||
{
|
||||
explicit TransportException(std::string const& msg) : std::runtime_error(msg) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Raw HTTP response.
|
||||
*/
|
||||
class RawResponse {
|
||||
|
||||
private:
|
||||
@ -401,6 +583,14 @@ namespace Azure { namespace Core { namespace Http {
|
||||
}
|
||||
|
||||
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,
|
||||
@ -410,27 +600,92 @@ namespace Azure { namespace Core { namespace Http {
|
||||
{
|
||||
}
|
||||
|
||||
// Methods used to build HTTP response
|
||||
// ===== Methods used to build HTTP response =====
|
||||
|
||||
/**
|
||||
* @brief Add header to the HTTP response.
|
||||
*
|
||||
* @param name HTTP response header name.
|
||||
* @param value HTTP response header value.
|
||||
*/
|
||||
void AddHeader(std::string const& name, std::string const& value);
|
||||
|
||||
/**
|
||||
* @brief Add header to the HTTP response.
|
||||
*
|
||||
* @param header HTTP response header in RFCnnnn format (`OWS header-value OWS`).
|
||||
*/
|
||||
// rfc form header-name: OWS header-value OWS
|
||||
void AddHeader(std::string const& header);
|
||||
|
||||
/**
|
||||
* @brief Add header to the HTTP response.
|
||||
* @detail HTTP response header should be in RFCnnnn format (`OWS header-value OWS`).
|
||||
*
|
||||
* @param begin Pointer to the first byte of the header string in RFCnnnn format.
|
||||
* @param last Pointer to the last byte of the header string in RFCnnnn format.
|
||||
*/
|
||||
void AddHeader(uint8_t const* const begin, uint8_t const* const last);
|
||||
|
||||
/**
|
||||
* @brief Set #BodyStream for this HTTP response.
|
||||
*
|
||||
* @param stream HTTP #BodyStream.
|
||||
*/
|
||||
void SetBodyStream(std::unique_ptr<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 major number of the HTTP response protocol version.
|
||||
*/
|
||||
int32_t GetMajorVersion() const { return this->m_majorVersion; }
|
||||
|
||||
/**
|
||||
* @brief Get minor number of the HTTP response protocol version.
|
||||
*/
|
||||
int32_t GetMinorVersion() const { return this->m_minorVersion; }
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*/
|
||||
std::map<std::string, std::string> const& GetHeaders() const;
|
||||
|
||||
/**
|
||||
* @brief Get HTTP response body as #BodyStream.
|
||||
*/
|
||||
std::unique_ptr<BodyStream> GetBodyStream()
|
||||
{
|
||||
// If m_bodyStream was moved before. nullpr 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; }
|
||||
};
|
||||
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief HTTP pipeline is a stack of HTTP policies.
|
||||
* @remark See #policy.hpp
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "azure/core/context.hpp"
|
||||
@ -12,11 +18,26 @@
|
||||
|
||||
namespace Azure { namespace Core { namespace Http {
|
||||
|
||||
/**
|
||||
* @brief HTTP pipeline is a stack of HTTP policies that get applied sequentially.
|
||||
*
|
||||
* @details Every client is expected to have its own HTTP pipeline, consisting of sequence of
|
||||
* individual HTTP policies. Policies shape the behavior of how a HTTP request is being handled,
|
||||
* ranging from retrying and logging, up to sending a HTTP request over the wire.
|
||||
*
|
||||
* @remark See #policy.hpp
|
||||
*/
|
||||
class HttpPipeline {
|
||||
protected:
|
||||
std::vector<std::unique_ptr<HttpPolicy>> m_policies;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Construct HTTP pipeline with the sequence of HTTP policies provided.
|
||||
*
|
||||
* @param policies A sequence of #HttpPolicy representing a stack, first element corresponding
|
||||
* to the top of the stack.
|
||||
*/
|
||||
explicit HttpPipeline(const std::vector<std::unique_ptr<HttpPolicy>>& policies)
|
||||
{
|
||||
m_policies.reserve(policies.size());
|
||||
@ -26,11 +47,18 @@ namespace Azure { namespace Core { namespace Http {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct HTTP pipeline with the sequence of HTTP policies provided.
|
||||
*
|
||||
* @param policies A sequence of #HttpPolicy representing a stack, first element corresponding
|
||||
* to the top of the stack.
|
||||
*/
|
||||
explicit HttpPipeline(std::vector<std::unique_ptr<HttpPolicy>>&& policies)
|
||||
: m_policies(std::move(policies))
|
||||
{
|
||||
}
|
||||
|
||||
/// Copy constructor.
|
||||
HttpPipeline(const HttpPipeline& other)
|
||||
{
|
||||
m_policies.reserve(other.m_policies.size());
|
||||
@ -41,11 +69,12 @@ namespace Azure { namespace Core { namespace Http {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts the pipeline
|
||||
* @param ctx A cancellation token. Can also be used to provide overrides to individual
|
||||
* policies
|
||||
* @param request The request to be processed
|
||||
* @return unique_ptr<Response>
|
||||
* @brief Start the HTTP pipeline.
|
||||
*
|
||||
* @param ctx #Context so that operation can be canceled.
|
||||
* @param request The HTTP request to be processed.
|
||||
*
|
||||
* @return HTTP response after the request has been processed.
|
||||
*/
|
||||
std::unique_ptr<RawResponse> Send(Context const& ctx, Request& request) const
|
||||
{
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Utilities to be used by HTTP transport policy implementations.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "azure/core/azure.hpp"
|
||||
@ -17,16 +22,38 @@ namespace Azure { namespace Core { namespace Http {
|
||||
|
||||
class NextHttpPolicy;
|
||||
|
||||
/**
|
||||
* @brief HTTP policy.
|
||||
* An HTTP pipeline inside SDK clients is an stack sequence of HTTP policies.
|
||||
*/
|
||||
class HttpPolicy {
|
||||
public:
|
||||
// If we get a response that goes up the stack
|
||||
// Any errors in the pipeline throws an exception
|
||||
// At the top of the pipeline we might want to turn certain responses into exceptions
|
||||
|
||||
/**
|
||||
* @brief Apply this HTTP policy.
|
||||
*
|
||||
* @param context #Context so that operation can be canceled.
|
||||
* @param request An HTTP #Request being sent.
|
||||
* @param policy #NextHttpPolicy to invoke after this policy has been applied.
|
||||
*
|
||||
* @return An HTTP #RawResponse after this policy, and all subsequent HTTP policies in the stack
|
||||
* sequence of policies have been applied.
|
||||
*/
|
||||
virtual std::unique_ptr<RawResponse> Send(
|
||||
Context const& context,
|
||||
Request& request,
|
||||
NextHttpPolicy policy) const = 0;
|
||||
|
||||
/// Destructor.
|
||||
virtual ~HttpPolicy() {}
|
||||
|
||||
/**
|
||||
* @brief Creates a clone of this HTTP policy.
|
||||
* @return A clone of this HTTP policy.
|
||||
*/
|
||||
virtual std::unique_ptr<HttpPolicy> Clone() const = 0;
|
||||
|
||||
protected:
|
||||
@ -36,11 +63,20 @@ namespace Azure { namespace Core { namespace Http {
|
||||
HttpPolicy& operator=(const HttpPolicy& other) = default;
|
||||
};
|
||||
|
||||
// Represents the next HTTP policy in the stack sequence of policies.
|
||||
class NextHttpPolicy {
|
||||
const std::size_t m_index;
|
||||
const std::vector<std::unique_ptr<HttpPolicy>>* m_policies;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Construct an abstraction representing a next line in the stack sequence of policies,
|
||||
* from the caller's perspective.
|
||||
*
|
||||
* @param index An sequential index of this policy in the stack sequence of policies.
|
||||
* @param policies A vector of unique pointers next in the line to be invoked after the current
|
||||
* policy.
|
||||
*/
|
||||
explicit NextHttpPolicy(
|
||||
std::size_t index,
|
||||
const std::vector<std::unique_ptr<HttpPolicy>>* policies)
|
||||
@ -48,14 +84,33 @@ namespace Azure { namespace Core { namespace Http {
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Apply this HTTP policy.
|
||||
*
|
||||
* @param context #Context so that operation can be canceled.
|
||||
* @param request An HTTP #Request being sent.
|
||||
*
|
||||
* @return An HTTP #RawResponse after this policy, and all subsequent HTTP policies in the stack
|
||||
* sequence of policies have been applied.
|
||||
*/
|
||||
std::unique_ptr<RawResponse> Send(Context const& ctx, Request& req);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Applying this policy sends an HTTP request over the wire.
|
||||
* @remark This policy must be the bottom policy in the stack of the HTTP policy stack.
|
||||
*/
|
||||
class TransportPolicy : public HttpPolicy {
|
||||
private:
|
||||
std::shared_ptr<HttpTransport> m_transport;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Construct an HTTP transport policy.
|
||||
*
|
||||
* @param transport A pointer to the #HttpTransport implementation to use when this policy gets
|
||||
* applied (#Send).
|
||||
*/
|
||||
explicit TransportPolicy(std::shared_ptr<HttpTransport> transport)
|
||||
: m_transport(std::move(transport))
|
||||
{
|
||||
@ -72,13 +127,29 @@ namespace Azure { namespace Core { namespace Http {
|
||||
NextHttpPolicy nextHttpPolicy) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Options for the #RetryPolicy.
|
||||
*/
|
||||
struct RetryOptions
|
||||
{
|
||||
/**
|
||||
* @brief Maximum number of attempts to retry.
|
||||
*/
|
||||
int MaxRetries = 3;
|
||||
|
||||
/**
|
||||
* @brief Mimimum amount of time between retry attempts.
|
||||
*/
|
||||
std::chrono::milliseconds RetryDelay = std::chrono::seconds(4);
|
||||
|
||||
/**
|
||||
* @brief Mimimum amount of time between retry attempts.
|
||||
*/
|
||||
decltype(RetryDelay) MaxRetryDelay = std::chrono::minutes(2);
|
||||
|
||||
/**
|
||||
* @brief HTTP status codes to retry on.
|
||||
*/
|
||||
std::vector<HttpStatusCode> StatusCodes{
|
||||
HttpStatusCode::RequestTimeout,
|
||||
HttpStatusCode::InternalServerError,
|
||||
@ -88,11 +159,19 @@ namespace Azure { namespace Core { namespace Http {
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief HTTP retry policy.
|
||||
*/
|
||||
class RetryPolicy : public HttpPolicy {
|
||||
private:
|
||||
RetryOptions m_retryOptions;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructs HTTP retry policy with the provided #RetryOptions.
|
||||
*
|
||||
* @param options HTTP #RetryOptions.
|
||||
*/
|
||||
explicit RetryPolicy(RetryOptions options) : m_retryOptions(std::move(options)) {}
|
||||
|
||||
std::unique_ptr<HttpPolicy> Clone() const override
|
||||
@ -106,11 +185,20 @@ namespace Azure { namespace Core { namespace Http {
|
||||
NextHttpPolicy nextHttpPolicy) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief HTTP Request ID policy.
|
||||
*
|
||||
* @details Applies an HTTP header with a unique ID to each HTTP request, so that each individual
|
||||
* request can be traced for troubleshooting.
|
||||
*/
|
||||
class RequestIdPolicy : public HttpPolicy {
|
||||
private:
|
||||
constexpr static const char* RequestIdHeader = "x-ms-client-request-id";
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs HTTP request ID policy.
|
||||
*/
|
||||
explicit RequestIdPolicy() {}
|
||||
|
||||
std::unique_ptr<HttpPolicy> Clone() const override
|
||||
@ -130,6 +218,13 @@ namespace Azure { namespace Core { namespace Http {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief HTTP telemetry policy.
|
||||
*
|
||||
* @details Applies an HTTP header with a component name and version to each HTTP request,
|
||||
* includes Azure SDK version information, and operating system information.
|
||||
* @remark See https://azure.github.io/azure-sdk/general_azurecore.html#telemetry-policy.
|
||||
*/
|
||||
class TelemetryPolicy : public HttpPolicy {
|
||||
std::string m_telemetryId;
|
||||
|
||||
@ -141,11 +236,25 @@ namespace Azure { namespace Core { namespace Http {
|
||||
std::string const& applicationId);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Construct HTTP telemetry policy with component name and component version.
|
||||
*
|
||||
* @param componentName Azure SDK component name (e.g. "storage.blobs")
|
||||
* @param componentVersion Azure SDK component version (e.g. "11.0.0")
|
||||
*/
|
||||
explicit TelemetryPolicy(std::string const& componentName, std::string const& componentVersion)
|
||||
: TelemetryPolicy(componentName, componentVersion, g_emptyApplicationId)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct HTTP telemetry policy with component name, component version, and an
|
||||
* applicatin ID.
|
||||
*
|
||||
* @param componentName Azure SDK component name (e.g. "storage.blobs")
|
||||
* @param componentVersion Azure SDK component version (e.g. "11.0.0")
|
||||
* @param applicationId Customer Application ID (e.g. "AzCopy")
|
||||
*/
|
||||
explicit TelemetryPolicy(
|
||||
std::string const& componentName,
|
||||
std::string const& componentVersion,
|
||||
@ -165,8 +274,17 @@ namespace Azure { namespace Core { namespace Http {
|
||||
NextHttpPolicy nextHttpPolicy) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Logs every HTTP request.
|
||||
*
|
||||
* @detail Logs every HTTP request, response, or retry attempt (see #LogClassification)
|
||||
* @remark See #logging.hpp
|
||||
*/
|
||||
class LoggingPolicy : public HttpPolicy {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs HTTP logging policy.
|
||||
*/
|
||||
explicit LoggingPolicy() {}
|
||||
|
||||
std::unique_ptr<HttpPolicy> Clone() const override
|
||||
@ -180,11 +298,20 @@ namespace Azure { namespace Core { namespace Http {
|
||||
NextHttpPolicy nextHttpPolicy) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Log classigications being used to designate log messages from HTTP #LoggingPolicy.
|
||||
*/
|
||||
class LogClassification : private Azure::Core::Logging::Details::LogClassificationProvider<
|
||||
Azure::Core::Logging::Details::Facility::Core> {
|
||||
public:
|
||||
/// HTTP request.
|
||||
static constexpr auto const Request = Classification(1);
|
||||
|
||||
/// HTTP response.
|
||||
static constexpr auto const Response = Classification(2);
|
||||
|
||||
/// HTTP retry attempt.
|
||||
static constexpr auto const Retry = Classification(3);
|
||||
};
|
||||
|
||||
}}} // namespace Azure::Core::Http
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Utilities to be used by HTTP transport implementations.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "azure/core/context.hpp"
|
||||
@ -8,14 +13,25 @@
|
||||
|
||||
namespace Azure { namespace Core { namespace Http {
|
||||
|
||||
/**
|
||||
* @brief Base class for all HTTP transport implementaions.
|
||||
*/
|
||||
class HttpTransport {
|
||||
public:
|
||||
// If we get a response that goes up the stack
|
||||
// Any errors in the pipeline throws an exception
|
||||
// At the top of the pipeline we might want to turn certain responses into exceptions
|
||||
|
||||
/**
|
||||
* @brief Send an HTTP request over the wire.
|
||||
*
|
||||
* @param context #Context so that operation can be canceled.
|
||||
* @param request An HTTP #Request to send.
|
||||
*/
|
||||
// TODO - Should this be const
|
||||
virtual std::unique_ptr<RawResponse> Send(Context const& context, Request& request) = 0;
|
||||
|
||||
/// Destructor.
|
||||
virtual ~HttpTransport() {}
|
||||
|
||||
protected:
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/**
|
||||
* @brief #HttpTransport implementation via WinHttp.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "azure/core/http/http.hpp"
|
||||
@ -13,13 +15,17 @@
|
||||
|
||||
namespace Azure { namespace Core { namespace Http {
|
||||
|
||||
/**
|
||||
* @brief #HttpTransport implementation via WinHttp.
|
||||
*/
|
||||
class WinHttpTansport : public HttpTransport {
|
||||
private:
|
||||
public:
|
||||
/// Constructor.
|
||||
WinHttpTansport();
|
||||
~WinHttpTansport();
|
||||
~WinHttpTansport() override;
|
||||
|
||||
virtual std::unique_ptr<RawResponse> Send(Context const& context, Request& request);
|
||||
virtual std::unique_ptr<RawResponse> Send(Context const& context, Request& request) override;
|
||||
};
|
||||
|
||||
}}} // namespace Azure::Core::Http
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief This header defines the types and functions your application uses to be notified of Azure
|
||||
* SDK client library log messages.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "azure/core/azure.hpp"
|
||||
@ -15,10 +21,31 @@ namespace Azure { namespace Core { namespace Logging {
|
||||
class LogClassification;
|
||||
class LogClassifications;
|
||||
|
||||
/**
|
||||
* @brief Defines the signature of the callback function that application developers must write in
|
||||
* order to receive Azure SDK log messages.
|
||||
*
|
||||
* @param classification The log message classification.
|
||||
* @param classification The log message.
|
||||
*/
|
||||
typedef std::function<void(LogClassification const& classification, std::string const& message)>
|
||||
LogListener;
|
||||
|
||||
/**
|
||||
* @brief Set the function that will be invoked to report an SDK log message.
|
||||
*
|
||||
* @param logListener A #LogListener function that will be invoked when the SDK reports a log
|
||||
* message matching one of the log classifications passed to #SetLogClassifications(). If null, no
|
||||
* function will be invoked.
|
||||
*/
|
||||
void SetLogListener(LogListener logListener);
|
||||
|
||||
/**
|
||||
* @brief Allows the application to specify which log classification types it is interested in
|
||||
* receiving.
|
||||
*
|
||||
* @param logClassifications Log classification values.
|
||||
*/
|
||||
void SetLogClassifications(LogClassifications logClassifications);
|
||||
|
||||
namespace Details {
|
||||
@ -33,6 +60,9 @@ namespace Azure { namespace Core { namespace Logging {
|
||||
class LogClassificationsPrivate;
|
||||
} // namespace Details
|
||||
|
||||
/**
|
||||
* @brief Represents a set of log classifications.
|
||||
*/
|
||||
class LogClassifications {
|
||||
friend class Details::LogClassificationsPrivate;
|
||||
|
||||
@ -42,17 +72,28 @@ namespace Azure { namespace Core { namespace Logging {
|
||||
explicit LogClassifications(bool all) : m_all(all) {}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Initialize the list of log classifications with `std::initializer_list`.
|
||||
* @param list An initializer list.
|
||||
*/
|
||||
LogClassifications(std::initializer_list<LogClassification> list)
|
||||
: m_classifications(list), m_all(false)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize the list of log classifications with `std::set`.
|
||||
* @param set A set of classifications.
|
||||
*/
|
||||
explicit LogClassifications(std::set<LogClassification> set)
|
||||
: m_classifications(std::move(set)), m_all(false)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Represents a log classification.
|
||||
*/
|
||||
class LogClassification {
|
||||
template <Details::Facility> friend class Details::LogClassificationProvider;
|
||||
friend struct std::less<LogClassification>;
|
||||
@ -70,17 +111,34 @@ namespace Azure { namespace Core { namespace Logging {
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Compare log classification to another one.
|
||||
* @param other Another log classification to compare to.
|
||||
* @return `true` if this log classification equals to \p other, `false` otherwise.
|
||||
*/
|
||||
constexpr bool operator==(LogClassification const& other) const
|
||||
{
|
||||
return m_value == other.m_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compare log classification to another one.
|
||||
* @param other Another log classification to compare to.
|
||||
* @return `true` if this log classification does not equal to \p other, `false` otherwise.
|
||||
*/
|
||||
constexpr bool operator!=(LogClassification const& other) const
|
||||
{
|
||||
return m_value != other.m_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Represents a list of all classifications.
|
||||
*/
|
||||
static LogClassifications const All;
|
||||
|
||||
/**
|
||||
* @brief Represents an empty list of classifications.
|
||||
*/
|
||||
static LogClassifications const None;
|
||||
};
|
||||
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Manages an optional contained value, i.e. a value that may or may not be present.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdlib> // for abort
|
||||
@ -16,6 +21,11 @@ namespace Azure { namespace Core {
|
||||
};
|
||||
} // namespace Details
|
||||
|
||||
/**
|
||||
* @brief Manages an optional contained value, i.e. a value that may or may not be present.
|
||||
*
|
||||
* @tparam T A type to represent contained values.
|
||||
*/
|
||||
template <class T> class Nullable {
|
||||
union
|
||||
{
|
||||
@ -27,9 +37,19 @@ namespace Azure { namespace Core {
|
||||
bool m_hasValue;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a #Nullable that represents the absence of value.
|
||||
*/
|
||||
constexpr Nullable() : m_disengaged{}, m_hasValue(false) {}
|
||||
|
||||
/**
|
||||
* @brief Construct a #Nullable having an \p initialValue.
|
||||
*
|
||||
* @param initialValue A non-absent value to initialize with.
|
||||
*/
|
||||
constexpr Nullable(const T& initialValue) : m_value(initialValue), m_hasValue(true) {}
|
||||
|
||||
/// Copy constructor.
|
||||
Nullable(const Nullable& other) noexcept(std::is_nothrow_copy_constructible<T>::value)
|
||||
: m_hasValue(other.m_hasValue)
|
||||
{
|
||||
@ -39,6 +59,7 @@ namespace Azure { namespace Core {
|
||||
}
|
||||
}
|
||||
|
||||
/// Move constructor.
|
||||
Nullable(Nullable&& other) noexcept(std::is_nothrow_move_constructible<T>::value)
|
||||
: m_hasValue(other.m_hasValue)
|
||||
{
|
||||
@ -48,6 +69,9 @@ namespace Azure { namespace Core {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destroy the contained value, if there is one.
|
||||
*/
|
||||
~Nullable()
|
||||
{
|
||||
if (m_hasValue)
|
||||
@ -56,6 +80,9 @@ namespace Azure { namespace Core {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destroy any contained value, if there is one.
|
||||
*/
|
||||
void Reset() noexcept /* enforces termination */
|
||||
{
|
||||
if (m_hasValue)
|
||||
@ -65,6 +92,11 @@ namespace Azure { namespace Core {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Exchange the contents.
|
||||
*
|
||||
* @param other An instance to exchange the contents with.
|
||||
*/
|
||||
// this assumes that swap can't throw if T is nothrow move constructible because
|
||||
// is_nothrow_swappable is added in C++17
|
||||
void Swap(Nullable& other) noexcept(std::is_nothrow_move_constructible<T>::value)
|
||||
@ -91,15 +123,19 @@ namespace Azure { namespace Core {
|
||||
}
|
||||
}
|
||||
|
||||
// Intentionally lowercase to follow the Swappable requirements
|
||||
// https://en.cppreference.com/w/cpp/named_req/Swappable
|
||||
//
|
||||
/**
|
||||
* @brief Invokes #Swap while having a lowercase name that satisfies `swappable` requirements
|
||||
* (see details).
|
||||
*
|
||||
* @details Swappable requirements: https://en.cppreference.com/w/cpp/named_req/Swappable
|
||||
*/
|
||||
friend void swap(Nullable& lhs, Nullable& rhs) noexcept(
|
||||
std::is_nothrow_move_constructible<T>::value)
|
||||
{
|
||||
lhs.Swap(rhs);
|
||||
}
|
||||
|
||||
/// Assignment operator.
|
||||
Nullable& operator=(const Nullable& other)
|
||||
{
|
||||
// this copy and swap may be inefficient for some Ts but
|
||||
@ -108,6 +144,7 @@ namespace Azure { namespace Core {
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assignment operator with move semantics.
|
||||
Nullable& operator=(Nullable&& other) noexcept(std::is_nothrow_move_constructible<T>::value)
|
||||
{
|
||||
// this move and swap may be inefficient for some Ts but
|
||||
@ -116,6 +153,13 @@ namespace Azure { namespace Core {
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assignment operator from another type.
|
||||
*
|
||||
* @tparam U
|
||||
*
|
||||
* @param other
|
||||
*/
|
||||
template <
|
||||
class U = T,
|
||||
typename std::enable_if<
|
||||
@ -148,6 +192,12 @@ namespace Azure { namespace Core {
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct the contained value in-place.
|
||||
*
|
||||
* @detail If this instance already contains a value before the call, the contained value is
|
||||
* destroyed by calling its destructor.
|
||||
*/
|
||||
template <class... U>
|
||||
T& Emplace(U&&... Args) noexcept(std::is_nothrow_constructible<T, U...>::value)
|
||||
{
|
||||
@ -156,8 +206,16 @@ namespace Azure { namespace Core {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check whether a value is contained.
|
||||
*
|
||||
* @return `true` If a value is contained, `false` if value is absent.
|
||||
*/
|
||||
bool HasValue() const noexcept { return m_hasValue; }
|
||||
|
||||
/**
|
||||
* @brief Get the contained value.
|
||||
*/
|
||||
const T& GetValue() const& noexcept
|
||||
{
|
||||
if (!m_hasValue)
|
||||
@ -170,6 +228,9 @@ namespace Azure { namespace Core {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the contained value reference.
|
||||
*/
|
||||
T& GetValue() & noexcept
|
||||
{
|
||||
if (!m_hasValue)
|
||||
@ -182,6 +243,9 @@ namespace Azure { namespace Core {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the contained value (as rvalue reference).
|
||||
*/
|
||||
T&& GetValue() && noexcept
|
||||
{
|
||||
if (!m_hasValue)
|
||||
@ -194,14 +258,21 @@ namespace Azure { namespace Core {
|
||||
return std::move(m_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief `operator bool` on the condition of #HasValue.
|
||||
*/
|
||||
explicit operator bool() const noexcept { return HasValue(); }
|
||||
|
||||
/**
|
||||
* @brief Get the contained value, returns \p other if value is absent.
|
||||
* @param other A value to return when no value is contained.
|
||||
* @return A contained value (when present), or \p other.
|
||||
*/
|
||||
template <
|
||||
class U = T,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<
|
||||
const T&,
|
||||
typename std::remove_cv<T>::type>::value && std::is_convertible<U, T>::value,
|
||||
std::is_convertible<const T&, typename std::remove_cv<T>::type>::value
|
||||
&& std::is_convertible<U, T>::value,
|
||||
int>::type
|
||||
= 0>
|
||||
constexpr typename std::remove_cv<T>::type ValueOr(U&& other) const&
|
||||
@ -214,12 +285,16 @@ namespace Azure { namespace Core {
|
||||
return static_cast<typename std::remove_cv<T>::type>(std::forward<U>(other));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the contained value, returns \p other if value is absent.
|
||||
* @param other A value to return when no value is contained.
|
||||
* @return A contained value (when present), or \p other.
|
||||
*/
|
||||
template <
|
||||
class U = T,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<
|
||||
T,
|
||||
typename std::remove_cv<T>::type>::value && std::is_convertible<U, T>::value,
|
||||
std::is_convertible<T, typename std::remove_cv<T>::type>::value
|
||||
&& std::is_convertible<U, T>::value,
|
||||
int>::type
|
||||
= 0>
|
||||
constexpr typename std::remove_cv<T>::type ValueOr(U&& other) &&
|
||||
|
||||
@ -1,33 +1,72 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Wraps raw HTTP response into a response of a specific type.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <azure/core/http/http.hpp>
|
||||
|
||||
namespace Azure { namespace Core {
|
||||
|
||||
/**
|
||||
* @brief Wraps raw HTTP response into a response of a specific type.
|
||||
*
|
||||
* @tparam T A specific type of value to get from the raw HTTP response type.
|
||||
*/
|
||||
template <class T> class Response {
|
||||
T m_value;
|
||||
std::unique_ptr<Http::RawResponse> m_rawResponse;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Initialize a #Response<T> with an initial value.
|
||||
*
|
||||
* @param initialValue Initial value.
|
||||
* @param rawResponse Raw HTTP response.
|
||||
*/
|
||||
// Require a raw response to create a Response T
|
||||
explicit Response(T initialValue, std::unique_ptr<Http::RawResponse>&& rawResponse)
|
||||
: m_value(std::move(initialValue)), m_rawResponse(std::move(rawResponse))
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get raw HTTP response.
|
||||
*/
|
||||
// Do not give up raw response ownership.
|
||||
Http::RawResponse& GetRawResponse() { return *this->m_rawResponse; }
|
||||
|
||||
/**
|
||||
* @brief Get a pointer to a value of a specific type.
|
||||
*/
|
||||
const T* operator->() const { return &this->m_value; };
|
||||
|
||||
/**
|
||||
* @brief Get a tpointer to a value of a specific type.
|
||||
*/
|
||||
T* operator->() { return &this->m_value; };
|
||||
|
||||
/**
|
||||
* @brief Get value of a specific type.
|
||||
*/
|
||||
T& operator*() { return this->m_value; };
|
||||
|
||||
/**
|
||||
* @brief Get value of a specific type.
|
||||
*/
|
||||
const T& operator*() const { return this->m_value; };
|
||||
|
||||
/**
|
||||
* @brief Get an rvalue reference to the value of a specific type.
|
||||
*/
|
||||
T&& ExtractValue() { return std::move(this->m_value); }
|
||||
|
||||
/**
|
||||
* @brief Get a smaprt pointer rvalue reference to the value of a specific type.
|
||||
*/
|
||||
std::unique_ptr<Http::RawResponse>&& ExtractRawResponse()
|
||||
{
|
||||
return std::move(this->m_rawResponse);
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Universally unique identifier.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
@ -10,7 +15,9 @@
|
||||
#include <utility> // for swap and move
|
||||
|
||||
namespace Azure { namespace Core {
|
||||
|
||||
/**
|
||||
* @brief Universally unique identifier.
|
||||
*/
|
||||
class Uuid {
|
||||
|
||||
private:
|
||||
@ -24,13 +31,13 @@ namespace Azure { namespace Core {
|
||||
static constexpr uint8_t ReservedFuture = 0x00;
|
||||
|
||||
private:
|
||||
Uuid(uint8_t const uuid[UuidSize])
|
||||
{
|
||||
std::memcpy(m_uuid, uuid, UuidSize);
|
||||
}
|
||||
Uuid(uint8_t const uuid[UuidSize]) { std::memcpy(m_uuid, uuid, UuidSize); }
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Gets UUID as a string.
|
||||
* @detail A string is in canonical format (4-2-2-2-6 lowercase hex and dashes only)
|
||||
*/
|
||||
std::string GetUuidString()
|
||||
{
|
||||
// Guid is 36 characters
|
||||
@ -61,7 +68,11 @@ namespace Azure { namespace Core {
|
||||
return std::string(s);
|
||||
}
|
||||
|
||||
static Uuid CreateUuid() {
|
||||
/**
|
||||
* @brief Create a new random UUID.
|
||||
*/
|
||||
static Uuid CreateUuid()
|
||||
{
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Provides version information.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
@ -12,12 +17,27 @@
|
||||
|
||||
namespace Azure { namespace Core {
|
||||
|
||||
/**
|
||||
* @brief Provides version information.
|
||||
*/
|
||||
class Version {
|
||||
public:
|
||||
/// Major numeric identifier.
|
||||
static constexpr int Major = AZURE_CORE_VERSION_MAJOR;
|
||||
|
||||
/// Minor numeric identifier.
|
||||
static constexpr int Minor = AZURE_CORE_VERSION_MINOR;
|
||||
|
||||
/// Patch numeric identifier.
|
||||
static constexpr int Patch = AZURE_CORE_VERSION_PATCH;
|
||||
|
||||
/// Optional pre-release identifier. SDK is in a pre-release state when not empty.
|
||||
static std::string const PreRelease;
|
||||
|
||||
/**
|
||||
* @brief The version in string format used for telemetry following the `semver.org` standard
|
||||
* (https://semver.org).
|
||||
*/
|
||||
static std::string const VersionString();
|
||||
|
||||
private:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user