Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
藤森雅人
sp2txt
Commits
14571fd2
Commit
14571fd2
authored
Jul 29, 2019
by
藤森雅人
Browse files
Initial commit
parents
Changes
208
Hide whitespace changes
Inline
Side-by-side
Too many changes to show.
To preserve performance only
20 of 208+
files are displayed.
Plain diff
Email patch
cpprestsdk_static_tester/vcpkg/include/cpprest/details/basic_types.h
0 → 100644
View file @
14571fd2
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* Platform-dependent type definitions
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#include
"cpprest/details/cpprest_compat.h"
#include
<fstream>
#include
<iostream>
#include
<sstream>
#include
<string>
#ifndef _WIN32
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif
#include
<stdint.h>
#else
#include
<cstdint>
#endif
#include
"cpprest/details/SafeInt3.hpp"
namespace
utility
{
#ifdef _WIN32
#define _UTF16_STRINGS
#endif
// We should be using a 64-bit size type for most situations that do
// not involve specifying the size of a memory allocation or buffer.
typedef
uint64_t
size64_t
;
#ifndef _WIN32
typedef
uint32_t
HRESULT
;
// Needed for PPLX
#endif
#ifdef _UTF16_STRINGS
//
// On Windows, all strings are wide
//
typedef
wchar_t
char_t
;
typedef
std
::
wstring
string_t
;
#define _XPLATSTR(x) L##x
typedef
std
::
wostringstream
ostringstream_t
;
typedef
std
::
wofstream
ofstream_t
;
typedef
std
::
wostream
ostream_t
;
typedef
std
::
wistream
istream_t
;
typedef
std
::
wifstream
ifstream_t
;
typedef
std
::
wistringstream
istringstream_t
;
typedef
std
::
wstringstream
stringstream_t
;
#define ucout std::wcout
#define ucin std::wcin
#define ucerr std::wcerr
#else
//
// On POSIX platforms, all strings are narrow
//
typedef
char
char_t
;
typedef
std
::
string
string_t
;
#define _XPLATSTR(x) x
typedef
std
::
ostringstream
ostringstream_t
;
typedef
std
::
ofstream
ofstream_t
;
typedef
std
::
ostream
ostream_t
;
typedef
std
::
istream
istream_t
;
typedef
std
::
ifstream
ifstream_t
;
typedef
std
::
istringstream
istringstream_t
;
typedef
std
::
stringstream
stringstream_t
;
#define ucout std::cout
#define ucin std::cin
#define ucerr std::cerr
#endif // endif _UTF16_STRINGS
#ifndef _TURN_OFF_PLATFORM_STRING
// The 'U' macro can be used to create a string or character literal of the platform type, i.e. utility::char_t.
// If you are using a library causing conflicts with 'U' macro, it can be turned off by defining the macro
// '_TURN_OFF_PLATFORM_STRING' before including the C++ REST SDK header files, and e.g. use '_XPLATSTR' instead.
#define U(x) _XPLATSTR(x)
#endif // !_TURN_OFF_PLATFORM_STRING
}
// namespace utility
typedef
char
utf8char
;
typedef
std
::
string
utf8string
;
typedef
std
::
stringstream
utf8stringstream
;
typedef
std
::
ostringstream
utf8ostringstream
;
typedef
std
::
ostream
utf8ostream
;
typedef
std
::
istream
utf8istream
;
typedef
std
::
istringstream
utf8istringstream
;
#ifdef _UTF16_STRINGS
typedef
wchar_t
utf16char
;
typedef
std
::
wstring
utf16string
;
typedef
std
::
wstringstream
utf16stringstream
;
typedef
std
::
wostringstream
utf16ostringstream
;
typedef
std
::
wostream
utf16ostream
;
typedef
std
::
wistream
utf16istream
;
typedef
std
::
wistringstream
utf16istringstream
;
#else
typedef
char16_t
utf16char
;
typedef
std
::
u16string
utf16string
;
typedef
std
::
basic_stringstream
<
utf16char
>
utf16stringstream
;
typedef
std
::
basic_ostringstream
<
utf16char
>
utf16ostringstream
;
typedef
std
::
basic_ostream
<
utf16char
>
utf16ostream
;
typedef
std
::
basic_istream
<
utf16char
>
utf16istream
;
typedef
std
::
basic_istringstream
<
utf16char
>
utf16istringstream
;
#endif
#if defined(_WIN32)
// Include on everything except Windows Desktop ARM, unless explicitly excluded.
#if !defined(CPPREST_EXCLUDE_WEBSOCKETS)
#if defined(WINAPI_FAMILY)
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && defined(_M_ARM)
#define CPPREST_EXCLUDE_WEBSOCKETS
#endif
#else
#if defined(_M_ARM)
#define CPPREST_EXCLUDE_WEBSOCKETS
#endif
#endif
#endif
#endif
cpprestsdk_static_tester/vcpkg/include/cpprest/details/cpprest_compat.h
0 → 100644
View file @
14571fd2
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* Standard macros and definitions.
* This header has minimal dependency on windows headers and is safe for use in the public API
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#if defined(_WIN32)
#if _MSC_VER >= 1900
#define CPPREST_NOEXCEPT noexcept
#define CPPREST_CONSTEXPR constexpr
#else
#define CPPREST_NOEXCEPT
#define CPPREST_CONSTEXPR const
#endif // _MSC_VER >= 1900
#define CASABLANCA_UNREFERENCED_PARAMETER(x) (x)
#include
<sal.h>
#else // ^^^ _WIN32 ^^^ // vvv !_WIN32 vvv
#define __declspec(x) __attribute__((x))
#define dllimport
#define novtable
/* no novtable equivalent */
#define __assume(x) \
do \
{ \
if (!(x)) __builtin_unreachable(); \
} while (false)
#define CASABLANCA_UNREFERENCED_PARAMETER(x) (void)x
#define CPPREST_NOEXCEPT noexcept
#define CPPREST_CONSTEXPR constexpr
#include
<assert.h>
#define _ASSERTE(x) assert(x)
// No SAL on non Windows platforms
#include
"cpprest/details/nosal.h"
#if !defined(__cdecl)
#if defined(cdecl)
#define __cdecl __attribute__((cdecl))
#else // ^^^ defined cdecl ^^^ // vvv !defined cdecl vvv
#define __cdecl
#endif // defined cdecl
#endif // not defined __cdecl
#if defined(__ANDROID__)
// This is needed to disable the use of __thread inside the boost library.
// Android does not support thread local storage -- if boost is included
// without this macro defined, it will create references to __tls_get_addr
// which (while able to link) will not be available at runtime and prevent
// the .so from loading.
#if not defined BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION
#define BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION
#endif // not defined BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION
#endif // defined(__ANDROID__)
#ifdef __clang__
#include
<cstdio>
#endif // __clang__
#endif // _WIN32
#ifdef _NO_ASYNCRTIMP
#define _ASYNCRTIMP
#else // ^^^ _NO_ASYNCRTIMP ^^^ // vvv !_NO_ASYNCRTIMP vvv
#ifdef _ASYNCRT_EXPORT
#define _ASYNCRTIMP __declspec(dllexport)
#else // ^^^ _ASYNCRT_EXPORT ^^^ // vvv !_ASYNCRT_EXPORT vvv
#define _ASYNCRTIMP __declspec(dllimport)
#endif // _ASYNCRT_EXPORT
#endif // _NO_ASYNCRTIMP
#ifdef CASABLANCA_DEPRECATION_NO_WARNINGS
#define CASABLANCA_DEPRECATED(x)
#else
#define CASABLANCA_DEPRECATED(x) __declspec(deprecated(x))
#endif // CASABLANCA_DEPRECATION_NO_WARNINGS
cpprestsdk_static_tester/vcpkg/include/cpprest/details/fileio.h
0 → 100644
View file @
14571fd2
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* fileio.h
*
* Asynchronous I/O: stream buffer implementation details
*
* We're going to some lengths to avoid exporting C++ class member functions and implementation details across
* module boundaries, and the factoring requires that we keep the implementation details away from the main header
* files. The supporting functions, which are in this file, use C-like signatures to avoid as many issues as
* possible.
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#ifdef _WIN32
#include
<cstdint>
#endif
#include
"cpprest/details/basic_types.h"
#include
"pplx/pplxtasks.h"
namespace
Concurrency
{
namespace
streams
{
namespace
details
{
/// <summary>
/// A record containing the essential private data members of a file stream,
/// in particular the parts that need to be shared between the public header
/// file and the implementation in the implementation file.
/// </summary>
struct
_file_info
{
_ASYNCRTIMP
_file_info
(
std
::
ios_base
::
openmode
mode
,
size_t
buffer_size
)
:
m_rdpos
(
0
)
,
m_wrpos
(
0
)
,
m_atend
(
false
)
,
m_buffer_size
(
buffer_size
)
,
m_buffer
(
nullptr
)
,
m_bufoff
(
0
)
,
m_bufsize
(
0
)
,
m_buffill
(
0
)
,
m_mode
(
mode
)
{
}
// Positional data
size_t
m_rdpos
;
size_t
m_wrpos
;
bool
m_atend
;
// Input buffer
size_t
m_buffer_size
;
// The intended size of the buffer to read into.
char
*
m_buffer
;
size_t
m_bufoff
;
// File position that the start of the buffer represents.
msl
::
safeint3
::
SafeInt
<
size_t
>
m_bufsize
;
// Buffer allocated size, as actually allocated.
size_t
m_buffill
;
// Amount of file data actually in the buffer
std
::
ios_base
::
openmode
m_mode
;
pplx
::
extensibility
::
recursive_lock_t
m_lock
;
};
/// <summary>
/// This interface provides the necessary callbacks for completion events.
/// </summary>
class
_filestream_callback
{
public:
virtual
void
on_opened
(
_In_
details
::
_file_info
*
)
{}
virtual
void
on_closed
()
{}
virtual
void
on_error
(
const
std
::
exception_ptr
&
)
{}
virtual
void
on_completed
(
size_t
)
{}
protected:
virtual
~
_filestream_callback
()
{}
};
}
// namespace details
}
// namespace streams
}
// namespace Concurrency
extern
"C"
{
/// <summary>
/// Open a file and create a streambuf instance to represent it.
/// </summary>
/// <param name="callback">A pointer to the callback interface to invoke when the file has been opened.</param>
/// <param name="filename">The name of the file to open</param>
/// <param name="mode">A creation mode for the stream buffer</param>
/// <param name="prot">A file protection mode to use for the file stream (not supported on Linux)</param>
/// <returns><c>true</c> if the opening operation could be initiated, <c>false</c> otherwise.</returns>
/// <remarks>
/// True does not signal that the file will eventually be successfully opened, just that the process was started.
/// </remarks>
#if !defined(__cplusplus_winrt)
_ASYNCRTIMP
bool
__cdecl
_open_fsb_str
(
_In_
concurrency
::
streams
::
details
::
_filestream_callback
*
callback
,
const
utility
::
char_t
*
filename
,
std
::
ios_base
::
openmode
mode
,
int
prot
);
#endif
/// <summary>
/// Create a streambuf instance to represent a WinRT file.
/// </summary>
/// <param name="callback">A pointer to the callback interface to invoke when the file has been opened.</param>
/// <param name="file">The file object</param>
/// <param name="mode">A creation mode for the stream buffer</param>
/// <returns><c>true</c> if the opening operation could be initiated, <c>false</c> otherwise.</returns>
/// <remarks>
/// True does not signal that the file will eventually be successfully opened, just that the process was started.
/// This is only available for WinRT.
/// </remarks>
#if defined(__cplusplus_winrt)
_ASYNCRTIMP
bool
__cdecl
_open_fsb_stf_str
(
_In_
concurrency
::
streams
::
details
::
_filestream_callback
*
callback
,
::
Windows
::
Storage
::
StorageFile
^
file
,
std
::
ios_base
::
openmode
mode
,
int
prot
);
#endif
/// <summary>
/// Close a file stream buffer.
/// </summary>
/// <param name="info">The file info record of the file</param>
/// <param name="callback">A pointer to the callback interface to invoke when the file has been opened.</param>
/// <returns><c>true</c> if the closing operation could be initiated, <c>false</c> otherwise.</returns>
/// <remarks>
/// True does not signal that the file will eventually be successfully closed, just that the process was started.
/// </remarks>
_ASYNCRTIMP
bool
__cdecl
_close_fsb_nolock
(
_In_
concurrency
::
streams
::
details
::
_file_info
**
info
,
_In_
concurrency
::
streams
::
details
::
_filestream_callback
*
callback
);
_ASYNCRTIMP
bool
__cdecl
_close_fsb
(
_In_
concurrency
::
streams
::
details
::
_file_info
**
info
,
_In_
concurrency
::
streams
::
details
::
_filestream_callback
*
callback
);
/// <summary>
/// Write data from a buffer into the file stream.
/// </summary>
/// <param name="info">The file info record of the file</param>
/// <param name="callback">A pointer to the callback interface to invoke when the write request is
/// completed.</param> <param name="ptr">A pointer to a buffer where the data should be placed</param> <param
/// name="count">The size (in characters) of the buffer</param> <returns>0 if the read request is still outstanding,
/// -1 if the request failed, otherwise the size of the data read into the buffer</returns>
_ASYNCRTIMP
size_t
__cdecl
_putn_fsb
(
_In_
concurrency
::
streams
::
details
::
_file_info
*
info
,
_In_
concurrency
::
streams
::
details
::
_filestream_callback
*
callback
,
const
void
*
ptr
,
size_t
count
,
size_t
char_size
);
/// <summary>
/// Read data from a file stream into a buffer
/// </summary>
/// <param name="info">The file info record of the file</param>
/// <param name="callback">A pointer to the callback interface to invoke when the write request is
/// completed.</param> <param name="ptr">A pointer to a buffer where the data should be placed</param> <param
/// name="count">The size (in characters) of the buffer</param> <returns>0 if the read request is still outstanding,
/// -1 if the request failed, otherwise the size of the data read into the buffer</returns>
_ASYNCRTIMP
size_t
__cdecl
_getn_fsb
(
_In_
concurrency
::
streams
::
details
::
_file_info
*
info
,
_In_
concurrency
::
streams
::
details
::
_filestream_callback
*
callback
,
_Out_writes_
(
count
)
void
*
ptr
,
_In_
size_t
count
,
size_t
char_size
);
/// <summary>
/// Flush all buffered data to the underlying file.
/// </summary>
/// <param name="info">The file info record of the file</param>
/// <param name="callback">A pointer to the callback interface to invoke when the write request is
/// completed.</param> <returns><c>true</c> if the request was initiated</returns>
_ASYNCRTIMP
bool
__cdecl
_sync_fsb
(
_In_
concurrency
::
streams
::
details
::
_file_info
*
info
,
_In_
concurrency
::
streams
::
details
::
_filestream_callback
*
callback
);
/// <summary>
/// Get the size of the underlying file.
/// </summary>
/// <param name="info">The file info record of the file</param>
/// <returns>The file size</returns>
_ASYNCRTIMP
utility
::
size64_t
__cdecl
_get_size
(
_In_
concurrency
::
streams
::
details
::
_file_info
*
info
,
size_t
char_size
);
/// <summary>
/// Adjust the internal buffers and pointers when the application seeks to a new read location in the stream.
/// </summary>
/// <param name="info">The file info record of the file</param>
/// <param name="pos">The new position (offset from the start) in the file stream</param>
/// <returns><c>true</c> if the request was initiated</returns>
_ASYNCRTIMP
size_t
__cdecl
_seekrdpos_fsb
(
_In_
concurrency
::
streams
::
details
::
_file_info
*
info
,
size_t
pos
,
size_t
char_size
);
/// <summary>
/// Adjust the internal buffers and pointers when the application seeks to a new read location in the stream.
/// </summary>
/// <param name="info">The file info record of the file</param>
/// <param name="pos">The new position (offset from the start) in the file stream</param>
/// <returns><c>true</c> if the request was initiated</returns>
_ASYNCRTIMP
size_t
__cdecl
_seekrdtoend_fsb
(
_In_
concurrency
::
streams
::
details
::
_file_info
*
info
,
int64_t
offset
,
size_t
char_size
);
/// <summary>
/// Adjust the internal buffers and pointers when the application seeks to a new write location in the stream.
/// </summary>
/// <param name="info">The file info record of the file</param>
/// <param name="pos">The new position (offset from the start) in the file stream</param>
/// <returns><c>true</c> if the request was initiated</returns>
_ASYNCRTIMP
size_t
__cdecl
_seekwrpos_fsb
(
_In_
concurrency
::
streams
::
details
::
_file_info
*
info
,
size_t
pos
,
size_t
char_size
);
}
cpprestsdk_static_tester/vcpkg/include/cpprest/details/http_constants.dat
0 → 100644
View file @
14571fd2
#ifdef _METHODS
DAT(GET, _XPLATSTR("GET"))
DAT(POST, _XPLATSTR("POST"))
DAT(PUT, _XPLATSTR("PUT"))
DAT(DEL, _XPLATSTR("DELETE"))
DAT(HEAD, _XPLATSTR("HEAD"))
DAT(OPTIONS, _XPLATSTR("OPTIONS"))
DAT(TRCE, _XPLATSTR("TRACE"))
DAT(CONNECT, _XPLATSTR("CONNECT"))
DAT(MERGE, _XPLATSTR("MERGE"))
DAT(PATCH, _XPLATSTR("PATCH"))
#endif
#ifdef _PHRASES
DAT(Continue, 100, _XPLATSTR("Continue"))
DAT(SwitchingProtocols, 101, _XPLATSTR("Switching Protocols"))
DAT(OK, 200, _XPLATSTR("OK"))
DAT(Created, 201, _XPLATSTR("Created"))
DAT(Accepted, 202, _XPLATSTR("Accepted"))
DAT(NonAuthInfo, 203, _XPLATSTR("Non-Authoritative Information"))
DAT(NoContent, 204, _XPLATSTR("No Content"))
DAT(ResetContent, 205, _XPLATSTR("Reset Content"))
DAT(PartialContent, 206, _XPLATSTR("Partial Content"))
DAT(MultiStatus, 207, _XPLATSTR("Multi-Status"))
DAT(AlreadyReported, 208, _XPLATSTR("Already Reported"))
DAT(IMUsed, 226, _XPLATSTR("IM Used"))
DAT(MultipleChoices, 300, _XPLATSTR("Multiple Choices"))
DAT(MovedPermanently, 301, _XPLATSTR("Moved Permanently"))
DAT(Found, 302, _XPLATSTR("Found"))
DAT(SeeOther, 303, _XPLATSTR("See Other"))
DAT(NotModified, 304, _XPLATSTR("Not Modified"))
DAT(UseProxy, 305, _XPLATSTR("Use Proxy"))
DAT(TemporaryRedirect, 307, _XPLATSTR("Temporary Redirect"))
DAT(PermanentRedirect, 308, _XPLATSTR("Permanent Redirect"))
DAT(BadRequest, 400, _XPLATSTR("Bad Request"))
DAT(Unauthorized, 401, _XPLATSTR("Unauthorized"))
DAT(PaymentRequired, 402, _XPLATSTR("Payment Required"))
DAT(Forbidden, 403, _XPLATSTR("Forbidden"))
DAT(NotFound, 404, _XPLATSTR("Not Found"))
DAT(MethodNotAllowed, 405, _XPLATSTR("Method Not Allowed"))
DAT(NotAcceptable, 406, _XPLATSTR("Not Acceptable"))
DAT(ProxyAuthRequired, 407, _XPLATSTR("Proxy Authentication Required"))
DAT(RequestTimeout, 408, _XPLATSTR("Request Time-out"))
DAT(Conflict, 409, _XPLATSTR("Conflict"))
DAT(Gone, 410, _XPLATSTR("Gone"))
DAT(LengthRequired, 411, _XPLATSTR("Length Required"))
DAT(PreconditionFailed, 412, _XPLATSTR("Precondition Failed"))
DAT(RequestEntityTooLarge, 413, _XPLATSTR("Request Entity Too Large"))
DAT(RequestUriTooLarge, 414, _XPLATSTR("Request Uri Too Large"))
DAT(UnsupportedMediaType, 415, _XPLATSTR("Unsupported Media Type"))
DAT(RangeNotSatisfiable, 416, _XPLATSTR("Requested range not satisfiable"))
DAT(ExpectationFailed, 417, _XPLATSTR("Expectation Failed"))
DAT(MisdirectedRequest, 421, _XPLATSTR("Misdirected Request"))
DAT(UnprocessableEntity, 422, _XPLATSTR("Unprocessable Entity"))
DAT(Locked, 423, _XPLATSTR("Locked"))
DAT(FailedDependency, 424, _XPLATSTR("Failed Dependency"))
DAT(UpgradeRequired, 426, _XPLATSTR("Upgrade Required"))
DAT(PreconditionRequired, 428, _XPLATSTR("Precondition Required"))
DAT(TooManyRequests, 429, _XPLATSTR("Too Many Requests"))
DAT(RequestHeaderFieldsTooLarge, 431, _XPLATSTR("Request Header Fields Too Large"))
DAT(UnavailableForLegalReasons, 451, _XPLATSTR("Unavailable For Legal Reasons"))
DAT(InternalError, 500, _XPLATSTR("Internal Error"))
DAT(NotImplemented, 501, _XPLATSTR("Not Implemented"))
DAT(BadGateway, 502, _XPLATSTR("Bad Gateway"))
DAT(ServiceUnavailable, 503, _XPLATSTR("Service Unavailable"))
DAT(GatewayTimeout, 504, _XPLATSTR("Gateway Time-out"))
DAT(HttpVersionNotSupported, 505, _XPLATSTR("HTTP Version not supported"))
DAT(VariantAlsoNegotiates, 506, _XPLATSTR("Variant Also Negotiates"))
DAT(InsufficientStorage, 507, _XPLATSTR("Insufficient Storage"))
DAT(LoopDetected, 508, _XPLATSTR("Loop Detected"))
DAT(NotExtended, 510, _XPLATSTR("Not Extended"))
DAT(NetworkAuthenticationRequired, 511, _XPLATSTR("Network Authentication Required"))
#endif // _PHRASES
#ifdef _HEADER_NAMES
DAT(accept, "Accept")
DAT(accept_charset, "Accept-Charset")
DAT(accept_encoding, "Accept-Encoding")
DAT(accept_language, "Accept-Language")
DAT(accept_ranges, "Accept-Ranges")
DAT(access_control_allow_origin, "Access-Control-Allow-Origin")
DAT(age, "Age")
DAT(allow, "Allow")
DAT(authorization, "Authorization")
DAT(cache_control, "Cache-Control")
DAT(connection, "Connection")
DAT(content_encoding, "Content-Encoding")
DAT(content_language, "Content-Language")
DAT(content_length, "Content-Length")
DAT(content_location, "Content-Location")
DAT(content_md5, "Content-MD5")
DAT(content_range, "Content-Range")
DAT(content_type, "Content-Type")
DAT(content_disposition, "Content-Disposition")
DAT(date, "Date")
DAT(etag, "ETag")
DAT(expect, "Expect")
DAT(expires, "Expires")
DAT(from, "From")
DAT(host, "Host")
DAT(if_match, "If-Match")
DAT(if_modified_since, "If-Modified-Since")
DAT(if_none_match, "If-None-Match")
DAT(if_range, "If-Range")
DAT(if_unmodified_since, "If-Unmodified-Since")
DAT(last_modified, "Last-Modified")
DAT(location, "Location")
DAT(max_forwards, "Max-Forwards")
DAT(pragma, "Pragma")
DAT(proxy_authenticate, "Proxy-Authenticate")
DAT(proxy_authorization, "Proxy-Authorization")
DAT(range, "Range")
DAT(referer, "Referer")
DAT(retry_after, "Retry-After")
DAT(server, "Server")
DAT(te, "TE")
DAT(trailer, "Trailer")
DAT(transfer_encoding, "Transfer-Encoding")
DAT(upgrade, "Upgrade")
DAT(user_agent, "User-Agent")
DAT(vary, "Vary")
DAT(via, "Via")
DAT(warning, "Warning")
DAT(www_authenticate, "WWW-Authenticate")
#endif // _HEADER_NAMES
#ifdef _MIME_TYPES
DAT(application_atom_xml, "application/atom+xml")
DAT(application_http, "application/http")
DAT(application_javascript, "application/javascript")
DAT(application_json, "application/json")
DAT(application_xjson, "application/x-json")
DAT(application_octetstream, "application/octet-stream")
DAT(application_x_www_form_urlencoded, "application/x-www-form-urlencoded")
DAT(multipart_form_data, "multipart/form-data")
DAT(boundary, "boundary")
DAT(form_data, "form-data")
DAT(application_xjavascript, "application/x-javascript")
DAT(application_xml, "application/xml")
DAT(message_http, "message/http")
DAT(text, "text")
DAT(text_javascript, "text/javascript")
DAT(text_json, "text/json")
DAT(text_plain, "text/plain")
DAT(text_plain_utf16, "text/plain; charset=utf-16")
DAT(text_plain_utf16le, "text/plain; charset=utf-16le")
DAT(text_plain_utf8, "text/plain; charset=utf-8")
DAT(text_xjavascript, "text/x-javascript")
DAT(text_xjson, "text/x-json")
#endif // _MIME_TYPES
#ifdef _CHARSET_TYPES
DAT(ascii, "ascii")
DAT(usascii, "us-ascii")
DAT(latin1, "iso-8859-1")
DAT(utf8, "utf-8")
DAT(utf16, "utf-16")
DAT(utf16le, "utf-16le")
DAT(utf16be, "utf-16be")
#endif // _CHARSET_TYPES
#ifdef _OAUTH1_METHODS
DAT(hmac_sha1, _XPLATSTR("HMAC-SHA1"))
DAT(plaintext, _XPLATSTR("PLAINTEXT"))
#endif // _OAUTH1_METHODS
#ifdef _OAUTH1_STRINGS
DAT(callback, "oauth_callback")
DAT(callback_confirmed, "oauth_callback_confirmed")
DAT(consumer_key, "oauth_consumer_key")
DAT(nonce, "oauth_nonce")
DAT(realm, "realm") // NOTE: No "oauth_" prefix.
DAT(signature, "oauth_signature")
DAT(signature_method, "oauth_signature_method")
DAT(timestamp, "oauth_timestamp")
DAT(token, "oauth_token")
DAT(token_secret, "oauth_token_secret")
DAT(verifier, "oauth_verifier")
DAT(version, "oauth_version")
#endif // _OAUTH1_STRINGS
#ifdef _OAUTH2_STRINGS
DAT(access_token, "access_token")
DAT(authorization_code, "authorization_code")
DAT(bearer, "bearer")
DAT(client_id, "client_id")
DAT(client_secret, "client_secret")
DAT(code, "code")
DAT(expires_in, "expires_in")
DAT(grant_type, "grant_type")
DAT(redirect_uri, "redirect_uri")
DAT(refresh_token, "refresh_token")
DAT(response_type, "response_type")
DAT(scope, "scope")
DAT(state, "state")
DAT(token, "token")
DAT(token_type, "token_type")
#endif // _OAUTH2_STRINGS
cpprestsdk_static_tester/vcpkg/include/cpprest/details/http_helpers.h
0 → 100644
View file @
14571fd2
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* Implementation Details of the http.h layer of messaging
*
* Functions and types for interoperating with http.h from modern C++
* This file includes windows definitions and should not be included in a public header
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#include
"cpprest/details/basic_types.h"
#include
"cpprest/http_msg.h"
namespace
web
{
namespace
http
{
namespace
details
{
namespace
chunked_encoding
{
// Transfer-Encoding: chunked support
static
const
size_t
additional_encoding_space
=
12
;
static
const
size_t
data_offset
=
additional_encoding_space
-
2
;
// Add the data necessary for properly sending data with transfer-encoding: chunked.
//
// There are up to 12 additional bytes needed for each chunk:
//
// The last chunk requires 5 bytes, and is fixed.
// All other chunks require up to 8 bytes for the length, and four for the two CRLF
// delimiters.
//
_ASYNCRTIMP
size_t
__cdecl
add_chunked_delimiters
(
_Out_writes_
(
buffer_size
)
uint8_t
*
data
,
_In_
size_t
buffer_size
,
size_t
bytes_read
);
}
// namespace chunked_encoding
}
// namespace details
}
// namespace http
}
// namespace web
cpprestsdk_static_tester/vcpkg/include/cpprest/details/http_server.h
0 → 100644
View file @
14571fd2
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* HTTP Library: interface to implement HTTP server to service http_listeners.
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#if _WIN32_WINNT < _WIN32_WINNT_VISTA
#error "Error: http server APIs are not supported in XP"
#endif //_WIN32_WINNT < _WIN32_WINNT_VISTA
#include
"cpprest/http_listener.h"
namespace
web
{
namespace
http
{
namespace
experimental
{
namespace
details
{
/// <summary>
/// Interface http listeners interact with for receiving and responding to http requests.
/// </summary>
class
http_server
{
public:
/// <summary>
/// Release any held resources.
/// </summary>
virtual
~
http_server
()
{};
/// <summary>
/// Start listening for incoming requests.
/// </summary>
virtual
pplx
::
task
<
void
>
start
()
=
0
;
/// <summary>
/// Registers an http listener.
/// </summary>
virtual
pplx
::
task
<
void
>
register_listener
(
_In_
web
::
http
::
experimental
::
listener
::
details
::
http_listener_impl
*
pListener
)
=
0
;
/// <summary>
/// Unregisters an http listener.
/// </summary>
virtual
pplx
::
task
<
void
>
unregister_listener
(
_In_
web
::
http
::
experimental
::
listener
::
details
::
http_listener_impl
*
pListener
)
=
0
;
/// <summary>
/// Stop processing and listening for incoming requests.
/// </summary>
virtual
pplx
::
task
<
void
>
stop
()
=
0
;
/// <summary>
/// Asynchronously sends the specified http response.
/// </summary>
/// <param name="response">The http_response to send.</param>
/// <returns>A operation which is completed once the response has been sent.</returns>
virtual
pplx
::
task
<
void
>
respond
(
http
::
http_response
response
)
=
0
;
};
}
// namespace details
}
// namespace experimental
}
// namespace http
}
// namespace web
cpprestsdk_static_tester/vcpkg/include/cpprest/details/http_server_api.h
0 → 100644
View file @
14571fd2
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* HTTP Library: exposes the entry points to the http server transport apis.
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#if _WIN32_WINNT < _WIN32_WINNT_VISTA
#error "Error: http server APIs are not supported in XP"
#endif //_WIN32_WINNT < _WIN32_WINNT_VISTA
#include
"cpprest/http_listener.h"
#include
<memory>
namespace
web
{
namespace
http
{
namespace
experimental
{
namespace
details
{
class
http_server
;
/// <summary>
/// Singleton class used to register for http requests and send responses.
///
/// The lifetime is tied to http listener registration. When the first listener registers an instance is created
/// and when the last one unregisters the receiver stops and is destroyed. It can be started back up again if
/// listeners are again registered.
/// </summary>
class
http_server_api
{
public:
/// <summary>
/// Returns whether or not any listeners are registered.
/// </summary>
static
bool
__cdecl
has_listener
();
/// <summary>
/// Registers a HTTP server API.
/// </summary>
static
void
__cdecl
register_server_api
(
std
::
unique_ptr
<
http_server
>
server_api
);
/// <summary>
/// Clears the http server API.
/// </summary>
static
void
__cdecl
unregister_server_api
();
/// <summary>
/// Registers a listener for HTTP requests and starts receiving.
/// </summary>
static
pplx
::
task
<
void
>
__cdecl
register_listener
(
_In_
web
::
http
::
experimental
::
listener
::
details
::
http_listener_impl
*
pListener
);
/// <summary>
/// Unregisters the given listener and stops listening for HTTP requests.
/// </summary>
static
pplx
::
task
<
void
>
__cdecl
unregister_listener
(
_In_
web
::
http
::
experimental
::
listener
::
details
::
http_listener_impl
*
pListener
);
/// <summary>
/// Gets static HTTP server API. Could be null if no registered listeners.
/// </summary>
static
http_server
*
__cdecl
server_api
();
private:
/// Used to lock access to the server api registration
static
pplx
::
extensibility
::
critical_section_t
s_lock
;
/// Registers a server API set -- this assumes the lock has already been taken
static
void
unsafe_register_server_api
(
std
::
unique_ptr
<
http_server
>
server_api
);
// Static instance of the HTTP server API.
static
std
::
unique_ptr
<
http_server
>
s_server_api
;
/// Number of registered listeners;
static
pplx
::
details
::
atomic_long
s_registrations
;
// Static only class. No creation.
http_server_api
();
};
}
// namespace details
}
// namespace experimental
}
// namespace http
}
// namespace web
cpprestsdk_static_tester/vcpkg/include/cpprest/details/nosal.h
0 → 100644
View file @
14571fd2
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
***/
#pragma once
// selected MS SAL annotations
#ifdef _In_
#undef _In_
#endif
#define _In_
#ifdef _Inout_
#undef _Inout_
#endif
#define _Inout_
#ifdef _Out_
#undef _Out_
#endif
#define _Out_
#ifdef _In_z_
#undef _In_z_
#endif
#define _In_z_
#ifdef _Out_z_
#undef _Out_z_
#endif
#define _Out_z_
#ifdef _Inout_z_
#undef _Inout_z_
#endif
#define _Inout_z_
#ifdef _In_opt_
#undef _In_opt_
#endif
#define _In_opt_
#ifdef _Out_opt_
#undef _Out_opt_
#endif
#define _Out_opt_
#ifdef _Inout_opt_
#undef _Inout_opt_
#endif
#define _Inout_opt_
#ifdef _Out_writes_
#undef _Out_writes_
#endif
#define _Out_writes_(x)
#ifdef _Out_writes_opt_
#undef _Out_writes_opt_
#endif
#define _Out_writes_opt_(x)
#ifdef _In_reads_
#undef _In_reads_
#endif
#define _In_reads_(x)
#ifdef _Inout_updates_bytes_
#undef _Inout_updates_bytes_
#endif
#define _Inout_updates_bytes_(x)
cpprestsdk_static_tester/vcpkg/include/cpprest/details/resource.h
0 → 100644
View file @
14571fd2
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by Resource.rc
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
cpprestsdk_static_tester/vcpkg/include/cpprest/details/web_utilities.h
0 → 100644
View file @
14571fd2
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* utility classes used by the different web:: clients
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#include
"cpprest/asyncrt_utils.h"
#include
"cpprest/uri.h"
namespace
web
{
namespace
details
{
class
zero_memory_deleter
{
public:
_ASYNCRTIMP
void
operator
()(
::
utility
::
string_t
*
data
)
const
;
};
typedef
std
::
unique_ptr
<::
utility
::
string_t
,
zero_memory_deleter
>
plaintext_string
;
#if defined(_WIN32) && !defined(CPPREST_TARGET_XP)
#if defined(__cplusplus_winrt)
class
winrt_encryption
{
public:
winrt_encryption
()
{}
_ASYNCRTIMP
winrt_encryption
(
const
std
::
wstring
&
data
);
_ASYNCRTIMP
plaintext_string
decrypt
()
const
;
private:
::
pplx
::
task
<
Windows
::
Storage
::
Streams
::
IBuffer
^>
m_buffer
;
};
#else
class
win32_encryption
{
public:
win32_encryption
()
{}
_ASYNCRTIMP
win32_encryption
(
const
std
::
wstring
&
data
);
_ASYNCRTIMP
~
win32_encryption
();
_ASYNCRTIMP
plaintext_string
decrypt
()
const
;
private:
std
::
vector
<
char
>
m_buffer
;
size_t
m_numCharacters
;
};
#endif
#endif
}
// namespace details
/// <summary>
/// Represents a set of user credentials (user name and password) to be used
/// for authentication.
/// </summary>
class
credentials
{
public:
/// <summary>
/// Constructs an empty set of credentials without a user name or password.
/// </summary>
credentials
()
{}
/// <summary>
/// Constructs credentials from given user name and password.
/// </summary>
/// <param name="username">User name as a string.</param>
/// <param name="password">Password as a string.</param>
credentials
(
utility
::
string_t
username
,
const
utility
::
string_t
&
password
)
:
m_username
(
std
::
move
(
username
)),
m_password
(
password
)
{
}
/// <summary>
/// The user name associated with the credentials.
/// </summary>
/// <returns>A string containing the user name.</returns>
const
utility
::
string_t
&
username
()
const
{
return
m_username
;
}
/// <summary>
/// The password for the user name associated with the credentials.
/// </summary>
/// <returns>A string containing the password.</returns>
CASABLANCA_DEPRECATED
(
"This API is deprecated for security reasons to avoid unnecessary password copies stored in plaintext."
)
utility
::
string_t
password
()
const
{
#if defined(_WIN32) && !defined(CPPREST_TARGET_XP)
return
utility
::
string_t
(
*
m_password
.
decrypt
());
#else
return
m_password
;
#endif
}
/// <summary>
/// Checks if credentials have been set
/// </summary>
/// <returns><c>true</c> if user name and password is set, <c>false</c> otherwise.</returns>
bool
is_set
()
const
{
return
!
m_username
.
empty
();
}
details
::
plaintext_string
_internal_decrypt
()
const
{
// Encryption APIs not supported on XP
#if defined(_WIN32) && !defined(CPPREST_TARGET_XP)
return
m_password
.
decrypt
();
#else
return
details
::
plaintext_string
(
new
::
utility
::
string_t
(
m_password
));
#endif
}
private:
::
utility
::
string_t
m_username
;
#if defined(_WIN32) && !defined(CPPREST_TARGET_XP)
#if defined(__cplusplus_winrt)
details
::
winrt_encryption
m_password
;
#else
details
::
win32_encryption
m_password
;
#endif
#else
::
utility
::
string_t
m_password
;
#endif
};
/// <summary>
/// web_proxy represents the concept of the web proxy, which can be auto-discovered,
/// disabled, or specified explicitly by the user.
/// </summary>
class
web_proxy
{
enum
web_proxy_mode_internal
{
use_default_
,
use_auto_discovery_
,
disabled_
,
user_provided_
};
public:
enum
web_proxy_mode
{
use_default
=
use_default_
,
use_auto_discovery
=
use_auto_discovery_
,
disabled
=
disabled_
};
/// <summary>
/// Constructs a proxy with the default settings.
/// </summary>
web_proxy
()
:
m_address
(
_XPLATSTR
(
""
)),
m_mode
(
use_default_
)
{}
/// <summary>
/// Creates a proxy with specified mode.
/// </summary>
/// <param name="mode">Mode to use.</param>
web_proxy
(
web_proxy_mode
mode
)
:
m_address
(
_XPLATSTR
(
""
)),
m_mode
(
static_cast
<
web_proxy_mode_internal
>
(
mode
))
{}
/// <summary>
/// Creates a proxy explicitly with provided address.
/// </summary>
/// <param name="address">Proxy URI to use.</param>
web_proxy
(
uri
address
)
:
m_address
(
address
),
m_mode
(
user_provided_
)
{}
/// <summary>
/// Gets this proxy's URI address. Returns an empty URI if not explicitly set by user.
/// </summary>
/// <returns>A reference to this proxy's URI.</returns>
const
uri
&
address
()
const
{
return
m_address
;
}
/// <summary>
/// Gets the credentials used for authentication with this proxy.
/// </summary>
/// <returns>Credentials to for this proxy.</returns>
const
web
::
credentials
&
credentials
()
const
{
return
m_credentials
;
}
/// <summary>
/// Sets the credentials to use for authentication with this proxy.
/// </summary>
/// <param name="cred">Credentials to use for this proxy.</param>
void
set_credentials
(
web
::
credentials
cred
)
{
if
(
m_mode
==
disabled_
)
{
throw
std
::
invalid_argument
(
"Cannot attach credentials to a disabled proxy"
);
}
m_credentials
=
std
::
move
(
cred
);
}
/// <summary>
/// Checks if this proxy was constructed with default settings.
/// </summary>
/// <returns>True if default, false otherwise.</param>
bool
is_default
()
const
{
return
m_mode
==
use_default_
;
}
/// <summary>
/// Checks if using a proxy is disabled.
/// </summary>
/// <returns>True if disabled, false otherwise.</returns>
bool
is_disabled
()
const
{
return
m_mode
==
disabled_
;
}
/// <summary>
/// Checks if the auto discovery protocol, WPAD, is to be used.
/// </summary>
/// <returns>True if auto discovery enabled, false otherwise.</returns>
bool
is_auto_discovery
()
const
{
return
m_mode
==
use_auto_discovery_
;
}
/// <summary>
/// Checks if a proxy address is explicitly specified by the user.
/// </summary>
/// <returns>True if a proxy address was explicitly specified, false otherwise.</returns>
bool
is_specified
()
const
{
return
m_mode
==
user_provided_
;
}
private:
web
::
uri
m_address
;
web_proxy_mode_internal
m_mode
;
web
::
credentials
m_credentials
;
};
}
// namespace web
cpprestsdk_static_tester/vcpkg/include/cpprest/filestream.h
0 → 100644
View file @
14571fd2
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* Asynchronous File streams
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#ifndef CASA_FILE_STREAMS_H
#define CASA_FILE_STREAMS_H
#include
"cpprest/astreambuf.h"
#include
"cpprest/details/fileio.h"
#include
"cpprest/streams.h"
#include
<assert.h>
#ifndef _CONCRT_H
#ifndef _LWRCASE_CNCRRNCY
#define _LWRCASE_CNCRRNCY
// Note to reader: we're using lower-case namespace names everywhere, but the 'Concurrency' namespace
// is capitalized for historical reasons. The alias let's us pretend that style issue doesn't exist.
namespace
Concurrency
{
}
namespace
concurrency
=
Concurrency
;
#endif
#endif
namespace
Concurrency
{
namespace
streams
{
// Forward declarations
template
<
typename
_CharType
>
class
file_buffer
;
namespace
details
{
// This operation queue is NOT thread safe
class
async_operation_queue
{
pplx
::
task
<
void
>
m_lastOperation
;
public:
async_operation_queue
()
{
m_lastOperation
=
pplx
::
task_from_result
();
}
// It only accepts functors that take no argument and return pplx::task<T>
// This function may execute op inline, thus it could throw immediately
template
<
typename
Func
>
auto
enqueue_operation
(
Func
&&
op
)
->
decltype
(
op
())
{
decltype
(
op
())
res
;
// res is task<T> , which always has default constructor
if
(
m_lastOperation
.
is_done
())
{
res
=
op
();
// Exceptions are expected to be thrown directly without catching
if
(
res
.
is_done
())
return
res
;
}
else
{
res
=
m_lastOperation
.
then
([
=
]
{
return
op
();
// It will cause task unwrapping
});
}
m_lastOperation
=
res
.
then
([
&
](
decltype
(
op
()))
{
// This empty task is necessary for keeping the rest of the operations on the list running
// even when the previous operation gets error.
// Don't observe exception here.
});
return
res
;
}
void
wait
()
const
{
m_lastOperation
.
wait
();
}
};
/// <summary>
/// Private stream buffer implementation for file streams.
/// The class itself should not be used in application code, it is used by the stream definitions farther down in the
/// header file.
/// </summary>
template
<
typename
_CharType
>
class
basic_file_buffer
:
public
details
::
streambuf_state_manager
<
_CharType
>
{
public:
typedef
typename
basic_streambuf
<
_CharType
>::
traits
traits
;
typedef
typename
basic_streambuf
<
_CharType
>::
int_type
int_type
;
typedef
typename
basic_streambuf
<
_CharType
>::
pos_type
pos_type
;
typedef
typename
basic_streambuf
<
_CharType
>::
off_type
off_type
;
virtual
~
basic_file_buffer
()
{
if
(
this
->
can_read
())
{
this
->
_close_read
().
wait
();
}
if
(
this
->
can_write
())
{
this
->
_close_write
().
wait
();
}
}
protected:
/// <summary>
/// <c>can_seek</c> is used to determine whether a stream buffer supports seeking.
/// </summary>
virtual
bool
can_seek
()
const
{
return
this
->
is_open
();
}
/// <summary>
/// <c>has_size<c/> is used to determine whether a stream buffer supports size().
/// </summary>
virtual
bool
has_size
()
const
{
return
this
->
is_open
();
}
virtual
utility
::
size64_t
size
()
const
{
if
(
!
this
->
is_open
())
return
0
;
return
_get_size
(
m_info
,
sizeof
(
_CharType
));
}
/// <summary>
/// Gets the stream buffer size, if one has been set.
/// </summary>
/// <param name="direction">The direction of buffering (in or out)</param>
/// <remarks>An implementation that does not support buffering will always return '0'.</remarks>
virtual
size_t
buffer_size
(
std
::
ios_base
::
openmode
direction
=
std
::
ios_base
::
in
)
const
{
if
(
direction
==
std
::
ios_base
::
in
)
return
m_info
->
m_buffer_size
;
else
return
0
;
}
/// <summary>
/// Sets the stream buffer implementation to buffer or not buffer.
/// </summary>
/// <param name="size">The size to use for internal buffering, 0 if no buffering should be done.</param>
/// <param name="direction">The direction of buffering (in or out)</param>
/// <remarks>An implementation that does not support buffering will silently ignore calls to this function and it
/// will not have
/// any effect on what is returned by subsequent calls to buffer_size().</remarks>
virtual
void
set_buffer_size
(
size_t
size
,
std
::
ios_base
::
openmode
direction
=
std
::
ios_base
::
in
)
{
if
(
direction
==
std
::
ios_base
::
out
)
return
;
m_info
->
m_buffer_size
=
size
;
if
(
size
==
0
&&
m_info
->
m_buffer
!=
nullptr
)
{
delete
m_info
->
m_buffer
;
m_info
->
m_buffer
=
nullptr
;
}
}
/// <summary>
/// For any input stream, <c>in_avail</c> returns the number of characters that are immediately available
/// to be consumed without blocking. May be used in conjunction with <cref="::sbumpc method"/> to read data without
/// incurring the overhead of using tasks.
/// </summary>
virtual
size_t
in_avail
()
const
{
pplx
::
extensibility
::
scoped_recursive_lock_t
lck
(
m_info
->
m_lock
);
return
_in_avail_unprot
();
}
size_t
_in_avail_unprot
()
const
{
if
(
!
this
->
is_open
())
return
0
;
if
(
m_info
->
m_buffer
==
nullptr
||
m_info
->
m_buffill
==
0
)
return
0
;
if
(
m_info
->
m_bufoff
>
m_info
->
m_rdpos
||
(
m_info
->
m_bufoff
+
m_info
->
m_buffill
)
<
m_info
->
m_rdpos
)
return
0
;
msl
::
safeint3
::
SafeInt
<
size_t
>
rdpos
(
m_info
->
m_rdpos
);
msl
::
safeint3
::
SafeInt
<
size_t
>
buffill
(
m_info
->
m_buffill
);
msl
::
safeint3
::
SafeInt
<
size_t
>
bufpos
=
rdpos
-
m_info
->
m_bufoff
;
return
buffill
-
bufpos
;
}
_file_info
*
_close_stream
()
{
// indicate that we are no longer open
auto
fileInfo
=
m_info
;
m_info
=
nullptr
;
return
fileInfo
;
}
static
pplx
::
task
<
void
>
_close_file
(
_In_
_file_info
*
fileInfo
)
{
pplx
::
task_completion_event
<
void
>
result_tce
;
auto
callback
=
new
_filestream_callback_close
(
result_tce
);
if
(
!
_close_fsb_nolock
(
&
fileInfo
,
callback
))
{
delete
callback
;
return
pplx
::
task_from_result
();
}
return
pplx
::
create_task
(
result_tce
);
}
// Workaround GCC compiler bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58972
void
_invoke_parent_close_read
()
{
streambuf_state_manager
<
_CharType
>::
_close_read
();
}
pplx
::
task
<
void
>
_close_read
()
{
return
m_readOps
.
enqueue_operation
([
this
]
{
_invoke_parent_close_read
();
if
(
this
->
can_write
())
{
return
pplx
::
task_from_result
();
}
else
{
// Neither heads are open. Close the underlying device
// to indicate that we are no longer open
auto
fileInfo
=
_close_stream
();
return
_close_file
(
fileInfo
);
}
});
}
pplx
::
task
<
void
>
_close_write
()
{
streambuf_state_manager
<
_CharType
>::
_close_write
();
if
(
this
->
can_read
())
{
// Read head is still open. Just flush the write data
return
flush_internal
();
}
else
{
// Neither heads are open. Close the underlying device
// We need to flush all writes if the file was opened for writing.
return
flush_internal
().
then
([
=
](
pplx
::
task
<
void
>
flushTask
)
->
pplx
::
task
<
void
>
{
// swallow exception from flush
try
{
flushTask
.
wait
();
}
catch
(...)
{
}
// indicate that we are no longer open
auto
fileInfo
=
this
->
_close_stream
();
return
this
->
_close_file
(
fileInfo
);
});
}
}
/// <summary>
/// Writes a single byte to an output stream.
/// </summary>
/// <param name="ch">The byte to write</param>
/// <returns>A <c>task</c> that holds the value of the byte written. This is EOF if the write operation
/// fails.</returns>
virtual
pplx
::
task
<
int_type
>
_putc
(
_CharType
ch
)
{
auto
result_tce
=
pplx
::
task_completion_event
<
size_t
>
();
auto
callback
=
new
_filestream_callback_write
<
size_t
>
(
m_info
,
result_tce
);
// Potentially we should consider deprecating this API, it is TERRIBLY inefficient.
std
::
shared_ptr
<
_CharType
>
sharedCh
;
try
{
sharedCh
=
std
::
make_shared
<
_CharType
>
(
ch
);
}
catch
(
const
std
::
bad_alloc
&
)
{
delete
callback
;
throw
;
}
size_t
written
=
_putn_fsb
(
m_info
,
callback
,
sharedCh
.
get
(),
1
,
sizeof
(
_CharType
));
if
(
written
==
sizeof
(
_CharType
))
{
delete
callback
;
return
pplx
::
task_from_result
<
int_type
>
(
ch
);
}
return
pplx
::
create_task
(
result_tce
).
then
([
sharedCh
](
size_t
)
{
return
static_cast
<
int_type
>
(
*
sharedCh
);
});
}
/// <summary>
/// Allocates a contiguous memory block and returns it.
/// </summary>
/// <param name="count">The number of characters to allocate.</param>
/// <returns>A pointer to a block to write to, null if the stream buffer implementation does not support
/// alloc/commit.</returns>
_CharType
*
_alloc
(
size_t
)
{
return
nullptr
;
}
/// <summary>
/// Submits a block already allocated by the stream buffer.
/// </summary>
/// <param name="ptr">Count of characters to be committed.</param>
void
_commit
(
size_t
)
{}
/// <summary>
/// Gets a pointer to the next already allocated contiguous block of data.
/// </summary>
/// <param name="ptr">A reference to a pointer variable that will hold the address of the block on success.</param>
/// <param name="count">The number of contiguous characters available at the address in 'ptr'.</param>
/// <returns><c>true</c> if the operation succeeded, <c>false</c> otherwise.</returns>
/// <remarks>
/// A return of false does not necessarily indicate that a subsequent read operation would fail, only that
/// there is no block to return immediately or that the stream buffer does not support the operation.
/// The stream buffer may not de-allocate the block until <see cref="::release method" /> is called.
/// If the end of the stream is reached, the function will return <c>true</c>, a null pointer, and a count of zero;
/// a subsequent read will not succeed.
/// </remarks>
virtual
bool
acquire
(
_Out_
_CharType
*&
ptr
,
_Out_
size_t
&
count
)
{
ptr
=
nullptr
;
count
=
0
;
return
false
;
}
/// <summary>
/// Releases a block of data acquired using <see cref="::acquire method"/>. This frees the stream buffer to
/// de-allocate the memory, if it so desires. Move the read position ahead by the count.
/// </summary>
/// <param name="ptr">A pointer to the block of data to be released.</param>
/// <param name="count">The number of characters that were read.</param>
virtual
void
release
(
_Out_writes_
(
count
)
_CharType
*
,
_In_
size_t
count
)
{
(
void
)(
count
);
}
/// <summary>
/// Writes a number of characters to the stream.
/// </summary>
/// <param name="ptr">A pointer to the block of data to be written.</param>
/// <param name="count">The number of characters to write.</param>
/// <returns>A <c>task</c> that holds the number of characters actually written, either 'count' or 0.</returns>
virtual
pplx
::
task
<
size_t
>
_putn
(
const
_CharType
*
ptr
,
size_t
count
)
{
auto
result_tce
=
pplx
::
task_completion_event
<
size_t
>
();
auto
callback
=
new
_filestream_callback_write
<
size_t
>
(
m_info
,
result_tce
);
size_t
written
=
_putn_fsb
(
m_info
,
callback
,
ptr
,
count
,
sizeof
(
_CharType
));
if
(
written
!=
0
&&
written
!=
size_t
(
-
1
))
{
delete
callback
;
written
=
written
/
sizeof
(
_CharType
);
return
pplx
::
task_from_result
<
size_t
>
(
written
);
}
return
pplx
::
create_task
(
result_tce
);
}
// Temporarily needed until the deprecated putn is removed.
virtual
pplx
::
task
<
size_t
>
_putn
(
const
_CharType
*
ptr
,
size_t
count
,
bool
copy
)
{
if
(
copy
)
{
auto
sharedData
=
std
::
make_shared
<
std
::
vector
<
_CharType
>>
(
ptr
,
ptr
+
count
);
return
_putn
(
ptr
,
count
).
then
([
sharedData
](
size_t
size
)
{
return
size
;
});
}
else
{
return
_putn
(
ptr
,
count
);
}
}
/// <summary>
/// Reads a single byte from the stream and advance the read position.
/// </summary>
/// <returns>A <c>task</c> that holds the value of the byte read. This is EOF if the read fails.</returns>
virtual
pplx
::
task
<
int_type
>
_bumpc
()
{
return
m_readOps
.
enqueue_operation
([
this
]()
->
pplx
::
task
<
int_type
>
{
if
(
_in_avail_unprot
()
>
0
)
{
pplx
::
extensibility
::
scoped_recursive_lock_t
lck
(
m_info
->
m_lock
);
// Check again once the lock is held.
if
(
_in_avail_unprot
()
>
0
)
{
auto
bufoff
=
m_info
->
m_rdpos
-
m_info
->
m_bufoff
;
_CharType
ch
=
m_info
->
m_buffer
[
bufoff
*
sizeof
(
_CharType
)];
m_info
->
m_rdpos
+=
1
;
return
pplx
::
task_from_result
<
int_type
>
(
ch
);
}
}
auto
result_tce
=
pplx
::
task_completion_event
<
int_type
>
();
auto
callback
=
new
_filestream_callback_bumpc
(
m_info
,
result_tce
);
size_t
ch
=
_getn_fsb
(
m_info
,
callback
,
&
callback
->
m_ch
,
1
,
sizeof
(
_CharType
));
if
(
ch
==
sizeof
(
_CharType
))
{
pplx
::
extensibility
::
scoped_recursive_lock_t
lck
(
m_info
->
m_lock
);
m_info
->
m_rdpos
+=
1
;
_CharType
ch1
=
(
_CharType
)
callback
->
m_ch
;
delete
callback
;
return
pplx
::
task_from_result
<
int_type
>
(
ch1
);
}
return
pplx
::
create_task
(
result_tce
);
});
}
/// <summary>
/// Reads a single byte from the stream and advance the read position.
/// </summary>
/// <returns>The value of the byte. EOF if the read fails. <see cref="::requires_async method" /> if an asynchronous
/// read is required</returns> <remarks>This is a synchronous operation, but is guaranteed to never block.</remarks>
virtual
int_type
_sbumpc
()
{
m_readOps
.
wait
();
if
(
m_info
->
m_atend
)
return
traits
::
eof
();
if
(
_in_avail_unprot
()
==
0
)
return
traits
::
requires_async
();
pplx
::
extensibility
::
scoped_recursive_lock_t
lck
(
m_info
->
m_lock
);
if
(
_in_avail_unprot
()
==
0
)
return
traits
::
requires_async
();
auto
bufoff
=
m_info
->
m_rdpos
-
m_info
->
m_bufoff
;
_CharType
ch
=
m_info
->
m_buffer
[
bufoff
*
sizeof
(
_CharType
)];
m_info
->
m_rdpos
+=
1
;
return
(
int_type
)
ch
;
}
pplx
::
task
<
int_type
>
_getcImpl
()
{
if
(
_in_avail_unprot
()
>
0
)
{
pplx
::
extensibility
::
scoped_recursive_lock_t
lck
(
m_info
->
m_lock
);
// Check again once the lock is held.
if
(
_in_avail_unprot
()
>
0
)
{
auto
bufoff
=
m_info
->
m_rdpos
-
m_info
->
m_bufoff
;
_CharType
ch
=
m_info
->
m_buffer
[
bufoff
*
sizeof
(
_CharType
)];
return
pplx
::
task_from_result
<
int_type
>
(
ch
);
}
}
auto
result_tce
=
pplx
::
task_completion_event
<
int_type
>
();
auto
callback
=
new
_filestream_callback_getc
(
m_info
,
result_tce
);
size_t
ch
=
_getn_fsb
(
m_info
,
callback
,
&
callback
->
m_ch
,
1
,
sizeof
(
_CharType
));
if
(
ch
==
sizeof
(
_CharType
))
{
pplx
::
extensibility
::
scoped_recursive_lock_t
lck
(
m_info
->
m_lock
);
_CharType
ch1
=
(
_CharType
)
callback
->
m_ch
;
delete
callback
;
return
pplx
::
task_from_result
<
int_type
>
(
ch1
);
}
return
pplx
::
create_task
(
result_tce
);
}
/// <summary>
/// Reads a single byte from the stream without advancing the read position.
/// </summary>
/// <returns>The value of the byte. EOF if the read fails.</returns>
pplx
::
task
<
int_type
>
_getc
()
{
return
m_readOps
.
enqueue_operation
([
this
]()
->
pplx
::
task
<
int_type
>
{
return
_getcImpl
();
});
}
/// <summary>
/// Reads a single byte from the stream without advancing the read position.
/// </summary>
/// <returns>The value of the byte. EOF if the read fails. <see cref="::requires_async method" /> if an asynchronous
/// read is required</returns> <remarks>This is a synchronous operation, but is guaranteed to never block.</remarks>
int_type
_sgetc
()
{
m_readOps
.
wait
();
if
(
m_info
->
m_atend
)
return
traits
::
eof
();
if
(
_in_avail_unprot
()
==
0
)
return
traits
::
requires_async
();
pplx
::
extensibility
::
scoped_recursive_lock_t
lck
(
m_info
->
m_lock
);
if
(
_in_avail_unprot
()
==
0
)
return
traits
::
requires_async
();
auto
bufoff
=
m_info
->
m_rdpos
-
m_info
->
m_bufoff
;
_CharType
ch
=
m_info
->
m_buffer
[
bufoff
*
sizeof
(
_CharType
)];
return
(
int_type
)
ch
;
}
/// <summary>
/// Advances the read position, then return the next character without advancing again.
/// </summary>
/// <returns>A <c>task</c> that holds the value of the byte, which is EOF if the read fails.</returns>
virtual
pplx
::
task
<
int_type
>
_nextc
()
{
return
m_readOps
.
enqueue_operation
([
this
]()
->
pplx
::
task
<
int_type
>
{
_seekrdpos_fsb
(
m_info
,
m_info
->
m_rdpos
+
1
,
sizeof
(
_CharType
));
if
(
m_info
->
m_atend
)
return
pplx
::
task_from_result
(
basic_file_buffer
<
_CharType
>::
traits
::
eof
());
return
this
->
_getcImpl
();
});
}
/// <summary>
/// Retreats the read position, then return the current character without advancing.
/// </summary>
/// <returns>A <c>task</c> that holds the value of the byte. The value is EOF if the read fails,
/// <c>requires_async</c> if an asynchronous read is required</returns>
virtual
pplx
::
task
<
int_type
>
_ungetc
()
{
return
m_readOps
.
enqueue_operation
([
this
]()
->
pplx
::
task
<
int_type
>
{
if
(
m_info
->
m_rdpos
==
0
)
return
pplx
::
task_from_result
<
int_type
>
(
basic_file_buffer
<
_CharType
>::
traits
::
eof
());
_seekrdpos_fsb
(
m_info
,
m_info
->
m_rdpos
-
1
,
sizeof
(
_CharType
));
return
this
->
_getcImpl
();
});
}
/// <summary>
/// Reads up to a given number of characters from the stream.
/// </summary>
/// <param name="ptr">The address of the target memory area</param>
/// <param name="count">The maximum number of characters to read</param>
/// <returns>A <c>task</c> that holds the number of characters read. This number is O if the end of the stream is
/// reached, EOF if there is some error.</returns>
virtual
pplx
::
task
<
size_t
>
_getn
(
_Out_writes_
(
count
)
_CharType
*
ptr
,
_In_
size_t
count
)
{
return
m_readOps
.
enqueue_operation
([
=
]()
->
pplx
::
task
<
size_t
>
{
if
(
m_info
->
m_atend
||
count
==
0
)
return
pplx
::
task_from_result
<
size_t
>
(
0
);
if
(
_in_avail_unprot
()
>=
count
)
{
pplx
::
extensibility
::
scoped_recursive_lock_t
lck
(
m_info
->
m_lock
);
// Check again once the lock is held.
if
(
_in_avail_unprot
()
>=
count
)
{
auto
bufoff
=
m_info
->
m_rdpos
-
m_info
->
m_bufoff
;
std
::
memcpy
(
(
void
*
)
ptr
,
this
->
m_info
->
m_buffer
+
bufoff
*
sizeof
(
_CharType
),
count
*
sizeof
(
_CharType
));
m_info
->
m_rdpos
+=
count
;
return
pplx
::
task_from_result
<
size_t
>
(
count
);
}
}
auto
result_tce
=
pplx
::
task_completion_event
<
size_t
>
();
auto
callback
=
new
_filestream_callback_read
(
m_info
,
result_tce
);
size_t
read
=
_getn_fsb
(
m_info
,
callback
,
ptr
,
count
,
sizeof
(
_CharType
));
if
(
read
!=
0
&&
read
!=
size_t
(
-
1
))
{
delete
callback
;
pplx
::
extensibility
::
scoped_recursive_lock_t
lck
(
m_info
->
m_lock
);
m_info
->
m_rdpos
+=
read
/
sizeof
(
_CharType
);
return
pplx
::
task_from_result
<
size_t
>
(
read
/
sizeof
(
_CharType
));
}
return
pplx
::
create_task
(
result_tce
);
});
}
/// <summary>
/// Reads up to a given number of characters from the stream.
/// </summary>
/// <param name="ptr">The address of the target memory area</param>
/// <param name="count">The maximum number of characters to read</param>
/// <returns>The number of characters read. O if the end of the stream is reached or an asynchronous read is
/// required.</returns> <remarks>This is a synchronous operation, but is guaranteed to never block.</remarks>
size_t
_sgetn
(
_Out_writes_
(
count
)
_CharType
*
ptr
,
_In_
size_t
count
)
{
m_readOps
.
wait
();
if
(
m_info
->
m_atend
)
return
0
;
if
(
count
==
0
||
in_avail
()
==
0
)
return
0
;
pplx
::
extensibility
::
scoped_recursive_lock_t
lck
(
m_info
->
m_lock
);
size_t
available
=
_in_avail_unprot
();
size_t
copy
=
(
count
<
available
)
?
count
:
available
;
auto
bufoff
=
m_info
->
m_rdpos
-
m_info
->
m_bufoff
;
std
::
memcpy
((
void
*
)
ptr
,
this
->
m_info
->
m_buffer
+
bufoff
*
sizeof
(
_CharType
),
copy
*
sizeof
(
_CharType
));
m_info
->
m_rdpos
+=
copy
;
m_info
->
m_atend
=
(
copy
<
count
);
return
copy
;
}
/// <summary>
/// Copies up to a given number of characters from the stream.
/// </summary>
/// <param name="ptr">The address of the target memory area</param>
/// <param name="count">The maximum number of characters to copy</param>
/// <returns>The number of characters copied. O if the end of the stream is reached or an asynchronous read is
/// required.</returns> <remarks>This is a synchronous operation, but is guaranteed to never block.</remarks>
virtual
size_t
_scopy
(
_CharType
*
,
size_t
)
{
return
0
;
}
/// <summary>
/// Gets the current read or write position in the stream.
/// </summary>
/// <param name="direction">The I/O direction to seek (see remarks)</param>
/// <returns>The current position. EOF if the operation fails.</returns>
/// <remarks>Some streams may have separate write and read cursors.
/// For such streams, the direction parameter defines whether to move the read or the write
/// cursor.</remarks>
virtual
pos_type
getpos
(
std
::
ios_base
::
openmode
mode
)
const
{
return
const_cast
<
basic_file_buffer
*>
(
this
)
->
seekoff
(
0
,
std
::
ios_base
::
cur
,
mode
);
}
/// <summary>
/// Seeks to the given position.
/// </summary>
/// <param name="pos">The offset from the beginning of the stream</param>
/// <param name="direction">The I/O direction to seek (see remarks)</param>
/// <returns>The position. EOF if the operation fails.</returns>
/// <remarks>Some streams may have separate write and read cursors.
/// For such streams, the direction parameter defines whether to move the read or the write
/// cursor.</remarks>
virtual
pos_type
seekpos
(
pos_type
pos
,
std
::
ios_base
::
openmode
mode
)
{
if
(
mode
==
std
::
ios_base
::
in
)
{
m_readOps
.
wait
();
return
(
pos_type
)
_seekrdpos_fsb
(
m_info
,
size_t
(
pos
),
sizeof
(
_CharType
));
}
else
if
((
m_info
->
m_mode
&
std
::
ios
::
ios_base
::
app
)
==
0
)
{
return
(
pos_type
)
_seekwrpos_fsb
(
m_info
,
size_t
(
pos
),
sizeof
(
_CharType
));
}
return
(
pos_type
)
Concurrency
::
streams
::
char_traits
<
_CharType
>::
eof
();
}
/// <summary>
/// Seeks to a position given by a relative offset.
/// </summary>
/// <param name="offset">The relative position to seek to</param>
/// <param name="way">The starting point (beginning, end, current) for the seek.</param>
/// <param name="mode">The I/O direction to seek (see remarks)</param>
/// <returns>The position. EOF if the operation fails.</returns>
/// <remarks>Some streams may have separate write and read cursors.
/// For such streams, the mode parameter defines whether to move the read or the write cursor.</remarks>
virtual
pos_type
seekoff
(
off_type
offset
,
std
::
ios_base
::
seekdir
way
,
std
::
ios_base
::
openmode
mode
)
{
if
(
mode
==
std
::
ios_base
::
in
)
{
m_readOps
.
wait
();
size_t
current_pos
=
static_cast
<
size_t
>
(
-
1
);
switch
(
way
)
{
case
std
::
ios_base
::
beg
:
return
(
pos_type
)
_seekrdpos_fsb
(
m_info
,
size_t
(
offset
),
sizeof
(
_CharType
));
case
std
::
ios_base
::
cur
:
return
(
pos_type
)
_seekrdpos_fsb
(
m_info
,
size_t
(
m_info
->
m_rdpos
+
offset
),
sizeof
(
_CharType
));
case
std
::
ios_base
::
end
:
current_pos
=
_seekrdtoend_fsb
(
m_info
,
int64_t
(
offset
),
sizeof
(
_CharType
));
if
(
current_pos
==
static_cast
<
size_t
>
(
-
1
))
{
return
-
1
;
}
return
(
pos_type
)
current_pos
;
default:
// Fail on invalid input (_S_ios_seekdir_end)
assert
(
false
);
}
}
else
if
((
m_info
->
m_mode
&
std
::
ios
::
ios_base
::
app
)
==
0
)
{
switch
(
way
)
{
case
std
::
ios_base
::
beg
:
return
(
pos_type
)
_seekwrpos_fsb
(
m_info
,
size_t
(
offset
),
sizeof
(
_CharType
));
case
std
::
ios_base
::
cur
:
return
(
pos_type
)
_seekwrpos_fsb
(
m_info
,
size_t
(
m_info
->
m_wrpos
+
offset
),
sizeof
(
_CharType
));
case
std
::
ios_base
::
end
:
return
(
pos_type
)
_seekwrpos_fsb
(
m_info
,
size_t
(
-
1
),
sizeof
(
_CharType
));
default:
// Fail on invalid input (_S_ios_seekdir_end)
assert
(
false
);
}
}
return
(
pos_type
)
traits
::
eof
();
}
/// <summary>
/// For output streams, flush any internally buffered data to the underlying medium.
/// </summary>
virtual
pplx
::
task
<
bool
>
_sync
()
{
return
flush_internal
().
then
([]()
{
return
true
;
});
}
private:
template
<
typename
_CharType1
>
friend
class
::
concurrency
::
streams
::
file_buffer
;
pplx
::
task
<
void
>
flush_internal
()
{
pplx
::
task_completion_event
<
void
>
result_tce
;
auto
callback
=
utility
::
details
::
make_unique
<
_filestream_callback_write_b
>
(
m_info
,
result_tce
);
if
(
!
_sync_fsb
(
m_info
,
callback
.
get
()))
{
return
pplx
::
task_from_exception
<
void
>
(
std
::
runtime_error
(
"failure to flush stream"
));
}
callback
.
release
();
return
pplx
::
create_task
(
result_tce
);
}
basic_file_buffer
(
_In_
_file_info
*
info
)
:
streambuf_state_manager
<
_CharType
>
(
info
->
m_mode
),
m_info
(
info
)
{}
#if !defined(__cplusplus_winrt)
static
pplx
::
task
<
std
::
shared_ptr
<
basic_streambuf
<
_CharType
>>>
open
(
const
utility
::
string_t
&
_Filename
,
std
::
ios_base
::
openmode
_Mode
=
std
::
ios_base
::
out
,
#ifdef _WIN32
int
_Prot
=
(
int
)
std
::
ios_base
::
_Openprot
#else
int
_Prot
=
0
// unsupported on Linux, for now
#endif
)
{
auto
result_tce
=
pplx
::
task_completion_event
<
std
::
shared_ptr
<
basic_streambuf
<
_CharType
>>>
();
auto
callback
=
new
_filestream_callback_open
(
result_tce
);
_open_fsb_str
(
callback
,
_Filename
.
c_str
(),
_Mode
,
_Prot
);
return
pplx
::
create_task
(
result_tce
);
}
#else
static
pplx
::
task
<
std
::
shared_ptr
<
basic_streambuf
<
_CharType
>>>
open
(
::
Windows
::
Storage
::
StorageFile
^
file
,
std
::
ios_base
::
openmode
_Mode
=
std
::
ios_base
::
out
)
{
auto
result_tce
=
pplx
::
task_completion_event
<
std
::
shared_ptr
<
basic_streambuf
<
_CharType
>>>
();
auto
callback
=
new
_filestream_callback_open
(
result_tce
);
_open_fsb_stf_str
(
callback
,
file
,
_Mode
,
0
);
return
pplx
::
create_task
(
result_tce
);
}
#endif
class
_filestream_callback_open
:
public
details
::
_filestream_callback
{
public:
_filestream_callback_open
(
const
pplx
::
task_completion_event
<
std
::
shared_ptr
<
basic_streambuf
<
_CharType
>>>&
op
)
:
m_op
(
op
)
{
}
virtual
void
on_opened
(
_In_
_file_info
*
info
)
{
m_op
.
set
(
std
::
shared_ptr
<
basic_file_buffer
<
_CharType
>>
(
new
basic_file_buffer
<
_CharType
>
(
info
)));
delete
this
;
}
virtual
void
on_error
(
const
std
::
exception_ptr
&
e
)
{
m_op
.
set_exception
(
e
);
delete
this
;
}
private:
pplx
::
task_completion_event
<
std
::
shared_ptr
<
basic_streambuf
<
_CharType
>>>
m_op
;
};
class
_filestream_callback_close
:
public
details
::
_filestream_callback
{
public:
_filestream_callback_close
(
const
pplx
::
task_completion_event
<
void
>&
op
)
:
m_op
(
op
)
{}
virtual
void
on_closed
()
{
m_op
.
set
();
delete
this
;
}
virtual
void
on_error
(
const
std
::
exception_ptr
&
e
)
{
m_op
.
set_exception
(
e
);
delete
this
;
}
private:
pplx
::
task_completion_event
<
void
>
m_op
;
};
template
<
typename
ResultType
>
class
_filestream_callback_write
:
public
details
::
_filestream_callback
{
public:
_filestream_callback_write
(
_In_
_file_info
*
info
,
const
pplx
::
task_completion_event
<
ResultType
>&
op
)
:
m_info
(
info
),
m_op
(
op
)
{
}
virtual
void
on_completed
(
size_t
result
)
{
m_op
.
set
((
ResultType
)
result
/
sizeof
(
_CharType
));
delete
this
;
}
virtual
void
on_error
(
const
std
::
exception_ptr
&
e
)
{
m_op
.
set_exception
(
e
);
delete
this
;
}
private:
_file_info
*
m_info
;
pplx
::
task_completion_event
<
ResultType
>
m_op
;
};
class
_filestream_callback_write_b
:
public
details
::
_filestream_callback
{
public:
_filestream_callback_write_b
(
_In_
_file_info
*
info
,
const
pplx
::
task_completion_event
<
void
>&
op
)
:
m_info
(
info
),
m_op
(
op
)
{
}
virtual
void
on_completed
(
size_t
)
{
m_op
.
set
();
delete
this
;
}
virtual
void
on_error
(
const
std
::
exception_ptr
&
e
)
{
m_op
.
set_exception
(
e
);
delete
this
;
}
private:
_file_info
*
m_info
;
pplx
::
task_completion_event
<
void
>
m_op
;
};
class
_filestream_callback_read
:
public
details
::
_filestream_callback
{
public:
_filestream_callback_read
(
_In_
_file_info
*
info
,
const
pplx
::
task_completion_event
<
size_t
>&
op
)
:
m_info
(
info
),
m_op
(
op
)
{
}
virtual
void
on_completed
(
size_t
result
)
{
result
=
result
/
sizeof
(
_CharType
);
m_info
->
m_rdpos
+=
result
;
m_op
.
set
(
result
);
delete
this
;
}
virtual
void
on_error
(
const
std
::
exception_ptr
&
e
)
{
m_op
.
set_exception
(
e
);
delete
this
;
}
private:
_file_info
*
m_info
;
pplx
::
task_completion_event
<
size_t
>
m_op
;
};
class
_filestream_callback_bumpc
:
public
details
::
_filestream_callback
{
public:
_filestream_callback_bumpc
(
_In_
_file_info
*
info
,
const
pplx
::
task_completion_event
<
int_type
>&
op
)
:
m_ch
(
0
),
m_info
(
info
),
m_op
(
op
)
{
}
virtual
void
on_completed
(
size_t
result
)
{
if
(
result
==
sizeof
(
_CharType
))
{
m_info
->
m_rdpos
+=
1
;
m_op
.
set
(
m_ch
);
}
else
{
m_op
.
set
(
traits
::
eof
());
}
delete
this
;
}
virtual
void
on_error
(
const
std
::
exception_ptr
&
e
)
{
m_op
.
set_exception
(
e
);
delete
this
;
}
int_type
m_ch
;
private:
_file_info
*
m_info
;
pplx
::
task_completion_event
<
int_type
>
m_op
;
};
class
_filestream_callback_getc
:
public
details
::
_filestream_callback
{
public:
_filestream_callback_getc
(
_In_
_file_info
*
info
,
const
pplx
::
task_completion_event
<
int_type
>&
op
)
:
m_ch
(
0
),
m_info
(
info
),
m_op
(
op
)
{
}
virtual
void
on_completed
(
size_t
result
)
{
if
(
result
==
sizeof
(
_CharType
))
{
m_op
.
set
(
m_ch
);
}
else
{
m_op
.
set
(
traits
::
eof
());
}
delete
this
;
}
int_type
m_ch
;
virtual
void
on_error
(
const
std
::
exception_ptr
&
e
)
{
m_op
.
set_exception
(
e
);
delete
this
;
}
private:
_file_info
*
m_info
;
pplx
::
task_completion_event
<
int_type
>
m_op
;
};
_file_info
*
m_info
;
async_operation_queue
m_readOps
;
};
}
// namespace details
/// <summary>
/// Stream buffer for file streams.
/// </summary>
/// <typeparam name="_CharType">
/// The data type of the basic element of the <c>file_buffer</c>.
/// </typeparam>
template
<
typename
_CharType
>
class
file_buffer
{
public:
#if !defined(__cplusplus_winrt)
/// <summary>
/// Open a new stream buffer representing the given file.
/// </summary>
/// <param name="file_name">The name of the file</param>
/// <param name="mode">The opening mode of the file</param>
/// <param name="prot">The file protection mode</param>
/// <returns>A <c>task</c> that returns an opened stream buffer on completion.</returns>
static
pplx
::
task
<
streambuf
<
_CharType
>>
open
(
const
utility
::
string_t
&
file_name
,
std
::
ios_base
::
openmode
mode
=
std
::
ios_base
::
out
,
#ifdef _WIN32
int
prot
=
_SH_DENYRD
#else
int
prot
=
0
// unsupported on Linux
#endif
)
{
auto
bfb
=
details
::
basic_file_buffer
<
_CharType
>::
open
(
file_name
,
mode
,
prot
);
return
bfb
.
then
(
[](
pplx
::
task
<
std
::
shared_ptr
<
details
::
basic_streambuf
<
_CharType
>>>
op
)
->
streambuf
<
_CharType
>
{
return
streambuf
<
_CharType
>
(
op
.
get
());
});
}
#else
/// <summary>
/// Open a new stream buffer representing the given file.
/// </summary>
/// <param name="file">The StorageFile instance</param>
/// <param name="mode">The opening mode of the file</param>
/// <param name="prot">The file protection mode</param>
/// <returns>A <c>task</c> that returns an opened stream buffer on completion.</returns>
static
pplx
::
task
<
streambuf
<
_CharType
>>
open
(
::
Windows
::
Storage
::
StorageFile
^
file
,
std
::
ios_base
::
openmode
mode
=
std
::
ios_base
::
out
)
{
auto
bfb
=
details
::
basic_file_buffer
<
_CharType
>::
open
(
file
,
mode
);
return
bfb
.
then
(
[](
pplx
::
task
<
std
::
shared_ptr
<
details
::
basic_streambuf
<
_CharType
>>>
op
)
->
streambuf
<
_CharType
>
{
return
streambuf
<
_CharType
>
(
op
.
get
());
});
}
#endif
};
/// <summary>
/// File stream class containing factory functions for file streams.
/// </summary>
/// <typeparam name="_CharType">
/// The data type of the basic element of the <c>file_stream</c>.
/// </typeparam>
template
<
typename
_CharType
>
class
file_stream
{
public:
#if !defined(__cplusplus_winrt)
/// <summary>
/// Open a new input stream representing the given file.
/// The file should already exist on disk, or an exception will be thrown.
/// </summary>
/// <param name="file_name">The name of the file</param>
/// <param name="mode">The opening mode of the file</param>
/// <param name="prot">The file protection mode</param>
/// <returns>A <c>task</c> that returns an opened input stream on completion.</returns>
static
pplx
::
task
<
streams
::
basic_istream
<
_CharType
>>
open_istream
(
const
utility
::
string_t
&
file_name
,
std
::
ios_base
::
openmode
mode
=
std
::
ios_base
::
in
,
#ifdef _WIN32
int
prot
=
(
int
)
std
::
ios_base
::
_Openprot
#else
int
prot
=
0
#endif
)
{
mode
|=
std
::
ios_base
::
in
;
return
streams
::
file_buffer
<
_CharType
>::
open
(
file_name
,
mode
,
prot
)
.
then
([](
streams
::
streambuf
<
_CharType
>
buf
)
->
basic_istream
<
_CharType
>
{
return
basic_istream
<
_CharType
>
(
buf
);
});
}
/// <summary>
/// Open a new output stream representing the given file.
/// If the file does not exist, it will be create unless the folder or directory
/// where it is to be found also does not exist.
/// </summary>
/// <param name="file_name">The name of the file</param>
/// <param name="mode">The opening mode of the file</param>
/// <param name="prot">The file protection mode</param>
/// <returns>A <c>task</c> that returns an opened output stream on completion.</returns>
static
pplx
::
task
<
streams
::
basic_ostream
<
_CharType
>>
open_ostream
(
const
utility
::
string_t
&
file_name
,
std
::
ios_base
::
openmode
mode
=
std
::
ios_base
::
out
,
#ifdef _WIN32
int
prot
=
(
int
)
std
::
ios_base
::
_Openprot
#else
int
prot
=
0
#endif
)
{
mode
|=
std
::
ios_base
::
out
;
return
streams
::
file_buffer
<
_CharType
>::
open
(
file_name
,
mode
,
prot
)
.
then
([](
streams
::
streambuf
<
_CharType
>
buf
)
->
basic_ostream
<
_CharType
>
{
return
basic_ostream
<
_CharType
>
(
buf
);
});
}
#else
/// <summary>
/// Open a new input stream representing the given file.
/// The file should already exist on disk, or an exception will be thrown.
/// </summary>
/// <param name="file">The StorageFile reference representing the file</param>
/// <param name="mode">The opening mode of the file</param>
/// <returns>A <c>task</c> that returns an opened input stream on completion.</returns>
static
pplx
::
task
<
streams
::
basic_istream
<
_CharType
>>
open_istream
(
::
Windows
::
Storage
::
StorageFile
^
file
,
std
::
ios_base
::
openmode
mode
=
std
::
ios_base
::
in
)
{
mode
|=
std
::
ios_base
::
in
;
return
streams
::
file_buffer
<
_CharType
>::
open
(
file
,
mode
)
.
then
([](
streams
::
streambuf
<
_CharType
>
buf
)
->
basic_istream
<
_CharType
>
{
return
basic_istream
<
_CharType
>
(
buf
);
});
}
/// <summary>
/// Open a new output stream representing the given file.
/// If the file does not exist, it will be create unless the folder or directory
/// where it is to be found also does not exist.
/// </summary>
/// <param name="file">The StorageFile reference representing the file</param>
/// <param name="mode">The opening mode of the file</param>
/// <returns>A <c>task</c> that returns an opened output stream on completion.</returns>
static
pplx
::
task
<
streams
::
basic_ostream
<
_CharType
>>
open_ostream
(
::
Windows
::
Storage
::
StorageFile
^
file
,
std
::
ios_base
::
openmode
mode
=
std
::
ios_base
::
out
)
{
mode
|=
std
::
ios_base
::
out
;
return
streams
::
file_buffer
<
_CharType
>::
open
(
file
,
mode
)
.
then
([](
streams
::
streambuf
<
_CharType
>
buf
)
->
basic_ostream
<
_CharType
>
{
return
basic_ostream
<
_CharType
>
(
buf
);
});
}
#endif
};
typedef
file_stream
<
uint8_t
>
fstream
;
}
// namespace streams
}
// namespace Concurrency
#endif
cpprestsdk_static_tester/vcpkg/include/cpprest/http_client.h
0 → 100644
View file @
14571fd2
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* HTTP Library: Client-side APIs.
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#ifndef CASA_HTTP_CLIENT_H
#define CASA_HTTP_CLIENT_H
#if defined(__cplusplus_winrt)
#if !defined(__WRL_NO_DEFAULT_LIB__)
#define __WRL_NO_DEFAULT_LIB__
#endif
#include
<msxml6.h>
#include
<wrl.h>
namespace
web
{
namespace
http
{
namespace
client
{
typedef
IXMLHTTPRequest2
*
native_handle
;
}
}
// namespace http
}
// namespace web
#else
namespace
web
{
namespace
http
{
namespace
client
{
typedef
void
*
native_handle
;
}
}
// namespace http
}
// namespace web
#endif // __cplusplus_winrt
#include
"cpprest/asyncrt_utils.h"
#include
"cpprest/details/basic_types.h"
#include
"cpprest/details/web_utilities.h"
#include
"cpprest/http_msg.h"
#include
"cpprest/json.h"
#include
"cpprest/uri.h"
#include
"pplx/pplxtasks.h"
#include
<limits>
#include
<memory>
#if !defined(CPPREST_TARGET_XP)
#include
"cpprest/oauth1.h"
#endif
#include
"cpprest/oauth2.h"
#if !defined(_WIN32) && !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_CLIENT_ASIO)
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#endif
#include
"boost/asio/ssl.hpp"
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
#endif
/// The web namespace contains functionality common to multiple protocols like HTTP and WebSockets.
namespace
web
{
/// Declarations and functionality for the HTTP protocol.
namespace
http
{
/// HTTP client side library.
namespace
client
{
// credentials and web_proxy class has been moved from web::http::client namespace to web namespace.
// The below using declarations ensure we don't break existing code.
// Please use the web::credentials and web::web_proxy class going forward.
using
web
::
credentials
;
using
web
::
web_proxy
;
/// <summary>
/// HTTP client configuration class, used to set the possible configuration options
/// used to create an http_client instance.
/// </summary>
class
http_client_config
{
public:
http_client_config
()
:
m_guarantee_order
(
false
)
,
m_timeout
(
std
::
chrono
::
seconds
(
30
))
,
m_chunksize
(
0
)
,
m_request_compressed
(
false
)
#if !defined(__cplusplus_winrt)
,
m_validate_certificates
(
true
)
#endif
#if !defined(_WIN32) && !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_CLIENT_ASIO)
,
m_tlsext_sni_enabled
(
true
)
#endif
#if defined(_WIN32) && !defined(__cplusplus_winrt)
,
m_buffer_request
(
false
)
#endif
{
}
#if !defined(CPPREST_TARGET_XP)
/// <summary>
/// Get OAuth 1.0 configuration.
/// </summary>
/// <returns>Shared pointer to OAuth 1.0 configuration.</returns>
const
std
::
shared_ptr
<
oauth1
::
experimental
::
oauth1_config
>
oauth1
()
const
{
return
m_oauth1
;
}
/// <summary>
/// Set OAuth 1.0 configuration.
/// </summary>
/// <param name="config">OAuth 1.0 configuration to set.</param>
void
set_oauth1
(
oauth1
::
experimental
::
oauth1_config
config
)
{
m_oauth1
=
std
::
make_shared
<
oauth1
::
experimental
::
oauth1_config
>
(
std
::
move
(
config
));
}
#endif
/// <summary>
/// Get OAuth 2.0 configuration.
/// </summary>
/// <returns>Shared pointer to OAuth 2.0 configuration.</returns>
const
std
::
shared_ptr
<
oauth2
::
experimental
::
oauth2_config
>
oauth2
()
const
{
return
m_oauth2
;
}
/// <summary>
/// Set OAuth 2.0 configuration.
/// </summary>
/// <param name="config">OAuth 2.0 configuration to set.</param>
void
set_oauth2
(
oauth2
::
experimental
::
oauth2_config
config
)
{
m_oauth2
=
std
::
make_shared
<
oauth2
::
experimental
::
oauth2_config
>
(
std
::
move
(
config
));
}
/// <summary>
/// Get the web proxy object
/// </summary>
/// <returns>A reference to the web proxy object.</returns>
const
web_proxy
&
proxy
()
const
{
return
m_proxy
;
}
/// <summary>
/// Set the web proxy object
/// </summary>
/// <param name="proxy">A reference to the web proxy object.</param>
void
set_proxy
(
web_proxy
proxy
)
{
m_proxy
=
std
::
move
(
proxy
);
}
/// <summary>
/// Get the client credentials
/// </summary>
/// <returns>A reference to the client credentials.</returns>
const
http
::
client
::
credentials
&
credentials
()
const
{
return
m_credentials
;
}
/// <summary>
/// Set the client credentials
/// </summary>
/// <param name="cred">A reference to the client credentials.</param>
void
set_credentials
(
const
http
::
client
::
credentials
&
cred
)
{
m_credentials
=
cred
;
}
/// <summary>
/// Get the 'guarantee order' property
/// </summary>
/// <returns>The value of the property.</returns>
bool
guarantee_order
()
const
{
return
m_guarantee_order
;
}
/// <summary>
/// Set the 'guarantee order' property
/// </summary>
/// <param name="guarantee_order">The value of the property.</param>
CASABLANCA_DEPRECATED
(
"Confusing API will be removed in future releases. If you need to order HTTP requests use task continuations."
)
void
set_guarantee_order
(
bool
guarantee_order
)
{
m_guarantee_order
=
guarantee_order
;
}
/// <summary>
/// Get the timeout
/// </summary>
/// <returns>The timeout (in seconds) used for each send and receive operation on the client.</returns>
utility
::
seconds
timeout
()
const
{
return
std
::
chrono
::
duration_cast
<
utility
::
seconds
>
(
m_timeout
);
}
/// <summary>
/// Get the timeout
/// </summary>
/// <returns>The timeout (in whatever duration) used for each send and receive operation on the client.</returns>
template
<
class
T
>
T
timeout
()
const
{
return
std
::
chrono
::
duration_cast
<
T
>
(
m_timeout
);
}
/// <summary>
/// Set the timeout
/// </summary>
/// <param name="timeout">The timeout (duration from microseconds range and up) used for each send and receive
/// operation on the client.</param>
template
<
class
T
>
void
set_timeout
(
const
T
&
timeout
)
{
m_timeout
=
std
::
chrono
::
duration_cast
<
std
::
chrono
::
microseconds
>
(
timeout
);
}
/// <summary>
/// Get the client chunk size.
/// </summary>
/// <returns>The internal buffer size used by the http client when sending and receiving data from the
/// network.</returns>
size_t
chunksize
()
const
{
return
m_chunksize
==
0
?
64
*
1024
:
m_chunksize
;
}
/// <summary>
/// Sets the client chunk size.
/// </summary>
/// <param name="size">The internal buffer size used by the http client when sending and receiving data from the
/// network.</param> <remarks>This is a hint -- an implementation may disregard the setting and use some other chunk
/// size.</remarks>
void
set_chunksize
(
size_t
size
)
{
m_chunksize
=
size
;
}
/// <summary>
/// Returns true if the default chunk size is in use.
/// <remarks>If true, implementations are allowed to choose whatever size is best.</remarks>
/// </summary>
/// <returns>True if default, false if set by user.</returns>
bool
is_default_chunksize
()
const
{
return
m_chunksize
==
0
;
}
/// <summary>
/// Checks if requesting a compressed response using Content-Encoding is turned on, the default is off.
/// </summary>
/// <returns>True if a content-encoded compressed response is allowed, false otherwise</returns>
bool
request_compressed_response
()
const
{
return
m_request_compressed
;
}
/// <summary>
/// Request that the server respond with a compressed body using Content-Encoding; to use Transfer-Encoding, do not
/// set this, and specify a vector of <see cref="web::http::details::compression::decompress_factory" /> pointers
/// to the set_decompress_factories method of the <see cref="web::http::http_request" /> object for the request.
/// If true and the server does not support compression, this will have no effect.
/// The response body is internally decompressed before the consumer receives the data.
/// </summary>
/// <param name="request_compressed">True to turn on content-encoded response body compression, false
/// otherwise.</param> <remarks>Please note there is a performance cost due to copying the request data. Currently
/// only supported on Windows and OSX.</remarks>
void
set_request_compressed_response
(
bool
request_compressed
)
{
m_request_compressed
=
request_compressed
;
}
#if !defined(__cplusplus_winrt)
/// <summary>
/// Gets the server certificate validation property.
/// </summary>
/// <returns>True if certificates are to be verified, false otherwise.</returns>
bool
validate_certificates
()
const
{
return
m_validate_certificates
;
}
/// <summary>
/// Sets the server certificate validation property.
/// </summary>
/// <param name="validate_certs">False to turn ignore all server certificate validation errors, true
/// otherwise.</param> <remarks>Note ignoring certificate errors can be dangerous and should be done with
/// caution.</remarks>
void
set_validate_certificates
(
bool
validate_certs
)
{
m_validate_certificates
=
validate_certs
;
}
#endif
#if defined(_WIN32) && !defined(__cplusplus_winrt)
/// <summary>
/// Checks if request data buffering is turned on, the default is off.
/// </summary>
/// <returns>True if buffering is enabled, false otherwise</returns>
bool
buffer_request
()
const
{
return
m_buffer_request
;
}
/// <summary>
/// Sets the request buffering property.
/// If true, in cases where the request body/stream doesn't support seeking the request data will be buffered.
/// This can help in situations where an authentication challenge might be expected.
/// </summary>
/// <param name="buffer_request">True to turn on buffer, false otherwise.</param>
/// <remarks>Please note there is a performance cost due to copying the request data.</remarks>
void
set_buffer_request
(
bool
buffer_request
)
{
m_buffer_request
=
buffer_request
;
}
#endif
/// <summary>
/// Sets a callback to enable custom setting of platform specific options.
/// </summary>
/// <remarks>
/// The native_handle is the following type depending on the underlying platform:
/// Windows Desktop, WinHTTP - HINTERNET (session)
/// </remarks>
/// <param name="callback">A user callback allowing for customization of the session</param>
void
set_nativesessionhandle_options
(
const
std
::
function
<
void
(
native_handle
)
>&
callback
)
{
m_set_user_nativesessionhandle_options
=
callback
;
}
/// <summary>
/// Invokes a user's callback to allow for customization of the session.
/// </summary>
/// <remarks>Internal Use Only</remarks>
/// <param name="handle">A internal implementation handle.</param>
void
_invoke_nativesessionhandle_options
(
native_handle
handle
)
const
{
if
(
m_set_user_nativesessionhandle_options
)
m_set_user_nativesessionhandle_options
(
handle
);
}
/// <summary>
/// Sets a callback to enable custom setting of platform specific options.
/// </summary>
/// <remarks>
/// The native_handle is the following type depending on the underlying platform:
/// Windows Desktop, WinHTTP - HINTERNET
/// Windows Runtime, WinRT - IXMLHTTPRequest2 *
/// All other platforms, Boost.Asio:
/// https - boost::asio::ssl::stream<boost::asio::ip::tcp::socket &> *
/// http - boost::asio::ip::tcp::socket *
/// </remarks>
/// <param name="callback">A user callback allowing for customization of the request</param>
void
set_nativehandle_options
(
const
std
::
function
<
void
(
native_handle
)
>&
callback
)
{
m_set_user_nativehandle_options
=
callback
;
}
/// <summary>
/// Invokes a user's callback to allow for customization of the request.
/// </summary>
/// <param name="handle">A internal implementation handle.</param>
void
invoke_nativehandle_options
(
native_handle
handle
)
const
{
if
(
m_set_user_nativehandle_options
)
m_set_user_nativehandle_options
(
handle
);
}
#if !defined(_WIN32) && !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_CLIENT_ASIO)
/// <summary>
/// Sets a callback to enable custom setting of the ssl context, at construction time.
/// </summary>
/// <param name="callback">A user callback allowing for customization of the ssl context at construction
/// time.</param>
void
set_ssl_context_callback
(
const
std
::
function
<
void
(
boost
::
asio
::
ssl
::
context
&
)
>&
callback
)
{
m_ssl_context_callback
=
callback
;
}
/// <summary>
/// Gets the user's callback to allow for customization of the ssl context.
/// </summary>
const
std
::
function
<
void
(
boost
::
asio
::
ssl
::
context
&
)
>&
get_ssl_context_callback
()
const
{
return
m_ssl_context_callback
;
}
/// <summary>
/// Gets the TLS extension server name indication (SNI) status.
/// </summary>
/// <returns>True if TLS server name indication is enabled, false otherwise.</returns>
bool
is_tlsext_sni_enabled
()
const
{
return
m_tlsext_sni_enabled
;
}
/// <summary>
/// Sets the TLS extension server name indication (SNI) status.
/// </summary>
/// <param name="tlsext_sni_enabled">False to disable the TLS (ClientHello) extension for server name indication,
/// true otherwise.</param> <remarks>Note: This setting is enabled by default as it is required in most virtual
/// hosting scenarios.</remarks>
void
set_tlsext_sni_enabled
(
bool
tlsext_sni_enabled
)
{
m_tlsext_sni_enabled
=
tlsext_sni_enabled
;
}
#endif
private:
#if !defined(CPPREST_TARGET_XP)
std
::
shared_ptr
<
oauth1
::
experimental
::
oauth1_config
>
m_oauth1
;
#endif
std
::
shared_ptr
<
oauth2
::
experimental
::
oauth2_config
>
m_oauth2
;
web_proxy
m_proxy
;
http
::
client
::
credentials
m_credentials
;
// Whether or not to guarantee ordering, i.e. only using one underlying TCP connection.
bool
m_guarantee_order
;
std
::
chrono
::
microseconds
m_timeout
;
size_t
m_chunksize
;
bool
m_request_compressed
;
#if !defined(__cplusplus_winrt)
// IXmlHttpRequest2 doesn't allow configuration of certificate verification.
bool
m_validate_certificates
;
#endif
std
::
function
<
void
(
native_handle
)
>
m_set_user_nativehandle_options
;
std
::
function
<
void
(
native_handle
)
>
m_set_user_nativesessionhandle_options
;
#if !defined(_WIN32) && !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_CLIENT_ASIO)
std
::
function
<
void
(
boost
::
asio
::
ssl
::
context
&
)
>
m_ssl_context_callback
;
bool
m_tlsext_sni_enabled
;
#endif
#if defined(_WIN32) && !defined(__cplusplus_winrt)
bool
m_buffer_request
;
#endif
};
class
http_pipeline
;
/// <summary>
/// HTTP client class, used to maintain a connection to an HTTP service for an extended session.
/// </summary>
class
http_client
{
public:
/// <summary>
/// Creates a new http_client connected to specified uri.
/// </summary>
/// <param name="base_uri">A string representation of the base uri to be used for all requests. Must start with
/// either "http://" or "https://"</param>
_ASYNCRTIMP
http_client
(
const
uri
&
base_uri
);
/// <summary>
/// Creates a new http_client connected to specified uri.
/// </summary>
/// <param name="base_uri">A string representation of the base uri to be used for all requests. Must start with
/// either "http://" or "https://"</param> <param name="client_config">The http client configuration object
/// containing the possible configuration options to initialize the <c>http_client</c>. </param>
_ASYNCRTIMP
http_client
(
const
uri
&
base_uri
,
const
http_client_config
&
client_config
);
/// <summary>
/// Note the destructor doesn't necessarily close the connection and release resources.
/// The connection is reference counted with the http_responses.
/// </summary>
_ASYNCRTIMP
~
http_client
()
CPPREST_NOEXCEPT
;
/// <summary>
/// Gets the base URI.
/// </summary>
/// <returns>
/// A base URI initialized in constructor
/// </returns>
_ASYNCRTIMP
const
uri
&
base_uri
()
const
;
/// <summary>
/// Get client configuration object
/// </summary>
/// <returns>A reference to the client configuration object.</returns>
_ASYNCRTIMP
const
http_client_config
&
client_config
()
const
;
/// <summary>
/// Adds an HTTP pipeline stage to the client.
/// </summary>
/// <param name="handler">A function object representing the pipeline stage.</param>
_ASYNCRTIMP
void
add_handler
(
const
std
::
function
<
pplx
::
task
<
http_response
>
__cdecl
(
http_request
,
std
::
shared_ptr
<
http
::
http_pipeline_stage
>
)
>&
handler
);
/// <summary>
/// Adds an HTTP pipeline stage to the client.
/// </summary>
/// <param name="stage">A shared pointer to a pipeline stage.</param>
_ASYNCRTIMP
void
add_handler
(
const
std
::
shared_ptr
<
http
::
http_pipeline_stage
>&
stage
);
/// <summary>
/// Asynchronously sends an HTTP request.
/// </summary>
/// <param name="request">Request to send.</param>
/// <param name="token">Cancellation token for cancellation of this request operation.</param>
/// <returns>An asynchronous operation that is completed once a response from the request is received.</returns>
_ASYNCRTIMP
pplx
::
task
<
http_response
>
request
(
http_request
request
,
const
pplx
::
cancellation_token
&
token
=
pplx
::
cancellation_token
::
none
());
/// <summary>
/// Asynchronously sends an HTTP request.
/// </summary>
/// <param name="mtd">HTTP request method.</param>
/// <param name="token">Cancellation token for cancellation of this request operation.</param>
/// <returns>An asynchronous operation that is completed once a response from the request is received.</returns>
pplx
::
task
<
http_response
>
request
(
const
method
&
mtd
,
const
pplx
::
cancellation_token
&
token
=
pplx
::
cancellation_token
::
none
())
{
http_request
msg
(
mtd
);
return
request
(
msg
,
token
);
}
/// <summary>
/// Asynchronously sends an HTTP request.
/// </summary>
/// <param name="mtd">HTTP request method.</param>
/// <param name="path_query_fragment">String containing the path, query, and fragment, relative to the http_client's
/// base URI.</param> <param name="token">Cancellation token for cancellation of this request operation.</param>
/// <returns>An asynchronous operation that is completed once a response from the request is received.</returns>
pplx
::
task
<
http_response
>
request
(
const
method
&
mtd
,
const
utility
::
string_t
&
path_query_fragment
,
const
pplx
::
cancellation_token
&
token
=
pplx
::
cancellation_token
::
none
())
{
http_request
msg
(
mtd
);
msg
.
set_request_uri
(
path_query_fragment
);
return
request
(
msg
,
token
);
}
/// <summary>
/// Asynchronously sends an HTTP request.
/// </summary>
/// <param name="mtd">HTTP request method.</param>
/// <param name="path_query_fragment">String containing the path, query, and fragment, relative to the http_client's
/// base URI.</param> <param name="body_data">The data to be used as the message body, represented using the json
/// object library.</param> <param name="token">Cancellation token for cancellation of this request
/// operation.</param> <returns>An asynchronous operation that is completed once a response from the request is
/// received.</returns>
pplx
::
task
<
http_response
>
request
(
const
method
&
mtd
,
const
utility
::
string_t
&
path_query_fragment
,
const
json
::
value
&
body_data
,
const
pplx
::
cancellation_token
&
token
=
pplx
::
cancellation_token
::
none
())
{
http_request
msg
(
mtd
);
msg
.
set_request_uri
(
path_query_fragment
);
msg
.
set_body
(
body_data
);
return
request
(
msg
,
token
);
}
/// <summary>
/// Asynchronously sends an HTTP request with a string body. Assumes the
/// character encoding of the string is UTF-8.
/// </summary>
/// <param name="mtd">HTTP request method.</param>
/// <param name="path_query_fragment">String containing the path, query, and fragment, relative to the http_client's
/// base URI.</param> <param name="content_type">A string holding the MIME type of the message body.</param> <param
/// name="body_data">String containing the text to use in the message body.</param> <param name="token">Cancellation
/// token for cancellation of this request operation.</param> <returns>An asynchronous operation that is completed
/// once a response from the request is received.</returns>
pplx
::
task
<
http_response
>
request
(
const
method
&
mtd
,
const
utf8string
&
path_query_fragment
,
const
utf8string
&
body_data
,
const
utf8string
&
content_type
=
"text/plain; charset=utf-8"
,
const
pplx
::
cancellation_token
&
token
=
pplx
::
cancellation_token
::
none
())
{
http_request
msg
(
mtd
);
msg
.
set_request_uri
(
::
utility
::
conversions
::
to_string_t
(
path_query_fragment
));
msg
.
set_body
(
body_data
,
content_type
);
return
request
(
msg
,
token
);
}
/// <summary>
/// Asynchronously sends an HTTP request with a string body. Assumes the
/// character encoding of the string is UTF-8.
/// </summary>
/// <param name="mtd">HTTP request method.</param>
/// <param name="path_query_fragment">String containing the path, query, and fragment, relative to the http_client's
/// base URI.</param> <param name="content_type">A string holding the MIME type of the message body.</param> <param
/// name="body_data">String containing the text to use in the message body.</param> <param name="token">Cancellation
/// token for cancellation of this request operation.</param> <returns>An asynchronous operation that is completed
/// once a response from the request is received.</returns>
pplx
::
task
<
http_response
>
request
(
const
method
&
mtd
,
const
utf8string
&
path_query_fragment
,
utf8string
&&
body_data
,
const
utf8string
&
content_type
=
"text/plain; charset=utf-8"
,
const
pplx
::
cancellation_token
&
token
=
pplx
::
cancellation_token
::
none
())
{
http_request
msg
(
mtd
);
msg
.
set_request_uri
(
::
utility
::
conversions
::
to_string_t
(
path_query_fragment
));
msg
.
set_body
(
std
::
move
(
body_data
),
content_type
);
return
request
(
msg
,
token
);
}
/// <summary>
/// Asynchronously sends an HTTP request with a string body. Assumes the
/// character encoding of the string is UTF-16 will perform conversion to UTF-8.
/// </summary>
/// <param name="mtd">HTTP request method.</param>
/// <param name="path_query_fragment">String containing the path, query, and fragment, relative to the http_client's
/// base URI.</param> <param name="content_type">A string holding the MIME type of the message body.</param> <param
/// name="body_data">String containing the text to use in the message body.</param> <param name="token">Cancellation
/// token for cancellation of this request operation.</param> <returns>An asynchronous operation that is completed
/// once a response from the request is received.</returns>
pplx
::
task
<
http_response
>
request
(
const
method
&
mtd
,
const
utf16string
&
path_query_fragment
,
const
utf16string
&
body_data
,
const
utf16string
&
content_type
=
utility
::
conversions
::
to_utf16string
(
"text/plain"
),
const
pplx
::
cancellation_token
&
token
=
pplx
::
cancellation_token
::
none
())
{
http_request
msg
(
mtd
);
msg
.
set_request_uri
(
::
utility
::
conversions
::
to_string_t
(
path_query_fragment
));
msg
.
set_body
(
body_data
,
content_type
);
return
request
(
msg
,
token
);
}
/// <summary>
/// Asynchronously sends an HTTP request with a string body. Assumes the
/// character encoding of the string is UTF-8.
/// </summary>
/// <param name="mtd">HTTP request method.</param>
/// <param name="path_query_fragment">String containing the path, query, and fragment, relative to the http_client's
/// base URI.</param> <param name="body_data">String containing the text to use in the message body.</param> <param
/// name="token">Cancellation token for cancellation of this request operation.</param> <returns>An asynchronous
/// operation that is completed once a response from the request is received.</returns>
pplx
::
task
<
http_response
>
request
(
const
method
&
mtd
,
const
utf8string
&
path_query_fragment
,
const
utf8string
&
body_data
,
const
pplx
::
cancellation_token
&
token
)
{
return
request
(
mtd
,
path_query_fragment
,
body_data
,
"text/plain; charset=utf-8"
,
token
);
}
/// <summary>
/// Asynchronously sends an HTTP request with a string body. Assumes the
/// character encoding of the string is UTF-8.
/// </summary>
/// <param name="mtd">HTTP request method.</param>
/// <param name="path_query_fragment">String containing the path, query, and fragment, relative to the http_client's
/// base URI.</param> <param name="body_data">String containing the text to use in the message body.</param> <param
/// name="token">Cancellation token for cancellation of this request operation.</param> <returns>An asynchronous
/// operation that is completed once a response from the request is received.</returns>
pplx
::
task
<
http_response
>
request
(
const
method
&
mtd
,
const
utf8string
&
path_query_fragment
,
utf8string
&&
body_data
,
const
pplx
::
cancellation_token
&
token
)
{
http_request
msg
(
mtd
);
msg
.
set_request_uri
(
::
utility
::
conversions
::
to_string_t
(
path_query_fragment
));
msg
.
set_body
(
std
::
move
(
body_data
),
"text/plain; charset=utf-8"
);
return
request
(
msg
,
token
);
}
/// <summary>
/// Asynchronously sends an HTTP request with a string body. Assumes
/// the character encoding of the string is UTF-16 will perform conversion to UTF-8.
/// </summary>
/// <param name="mtd">HTTP request method.</param>
/// <param name="path_query_fragment">String containing the path, query, and fragment, relative to the http_client's
/// base URI.</param> <param name="body_data">String containing the text to use in the message body.</param> <param
/// name="token">Cancellation token for cancellation of this request operation.</param> <returns>An asynchronous
/// operation that is completed once a response from the request is received.</returns>
pplx
::
task
<
http_response
>
request
(
const
method
&
mtd
,
const
utf16string
&
path_query_fragment
,
const
utf16string
&
body_data
,
const
pplx
::
cancellation_token
&
token
)
{
return
request
(
mtd
,
path_query_fragment
,
body_data
,
::
utility
::
conversions
::
to_utf16string
(
"text/plain"
),
token
);
}
#if !defined(__cplusplus_winrt)
/// <summary>
/// Asynchronously sends an HTTP request.
/// </summary>
/// <param name="mtd">HTTP request method.</param>
/// <param name="path_query_fragment">String containing the path, query, and fragment, relative to the http_client's
/// base URI.</param> <param name="body">An asynchronous stream representing the body data.</param> <param
/// name="content_type">A string holding the MIME type of the message body.</param> <param name="token">Cancellation
/// token for cancellation of this request operation.</param> <returns>A task that is completed once a response from
/// the request is received.</returns>
pplx
::
task
<
http_response
>
request
(
const
method
&
mtd
,
const
utility
::
string_t
&
path_query_fragment
,
const
concurrency
::
streams
::
istream
&
body
,
const
utility
::
string_t
&
content_type
=
_XPLATSTR
(
"application/octet-stream"
),
const
pplx
::
cancellation_token
&
token
=
pplx
::
cancellation_token
::
none
())
{
http_request
msg
(
mtd
);
msg
.
set_request_uri
(
path_query_fragment
);
msg
.
set_body
(
body
,
content_type
);
return
request
(
msg
,
token
);
}
/// <summary>
/// Asynchronously sends an HTTP request.
/// </summary>
/// <param name="mtd">HTTP request method.</param>
/// <param name="path_query_fragment">String containing the path, query, and fragment, relative to the http_client's
/// base URI.</param> <param name="body">An asynchronous stream representing the body data.</param> <param
/// name="token">Cancellation token for cancellation of this request operation.</param> <returns>A task that is
/// completed once a response from the request is received.</returns>
pplx
::
task
<
http_response
>
request
(
const
method
&
mtd
,
const
utility
::
string_t
&
path_query_fragment
,
const
concurrency
::
streams
::
istream
&
body
,
const
pplx
::
cancellation_token
&
token
)
{
return
request
(
mtd
,
path_query_fragment
,
body
,
_XPLATSTR
(
"application/octet-stream"
),
token
);
}
#endif // __cplusplus_winrt
/// <summary>
/// Asynchronously sends an HTTP request.
/// </summary>
/// <param name="mtd">HTTP request method.</param>
/// <param name="path_query_fragment">String containing the path, query, and fragment, relative to the http_client's
/// base URI.</param> <param name="body">An asynchronous stream representing the body data.</param> <param
/// name="content_length">Size of the message body.</param> <param name="content_type">A string holding the MIME
/// type of the message body.</param> <param name="token">Cancellation token for cancellation of this request
/// operation.</param> <returns>A task that is completed once a response from the request is received.</returns>
/// <remarks>Winrt requires to provide content_length.</remarks>
pplx
::
task
<
http_response
>
request
(
const
method
&
mtd
,
const
utility
::
string_t
&
path_query_fragment
,
const
concurrency
::
streams
::
istream
&
body
,
size_t
content_length
,
const
utility
::
string_t
&
content_type
=
_XPLATSTR
(
"application/octet-stream"
),
const
pplx
::
cancellation_token
&
token
=
pplx
::
cancellation_token
::
none
())
{
http_request
msg
(
mtd
);
msg
.
set_request_uri
(
path_query_fragment
);
msg
.
set_body
(
body
,
content_length
,
content_type
);
return
request
(
msg
,
token
);
}
/// <summary>
/// Asynchronously sends an HTTP request.
/// </summary>
/// <param name="mtd">HTTP request method.</param>
/// <param name="path_query_fragment">String containing the path, query, and fragment, relative to the http_client's
/// base URI.</param> <param name="body">An asynchronous stream representing the body data.</param> <param
/// name="content_length">Size of the message body.</param> <param name="token">Cancellation token for cancellation
/// of this request operation.</param> <returns>A task that is completed once a response from the request is
/// received.</returns> <remarks>Winrt requires to provide content_length.</remarks>
pplx
::
task
<
http_response
>
request
(
const
method
&
mtd
,
const
utility
::
string_t
&
path_query_fragment
,
const
concurrency
::
streams
::
istream
&
body
,
size_t
content_length
,
const
pplx
::
cancellation_token
&
token
)
{
return
request
(
mtd
,
path_query_fragment
,
body
,
content_length
,
_XPLATSTR
(
"application/octet-stream"
),
token
);
}
private:
std
::
shared_ptr
<::
web
::
http
::
client
::
http_pipeline
>
m_pipeline
;
};
namespace
details
{
#if defined(_WIN32)
extern
const
utility
::
char_t
*
get_with_body_err_msg
;
#endif
}
// namespace details
}
// namespace client
}
// namespace http
}
// namespace web
#endif
cpprestsdk_static_tester/vcpkg/include/cpprest/http_compression.h
0 → 100644
View file @
14571fd2
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* HTTP Library: Compression and decompression interfaces
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
namespace
web
{
namespace
http
{
namespace
compression
{
/// <summary>
/// Hint as to whether a compress or decompress call is meant to be the last for a particular HTTP request or reply
/// </summary>
enum
operation_hint
{
is_last
,
// Used for the expected last compress() call, or for an expected single decompress() call
has_more
// Used when further compress() calls will be made, or when multiple decompress() calls may be required
};
/// <summary>
/// Result structure for asynchronous compression and decompression operations
/// </summary>
struct
operation_result
{
size_t
input_bytes_processed
;
// From the input buffer
size_t
output_bytes_produced
;
// To the output buffer
bool
done
;
// For compress, set when 'last' is true and there was enough space to complete compression;
// for decompress, set if the end of the decompression stream has been reached
};
/// <summary>
/// Compression interface for use with HTTP requests
/// </summary>
class
compress_provider
{
public:
virtual
const
utility
::
string_t
&
algorithm
()
const
=
0
;
virtual
size_t
compress
(
const
uint8_t
*
input
,
size_t
input_size
,
uint8_t
*
output
,
size_t
output_size
,
operation_hint
hint
,
size_t
&
input_bytes_processed
,
bool
&
done
)
=
0
;
virtual
pplx
::
task
<
operation_result
>
compress
(
const
uint8_t
*
input
,
size_t
input_size
,
uint8_t
*
output
,
size_t
output_size
,
operation_hint
hint
)
=
0
;
virtual
void
reset
()
=
0
;
virtual
~
compress_provider
()
=
default
;
};
/// <summary>
/// Decompression interface for use with HTTP requests
/// </summary>
class
decompress_provider
{
public:
virtual
const
utility
::
string_t
&
algorithm
()
const
=
0
;
virtual
size_t
decompress
(
const
uint8_t
*
input
,
size_t
input_size
,
uint8_t
*
output
,
size_t
output_size
,
operation_hint
hint
,
size_t
&
input_bytes_processed
,
bool
&
done
)
=
0
;
virtual
pplx
::
task
<
operation_result
>
decompress
(
const
uint8_t
*
input
,
size_t
input_size
,
uint8_t
*
output
,
size_t
output_size
,
operation_hint
hint
)
=
0
;
virtual
void
reset
()
=
0
;
virtual
~
decompress_provider
()
=
default
;
};
/// <summary>
/// Factory interface for compressors for use with received HTTP requests
/// </summary>
class
compress_factory
{
public:
virtual
const
utility
::
string_t
&
algorithm
()
const
=
0
;
virtual
std
::
unique_ptr
<
compress_provider
>
make_compressor
()
const
=
0
;
virtual
~
compress_factory
()
=
default
;
};
/// <summary>
/// Factory interface for decompressors for use with HTTP requests
/// </summary>
class
decompress_factory
{
public:
virtual
const
utility
::
string_t
&
algorithm
()
const
=
0
;
virtual
uint16_t
weight
()
const
=
0
;
virtual
std
::
unique_ptr
<
decompress_provider
>
make_decompressor
()
const
=
0
;
virtual
~
decompress_factory
()
=
default
;
};
/// <summary>
/// Built-in compression support
/// </summary>
namespace
builtin
{
/// <summary>
/// Test whether cpprestsdk was built with built-in compression support
/// <returns>True if cpprestsdk was built with built-in compression support, and false if not.</returns>
/// </summary>
_ASYNCRTIMP
bool
supported
();
/// <summary>
// String constants for each built-in compression algorithm, for convenient use with the factory functions
/// </summary>
namespace
algorithm
{
#if defined(_MSC_VER) && _MSC_VER < 1900
const
utility
::
char_t
*
const
GZIP
=
_XPLATSTR
(
"gzip"
);
const
utility
::
char_t
*
const
DEFLATE
=
_XPLATSTR
(
"deflate"
);
const
utility
::
char_t
*
const
BROTLI
=
_XPLATSTR
(
"br"
);
#else // ^^^ VS2013 and before ^^^ // vvv VS2015+, and everything else vvv
constexpr
const
utility
::
char_t
*
const
GZIP
=
_XPLATSTR
(
"gzip"
);
constexpr
const
utility
::
char_t
*
const
DEFLATE
=
_XPLATSTR
(
"deflate"
);
constexpr
const
utility
::
char_t
*
const
BROTLI
=
_XPLATSTR
(
"br"
);
#endif
/// <summary>
/// Test whether cpprestsdk was built with built-in compression support and
/// the supplied string matches a supported built-in algorithm
/// <param name="algorithm">The name of the algorithm to test for built-in support.</param>
/// <returns>True if cpprestsdk was built with built-in compression support and
/// the supplied string matches a supported built-in algorithm, and false if not.</returns>
/// <summary>
_ASYNCRTIMP
bool
supported
(
const
utility
::
string_t
&
algorithm
);
}
// namespace algorithm
/// <summary>
/// Factory function to instantiate a built-in compression provider with default parameters by compression algorithm
/// name.
/// </summary>
/// <param name="algorithm">The name of the algorithm for which to instantiate a provider.</param>
/// <returns>
/// A caller-owned pointer to a provider of the requested-type, or to nullptr if no such built-in type exists.
/// </returns>
_ASYNCRTIMP
std
::
unique_ptr
<
compress_provider
>
make_compressor
(
const
utility
::
string_t
&
algorithm
);
/// <summary>
/// Factory function to instantiate a built-in decompression provider with default parameters by compression algorithm
/// name.
/// </summary>
/// <param name="algorithm">The name of the algorithm for which to instantiate a provider.</param>
/// <returns>
/// A caller-owned pointer to a provider of the requested-type, or to nullptr if no such built-in type exists.
/// </returns>
_ASYNCRTIMP
std
::
unique_ptr
<
decompress_provider
>
make_decompressor
(
const
utility
::
string_t
&
algorithm
);
/// <summary>
/// Factory function to obtain a pointer to a built-in compression provider factory by compression algorithm name.
/// </summary>
/// <param name="algorithm">The name of the algorithm for which to find a factory.</param>
/// <returns>
/// A caller-owned pointer to a provider of the requested-type, or to nullptr if no such built-in type exists.
/// </returns>
_ASYNCRTIMP
std
::
shared_ptr
<
compress_factory
>
get_compress_factory
(
const
utility
::
string_t
&
algorithm
);
/// <summary>
/// Factory function to obtain a pointer to a built-in decompression provider factory by compression algorithm name.
/// </summary>
/// <param name="algorithm">The name of the algorithm for which to find a factory.</param>
/// <returns>
/// A caller-owned pointer to a provider of the requested-type, or to nullptr if no such built-in type exists.
/// </returns>
_ASYNCRTIMP
std
::
shared_ptr
<
decompress_factory
>
get_decompress_factory
(
const
utility
::
string_t
&
algorithm
);
/// <summary>
// Factory function to instantiate a built-in gzip compression provider with caller-selected parameters.
/// </summary>
/// <returns>
/// A caller-owned pointer to a gzip compression provider, or to nullptr if the library was built without built-in
/// compression support.
/// </returns>
_ASYNCRTIMP
std
::
unique_ptr
<
compress_provider
>
make_gzip_compressor
(
int
compressionLevel
,
int
method
,
int
strategy
,
int
memLevel
);
/// <summary>
// Factory function to instantiate a built-in deflate compression provider with caller-selected parameters.
/// </summary>
/// <returns>
/// A caller-owned pointer to a deflate compression provider, or to nullptr if the library was built without built-in
/// compression support..
/// </returns>
_ASYNCRTIMP
std
::
unique_ptr
<
compress_provider
>
make_deflate_compressor
(
int
compressionLevel
,
int
method
,
int
strategy
,
int
memLevel
);
/// <summary>
// Factory function to instantiate a built-in Brotli compression provider with caller-selected parameters.
/// </summary>
/// <returns>
/// A caller-owned pointer to a Brotli compression provider, or to nullptr if the library was built without built-in
/// compression support.
/// </returns>
_ASYNCRTIMP
std
::
unique_ptr
<
compress_provider
>
make_brotli_compressor
(
uint32_t
window
,
uint32_t
quality
,
uint32_t
mode
,
uint32_t
block
,
uint32_t
nomodel
,
uint32_t
hint
);
}
// namespace builtin
/// <summary>
/// Factory function to instantiate a compression provider factory by compression algorithm name.
/// </summary>
/// <param name="algorithm">The name of the algorithm supported by the factory. Must match that returned by the
/// <c>web::http::compression::compress_provider</c> type instantiated by the factory's make_compressor function.
/// The supplied string is copied, and thus need not remain valid once the call returns.</param>
/// <param name="make_compressor">A factory function to be used to instantiate a compressor matching the factory's
/// reported algorithm.</param>
/// <returns>
/// A pointer to a generic provider factory implementation configured with the supplied parameters.
/// </returns>
/// <remarks>
/// This method may be used to conveniently instantiate a factory object for a caller-selected <c>compress_provider</c>.
/// That provider may be of the caller's own design, or it may be one of the built-in types. As such, this method may
/// be helpful when a caller wishes to build vectors containing a mix of custom and built-in providers.
/// </remarks>
_ASYNCRTIMP
std
::
shared_ptr
<
compress_factory
>
make_compress_factory
(
const
utility
::
string_t
&
algorithm
,
std
::
function
<
std
::
unique_ptr
<
compress_provider
>
()
>
make_compressor
);
/// <summary>
/// Factory function to instantiate a decompression provider factory by compression algorithm name.
/// </summary>
/// <param name="algorithm">The name of the algorithm supported by the factory. Must match that returned by the
/// <c>web::http::compression::decompress_provider</c> type instantiated by the factory's make_decompressor function.
/// The supplied string is copied, and thus need not remain valid once the call returns.</param>
/// <param name="weight">A numeric weight for the compression algorithm, times 1000, for use as a "quality value" when
/// requesting that the server send a compressed response. Valid values are between 0 and 1000, inclusive, where higher
/// values indicate more preferred algorithms, and 0 indicates that the algorithm is not allowed; values greater than
/// 1000 are treated as 1000.</param>
/// <param name="make_decompressor">A factory function to be used to instantiate a decompressor matching the factory's
/// reported algorithm.</param>
/// <returns>
/// A pointer to a generic provider factory implementation configured with the supplied parameters.
/// </returns>
/// <remarks>
/// This method may be used to conveniently instantiate a factory object for a caller-selected
/// <c>decompress_provider</c>. That provider may be of the caller's own design, or it may be one of the built-in
/// types. As such, this method may be helpful when a caller wishes to change the weights of built-in provider types,
/// to use custom providers without explicitly implementing a <c>decompress_factory</c>, or to build vectors containing
/// a mix of custom and built-in providers.
/// </remarks>
_ASYNCRTIMP
std
::
shared_ptr
<
decompress_factory
>
make_decompress_factory
(
const
utility
::
string_t
&
algorithm
,
uint16_t
weight
,
std
::
function
<
std
::
unique_ptr
<
decompress_provider
>
()
>
make_decompressor
);
namespace
details
{
/// <summary>
/// Header type enum for use with compressor and decompressor header parsing and building functions
/// </summary>
enum
header_types
{
transfer_encoding
,
content_encoding
,
te
,
accept_encoding
};
/// <summary>
/// Factory function to instantiate an appropriate compression provider, if any.
/// </summary>
/// <param name="encoding">A TE or Accept-Encoding header to interpret.</param>
/// <param name="type">Specifies the type of header whose contents are in the encoding parameter; valid values are
/// <c>header_type::te</c> and <c>header_type::accept_encoding</c>.</param>
/// <param name="preferred">A compressor object of the caller's preferred (possibly custom) type, which is used if
/// possible.</param>
/// <param name="factories">A collection of factory objects for use in construction of an appropriate compressor, if
/// any. If empty or not supplied, the set of supported built-in compressors is used.</param>
/// <returns>
/// A pointer to a compressor object that is acceptable per the supplied header, or to nullptr if no matching
/// algorithm is found.
/// </returns>
_ASYNCRTIMP
std
::
unique_ptr
<
compress_provider
>
get_compressor_from_header
(
const
utility
::
string_t
&
encoding
,
header_types
type
,
const
std
::
vector
<
std
::
shared_ptr
<
compress_factory
>>&
factories
=
std
::
vector
<
std
::
shared_ptr
<
compress_factory
>>
());
/// <summary>
/// Factory function to instantiate an appropriate decompression provider, if any.
/// </summary>
/// <param name="encoding">A Transfer-Encoding or Content-Encoding header to interpret.</param>
/// <param name="type">Specifies the type of header whose contents are in the encoding parameter; valid values are
/// <c>header_type::transfer_encoding</c> and <c>header_type::content_encoding</c>.</param>
/// <param name="factories">A collection of factory objects for use in construction of an appropriate decompressor,
/// if any. If empty or not supplied, the set of supported built-in compressors is used.</param>
/// <returns>
/// A pointer to a decompressor object that is acceptable per the supplied header, or to nullptr if no matching
/// algorithm is found.
/// </returns>
_ASYNCRTIMP
std
::
unique_ptr
<
decompress_provider
>
get_decompressor_from_header
(
const
utility
::
string_t
&
encoding
,
header_types
type
,
const
std
::
vector
<
std
::
shared_ptr
<
decompress_factory
>>&
factories
=
std
::
vector
<
std
::
shared_ptr
<
decompress_factory
>>
());
/// <summary>
/// Helper function to compose a TE or Accept-Encoding header with supported, and possibly ranked, compression
/// algorithms.
/// </summary>
/// <param name="type">Specifies the type of header to be built; valid values are <c>header_type::te</c> and
/// <c>header_type::accept_encoding</c>.</param>
/// <param name="factories">A collection of factory objects for use in header construction. If empty or not
/// supplied, the set of supported built-in compressors is used.</param>
/// <returns>
/// A well-formed header, without the header name, specifying the acceptable ranked compression types.
/// </returns>
_ASYNCRTIMP
utility
::
string_t
build_supported_header
(
header_types
type
,
const
std
::
vector
<
std
::
shared_ptr
<
decompress_factory
>>&
factories
=
std
::
vector
<
std
::
shared_ptr
<
decompress_factory
>>
());
}
// namespace details
}
// namespace compression
}
// namespace http
}
// namespace web
cpprestsdk_static_tester/vcpkg/include/cpprest/http_headers.h
0 → 100644
View file @
14571fd2
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#include
"cpprest/asyncrt_utils.h"
#include
<map>
#include
<memory>
#include
<string>
#include
<system_error>
#include
<vector>
namespace
web
{
namespace
http
{
/// <summary>
/// Binds an individual reference to a string value.
/// </summary>
/// <typeparam name="key_type">The type of string value.</typeparam>
/// <typeparam name="_t">The type of the value to bind to.</typeparam>
/// <param name="text">The string value.</param>
/// <param name="ref">The value to bind to.</param>
/// <returns><c>true</c> if the binding succeeds, <c>false</c> otherwise.</returns>
template
<
typename
key_type
,
typename
_t
>
CASABLANCA_DEPRECATED
(
"This API is deprecated and will be removed in a future release, std::istringstream instead."
)
bool
bind
(
const
key_type
&
text
,
_t
&
ref
)
// const
{
utility
::
istringstream_t
iss
(
text
);
iss
>>
ref
;
if
(
iss
.
fail
()
||
!
iss
.
eof
())
{
return
false
;
}
return
true
;
}
/// <summary>
/// Binds an individual reference to a string value.
/// This specialization is need because <c>istringstream::>></c> delimits on whitespace.
/// </summary>
/// <typeparam name="key_type">The type of the string value.</typeparam>
/// <param name="text">The string value.</param>
/// <param name="ref">The value to bind to.</param>
/// <returns><c>true</c> if the binding succeeds, <c>false</c> otherwise.</returns>
template
<
typename
key_type
>
CASABLANCA_DEPRECATED
(
"This API is deprecated and will be removed in a future release."
)
bool
bind
(
const
key_type
&
text
,
utility
::
string_t
&
ref
)
// const
{
ref
=
text
;
return
true
;
}
namespace
details
{
template
<
typename
key_type
,
typename
_t
>
bool
bind_impl
(
const
key_type
&
text
,
_t
&
ref
)
{
utility
::
istringstream_t
iss
(
text
);
iss
.
imbue
(
std
::
locale
::
classic
());
iss
>>
ref
;
if
(
iss
.
fail
()
||
!
iss
.
eof
())
{
return
false
;
}
return
true
;
}
template
<
typename
key_type
>
bool
bind_impl
(
const
key_type
&
text
,
utf16string
&
ref
)
{
ref
=
utility
::
conversions
::
to_utf16string
(
text
);
return
true
;
}
template
<
typename
key_type
>
bool
bind_impl
(
const
key_type
&
text
,
std
::
string
&
ref
)
{
ref
=
utility
::
conversions
::
to_utf8string
(
text
);
return
true
;
}
}
// namespace details
/// <summary>
/// Represents HTTP headers, acts like a map.
/// </summary>
class
http_headers
{
public:
/// Function object to perform case insensitive comparison of wstrings.
struct
_case_insensitive_cmp
{
bool
operator
()(
const
utility
::
string_t
&
str1
,
const
utility
::
string_t
&
str2
)
const
{
return
utility
::
details
::
str_iless
(
str1
,
str2
);
}
};
private:
typedef
std
::
map
<
utility
::
string_t
,
utility
::
string_t
,
_case_insensitive_cmp
>
inner_container
;
public:
/// <summary>
/// STL-style typedefs
/// </summary>
typedef
inner_container
::
key_type
key_type
;
typedef
inner_container
::
key_compare
key_compare
;
typedef
inner_container
::
allocator_type
allocator_type
;
typedef
inner_container
::
size_type
size_type
;
typedef
inner_container
::
difference_type
difference_type
;
typedef
inner_container
::
pointer
pointer
;
typedef
inner_container
::
const_pointer
const_pointer
;
typedef
inner_container
::
reference
reference
;
typedef
inner_container
::
const_reference
const_reference
;
typedef
inner_container
::
iterator
iterator
;
typedef
inner_container
::
const_iterator
const_iterator
;
typedef
inner_container
::
reverse_iterator
reverse_iterator
;
typedef
inner_container
::
const_reverse_iterator
const_reverse_iterator
;
/// <summary>
/// Constructs an empty set of HTTP headers.
/// </summary>
http_headers
()
{}
/// <summary>
/// Copy constructor.
/// </summary>
/// <param name="other">An <c>http_headers</c> object to copy from.</param>
http_headers
(
const
http_headers
&
other
)
:
m_headers
(
other
.
m_headers
)
{}
/// <summary>
/// Assignment operator.
/// </summary>
/// <param name="other">An <c>http_headers</c> object to copy from.</param>
http_headers
&
operator
=
(
const
http_headers
&
other
)
{
if
(
this
!=
&
other
)
{
m_headers
=
other
.
m_headers
;
}
return
*
this
;
}
/// <summary>
/// Move constructor.
/// </summary>
/// <param name="other">An <c>http_headers</c> object to move.</param>
http_headers
(
http_headers
&&
other
)
:
m_headers
(
std
::
move
(
other
.
m_headers
))
{}
/// <summary>
/// Move assignment operator.
/// </summary>
/// <param name="other">An <c>http_headers</c> object to move.</param>
http_headers
&
operator
=
(
http_headers
&&
other
)
{
if
(
this
!=
&
other
)
{
m_headers
=
std
::
move
(
other
.
m_headers
);
}
return
*
this
;
}
/// <summary>
/// Adds a header field using the '<<' operator.
/// </summary>
/// <param name="name">The name of the header field.</param>
/// <param name="value">The value of the header field.</param>
/// <remarks>If the header field exists, the value will be combined as comma separated string.</remarks>
template
<
typename
_t1
>
void
add
(
const
key_type
&
name
,
const
_t1
&
value
)
{
auto
printedValue
=
utility
::
conversions
::
details
::
print_string
(
value
);
auto
&
mapVal
=
m_headers
[
name
];
if
(
mapVal
.
empty
())
{
mapVal
=
std
::
move
(
printedValue
);
}
else
{
mapVal
.
append
(
_XPLATSTR
(
", "
)).
append
(
std
::
move
(
printedValue
));
}
}
/// <summary>
/// Removes a header field.
/// </summary>
/// <param name="name">The name of the header field.</param>
void
remove
(
const
key_type
&
name
)
{
m_headers
.
erase
(
name
);
}
/// <summary>
/// Removes all elements from the headers.
/// </summary>
void
clear
()
{
m_headers
.
clear
();
}
/// <summary>
/// Checks if there is a header with the given key.
/// </summary>
/// <param name="name">The name of the header field.</param>
/// <returns><c>true</c> if there is a header with the given name, <c>false</c> otherwise.</returns>
bool
has
(
const
key_type
&
name
)
const
{
return
m_headers
.
find
(
name
)
!=
m_headers
.
end
();
}
/// <summary>
/// Returns the number of header fields.
/// </summary>
/// <returns>Number of header fields.</returns>
size_type
size
()
const
{
return
m_headers
.
size
();
}
/// <summary>
/// Tests to see if there are any header fields.
/// </summary>
/// <returns><c>true</c> if there are no headers, <c>false</c> otherwise.</returns>
bool
empty
()
const
{
return
m_headers
.
empty
();
}
/// <summary>
/// Returns a reference to header field with given name, if there is no header field one is inserted.
/// </summary>
utility
::
string_t
&
operator
[](
const
key_type
&
name
)
{
return
m_headers
[
name
];
}
/// <summary>
/// Checks if a header field exists with given name and returns an iterator if found. Otherwise
/// and iterator to end is returned.
/// </summary>
/// <param name="name">The name of the header field.</param>
/// <returns>An iterator to where the HTTP header is found.</returns>
iterator
find
(
const
key_type
&
name
)
{
return
m_headers
.
find
(
name
);
}
const_iterator
find
(
const
key_type
&
name
)
const
{
return
m_headers
.
find
(
name
);
}
/// <summary>
/// Attempts to match a header field with the given name using the '>>' operator.
/// </summary>
/// <param name="name">The name of the header field.</param>
/// <param name="value">The value of the header field.</param>
/// <returns><c>true</c> if header field was found and successfully stored in value parameter.</returns>
template
<
typename
_t1
>
bool
match
(
const
key_type
&
name
,
_t1
&
value
)
const
{
auto
iter
=
m_headers
.
find
(
name
);
if
(
iter
==
m_headers
.
end
())
{
return
false
;
}
return
web
::
http
::
details
::
bind_impl
(
iter
->
second
,
value
)
||
iter
->
second
.
empty
();
}
/// <summary>
/// Returns an iterator referring to the first header field.
/// </summary>
/// <returns>An iterator to the beginning of the HTTP headers</returns>
iterator
begin
()
{
return
m_headers
.
begin
();
}
const_iterator
begin
()
const
{
return
m_headers
.
begin
();
}
/// <summary>
/// Returns an iterator referring to the past-the-end header field.
/// </summary>
/// <returns>An iterator to the element past the end of the HTTP headers.</returns>
iterator
end
()
{
return
m_headers
.
end
();
}
const_iterator
end
()
const
{
return
m_headers
.
end
();
}
/// <summary>
/// Gets the content length of the message.
/// </summary>
/// <returns>The length of the content.</returns>
_ASYNCRTIMP
utility
::
size64_t
content_length
()
const
;
/// <summary>
/// Sets the content length of the message.
/// </summary>
/// <param name="length">The length of the content.</param>
_ASYNCRTIMP
void
set_content_length
(
utility
::
size64_t
length
);
/// <summary>
/// Gets the content type of the message.
/// </summary>
/// <returns>The content type of the body.</returns>
_ASYNCRTIMP
utility
::
string_t
content_type
()
const
;
/// <summary>
/// Sets the content type of the message.
/// </summary>
/// <param name="type">The content type of the body.</param>
_ASYNCRTIMP
void
set_content_type
(
utility
::
string_t
type
);
/// <summary>
/// Gets the cache control header of the message.
/// </summary>
/// <returns>The cache control header value.</returns>
_ASYNCRTIMP
utility
::
string_t
cache_control
()
const
;
/// <summary>
/// Sets the cache control header of the message.
/// </summary>
/// <param name="control">The cache control header value.</param>
_ASYNCRTIMP
void
set_cache_control
(
utility
::
string_t
control
);
/// <summary>
/// Gets the date header of the message.
/// </summary>
/// <returns>The date header value.</returns>
_ASYNCRTIMP
utility
::
string_t
date
()
const
;
/// <summary>
/// Sets the date header of the message.
/// </summary>
/// <param name="date">The date header value.</param>
_ASYNCRTIMP
void
set_date
(
const
utility
::
datetime
&
date
);
private:
// Headers are stored in a map with case insensitive key.
inner_container
m_headers
;
};
}
// namespace http
}
// namespace web
cpprestsdk_static_tester/vcpkg/include/cpprest/http_listener.h
0 → 100644
View file @
14571fd2
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* HTTP Library: HTTP listener (server-side) APIs
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#ifndef CASA_HTTP_LISTENER_H
#define CASA_HTTP_LISTENER_H
#include
"cpprest/http_msg.h"
#include
<functional>
#include
<limits>
#if !defined(_WIN32) && !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO)
#include
<boost/asio/ssl.hpp>
#endif
#if !defined(_WIN32) || (_WIN32_WINNT >= _WIN32_WINNT_VISTA && !defined(__cplusplus_winrt)) || \
defined(CPPREST_FORCE_HTTP_LISTENER_ASIO)
namespace
web
{
namespace
http
{
/// HTTP listener is currently in beta.
namespace
experimental
{
/// HTTP server side library.
namespace
listener
{
/// <summary>
/// Configuration class used to set various options when constructing and http_listener instance.
/// </summary>
class
http_listener_config
{
public:
/// <summary>
/// Create an http_listener configuration with default options.
/// </summary>
http_listener_config
()
:
m_timeout
(
utility
::
seconds
(
120
)),
m_backlog
(
0
)
{}
/// <summary>
/// Copy constructor.
/// </summary>
/// <param name="other">http_listener_config to copy.</param>
http_listener_config
(
const
http_listener_config
&
other
)
:
m_timeout
(
other
.
m_timeout
)
,
m_backlog
(
other
.
m_backlog
)
#if !defined(_WIN32) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO)
,
m_ssl_context_callback
(
other
.
m_ssl_context_callback
)
#endif
{
}
/// <summary>
/// Move constructor.
/// <summary>
/// <param name="other">http_listener_config to move from.</param>
http_listener_config
(
http_listener_config
&&
other
)
:
m_timeout
(
std
::
move
(
other
.
m_timeout
))
,
m_backlog
(
std
::
move
(
other
.
m_backlog
))
#if !defined(_WIN32) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO)
,
m_ssl_context_callback
(
std
::
move
(
other
.
m_ssl_context_callback
))
#endif
{
}
/// <summary>
/// Assignment operator.
/// </summary>
/// <returns>http_listener_config instance.</returns>
http_listener_config
&
operator
=
(
const
http_listener_config
&
rhs
)
{
if
(
this
!=
&
rhs
)
{
m_timeout
=
rhs
.
m_timeout
;
m_backlog
=
rhs
.
m_backlog
;
#if !defined(_WIN32) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO)
m_ssl_context_callback
=
rhs
.
m_ssl_context_callback
;
#endif
}
return
*
this
;
}
/// <summary>
/// Assignment operator.
/// </summary>
/// <returns>http_listener_config instance.</returns>
http_listener_config
&
operator
=
(
http_listener_config
&&
rhs
)
{
if
(
this
!=
&
rhs
)
{
m_timeout
=
std
::
move
(
rhs
.
m_timeout
);
m_backlog
=
std
::
move
(
rhs
.
m_backlog
);
#if !defined(_WIN32) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO)
m_ssl_context_callback
=
std
::
move
(
rhs
.
m_ssl_context_callback
);
#endif
}
return
*
this
;
}
/// <summary>
/// Get the timeout
/// </summary>
/// <returns>The timeout (in seconds).</returns>
utility
::
seconds
timeout
()
const
{
return
m_timeout
;
}
/// <summary>
/// Set the timeout
/// </summary>
/// <param name="timeout">The timeout (in seconds) used for each send and receive operation on the client.</param>
void
set_timeout
(
utility
::
seconds
timeout
)
{
m_timeout
=
std
::
move
(
timeout
);
}
/// <summary>
/// Get the listen backlog
/// </summary>
/// <returns>The maximum length of the queue of pending connections, or zero for the implementation
/// default.</returns> <remarks>The implementation may not honour this value.</remarks>
int
backlog
()
const
{
return
m_backlog
;
}
/// <summary>
/// Set the listen backlog
/// </summary>
/// <param name="backlog">The maximum length of the queue of pending connections, or zero for the implementation
/// default.</param> <remarks>The implementation may not honour this value.</remarks>
void
set_backlog
(
int
backlog
)
{
m_backlog
=
backlog
;
}
#if !defined(_WIN32) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO)
/// <summary>
/// Get the callback of ssl context
/// </summary>
/// <returns>The function defined by the user of http_listener_config to configure a ssl context.</returns>
const
std
::
function
<
void
(
boost
::
asio
::
ssl
::
context
&
)
>&
get_ssl_context_callback
()
const
{
return
m_ssl_context_callback
;
}
/// <summary>
/// Set the callback of ssl context
/// </summary>
/// <param name="ssl_context_callback">The function to configure a ssl context which will setup https
/// connections.</param>
void
set_ssl_context_callback
(
const
std
::
function
<
void
(
boost
::
asio
::
ssl
::
context
&
)
>&
ssl_context_callback
)
{
m_ssl_context_callback
=
ssl_context_callback
;
}
#endif
private:
utility
::
seconds
m_timeout
;
int
m_backlog
;
#if !defined(_WIN32) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO)
std
::
function
<
void
(
boost
::
asio
::
ssl
::
context
&
)
>
m_ssl_context_callback
;
#endif
};
namespace
details
{
/// <summary>
/// Internal class for pointer to implementation design pattern.
/// </summary>
class
http_listener_impl
{
public:
http_listener_impl
()
:
m_closed
(
true
),
m_close_task
(
pplx
::
task_from_result
())
{}
_ASYNCRTIMP
http_listener_impl
(
http
::
uri
address
);
_ASYNCRTIMP
http_listener_impl
(
http
::
uri
address
,
http_listener_config
config
);
_ASYNCRTIMP
pplx
::
task
<
void
>
open
();
_ASYNCRTIMP
pplx
::
task
<
void
>
close
();
/// <summary>
/// Handler for all requests. The HTTP host uses this to dispatch a message to the pipeline.
/// </summary>
/// <remarks>Only HTTP server implementations should call this API.</remarks>
_ASYNCRTIMP
void
handle_request
(
http
::
http_request
msg
);
const
http
::
uri
&
uri
()
const
{
return
m_uri
;
}
const
http_listener_config
&
configuration
()
const
{
return
m_config
;
}
// Handlers
std
::
function
<
void
(
http
::
http_request
)
>
m_all_requests
;
std
::
map
<
http
::
method
,
std
::
function
<
void
(
http
::
http_request
)
>>
m_supported_methods
;
private:
// Default implementation for TRACE and OPTIONS.
void
handle_trace
(
http
::
http_request
message
);
void
handle_options
(
http
::
http_request
message
);
// Gets a comma separated string containing the methods supported by this listener.
utility
::
string_t
get_supported_methods
()
const
;
http
::
uri
m_uri
;
http_listener_config
m_config
;
// Used to record that the listener is closed.
bool
m_closed
;
pplx
::
task
<
void
>
m_close_task
;
};
}
// namespace details
/// <summary>
/// A class for listening and processing HTTP requests at a specific URI.
/// </summary>
class
http_listener
{
public:
/// <summary>
/// Create a listener from a URI.
/// </summary>
/// <remarks>The listener will not have been opened when returned.</remarks>
/// <param name="address">URI at which the listener should accept requests.</param>
http_listener
(
http
::
uri
address
)
:
m_impl
(
utility
::
details
::
make_unique
<
details
::
http_listener_impl
>
(
std
::
move
(
address
)))
{
}
/// <summary>
/// Create a listener with specified URI and configuration.
/// </summary>
/// <param name="address">URI at which the listener should accept requests.</param>
/// <param name="config">Configuration to create listener with.</param>
http_listener
(
http
::
uri
address
,
http_listener_config
config
)
:
m_impl
(
utility
::
details
::
make_unique
<
details
::
http_listener_impl
>
(
std
::
move
(
address
),
std
::
move
(
config
)))
{
}
/// <summary>
/// Default constructor.
/// </summary>
/// <remarks>The resulting listener cannot be used for anything, but is useful to initialize a variable
/// that will later be overwritten with a real listener instance.</remarks>
http_listener
()
:
m_impl
(
utility
::
details
::
make_unique
<
details
::
http_listener_impl
>
())
{}
/// <summary>
/// Destructor frees any held resources.
/// </summary>
/// <remarks>Call close() before allowing a listener to be destroyed.</remarks>
~
http_listener
()
{
if
(
m_impl
)
{
// As a safe guard close the listener if not already done.
// Users are required to call close, but this is just a safeguard.
try
{
m_impl
->
close
().
wait
();
}
catch
(...)
{
}
}
}
/// <summary>
/// Asynchronously open the listener, i.e. start accepting requests.
/// </summary>
/// <returns>A task that will be completed once this listener is actually opened, accepting requests.</returns>
pplx
::
task
<
void
>
open
()
{
return
m_impl
->
open
();
}
/// <summary>
/// Asynchronously stop accepting requests and close all connections.
/// </summary>
/// <returns>A task that will be completed once this listener is actually closed, no longer accepting
/// requests.</returns> <remarks> This function will stop accepting requests and wait for all outstanding handler
/// calls to finish before completing the task. Waiting on the task returned from close() within a handler and
/// blocking waiting for its result will result in a deadlock.
///
/// Call close() before allowing a listener to be destroyed.
/// </remarks>
pplx
::
task
<
void
>
close
()
{
return
m_impl
->
close
();
}
/// <summary>
/// Add a general handler to support all requests.
/// </summary>
/// <param name="handler">Function object to be called for all requests.</param>
void
support
(
const
std
::
function
<
void
(
http_request
)
>&
handler
)
{
m_impl
->
m_all_requests
=
handler
;
}
/// <summary>
/// Add support for a specific HTTP method.
/// </summary>
/// <param name="method">An HTTP method.</param>
/// <param name="handler">Function object to be called for all requests for the given HTTP method.</param>
void
support
(
const
http
::
method
&
method
,
const
std
::
function
<
void
(
http_request
)
>&
handler
)
{
m_impl
->
m_supported_methods
[
method
]
=
handler
;
}
/// <summary>
/// Get the URI of the listener.
/// </summary>
/// <returns>The URI this listener is for.</returns>
const
http
::
uri
&
uri
()
const
{
return
m_impl
->
uri
();
}
/// <summary>
/// Get the configuration of this listener.
/// </summary>
/// <returns>Configuration this listener was constructed with.</returns>
const
http_listener_config
&
configuration
()
const
{
return
m_impl
->
configuration
();
}
/// <summary>
/// Move constructor.
/// </summary>
/// <param name="other">http_listener instance to construct this one from.</param>
http_listener
(
http_listener
&&
other
)
:
m_impl
(
std
::
move
(
other
.
m_impl
))
{}
/// <summary>
/// Move assignment operator.
/// </summary>
/// <param name="other">http_listener to replace this one with.</param>
http_listener
&
operator
=
(
http_listener
&&
other
)
{
if
(
this
!=
&
other
)
{
m_impl
=
std
::
move
(
other
.
m_impl
);
}
return
*
this
;
}
private:
// No copying of listeners.
http_listener
(
const
http_listener
&
other
);
http_listener
&
operator
=
(
const
http_listener
&
other
);
std
::
unique_ptr
<
details
::
http_listener_impl
>
m_impl
;
};
}
// namespace listener
}
// namespace experimental
}
// namespace http
}
// namespace web
#endif
#endif
cpprestsdk_static_tester/vcpkg/include/cpprest/http_msg.h
0 → 100644
View file @
14571fd2
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* HTTP Library: Request and reply message definitions.
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#include
"cpprest/asyncrt_utils.h"
#include
"cpprest/containerstream.h"
#include
"cpprest/details/cpprest_compat.h"
#include
"cpprest/http_compression.h"
#include
"cpprest/http_headers.h"
#include
"cpprest/json.h"
#include
"cpprest/streams.h"
#include
"cpprest/uri.h"
#include
"pplx/pplxtasks.h"
#include
<map>
#include
<memory>
#include
<string>
#include
<system_error>
#include
<vector>
namespace
web
{
namespace
http
{
// URI class has been moved from web::http namespace to web namespace.
// The below using declarations ensure we don't break existing code.
// Please use the web::uri class going forward.
using
web
::
uri
;
using
web
::
uri_builder
;
namespace
client
{
class
http_client
;
}
/// <summary>
/// Represents the HTTP protocol version of a message, as {major, minor}.
/// </summary>
struct
http_version
{
uint8_t
major
;
uint8_t
minor
;
inline
bool
operator
==
(
const
http_version
&
other
)
const
{
return
major
==
other
.
major
&&
minor
==
other
.
minor
;
}
inline
bool
operator
<
(
const
http_version
&
other
)
const
{
return
major
<
other
.
major
||
(
major
==
other
.
major
&&
minor
<
other
.
minor
);
}
inline
bool
operator
!=
(
const
http_version
&
other
)
const
{
return
!
(
*
this
==
other
);
}
inline
bool
operator
>=
(
const
http_version
&
other
)
const
{
return
!
(
*
this
<
other
);
}
inline
bool
operator
>
(
const
http_version
&
other
)
const
{
return
!
(
*
this
<
other
||
*
this
==
other
);
}
inline
bool
operator
<=
(
const
http_version
&
other
)
const
{
return
*
this
<
other
||
*
this
==
other
;
}
/// <summary>
/// Creates <c>http_version</c> from an HTTP-Version string, "HTTP" "/" 1*DIGIT "." 1*DIGIT.
/// </summary>
/// <returns>Returns a <c>http_version</c> of {0, 0} if not successful.</returns>
static
_ASYNCRTIMP
http_version
__cdecl
from_string
(
const
std
::
string
&
http_version_string
);
/// <summary>
/// Returns the string representation of the <c>http_version</c>.
/// </summary>
_ASYNCRTIMP
std
::
string
to_utf8string
()
const
;
};
/// <summary>
/// Predefined HTTP protocol versions.
/// </summary>
class
http_versions
{
public:
_ASYNCRTIMP
static
const
http_version
HTTP_0_9
;
_ASYNCRTIMP
static
const
http_version
HTTP_1_0
;
_ASYNCRTIMP
static
const
http_version
HTTP_1_1
;
};
/// <summary>
/// Predefined method strings for the standard HTTP methods mentioned in the
/// HTTP 1.1 specification.
/// </summary>
typedef
utility
::
string_t
method
;
/// <summary>
/// Common HTTP methods.
/// </summary>
class
methods
{
public:
#define _METHODS
#define DAT(a, b) _ASYNCRTIMP const static method a;
#include
"cpprest/details/http_constants.dat"
#undef _METHODS
#undef DAT
};
typedef
unsigned
short
status_code
;
/// <summary>
/// Predefined values for all of the standard HTTP 1.1 response status codes.
/// </summary>
class
status_codes
{
public:
#define _PHRASES
#define DAT(a, b, c) const static status_code a = b;
#include
"cpprest/details/http_constants.dat"
#undef _PHRASES
#undef DAT
};
namespace
details
{
/// <summary>
/// Constants for MIME types.
/// </summary>
class
mime_types
{
public:
#define _MIME_TYPES
#define DAT(a, b) _ASYNCRTIMP const static utility::string_t a;
#include
"cpprest/details/http_constants.dat"
#undef _MIME_TYPES
#undef DAT
};
/// <summary>
/// Constants for charset types.
/// </summary>
class
charset_types
{
public:
#define _CHARSET_TYPES
#define DAT(a, b) _ASYNCRTIMP const static utility::string_t a;
#include
"cpprest/details/http_constants.dat"
#undef _CHARSET_TYPES
#undef DAT
};
}
// namespace details
/// Message direction
namespace
message_direction
{
/// <summary>
/// Enumeration used to denote the direction of a message: a request with a body is
/// an upload, a response with a body is a download.
/// </summary>
enum
direction
{
upload
,
download
};
}
// namespace message_direction
typedef
utility
::
string_t
reason_phrase
;
typedef
std
::
function
<
void
(
message_direction
::
direction
,
utility
::
size64_t
)
>
progress_handler
;
struct
http_status_to_phrase
{
unsigned
short
id
;
reason_phrase
phrase
;
};
/// <summary>
/// Constants for the HTTP headers mentioned in RFC 2616.
/// </summary>
class
header_names
{
public:
#define _HEADER_NAMES
#define DAT(a, b) _ASYNCRTIMP const static utility::string_t a;
#include
"cpprest/details/http_constants.dat"
#undef _HEADER_NAMES
#undef DAT
};
/// <summary>
/// Represents an HTTP error. This class holds an error message and an optional error code.
/// </summary>
class
http_exception
:
public
std
::
exception
{
public:
/// <summary>
/// Creates an <c>http_exception</c> with just a string message and no error code.
/// </summary>
/// <param name="whatArg">Error message string.</param>
http_exception
(
const
utility
::
string_t
&
whatArg
)
:
m_msg
(
utility
::
conversions
::
to_utf8string
(
whatArg
))
{}
#ifdef _WIN32
/// <summary>
/// Creates an <c>http_exception</c> with just a string message and no error code.
/// </summary>
/// <param name="whatArg">Error message string.</param>
http_exception
(
std
::
string
whatArg
)
:
m_msg
(
std
::
move
(
whatArg
))
{}
#endif
/// <summary>
/// Creates an <c>http_exception</c> with from a error code using the current platform error category.
/// The message of the error code will be used as the what() string message.
/// </summary>
/// <param name="errorCode">Error code value.</param>
http_exception
(
int
errorCode
)
:
m_errorCode
(
utility
::
details
::
create_error_code
(
errorCode
))
{
m_msg
=
m_errorCode
.
message
();
}
/// <summary>
/// Creates an <c>http_exception</c> with from a error code using the current platform error category.
/// </summary>
/// <param name="errorCode">Error code value.</param>
/// <param name="whatArg">Message to use in what() string.</param>
http_exception
(
int
errorCode
,
const
utility
::
string_t
&
whatArg
)
:
m_errorCode
(
utility
::
details
::
create_error_code
(
errorCode
))
,
m_msg
(
utility
::
conversions
::
to_utf8string
(
whatArg
))
{
}
#ifdef _WIN32
/// <summary>
/// Creates an <c>http_exception</c> with from a error code using the current platform error category.
/// </summary>
/// <param name="errorCode">Error code value.</param>
/// <param name="whatArg">Message to use in what() string.</param>
http_exception
(
int
errorCode
,
std
::
string
whatArg
)
:
m_errorCode
(
utility
::
details
::
create_error_code
(
errorCode
)),
m_msg
(
std
::
move
(
whatArg
))
{
}
#endif
/// <summary>
/// Creates an <c>http_exception</c> with from a error code and category. The message of the error code will be used
/// as the <c>what</c> string message.
/// </summary>
/// <param name="errorCode">Error code value.</param>
/// <param name="cat">Error category for the code.</param>
http_exception
(
int
errorCode
,
const
std
::
error_category
&
cat
)
:
m_errorCode
(
std
::
error_code
(
errorCode
,
cat
))
{
m_msg
=
m_errorCode
.
message
();
}
/// <summary>
/// Creates an <c>http_exception</c> with from a error code with a category, and a string message.
/// </summary>
/// <param name="errorCode">Error code value.</param>
/// <param name="whatArg">Error message string.</param>
http_exception
(
std
::
error_code
errorCode
,
const
utility
::
string_t
&
whatArg
)
:
m_errorCode
(
std
::
move
(
errorCode
)),
m_msg
(
utility
::
conversions
::
to_utf8string
(
whatArg
))
{
}
#ifdef _WIN32
/// <summary>
/// Creates an <c>http_exception</c> with from a error code with a category, and a string message.
/// </summary>
/// <param name="errorCode">Error code value.</param>
/// <param name="whatArg">Error message string.</param>
http_exception
(
std
::
error_code
errorCode
,
std
::
string
whatArg
)
:
m_errorCode
(
std
::
move
(
errorCode
)),
m_msg
(
std
::
move
(
whatArg
))
{
}
#endif
/// <summary>
/// Gets a string identifying the cause of the exception.
/// </summary>
/// <returns>A null terminated character string.</returns>
const
char
*
what
()
const
CPPREST_NOEXCEPT
{
return
m_msg
.
c_str
();
}
/// <summary>
/// Retrieves the underlying error code causing this exception.
/// </summary>
/// <returns>A std::error_code.</returns>
const
std
::
error_code
&
error_code
()
const
{
return
m_errorCode
;
}
private:
std
::
error_code
m_errorCode
;
std
::
string
m_msg
;
};
namespace
details
{
/// <summary>
/// Base class for HTTP messages.
/// This class is to store common functionality so it isn't duplicated on
/// both the request and response side.
/// </summary>
class
http_msg_base
{
public:
friend
class
http
::
client
::
http_client
;
_ASYNCRTIMP
http_msg_base
();
virtual
~
http_msg_base
()
{}
http
::
http_version
http_version
()
const
{
return
m_http_version
;
}
http_headers
&
headers
()
{
return
m_headers
;
}
_ASYNCRTIMP
void
set_body
(
const
concurrency
::
streams
::
istream
&
instream
,
const
utf8string
&
contentType
);
_ASYNCRTIMP
void
set_body
(
const
concurrency
::
streams
::
istream
&
instream
,
const
utf16string
&
contentType
);
_ASYNCRTIMP
void
set_body
(
const
concurrency
::
streams
::
istream
&
instream
,
utility
::
size64_t
contentLength
,
const
utf8string
&
contentType
);
_ASYNCRTIMP
void
set_body
(
const
concurrency
::
streams
::
istream
&
instream
,
utility
::
size64_t
contentLength
,
const
utf16string
&
contentType
);
/// <summary>
/// Helper function for extract functions. Parses the Content-Type header and check to make sure it matches,
/// throws an exception if not.
/// </summary>
/// <param name="ignore_content_type">If true ignores the Content-Type header value.</param>
/// <param name="check_content_type">Function to verify additional information on Content-Type.</param>
/// <returns>A string containing the charset, an empty string if no Content-Type header is empty.</returns>
utility
::
string_t
parse_and_check_content_type
(
bool
ignore_content_type
,
const
std
::
function
<
bool
(
const
utility
::
string_t
&
)
>&
check_content_type
);
_ASYNCRTIMP
utf8string
extract_utf8string
(
bool
ignore_content_type
=
false
);
_ASYNCRTIMP
utf16string
extract_utf16string
(
bool
ignore_content_type
=
false
);
_ASYNCRTIMP
utility
::
string_t
extract_string
(
bool
ignore_content_type
=
false
);
_ASYNCRTIMP
json
::
value
_extract_json
(
bool
ignore_content_type
=
false
);
_ASYNCRTIMP
std
::
vector
<
unsigned
char
>
_extract_vector
();
virtual
_ASYNCRTIMP
utility
::
string_t
to_string
()
const
;
/// <summary>
/// Completes this message
/// </summary>
virtual
_ASYNCRTIMP
void
_complete
(
utility
::
size64_t
bodySize
,
const
std
::
exception_ptr
&
exceptionPtr
=
std
::
exception_ptr
());
/// <summary>
/// Set the stream through which the message body could be read
/// </summary>
void
set_instream
(
const
concurrency
::
streams
::
istream
&
instream
)
{
m_inStream
=
instream
;
}
/// <summary>
/// Get the stream through which the message body could be read
/// </summary>
const
concurrency
::
streams
::
istream
&
instream
()
const
{
return
m_inStream
;
}
/// <summary>
/// Set the stream through which the message body could be written
/// </summary>
void
set_outstream
(
const
concurrency
::
streams
::
ostream
&
outstream
,
bool
is_default
)
{
m_outStream
=
outstream
;
m_default_outstream
=
is_default
;
}
/// <summary>
/// Get the stream through which the message body could be written
/// </summary>
const
concurrency
::
streams
::
ostream
&
outstream
()
const
{
return
m_outStream
;
}
/// <summary>
/// Sets the compressor for the message body
/// </summary>
void
set_compressor
(
std
::
unique_ptr
<
http
::
compression
::
compress_provider
>
compressor
)
{
m_compressor
=
std
::
move
(
compressor
);
}
/// <summary>
/// Gets the compressor for the message body, if any
/// </summary>
std
::
unique_ptr
<
http
::
compression
::
compress_provider
>&
compressor
()
{
return
m_compressor
;
}
/// <summary>
/// Sets the collection of factory classes for decompressors for use with the message body
/// </summary>
void
set_decompress_factories
(
const
std
::
vector
<
std
::
shared_ptr
<
http
::
compression
::
decompress_factory
>>&
factories
)
{
m_decompressors
=
factories
;
}
/// <summary>
/// Gets the collection of factory classes for decompressors to be used to decompress the message body, if any
/// </summary>
const
std
::
vector
<
std
::
shared_ptr
<
http
::
compression
::
decompress_factory
>>&
decompress_factories
()
{
return
m_decompressors
;
}
const
pplx
::
task_completion_event
<
utility
::
size64_t
>&
_get_data_available
()
const
{
return
m_data_available
;
}
/// <summary>
/// Prepare the message with an output stream to receive network data
/// </summary>
_ASYNCRTIMP
void
_prepare_to_receive_data
();
/// <summary>
/// Determine the remaining input stream length
/// </summary>
/// <returns>
/// std::numeric_limits<size_t>::max() if the stream's remaining length cannot be determined
/// length if the stream's remaining length (which may be 0) can be determined
/// </returns>
/// <remarks>
/// This routine should only be called after a msg (request/response) has been
/// completely constructed.
/// </remarks>
_ASYNCRTIMP
size_t
_get_stream_length
();
/// <summary>
/// Determine the content length
/// </summary>
/// <returns>
/// std::numeric_limits<size_t>::max() if there is content with unknown length (transfer_encoding:chunked)
/// 0 if there is no content
/// length if there is content with known length
/// </returns>
/// <remarks>
/// This routine should only be called after a msg (request/response) has been
/// completely constructed.
/// </remarks>
_ASYNCRTIMP
size_t
_get_content_length
();
/// <summary>
/// Determine the content length, and, if necessary, manage compression in the Transfer-Encoding header
/// </summary>
/// <returns>
/// std::numeric_limits<size_t>::max() if there is content with unknown length (transfer_encoding:chunked)
/// 0 if there is no content
/// length if there is content with known length
/// </returns>
/// <remarks>
/// This routine is like _get_content_length, except that it adds a compression algorithm to
/// the Trasfer-Length header if compression is configured. It throws if a Transfer-Encoding
/// header exists and does not match the one it generated.
/// </remarks>
_ASYNCRTIMP
size_t
_get_content_length_and_set_compression
();
void
_set_http_version
(
const
http
::
http_version
&
http_version
)
{
m_http_version
=
http_version
;
}
protected:
std
::
unique_ptr
<
http
::
compression
::
compress_provider
>
m_compressor
;
std
::
unique_ptr
<
http
::
compression
::
decompress_provider
>
m_decompressor
;
std
::
vector
<
std
::
shared_ptr
<
http
::
compression
::
decompress_factory
>>
m_decompressors
;
/// <summary>
/// Stream to read the message body.
/// By default this is an invalid stream. The user could set the instream on
/// a request by calling set_request_stream(...). This would also be set when
/// set_body() is called - a stream from the body is constructed and set.
/// Even in the presence of msg body this stream could be invalid. An example
/// would be when the user sets an ostream for the response. With that API the
/// user does not provide the ability to read the msg body.
/// Thus m_instream is valid when there is a msg body and it can actually be read
/// </summary>
concurrency
::
streams
::
istream
m_inStream
;
/// <summary>
/// stream to write the msg body
/// By default this is an invalid stream. The user could set this on the response
/// (for http_client). In all the other cases we would construct one to transfer
/// the data from the network into the message body.
/// </summary>
concurrency
::
streams
::
ostream
m_outStream
;
http
::
http_version
m_http_version
;
http_headers
m_headers
;
bool
m_default_outstream
;
/// <summary> The TCE is used to signal the availability of the message body. </summary>
pplx
::
task_completion_event
<
utility
::
size64_t
>
m_data_available
;
size_t
_get_content_length
(
bool
honor_compression
);
};
/// <summary>
/// Base structure for associating internal server information
/// with an HTTP request/response.
/// </summary>
class
_http_server_context
{
public:
_http_server_context
()
{}
virtual
~
_http_server_context
()
{}
private:
};
/// <summary>
/// Internal representation of an HTTP response.
/// </summary>
class
_http_response
final
:
public
http
::
details
::
http_msg_base
{
public:
_http_response
()
:
m_status_code
((
std
::
numeric_limits
<
uint16_t
>::
max
)())
{}
_http_response
(
http
::
status_code
code
)
:
m_status_code
(
code
)
{}
http
::
status_code
status_code
()
const
{
return
m_status_code
;
}
void
set_status_code
(
http
::
status_code
code
)
{
m_status_code
=
code
;
}
const
http
::
reason_phrase
&
reason_phrase
()
const
{
return
m_reason_phrase
;
}
void
set_reason_phrase
(
const
http
::
reason_phrase
&
reason
)
{
m_reason_phrase
=
reason
;
}
_ASYNCRTIMP
utility
::
string_t
to_string
()
const
;
_http_server_context
*
_get_server_context
()
const
{
return
m_server_context
.
get
();
}
void
_set_server_context
(
std
::
unique_ptr
<
details
::
_http_server_context
>
server_context
)
{
m_server_context
=
std
::
move
(
server_context
);
}
private:
std
::
unique_ptr
<
_http_server_context
>
m_server_context
;
http
::
status_code
m_status_code
;
http
::
reason_phrase
m_reason_phrase
;
};
}
// namespace details
/// <summary>
/// Represents an HTTP response.
/// </summary>
class
http_response
{
public:
/// <summary>
/// Constructs a response with an empty status code, no headers, and no body.
/// </summary>
/// <returns>A new HTTP response.</returns>
http_response
()
:
_m_impl
(
std
::
make_shared
<
details
::
_http_response
>
())
{}
/// <summary>
/// Constructs a response with given status code, no headers, and no body.
/// </summary>
/// <param name="code">HTTP status code to use in response.</param>
/// <returns>A new HTTP response.</returns>
http_response
(
http
::
status_code
code
)
:
_m_impl
(
std
::
make_shared
<
details
::
_http_response
>
(
code
))
{}
/// <summary>
/// Gets the status code of the response message.
/// </summary>
/// <returns>status code.</returns>
http
::
status_code
status_code
()
const
{
return
_m_impl
->
status_code
();
}
/// <summary>
/// Sets the status code of the response message.
/// </summary>
/// <param name="code">Status code to set.</param>
/// <remarks>
/// This will overwrite any previously set status code.
/// </remarks>
void
set_status_code
(
http
::
status_code
code
)
const
{
_m_impl
->
set_status_code
(
code
);
}
/// <summary>
/// Gets the reason phrase of the response message.
/// If no reason phrase is set it will default to the standard one corresponding to the status code.
/// </summary>
/// <returns>Reason phrase.</returns>
const
http
::
reason_phrase
&
reason_phrase
()
const
{
return
_m_impl
->
reason_phrase
();
}
/// <summary>
/// Sets the reason phrase of the response message.
/// If no reason phrase is set it will default to the standard one corresponding to the status code.
/// </summary>
/// <param name="reason">The reason phrase to set.</param>
void
set_reason_phrase
(
const
http
::
reason_phrase
&
reason
)
const
{
_m_impl
->
set_reason_phrase
(
reason
);
}
/// <summary>
/// Gets the headers of the response message.
/// </summary>
/// <returns>HTTP headers for this response.</returns>
/// <remarks>
/// Use the <seealso cref="http_headers::add Method"/> to fill in desired headers.
/// </remarks>
http_headers
&
headers
()
{
return
_m_impl
->
headers
();
}
/// <summary>
/// Gets a const reference to the headers of the response message.
/// </summary>
/// <returns>HTTP headers for this response.</returns>
const
http_headers
&
headers
()
const
{
return
_m_impl
->
headers
();
}
/// <summary>
/// Generates a string representation of the message, including the body when possible.
/// Mainly this should be used for debugging purposes as it has to copy the
/// message body and doesn't have excellent performance.
/// </summary>
/// <returns>A string representation of this HTTP request.</returns>
/// <remarks>Note this function is synchronous and doesn't wait for the
/// entire message body to arrive. If the message body has arrived by the time this
/// function is called and it is has a textual Content-Type it will be included.
/// Otherwise just the headers will be present.</remarks>
utility
::
string_t
to_string
()
const
{
return
_m_impl
->
to_string
();
}
/// <summary>
/// Extracts the body of the response message as a string value, checking that the content type is a MIME text type.
/// A body can only be extracted once because in some cases an optimization is made where the data is 'moved' out.
/// </summary>
/// <param name="ignore_content_type">If true, ignores the Content-Type header and assumes text.</param>
/// <returns>String containing body of the message.</returns>
pplx
::
task
<
utility
::
string_t
>
extract_string
(
bool
ignore_content_type
=
false
)
const
{
auto
impl
=
_m_impl
;
return
pplx
::
create_task
(
_m_impl
->
_get_data_available
()).
then
([
impl
,
ignore_content_type
](
utility
::
size64_t
)
{
return
impl
->
extract_string
(
ignore_content_type
);
});
}
/// <summary>
/// Extracts the body of the response message as a UTF-8 string value, checking that the content type is a MIME text
/// type. A body can only be extracted once because in some cases an optimization is made where the data is 'moved'
/// out.
/// </summary>
/// <param name="ignore_content_type">If true, ignores the Content-Type header and assumes text.</param>
/// <returns>String containing body of the message.</returns>
pplx
::
task
<
utf8string
>
extract_utf8string
(
bool
ignore_content_type
=
false
)
const
{
auto
impl
=
_m_impl
;
return
pplx
::
create_task
(
_m_impl
->
_get_data_available
()).
then
([
impl
,
ignore_content_type
](
utility
::
size64_t
)
{
return
impl
->
extract_utf8string
(
ignore_content_type
);
});
}
/// <summary>
/// Extracts the body of the response message as a UTF-16 string value, checking that the content type is a MIME
/// text type. A body can only be extracted once because in some cases an optimization is made where the data is
/// 'moved' out.
/// </summary>
/// <param name="ignore_content_type">If true, ignores the Content-Type header and assumes text.</param>
/// <returns>String containing body of the message.</returns>
pplx
::
task
<
utf16string
>
extract_utf16string
(
bool
ignore_content_type
=
false
)
const
{
auto
impl
=
_m_impl
;
return
pplx
::
create_task
(
_m_impl
->
_get_data_available
()).
then
([
impl
,
ignore_content_type
](
utility
::
size64_t
)
{
return
impl
->
extract_utf16string
(
ignore_content_type
);
});
}
/// <summary>
/// Extracts the body of the response message into a json value, checking that the content type is application/json.
/// A body can only be extracted once because in some cases an optimization is made where the data is 'moved' out.
/// </summary>
/// <param name="ignore_content_type">If true, ignores the Content-Type header and assumes json.</param>
/// <returns>JSON value from the body of this message.</returns>
pplx
::
task
<
json
::
value
>
extract_json
(
bool
ignore_content_type
=
false
)
const
{
auto
impl
=
_m_impl
;
return
pplx
::
create_task
(
_m_impl
->
_get_data_available
()).
then
([
impl
,
ignore_content_type
](
utility
::
size64_t
)
{
return
impl
->
_extract_json
(
ignore_content_type
);
});
}
/// <summary>
/// Extracts the body of the response message into a vector of bytes.
/// </summary>
/// <returns>The body of the message as a vector of bytes.</returns>
pplx
::
task
<
std
::
vector
<
unsigned
char
>>
extract_vector
()
const
{
auto
impl
=
_m_impl
;
return
pplx
::
create_task
(
_m_impl
->
_get_data_available
()).
then
([
impl
](
utility
::
size64_t
)
{
return
impl
->
_extract_vector
();
});
}
/// <summary>
/// Sets the body of the message to a textual string and set the "Content-Type" header. Assumes
/// the character encoding of the string is UTF-8.
/// </summary>
/// <param name="body_text">String containing body text.</param>
/// <param name="content_type">MIME type to set the "Content-Type" header to. Default to "text/plain;
/// charset=utf-8".</param> <remarks> This will overwrite any previously set body data and "Content-Type" header.
/// </remarks>
void
set_body
(
utf8string
&&
body_text
,
const
utf8string
&
content_type
=
utf8string
(
"text/plain; charset=utf-8"
))
{
const
auto
length
=
body_text
.
size
();
_m_impl
->
set_body
(
concurrency
::
streams
::
bytestream
::
open_istream
<
std
::
string
>
(
std
::
move
(
body_text
)),
length
,
content_type
);
}
/// <summary>
/// Sets the body of the message to a textual string and set the "Content-Type" header. Assumes
/// the character encoding of the string is UTF-8.
/// </summary>
/// <param name="body_text">String containing body text.</param>
/// <param name="content_type">MIME type to set the "Content-Type" header to. Default to "text/plain;
/// charset=utf-8".</param> <remarks> This will overwrite any previously set body data and "Content-Type" header.
/// </remarks>
void
set_body
(
const
utf8string
&
body_text
,
const
utf8string
&
content_type
=
utf8string
(
"text/plain; charset=utf-8"
))
{
_m_impl
->
set_body
(
concurrency
::
streams
::
bytestream
::
open_istream
<
std
::
string
>
(
body_text
),
body_text
.
size
(),
content_type
);
}
/// <summary>
/// Sets the body of the message to a textual string and set the "Content-Type" header. Assumes
/// the character encoding of the string is UTF-16 will perform conversion to UTF-8.
/// </summary>
/// <param name="body_text">String containing body text.</param>
/// <param name="content_type">MIME type to set the "Content-Type" header to. Default to "text/plain".</param>
/// <remarks>
/// This will overwrite any previously set body data and "Content-Type" header.
/// </remarks>
void
set_body
(
const
utf16string
&
body_text
,
utf16string
content_type
=
utility
::
conversions
::
to_utf16string
(
"text/plain"
))
{
if
(
content_type
.
find
(
::
utility
::
conversions
::
to_utf16string
(
"charset="
))
!=
content_type
.
npos
)
{
throw
std
::
invalid_argument
(
"content_type can't contain a 'charset'."
);
}
auto
utf8body
=
utility
::
conversions
::
utf16_to_utf8
(
body_text
);
auto
length
=
utf8body
.
size
();
_m_impl
->
set_body
(
concurrency
::
streams
::
bytestream
::
open_istream
<
std
::
string
>
(
std
::
move
(
utf8body
)),
length
,
std
::
move
(
content_type
.
append
(
::
utility
::
conversions
::
to_utf16string
(
"; charset=utf-8"
))));
}
/// <summary>
/// Sets the body of the message to contain json value. If the 'Content-Type'
/// header hasn't already been set it will be set to 'application/json'.
/// </summary>
/// <param name="body_text">json value.</param>
/// <remarks>
/// This will overwrite any previously set body data.
/// </remarks>
void
set_body
(
const
json
::
value
&
body_data
)
{
auto
body_text
=
utility
::
conversions
::
to_utf8string
(
body_data
.
serialize
());
auto
length
=
body_text
.
size
();
set_body
(
concurrency
::
streams
::
bytestream
::
open_istream
(
std
::
move
(
body_text
)),
length
,
_XPLATSTR
(
"application/json"
));
}
/// <summary>
/// Sets the body of the message to the contents of a byte vector. If the 'Content-Type'
/// header hasn't already been set it will be set to 'application/octet-stream'.
/// </summary>
/// <param name="body_data">Vector containing body data.</param>
/// <remarks>
/// This will overwrite any previously set body data.
/// </remarks>
void
set_body
(
std
::
vector
<
unsigned
char
>&&
body_data
)
{
auto
length
=
body_data
.
size
();
set_body
(
concurrency
::
streams
::
bytestream
::
open_istream
(
std
::
move
(
body_data
)),
length
);
}
/// <summary>
/// Sets the body of the message to the contents of a byte vector. If the 'Content-Type'
/// header hasn't already been set it will be set to 'application/octet-stream'.
/// </summary>
/// <param name="body_data">Vector containing body data.</param>
/// <remarks>
/// This will overwrite any previously set body data.
/// </remarks>
void
set_body
(
const
std
::
vector
<
unsigned
char
>&
body_data
)
{
set_body
(
concurrency
::
streams
::
bytestream
::
open_istream
(
body_data
),
body_data
.
size
());
}
/// <summary>
/// Defines a stream that will be relied on to provide the body of the HTTP message when it is
/// sent.
/// </summary>
/// <param name="stream">A readable, open asynchronous stream.</param>
/// <param name="content_type">A string holding the MIME type of the message body.</param>
/// <remarks>
/// This cannot be used in conjunction with any external means of setting the body of the request.
/// The stream will not be read until the message is sent.
/// </remarks>
void
set_body
(
const
concurrency
::
streams
::
istream
&
stream
,
const
utility
::
string_t
&
content_type
=
_XPLATSTR
(
"application/octet-stream"
))
{
_m_impl
->
set_body
(
stream
,
content_type
);
}
/// <summary>
/// Defines a stream that will be relied on to provide the body of the HTTP message when it is
/// sent.
/// </summary>
/// <param name="stream">A readable, open asynchronous stream.</param>
/// <param name="content_length">The size of the data to be sent in the body.</param>
/// <param name="content_type">A string holding the MIME type of the message body.</param>
/// <remarks>
/// This cannot be used in conjunction with any external means of setting the body of the request.
/// The stream will not be read until the message is sent.
/// </remarks>
void
set_body
(
const
concurrency
::
streams
::
istream
&
stream
,
utility
::
size64_t
content_length
,
const
utility
::
string_t
&
content_type
=
_XPLATSTR
(
"application/octet-stream"
))
{
_m_impl
->
set_body
(
stream
,
content_length
,
content_type
);
}
/// <summary>
/// Produces a stream which the caller may use to retrieve data from an incoming request.
/// </summary>
/// <returns>A readable, open asynchronous stream.</returns>
/// <remarks>
/// This cannot be used in conjunction with any other means of getting the body of the request.
/// It is not necessary to wait until the message has been sent before starting to write to the
/// stream, but it is advisable to do so, since it will allow the network I/O to start earlier
/// and the work of sending data can be overlapped with the production of more data.
/// </remarks>
concurrency
::
streams
::
istream
body
()
const
{
return
_m_impl
->
instream
();
}
/// <summary>
/// Signals the user (client) when all the data for this response message has been received.
/// </summary>
/// <returns>A <c>task</c> which is completed when all of the response body has been received.</returns>
pplx
::
task
<
http
::
http_response
>
content_ready
()
const
{
http_response
resp
=
*
this
;
return
pplx
::
create_task
(
_m_impl
->
_get_data_available
()).
then
([
resp
](
utility
::
size64_t
)
mutable
{
return
resp
;
});
}
std
::
shared_ptr
<
http
::
details
::
_http_response
>
_get_impl
()
const
{
return
_m_impl
;
}
http
::
details
::
_http_server_context
*
_get_server_context
()
const
{
return
_m_impl
->
_get_server_context
();
}
void
_set_server_context
(
std
::
unique_ptr
<
http
::
details
::
_http_server_context
>
server_context
)
{
_m_impl
->
_set_server_context
(
std
::
move
(
server_context
));
}
private:
std
::
shared_ptr
<
http
::
details
::
_http_response
>
_m_impl
;
};
namespace
details
{
/// <summary>
/// Internal representation of an HTTP request message.
/// </summary>
class
_http_request
final
:
public
http
::
details
::
http_msg_base
,
public
std
::
enable_shared_from_this
<
_http_request
>
{
public:
_ASYNCRTIMP
_http_request
(
http
::
method
mtd
);
_ASYNCRTIMP
_http_request
(
std
::
unique_ptr
<
http
::
details
::
_http_server_context
>
server_context
);
virtual
~
_http_request
()
{}
http
::
method
&
method
()
{
return
m_method
;
}
uri
&
request_uri
()
{
return
m_uri
;
}
_ASYNCRTIMP
uri
absolute_uri
()
const
;
_ASYNCRTIMP
uri
relative_uri
()
const
;
_ASYNCRTIMP
void
set_request_uri
(
const
uri
&
);
const
utility
::
string_t
&
remote_address
()
const
{
return
m_remote_address
;
}
const
pplx
::
cancellation_token
&
cancellation_token
()
const
{
return
m_cancellationToken
;
}
void
set_cancellation_token
(
const
pplx
::
cancellation_token
&
token
)
{
m_cancellationToken
=
token
;
}
_ASYNCRTIMP
utility
::
string_t
to_string
()
const
;
_ASYNCRTIMP
pplx
::
task
<
void
>
reply
(
const
http_response
&
response
);
pplx
::
task
<
http_response
>
get_response
()
{
return
pplx
::
task
<
http_response
>
(
m_response
);
}
_ASYNCRTIMP
pplx
::
task
<
void
>
_reply_if_not_already
(
http
::
status_code
status
);
void
set_response_stream
(
const
concurrency
::
streams
::
ostream
&
stream
)
{
m_response_stream
=
stream
;
}
void
set_progress_handler
(
const
progress_handler
&
handler
)
{
m_progress_handler
=
std
::
make_shared
<
progress_handler
>
(
handler
);
}
const
concurrency
::
streams
::
ostream
&
_response_stream
()
const
{
return
m_response_stream
;
}
const
std
::
shared_ptr
<
progress_handler
>&
_progress_handler
()
const
{
return
m_progress_handler
;
}
http
::
details
::
_http_server_context
*
_get_server_context
()
const
{
return
m_server_context
.
get
();
}
void
_set_server_context
(
std
::
unique_ptr
<
http
::
details
::
_http_server_context
>
server_context
)
{
m_server_context
=
std
::
move
(
server_context
);
}
void
_set_listener_path
(
const
utility
::
string_t
&
path
)
{
m_listener_path
=
path
;
}
void
_set_base_uri
(
const
http
::
uri
&
base_uri
)
{
m_base_uri
=
base_uri
;
}
void
_set_remote_address
(
const
utility
::
string_t
&
remote_address
)
{
m_remote_address
=
remote_address
;
}
private:
// Actual initiates sending the response, without checking if a response has already been sent.
pplx
::
task
<
void
>
_reply_impl
(
http_response
response
);
http
::
method
m_method
;
// Tracks whether or not a response has already been started for this message.
// 0 = No reply sent
// 1 = Usual reply sent
// 2 = Reply aborted by another thread; e.g. server shutdown
pplx
::
details
::
atomic_long
m_initiated_response
;
std
::
unique_ptr
<
http
::
details
::
_http_server_context
>
m_server_context
;
pplx
::
cancellation_token
m_cancellationToken
;
http
::
uri
m_base_uri
;
http
::
uri
m_uri
;
utility
::
string_t
m_listener_path
;
concurrency
::
streams
::
ostream
m_response_stream
;
std
::
shared_ptr
<
progress_handler
>
m_progress_handler
;
pplx
::
task_completion_event
<
http_response
>
m_response
;
utility
::
string_t
m_remote_address
;
};
}
// namespace details
/// <summary>
/// Represents an HTTP request.
/// </summary>
class
http_request
{
public:
/// <summary>
/// Constructs a new HTTP request with the 'GET' method.
/// </summary>
http_request
()
:
_m_impl
(
std
::
make_shared
<
http
::
details
::
_http_request
>
(
methods
::
GET
))
{}
/// <summary>
/// Constructs a new HTTP request with the given request method.
/// </summary>
/// <param name="mtd">Request method.</param>
http_request
(
http
::
method
mtd
)
:
_m_impl
(
std
::
make_shared
<
http
::
details
::
_http_request
>
(
std
::
move
(
mtd
)))
{}
/// <summary>
/// Destructor frees any held resources.
/// </summary>
~
http_request
()
{}
/// <summary>
/// Get the method (GET/PUT/POST/DELETE) of the request message.
/// </summary>
/// <returns>Request method of this HTTP request.</returns>
const
http
::
method
&
method
()
const
{
return
_m_impl
->
method
();
}
/// <summary>
/// Set the method (GET/PUT/POST/DELETE) of the request message.
/// </summary>
/// <param name="method">Request method of this HTTP request.</param>
void
set_method
(
const
http
::
method
&
method
)
const
{
_m_impl
->
method
()
=
method
;
}
/// <summary>
/// Get the underling URI of the request message.
/// </summary>
/// <returns>The uri of this message.</returns>
const
uri
&
request_uri
()
const
{
return
_m_impl
->
request_uri
();
}
/// <summary>
/// Set the underling URI of the request message.
/// </summary>
/// <param name="uri">The uri for this message.</param>
void
set_request_uri
(
const
uri
&
uri
)
{
return
_m_impl
->
set_request_uri
(
uri
);
}
/// <summary>
/// Gets a reference the URI path, query, and fragment part of this request message.
/// This will be appended to the base URI specified at construction of the http_client.
/// </summary>
/// <returns>A string.</returns>
/// <remarks>When the request is the one passed to a listener's handler, the
/// relative URI is the request URI less the listener's path. In all other circumstances,
/// request_uri() and relative_uri() will return the same value.
/// </remarks>
uri
relative_uri
()
const
{
return
_m_impl
->
relative_uri
();
}
/// <summary>
/// Get an absolute URI with scheme, host, port, path, query, and fragment part of
/// the request message.
/// </summary>
/// <remarks>Absolute URI is only valid after this http_request object has been passed
/// to http_client::request().
/// </remarks>
uri
absolute_uri
()
const
{
return
_m_impl
->
absolute_uri
();
}
/// <summary>
/// Gets a reference to the headers of the response message.
/// </summary>
/// <returns>HTTP headers for this response.</returns>
/// <remarks>
/// Use the http_headers::add to fill in desired headers.
/// </remarks>
http_headers
&
headers
()
{
return
_m_impl
->
headers
();
}
/// <summary>
/// Gets a const reference to the headers of the response message.
/// </summary>
/// <returns>HTTP headers for this response.</returns>
/// <remarks>
/// Use the http_headers::add to fill in desired headers.
/// </remarks>
const
http_headers
&
headers
()
const
{
return
_m_impl
->
headers
();
}
/// <summary>
/// Returns the HTTP protocol version of this request message.
/// </summary>
/// <returns>The HTTP protocol version.</returns>
http
::
http_version
http_version
()
const
{
return
_m_impl
->
http_version
();
}
/// <summary>
/// Returns a string representation of the remote IP address.
/// </summary>
/// <returns>The remote IP address.</returns>
const
utility
::
string_t
&
remote_address
()
const
{
return
_m_impl
->
remote_address
();
}
CASABLANCA_DEPRECATED
(
"Use `remote_address()` instead."
)
const
utility
::
string_t
&
get_remote_address
()
const
{
return
_m_impl
->
remote_address
();
}
/// <summary>
/// Extract the body of the request message as a string value, checking that the content type is a MIME text type.
/// A body can only be extracted once because in some cases an optimization is made where the data is 'moved' out.
/// </summary>
/// <param name="ignore_content_type">If true, ignores the Content-Type header and assumes UTF-8.</param>
/// <returns>String containing body of the message.</returns>
pplx
::
task
<
utility
::
string_t
>
extract_string
(
bool
ignore_content_type
=
false
)
{
auto
impl
=
_m_impl
;
return
pplx
::
create_task
(
_m_impl
->
_get_data_available
()).
then
([
impl
,
ignore_content_type
](
utility
::
size64_t
)
{
return
impl
->
extract_string
(
ignore_content_type
);
});
}
/// <summary>
/// Extract the body of the request message as a UTF-8 string value, checking that the content type is a MIME text
/// type. A body can only be extracted once because in some cases an optimization is made where the data is 'moved'
/// out.
/// </summary>
/// <param name="ignore_content_type">If true, ignores the Content-Type header and assumes UTF-8.</param>
/// <returns>String containing body of the message.</returns>
pplx
::
task
<
utf8string
>
extract_utf8string
(
bool
ignore_content_type
=
false
)
{
auto
impl
=
_m_impl
;
return
pplx
::
create_task
(
_m_impl
->
_get_data_available
()).
then
([
impl
,
ignore_content_type
](
utility
::
size64_t
)
{
return
impl
->
extract_utf8string
(
ignore_content_type
);
});
}
/// <summary>
/// Extract the body of the request message as a UTF-16 string value, checking that the content type is a MIME text
/// type. A body can only be extracted once because in some cases an optimization is made where the data is 'moved'
/// out.
/// </summary>
/// <param name="ignore_content_type">If true, ignores the Content-Type header and assumes UTF-16.</param>
/// <returns>String containing body of the message.</returns>
pplx
::
task
<
utf16string
>
extract_utf16string
(
bool
ignore_content_type
=
false
)
{
auto
impl
=
_m_impl
;
return
pplx
::
create_task
(
_m_impl
->
_get_data_available
()).
then
([
impl
,
ignore_content_type
](
utility
::
size64_t
)
{
return
impl
->
extract_utf16string
(
ignore_content_type
);
});
}
/// <summary>
/// Extracts the body of the request message into a json value, checking that the content type is application/json.
/// A body can only be extracted once because in some cases an optimization is made where the data is 'moved' out.
/// </summary>
/// <param name="ignore_content_type">If true, ignores the Content-Type header and assumes UTF-8.</param>
/// <returns>JSON value from the body of this message.</returns>
pplx
::
task
<
json
::
value
>
extract_json
(
bool
ignore_content_type
=
false
)
const
{
auto
impl
=
_m_impl
;
return
pplx
::
create_task
(
_m_impl
->
_get_data_available
()).
then
([
impl
,
ignore_content_type
](
utility
::
size64_t
)
{
return
impl
->
_extract_json
(
ignore_content_type
);
});
}
/// <summary>
/// Extract the body of the response message into a vector of bytes. Extracting a vector can be done on
/// </summary>
/// <returns>The body of the message as a vector of bytes.</returns>
pplx
::
task
<
std
::
vector
<
unsigned
char
>>
extract_vector
()
const
{
auto
impl
=
_m_impl
;
return
pplx
::
create_task
(
_m_impl
->
_get_data_available
()).
then
([
impl
](
utility
::
size64_t
)
{
return
impl
->
_extract_vector
();
});
}
/// <summary>
/// Sets the body of the message to a textual string and set the "Content-Type" header. Assumes
/// the character encoding of the string is UTF-8.
/// </summary>
/// <param name="body_text">String containing body text.</param>
/// <param name="content_type">MIME type to set the "Content-Type" header to. Default to "text/plain;
/// charset=utf-8".</param> <remarks> This will overwrite any previously set body data and "Content-Type" header.
/// </remarks>
void
set_body
(
utf8string
&&
body_text
,
const
utf8string
&
content_type
=
utf8string
(
"text/plain; charset=utf-8"
))
{
const
auto
length
=
body_text
.
size
();
_m_impl
->
set_body
(
concurrency
::
streams
::
bytestream
::
open_istream
<
std
::
string
>
(
std
::
move
(
body_text
)),
length
,
content_type
);
}
/// <summary>
/// Sets the body of the message to a textual string and set the "Content-Type" header. Assumes
/// the character encoding of the string is UTF-8.
/// </summary>
/// <param name="body_text">String containing body text.</param>
/// <param name="content_type">MIME type to set the "Content-Type" header to. Default to "text/plain;
/// charset=utf-8".</param> <remarks> This will overwrite any previously set body data and "Content-Type" header.
/// </remarks>
void
set_body
(
const
utf8string
&
body_text
,
const
utf8string
&
content_type
=
utf8string
(
"text/plain; charset=utf-8"
))
{
_m_impl
->
set_body
(
concurrency
::
streams
::
bytestream
::
open_istream
<
std
::
string
>
(
body_text
),
body_text
.
size
(),
content_type
);
}
/// <summary>
/// Sets the body of the message to a textual string and set the "Content-Type" header. Assumes
/// the character encoding of the string is UTF-16 will perform conversion to UTF-8.
/// </summary>
/// </summary>
/// <param name="body_text">String containing body text.</param>
/// <param name="content_type">MIME type to set the "Content-Type" header to. Default to "text/plain".</param>
/// <remarks>
/// This will overwrite any previously set body data and "Content-Type" header.
/// </remarks>
void
set_body
(
const
utf16string
&
body_text
,
utf16string
content_type
=
utility
::
conversions
::
to_utf16string
(
"text/plain"
))
{
if
(
content_type
.
find
(
::
utility
::
conversions
::
to_utf16string
(
"charset="
))
!=
content_type
.
npos
)
{
throw
std
::
invalid_argument
(
"content_type can't contain a 'charset'."
);
}
auto
utf8body
=
utility
::
conversions
::
utf16_to_utf8
(
body_text
);
auto
length
=
utf8body
.
size
();
_m_impl
->
set_body
(
concurrency
::
streams
::
bytestream
::
open_istream
(
std
::
move
(
utf8body
)),
length
,
std
::
move
(
content_type
.
append
(
::
utility
::
conversions
::
to_utf16string
(
"; charset=utf-8"
))));
}
/// <summary>
/// Sets the body of the message to contain json value. If the 'Content-Type'
/// header hasn't already been set it will be set to 'application/json'.
/// </summary>
/// <param name="body_data">json value.</param>
/// <remarks>
/// This will overwrite any previously set body data.
/// </remarks>
void
set_body
(
const
json
::
value
&
body_data
)
{
auto
body_text
=
utility
::
conversions
::
to_utf8string
(
body_data
.
serialize
());
auto
length
=
body_text
.
size
();
_m_impl
->
set_body
(
concurrency
::
streams
::
bytestream
::
open_istream
(
std
::
move
(
body_text
)),
length
,
_XPLATSTR
(
"application/json"
));
}
/// <summary>
/// Sets the body of the message to the contents of a byte vector. If the 'Content-Type'
/// header hasn't already been set it will be set to 'application/octet-stream'.
/// </summary>
/// <param name="body_data">Vector containing body data.</param>
/// <remarks>
/// This will overwrite any previously set body data.
/// </remarks>
void
set_body
(
std
::
vector
<
unsigned
char
>&&
body_data
)
{
auto
length
=
body_data
.
size
();
_m_impl
->
set_body
(
concurrency
::
streams
::
bytestream
::
open_istream
(
std
::
move
(
body_data
)),
length
,
_XPLATSTR
(
"application/octet-stream"
));
}
/// <summary>
/// Sets the body of the message to the contents of a byte vector. If the 'Content-Type'
/// header hasn't already been set it will be set to 'application/octet-stream'.
/// </summary>
/// <param name="body_data">Vector containing body data.</param>
/// <remarks>
/// This will overwrite any previously set body data.
/// </remarks>
void
set_body
(
const
std
::
vector
<
unsigned
char
>&
body_data
)
{
set_body
(
concurrency
::
streams
::
bytestream
::
open_istream
(
body_data
),
body_data
.
size
());
}
/// <summary>
/// Defines a stream that will be relied on to provide the body of the HTTP message when it is
/// sent.
/// </summary>
/// <param name="stream">A readable, open asynchronous stream.</param>
/// <param name="content_type">A string holding the MIME type of the message body.</param>
/// <remarks>
/// This cannot be used in conjunction with any other means of setting the body of the request.
/// The stream will not be read until the message is sent.
/// </remarks>
void
set_body
(
const
concurrency
::
streams
::
istream
&
stream
,
const
utility
::
string_t
&
content_type
=
_XPLATSTR
(
"application/octet-stream"
))
{
_m_impl
->
set_body
(
stream
,
content_type
);
}
/// <summary>
/// Defines a stream that will be relied on to provide the body of the HTTP message when it is
/// sent.
/// </summary>
/// <param name="stream">A readable, open asynchronous stream.</param>
/// <param name="content_length">The size of the data to be sent in the body.</param>
/// <param name="content_type">A string holding the MIME type of the message body.</param>
/// <remarks>
/// This cannot be used in conjunction with any other means of setting the body of the request.
/// The stream will not be read until the message is sent.
/// </remarks>
void
set_body
(
const
concurrency
::
streams
::
istream
&
stream
,
utility
::
size64_t
content_length
,
const
utility
::
string_t
&
content_type
=
_XPLATSTR
(
"application/octet-stream"
))
{
_m_impl
->
set_body
(
stream
,
content_length
,
content_type
);
}
/// <summary>
/// Produces a stream which the caller may use to retrieve data from an incoming request.
/// </summary>
/// <returns>A readable, open asynchronous stream.</returns>
/// <remarks>
/// This cannot be used in conjunction with any other means of getting the body of the request.
/// It is not necessary to wait until the message has been sent before starting to write to the
/// stream, but it is advisable to do so, since it will allow the network I/O to start earlier
/// and the work of sending data can be overlapped with the production of more data.
/// </remarks>
concurrency
::
streams
::
istream
body
()
const
{
return
_m_impl
->
instream
();
}
/// <summary>
/// Defines a stream that will be relied on to hold the body of the HTTP response message that
/// results from the request.
/// </summary>
/// <param name="stream">A writable, open asynchronous stream.</param>
/// <remarks>
/// If this function is called, the body of the response should not be accessed in any other
/// way.
/// </remarks>
void
set_response_stream
(
const
concurrency
::
streams
::
ostream
&
stream
)
{
return
_m_impl
->
set_response_stream
(
stream
);
}
/// <summary>
/// Sets a compressor that will be used to compress the body of the HTTP message as it is sent.
/// </summary>
/// <param name="compressor">A pointer to an instantiated compressor of the desired type.</param>
/// <remarks>
/// This cannot be used in conjunction with any external means of compression. The Transfer-Encoding
/// header will be managed internally, and must not be set by the client.
/// </remarks>
void
set_compressor
(
std
::
unique_ptr
<
http
::
compression
::
compress_provider
>
compressor
)
{
return
_m_impl
->
set_compressor
(
std
::
move
(
compressor
));
}
/// <summary>
/// Sets a compressor that will be used to compress the body of the HTTP message as it is sent.
/// </summary>
/// <param name="algorithm">The built-in compression algorithm to use.</param>
/// <returns>
/// True if a built-in compressor was instantiated, otherwise false.
/// </returns>
/// <remarks>
/// This cannot be used in conjunction with any external means of compression. The Transfer-Encoding
/// header will be managed internally, and must not be set by the client.
/// </remarks>
bool
set_compressor
(
utility
::
string_t
algorithm
)
{
_m_impl
->
set_compressor
(
http
::
compression
::
builtin
::
make_compressor
(
algorithm
));
return
(
bool
)
_m_impl
->
compressor
();
}
/// <summary>
/// Gets the compressor to be used to compress the message body, if any.
/// </summary>
/// <returns>
/// The compressor itself.
/// </returns>
std
::
unique_ptr
<
http
::
compression
::
compress_provider
>&
compressor
()
{
return
_m_impl
->
compressor
();
}
/// <summary>
/// Sets the default collection of built-in factory classes for decompressors that may be used to
/// decompress the body of the HTTP message as it is received, effectively enabling decompression.
/// </summary>
/// <param name="factories">The collection of factory classes for allowable decompressors. The
/// supplied vector itself need not remain valid after the call returns.</param>
/// <remarks>
/// This default collection is implied if request_compressed_response() is set in the associated
/// <c>client::http_client_config</c> and neither overload of this method has been called.
///
/// This cannot be used in conjunction with any external means of decompression. The TE and Accept-Encoding
/// headers must not be set by the client, as they will be managed internally as appropriate.
/// </remarks>
_ASYNCRTIMP
void
set_decompress_factories
();
/// <summary>
/// Sets a collection of factory classes for decompressors that may be used to decompress the
/// body of the HTTP message as it is received, effectively enabling decompression.
/// </summary>
/// <remarks>
/// If set, this collection takes the place of the built-in compression providers. It may contain
/// custom factory classes and/or factory classes for built-in providers, and may be used to adjust
/// the weights of the built-in providers, which default to 500 (i.e. "q=0.500").
///
/// This cannot be used in conjunction with any external means of decompression. The TE and Accept-Encoding
/// headers must not be set by the client, as they will be managed internally as appropriate.
/// </remarks>
void
set_decompress_factories
(
const
std
::
vector
<
std
::
shared_ptr
<
http
::
compression
::
decompress_factory
>>&
factories
)
{
return
_m_impl
->
set_decompress_factories
(
factories
);
}
/// <summary>
/// Gets the collection of factory classes for decompressors to be used to decompress the message body, if any.
/// </summary>
/// <returns>
/// The collection of factory classes itself.
/// </returns>
/// <remarks>
/// This cannot be used in conjunction with any external means of decompression. The TE
/// header must not be set by the client, as it will be managed internally.
/// </remarks>
const
std
::
vector
<
std
::
shared_ptr
<
http
::
compression
::
decompress_factory
>>&
decompress_factories
()
const
{
return
_m_impl
->
decompress_factories
();
}
/// <summary>
/// Defines a callback function that will be invoked for every chunk of data uploaded or downloaded
/// as part of the request.
/// </summary>
/// <param name="handler">A function representing the progress handler. It's parameters are:
/// up: a <c>message_direction::direction</c> value indicating the direction of the message
/// that is being reported.
/// progress: the number of bytes that have been processed so far.
/// </param>
/// <remarks>
/// This function will be called at least once for upload and at least once for
/// the download body, unless there is some exception generated. An HTTP message with an error
/// code is not an exception. This means, that even if there is no body, the progress handler
/// will be called.
///
/// Setting the chunk size on the http_client does not guarantee that the client will be using
/// exactly that increment for uploading and downloading data.
///
/// The handler will be called only once for each combination of argument values, in order. Depending
/// on how a service responds, some download values may come before all upload values have been
/// reported.
///
/// The progress handler will be called on the thread processing the request. This means that
/// the implementation of the handler must take care not to block the thread or do anything
/// that takes significant amounts of time. In particular, do not do any kind of I/O from within
/// the handler, do not update user interfaces, and to not acquire any locks. If such activities
/// are necessary, it is the handler's responsibility to execute that work on a separate thread.
/// </remarks>
void
set_progress_handler
(
const
progress_handler
&
handler
)
{
return
_m_impl
->
set_progress_handler
(
handler
);
}
/// <summary>
/// Asynchronously responses to this HTTP request.
/// </summary>
/// <param name="response">Response to send.</param>
/// <returns>An asynchronous operation that is completed once response is sent.</returns>
pplx
::
task
<
void
>
reply
(
const
http_response
&
response
)
const
{
return
_m_impl
->
reply
(
response
);
}
/// <summary>
/// Asynchronously responses to this HTTP request.
/// </summary>
/// <param name="status">Response status code.</param>
/// <returns>An asynchronous operation that is completed once response is sent.</returns>
pplx
::
task
<
void
>
reply
(
http
::
status_code
status
)
const
{
return
reply
(
http_response
(
status
));
}
/// <summary>
/// Responds to this HTTP request.
/// </summary>
/// <param name="status">Response status code.</param>
/// <param name="body_data">Json value to use in the response body.</param>
/// <returns>An asynchronous operation that is completed once response is sent.</returns>
pplx
::
task
<
void
>
reply
(
http
::
status_code
status
,
const
json
::
value
&
body_data
)
const
{
http_response
response
(
status
);
response
.
set_body
(
body_data
);
return
reply
(
response
);
}
/// Responds to this HTTP request with a string.
/// Assumes the character encoding of the string is UTF-8.
/// </summary>
/// <param name="status">Response status code.</param>
/// <param name="body_data">UTF-8 string containing the text to use in the response body.</param>
/// <param name="content_type">Content type of the body.</param>
/// <returns>An asynchronous operation that is completed once response is sent.</returns>
/// <remarks>
// Callers of this function do NOT need to block waiting for the response to be
/// sent to before the body data is destroyed or goes out of scope.
/// </remarks>
pplx
::
task
<
void
>
reply
(
http
::
status_code
status
,
utf8string
&&
body_data
,
const
utf8string
&
content_type
=
"text/plain; charset=utf-8"
)
const
{
http_response
response
(
status
);
response
.
set_body
(
std
::
move
(
body_data
),
content_type
);
return
reply
(
response
);
}
/// <summary>
/// Responds to this HTTP request with a string.
/// Assumes the character encoding of the string is UTF-8.
/// </summary>
/// <param name="status">Response status code.</param>
/// <param name="body_data">UTF-8 string containing the text to use in the response body.</param>
/// <param name="content_type">Content type of the body.</param>
/// <returns>An asynchronous operation that is completed once response is sent.</returns>
/// <remarks>
// Callers of this function do NOT need to block waiting for the response to be
/// sent to before the body data is destroyed or goes out of scope.
/// </remarks>
pplx
::
task
<
void
>
reply
(
http
::
status_code
status
,
const
utf8string
&
body_data
,
const
utf8string
&
content_type
=
"text/plain; charset=utf-8"
)
const
{
http_response
response
(
status
);
response
.
set_body
(
body_data
,
content_type
);
return
reply
(
response
);
}
/// <summary>
/// Responds to this HTTP request with a string. Assumes the character encoding
/// of the string is UTF-16 will perform conversion to UTF-8.
/// </summary>
/// <param name="status">Response status code.</param>
/// <param name="body_data">UTF-16 string containing the text to use in the response body.</param>
/// <param name="content_type">Content type of the body.</param>
/// <returns>An asynchronous operation that is completed once response is sent.</returns>
/// <remarks>
// Callers of this function do NOT need to block waiting for the response to be
/// sent to before the body data is destroyed or goes out of scope.
/// </remarks>
pplx
::
task
<
void
>
reply
(
http
::
status_code
status
,
const
utf16string
&
body_data
,
const
utf16string
&
content_type
=
utility
::
conversions
::
to_utf16string
(
"text/plain"
))
const
{
http_response
response
(
status
);
response
.
set_body
(
body_data
,
content_type
);
return
reply
(
response
);
}
/// <summary>
/// Responds to this HTTP request.
/// </summary>
/// <param name="status">Response status code.</param>
/// <param name="content_type">A string holding the MIME type of the message body.</param>
/// <param name="body">An asynchronous stream representing the body data.</param>
/// <returns>A task that is completed once a response from the request is received.</returns>
pplx
::
task
<
void
>
reply
(
status_code
status
,
const
concurrency
::
streams
::
istream
&
body
,
const
utility
::
string_t
&
content_type
=
_XPLATSTR
(
"application/octet-stream"
))
const
{
http_response
response
(
status
);
response
.
set_body
(
body
,
content_type
);
return
reply
(
response
);
}
/// <summary>
/// Responds to this HTTP request.
/// </summary>
/// <param name="status">Response status code.</param>
/// <param name="content_length">The size of the data to be sent in the body..</param>
/// <param name="content_type">A string holding the MIME type of the message body.</param>
/// <param name="body">An asynchronous stream representing the body data.</param>
/// <returns>A task that is completed once a response from the request is received.</returns>
pplx
::
task
<
void
>
reply
(
status_code
status
,
const
concurrency
::
streams
::
istream
&
body
,
utility
::
size64_t
content_length
,
const
utility
::
string_t
&
content_type
=
_XPLATSTR
(
"application/octet-stream"
))
const
{
http_response
response
(
status
);
response
.
set_body
(
body
,
content_length
,
content_type
);
return
reply
(
response
);
}
/// <summary>
/// Signals the user (listener) when all the data for this request message has been received.
/// </summary>
/// <returns>A <c>task</c> which is completed when all of the response body has been received</returns>
pplx
::
task
<
http_request
>
content_ready
()
const
{
http_request
req
=
*
this
;
return
pplx
::
create_task
(
_m_impl
->
_get_data_available
()).
then
([
req
](
utility
::
size64_t
)
mutable
{
return
req
;
});
}
/// <summary>
/// Gets a task representing the response that will eventually be sent.
/// </summary>
/// <returns>A task that is completed once response is sent.</returns>
pplx
::
task
<
http_response
>
get_response
()
const
{
return
_m_impl
->
get_response
();
}
/// <summary>
/// Generates a string representation of the message, including the body when possible.
/// Mainly this should be used for debugging purposes as it has to copy the
/// message body and doesn't have excellent performance.
/// </summary>
/// <returns>A string representation of this HTTP request.</returns>
/// <remarks>Note this function is synchronous and doesn't wait for the
/// entire message body to arrive. If the message body has arrived by the time this
/// function is called and it is has a textual Content-Type it will be included.
/// Otherwise just the headers will be present.</remarks>
utility
::
string_t
to_string
()
const
{
return
_m_impl
->
to_string
();
}
/// <summary>
/// Sends a response if one has not already been sent.
/// </summary>
pplx
::
task
<
void
>
_reply_if_not_already
(
status_code
status
)
{
return
_m_impl
->
_reply_if_not_already
(
status
);
}
/// <summary>
/// Gets the server context associated with this HTTP message.
/// </summary>
http
::
details
::
_http_server_context
*
_get_server_context
()
const
{
return
_m_impl
->
_get_server_context
();
}
/// <summary>
/// These are used for the initial creation of the HTTP request.
/// </summary>
static
http_request
_create_request
(
std
::
unique_ptr
<
http
::
details
::
_http_server_context
>
server_context
)
{
return
http_request
(
std
::
move
(
server_context
));
}
void
_set_server_context
(
std
::
unique_ptr
<
http
::
details
::
_http_server_context
>
server_context
)
{
_m_impl
->
_set_server_context
(
std
::
move
(
server_context
));
}
void
_set_listener_path
(
const
utility
::
string_t
&
path
)
{
_m_impl
->
_set_listener_path
(
path
);
}
const
std
::
shared_ptr
<
http
::
details
::
_http_request
>&
_get_impl
()
const
{
return
_m_impl
;
}
void
_set_cancellation_token
(
const
pplx
::
cancellation_token
&
token
)
{
_m_impl
->
set_cancellation_token
(
token
);
}
const
pplx
::
cancellation_token
&
_cancellation_token
()
const
{
return
_m_impl
->
cancellation_token
();
}
void
_set_base_uri
(
const
http
::
uri
&
base_uri
)
{
_m_impl
->
_set_base_uri
(
base_uri
);
}
private:
friend
class
http
::
details
::
_http_request
;
friend
class
http
::
client
::
http_client
;
http_request
(
std
::
unique_ptr
<
http
::
details
::
_http_server_context
>
server_context
)
:
_m_impl
(
std
::
make_shared
<
details
::
_http_request
>
(
std
::
move
(
server_context
)))
{
}
std
::
shared_ptr
<
http
::
details
::
_http_request
>
_m_impl
;
};
namespace
client
{
class
http_pipeline
;
}
/// <summary>
/// HTTP client handler class, used to represent an HTTP pipeline stage.
/// </summary>
/// <remarks>
/// When a request goes out, it passes through a series of stages, customizable by
/// the application and/or libraries. The default stage will interact with lower-level
/// communication layers to actually send the message on the network. When creating a client
/// instance, an application may add pipeline stages in front of the already existing
/// stages. Each stage has a reference to the next stage available in the <seealso cref="http_pipeline_stage::next_stage
/// Method"/> value.
/// </remarks>
class
http_pipeline_stage
:
public
std
::
enable_shared_from_this
<
http_pipeline_stage
>
{
public:
http_pipeline_stage
()
=
default
;
http_pipeline_stage
&
operator
=
(
const
http_pipeline_stage
&
)
=
delete
;
http_pipeline_stage
(
const
http_pipeline_stage
&
)
=
delete
;
virtual
~
http_pipeline_stage
()
=
default
;
/// <summary>
/// Runs this stage against the given request and passes onto the next stage.
/// </summary>
/// <param name="request">The HTTP request.</param>
/// <returns>A task of the HTTP response.</returns>
virtual
pplx
::
task
<
http_response
>
propagate
(
http_request
request
)
=
0
;
protected:
/// <summary>
/// Gets the next stage in the pipeline.
/// </summary>
/// <returns>A shared pointer to a pipeline stage.</returns>
const
std
::
shared_ptr
<
http_pipeline_stage
>&
next_stage
()
const
{
return
m_next_stage
;
}
/// <summary>
/// Gets a shared pointer to this pipeline stage.
/// </summary>
/// <returns>A shared pointer to a pipeline stage.</returns>
CASABLANCA_DEPRECATED
(
"This api is redundant. Use 'shared_from_this()' directly instead."
)
std
::
shared_ptr
<
http_pipeline_stage
>
current_stage
()
{
return
this
->
shared_from_this
();
}
private:
friend
class
::
web
::
http
::
client
::
http_pipeline
;
void
set_next_stage
(
const
std
::
shared_ptr
<
http_pipeline_stage
>&
next
)
{
m_next_stage
=
next
;
}
std
::
shared_ptr
<
http_pipeline_stage
>
m_next_stage
;
};
}
// namespace http
}
// namespace web
cpprestsdk_static_tester/vcpkg/include/cpprest/interopstream.h
0 → 100644
View file @
14571fd2
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* Adapter classes for async and STD stream buffers, used to connect std-based and async-based APIs.
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#include
"cpprest/astreambuf.h"
#include
"cpprest/streams.h"
#include
"pplx/pplxtasks.h"
#if defined(_WIN32)
#pragma warning(push)
#pragma warning(disable : 4250)
#endif
namespace
Concurrency
{
namespace
streams
{
template
<
typename
CharType
>
class
stdio_ostream
;
template
<
typename
CharType
>
class
stdio_istream
;
namespace
details
{
/// <summary>
/// The basic_stdio_buffer class serves to support interoperability with STL stream buffers.
/// Sitting atop a std::streambuf, which does all the I/O, instances of this class may read
/// and write data to standard iostreams. The class itself should not be used in application
/// code, it is used by the stream definitions farther down in the header file.
/// </summary>
template
<
typename
_CharType
>
class
basic_stdio_buffer
:
public
streambuf_state_manager
<
_CharType
>
{
typedef
concurrency
::
streams
::
char_traits
<
_CharType
>
traits
;
typedef
typename
traits
::
int_type
int_type
;
typedef
typename
traits
::
pos_type
pos_type
;
typedef
typename
traits
::
off_type
off_type
;
/// <summary>
/// Private constructor
/// </summary>
basic_stdio_buffer
(
_In_
std
::
basic_streambuf
<
_CharType
>*
streambuf
,
std
::
ios_base
::
openmode
mode
)
:
streambuf_state_manager
<
_CharType
>
(
mode
),
m_buffer
(
streambuf
)
{
}
public:
/// <summary>
/// Destructor
/// </summary>
virtual
~
basic_stdio_buffer
()
{
this
->
_close_read
();
this
->
_close_write
();
}
private:
//
// The functions overridden below here are documented elsewhere.
// See astreambuf.h for further information.
//
virtual
bool
can_seek
()
const
{
return
this
->
is_open
();
}
virtual
bool
has_size
()
const
{
return
false
;
}
virtual
size_t
in_avail
()
const
{
return
(
size_t
)
m_buffer
->
in_avail
();
}
virtual
size_t
buffer_size
(
std
::
ios_base
::
openmode
)
const
{
return
0
;
}
virtual
void
set_buffer_size
(
size_t
,
std
::
ios_base
::
openmode
)
{
return
;
}
virtual
pplx
::
task
<
bool
>
_sync
()
{
return
pplx
::
task_from_result
(
m_buffer
->
pubsync
()
==
0
);
}
virtual
pplx
::
task
<
int_type
>
_putc
(
_CharType
ch
)
{
return
pplx
::
task_from_result
(
m_buffer
->
sputc
(
ch
));
}
virtual
pplx
::
task
<
size_t
>
_putn
(
const
_CharType
*
ptr
,
size_t
size
)
{
return
pplx
::
task_from_result
((
size_t
)
m_buffer
->
sputn
(
ptr
,
size
));
}
size_t
_sgetn
(
_Out_writes_
(
size
)
_CharType
*
ptr
,
_In_
size_t
size
)
const
{
return
m_buffer
->
sgetn
(
ptr
,
size
);
}
virtual
size_t
_scopy
(
_Out_writes_
(
size
)
_CharType
*
,
_In_
size_t
size
)
{
(
void
)(
size
);
return
(
size_t
)
-
1
;
}
virtual
pplx
::
task
<
size_t
>
_getn
(
_Out_writes_
(
size
)
_CharType
*
ptr
,
_In_
size_t
size
)
{
return
pplx
::
task_from_result
((
size_t
)
m_buffer
->
sgetn
(
ptr
,
size
));
}
virtual
int_type
_sbumpc
()
{
return
m_buffer
->
sbumpc
();
}
virtual
int_type
_sgetc
()
{
return
m_buffer
->
sgetc
();
}
virtual
pplx
::
task
<
int_type
>
_bumpc
()
{
return
pplx
::
task_from_result
<
int_type
>
(
m_buffer
->
sbumpc
());
}
virtual
pplx
::
task
<
int_type
>
_getc
()
{
return
pplx
::
task_from_result
<
int_type
>
(
m_buffer
->
sgetc
());
}
virtual
pplx
::
task
<
int_type
>
_nextc
()
{
return
pplx
::
task_from_result
<
int_type
>
(
m_buffer
->
snextc
());
}
virtual
pplx
::
task
<
int_type
>
_ungetc
()
{
return
pplx
::
task_from_result
<
int_type
>
(
m_buffer
->
sungetc
());
}
virtual
pos_type
getpos
(
std
::
ios_base
::
openmode
mode
)
const
{
return
m_buffer
->
pubseekoff
(
0
,
std
::
ios_base
::
cur
,
mode
);
}
virtual
pos_type
seekpos
(
pos_type
pos
,
std
::
ios_base
::
openmode
mode
)
{
return
m_buffer
->
pubseekpos
(
pos
,
mode
);
}
virtual
pos_type
seekoff
(
off_type
off
,
std
::
ios_base
::
seekdir
dir
,
std
::
ios_base
::
openmode
mode
)
{
return
m_buffer
->
pubseekoff
(
off
,
dir
,
mode
);
}
virtual
_CharType
*
_alloc
(
size_t
)
{
return
nullptr
;
}
virtual
void
_commit
(
size_t
)
{}
virtual
bool
acquire
(
_CharType
*&
,
size_t
&
)
{
return
false
;
}
virtual
void
release
(
_CharType
*
,
size_t
)
{}
template
<
typename
CharType
>
friend
class
concurrency
::
streams
::
stdio_ostream
;
template
<
typename
CharType
>
friend
class
concurrency
::
streams
::
stdio_istream
;
std
::
basic_streambuf
<
_CharType
>*
m_buffer
;
};
}
// namespace details
/// <summary>
/// stdio_ostream represents an async ostream derived from a standard synchronous stream, as
/// defined by the "std" namespace. It is constructed from a reference to a standard stream, which
/// must be valid for the lifetime of the asynchronous stream.
/// </summary>
/// <typeparam name="CharType">
/// The data type of the basic element of the <c>stdio_ostream</c>.
/// </typeparam>
/// <remarks>
/// Since std streams are not reference-counted, great care must be taken by an application to make
/// sure that the std stream does not get destroyed until all uses of the asynchronous stream are
/// done and have been serviced.
/// </remarks>
template
<
typename
CharType
>
class
stdio_ostream
:
public
basic_ostream
<
CharType
>
{
public:
/// <summary>
/// Constructor
/// </summary>
/// <typeparam name="AlterCharType">
/// The data type of the basic element of the source output stream.
/// </typeparam>
/// <param name="stream">The synchronous stream that this is using for its I/O</param>
template
<
typename
AlterCharType
>
stdio_ostream
(
std
::
basic_ostream
<
AlterCharType
>&
stream
)
:
basic_ostream
<
CharType
>
(
streams
::
streambuf
<
AlterCharType
>
(
std
::
shared_ptr
<
details
::
basic_stdio_buffer
<
AlterCharType
>>
(
new
details
::
basic_stdio_buffer
<
AlterCharType
>
(
stream
.
rdbuf
(),
std
::
ios_base
::
out
))))
{
}
/// <summary>
/// Copy constructor
/// </summary>
/// <param name="other">The source object</param>
stdio_ostream
(
const
stdio_ostream
&
other
)
:
basic_ostream
<
CharType
>
(
other
)
{}
/// <summary>
/// Assignment operator
/// </summary>
/// <param name="other">The source object</param>
/// <returns>A reference to the output stream object that contains the result of the assignment.</returns>
stdio_ostream
&
operator
=
(
const
stdio_ostream
&
other
)
{
basic_ostream
<
CharType
>::
operator
=
(
other
);
return
*
this
;
}
};
/// <summary>
/// stdio_istream represents an async istream derived from a standard synchronous stream, as
/// defined by the "std" namespace. It is constructed from a reference to a standard stream, which
/// must be valid for the lifetime of the asynchronous stream.
/// </summary>
/// <typeparam name="CharType">
/// The data type of the basic element of the <c>stdio_istream</c>.
/// </typeparam>
/// <remarks>
/// Since std streams are not reference-counted, great care must be taken by an application to make
/// sure that the std stream does not get destroyed until all uses of the asynchronous stream are
/// done and have been serviced.
/// </remarks>
template
<
typename
CharType
>
class
stdio_istream
:
public
basic_istream
<
CharType
>
{
public:
/// <summary>
/// Constructor
/// </summary>
/// <typeparam name="AlterCharType">
/// The data type of the basic element of the source <c>istream</c>
/// </typeparam>
/// <param name="stream">The synchronous stream that this is using for its I/O</param>
template
<
typename
AlterCharType
>
stdio_istream
(
std
::
basic_istream
<
AlterCharType
>&
stream
)
:
basic_istream
<
CharType
>
(
streams
::
streambuf
<
AlterCharType
>
(
std
::
shared_ptr
<
details
::
basic_stdio_buffer
<
AlterCharType
>>
(
new
details
::
basic_stdio_buffer
<
AlterCharType
>
(
stream
.
rdbuf
(),
std
::
ios_base
::
in
))))
{
}
/// <summary>
/// Copy constructor
/// </summary>
/// <param name="other">The source object</param>
stdio_istream
(
const
stdio_istream
&
other
)
:
basic_istream
<
CharType
>
(
other
)
{}
/// <summary>
/// Assignment operator
/// </summary>
/// <param name="other">The source object</param>
/// <returns>A reference to the input stream object that contains the result of the assignment.</returns>
stdio_istream
&
operator
=
(
const
stdio_istream
&
other
)
{
basic_istream
<
CharType
>::
operator
=
(
other
);
return
*
this
;
}
};
namespace
details
{
/// <summary>
/// IO streams stream buffer implementation used to interface with an async streambuffer underneath.
/// Used for implementing the standard synchronous streams that provide interop between std:: and concurrency::streams::
/// </summary>
template
<
typename
CharType
>
class
basic_async_streambuf
:
public
std
::
basic_streambuf
<
CharType
>
{
public:
typedef
concurrency
::
streams
::
char_traits
<
CharType
>
traits
;
typedef
typename
traits
::
int_type
int_type
;
typedef
typename
traits
::
pos_type
pos_type
;
typedef
typename
traits
::
off_type
off_type
;
basic_async_streambuf
(
const
streams
::
streambuf
<
CharType
>&
async_buf
)
:
m_buffer
(
async_buf
)
{}
protected:
//
// The following are the functions in std::basic_streambuf that we need to override.
//
/// <summary>
/// Writes one byte to the stream buffer.
/// </summary>
int_type
overflow
(
int_type
ch
)
{
try
{
return
m_buffer
.
putc
(
CharType
(
ch
)).
get
();
}
catch
(...)
{
return
traits
::
eof
();
}
}
/// <summary>
/// Gets one byte from the stream buffer without moving the read position.
/// </summary>
int_type
underflow
()
{
try
{
return
m_buffer
.
getc
().
get
();
}
catch
(...)
{
return
traits
::
eof
();
}
}
/// <summary>
/// Gets one byte from the stream buffer and move the read position one character.
/// </summary>
int_type
uflow
()
{
try
{
return
m_buffer
.
bumpc
().
get
();
}
catch
(...)
{
return
traits
::
eof
();
}
}
/// <summary>
/// Gets a number of characters from the buffer and place it into the provided memory block.
/// </summary>
std
::
streamsize
xsgetn
(
_Out_writes_
(
count
)
CharType
*
ptr
,
_In_
std
::
streamsize
count
)
{
size_t
cnt
=
size_t
(
count
);
size_t
read_so_far
=
0
;
try
{
while
(
read_so_far
<
cnt
)
{
size_t
rd
=
m_buffer
.
getn
(
ptr
+
read_so_far
,
cnt
-
read_so_far
).
get
();
read_so_far
+=
rd
;
if
(
rd
==
0
)
break
;
}
return
read_so_far
;
}
catch
(...)
{
return
0
;
}
}
/// <summary>
/// Writes a given number of characters from the provided block into the stream buffer.
/// </summary>
std
::
streamsize
xsputn
(
const
CharType
*
ptr
,
std
::
streamsize
count
)
{
try
{
return
m_buffer
.
putn_nocopy
(
ptr
,
static_cast
<
size_t
>
(
count
)).
get
();
}
catch
(...)
{
return
0
;
}
}
/// <summary>
/// Synchronizes with the underlying medium.
/// </summary>
int
sync
()
// must be int as per std::basic_streambuf
{
try
{
m_buffer
.
sync
().
wait
();
}
catch
(...)
{
}
return
0
;
}
/// <summary>
/// Seeks to the given offset relative to the beginning, end, or current position.
/// </summary>
pos_type
seekoff
(
off_type
offset
,
std
::
ios_base
::
seekdir
dir
,
std
::
ios_base
::
openmode
mode
=
std
::
ios_base
::
in
|
std
::
ios_base
::
out
)
{
try
{
if
(
dir
==
std
::
ios_base
::
cur
&&
offset
==
0
)
// Special case for getting the current position.
return
m_buffer
.
getpos
(
mode
);
return
m_buffer
.
seekoff
(
offset
,
dir
,
mode
);
}
catch
(...)
{
return
(
pos_type
(
-
1
));
}
}
/// <summary>
/// Seeks to the given offset relative to the beginning of the stream.
/// </summary>
pos_type
seekpos
(
pos_type
pos
,
std
::
ios_base
::
openmode
mode
=
std
::
ios_base
::
in
|
std
::
ios_base
::
out
)
{
try
{
return
m_buffer
.
seekpos
(
pos
,
mode
);
}
catch
(...)
{
return
(
pos_type
(
-
1
));
}
}
private:
concurrency
::
streams
::
streambuf
<
CharType
>
m_buffer
;
};
}
// namespace details
/// <summary>
/// A concrete STL ostream which relies on an asynchronous stream for its I/O.
/// </summary>
/// <typeparam name="CharType">
/// The data type of the basic element of the stream.
/// </typeparam>
template
<
typename
CharType
>
class
async_ostream
:
public
std
::
basic_ostream
<
CharType
>
{
public:
/// <summary>
/// Constructor
/// </summary>
/// <typeparam name="AlterCharType">
/// The data type of the basic element of the source ostream.
/// </typeparam>
/// <param name="astream">The asynchronous stream whose stream buffer should be used for I/O</param>
template
<
typename
AlterCharType
>
async_ostream
(
const
streams
::
basic_ostream
<
AlterCharType
>&
astream
)
:
std
::
basic_ostream
<
CharType
>
(
&
m_strbuf
),
m_strbuf
(
astream
.
streambuf
())
{
}
/// <summary>
/// Constructor
/// </summary>
/// <typeparam name="AlterCharType">
/// The data type of the basic element of the source <c>streambuf</c>.
/// </typeparam>
/// <param name="strbuf">The asynchronous stream buffer to use for I/O</param>
template
<
typename
AlterCharType
>
async_ostream
(
const
streams
::
streambuf
<
AlterCharType
>&
strbuf
)
:
std
::
basic_ostream
<
CharType
>
(
&
m_strbuf
),
m_strbuf
(
strbuf
)
{
}
private:
details
::
basic_async_streambuf
<
CharType
>
m_strbuf
;
};
/// <summary>
/// A concrete STL istream which relies on an asynchronous stream for its I/O.
/// </summary>
/// <typeparam name="CharType">
/// The data type of the basic element of the stream.
/// </typeparam>
template
<
typename
CharType
>
class
async_istream
:
public
std
::
basic_istream
<
CharType
>
{
public:
/// <summary>
/// Constructor
/// </summary>
/// <typeparam name="AlterCharType">
/// The data type of the basic element of the source istream.
/// </typeparam>
/// <param name="astream">The asynchronous stream whose stream buffer should be used for I/O</param>
template
<
typename
AlterCharType
>
async_istream
(
const
streams
::
basic_istream
<
AlterCharType
>&
astream
)
:
std
::
basic_istream
<
CharType
>
(
&
m_strbuf
),
m_strbuf
(
astream
.
streambuf
())
{
}
/// <summary>
/// Constructor
/// </summary>
/// <typeparam name="AlterCharType">
/// The data type of the basic element of the source <c>streambuf</c>.
/// </typeparam>
/// <param name="strbuf">The asynchronous stream buffer to use for I/O</param>
template
<
typename
AlterCharType
>
async_istream
(
const
streams
::
streambuf
<
AlterCharType
>&
strbuf
)
:
std
::
basic_istream
<
CharType
>
(
&
m_strbuf
),
m_strbuf
(
strbuf
)
{
}
private:
details
::
basic_async_streambuf
<
CharType
>
m_strbuf
;
};
/// <summary>
/// A concrete STL istream which relies on an asynchronous stream buffer for its I/O.
/// </summary>
/// <typeparam name="CharType">
/// The data type of the basic element of the stream.
/// </typeparam>
template
<
typename
CharType
>
class
async_iostream
:
public
std
::
basic_iostream
<
CharType
>
{
public:
/// <summary>
/// Constructor
/// </summary>
/// <param name="strbuf">The asynchronous stream buffer to use for I/O</param>
async_iostream
(
const
streams
::
streambuf
<
CharType
>&
strbuf
)
:
std
::
basic_iostream
<
CharType
>
(
&
m_strbuf
),
m_strbuf
(
strbuf
)
{
}
private:
details
::
basic_async_streambuf
<
CharType
>
m_strbuf
;
};
#if defined(__cplusplus_winrt)
/// <summary>
/// Static class containing factory functions for WinRT streams implemented on top of Casablanca async streams.
/// </summary>
/// <remarks>WinRT streams are defined in terms of single-byte characters only.</remarks>
class
winrt_stream
{
public:
/// <summary>
/// Creates a WinRT <c>IInputStream</c> reference from an asynchronous stream buffer.
/// </summary>
/// <param name="buffer">A stream buffer based on a single-byte character.</param>
/// <returns>A reference to a WinRT <c>IInputStream</c>.</returns>
/// <remarks>
/// The stream buffer passed in must allow reading.
/// The stream buffer is shared with the caller, allowing data to be passed between the two contexts. For
/// example, using a <c>producer_consumer_buffer</c>, a Casablanca-based caller can pass data to a WinRT component.
/// </remarks>
_ASYNCRTIMP
static
Windows
::
Storage
::
Streams
::
IInputStream
^
__cdecl
create_input_stream
(
const
concurrency
::
streams
::
streambuf
<
uint8_t
>&
buffer
);
/// <summary>
/// Creates a WinRT <c>IOutputStream</c> reference from an asynchronous stream buffer.
/// </summary>
/// <param name="buffer">A stream buffer based on a single-byte character.</param>
/// <returns>A reference to a WinRT <c>IOutputStream</c>.</returns>
/// <remarks>
/// The stream buffer passed in must allow writing.
/// The stream buffer is shared with the caller, allowing data to be passed between the two contexts. For
/// example, using a <c>producer_consumer_buffer</c>, a Casablanca-based caller can retrieve data from a WinRT
/// component.
/// </remarks>
_ASYNCRTIMP
static
Windows
::
Storage
::
Streams
::
IOutputStream
^
__cdecl
create_output_stream
(
const
concurrency
::
streams
::
streambuf
<
uint8_t
>&
buffer
);
/// <summary>
/// Creates a WinRT <c>IRandomAccessStream reference from an asynchronous input stream.
/// </summary>
/// <param name="buffer">A stream based on a single-byte character.</param>
/// <returns>A reference to a WinRT <c>IRandomAccessStream</c>.</returns>
/// <remarks>
/// The stream buffer is shared with the caller, allowing data to be passed between the two contexts. For
/// example, using a <c>producer_consumer_buffer</c>, a Casablanca-based caller can pass data to and retrieve data
/// from a WinRT component.
/// </remarks>
_ASYNCRTIMP
static
Windows
::
Storage
::
Streams
::
IRandomAccessStream
^
__cdecl
create_random_access_stream
(
const
concurrency
::
streams
::
streambuf
<
uint8_t
>&
buffer
);
};
#endif
}
// namespace streams
}
// namespace Concurrency
#if defined(_WIN32)
#pragma warning(pop)
#endif
cpprestsdk_static_tester/vcpkg/include/cpprest/json.h
0 → 100644
View file @
14571fd2
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* HTTP Library: JSON parser and writer
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#ifndef CASA_JSON_H
#define CASA_JSON_H
#include
"cpprest/asyncrt_utils.h"
#include
"cpprest/details/basic_types.h"
#include
<cstdint>
#include
<memory>
#include
<sstream>
#include
<string>
#include
<unordered_map>
#include
<vector>
namespace
web
{
/// Library for parsing and serializing JSON values to and from C++ types.
namespace
json
{
// Various forward declarations.
namespace
details
{
class
_Value
;
class
_Number
;
class
_Null
;
class
_Boolean
;
class
_String
;
class
_Object
;
class
_Array
;
template
<
typename
CharType
>
class
JSON_Parser
;
}
// namespace details
namespace
details
{
extern
bool
g_keep_json_object_unsorted
;
}
/// <summary>
/// Preserve the order of the name/value pairs when parsing a JSON object.
/// The default is false, which can yield better performance.
/// </summary>
/// <param name="keep_order"><c>true</c> if ordering should be preserved when parsing, <c>false</c> otherwise.</param>
/// <remarks>Note this is a global setting and affects all JSON parsing done.</remarks>
void
_ASYNCRTIMP
__cdecl
keep_object_element_order
(
bool
keep_order
);
#ifdef _WIN32
#ifdef _DEBUG
#define ENABLE_JSON_VALUE_VISUALIZER
#endif
#endif
class
number
;
class
array
;
class
object
;
/// <summary>
/// A JSON value represented as a C++ class.
/// </summary>
class
value
{
public:
/// <summary>
/// This enumeration represents the various kinds of JSON values.
/// </summary>
enum
value_type
{
/// Number value
Number
,
/// Boolean value
Boolean
,
/// String value
String
,
/// Object value
Object
,
/// Array value
Array
,
/// Null value
Null
};
/// <summary>
/// Constructor creating a null value
/// </summary>
_ASYNCRTIMP
value
();
/// <summary>
/// Constructor creating a JSON number value
/// </summary>
/// <param name="value">The C++ value to create a JSON value from</param>
_ASYNCRTIMP
value
(
int32_t
value
);
/// <summary>
/// Constructor creating a JSON number value
/// </summary>
/// <param name="value">The C++ value to create a JSON value from</param>
_ASYNCRTIMP
value
(
uint32_t
value
);
/// <summary>
/// Constructor creating a JSON number value
/// </summary>
/// <param name="value">The C++ value to create a JSON value from</param>
_ASYNCRTIMP
value
(
int64_t
value
);
/// <summary>
/// Constructor creating a JSON number value
/// </summary>
/// <param name="value">The C++ value to create a JSON value from</param>
_ASYNCRTIMP
value
(
uint64_t
value
);
/// <summary>
/// Constructor creating a JSON number value
/// </summary>
/// <param name="value">The C++ value to create a JSON value from</param>
_ASYNCRTIMP
value
(
double
value
);
/// <summary>
/// Constructor creating a JSON Boolean value
/// </summary>
/// <param name="value">The C++ value to create a JSON value from</param>
_ASYNCRTIMP
explicit
value
(
bool
value
);
/// <summary>
/// Constructor creating a JSON string value
/// </summary>
/// <param name="value">The C++ value to create a JSON value from, a C++ STL string of the platform-native character
/// width</param> <remarks> This constructor has O(n) performance because it tries to determine if specified string
/// has characters that should be properly escaped in JSON. <remarks>
_ASYNCRTIMP
explicit
value
(
utility
::
string_t
value
);
/// <summary>
/// Constructor creating a JSON string value specifying if the string contains characters to escape
/// </summary>
/// <param name="value">The C++ value to create a JSON value from, a C++ STL string of the platform-native character
/// width</param> <param name="has_escape_chars">Whether <paramref name="value" /> contains characters that should
/// be escaped in JSON value</param> <remarks> This constructor has O(1) performance.
/// </remarks>
_ASYNCRTIMP
explicit
value
(
utility
::
string_t
value
,
bool
has_escape_chars
);
/// <summary>
/// Constructor creating a JSON string value
/// </summary>
/// <param name="value">The C++ value to create a JSON value from, a C++ STL string of the platform-native character
/// width</param> <remarks> <para> This constructor has O(n) performance because it tries to determine if specified
/// string has characters that should be properly escaped in JSON.
/// </para>
/// <para>
/// This constructor exists in order to avoid string literals matching another constructor,
/// as is very likely. For example, conversion to bool does not require a user-defined conversion,
/// and will therefore match first, which means that the JSON value turns up as a boolean.
/// </para>
/// </remarks>
_ASYNCRTIMP
explicit
value
(
const
utility
::
char_t
*
value
);
/// <summary>
/// Constructor creating a JSON string value
/// </summary>
/// <param name="value">The C++ value to create a JSON value from, a C++ STL string of the platform-native character
/// width</param> <param name="has_escape_chars">Whether <paramref name="value" /> contains characters <remarks>
/// <para>
/// This overload has O(1) performance.
/// </para>
/// <para>
/// This constructor exists in order to avoid string literals matching another constructor,
/// as is very likely. For example, conversion to bool does not require a user-defined conversion,
/// and will therefore match first, which means that the JSON value turns up as a boolean.
/// </para>
/// </remarks>
_ASYNCRTIMP
explicit
value
(
const
utility
::
char_t
*
value
,
bool
has_escape_chars
);
/// <summary>
/// Copy constructor
/// </summary>
_ASYNCRTIMP
value
(
const
value
&
);
/// <summary>
/// Move constructor
/// </summary>
_ASYNCRTIMP
value
(
value
&&
)
CPPREST_NOEXCEPT
;
/// <summary>
/// Assignment operator.
/// </summary>
/// <returns>The JSON value object that contains the result of the assignment.</returns>
_ASYNCRTIMP
value
&
operator
=
(
const
value
&
);
/// <summary>
/// Move assignment operator.
/// </summary>
/// <returns>The JSON value object that contains the result of the assignment.</returns>
_ASYNCRTIMP
value
&
operator
=
(
value
&&
)
CPPREST_NOEXCEPT
;
// Static factories
/// <summary>
/// Creates a null value
/// </summary>
/// <returns>A JSON null value</returns>
static
_ASYNCRTIMP
value
__cdecl
null
();
/// <summary>
/// Creates a number value
/// </summary>
/// <param name="value">The C++ value to create a JSON value from</param>
/// <returns>A JSON number value</returns>
static
_ASYNCRTIMP
value
__cdecl
number
(
double
value
);
/// <summary>
/// Creates a number value
/// </summary>
/// <param name="value">The C++ value to create a JSON value from</param>
/// <returns>A JSON number value</returns>
static
_ASYNCRTIMP
value
__cdecl
number
(
int32_t
value
);
/// <summary>
/// Creates a number value
/// </summary>
/// <param name="value">The C++ value to create a JSON value from</param>
/// <returns>A JSON number value</returns>
static
_ASYNCRTIMP
value
__cdecl
number
(
uint32_t
value
);
/// <summary>
/// Creates a number value
/// </summary>
/// <param name="value">The C++ value to create a JSON value from</param>
/// <returns>A JSON number value</returns>
static
_ASYNCRTIMP
value
__cdecl
number
(
int64_t
value
);
/// <summary>
/// Creates a number value
/// </summary>
/// <param name="value">The C++ value to create a JSON value from</param>
/// <returns>A JSON number value</returns>
static
_ASYNCRTIMP
value
__cdecl
number
(
uint64_t
value
);
/// <summary>
/// Creates a Boolean value
/// </summary>
/// <param name="value">The C++ value to create a JSON value from</param>
/// <returns>A JSON Boolean value</returns>
static
_ASYNCRTIMP
value
__cdecl
boolean
(
bool
value
);
/// <summary>
/// Creates a string value
/// </summary>
/// <param name="value">The C++ value to create a JSON value from</param>
/// <returns>A JSON string value</returns>
/// <remarks>
/// This overload has O(n) performance because it tries to determine if
/// specified string has characters that should be properly escaped in JSON.
/// </remarks>
static
_ASYNCRTIMP
value
__cdecl
string
(
utility
::
string_t
value
);
/// <summary>
/// Creates a string value specifying if the string contains characters to escape
/// </summary>
/// <param name="value">The C++ value to create a JSON value from</param>
/// <param name="has_escape_chars">Whether <paramref name="value" /> contains characters
/// that should be escaped in JSON value</param>
/// <returns>A JSON string value</returns>
/// <remarks>
/// This overload has O(1) performance.
/// </remarks>
static
_ASYNCRTIMP
value
__cdecl
string
(
utility
::
string_t
value
,
bool
has_escape_chars
);
#ifdef _WIN32
private:
// Only used internally by JSON parser.
static
_ASYNCRTIMP
value
__cdecl
string
(
const
std
::
string
&
value
);
public:
#endif
/// <summary>
/// Creates an object value
/// </summary>
/// <param name="keep_order">Whether to preserve the original order of the fields</param>
/// <returns>An empty JSON object value</returns>
static
_ASYNCRTIMP
json
::
value
__cdecl
object
(
bool
keep_order
=
false
);
/// <summary>
/// Creates an object value from a collection of field/values
/// </summary>
/// <param name="fields">Field names associated with JSON values</param>
/// <param name="keep_order">Whether to preserve the original order of the fields</param>
/// <returns>A non-empty JSON object value</returns>
static
_ASYNCRTIMP
json
::
value
__cdecl
object
(
std
::
vector
<
std
::
pair
<::
utility
::
string_t
,
value
>>
fields
,
bool
keep_order
=
false
);
/// <summary>
/// Creates an empty JSON array
/// </summary>
/// <returns>An empty JSON array value</returns>
static
_ASYNCRTIMP
json
::
value
__cdecl
array
();
/// <summary>
/// Creates a JSON array
/// </summary>
/// <param name="size">The initial number of elements of the JSON value</param>
/// <returns>A JSON array value</returns>
static
_ASYNCRTIMP
json
::
value
__cdecl
array
(
size_t
size
);
/// <summary>
/// Creates a JSON array
/// </summary>
/// <param name="elements">A vector of JSON values</param>
/// <returns>A JSON array value</returns>
static
_ASYNCRTIMP
json
::
value
__cdecl
array
(
std
::
vector
<
value
>
elements
);
/// <summary>
/// Accesses the type of JSON value the current value instance is
/// </summary>
/// <returns>The value's type</returns>
_ASYNCRTIMP
json
::
value
::
value_type
type
()
const
;
/// <summary>
/// Is the current value a null value?
/// </summary>
/// <returns><c>true</c> if the value is a null value, <c>false</c> otherwise</returns>
bool
is_null
()
const
{
return
type
()
==
Null
;
};
/// <summary>
/// Is the current value a number value?
/// </summary>
/// <returns><c>true</c> if the value is a number value, <c>false</c> otherwise</returns>
bool
is_number
()
const
{
return
type
()
==
Number
;
}
/// <summary>
/// Is the current value represented as an integer number value?
/// </summary>
/// <remarks>
/// Note that if a json value is a number but represented as a double it can still
/// be retrieved as a integer using as_integer(), however the value will be truncated.
/// </remarks>
/// <returns><c>true</c> if the value is an integer value, <c>false</c> otherwise.</returns>
_ASYNCRTIMP
bool
is_integer
()
const
;
/// <summary>
/// Is the current value represented as an double number value?
/// </summary>
/// <remarks>
/// Note that if a json value is a number but represented as a int it can still
/// be retrieved as a double using as_double().
/// </remarks>
/// <returns><c>true</c> if the value is an double value, <c>false</c> otherwise.</returns>
_ASYNCRTIMP
bool
is_double
()
const
;
/// <summary>
/// Is the current value a Boolean value?
/// </summary>
/// <returns><c>true</c> if the value is a Boolean value, <c>false</c> otherwise</returns>
bool
is_boolean
()
const
{
return
type
()
==
Boolean
;
}
/// <summary>
/// Is the current value a string value?
/// </summary>
/// <returns><c>true</c> if the value is a string value, <c>false</c> otherwise</returns>
bool
is_string
()
const
{
return
type
()
==
String
;
}
/// <summary>
/// Is the current value an array?
/// </summary>
/// <returns><c>true</c> if the value is an array, <c>false</c> otherwise</returns>
bool
is_array
()
const
{
return
type
()
==
Array
;
}
/// <summary>
/// Is the current value an object?
/// </summary>
/// <returns><c>true</c> if the value is an object, <c>false</c> otherwise</returns>
bool
is_object
()
const
{
return
type
()
==
Object
;
}
/// <summary>
/// Gets the number of children of the value.
/// </summary>
/// <returns>The number of children. 0 for all non-composites.</returns>
size_t
size
()
const
;
/// <summary>
/// Parses a string and construct a JSON value.
/// </summary>
/// <param name="value">The C++ value to create a JSON value from, a C++ STL double-byte string</param>
_ASYNCRTIMP
static
value
__cdecl
parse
(
const
utility
::
string_t
&
value
);
/// <summary>
/// Attempts to parse a string and construct a JSON value.
/// </summary>
/// <param name="value">The C++ value to create a JSON value from, a C++ STL double-byte string</param>
/// <param name="errorCode">If parsing fails, the error code is greater than 0</param>
/// <returns>The parsed object. Returns web::json::value::null if failed</returns>
_ASYNCRTIMP
static
value
__cdecl
parse
(
const
utility
::
string_t
&
value
,
std
::
error_code
&
errorCode
);
/// <summary>
/// Serializes the current JSON value to a C++ string.
/// </summary>
/// <returns>A string representation of the value</returns>
_ASYNCRTIMP
utility
::
string_t
serialize
()
const
;
/// <summary>
/// Serializes the current JSON value to a C++ string.
/// </summary>
/// <returns>A string representation of the value</returns>
CASABLANCA_DEPRECATED
(
"This API is deprecated and has been renamed to avoid confusion with as_string(), use "
"::web::json::value::serialize() instead."
)
_ASYNCRTIMP
utility
::
string_t
to_string
()
const
;
/// <summary>
/// Parses a JSON value from the contents of an input stream using the native platform character width.
/// </summary>
/// <param name="input">The stream to read the JSON value from</param>
/// <returns>The JSON value object created from the input stream.</returns>
_ASYNCRTIMP
static
value
__cdecl
parse
(
utility
::
istream_t
&
input
);
/// <summary>
/// Parses a JSON value from the contents of an input stream using the native platform character width.
/// </summary>
/// <param name="input">The stream to read the JSON value from</param>
/// <param name="errorCode">If parsing fails, the error code is greater than 0</param>
/// <returns>The parsed object. Returns web::json::value::null if failed</returns>
_ASYNCRTIMP
static
value
__cdecl
parse
(
utility
::
istream_t
&
input
,
std
::
error_code
&
errorCode
);
/// <summary>
/// Writes the current JSON value to a stream with the native platform character width.
/// </summary>
/// <param name="stream">The stream that the JSON string representation should be written to.</param>
_ASYNCRTIMP
void
serialize
(
utility
::
ostream_t
&
stream
)
const
;
#ifdef _WIN32
/// <summary>
/// Parses a JSON value from the contents of a single-byte (UTF8) stream.
/// </summary>
/// <param name="stream">The stream to read the JSON value from</param>
_ASYNCRTIMP
static
value
__cdecl
parse
(
std
::
istream
&
stream
);
/// <summary>
/// Parses a JSON value from the contents of a single-byte (UTF8) stream.
/// </summary>
/// <param name="stream">The stream to read the JSON value from</param>
/// <param name="errorCode">If parsing fails, the error code is greater than 0</param>
/// <returns>The parsed object. Returns web::json::value::null if failed</returns>
_ASYNCRTIMP
static
value
__cdecl
parse
(
std
::
istream
&
stream
,
std
::
error_code
&
error
);
/// <summary>
/// Serializes the content of the value into a single-byte (UTF8) stream.
/// </summary>
/// <param name="stream">The stream that the JSON string representation should be written to.</param>
_ASYNCRTIMP
void
serialize
(
std
::
ostream
&
stream
)
const
;
#endif
/// <summary>
/// Converts the JSON value to a C++ double, if and only if it is a number value.
/// Throws <see cref="json_exception"/> if the value is not a number
/// </summary>
/// <returns>A double representation of the value</returns>
_ASYNCRTIMP
double
as_double
()
const
;
/// <summary>
/// Converts the JSON value to a C++ integer, if and only if it is a number value.
/// Throws <see cref="json_exception"/> if the value is not a number
/// </summary>
/// <returns>An integer representation of the value</returns>
_ASYNCRTIMP
int
as_integer
()
const
;
/// <summary>
/// Converts the JSON value to a number class, if and only if it is a number value.
/// Throws <see cref="json_exception"/> if the value is not a number
/// </summary>
/// <returns>An instance of number class</returns>
_ASYNCRTIMP
const
json
::
number
&
as_number
()
const
;
/// <summary>
/// Converts the JSON value to a C++ bool, if and only if it is a Boolean value.
/// </summary>
/// <returns>A C++ bool representation of the value</returns>
_ASYNCRTIMP
bool
as_bool
()
const
;
/// <summary>
/// Converts the JSON value to a json array, if and only if it is an array value.
/// </summary>
/// <remarks>The returned <c>json::array</c> should have the same or shorter lifetime as <c>this</c></remarks>
/// <returns>An array representation of the value</returns>
_ASYNCRTIMP
json
::
array
&
as_array
();
/// <summary>
/// Converts the JSON value to a json array, if and only if it is an array value.
/// </summary>
/// <remarks>The returned <c>json::array</c> should have the same or shorter lifetime as <c>this</c></remarks>
/// <returns>An array representation of the value</returns>
_ASYNCRTIMP
const
json
::
array
&
as_array
()
const
;
/// <summary>
/// Converts the JSON value to a json object, if and only if it is an object value.
/// </summary>
/// <returns>An object representation of the value</returns>
_ASYNCRTIMP
json
::
object
&
as_object
();
/// <summary>
/// Converts the JSON value to a json object, if and only if it is an object value.
/// </summary>
/// <returns>An object representation of the value</returns>
_ASYNCRTIMP
const
json
::
object
&
as_object
()
const
;
/// <summary>
/// Converts the JSON value to a C++ STL string, if and only if it is a string value.
/// </summary>
/// <returns>A C++ STL string representation of the value</returns>
_ASYNCRTIMP
const
utility
::
string_t
&
as_string
()
const
;
/// <summary>
/// Compares two JSON values for equality.
/// </summary>
/// <param name="other">The JSON value to compare with.</param>
/// <returns>True if the values are equal.</returns>
_ASYNCRTIMP
bool
operator
==
(
const
value
&
other
)
const
;
/// <summary>
/// Compares two JSON values for inequality.
/// </summary>
/// <param name="other">The JSON value to compare with.</param>
/// <returns>True if the values are unequal.</returns>
bool
operator
!=
(
const
value
&
other
)
const
{
return
!
((
*
this
)
==
other
);
}
/// <summary>
/// Tests for the presence of a field.
/// </summary>
/// <param name="key">The name of the field</param>
/// <returns>True if the field exists, false otherwise.</returns>
bool
has_field
(
const
utility
::
string_t
&
key
)
const
;
/// <summary>
/// Tests for the presence of a number field
/// </summary>
/// <param name="key">The name of the field</param>
/// <returns>True if the field exists, false otherwise.</returns>
_ASYNCRTIMP
bool
has_number_field
(
const
utility
::
string_t
&
key
)
const
;
/// <summary>
/// Tests for the presence of an integer field
/// </summary>
/// <param name="key">The name of the field</param>
/// <returns>True if the field exists, false otherwise.</returns>
_ASYNCRTIMP
bool
has_integer_field
(
const
utility
::
string_t
&
key
)
const
;
/// <summary>
/// Tests for the presence of a double field
/// </summary>
/// <param name="key">The name of the field</param>
/// <returns>True if the field exists, false otherwise.</returns>
_ASYNCRTIMP
bool
has_double_field
(
const
utility
::
string_t
&
key
)
const
;
/// <summary>
/// Tests for the presence of a boolean field
/// </summary>
/// <param name="key">The name of the field</param>
/// <returns>True if the field exists, false otherwise.</returns>
_ASYNCRTIMP
bool
has_boolean_field
(
const
utility
::
string_t
&
key
)
const
;
/// <summary>
/// Tests for the presence of a string field
/// </summary>
/// <param name="key">The name of the field</param>
/// <returns>True if the field exists, false otherwise.</returns>
_ASYNCRTIMP
bool
has_string_field
(
const
utility
::
string_t
&
key
)
const
;
/// <summary>
/// Tests for the presence of an array field
/// </summary>
/// <param name="key">The name of the field</param>
/// <returns>True if the field exists, false otherwise.</returns>
_ASYNCRTIMP
bool
has_array_field
(
const
utility
::
string_t
&
key
)
const
;
/// <summary>
/// Tests for the presence of an object field
/// </summary>
/// <param name="key">The name of the field</param>
/// <returns>True if the field exists, false otherwise.</returns>
_ASYNCRTIMP
bool
has_object_field
(
const
utility
::
string_t
&
key
)
const
;
/// <summary>
/// Accesses a field of a JSON object.
/// </summary>
/// <param name="key">The name of the field</param>
/// <returns>The value kept in the field; null if the field does not exist</returns>
CASABLANCA_DEPRECATED
(
"This API is deprecated and will be removed in a future release, use json::value::at() instead."
)
value
get
(
const
utility
::
string_t
&
key
)
const
;
/// <summary>
/// Erases an element of a JSON array. Throws if index is out of bounds.
/// </summary>
/// <param name="index">The index of the element to erase in the JSON array.</param>
_ASYNCRTIMP
void
erase
(
size_t
index
);
/// <summary>
/// Erases an element of a JSON object. Throws if the key doesn't exist.
/// </summary>
/// <param name="key">The key of the element to erase in the JSON object.</param>
_ASYNCRTIMP
void
erase
(
const
utility
::
string_t
&
key
);
/// <summary>
/// Accesses an element of a JSON array. Throws when index out of bounds.
/// </summary>
/// <param name="index">The index of an element in the JSON array.</param>
/// <returns>A reference to the value.</returns>
_ASYNCRTIMP
json
::
value
&
at
(
size_t
index
);
/// <summary>
/// Accesses an element of a JSON array. Throws when index out of bounds.
/// </summary>
/// <param name="index">The index of an element in the JSON array.</param>
/// <returns>A reference to the value.</returns>
_ASYNCRTIMP
const
json
::
value
&
at
(
size_t
index
)
const
;
/// <summary>
/// Accesses an element of a JSON object. If the key doesn't exist, this method throws.
/// </summary>
/// <param name="key">The key of an element in the JSON object.</param>
/// <returns>If the key exists, a reference to the value.</returns>
_ASYNCRTIMP
json
::
value
&
at
(
const
utility
::
string_t
&
key
);
/// <summary>
/// Accesses an element of a JSON object. If the key doesn't exist, this method throws.
/// </summary>
/// <param name="key">The key of an element in the JSON object.</param>
/// <returns>If the key exists, a reference to the value.</returns>
_ASYNCRTIMP
const
json
::
value
&
at
(
const
utility
::
string_t
&
key
)
const
;
/// <summary>
/// Accesses a field of a JSON object.
/// </summary>
/// <param name="key">The name of the field</param>
/// <returns>A reference to the value kept in the field.</returns>
_ASYNCRTIMP
value
&
operator
[](
const
utility
::
string_t
&
key
);
#ifdef _WIN32
private:
// Only used internally by JSON parser
_ASYNCRTIMP
value
&
operator
[](
const
std
::
string
&
key
)
{
// JSON object stores its field map as a unordered_map of string_t, so this conversion is hard to avoid
return
operator
[](
utility
::
conversions
::
to_string_t
(
key
));
}
public:
#endif
/// <summary>
/// Accesses an element of a JSON array.
/// </summary>
/// <param name="index">The index of an element in the JSON array</param>
/// <returns>The value kept at the array index; null if outside the boundaries of the array</returns>
CASABLANCA_DEPRECATED
(
"This API is deprecated and will be removed in a future release, use json::value::at() instead."
)
value
get
(
size_t
index
)
const
;
/// <summary>
/// Accesses an element of a JSON array.
/// </summary>
/// <param name="index">The index of an element in the JSON array.</param>
/// <returns>A reference to the value kept in the field.</returns>
_ASYNCRTIMP
value
&
operator
[](
size_t
index
);
private:
friend
class
web
::
json
::
details
::
_Object
;
friend
class
web
::
json
::
details
::
_Array
;
template
<
typename
CharType
>
friend
class
web
::
json
::
details
::
JSON_Parser
;
#ifdef _WIN32
/// <summary>
/// Writes the current JSON value as a double-byte string to a string instance.
/// </summary>
/// <param name="string">The string that the JSON representation should be written to.</param>
_ASYNCRTIMP
void
format
(
std
::
basic_string
<
utf16char
>&
string
)
const
;
#endif
/// <summary>
/// Serializes the content of the value into a string instance in UTF8 format
/// </summary>
/// <param name="string">The string that the JSON representation should be written to</param>
_ASYNCRTIMP
void
format
(
std
::
basic_string
<
char
>&
string
)
const
;
#ifdef ENABLE_JSON_VALUE_VISUALIZER
explicit
value
(
std
::
unique_ptr
<
details
::
_Value
>
v
,
value_type
kind
)
:
m_value
(
std
::
move
(
v
)),
m_kind
(
kind
)
#else
explicit
value
(
std
::
unique_ptr
<
details
::
_Value
>
v
)
:
m_value
(
std
::
move
(
v
))
#endif
{
}
std
::
unique_ptr
<
details
::
_Value
>
m_value
;
#ifdef ENABLE_JSON_VALUE_VISUALIZER
value_type
m_kind
;
#endif
};
/// <summary>
/// A single exception type to represent errors in parsing, converting, and accessing
/// elements of JSON values.
/// </summary>
class
json_exception
:
public
std
::
exception
{
private:
std
::
string
_message
;
public:
json_exception
(
const
char
*
const
message
)
:
_message
(
message
)
{}
#ifdef _UTF16_STRINGS
json_exception
(
const
wchar_t
*
const
message
)
:
_message
(
utility
::
conversions
::
utf16_to_utf8
(
message
))
{}
#endif // _UTF16_STRINGS
json_exception
(
std
::
string
&&
message
)
:
_message
(
std
::
move
(
message
))
{}
// Must be narrow string because it derives from std::exception
const
char
*
what
()
const
CPPREST_NOEXCEPT
{
return
_message
.
c_str
();
}
};
namespace
details
{
enum
json_error
{
left_over_character_in_stream
=
1
,
malformed_array_literal
,
malformed_comment
,
malformed_literal
,
malformed_object_literal
,
malformed_numeric_literal
,
malformed_string_literal
,
malformed_token
,
mismatched_brances
,
nesting
,
unexpected_token
};
class
json_error_category_impl
:
public
std
::
error_category
{
public:
virtual
const
char
*
name
()
const
CPPREST_NOEXCEPT
override
{
return
"json"
;
}
virtual
std
::
string
message
(
int
ev
)
const
override
{
switch
(
ev
)
{
case
json_error
::
left_over_character_in_stream
:
return
"Left-over characters in stream after parsing a JSON value"
;
case
json_error
::
malformed_array_literal
:
return
"Malformed array literal"
;
case
json_error
::
malformed_comment
:
return
"Malformed comment"
;
case
json_error
::
malformed_literal
:
return
"Malformed literal"
;
case
json_error
::
malformed_object_literal
:
return
"Malformed object literal"
;
case
json_error
::
malformed_numeric_literal
:
return
"Malformed numeric literal"
;
case
json_error
::
malformed_string_literal
:
return
"Malformed string literal"
;
case
json_error
::
malformed_token
:
return
"Malformed token"
;
case
json_error
::
mismatched_brances
:
return
"Mismatched braces"
;
case
json_error
::
nesting
:
return
"Nesting too deep"
;
case
json_error
::
unexpected_token
:
return
"Unexpected token"
;
default:
return
"Unknown json error"
;
}
}
};
const
json_error_category_impl
&
json_error_category
();
}
// namespace details
/// <summary>
/// A JSON array represented as a C++ class.
/// </summary>
class
array
{
typedef
std
::
vector
<
json
::
value
>
storage_type
;
public:
typedef
storage_type
::
iterator
iterator
;
typedef
storage_type
::
const_iterator
const_iterator
;
typedef
storage_type
::
reverse_iterator
reverse_iterator
;
typedef
storage_type
::
const_reverse_iterator
const_reverse_iterator
;
typedef
storage_type
::
size_type
size_type
;
private:
array
()
:
m_elements
()
{}
array
(
size_type
size
)
:
m_elements
(
size
)
{}
array
(
storage_type
elements
)
:
m_elements
(
std
::
move
(
elements
))
{}
public:
/// <summary>
/// Gets the beginning iterator element of the array
/// </summary>
/// <returns>An <c>iterator</c> to the beginning of the JSON array.</returns>
iterator
begin
()
{
return
m_elements
.
begin
();
}
/// <summary>
/// Gets the beginning const iterator element of the array.
/// </summary>
/// <returns>A <c>const_iterator</c> to the beginning of the JSON array.</returns>
const_iterator
begin
()
const
{
return
m_elements
.
cbegin
();
}
/// <summary>
/// Gets the end iterator element of the array
/// </summary>
/// <returns>An <c>iterator</c> to the end of the JSON array.</returns>
iterator
end
()
{
return
m_elements
.
end
();
}
/// <summary>
/// Gets the end const iterator element of the array.
/// </summary>
/// <returns>A <c>const_iterator</c> to the end of the JSON array.</returns>
const_iterator
end
()
const
{
return
m_elements
.
cend
();
}
/// <summary>
/// Gets the beginning reverse iterator element of the array
/// </summary>
/// <returns>An <c>reverse_iterator</c> to the beginning of the JSON array.</returns>
reverse_iterator
rbegin
()
{
return
m_elements
.
rbegin
();
}
/// <summary>
/// Gets the beginning const reverse iterator element of the array
/// </summary>
/// <returns>An <c>const_reverse_iterator</c> to the beginning of the JSON array.</returns>
const_reverse_iterator
rbegin
()
const
{
return
m_elements
.
rbegin
();
}
/// <summary>
/// Gets the end reverse iterator element of the array
/// </summary>
/// <returns>An <c>reverse_iterator</c> to the end of the JSON array.</returns>
reverse_iterator
rend
()
{
return
m_elements
.
rend
();
}
/// <summary>
/// Gets the end const reverse iterator element of the array
/// </summary>
/// <returns>An <c>const_reverse_iterator</c> to the end of the JSON array.</returns>
const_reverse_iterator
rend
()
const
{
return
m_elements
.
crend
();
}
/// <summary>
/// Gets the beginning const iterator element of the array.
/// </summary>
/// <returns>A <c>const_iterator</c> to the beginning of the JSON array.</returns>
const_iterator
cbegin
()
const
{
return
m_elements
.
cbegin
();
}
/// <summary>
/// Gets the end const iterator element of the array.
/// </summary>
/// <returns>A <c>const_iterator</c> to the end of the JSON array.</returns>
const_iterator
cend
()
const
{
return
m_elements
.
cend
();
}
/// <summary>
/// Gets the beginning const reverse iterator element of the array.
/// </summary>
/// <returns>A <c>const_reverse_iterator</c> to the beginning of the JSON array.</returns>
const_reverse_iterator
crbegin
()
const
{
return
m_elements
.
crbegin
();
}
/// <summary>
/// Gets the end const reverse iterator element of the array.
/// </summary>
/// <returns>A <c>const_reverse_iterator</c> to the end of the JSON array.</returns>
const_reverse_iterator
crend
()
const
{
return
m_elements
.
crend
();
}
/// <summary>
/// Deletes an element of the JSON array.
/// </summary>
/// <param name="position">A const_iterator to the element to delete.</param>
/// <returns>Iterator to the new location of the element following the erased element.</returns>
/// <remarks>GCC doesn't support erase with const_iterator on vector yet. In the future this should be
/// changed.</remarks>
iterator
erase
(
iterator
position
)
{
return
m_elements
.
erase
(
position
);
}
/// <summary>
/// Deletes the element at an index of the JSON array.
/// </summary>
/// <param name="index">The index of the element to delete.</param>
void
erase
(
size_type
index
)
{
if
(
index
>=
m_elements
.
size
())
{
throw
json_exception
(
"index out of bounds"
);
}
m_elements
.
erase
(
m_elements
.
begin
()
+
index
);
}
/// <summary>
/// Accesses an element of a JSON array. Throws when index out of bounds.
/// </summary>
/// <param name="index">The index of an element in the JSON array.</param>
/// <returns>A reference to the value kept in the field.</returns>
json
::
value
&
at
(
size_type
index
)
{
if
(
index
>=
m_elements
.
size
())
throw
json_exception
(
"index out of bounds"
);
return
m_elements
[
index
];
}
/// <summary>
/// Accesses an element of a JSON array. Throws when index out of bounds.
/// </summary>
/// <param name="index">The index of an element in the JSON array.</param>
/// <returns>A reference to the value kept in the field.</returns>
const
json
::
value
&
at
(
size_type
index
)
const
{
if
(
index
>=
m_elements
.
size
())
throw
json_exception
(
"index out of bounds"
);
return
m_elements
[
index
];
}
/// <summary>
/// Accesses an element of a JSON array.
/// </summary>
/// <param name="index">The index of an element in the JSON array.</param>
/// <returns>A reference to the value kept in the field.</returns>
json
::
value
&
operator
[](
size_type
index
)
{
msl
::
safeint3
::
SafeInt
<
size_type
>
nMinSize
(
index
);
nMinSize
+=
1
;
msl
::
safeint3
::
SafeInt
<
size_type
>
nlastSize
(
m_elements
.
size
());
if
(
nlastSize
<
nMinSize
)
m_elements
.
resize
(
nMinSize
);
return
m_elements
[
index
];
}
/// <summary>
/// Gets the number of elements of the array.
/// </summary>
/// <returns>The number of elements.</returns>
size_type
size
()
const
{
return
m_elements
.
size
();
}
private:
storage_type
m_elements
;
friend
class
details
::
_Array
;
template
<
typename
CharType
>
friend
class
json
::
details
::
JSON_Parser
;
};
/// <summary>
/// A JSON object represented as a C++ class.
/// </summary>
class
object
{
typedef
std
::
vector
<
std
::
pair
<
utility
::
string_t
,
json
::
value
>>
storage_type
;
public:
typedef
storage_type
::
iterator
iterator
;
typedef
storage_type
::
const_iterator
const_iterator
;
typedef
storage_type
::
reverse_iterator
reverse_iterator
;
typedef
storage_type
::
const_reverse_iterator
const_reverse_iterator
;
typedef
storage_type
::
size_type
size_type
;
private:
object
(
bool
keep_order
=
false
)
:
m_elements
(),
m_keep_order
(
keep_order
)
{}
object
(
storage_type
elements
,
bool
keep_order
=
false
)
:
m_elements
(
std
::
move
(
elements
)),
m_keep_order
(
keep_order
)
{
if
(
!
keep_order
)
{
sort
(
m_elements
.
begin
(),
m_elements
.
end
(),
compare_pairs
);
}
}
public:
/// <summary>
/// Gets the beginning iterator element of the object
/// </summary>
/// <returns>An <c>iterator</c> to the beginning of the JSON object.</returns>
iterator
begin
()
{
return
m_elements
.
begin
();
}
/// <summary>
/// Gets the beginning const iterator element of the object.
/// </summary>
/// <returns>A <c>const_iterator</c> to the beginning of the JSON object.</returns>
const_iterator
begin
()
const
{
return
m_elements
.
cbegin
();
}
/// <summary>
/// Gets the end iterator element of the object
/// </summary>
/// <returns>An <c>iterator</c> to the end of the JSON object.</returns>
iterator
end
()
{
return
m_elements
.
end
();
}
/// <summary>
/// Gets the end const iterator element of the object.
/// </summary>
/// <returns>A <c>const_iterator</c> to the end of the JSON object.</returns>
const_iterator
end
()
const
{
return
m_elements
.
cend
();
}
/// <summary>
/// Gets the beginning reverse iterator element of the object
/// </summary>
/// <returns>An <c>reverse_iterator</c> to the beginning of the JSON object.</returns>
reverse_iterator
rbegin
()
{
return
m_elements
.
rbegin
();
}
/// <summary>
/// Gets the beginning const reverse iterator element of the object
/// </summary>
/// <returns>An <c>const_reverse_iterator</c> to the beginning of the JSON object.</returns>
const_reverse_iterator
rbegin
()
const
{
return
m_elements
.
rbegin
();
}
/// <summary>
/// Gets the end reverse iterator element of the object
/// </summary>
/// <returns>An <c>reverse_iterator</c> to the end of the JSON object.</returns>
reverse_iterator
rend
()
{
return
m_elements
.
rend
();
}
/// <summary>
/// Gets the end const reverse iterator element of the object
/// </summary>
/// <returns>An <c>const_reverse_iterator</c> to the end of the JSON object.</returns>
const_reverse_iterator
rend
()
const
{
return
m_elements
.
crend
();
}
/// <summary>
/// Gets the beginning const iterator element of the object.
/// </summary>
/// <returns>A <c>const_iterator</c> to the beginning of the JSON object.</returns>
const_iterator
cbegin
()
const
{
return
m_elements
.
cbegin
();
}
/// <summary>
/// Gets the end const iterator element of the object.
/// </summary>
/// <returns>A <c>const_iterator</c> to the end of the JSON object.</returns>
const_iterator
cend
()
const
{
return
m_elements
.
cend
();
}
/// <summary>
/// Gets the beginning const reverse iterator element of the object.
/// </summary>
/// <returns>A <c>const_reverse_iterator</c> to the beginning of the JSON object.</returns>
const_reverse_iterator
crbegin
()
const
{
return
m_elements
.
crbegin
();
}
/// <summary>
/// Gets the end const reverse iterator element of the object.
/// </summary>
/// <returns>A <c>const_reverse_iterator</c> to the end of the JSON object.</returns>
const_reverse_iterator
crend
()
const
{
return
m_elements
.
crend
();
}
/// <summary>
/// Deletes an element of the JSON object.
/// </summary>
/// <param name="position">A const_iterator to the element to delete.</param>
/// <returns>Iterator to the new location of the element following the erased element.</returns>
/// <remarks>GCC doesn't support erase with const_iterator on vector yet. In the future this should be
/// changed.</remarks>
iterator
erase
(
iterator
position
)
{
return
m_elements
.
erase
(
position
);
}
/// <summary>
/// Deletes an element of the JSON object. If the key doesn't exist, this method throws.
/// </summary>
/// <param name="key">The key of an element in the JSON object.</param>
void
erase
(
const
utility
::
string_t
&
key
)
{
auto
iter
=
find_by_key
(
key
);
if
(
iter
==
m_elements
.
end
())
{
throw
web
::
json
::
json_exception
(
"Key not found"
);
}
m_elements
.
erase
(
iter
);
}
/// <summary>
/// Accesses an element of a JSON object. If the key doesn't exist, this method throws.
/// </summary>
/// <param name="key">The key of an element in the JSON object.</param>
/// <returns>If the key exists, a reference to the value kept in the field.</returns>
json
::
value
&
at
(
const
utility
::
string_t
&
key
)
{
auto
iter
=
find_by_key
(
key
);
if
(
iter
==
m_elements
.
end
())
{
throw
web
::
json
::
json_exception
(
"Key not found"
);
}
return
iter
->
second
;
}
/// <summary>
/// Accesses an element of a JSON object. If the key doesn't exist, this method throws.
/// </summary>
/// <param name="key">The key of an element in the JSON object.</param>
/// <returns>If the key exists, a reference to the value kept in the field.</returns>
const
json
::
value
&
at
(
const
utility
::
string_t
&
key
)
const
{
auto
iter
=
find_by_key
(
key
);
if
(
iter
==
m_elements
.
end
())
{
throw
web
::
json
::
json_exception
(
"Key not found"
);
}
return
iter
->
second
;
}
/// <summary>
/// Accesses an element of a JSON object.
/// </summary>
/// <param name="key">The key of an element in the JSON object.</param>
/// <returns>If the key exists, a reference to the value kept in the field, otherwise a newly created null value
/// that will be stored for the given key.</returns>
json
::
value
&
operator
[](
const
utility
::
string_t
&
key
)
{
auto
iter
=
find_insert_location
(
key
);
if
(
iter
==
m_elements
.
end
()
||
key
!=
iter
->
first
)
{
return
m_elements
.
insert
(
iter
,
std
::
pair
<
utility
::
string_t
,
value
>
(
key
,
value
()))
->
second
;
}
return
iter
->
second
;
}
/// <summary>
/// Gets an iterator to an element of a JSON object.
/// </summary>
/// <param name="key">The key of an element in the JSON object.</param>
/// <returns>A const iterator to the value kept in the field.</returns>
const_iterator
find
(
const
utility
::
string_t
&
key
)
const
{
return
find_by_key
(
key
);
}
/// <summary>
/// Gets the number of elements of the object.
/// </summary>
/// <returns>The number of elements.</returns>
size_type
size
()
const
{
return
m_elements
.
size
();
}
/// <summary>
/// Checks if there are any elements in the JSON object.
/// </summary>
/// <returns>True if empty.</returns>
bool
empty
()
const
{
return
m_elements
.
empty
();
}
private:
static
bool
compare_pairs
(
const
std
::
pair
<
utility
::
string_t
,
value
>&
p1
,
const
std
::
pair
<
utility
::
string_t
,
value
>&
p2
)
{
return
p1
.
first
<
p2
.
first
;
}
static
bool
compare_with_key
(
const
std
::
pair
<
utility
::
string_t
,
value
>&
p1
,
const
utility
::
string_t
&
key
)
{
return
p1
.
first
<
key
;
}
storage_type
::
iterator
find_insert_location
(
const
utility
::
string_t
&
key
)
{
if
(
m_keep_order
)
{
return
std
::
find_if
(
m_elements
.
begin
(),
m_elements
.
end
(),
[
&
key
](
const
std
::
pair
<
utility
::
string_t
,
value
>&
p
)
{
return
p
.
first
==
key
;
});
}
else
{
return
std
::
lower_bound
(
m_elements
.
begin
(),
m_elements
.
end
(),
key
,
compare_with_key
);
}
}
storage_type
::
const_iterator
find_by_key
(
const
utility
::
string_t
&
key
)
const
{
if
(
m_keep_order
)
{
return
std
::
find_if
(
m_elements
.
begin
(),
m_elements
.
end
(),
[
&
key
](
const
std
::
pair
<
utility
::
string_t
,
value
>&
p
)
{
return
p
.
first
==
key
;
});
}
else
{
auto
iter
=
std
::
lower_bound
(
m_elements
.
begin
(),
m_elements
.
end
(),
key
,
compare_with_key
);
if
(
iter
!=
m_elements
.
end
()
&&
key
!=
iter
->
first
)
{
return
m_elements
.
end
();
}
return
iter
;
}
}
storage_type
::
iterator
find_by_key
(
const
utility
::
string_t
&
key
)
{
auto
iter
=
find_insert_location
(
key
);
if
(
iter
!=
m_elements
.
end
()
&&
key
!=
iter
->
first
)
{
return
m_elements
.
end
();
}
return
iter
;
}
storage_type
m_elements
;
bool
m_keep_order
;
friend
class
details
::
_Object
;
template
<
typename
CharType
>
friend
class
json
::
details
::
JSON_Parser
;
};
/// <summary>
/// A JSON number represented as a C++ class.
/// </summary>
class
number
{
// Note that these constructors make sure that only negative integers are stored as signed int64 (while others
// convert to unsigned int64). This helps handling number objects e.g. comparing two numbers.
number
(
double
value
)
:
m_value
(
value
),
m_type
(
double_type
)
{}
number
(
int32_t
value
)
:
m_intval
(
value
),
m_type
(
value
<
0
?
signed_type
:
unsigned_type
)
{}
number
(
uint32_t
value
)
:
m_intval
(
value
),
m_type
(
unsigned_type
)
{}
number
(
int64_t
value
)
:
m_intval
(
value
),
m_type
(
value
<
0
?
signed_type
:
unsigned_type
)
{}
number
(
uint64_t
value
)
:
m_uintval
(
value
),
m_type
(
unsigned_type
)
{}
public:
/// <summary>
/// Does the number fit into int32?
/// </summary>
/// <returns><c>true</c> if the number fits into int32, <c>false</c> otherwise</returns>
_ASYNCRTIMP
bool
is_int32
()
const
;
/// <summary>
/// Does the number fit into unsigned int32?
/// </summary>
/// <returns><c>true</c> if the number fits into unsigned int32, <c>false</c> otherwise</returns>
_ASYNCRTIMP
bool
is_uint32
()
const
;
/// <summary>
/// Does the number fit into int64?
/// </summary>
/// <returns><c>true</c> if the number fits into int64, <c>false</c> otherwise</returns>
_ASYNCRTIMP
bool
is_int64
()
const
;
/// <summary>
/// Does the number fit into unsigned int64?
/// </summary>
/// <returns><c>true</c> if the number fits into unsigned int64, <c>false</c> otherwise</returns>
bool
is_uint64
()
const
{
switch
(
m_type
)
{
case
signed_type
:
return
m_intval
>=
0
;
case
unsigned_type
:
return
true
;
case
double_type
:
default:
return
false
;
}
}
/// <summary>
/// Converts the JSON number to a C++ double.
/// </summary>
/// <returns>A double representation of the number</returns>
double
to_double
()
const
{
switch
(
m_type
)
{
case
double_type
:
return
m_value
;
case
signed_type
:
return
static_cast
<
double
>
(
m_intval
);
case
unsigned_type
:
return
static_cast
<
double
>
(
m_uintval
);
default:
return
false
;
}
}
/// <summary>
/// Converts the JSON number to int32.
/// </summary>
/// <returns>An int32 representation of the number</returns>
int32_t
to_int32
()
const
{
if
(
m_type
==
double_type
)
return
static_cast
<
int32_t
>
(
m_value
);
else
return
static_cast
<
int32_t
>
(
m_intval
);
}
/// <summary>
/// Converts the JSON number to unsigned int32.
/// </summary>
/// <returns>An unsigned int32 representation of the number</returns>
uint32_t
to_uint32
()
const
{
if
(
m_type
==
double_type
)
return
static_cast
<
uint32_t
>
(
m_value
);
else
return
static_cast
<
uint32_t
>
(
m_intval
);
}
/// <summary>
/// Converts the JSON number to int64.
/// </summary>
/// <returns>An int64 representation of the number</returns>
int64_t
to_int64
()
const
{
if
(
m_type
==
double_type
)
return
static_cast
<
int64_t
>
(
m_value
);
else
return
static_cast
<
int64_t
>
(
m_intval
);
}
/// <summary>
/// Converts the JSON number to unsigned int64.
/// </summary>
/// <returns>An unsigned int64 representation of the number</returns>
uint64_t
to_uint64
()
const
{
if
(
m_type
==
double_type
)
return
static_cast
<
uint64_t
>
(
m_value
);
else
return
static_cast
<
uint64_t
>
(
m_intval
);
}
/// <summary>
/// Is the number represented internally as an integral type?
/// </summary>
/// <returns><c>true</c> if the number is represented as an integral type, <c>false</c> otherwise</returns>
bool
is_integral
()
const
{
return
m_type
!=
double_type
;
}
/// <summary>
/// Compares two JSON numbers for equality.
/// </summary>
/// <param name="other">The JSON number to compare with.</param>
/// <returns>True if the numbers are equal.</returns>
bool
operator
==
(
const
number
&
other
)
const
{
if
(
m_type
!=
other
.
m_type
)
return
false
;
switch
(
m_type
)
{
case
json
::
number
::
type
::
signed_type
:
return
m_intval
==
other
.
m_intval
;
case
json
::
number
::
type
::
unsigned_type
:
return
m_uintval
==
other
.
m_uintval
;
case
json
::
number
::
type
::
double_type
:
return
m_value
==
other
.
m_value
;
}
__assume
(
0
);
// Absence of this return statement provokes a warning from Intel
// compiler, but its presence results in a warning from MSVC, so
// we have to resort to conditional compilation to keep both happy.
#ifdef __INTEL_COMPILER
return
false
;
#endif
}
private:
union
{
int64_t
m_intval
;
uint64_t
m_uintval
;
double
m_value
;
};
enum
type
{
signed_type
=
0
,
unsigned_type
,
double_type
}
m_type
;
friend
class
details
::
_Number
;
};
namespace
details
{
class
_Value
{
public:
virtual
std
::
unique_ptr
<
_Value
>
_copy_value
()
=
0
;
virtual
bool
has_field
(
const
utility
::
string_t
&
)
const
{
return
false
;
}
virtual
value
get_field
(
const
utility
::
string_t
&
)
const
{
throw
json_exception
(
"not an object"
);
}
virtual
value
get_element
(
array
::
size_type
)
const
{
throw
json_exception
(
"not an array"
);
}
virtual
value
&
index
(
const
utility
::
string_t
&
)
{
throw
json_exception
(
"not an object"
);
}
virtual
value
&
index
(
array
::
size_type
)
{
throw
json_exception
(
"not an array"
);
}
virtual
const
value
&
cnst_index
(
const
utility
::
string_t
&
)
const
{
throw
json_exception
(
"not an object"
);
}
virtual
const
value
&
cnst_index
(
array
::
size_type
)
const
{
throw
json_exception
(
"not an array"
);
}
// Common function used for serialization to strings and streams.
virtual
void
serialize_impl
(
std
::
string
&
str
)
const
{
format
(
str
);
}
#ifdef _WIN32
virtual
void
serialize_impl
(
std
::
wstring
&
str
)
const
{
format
(
str
);
}
#endif
virtual
utility
::
string_t
to_string
()
const
{
utility
::
string_t
str
;
serialize_impl
(
str
);
return
str
;
}
virtual
json
::
value
::
value_type
type
()
const
{
return
json
::
value
::
Null
;
}
virtual
bool
is_integer
()
const
{
throw
json_exception
(
"not a number"
);
}
virtual
bool
is_double
()
const
{
throw
json_exception
(
"not a number"
);
}
virtual
const
json
::
number
&
as_number
()
{
throw
json_exception
(
"not a number"
);
}
virtual
double
as_double
()
const
{
throw
json_exception
(
"not a number"
);
}
virtual
int
as_integer
()
const
{
throw
json_exception
(
"not a number"
);
}
virtual
bool
as_bool
()
const
{
throw
json_exception
(
"not a boolean"
);
}
virtual
json
::
array
&
as_array
()
{
throw
json_exception
(
"not an array"
);
}
virtual
const
json
::
array
&
as_array
()
const
{
throw
json_exception
(
"not an array"
);
}
virtual
json
::
object
&
as_object
()
{
throw
json_exception
(
"not an object"
);
}
virtual
const
json
::
object
&
as_object
()
const
{
throw
json_exception
(
"not an object"
);
}
virtual
const
utility
::
string_t
&
as_string
()
const
{
throw
json_exception
(
"not a string"
);
}
virtual
size_t
size
()
const
{
return
0
;
}
virtual
~
_Value
()
{}
protected:
_Value
()
{}
virtual
void
format
(
std
::
basic_string
<
char
>&
stream
)
const
{
stream
.
append
(
"null"
);
}
#ifdef _WIN32
virtual
void
format
(
std
::
basic_string
<
wchar_t
>&
stream
)
const
{
stream
.
append
(
L"null"
);
}
#endif
private:
friend
class
web
::
json
::
value
;
};
class
_Null
:
public
_Value
{
public:
virtual
std
::
unique_ptr
<
_Value
>
_copy_value
()
{
return
utility
::
details
::
make_unique
<
_Null
>
();
}
virtual
json
::
value
::
value_type
type
()
const
{
return
json
::
value
::
Null
;
}
};
class
_Number
:
public
_Value
{
public:
_Number
(
double
value
)
:
m_number
(
value
)
{}
_Number
(
int32_t
value
)
:
m_number
(
value
)
{}
_Number
(
uint32_t
value
)
:
m_number
(
value
)
{}
_Number
(
int64_t
value
)
:
m_number
(
value
)
{}
_Number
(
uint64_t
value
)
:
m_number
(
value
)
{}
virtual
std
::
unique_ptr
<
_Value
>
_copy_value
()
{
return
utility
::
details
::
make_unique
<
_Number
>
(
*
this
);
}
virtual
json
::
value
::
value_type
type
()
const
{
return
json
::
value
::
Number
;
}
virtual
bool
is_integer
()
const
{
return
m_number
.
is_integral
();
}
virtual
bool
is_double
()
const
{
return
!
m_number
.
is_integral
();
}
virtual
double
as_double
()
const
{
return
m_number
.
to_double
();
}
virtual
int
as_integer
()
const
{
return
m_number
.
to_int32
();
}
virtual
const
number
&
as_number
()
{
return
m_number
;
}
protected:
virtual
void
format
(
std
::
basic_string
<
char
>&
stream
)
const
;
#ifdef _WIN32
virtual
void
format
(
std
::
basic_string
<
wchar_t
>&
stream
)
const
;
#endif
private:
template
<
typename
CharType
>
friend
class
json
::
details
::
JSON_Parser
;
json
::
number
m_number
;
};
class
_Boolean
:
public
_Value
{
public:
_Boolean
(
bool
value
)
:
m_value
(
value
)
{}
virtual
std
::
unique_ptr
<
_Value
>
_copy_value
()
{
return
utility
::
details
::
make_unique
<
_Boolean
>
(
*
this
);
}
virtual
json
::
value
::
value_type
type
()
const
{
return
json
::
value
::
Boolean
;
}
virtual
bool
as_bool
()
const
{
return
m_value
;
}
protected:
virtual
void
format
(
std
::
basic_string
<
char
>&
stream
)
const
{
stream
.
append
(
m_value
?
"true"
:
"false"
);
}
#ifdef _WIN32
virtual
void
format
(
std
::
basic_string
<
wchar_t
>&
stream
)
const
{
stream
.
append
(
m_value
?
L"true"
:
L"false"
);
}
#endif
private:
template
<
typename
CharType
>
friend
class
json
::
details
::
JSON_Parser
;
bool
m_value
;
};
class
_String
:
public
_Value
{
public:
_String
(
utility
::
string_t
value
)
:
m_string
(
std
::
move
(
value
))
{
m_has_escape_char
=
has_escape_chars
(
*
this
);
}
_String
(
utility
::
string_t
value
,
bool
escaped_chars
)
:
m_string
(
std
::
move
(
value
)),
m_has_escape_char
(
escaped_chars
)
{
}
#ifdef _WIN32
_String
(
std
::
string
&&
value
)
:
m_string
(
utility
::
conversions
::
to_utf16string
(
std
::
move
(
value
)))
{
m_has_escape_char
=
has_escape_chars
(
*
this
);
}
_String
(
std
::
string
&&
value
,
bool
escape_chars
)
:
m_string
(
utility
::
conversions
::
to_utf16string
(
std
::
move
(
value
))),
m_has_escape_char
(
escape_chars
)
{
}
#endif
virtual
std
::
unique_ptr
<
_Value
>
_copy_value
()
{
return
utility
::
details
::
make_unique
<
_String
>
(
*
this
);
}
virtual
json
::
value
::
value_type
type
()
const
{
return
json
::
value
::
String
;
}
virtual
const
utility
::
string_t
&
as_string
()
const
;
virtual
void
serialize_impl
(
std
::
string
&
str
)
const
{
serialize_impl_char_type
(
str
);
}
#ifdef _WIN32
virtual
void
serialize_impl
(
std
::
wstring
&
str
)
const
{
serialize_impl_char_type
(
str
);
}
#endif
protected:
virtual
void
format
(
std
::
basic_string
<
char
>&
str
)
const
;
#ifdef _WIN32
virtual
void
format
(
std
::
basic_string
<
wchar_t
>&
str
)
const
;
#endif
private:
friend
class
_Object
;
friend
class
_Array
;
size_t
get_reserve_size
()
const
{
return
m_string
.
size
()
+
2
;
}
template
<
typename
CharType
>
void
serialize_impl_char_type
(
std
::
basic_string
<
CharType
>&
str
)
const
{
// To avoid repeated allocations reserve some space all up front.
// size of string + 2 for quotes
str
.
reserve
(
get_reserve_size
());
format
(
str
);
}
std
::
string
as_utf8_string
()
const
;
utf16string
as_utf16_string
()
const
;
utility
::
string_t
m_string
;
// There are significant performance gains that can be made by knowing whether
// or not a character that requires escaping is present.
bool
m_has_escape_char
;
static
bool
has_escape_chars
(
const
_String
&
str
);
};
template
<
typename
CharType
>
_ASYNCRTIMP
void
append_escape_string
(
std
::
basic_string
<
CharType
>&
str
,
const
std
::
basic_string
<
CharType
>&
escaped
);
void
format_string
(
const
utility
::
string_t
&
key
,
utility
::
string_t
&
str
);
#ifdef _WIN32
void
format_string
(
const
utility
::
string_t
&
key
,
std
::
string
&
str
);
#endif
class
_Object
:
public
_Value
{
public:
_Object
(
bool
keep_order
)
:
m_object
(
keep_order
)
{}
_Object
(
object
::
storage_type
fields
,
bool
keep_order
)
:
m_object
(
std
::
move
(
fields
),
keep_order
)
{}
virtual
std
::
unique_ptr
<
_Value
>
_copy_value
()
{
return
utility
::
details
::
make_unique
<
_Object
>
(
*
this
);
}
virtual
json
::
object
&
as_object
()
{
return
m_object
;
}
virtual
const
json
::
object
&
as_object
()
const
{
return
m_object
;
}
virtual
json
::
value
::
value_type
type
()
const
{
return
json
::
value
::
Object
;
}
virtual
bool
has_field
(
const
utility
::
string_t
&
)
const
;
virtual
json
::
value
&
index
(
const
utility
::
string_t
&
key
);
bool
is_equal
(
const
_Object
*
other
)
const
{
if
(
m_object
.
size
()
!=
other
->
m_object
.
size
())
return
false
;
return
std
::
equal
(
std
::
begin
(
m_object
),
std
::
end
(
m_object
),
std
::
begin
(
other
->
m_object
));
}
virtual
void
serialize_impl
(
std
::
string
&
str
)
const
{
// To avoid repeated allocations reserve some space all up front.
str
.
reserve
(
get_reserve_size
());
format
(
str
);
}
#ifdef _WIN32
virtual
void
serialize_impl
(
std
::
wstring
&
str
)
const
{
// To avoid repeated allocations reserve some space all up front.
str
.
reserve
(
get_reserve_size
());
format
(
str
);
}
#endif
size_t
size
()
const
{
return
m_object
.
size
();
}
protected:
virtual
void
format
(
std
::
basic_string
<
char
>&
str
)
const
{
format_impl
(
str
);
}
#ifdef _WIN32
virtual
void
format
(
std
::
basic_string
<
wchar_t
>&
str
)
const
{
format_impl
(
str
);
}
#endif
private:
json
::
object
m_object
;
template
<
typename
CharType
>
friend
class
json
::
details
::
JSON_Parser
;
template
<
typename
CharType
>
void
format_impl
(
std
::
basic_string
<
CharType
>&
str
)
const
{
str
.
push_back
(
'{'
);
if
(
!
m_object
.
empty
())
{
auto
lastElement
=
m_object
.
end
()
-
1
;
for
(
auto
iter
=
m_object
.
begin
();
iter
!=
lastElement
;
++
iter
)
{
format_string
(
iter
->
first
,
str
);
str
.
push_back
(
':'
);
iter
->
second
.
format
(
str
);
str
.
push_back
(
','
);
}
format_string
(
lastElement
->
first
,
str
);
str
.
push_back
(
':'
);
lastElement
->
second
.
format
(
str
);
}
str
.
push_back
(
'}'
);
}
size_t
get_reserve_size
()
const
{
// This is a heuristic we can tune more in the future:
// Basically size of string plus
// sum size of value if an object, array, or string.
size_t
reserveSize
=
2
;
// For brackets {}
for
(
auto
iter
=
m_object
.
begin
();
iter
!=
m_object
.
end
();
++
iter
)
{
reserveSize
+=
iter
->
first
.
length
()
+
2
;
// 2 for quotes
size_t
valueSize
=
iter
->
second
.
size
()
*
20
;
// Multiply by each object/array element
if
(
valueSize
==
0
)
{
if
(
iter
->
second
.
type
()
==
json
::
value
::
String
)
{
valueSize
=
static_cast
<
_String
*>
(
iter
->
second
.
m_value
.
get
())
->
get_reserve_size
();
}
else
{
valueSize
=
5
;
// true, false, or null
}
}
reserveSize
+=
valueSize
;
}
return
reserveSize
;
}
};
class
_Array
:
public
_Value
{
public:
_Array
()
{}
_Array
(
array
::
size_type
size
)
:
m_array
(
size
)
{}
_Array
(
array
::
storage_type
elements
)
:
m_array
(
std
::
move
(
elements
))
{}
virtual
std
::
unique_ptr
<
_Value
>
_copy_value
()
{
return
utility
::
details
::
make_unique
<
_Array
>
(
*
this
);
}
virtual
json
::
value
::
value_type
type
()
const
{
return
json
::
value
::
Array
;
}
virtual
json
::
array
&
as_array
()
{
return
m_array
;
}
virtual
const
json
::
array
&
as_array
()
const
{
return
m_array
;
}
virtual
json
::
value
&
index
(
json
::
array
::
size_type
index
)
{
return
m_array
[
index
];
}
bool
is_equal
(
const
_Array
*
other
)
const
{
if
(
m_array
.
size
()
!=
other
->
m_array
.
size
())
return
false
;
auto
iterT
=
m_array
.
cbegin
();
auto
iterO
=
other
->
m_array
.
cbegin
();
auto
iterTe
=
m_array
.
cend
();
auto
iterOe
=
other
->
m_array
.
cend
();
for
(;
iterT
!=
iterTe
&&
iterO
!=
iterOe
;
++
iterT
,
++
iterO
)
{
if
(
*
iterT
!=
*
iterO
)
return
false
;
}
return
true
;
}
virtual
void
serialize_impl
(
std
::
string
&
str
)
const
{
// To avoid repeated allocations reserve some space all up front.
str
.
reserve
(
get_reserve_size
());
format
(
str
);
}
#ifdef _WIN32
virtual
void
serialize_impl
(
std
::
wstring
&
str
)
const
{
// To avoid repeated allocations reserve some space all up front.
str
.
reserve
(
get_reserve_size
());
format
(
str
);
}
#endif
size_t
size
()
const
{
return
m_array
.
size
();
}
protected:
virtual
void
format
(
std
::
basic_string
<
char
>&
str
)
const
{
format_impl
(
str
);
}
#ifdef _WIN32
virtual
void
format
(
std
::
basic_string
<
wchar_t
>&
str
)
const
{
format_impl
(
str
);
}
#endif
private:
json
::
array
m_array
;
template
<
typename
CharType
>
friend
class
json
::
details
::
JSON_Parser
;
template
<
typename
CharType
>
void
format_impl
(
std
::
basic_string
<
CharType
>&
str
)
const
{
str
.
push_back
(
'['
);
if
(
!
m_array
.
m_elements
.
empty
())
{
auto
lastElement
=
m_array
.
m_elements
.
end
()
-
1
;
for
(
auto
iter
=
m_array
.
m_elements
.
begin
();
iter
!=
lastElement
;
++
iter
)
{
iter
->
format
(
str
);
str
.
push_back
(
','
);
}
lastElement
->
format
(
str
);
}
str
.
push_back
(
']'
);
}
size_t
get_reserve_size
()
const
{
// This is a heuristic we can tune more in the future:
// Basically sum size of each value if an object, array, or string by a multiplier.
size_t
reserveSize
=
2
;
// For brackets []
for
(
auto
iter
=
m_array
.
cbegin
();
iter
!=
m_array
.
cend
();
++
iter
)
{
size_t
valueSize
=
iter
->
size
()
*
20
;
// Per each nested array/object
if
(
valueSize
==
0
)
valueSize
=
5
;
// true, false, or null
reserveSize
+=
valueSize
;
}
return
reserveSize
;
}
};
}
// namespace details
/// <summary>
/// Gets the number of children of the value.
/// </summary>
/// <returns>The number of children. 0 for all non-composites.</returns>
inline
size_t
json
::
value
::
size
()
const
{
return
m_value
->
size
();
}
/// <summary>
/// Test for the presence of a field.
/// </summary>
/// <param name="key">The name of the field</param>
/// <returns>True if the field exists, false otherwise.</returns>
inline
bool
json
::
value
::
has_field
(
const
utility
::
string_t
&
key
)
const
{
return
m_value
->
has_field
(
key
);
}
/// <summary>
/// Access a field of a JSON object.
/// </summary>
/// <param name="key">The name of the field</param>
/// <returns>The value kept in the field; null if the field does not exist</returns>
inline
json
::
value
json
::
value
::
get
(
const
utility
::
string_t
&
key
)
const
{
return
m_value
->
get_field
(
key
);
}
/// <summary>
/// Access an element of a JSON array.
/// </summary>
/// <param name="index">The index of an element in the JSON array</param>
/// <returns>The value kept at the array index; null if outside the boundaries of the array</returns>
inline
json
::
value
json
::
value
::
get
(
size_t
index
)
const
{
return
m_value
->
get_element
(
index
);
}
/// <summary>
/// A standard <c>std::ostream</c> operator to facilitate writing JSON values to streams.
/// </summary>
/// <param name="os">The output stream to write the JSON value to.</param>
/// <param name="val">The JSON value to be written to the stream.</param>
/// <returns>The output stream object</returns>
_ASYNCRTIMP
utility
::
ostream_t
&
__cdecl
operator
<<
(
utility
::
ostream_t
&
os
,
const
json
::
value
&
val
);
/// <summary>
/// A standard <c>std::istream</c> operator to facilitate reading JSON values from streams.
/// </summary>
/// <param name="is">The input stream to read the JSON value from.</param>
/// <param name="val">The JSON value object read from the stream.</param>
/// <returns>The input stream object.</returns>
_ASYNCRTIMP
utility
::
istream_t
&
__cdecl
operator
>>
(
utility
::
istream_t
&
is
,
json
::
value
&
val
);
}
// namespace json
}
// namespace web
#endif
cpprestsdk_static_tester/vcpkg/include/cpprest/oauth1.h
0 → 100644
View file @
14571fd2
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* HTTP Library: Oauth 1.0
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#ifndef CASA_OAUTH1_H
#define CASA_OAUTH1_H
#include
"cpprest/details/web_utilities.h"
#include
"cpprest/http_msg.h"
namespace
web
{
namespace
http
{
namespace
client
{
// Forward declaration to avoid circular include dependency.
class
http_client_config
;
}
// namespace client
/// oAuth 1.0 library.
namespace
oauth1
{
namespace
details
{
class
oauth1_handler
;
// State currently used by oauth1_config to authenticate request.
// The state varies for every request (due to timestamp and nonce).
// The state also contains extra transmitted protocol parameters during
// authorization flow (i.e. 'oauth_callback' or 'oauth_verifier').
class
oauth1_state
{
public:
oauth1_state
(
utility
::
string_t
timestamp
,
utility
::
string_t
nonce
,
utility
::
string_t
extra_key
=
utility
::
string_t
(),
utility
::
string_t
extra_value
=
utility
::
string_t
())
:
m_timestamp
(
std
::
move
(
timestamp
))
,
m_nonce
(
std
::
move
(
nonce
))
,
m_extra_key
(
std
::
move
(
extra_key
))
,
m_extra_value
(
std
::
move
(
extra_value
))
{
}
const
utility
::
string_t
&
timestamp
()
const
{
return
m_timestamp
;
}
void
set_timestamp
(
utility
::
string_t
timestamp
)
{
m_timestamp
=
std
::
move
(
timestamp
);
}
const
utility
::
string_t
&
nonce
()
const
{
return
m_nonce
;
}
void
set_nonce
(
utility
::
string_t
nonce
)
{
m_nonce
=
std
::
move
(
nonce
);
}
const
utility
::
string_t
&
extra_key
()
const
{
return
m_extra_key
;
}
void
set_extra_key
(
utility
::
string_t
key
)
{
m_extra_key
=
std
::
move
(
key
);
}
const
utility
::
string_t
&
extra_value
()
const
{
return
m_extra_value
;
}
void
set_extra_value
(
utility
::
string_t
value
)
{
m_extra_value
=
std
::
move
(
value
);
}
private:
utility
::
string_t
m_timestamp
;
utility
::
string_t
m_nonce
;
utility
::
string_t
m_extra_key
;
utility
::
string_t
m_extra_value
;
};
// Constant strings for OAuth 1.0.
typedef
utility
::
string_t
oauth1_string
;
class
oauth1_strings
{
public:
#define _OAUTH1_STRINGS
#define DAT(a_, b_) _ASYNCRTIMP static const oauth1_string a_;
#include
"cpprest/details/http_constants.dat"
#undef _OAUTH1_STRINGS
#undef DAT
};
}
// namespace details
/// oAuth functionality is currently in beta.
namespace
experimental
{
/// <summary>
/// Constant strings for OAuth 1.0 signature methods.
/// </summary>
typedef
utility
::
string_t
oauth1_method
;
class
oauth1_methods
{
public:
#define _OAUTH1_METHODS
#define DAT(a, b) _ASYNCRTIMP static const oauth1_method a;
#include
"cpprest/details/http_constants.dat"
#undef _OAUTH1_METHODS
#undef DAT
};
/// <summary>
/// Exception type for OAuth 1.0 errors.
/// </summary>
class
oauth1_exception
:
public
std
::
exception
{
public:
oauth1_exception
(
utility
::
string_t
msg
)
:
m_msg
(
utility
::
conversions
::
to_utf8string
(
std
::
move
(
msg
)))
{}
~
oauth1_exception
()
CPPREST_NOEXCEPT
{}
const
char
*
what
()
const
CPPREST_NOEXCEPT
{
return
m_msg
.
c_str
();
}
private:
std
::
string
m_msg
;
};
/// <summary>
/// OAuth 1.0 token and associated information.
/// </summary>
class
oauth1_token
{
public:
/// <summary>
/// Constructs an initially empty invalid access token.
/// </summary>
oauth1_token
()
{}
/// <summary>
/// Constructs a OAuth1 token from a given access token and secret.
/// </summary>
/// <param name="access_token">Access token string.</param>
/// <param name="secret">Token secret string.</param>
oauth1_token
(
utility
::
string_t
access_token
,
utility
::
string_t
secret
)
:
m_token
(
std
::
move
(
access_token
)),
m_secret
(
std
::
move
(
secret
))
{
}
/// <summary>
/// Get access token validity state.
/// If true, token is a valid access token.
/// </summary>
/// <returns>Access token validity state of the token.</returns>
bool
is_valid_access_token
()
const
{
return
!
(
access_token
().
empty
()
||
secret
().
empty
());
}
/// <summary>
/// Get access token.
/// </summary>
/// <returns>The access token string.</returns>
const
utility
::
string_t
&
access_token
()
const
{
return
m_token
;
}
/// <summary>
/// Set access token.
/// </summary>
/// <param name="access_token">Access token string to set.</param>
void
set_access_token
(
utility
::
string_t
&&
access_token
)
{
m_token
=
std
::
move
(
access_token
);
}
/// <summary>
/// Set access token.
/// </summary>
/// <param name="access_token">Access token string to set.</param>
void
set_access_token
(
const
utility
::
string_t
&
access_token
)
{
m_token
=
access_token
;
}
/// <summary>
/// Get token secret.
/// </summary>
/// <returns>Token secret string.</returns>
const
utility
::
string_t
&
secret
()
const
{
return
m_secret
;
}
/// <summary>
/// Set token secret.
/// </summary>
/// <param name="secret">Token secret string to set.</param>
void
set_secret
(
utility
::
string_t
&&
secret
)
{
m_secret
=
std
::
move
(
secret
);
}
/// <summary>
/// Set token secret.
/// </summary>
/// <param name="secret">Token secret string to set.</param>
void
set_secret
(
const
utility
::
string_t
&
secret
)
{
m_secret
=
secret
;
}
/// <summary>
/// Retrieves any additional parameters.
/// </summary>
/// <returns>A map containing the additional parameters.</returns>
const
std
::
map
<
utility
::
string_t
,
utility
::
string_t
>&
additional_parameters
()
const
{
return
m_additional_parameters
;
}
/// <summary>
/// Sets a specific parameter additional parameter.
/// </summary>
/// <param name="paramName">Parameter name.</param>
/// <param name="paramValue">Parameter value.</param>
void
set_additional_parameter
(
utility
::
string_t
&&
paramName
,
utility
::
string_t
&&
paramValue
)
{
m_additional_parameters
[
std
::
move
(
paramName
)]
=
std
::
move
(
paramValue
);
}
/// <summary>
/// Sets a specific parameter additional parameter.
/// </summary>
/// <param name="paramName">Parameter name.</param>
/// <param name="paramValue">Parameter value.</param>
void
set_additional_parameter
(
const
utility
::
string_t
&
paramName
,
const
utility
::
string_t
&
paramValue
)
{
m_additional_parameters
[
paramName
]
=
paramValue
;
}
/// <summary>
/// Clears all additional parameters.
/// </summary>
void
clear_additional_parameters
()
{
m_additional_parameters
.
clear
();
}
private:
friend
class
oauth1_config
;
utility
::
string_t
m_token
;
utility
::
string_t
m_secret
;
std
::
map
<
utility
::
string_t
,
utility
::
string_t
>
m_additional_parameters
;
};
/// <summary>
/// OAuth 1.0 configuration class.
/// </summary>
class
oauth1_config
{
public:
oauth1_config
(
utility
::
string_t
consumer_key
,
utility
::
string_t
consumer_secret
,
utility
::
string_t
temp_endpoint
,
utility
::
string_t
auth_endpoint
,
utility
::
string_t
token_endpoint
,
utility
::
string_t
callback_uri
,
oauth1_method
method
,
utility
::
string_t
realm
=
utility
::
string_t
())
:
m_consumer_key
(
std
::
move
(
consumer_key
))
,
m_consumer_secret
(
std
::
move
(
consumer_secret
))
,
m_temp_endpoint
(
std
::
move
(
temp_endpoint
))
,
m_auth_endpoint
(
std
::
move
(
auth_endpoint
))
,
m_token_endpoint
(
std
::
move
(
token_endpoint
))
,
m_callback_uri
(
std
::
move
(
callback_uri
))
,
m_realm
(
std
::
move
(
realm
))
,
m_method
(
std
::
move
(
method
))
,
m_is_authorization_completed
(
false
)
{
}
/// <summary>
/// Builds an authorization URI to be loaded in a web browser/view.
/// The URI is built with auth_endpoint() as basis.
/// The method creates a task for HTTP request to first obtain a
/// temporary token. The authorization URI build based on this token.
/// </summary>
/// <returns>Authorization URI to be loaded in a web browser/view.</returns>
_ASYNCRTIMP
pplx
::
task
<
utility
::
string_t
>
build_authorization_uri
();
/// <summary>
/// Fetch an access token based on redirected URI.
/// The URI is expected to contain 'oauth_verifier'
/// parameter, which is then used to fetch an access token using the
/// token_from_verifier() method.
/// See: http://tools.ietf.org/html/rfc5849#section-2.2
/// The received 'oauth_token' is parsed and verified to match the current token().
/// When access token is successfully obtained, set_token() is called, and config is
/// ready for use by oauth1_handler.
/// </summary>
/// <param name="redirected_uri">The URI where web browser/view was redirected after resource owner's
/// authorization.</param> <returns>Task that fetches the access token based on redirected URI.</returns>
_ASYNCRTIMP
pplx
::
task
<
void
>
token_from_redirected_uri
(
const
web
::
http
::
uri
&
redirected_uri
);
/// <summary>
/// Creates a task with HTTP request to fetch an access token from the token endpoint.
/// The request exchanges a verifier code to an access token.
/// If successful, the resulting token is set as active via set_token().
/// See: http://tools.ietf.org/html/rfc5849#section-2.3
/// </summary>
/// <param name="verifier">Verifier received via redirect upon successful authorization.</param>
/// <returns>Task that fetches the access token based on the verifier.</returns>
pplx
::
task
<
void
>
token_from_verifier
(
utility
::
string_t
verifier
)
{
return
_request_token
(
_generate_auth_state
(
details
::
oauth1_strings
::
verifier
,
std
::
move
(
verifier
)),
false
);
}
/// <summary>
/// Creates a task with HTTP request to fetch an access token from the token endpoint.
/// If successful, the resulting token is set as active via set_token().
/// </summary>
/// <returns>Task that fetches the access token based on the verifier.</returns>
pplx
::
task
<
void
>
refresh_token
(
const
utility
::
string_t
&
key
)
{
return
_request_token
(
_generate_auth_state
(
key
,
m_token
.
additional_parameters
().
at
(
key
)),
false
);
}
/// <summary>
/// Get consumer key used in authorization and authentication.
/// </summary>
/// <returns>Consumer key string.</returns>
const
utility
::
string_t
&
consumer_key
()
const
{
return
m_consumer_key
;
}
/// <summary>
/// Set consumer key used in authorization and authentication.
/// </summary>
/// <param name="key">Consumer key string to set.</param>
void
set_consumer_key
(
utility
::
string_t
key
)
{
m_consumer_key
=
std
::
move
(
key
);
}
/// <summary>
/// Get consumer secret used in authorization and authentication.
/// </summary>
/// <returns>Consumer secret string.</returns>
const
utility
::
string_t
&
consumer_secret
()
const
{
return
m_consumer_secret
;
}
/// <summary>
/// Set consumer secret used in authorization and authentication.
/// </summary>
/// <param name="secret">Consumer secret string to set.</param>
void
set_consumer_secret
(
utility
::
string_t
secret
)
{
m_consumer_secret
=
std
::
move
(
secret
);
}
/// <summary>
/// Get temporary token endpoint URI string.
/// </summary>
/// <returns>Temporary token endpoint URI string.</returns>
const
utility
::
string_t
&
temp_endpoint
()
const
{
return
m_temp_endpoint
;
}
/// <summary>
/// Set temporary token endpoint URI string.
/// </summary>
/// <param name="temp_endpoint">Temporary token endpoint URI string to set.</param>
void
set_temp_endpoint
(
utility
::
string_t
temp_endpoint
)
{
m_temp_endpoint
=
std
::
move
(
temp_endpoint
);
}
/// <summary>
/// Get authorization endpoint URI string.
/// </summary>
/// <returns>Authorization endpoint URI string.</returns>
const
utility
::
string_t
&
auth_endpoint
()
const
{
return
m_auth_endpoint
;
}
/// <summary>
/// Set authorization endpoint URI string.
/// </summary>
/// <param name="auth_endpoint">Authorization endpoint URI string to set.</param>
void
set_auth_endpoint
(
utility
::
string_t
auth_endpoint
)
{
m_auth_endpoint
=
std
::
move
(
auth_endpoint
);
}
/// <summary>
/// Get token endpoint URI string.
/// </summary>
/// <returns>Token endpoint URI string.</returns>
const
utility
::
string_t
&
token_endpoint
()
const
{
return
m_token_endpoint
;
}
/// <summary>
/// Set token endpoint URI string.
/// </summary>
/// <param name="token_endpoint">Token endpoint URI string to set.</param>
void
set_token_endpoint
(
utility
::
string_t
token_endpoint
)
{
m_token_endpoint
=
std
::
move
(
token_endpoint
);
}
/// <summary>
/// Get callback URI string.
/// </summary>
/// <returns>Callback URI string.</returns>
const
utility
::
string_t
&
callback_uri
()
const
{
return
m_callback_uri
;
}
/// <summary>
/// Set callback URI string.
/// </summary>
/// <param name="callback_uri">Callback URI string to set.</param>
void
set_callback_uri
(
utility
::
string_t
callback_uri
)
{
m_callback_uri
=
std
::
move
(
callback_uri
);
}
/// <summary>
/// Get token.
/// </summary>
/// <returns>Token.</returns>
_ASYNCRTIMP
const
oauth1_token
&
token
()
const
;
/// <summary>
/// Set token.
/// </summary>
/// <param name="token">Token to set.</param>
void
set_token
(
oauth1_token
token
)
{
m_token
=
std
::
move
(
token
);
m_is_authorization_completed
=
true
;
}
/// <summary>
/// Get signature method.
/// </summary>
/// <returns>Signature method.</returns>
const
oauth1_method
&
method
()
const
{
return
m_method
;
}
/// <summary>
/// Set signature method.
/// </summary>
/// <param name="method">Signature method.</param>
void
set_method
(
oauth1_method
method
)
{
m_method
=
std
::
move
(
method
);
}
/// <summary>
/// Get authentication realm.
/// </summary>
/// <returns>Authentication realm string.</returns>
const
utility
::
string_t
&
realm
()
const
{
return
m_realm
;
}
/// <summary>
/// Set authentication realm.
/// </summary>
/// <param name="realm">Authentication realm string to set.</param>
void
set_realm
(
utility
::
string_t
realm
)
{
m_realm
=
std
::
move
(
realm
);
}
/// <summary>
/// Returns enabled state of the configuration.
/// The oauth1_handler will perform OAuth 1.0 authentication only if
/// this method returns true.
/// Return value is true if access token is valid (=fetched or manually set)
/// and both consumer_key() and consumer_secret() are set (=non-empty).
/// </summary>
/// <returns>The configuration enabled state.</returns>
bool
is_enabled
()
const
{
return
token
().
is_valid_access_token
()
&&
!
(
consumer_key
().
empty
()
||
consumer_secret
().
empty
());
}
// Builds signature base string according to:
// http://tools.ietf.org/html/rfc5849#section-3.4.1.1
_ASYNCRTIMP
utility
::
string_t
_build_signature_base_string
(
http_request
request
,
details
::
oauth1_state
state
)
const
;
// Builds HMAC-SHA1 signature according to:
// http://tools.ietf.org/html/rfc5849#section-3.4.2
utility
::
string_t
_build_hmac_sha1_signature
(
http_request
request
,
details
::
oauth1_state
state
)
const
{
auto
text
(
_build_signature_base_string
(
std
::
move
(
request
),
std
::
move
(
state
)));
auto
digest
(
_hmac_sha1
(
_build_key
(),
std
::
move
(
text
)));
auto
signature
(
utility
::
conversions
::
to_base64
(
std
::
move
(
digest
)));
return
signature
;
}
// Builds PLAINTEXT signature according to:
// http://tools.ietf.org/html/rfc5849#section-3.4.4
utility
::
string_t
_build_plaintext_signature
()
const
{
return
_build_key
();
}
details
::
oauth1_state
_generate_auth_state
(
utility
::
string_t
extra_key
,
utility
::
string_t
extra_value
)
{
return
details
::
oauth1_state
(
_generate_timestamp
(),
_generate_nonce
(),
std
::
move
(
extra_key
),
std
::
move
(
extra_value
));
}
details
::
oauth1_state
_generate_auth_state
()
{
return
details
::
oauth1_state
(
_generate_timestamp
(),
_generate_nonce
());
}
/// <summary>
/// Gets map of parameters to sign.
/// </summary>
/// <returns>Map of parameters.</returns>
const
std
::
map
<
utility
::
string_t
,
utility
::
string_t
>&
parameters
()
const
{
return
m_parameters_to_sign
;
}
/// <summary>
/// Adds a key value parameter.
/// </summary>
/// <param name="key">Key as a string value.</param>
/// <param name="value">Value as a string value.</param>
void
add_parameter
(
const
utility
::
string_t
&
key
,
const
utility
::
string_t
&
value
)
{
m_parameters_to_sign
[
key
]
=
value
;
}
/// <summary>
/// Adds a key value parameter.
/// </summary>
/// <param name="key">Key as a string value.</param>
/// <param name="value">Value as a string value.</param>
void
add_parameter
(
utility
::
string_t
&&
key
,
utility
::
string_t
&&
value
)
{
m_parameters_to_sign
[
std
::
move
(
key
)]
=
std
::
move
(
value
);
}
/// <summary>
/// Sets entire map or parameters replacing all previously values.
/// </summary>
/// <param name="parameters">Map of values.</param>
void
set_parameters
(
const
std
::
map
<
utility
::
string_t
,
utility
::
string_t
>&
parameters
)
{
m_parameters_to_sign
.
clear
();
m_parameters_to_sign
=
parameters
;
}
/// <summary>
/// Clears all parameters.
/// </summary>
void
clear_parameters
()
{
m_parameters_to_sign
.
clear
();
}
/// <summary>
/// Get the web proxy object
/// </summary>
/// <returns>A reference to the web proxy object.</returns>
const
web_proxy
&
proxy
()
const
{
return
m_proxy
;
}
/// <summary>
/// Set the web proxy object that will be used by token_from_code and token_from_refresh
/// </summary>
/// <param name="proxy">A reference to the web proxy object.</param>
void
set_proxy
(
const
web_proxy
&
proxy
)
{
m_proxy
=
proxy
;
}
private:
friend
class
web
::
http
::
client
::
http_client_config
;
friend
class
web
::
http
::
oauth1
::
details
::
oauth1_handler
;
oauth1_config
()
:
m_is_authorization_completed
(
false
)
{}
utility
::
string_t
_generate_nonce
()
{
return
m_nonce_generator
.
generate
();
}
static
utility
::
string_t
_generate_timestamp
()
{
return
utility
::
conversions
::
details
::
to_string_t
(
utility
::
datetime
::
utc_timestamp
());
}
_ASYNCRTIMP
static
std
::
vector
<
unsigned
char
>
__cdecl
_hmac_sha1
(
const
utility
::
string_t
&
key
,
const
utility
::
string_t
&
data
);
static
utility
::
string_t
_build_base_string_uri
(
const
uri
&
u
);
utility
::
string_t
_build_normalized_parameters
(
web
::
http
::
uri
u
,
const
details
::
oauth1_state
&
state
)
const
;
utility
::
string_t
_build_signature
(
http_request
request
,
details
::
oauth1_state
state
)
const
;
utility
::
string_t
_build_key
()
const
{
return
uri
::
encode_data_string
(
consumer_secret
())
+
_XPLATSTR
(
"&"
)
+
uri
::
encode_data_string
(
m_token
.
secret
());
}
void
_authenticate_request
(
http_request
&
req
)
{
_authenticate_request
(
req
,
_generate_auth_state
());
}
_ASYNCRTIMP
void
_authenticate_request
(
http_request
&
req
,
details
::
oauth1_state
state
);
_ASYNCRTIMP
pplx
::
task
<
void
>
_request_token
(
details
::
oauth1_state
state
,
bool
is_temp_token_request
);
utility
::
string_t
m_consumer_key
;
utility
::
string_t
m_consumer_secret
;
oauth1_token
m_token
;
utility
::
string_t
m_temp_endpoint
;
utility
::
string_t
m_auth_endpoint
;
utility
::
string_t
m_token_endpoint
;
utility
::
string_t
m_callback_uri
;
utility
::
string_t
m_realm
;
oauth1_method
m_method
;
std
::
map
<
utility
::
string_t
,
utility
::
string_t
>
m_parameters_to_sign
;
web
::
web_proxy
m_proxy
;
utility
::
nonce_generator
m_nonce_generator
;
bool
m_is_authorization_completed
;
};
}
// namespace experimental
namespace
details
{
class
oauth1_handler
:
public
http_pipeline_stage
{
public:
oauth1_handler
(
std
::
shared_ptr
<
experimental
::
oauth1_config
>
cfg
)
:
m_config
(
std
::
move
(
cfg
))
{}
virtual
pplx
::
task
<
http_response
>
propagate
(
http_request
request
)
override
{
if
(
m_config
)
{
m_config
->
_authenticate_request
(
request
);
}
return
next_stage
()
->
propagate
(
request
);
}
private:
std
::
shared_ptr
<
experimental
::
oauth1_config
>
m_config
;
};
}
// namespace details
}
// namespace oauth1
}
// namespace http
}
// namespace web
#endif
cpprestsdk_static_tester/vcpkg/include/cpprest/oauth2.h
0 → 100644
View file @
14571fd2
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* HTTP Library: Oauth 2.0
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#ifndef CASA_OAUTH2_H
#define CASA_OAUTH2_H
#include
"cpprest/details/web_utilities.h"
#include
"cpprest/http_msg.h"
namespace
web
{
namespace
http
{
namespace
client
{
// Forward declaration to avoid circular include dependency.
class
http_client_config
;
}
// namespace client
/// oAuth 2.0 library.
namespace
oauth2
{
namespace
details
{
class
oauth2_handler
;
// Constant strings for OAuth 2.0.
typedef
utility
::
string_t
oauth2_string
;
class
oauth2_strings
{
public:
#define _OAUTH2_STRINGS
#define DAT(a_, b_) _ASYNCRTIMP static const oauth2_string a_;
#include
"cpprest/details/http_constants.dat"
#undef _OAUTH2_STRINGS
#undef DAT
};
}
// namespace details
/// oAuth functionality is currently in beta.
namespace
experimental
{
/// <summary>
/// Exception type for OAuth 2.0 errors.
/// </summary>
class
oauth2_exception
:
public
std
::
exception
{
public:
oauth2_exception
(
utility
::
string_t
msg
)
:
m_msg
(
utility
::
conversions
::
to_utf8string
(
std
::
move
(
msg
)))
{}
~
oauth2_exception
()
CPPREST_NOEXCEPT
{}
const
char
*
what
()
const
CPPREST_NOEXCEPT
{
return
m_msg
.
c_str
();
}
private:
std
::
string
m_msg
;
};
/// <summary>
/// OAuth 2.0 token and associated information.
/// </summary>
class
oauth2_token
{
public:
/// <summary>
/// Value for undefined expiration time in expires_in().
/// </summary>
enum
{
undefined_expiration
=
-
1
};
oauth2_token
(
utility
::
string_t
access_token
=
utility
::
string_t
())
:
m_access_token
(
std
::
move
(
access_token
)),
m_expires_in
(
undefined_expiration
)
{
}
/// <summary>
/// Get access token validity state.
/// If true, access token is a valid.
/// </summary>
/// <returns>Access token validity state.</returns>
bool
is_valid_access_token
()
const
{
return
!
access_token
().
empty
();
}
/// <summary>
/// Get access token.
/// </summary>
/// <returns>Access token string.</returns>
const
utility
::
string_t
&
access_token
()
const
{
return
m_access_token
;
}
/// <summary>
/// Set access token.
/// </summary>
/// <param name="access_token">Access token string to set.</param>
void
set_access_token
(
utility
::
string_t
access_token
)
{
m_access_token
=
std
::
move
(
access_token
);
}
/// <summary>
/// Get refresh token.
/// </summary>
/// <returns>Refresh token string.</returns>
const
utility
::
string_t
&
refresh_token
()
const
{
return
m_refresh_token
;
}
/// <summary>
/// Set refresh token.
/// </summary>
/// <param name="refresh_token">Refresh token string to set.</param>
void
set_refresh_token
(
utility
::
string_t
refresh_token
)
{
m_refresh_token
=
std
::
move
(
refresh_token
);
}
/// <summary>
/// Get token type.
/// </summary>
/// <returns>Token type string.</returns>
const
utility
::
string_t
&
token_type
()
const
{
return
m_token_type
;
}
/// <summary>
/// Set token type.
/// </summary>
/// <param name="token_type">Token type string to set.</param>
void
set_token_type
(
utility
::
string_t
token_type
)
{
m_token_type
=
std
::
move
(
token_type
);
}
/// <summary>
/// Get token scope.
/// </summary>
/// <returns>Token scope string.</returns>
const
utility
::
string_t
&
scope
()
const
{
return
m_scope
;
}
/// <summary>
/// Set token scope.
/// </summary>
/// <param name="scope">Token scope string to set.</param>
void
set_scope
(
utility
::
string_t
scope
)
{
m_scope
=
std
::
move
(
scope
);
}
/// <summary>
/// Get the lifetime of the access token in seconds.
/// For example, 3600 means the access token will expire in one hour from
/// the time when access token response was generated by the authorization server.
/// Value of undefined_expiration means expiration time is either
/// unset or that it was not returned by the server with the access token.
/// </summary>
/// <returns>Lifetime of the access token in seconds or undefined_expiration if not set.</returns>
int64_t
expires_in
()
const
{
return
m_expires_in
;
}
/// <summary>
/// Set lifetime of access token (in seconds).
/// </summary>
/// <param name="expires_in">Lifetime of access token in seconds.</param>
void
set_expires_in
(
int64_t
expires_in
)
{
m_expires_in
=
expires_in
;
}
private:
utility
::
string_t
m_access_token
;
utility
::
string_t
m_refresh_token
;
utility
::
string_t
m_token_type
;
utility
::
string_t
m_scope
;
int64_t
m_expires_in
;
};
/// <summary>
/// OAuth 2.0 configuration.
///
/// Encapsulates functionality for:
/// - Authenticating requests with an access token.
/// - Performing the OAuth 2.0 authorization code grant authorization flow.
/// See: http://tools.ietf.org/html/rfc6749#section-4.1
/// - Performing the OAuth 2.0 implicit grant authorization flow.
/// See: http://tools.ietf.org/html/rfc6749#section-4.2
///
/// Performing OAuth 2.0 authorization:
/// 1. Set service and client/app parameters:
/// - Client/app key & secret (as provided by the service).
/// - The service authorization endpoint and token endpoint.
/// - Your client/app redirect URI.
/// - Use set_state() to assign a unique state string for the authorization
/// session (default: "").
/// - If needed, use set_bearer_auth() to control bearer token passing in either
/// query or header (default: header). See: http://tools.ietf.org/html/rfc6750#section-2
/// - If needed, use set_access_token_key() to set "non-standard" access token
/// key (default: "access_token").
/// - If needed, use set_implicit_grant() to enable implicit grant flow.
/// 2. Build authorization URI with build_authorization_uri() and open this in web browser/control.
/// 3. The resource owner should then clicks "Yes" to authorize your client/app, and
/// as a result the web browser/control is redirected to redirect_uri().
/// 5. Capture the redirected URI either in web control or by HTTP listener.
/// 6. Pass the redirected URI to token_from_redirected_uri() to obtain access token.
/// - The method ensures redirected URI contains same state() as set in step 1.
/// - In implicit_grant() is false, this will create HTTP request to fetch access token
/// from the service. Otherwise access token is already included in the redirected URI.
///
/// Usage for issuing authenticated requests:
/// 1. Perform authorization as above to obtain the access token or use an existing token.
/// - Some services provide option to generate access tokens for testing purposes.
/// 2. Pass the resulting oauth2_config with the access token to http_client_config::set_oauth2().
/// 3. Construct http_client with this http_client_config. As a result, all HTTP requests
/// by that client will be OAuth 2.0 authenticated.
///
/// </summary>
class
oauth2_config
{
public:
oauth2_config
(
utility
::
string_t
client_key
,
utility
::
string_t
client_secret
,
utility
::
string_t
auth_endpoint
,
utility
::
string_t
token_endpoint
,
utility
::
string_t
redirect_uri
,
utility
::
string_t
scope
=
utility
::
string_t
(),
utility
::
string_t
user_agent
=
utility
::
string_t
())
:
m_client_key
(
std
::
move
(
client_key
))
,
m_client_secret
(
std
::
move
(
client_secret
))
,
m_auth_endpoint
(
std
::
move
(
auth_endpoint
))
,
m_token_endpoint
(
std
::
move
(
token_endpoint
))
,
m_redirect_uri
(
std
::
move
(
redirect_uri
))
,
m_scope
(
std
::
move
(
scope
))
,
m_user_agent
(
std
::
move
(
user_agent
))
,
m_implicit_grant
(
false
)
,
m_bearer_auth
(
true
)
,
m_http_basic_auth
(
true
)
,
m_access_token_key
(
details
::
oauth2_strings
::
access_token
)
{
}
/// <summary>
/// Builds an authorization URI to be loaded in the web browser/view.
/// The URI is built with auth_endpoint() as basis.
/// The implicit_grant() affects the built URI by selecting
/// either authorization code or implicit grant flow.
/// You can set generate_state to generate a new random state string.
/// </summary>
/// <param name="generate_state">If true, a new random state() string is generated
/// which replaces the current state(). If false, state() is unchanged and used as-is.</param>
/// <returns>Authorization URI string.</returns>
_ASYNCRTIMP
utility
::
string_t
build_authorization_uri
(
bool
generate_state
);
/// <summary>
/// Fetch an access token (and possibly a refresh token) based on redirected URI.
/// Behavior depends on the implicit_grant() setting.
/// If implicit_grant() is false, the URI is parsed for 'code'
/// parameter, and then token_from_code() is called with this code.
/// See: http://tools.ietf.org/html/rfc6749#section-4.1
/// Otherwise, redirect URI fragment part is parsed for 'access_token'
/// parameter, which directly contains the token(s).
/// See: http://tools.ietf.org/html/rfc6749#section-4.2
/// In both cases, the 'state' parameter is parsed and is verified to match state().
/// </summary>
/// <param name="redirected_uri">The URI where web browser/view was redirected after resource owner's
/// authorization.</param> <returns>Task that fetches the token(s) based on redirected URI.</returns>
_ASYNCRTIMP
pplx
::
task
<
void
>
token_from_redirected_uri
(
const
web
::
http
::
uri
&
redirected_uri
);
/// <summary>
/// Fetches an access token (and possibly a refresh token) from the token endpoint.
/// The task creates an HTTP request to the token_endpoint() which exchanges
/// the authorization code for the token(s).
/// This also sets the refresh token if one was returned.
/// See: http://tools.ietf.org/html/rfc6749#section-4.1.3
/// </summary>
/// <param name="authorization_code">Code received via redirect upon successful authorization.</param>
/// <returns>Task that fetches token(s) based on the authorization code.</returns>
pplx
::
task
<
void
>
token_from_code
(
utility
::
string_t
authorization_code
)
{
uri_builder
ub
;
ub
.
append_query
(
details
::
oauth2_strings
::
grant_type
,
details
::
oauth2_strings
::
authorization_code
,
false
);
ub
.
append_query
(
details
::
oauth2_strings
::
code
,
uri
::
encode_data_string
(
std
::
move
(
authorization_code
)),
false
);
ub
.
append_query
(
details
::
oauth2_strings
::
redirect_uri
,
uri
::
encode_data_string
(
redirect_uri
()),
false
);
return
_request_token
(
ub
);
}
/// <summary>
/// Fetches a new access token (and possibly a new refresh token) using the refresh token.
/// The task creates a HTTP request to the token_endpoint().
/// If successful, resulting access token is set as active via set_token().
/// See: http://tools.ietf.org/html/rfc6749#section-6
/// This also sets a new refresh token if one was returned.
/// </summary>
/// <returns>Task that fetches the token(s) using the refresh token.</returns>
pplx
::
task
<
void
>
token_from_refresh
()
{
uri_builder
ub
;
ub
.
append_query
(
details
::
oauth2_strings
::
grant_type
,
details
::
oauth2_strings
::
refresh_token
,
false
);
ub
.
append_query
(
details
::
oauth2_strings
::
refresh_token
,
uri
::
encode_data_string
(
token
().
refresh_token
()),
false
);
return
_request_token
(
ub
);
}
/// <summary>
/// Returns enabled state of the configuration.
/// The oauth2_handler will perform OAuth 2.0 authentication only if
/// this method returns true.
/// Return value is true if access token is valid (=fetched or manually set).
/// </summary>
/// <returns>The configuration enabled state.</returns>
bool
is_enabled
()
const
{
return
token
().
is_valid_access_token
();
}
/// <summary>
/// Get client key.
/// </summary>
/// <returns>Client key string.</returns>
const
utility
::
string_t
&
client_key
()
const
{
return
m_client_key
;
}
/// <summary>
/// Set client key.
/// </summary>
/// <param name="client_key">Client key string to set.</param>
void
set_client_key
(
utility
::
string_t
client_key
)
{
m_client_key
=
std
::
move
(
client_key
);
}
/// <summary>
/// Get client secret.
/// </summary>
/// <returns>Client secret string.</returns>
const
utility
::
string_t
&
client_secret
()
const
{
return
m_client_secret
;
}
/// <summary>
/// Set client secret.
/// </summary>
/// <param name="client_secret">Client secret string to set.</param>
void
set_client_secret
(
utility
::
string_t
client_secret
)
{
m_client_secret
=
std
::
move
(
client_secret
);
}
/// <summary>
/// Get authorization endpoint URI string.
/// </summary>
/// <returns>Authorization endpoint URI string.</returns>
const
utility
::
string_t
&
auth_endpoint
()
const
{
return
m_auth_endpoint
;
}
/// <summary>
/// Set authorization endpoint URI string.
/// </summary>
/// <param name="auth_endpoint">Authorization endpoint URI string to set.</param>
void
set_auth_endpoint
(
utility
::
string_t
auth_endpoint
)
{
m_auth_endpoint
=
std
::
move
(
auth_endpoint
);
}
/// <summary>
/// Get token endpoint URI string.
/// </summary>
/// <returns>Token endpoint URI string.</returns>
const
utility
::
string_t
&
token_endpoint
()
const
{
return
m_token_endpoint
;
}
/// <summary>
/// Set token endpoint URI string.
/// </summary>
/// <param name="token_endpoint">Token endpoint URI string to set.</param>
void
set_token_endpoint
(
utility
::
string_t
token_endpoint
)
{
m_token_endpoint
=
std
::
move
(
token_endpoint
);
}
/// <summary>
/// Get redirect URI string.
/// </summary>
/// <returns>Redirect URI string.</returns>
const
utility
::
string_t
&
redirect_uri
()
const
{
return
m_redirect_uri
;
}
/// <summary>
/// Set redirect URI string.
/// </summary>
/// <param name="redirect_uri">Redirect URI string to set.</param>
void
set_redirect_uri
(
utility
::
string_t
redirect_uri
)
{
m_redirect_uri
=
std
::
move
(
redirect_uri
);
}
/// <summary>
/// Get scope used in authorization for token.
/// </summary>
/// <returns>Scope string used in authorization.</returns>
const
utility
::
string_t
&
scope
()
const
{
return
m_scope
;
}
/// <summary>
/// Set scope for authorization for token.
/// </summary>
/// <param name="scope">Scope string for authorization for token.</param>
void
set_scope
(
utility
::
string_t
scope
)
{
m_scope
=
std
::
move
(
scope
);
}
/// <summary>
/// Get client state string used in authorization.
/// </summary>
/// <returns>Client state string used in authorization.</returns>
const
utility
::
string_t
&
state
()
{
return
m_state
;
}
/// <summary>
/// Set client state string for authorization for token.
/// The state string is used in authorization for security reasons
/// (to uniquely identify authorization sessions).
/// If desired, suitably secure state string can be automatically generated
/// by build_authorization_uri().
/// A good state string consist of 30 or more random alphanumeric characters.
/// </summary>
/// <param name="state">Client authorization state string to set.</param>
void
set_state
(
utility
::
string_t
state
)
{
m_state
=
std
::
move
(
state
);
}
/// <summary>
/// Get token.
/// </summary>
/// <returns>Token.</returns>
const
oauth2_token
&
token
()
const
{
return
m_token
;
}
/// <summary>
/// Set token.
/// </summary>
/// <param name="token">Token to set.</param>
void
set_token
(
oauth2_token
token
)
{
m_token
=
std
::
move
(
token
);
}
/// <summary>
/// Get implicit grant setting for authorization.
/// </summary>
/// <returns>Implicit grant setting for authorization.</returns>
bool
implicit_grant
()
const
{
return
m_implicit_grant
;
}
/// <summary>
/// Set implicit grant setting for authorization.
/// False means authorization code grant is used for authorization.
/// True means implicit grant is used.
/// Default: False.
/// </summary>
/// <param name="implicit_grant">The implicit grant setting to set.</param>
void
set_implicit_grant
(
bool
implicit_grant
)
{
m_implicit_grant
=
implicit_grant
;
}
/// <summary>
/// Get bearer token authentication setting.
/// </summary>
/// <returns>Bearer token authentication setting.</returns>
bool
bearer_auth
()
const
{
return
m_bearer_auth
;
}
/// <summary>
/// Set bearer token authentication setting.
/// This must be selected based on what the service accepts.
/// True means access token is passed in the request header. (http://tools.ietf.org/html/rfc6750#section-2.1)
/// False means access token in passed in the query parameters. (http://tools.ietf.org/html/rfc6750#section-2.3)
/// Default: True.
/// </summary>
/// <param name="bearer_auth">The bearer token authentication setting to set.</param>
void
set_bearer_auth
(
bool
bearer_auth
)
{
m_bearer_auth
=
bearer_auth
;
}
/// <summary>
/// Get HTTP Basic authentication setting for token endpoint.
/// </summary>
/// <returns>HTTP Basic authentication setting for token endpoint.</returns>
bool
http_basic_auth
()
const
{
return
m_http_basic_auth
;
}
/// <summary>
/// Set HTTP Basic authentication setting for token endpoint.
/// This setting must be selected based on what the service accepts.
/// True means HTTP Basic authentication is used for the token endpoint.
/// False means client key & secret are passed in the HTTP request body.
/// Default: True.
/// </summary>
/// <param name="http_basic_auth">The HTTP Basic authentication setting to set.</param>
void
set_http_basic_auth
(
bool
http_basic_auth
)
{
m_http_basic_auth
=
http_basic_auth
;
}
/// <summary>
/// Get access token key.
/// </summary>
/// <returns>Access token key string.</returns>
const
utility
::
string_t
&
access_token_key
()
const
{
return
m_access_token_key
;
}
/// <summary>
/// Set access token key.
/// If the service requires a "non-standard" key you must set it here.
/// Default: "access_token".
/// </summary>
void
set_access_token_key
(
utility
::
string_t
access_token_key
)
{
m_access_token_key
=
std
::
move
(
access_token_key
);
}
/// <summary>
/// Get the web proxy object
/// </summary>
/// <returns>A reference to the web proxy object.</returns>
const
web_proxy
&
proxy
()
const
{
return
m_proxy
;
}
/// <summary>
/// Set the web proxy object that will be used by token_from_code and token_from_refresh
/// </summary>
/// <param name="proxy">A reference to the web proxy object.</param>
void
set_proxy
(
const
web_proxy
&
proxy
)
{
m_proxy
=
proxy
;
}
/// <summary>
/// Get user agent to be used in oauth2 flows.
/// </summary>
/// <returns>User agent string.</returns>
const
utility
::
string_t
&
user_agent
()
const
{
return
m_user_agent
;
}
/// <summary>
/// Set user agent to be used in oauth2 flows.
/// If none is provided a default user agent is provided.
/// </summary>
void
set_user_agent
(
utility
::
string_t
user_agent
)
{
m_user_agent
=
std
::
move
(
user_agent
);
}
private:
friend
class
web
::
http
::
client
::
http_client_config
;
friend
class
web
::
http
::
oauth2
::
details
::
oauth2_handler
;
oauth2_config
()
:
m_implicit_grant
(
false
),
m_bearer_auth
(
true
),
m_http_basic_auth
(
true
)
{}
_ASYNCRTIMP
pplx
::
task
<
void
>
_request_token
(
uri_builder
&
request_body
);
oauth2_token
_parse_token_from_json
(
const
json
::
value
&
token_json
);
void
_authenticate_request
(
http_request
&
req
)
const
{
if
(
bearer_auth
())
{
req
.
headers
().
add
(
header_names
::
authorization
,
_XPLATSTR
(
"Bearer "
)
+
token
().
access_token
());
}
else
{
uri_builder
ub
(
req
.
request_uri
());
ub
.
append_query
(
access_token_key
(),
token
().
access_token
());
req
.
set_request_uri
(
ub
.
to_uri
());
}
}
utility
::
string_t
m_client_key
;
utility
::
string_t
m_client_secret
;
utility
::
string_t
m_auth_endpoint
;
utility
::
string_t
m_token_endpoint
;
utility
::
string_t
m_redirect_uri
;
utility
::
string_t
m_scope
;
utility
::
string_t
m_state
;
utility
::
string_t
m_user_agent
;
web
::
web_proxy
m_proxy
;
bool
m_implicit_grant
;
bool
m_bearer_auth
;
bool
m_http_basic_auth
;
utility
::
string_t
m_access_token_key
;
oauth2_token
m_token
;
utility
::
nonce_generator
m_state_generator
;
};
}
// namespace experimental
namespace
details
{
class
oauth2_handler
:
public
http_pipeline_stage
{
public:
oauth2_handler
(
std
::
shared_ptr
<
experimental
::
oauth2_config
>
cfg
)
:
m_config
(
std
::
move
(
cfg
))
{}
virtual
pplx
::
task
<
http_response
>
propagate
(
http_request
request
)
override
{
if
(
m_config
)
{
m_config
->
_authenticate_request
(
request
);
}
return
next_stage
()
->
propagate
(
request
);
}
private:
std
::
shared_ptr
<
experimental
::
oauth2_config
>
m_config
;
};
}
// namespace details
}
// namespace oauth2
}
// namespace http
}
// namespace web
#endif
Prev
1
…
6
7
8
9
10
11
Next
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment