27 #include "cpprest/details/basic_types.h"
28 #include "cpprest/details/http_helpers.h"
31 # define CRLF _XPLATSTR("\r\n")
33 # define CRLF std::string("\r\n")
36 namespace web {
namespace http {
namespace client {
namespace details
40 static const utility::char_t * get_with_body = _XPLATSTR(
"A GET or HEAD request should not have an entity body.");
43 static void trim_nulls(utility::string_t &str)
46 for(index = 0; index < str.size() && str[index] == 0; ++index);
48 for(index = str.size(); index > 0 && str[index - 1] == 0; --index);
55 static utility::string_t flatten_http_headers(
const http_headers &headers)
57 utility::string_t flattened_headers;
58 for(
auto iter = headers.
begin(); iter != headers.
end(); ++iter)
60 flattened_headers.append(iter->first);
61 flattened_headers.push_back(
':');
62 flattened_headers.append(iter->second);
63 flattened_headers.append(CRLF);
65 return flattened_headers;
69 static void parse_headers_string(_Inout_z_ utf16char *headersStr,
http_headers &headers)
74 utf16char *context =
nullptr;
75 utf16char *line = wcstok_s(headersStr, CRLF, &context);
76 while(line !=
nullptr)
78 const utility::string_t header_line(line);
79 const size_t colonIndex = header_line.find_first_of(_XPLATSTR(
":"));
80 if(colonIndex != utility::string_t::npos)
82 utility::string_t key = header_line.substr(0, colonIndex);
83 utility::string_t value = header_line.substr(colonIndex + 1, header_line.length() - colonIndex - 1);
84 http::details::trim_whitespace(key);
85 http::details::trim_whitespace(value);
86 headers.
add(key, value);
88 line = wcstok_s(
nullptr, CRLF, &context);
93 class _http_client_communicator;
105 void complete_headers()
111 m_request_completion.set(m_response);
119 m_response._get_impl()->_complete(body_size);
124 void report_error(
unsigned long error_code,
const std::string &errorMessage)
126 report_exception(
http_exception(static_cast<int>(error_code), errorMessage));
130 void report_error(
unsigned long error_code,
const std::wstring &errorMessage)
132 report_exception(
http_exception(static_cast<int>(error_code), errorMessage));
136 template<
typename _ExceptionType>
137 void report_exception(
const _ExceptionType &e)
139 report_exception(std::make_exception_ptr(e));
142 virtual void report_exception(std::exception_ptr exceptionPtr)
144 auto response_impl = m_response._get_impl();
149 exceptionPtr = std::make_exception_ptr(http_exception((
int)std::errc::operation_canceled, std::generic_category()));
153 if(m_request_completion.set_exception(exceptionPtr))
157 response_impl->_complete(0);
162 response_impl->_complete(0, exceptionPtr);
168 virtual concurrency::streams::streambuf<uint8_t> _get_readbuffer()
170 auto instream = m_request.
body();
172 _ASSERTE((
bool)instream);
173 return instream.streambuf();
176 concurrency::streams::streambuf<uint8_t> _get_writebuffer()
178 auto outstream = m_response._get_impl()->outstream();
180 _ASSERTE((
bool)outstream);
181 return outstream.streambuf();
185 std::shared_ptr<_http_client_communicator> m_http_client;
188 http_request m_request;
189 http_response m_response;
191 utility::size64_t m_uploaded;
192 utility::size64_t m_downloaded;
202 request_context(
const std::shared_ptr<_http_client_communicator> &client,
const http_request &request)
203 : m_http_client(client),
208 auto responseImpl = m_response._get_impl();
211 responseImpl->set_outstream(request._get_impl()->_response_stream(),
false);
216 responseImpl->_prepare_to_receive_data();
219 virtual void finish();
234 void async_send_request(
const std::shared_ptr<request_context> &request)
239 push_request(request);
244 pplx::create_task([
this, request]
246 open_and_send_request(request);
251 void finish_request()
260 if( !m_requests_queue.empty())
262 auto request = m_requests_queue.front();
263 m_requests_queue.pop();
266 pplx::create_task([
this, request]
268 open_and_send_request(request);
276 return m_client_config;
279 const uri & base_uri()
const
286 : m_uri(std::move(address)), m_client_config(std::move(client_config)), m_opened(
false), m_scheduled(0)
291 virtual unsigned long open() = 0;
294 virtual void send_request(_In_
const std::shared_ptr<request_context> &request) = 0;
305 pplx::extensibility::critical_section_t m_open_lock;
308 void open_and_send_request(
const std::shared_ptr<request_context> &request)
311 auto error = open_if_required();
316 request->report_error(error, _XPLATSTR(
"Open failed"));
324 send_request(request);
327 unsigned long open_if_required()
329 unsigned long error = 0;
350 void push_request(
const std::shared_ptr<request_context> &request)
354 if(++m_scheduled == 1)
357 pplx::create_task([
this, request]()
359 open_and_send_request(request);
364 m_requests_queue.push(request);
369 std::queue<std::shared_ptr<request_context>> m_requests_queue;
373 inline void request_context::finish()
379 m_request._cancellation_token().deregister_callback(m_cancellationRegistration);
382 m_http_client->finish_request();
392 const std::shared_ptr<details::_http_client_communicator>& http_client_impl()
const
394 return m_http_client_impl;
398 std::shared_ptr<_http_client_communicator> m_http_client_impl;
402 void verify_uri(
const uri &
uri)
406 if (uri.
scheme() != _XPLATSTR(
"http") && uri.
scheme() != _XPLATSTR(
"https"))
408 throw std::invalid_argument(
"URI scheme must be 'http' or 'https'");
411 if(uri.
host().empty())
413 throw std::invalid_argument(
"URI must contain a hostname.");
426 build_pipeline(base_uri, client_config);
429 void http_client::build_pipeline(
const uri &base_uri,
const http_client_config &client_config)
431 if (base_uri.
scheme().empty())
434 uribuilder.set_scheme(_XPLATSTR(
"http"));
435 uri uriWithScheme = uribuilder.to_uri();
436 details::verify_uri(uriWithScheme);
441 details::verify_uri(base_uri);
445 #if !defined(CPPREST_TARGET_XP)
446 add_handler(std::static_pointer_cast<http::http_pipeline_stage>(
447 std::make_shared<oauth1::details::oauth1_handler>(client_config.
oauth1())));
450 add_handler(std::static_pointer_cast<http::http_pipeline_stage>(
451 std::make_shared<oauth2::details::oauth2_handler>(client_config.
oauth2())));
457 return ph->http_client_impl()->client_config();
463 return ph->http_client_impl()->base_uri();
A generic RAII wrapper for locks that implements the critical_section interface cpprest_synchronizati...
Definition: pplxlinux.h:264
Represents an HTTP error. This class holds an error message and an optional error code...
Definition: http_msg.h:130
concurrency::streams::istream body() const
Produces a stream which the caller may use to retrieve data from an incoming request.
Definition: http_msg.h:1049
const std::shared_ptr< oauth2::experimental::oauth2_config > oauth2() const
Get OAuth 2.0 configuration.
Definition: http_client.h:134
_ASYNCRTIMP http_client(const uri &base_uri)
Creates a new http_client connected to specified uri.
Definition: http_client_impl.h:419
HTTP client handler class, used to represent an HTTP pipeline stage.
Definition: http_msg.h:1302
A flexible, protocol independent URI implementation.
Definition: base_uri.h:151
The web namespace contains functionality common to multiple protocols like HTTP and WebSockets...
Definition: base_uri.h:37
static std::shared_ptr< http_pipeline > create_pipeline(const std::shared_ptr< http_pipeline_stage > &last)
Create an http pipeline that consists of a linear chain of stages
Definition: http_msg.h:1387
HTTP client configuration class, used to set the possible configuration options used to create an htt...
Definition: http_client.h:90
void set_body(utf8string &&body_text, const utf8string &content_type=utf8string("text/plain; charset=utf-8"))
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.
Definition: http_msg.h:921
bool is_canceled() const
Returns true if the token has been canceled.
Definition: pplxcancellation_token.h:791
_ASYNCRTIMP const http_client_config & client_config() const
Get client configuration object
Definition: http_client_impl.h:454
Definition: http_client_impl.h:385
virtual pplx::task< http_response > propagate(http_request request)
Runs this stage against the given request and passes onto the next stage.
The Parallel Patterns Library (PPL) task class. A task object represents work that can be executed as...
Definition: pplxtasks.h:176
const utility::string_t & host() const
Get the host component of the URI as an encoded string.
Definition: base_uri.h:298
The cancellation_token_registration class represents a callback notification from a cancellation_toke...
Definition: pplxcancellation_token.h:616
Definition: http_client_impl.h:96
_ASYNCRTIMP const uri & base_uri() const
Gets the base URI.
Definition: http_client_impl.h:460
Base interface for all asynchronous input streams.
Definition: astreambuf.h:791
static cancellation_token none()
Returns a cancellation token which can never be subject to cancellation.
Definition: pplxcancellation_token.h:724
Represents an HTTP request.
Definition: http_msg.h:771
bool guarantee_order() const
Get the 'guarantee order' property
Definition: http_client.h:188
void complete_request(utility::size64_t body_size)
Completes this request, setting the underlying task completion event, and cleaning up the handles ...
Definition: http_client_impl.h:117
const std::shared_ptr< oauth1::experimental::oauth1_config > oauth1() const
Get OAuth 1.0 configuration.
Definition: http_client.h:115
Builder for constructing URIs incrementally.
Definition: uri_builder.h:40
void add_handler(const std::function< pplx::task< http_response >(http_request, std::shared_ptr< http::http_pipeline_stage >)> &handler)
Adds an HTTP pipeline stage to the client.
Definition: http_client.h:423
const utility::string_t & scheme() const
Get the scheme component of the URI as an encoded string.
Definition: base_uri.h:286
The task_completion_event class allows you to delay the execution of a task until a condition is sati...
Definition: pplxtasks.h:2674
Definition: http_client_impl.h:226