1 /*** 2 * Copyright (C) Microsoft. All rights reserved. 3 * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. 4 * 5 * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 6 * 7 * HTTP Library: Client-side APIs. 8 * 9 * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk 10 * 11 * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 12 ****/ 13 #pragma once 14 15 #ifndef CASA_HTTP_CLIENT_H 16 #define CASA_HTTP_CLIENT_H 17 18 #if defined(__cplusplus_winrt) 19 #if !defined(__WRL_NO_DEFAULT_LIB__) 20 #define __WRL_NO_DEFAULT_LIB__ 21 #endif 22 #include <msxml6.h> 23 #include <wrl.h> 24 namespace web 25 { 26 namespace http 27 { 28 namespace client 29 { 30 typedef IXMLHTTPRequest2* native_handle; 31 } 32 } // namespace http 33 } // namespace web 34 #else 35 namespace web 36 { 37 namespace http 38 { 39 namespace client 40 { 41 typedef void* native_handle; 42 } 43 } // namespace http 44 } // namespace web 45 #endif // __cplusplus_winrt 46 47 #include "cpprest/asyncrt_utils.h" 48 #include "cpprest/details/basic_types.h" 49 #include "cpprest/details/web_utilities.h" 50 #include "cpprest/http_msg.h" 51 #include "cpprest/json.h" 52 #include "cpprest/uri.h" 53 #include "pplx/pplxtasks.h" 54 #include <limits> 55 #include <memory> 56 57 #if _WIN32_WINNT >= _WIN32_WINNT_VISTA 58 #include "cpprest/oauth1.h" 59 #endif 60 61 #include "cpprest/oauth2.h" 62 63 #if !defined(_WIN32) && !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_CLIENT_ASIO) 64 #if defined(__clang__) 65 #pragma clang diagnostic push 66 #pragma clang diagnostic ignored "-Wconversion" 67 #endif 68 #include "boost/asio/ssl.hpp" 69 #if defined(__clang__) 70 #pragma clang diagnostic pop 71 #endif 72 #endif 73 74 /// The web namespace contains functionality common to multiple protocols like HTTP and WebSockets. 75 namespace web 76 { 77 /// Declarations and functionality for the HTTP protocol. 78 namespace http 79 { 80 /// HTTP client side library. 81 namespace client 82 { 83 // credentials and web_proxy class has been moved from web::http::client namespace to web namespace. 84 // The below using declarations ensure we don't break existing code. 85 // Please use the web::credentials and web::web_proxy class going forward. 86 using web::credentials; 87 using web::web_proxy; 88 89 /// <summary> 90 /// HTTP client configuration class, used to set the possible configuration options 91 /// used to create an http_client instance. 92 /// </summary> 93 class http_client_config 94 { 95 public: http_client_config()96 http_client_config() 97 : m_guarantee_order(false) 98 , m_timeout(std::chrono::seconds(30)) 99 , m_chunksize(0) 100 , m_request_compressed(false) 101 #if !defined(__cplusplus_winrt) 102 , m_validate_certificates(true) 103 #endif 104 #if !defined(_WIN32) && !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_CLIENT_ASIO) 105 , m_tlsext_sni_enabled(true) 106 #endif 107 #if (defined(_WIN32) && !defined(__cplusplus_winrt)) || defined(CPPREST_FORCE_HTTP_CLIENT_WINHTTPPAL) 108 , m_buffer_request(false) 109 #endif 110 , m_max_redirects(10) 111 , m_https_to_http_redirects(false) 112 { 113 } 114 115 #if _WIN32_WINNT >= _WIN32_WINNT_VISTA 116 /// <summary> 117 /// Get OAuth 1.0 configuration. 118 /// </summary> 119 /// <returns>Shared pointer to OAuth 1.0 configuration.</returns> oauth1()120 const std::shared_ptr<oauth1::experimental::oauth1_config> oauth1() const { return m_oauth1; } 121 122 /// <summary> 123 /// Set OAuth 1.0 configuration. 124 /// </summary> 125 /// <param name="config">OAuth 1.0 configuration to set.</param> set_oauth1(oauth1::experimental::oauth1_config config)126 void set_oauth1(oauth1::experimental::oauth1_config config) 127 { 128 m_oauth1 = std::make_shared<oauth1::experimental::oauth1_config>(std::move(config)); 129 } 130 #endif 131 132 /// <summary> 133 /// Get OAuth 2.0 configuration. 134 /// </summary> 135 /// <returns>Shared pointer to OAuth 2.0 configuration.</returns> oauth2()136 const std::shared_ptr<oauth2::experimental::oauth2_config> oauth2() const { return m_oauth2; } 137 138 /// <summary> 139 /// Set OAuth 2.0 configuration. 140 /// </summary> 141 /// <param name="config">OAuth 2.0 configuration to set.</param> set_oauth2(oauth2::experimental::oauth2_config config)142 void set_oauth2(oauth2::experimental::oauth2_config config) 143 { 144 m_oauth2 = std::make_shared<oauth2::experimental::oauth2_config>(std::move(config)); 145 } 146 147 /// <summary> 148 /// Get the web proxy object 149 /// </summary> 150 /// <returns>A reference to the web proxy object.</returns> proxy()151 const web_proxy& proxy() const { return m_proxy; } 152 153 /// <summary> 154 /// Set the web proxy object 155 /// </summary> 156 /// <param name="proxy">A reference to the web proxy object.</param> set_proxy(web_proxy proxy)157 void set_proxy(web_proxy proxy) { m_proxy = std::move(proxy); } 158 159 /// <summary> 160 /// Get the client credentials 161 /// </summary> 162 /// <returns>A reference to the client credentials.</returns> credentials()163 const http::client::credentials& credentials() const { return m_credentials; } 164 165 /// <summary> 166 /// Set the client credentials 167 /// </summary> 168 /// <param name="cred">A reference to the client credentials.</param> set_credentials(const http::client::credentials & cred)169 void set_credentials(const http::client::credentials& cred) { m_credentials = cred; } 170 171 /// <summary> 172 /// Get the 'guarantee order' property 173 /// </summary> 174 /// <returns>The value of the property.</returns> guarantee_order()175 bool guarantee_order() const { return m_guarantee_order; } 176 177 /// <summary> 178 /// Set the 'guarantee order' property 179 /// </summary> 180 /// <param name="guarantee_order">The value of the property.</param> 181 CASABLANCA_DEPRECATED( 182 "Confusing API will be removed in future releases. If you need to order HTTP requests use task continuations.") set_guarantee_order(bool guarantee_order)183 void set_guarantee_order(bool guarantee_order) { m_guarantee_order = guarantee_order; } 184 185 /// <summary> 186 /// Get the timeout 187 /// </summary> 188 /// <returns>The timeout (in seconds) used for each send and receive operation on the client.</returns> timeout()189 utility::seconds timeout() const { return std::chrono::duration_cast<utility::seconds>(m_timeout); } 190 191 /// <summary> 192 /// Get the timeout 193 /// </summary> 194 /// <returns>The timeout (in whatever duration) used for each send and receive operation on the client.</returns> 195 template<class T> timeout()196 T timeout() const 197 { 198 return std::chrono::duration_cast<T>(m_timeout); 199 } 200 /// <summary> 201 /// Set the timeout 202 /// </summary> 203 /// <param name="timeout">The timeout (duration from microseconds range and up) used for each send and receive 204 /// operation on the client.</param> 205 template<class T> set_timeout(const T & timeout)206 void set_timeout(const T& timeout) 207 { 208 m_timeout = std::chrono::duration_cast<std::chrono::microseconds>(timeout); 209 } 210 211 /// <summary> 212 /// Get the client chunk size. 213 /// </summary> 214 /// <returns>The internal buffer size used by the http client when sending and receiving data from the 215 /// network.</returns> chunksize()216 size_t chunksize() const { return m_chunksize == 0 ? 64 * 1024 : m_chunksize; } 217 218 /// <summary> 219 /// Sets the client chunk size. 220 /// </summary> 221 /// <param name="size">The internal buffer size used by the http client when sending and receiving data from the 222 /// network.</param> <remarks>This is a hint -- an implementation may disregard the setting and use some other chunk 223 /// size.</remarks> set_chunksize(size_t size)224 void set_chunksize(size_t size) { m_chunksize = size; } 225 226 /// <summary> 227 /// Returns true if the default chunk size is in use. 228 /// <remarks>If true, implementations are allowed to choose whatever size is best.</remarks> 229 /// </summary> 230 /// <returns>True if default, false if set by user.</returns> is_default_chunksize()231 bool is_default_chunksize() const { return m_chunksize == 0; } 232 233 /// <summary> 234 /// Checks if requesting a compressed response using Content-Encoding is turned on, the default is off. 235 /// </summary> 236 /// <returns>True if a content-encoded compressed response is allowed, false otherwise</returns> request_compressed_response()237 bool request_compressed_response() const { return m_request_compressed; } 238 239 /// <summary> 240 /// Request that the server respond with a compressed body using Content-Encoding; to use Transfer-Encoding, do not 241 /// set this, and specify a vector of <see cref="web::http::details::compression::decompress_factory" /> pointers 242 /// to the set_decompress_factories method of the <see cref="web::http::http_request" /> object for the request. 243 /// If true and the server does not support compression, this will have no effect. 244 /// The response body is internally decompressed before the consumer receives the data. 245 /// </summary> 246 /// <param name="request_compressed">True to turn on content-encoded response body compression, false 247 /// otherwise.</param> <remarks>Please note there is a performance cost due to copying the request data. Currently 248 /// only supported on Windows and OSX.</remarks> set_request_compressed_response(bool request_compressed)249 void set_request_compressed_response(bool request_compressed) { m_request_compressed = request_compressed; } 250 251 #if !defined(__cplusplus_winrt) 252 /// <summary> 253 /// Gets the server certificate validation property. 254 /// </summary> 255 /// <returns>True if certificates are to be verified, false otherwise.</returns> validate_certificates()256 bool validate_certificates() const { return m_validate_certificates; } 257 258 /// <summary> 259 /// Sets the server certificate validation property. 260 /// </summary> 261 /// <param name="validate_certs">False to turn ignore all server certificate validation errors, true 262 /// otherwise.</param> <remarks>Note ignoring certificate errors can be dangerous and should be done with 263 /// caution.</remarks> set_validate_certificates(bool validate_certs)264 void set_validate_certificates(bool validate_certs) { m_validate_certificates = validate_certs; } 265 #endif 266 267 #if (defined(_WIN32) && !defined(__cplusplus_winrt)) || defined(CPPREST_FORCE_HTTP_CLIENT_WINHTTPPAL) 268 /// <summary> 269 /// Checks if request data buffering is turned on, the default is off. 270 /// </summary> 271 /// <returns>True if buffering is enabled, false otherwise</returns> buffer_request()272 bool buffer_request() const { return m_buffer_request; } 273 274 /// <summary> 275 /// Sets the request buffering property. 276 /// If true, in cases where the request body/stream doesn't support seeking the request data will be buffered. 277 /// This can help in situations where an authentication challenge might be expected. 278 /// </summary> 279 /// <param name="buffer_request">True to turn on buffer, false otherwise.</param> 280 /// <remarks>Please note there is a performance cost due to copying the request data.</remarks> set_buffer_request(bool buffer_request)281 void set_buffer_request(bool buffer_request) { m_buffer_request = buffer_request; } 282 #endif 283 284 /// <summary> 285 /// Get the maximum number of redirects to follow automatically. 286 /// A value of 0 indicates that no automatic redirection is performed. 287 /// </summary> 288 /// <returns>The maximum number of redirects to follow automatically.</returns> 289 /// <remarks>This is a hint -- an implementation may enforce a lower value.</remarks> max_redirects()290 size_t max_redirects() const { return m_max_redirects; } 291 292 /// <summary> 293 /// Set the maximum number of redirects to follow automatically. 294 /// A value of 0 indicates that no automatic redirection is performed. 295 /// </summary> 296 /// <param name="max_redirects">The maximum number of redirects to follow automatically.</param> 297 /// <remarks>This is a hint -- an implementation may enforce a lower value.</remarks> set_max_redirects(size_t max_redirects)298 void set_max_redirects(size_t max_redirects) { m_max_redirects = max_redirects; } 299 300 /// <summary> 301 /// Checks if HTTPS to HTTP redirects are automatically followed. 302 /// </summary> 303 /// <returns>True if HTTPS to HTTP redirects are automatically followed, false otherwise.</returns> https_to_http_redirects()304 bool https_to_http_redirects() const { return m_https_to_http_redirects; } 305 306 /// <summary> 307 /// Sets if HTTPS to HTTP redirects are automatically followed. 308 /// </summary> 309 /// <param name="https_to_http_redirects">True if HTTPS to HTTP redirects are to be automatically 310 /// followed, false otherwise.</param> set_https_to_http_redirects(bool https_to_http_redirects)311 void set_https_to_http_redirects(bool https_to_http_redirects) 312 { 313 m_https_to_http_redirects = https_to_http_redirects; 314 } 315 316 /// <summary> 317 /// Sets a callback to enable custom setting of platform specific options. 318 /// </summary> 319 /// <remarks> 320 /// The native_handle is the following type depending on the underlying platform: 321 /// Windows Desktop, WinHTTP - HINTERNET (session) 322 /// </remarks> 323 /// <param name="callback">A user callback allowing for customization of the session</param> set_nativesessionhandle_options(const std::function<void (native_handle)> & callback)324 void set_nativesessionhandle_options(const std::function<void(native_handle)>& callback) 325 { 326 m_set_user_nativesessionhandle_options = callback; 327 } 328 329 /// <summary> 330 /// Invokes a user's callback to allow for customization of the session. 331 /// </summary> 332 /// <remarks>Internal Use Only</remarks> 333 /// <param name="handle">A internal implementation handle.</param> _invoke_nativesessionhandle_options(native_handle handle)334 void _invoke_nativesessionhandle_options(native_handle handle) const 335 { 336 if (m_set_user_nativesessionhandle_options) m_set_user_nativesessionhandle_options(handle); 337 } 338 339 /// <summary> 340 /// Sets a callback to enable custom setting of platform specific options. 341 /// </summary> 342 /// <remarks> 343 /// The native_handle is the following type depending on the underlying platform: 344 /// Windows Desktop, WinHTTP - HINTERNET 345 /// Windows Runtime, WinRT - IXMLHTTPRequest2 * 346 /// All other platforms, Boost.Asio: 347 /// https - boost::asio::ssl::stream<boost::asio::ip::tcp::socket &> * 348 /// http - boost::asio::ip::tcp::socket * 349 /// </remarks> 350 /// <param name="callback">A user callback allowing for customization of the request</param> set_nativehandle_options(const std::function<void (native_handle)> & callback)351 void set_nativehandle_options(const std::function<void(native_handle)>& callback) 352 { 353 m_set_user_nativehandle_options = callback; 354 } 355 356 /// <summary> 357 /// Invokes a user's callback to allow for customization of the request. 358 /// </summary> 359 /// <param name="handle">A internal implementation handle.</param> invoke_nativehandle_options(native_handle handle)360 void invoke_nativehandle_options(native_handle handle) const 361 { 362 if (m_set_user_nativehandle_options) m_set_user_nativehandle_options(handle); 363 } 364 365 #if !defined(_WIN32) && !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_CLIENT_ASIO) 366 /// <summary> 367 /// Sets a callback to enable custom setting of the ssl context, at construction time. 368 /// </summary> 369 /// <param name="callback">A user callback allowing for customization of the ssl context at construction 370 /// time.</param> set_ssl_context_callback(const std::function<void (boost::asio::ssl::context &)> & callback)371 void set_ssl_context_callback(const std::function<void(boost::asio::ssl::context&)>& callback) 372 { 373 m_ssl_context_callback = callback; 374 } 375 376 /// <summary> 377 /// Gets the user's callback to allow for customization of the ssl context. 378 /// </summary> get_ssl_context_callback()379 const std::function<void(boost::asio::ssl::context&)>& get_ssl_context_callback() const 380 { 381 return m_ssl_context_callback; 382 } 383 384 /// <summary> 385 /// Gets the TLS extension server name indication (SNI) status. 386 /// </summary> 387 /// <returns>True if TLS server name indication is enabled, false otherwise.</returns> is_tlsext_sni_enabled()388 bool is_tlsext_sni_enabled() const { return m_tlsext_sni_enabled; } 389 390 /// <summary> 391 /// Sets the TLS extension server name indication (SNI) status. 392 /// </summary> 393 /// <param name="tlsext_sni_enabled">False to disable the TLS (ClientHello) extension for server name indication, 394 /// true otherwise.</param> <remarks>Note: This setting is enabled by default as it is required in most virtual 395 /// hosting scenarios.</remarks> set_tlsext_sni_enabled(bool tlsext_sni_enabled)396 void set_tlsext_sni_enabled(bool tlsext_sni_enabled) { m_tlsext_sni_enabled = tlsext_sni_enabled; } 397 #endif 398 399 private: 400 #if _WIN32_WINNT >= _WIN32_WINNT_VISTA 401 std::shared_ptr<oauth1::experimental::oauth1_config> m_oauth1; 402 #endif 403 404 std::shared_ptr<oauth2::experimental::oauth2_config> m_oauth2; 405 web_proxy m_proxy; 406 http::client::credentials m_credentials; 407 // Whether or not to guarantee ordering, i.e. only using one underlying TCP connection. 408 bool m_guarantee_order; 409 410 std::chrono::microseconds m_timeout; 411 size_t m_chunksize; 412 bool m_request_compressed; 413 414 #if !defined(__cplusplus_winrt) 415 // IXmlHttpRequest2 doesn't allow configuration of certificate verification. 416 bool m_validate_certificates; 417 #endif 418 419 std::function<void(native_handle)> m_set_user_nativehandle_options; 420 std::function<void(native_handle)> m_set_user_nativesessionhandle_options; 421 422 #if !defined(_WIN32) && !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_CLIENT_ASIO) 423 std::function<void(boost::asio::ssl::context&)> m_ssl_context_callback; 424 bool m_tlsext_sni_enabled; 425 #endif 426 #if (defined(_WIN32) && !defined(__cplusplus_winrt)) || defined(CPPREST_FORCE_HTTP_CLIENT_WINHTTPPAL) 427 bool m_buffer_request; 428 #endif 429 430 size_t m_max_redirects; 431 bool m_https_to_http_redirects; 432 }; 433 434 class http_pipeline; 435 436 /// <summary> 437 /// HTTP client class, used to maintain a connection to an HTTP service for an extended session. 438 /// </summary> 439 class http_client 440 { 441 public: 442 /// <summary> 443 /// Creates a new http_client connected to specified uri. 444 /// </summary> 445 /// <param name="base_uri">A string representation of the base uri to be used for all requests. Must start with 446 /// either "http://" or "https://"</param> 447 _ASYNCRTIMP http_client(const uri& base_uri); 448 449 /// <summary> 450 /// Creates a new http_client connected to specified uri. 451 /// </summary> 452 /// <param name="base_uri">A string representation of the base uri to be used for all requests. Must start with 453 /// either "http://" or "https://"</param> <param name="client_config">The http client configuration object 454 /// containing the possible configuration options to initialize the <c>http_client</c>. </param> 455 _ASYNCRTIMP http_client(const uri& base_uri, const http_client_config& client_config); 456 457 /// <summary> 458 /// Note the destructor doesn't necessarily close the connection and release resources. 459 /// The connection is reference counted with the http_responses. 460 /// </summary> 461 _ASYNCRTIMP ~http_client() CPPREST_NOEXCEPT; 462 463 /// <summary> 464 /// Gets the base URI. 465 /// </summary> 466 /// <returns> 467 /// A base URI initialized in constructor 468 /// </returns> 469 _ASYNCRTIMP const uri& base_uri() const; 470 471 /// <summary> 472 /// Get client configuration object 473 /// </summary> 474 /// <returns>A reference to the client configuration object.</returns> 475 _ASYNCRTIMP const http_client_config& client_config() const; 476 477 /// <summary> 478 /// Adds an HTTP pipeline stage to the client. 479 /// </summary> 480 /// <param name="handler">A function object representing the pipeline stage.</param> 481 _ASYNCRTIMP void add_handler(const std::function<pplx::task<http_response> __cdecl( 482 http_request, std::shared_ptr<http::http_pipeline_stage>)>& handler); 483 484 /// <summary> 485 /// Adds an HTTP pipeline stage to the client. 486 /// </summary> 487 /// <param name="stage">A shared pointer to a pipeline stage.</param> 488 _ASYNCRTIMP void add_handler(const std::shared_ptr<http::http_pipeline_stage>& stage); 489 490 /// <summary> 491 /// Asynchronously sends an HTTP request. 492 /// </summary> 493 /// <param name="request">Request to send.</param> 494 /// <param name="token">Cancellation token for cancellation of this request operation.</param> 495 /// <returns>An asynchronous operation that is completed once a response from the request is received.</returns> 496 _ASYNCRTIMP pplx::task<http_response> request( 497 http_request request, const pplx::cancellation_token& token = pplx::cancellation_token::none()); 498 499 /// <summary> 500 /// Asynchronously sends an HTTP request. 501 /// </summary> 502 /// <param name="mtd">HTTP request method.</param> 503 /// <param name="token">Cancellation token for cancellation of this request operation.</param> 504 /// <returns>An asynchronous operation that is completed once a response from the request is received.</returns> 505 pplx::task<http_response> request(const method& mtd, 506 const pplx::cancellation_token& token = pplx::cancellation_token::none()) 507 { 508 http_request msg(mtd); 509 return request(msg, token); 510 } 511 512 /// <summary> 513 /// Asynchronously sends an HTTP request. 514 /// </summary> 515 /// <param name="mtd">HTTP request method.</param> 516 /// <param name="path_query_fragment">String containing the path, query, and fragment, relative to the http_client's 517 /// base URI.</param> <param name="token">Cancellation token for cancellation of this request operation.</param> 518 /// <returns>An asynchronous operation that is completed once a response from the request is received.</returns> 519 pplx::task<http_response> request(const method& mtd, 520 const utility::string_t& path_query_fragment, 521 const pplx::cancellation_token& token = pplx::cancellation_token::none()) 522 { 523 http_request msg(mtd); 524 msg.set_request_uri(path_query_fragment); 525 return request(msg, token); 526 } 527 528 /// <summary> 529 /// Asynchronously sends an HTTP request. 530 /// </summary> 531 /// <param name="mtd">HTTP request method.</param> 532 /// <param name="path_query_fragment">String containing the path, query, and fragment, relative to the http_client's 533 /// base URI.</param> <param name="body_data">The data to be used as the message body, represented using the json 534 /// object library.</param> <param name="token">Cancellation token for cancellation of this request 535 /// operation.</param> <returns>An asynchronous operation that is completed once a response from the request is 536 /// received.</returns> 537 pplx::task<http_response> request(const method& mtd, 538 const utility::string_t& path_query_fragment, 539 const json::value& body_data, 540 const pplx::cancellation_token& token = pplx::cancellation_token::none()) 541 { 542 http_request msg(mtd); 543 msg.set_request_uri(path_query_fragment); 544 msg.set_body(body_data); 545 return request(msg, token); 546 } 547 548 /// <summary> 549 /// Asynchronously sends an HTTP request with a string body. Assumes the 550 /// character encoding of the string is UTF-8. 551 /// </summary> 552 /// <param name="mtd">HTTP request method.</param> 553 /// <param name="path_query_fragment">String containing the path, query, and fragment, relative to the http_client's 554 /// base URI.</param> <param name="content_type">A string holding the MIME type of the message body.</param> <param 555 /// name="body_data">String containing the text to use in the message body.</param> <param name="token">Cancellation 556 /// token for cancellation of this request operation.</param> <returns>An asynchronous operation that is completed 557 /// once a response from the request is received.</returns> 558 pplx::task<http_response> request(const method& mtd, 559 const utf8string& path_query_fragment, 560 const utf8string& body_data, 561 const utf8string& content_type = "text/plain; charset=utf-8", 562 const pplx::cancellation_token& token = pplx::cancellation_token::none()) 563 { 564 http_request msg(mtd); 565 msg.set_request_uri(::utility::conversions::to_string_t(path_query_fragment)); 566 msg.set_body(body_data, content_type); 567 return request(msg, token); 568 } 569 570 /// <summary> 571 /// Asynchronously sends an HTTP request with a string body. Assumes the 572 /// character encoding of the string is UTF-8. 573 /// </summary> 574 /// <param name="mtd">HTTP request method.</param> 575 /// <param name="path_query_fragment">String containing the path, query, and fragment, relative to the http_client's 576 /// base URI.</param> <param name="content_type">A string holding the MIME type of the message body.</param> <param 577 /// name="body_data">String containing the text to use in the message body.</param> <param name="token">Cancellation 578 /// token for cancellation of this request operation.</param> <returns>An asynchronous operation that is completed 579 /// once a response from the request is received.</returns> 580 pplx::task<http_response> request(const method& mtd, 581 const utf8string& path_query_fragment, 582 utf8string&& body_data, 583 const utf8string& content_type = "text/plain; charset=utf-8", 584 const pplx::cancellation_token& token = pplx::cancellation_token::none()) 585 { 586 http_request msg(mtd); 587 msg.set_request_uri(::utility::conversions::to_string_t(path_query_fragment)); 588 msg.set_body(std::move(body_data), content_type); 589 return request(msg, token); 590 } 591 592 /// <summary> 593 /// Asynchronously sends an HTTP request with a string body. Assumes the 594 /// character encoding of the string is UTF-16 will perform conversion to UTF-8. 595 /// </summary> 596 /// <param name="mtd">HTTP request method.</param> 597 /// <param name="path_query_fragment">String containing the path, query, and fragment, relative to the http_client's 598 /// base URI.</param> <param name="content_type">A string holding the MIME type of the message body.</param> <param 599 /// name="body_data">String containing the text to use in the message body.</param> <param name="token">Cancellation 600 /// token for cancellation of this request operation.</param> <returns>An asynchronous operation that is completed 601 /// once a response from the request is received.</returns> 602 pplx::task<http_response> request( 603 const method& mtd, 604 const utf16string& path_query_fragment, 605 const utf16string& body_data, 606 const utf16string& content_type = utility::conversions::to_utf16string("text/plain"), 607 const pplx::cancellation_token& token = pplx::cancellation_token::none()) 608 { 609 http_request msg(mtd); 610 msg.set_request_uri(::utility::conversions::to_string_t(path_query_fragment)); 611 msg.set_body(body_data, content_type); 612 return request(msg, token); 613 } 614 615 /// <summary> 616 /// Asynchronously sends an HTTP request with a string body. Assumes the 617 /// character encoding of the string is UTF-8. 618 /// </summary> 619 /// <param name="mtd">HTTP request method.</param> 620 /// <param name="path_query_fragment">String containing the path, query, and fragment, relative to the http_client's 621 /// base URI.</param> <param name="body_data">String containing the text to use in the message body.</param> <param 622 /// name="token">Cancellation token for cancellation of this request operation.</param> <returns>An asynchronous 623 /// operation that is completed once a response from the request is received.</returns> request(const method & mtd,const utf8string & path_query_fragment,const utf8string & body_data,const pplx::cancellation_token & token)624 pplx::task<http_response> request(const method& mtd, 625 const utf8string& path_query_fragment, 626 const utf8string& body_data, 627 const pplx::cancellation_token& token) 628 { 629 return request(mtd, path_query_fragment, body_data, "text/plain; charset=utf-8", token); 630 } 631 632 /// <summary> 633 /// Asynchronously sends an HTTP request with a string body. Assumes the 634 /// character encoding of the string is UTF-8. 635 /// </summary> 636 /// <param name="mtd">HTTP request method.</param> 637 /// <param name="path_query_fragment">String containing the path, query, and fragment, relative to the http_client's 638 /// base URI.</param> <param name="body_data">String containing the text to use in the message body.</param> <param 639 /// name="token">Cancellation token for cancellation of this request operation.</param> <returns>An asynchronous 640 /// operation that is completed once a response from the request is received.</returns> request(const method & mtd,const utf8string & path_query_fragment,utf8string && body_data,const pplx::cancellation_token & token)641 pplx::task<http_response> request(const method& mtd, 642 const utf8string& path_query_fragment, 643 utf8string&& body_data, 644 const pplx::cancellation_token& token) 645 { 646 http_request msg(mtd); 647 msg.set_request_uri(::utility::conversions::to_string_t(path_query_fragment)); 648 msg.set_body(std::move(body_data), "text/plain; charset=utf-8"); 649 return request(msg, token); 650 } 651 652 /// <summary> 653 /// Asynchronously sends an HTTP request with a string body. Assumes 654 /// the character encoding of the string is UTF-16 will perform conversion to UTF-8. 655 /// </summary> 656 /// <param name="mtd">HTTP request method.</param> 657 /// <param name="path_query_fragment">String containing the path, query, and fragment, relative to the http_client's 658 /// base URI.</param> <param name="body_data">String containing the text to use in the message body.</param> <param 659 /// name="token">Cancellation token for cancellation of this request operation.</param> <returns>An asynchronous 660 /// operation that is completed once a response from the request is received.</returns> request(const method & mtd,const utf16string & path_query_fragment,const utf16string & body_data,const pplx::cancellation_token & token)661 pplx::task<http_response> request(const method& mtd, 662 const utf16string& path_query_fragment, 663 const utf16string& body_data, 664 const pplx::cancellation_token& token) 665 { 666 return request( 667 mtd, path_query_fragment, body_data, ::utility::conversions::to_utf16string("text/plain"), token); 668 } 669 670 #if !defined(__cplusplus_winrt) 671 /// <summary> 672 /// Asynchronously sends an HTTP request. 673 /// </summary> 674 /// <param name="mtd">HTTP request method.</param> 675 /// <param name="path_query_fragment">String containing the path, query, and fragment, relative to the http_client's 676 /// base URI.</param> <param name="body">An asynchronous stream representing the body data.</param> <param 677 /// name="content_type">A string holding the MIME type of the message body.</param> <param name="token">Cancellation 678 /// token for cancellation of this request operation.</param> <returns>A task that is completed once a response from 679 /// the request is received.</returns> 680 pplx::task<http_response> request(const method& mtd, 681 const utility::string_t& path_query_fragment, 682 const concurrency::streams::istream& body, 683 const utility::string_t& content_type = _XPLATSTR("application/octet-stream"), 684 const pplx::cancellation_token& token = pplx::cancellation_token::none()) 685 { 686 http_request msg(mtd); 687 msg.set_request_uri(path_query_fragment); 688 msg.set_body(body, content_type); 689 return request(msg, token); 690 } 691 692 /// <summary> 693 /// Asynchronously sends an HTTP request. 694 /// </summary> 695 /// <param name="mtd">HTTP request method.</param> 696 /// <param name="path_query_fragment">String containing the path, query, and fragment, relative to the http_client's 697 /// base URI.</param> <param name="body">An asynchronous stream representing the body data.</param> <param 698 /// name="token">Cancellation token for cancellation of this request operation.</param> <returns>A task that is 699 /// completed once a response from the request is received.</returns> request(const method & mtd,const utility::string_t & path_query_fragment,const concurrency::streams::istream & body,const pplx::cancellation_token & token)700 pplx::task<http_response> request(const method& mtd, 701 const utility::string_t& path_query_fragment, 702 const concurrency::streams::istream& body, 703 const pplx::cancellation_token& token) 704 { 705 return request(mtd, path_query_fragment, body, _XPLATSTR("application/octet-stream"), token); 706 } 707 #endif // __cplusplus_winrt 708 709 /// <summary> 710 /// Asynchronously sends an HTTP request. 711 /// </summary> 712 /// <param name="mtd">HTTP request method.</param> 713 /// <param name="path_query_fragment">String containing the path, query, and fragment, relative to the http_client's 714 /// base URI.</param> <param name="body">An asynchronous stream representing the body data.</param> <param 715 /// name="content_length">Size of the message body.</param> <param name="content_type">A string holding the MIME 716 /// type of the message body.</param> <param name="token">Cancellation token for cancellation of this request 717 /// operation.</param> <returns>A task that is completed once a response from the request is received.</returns> 718 /// <remarks>Winrt requires to provide content_length.</remarks> 719 pplx::task<http_response> request(const method& mtd, 720 const utility::string_t& path_query_fragment, 721 const concurrency::streams::istream& body, 722 size_t content_length, 723 const utility::string_t& content_type = _XPLATSTR("application/octet-stream"), 724 const pplx::cancellation_token& token = pplx::cancellation_token::none()) 725 { 726 http_request msg(mtd); 727 msg.set_request_uri(path_query_fragment); 728 msg.set_body(body, content_length, content_type); 729 return request(msg, token); 730 } 731 732 /// <summary> 733 /// Asynchronously sends an HTTP request. 734 /// </summary> 735 /// <param name="mtd">HTTP request method.</param> 736 /// <param name="path_query_fragment">String containing the path, query, and fragment, relative to the http_client's 737 /// base URI.</param> <param name="body">An asynchronous stream representing the body data.</param> <param 738 /// name="content_length">Size of the message body.</param> <param name="token">Cancellation token for cancellation 739 /// of this request operation.</param> <returns>A task that is completed once a response from the request is 740 /// received.</returns> <remarks>Winrt requires to provide content_length.</remarks> 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)741 pplx::task<http_response> request(const method& mtd, 742 const utility::string_t& path_query_fragment, 743 const concurrency::streams::istream& body, 744 size_t content_length, 745 const pplx::cancellation_token& token) 746 { 747 return request(mtd, path_query_fragment, body, content_length, _XPLATSTR("application/octet-stream"), token); 748 } 749 750 private: 751 std::shared_ptr<::web::http::client::http_pipeline> m_pipeline; 752 }; 753 754 namespace details 755 { 756 #if defined(_WIN32) || defined(CPPREST_FORCE_HTTP_CLIENT_WINHTTPPAL) 757 extern const utility::char_t* get_with_body_err_msg; 758 #endif 759 760 } // namespace details 761 762 } // namespace client 763 } // namespace http 764 } // namespace web 765 766 #endif 767