1 #ifndef CONNECT___NCBI_HTTP_SESSION__HPP 2 #define CONNECT___NCBI_HTTP_SESSION__HPP 3 4 /* $Id: ncbi_http_session.hpp 612999 2020-07-30 19:22:55Z sadyrovr $ 5 * =========================================================================== 6 * 7 * PUBLIC DOMAIN NOTICE 8 * National Center for Biotechnology Information 9 * 10 * This software/database is a "United States Government Work" under the 11 * terms of the United States Copyright Act. It was written as part of 12 * the author's official duties as a United States Government employee and 13 * thus cannot be copyrighted. This software/database is freely available 14 * to the public for use. The National Library of Medicine and the U.S. 15 * Government have not placed any restriction on its use or reproduction. 16 * 17 * Although all reasonable efforts have been taken to ensure the accuracy 18 * and reliability of the software and data, the NLM and the U.S. 19 * Government do not and cannot warrant the performance or results that 20 * may be obtained by using this software or data. The NLM and the U.S. 21 * Government disclaim all warranties, express or implied, including 22 * warranties of performance, merchantability or fitness for any particular 23 * purpose. 24 * 25 * Please cite the author in any work or product based on this material. 26 * 27 * =========================================================================== 28 * 29 * Author: Aleksey Grichenko 30 * 31 * File Description: 32 * CHttpSession class supporting different types of requests/responses, 33 * headers/cookies/sessions management etc. 34 * 35 */ 36 37 #include <corelib/ncbi_cookies.hpp> 38 #include <connect/ncbi_conn_stream.hpp> 39 40 41 /** @addtogroup HttpSession 42 * 43 * @{ 44 */ 45 46 47 BEGIN_NCBI_SCOPE 48 49 50 // Forward declarations for shortcut functions. 51 class CHttpResponse; 52 class CHttpHeaders; 53 54 55 // Default retries value. 56 struct SGetHttpDefaultRetries 57 { 58 unsigned short operator()(void) const; 59 }; 60 61 /// Nullable retries for CHttpRequest 62 typedef CNullable<unsigned short, SGetHttpDefaultRetries> THttpRetries; 63 64 65 /// Shortcut for GET request. Each request uses a separate session, 66 /// no data like cookies is shared between multiple requests. 67 /// @sa CHttpSession::Get() 68 NCBI_XCONNECT_EXPORT 69 CHttpResponse g_HttpGet(const CUrl& url, 70 const CTimeout& timeout = CTimeout(CTimeout::eDefault), 71 THttpRetries retries = null); 72 73 /// Shortcut for GET request with custom headers. Each request uses a separate 74 /// session, no data like cookies is shared between multiple requests. 75 /// @sa CHttpSession::Get() 76 NCBI_XCONNECT_EXPORT 77 CHttpResponse g_HttpGet(const CUrl& url, 78 const CHttpHeaders& headers, 79 const CTimeout& timeout = CTimeout(CTimeout::eDefault), 80 THttpRetries retries = null); 81 82 /// Shortcut for POST request. Each request uses a separate session, 83 /// no data like cookies is shared between multiple requests. 84 /// @sa CHttpSession::Post() 85 NCBI_XCONNECT_EXPORT 86 CHttpResponse g_HttpPost(const CUrl& url, 87 CTempString data, 88 CTempString content_type = CTempString(), 89 const CTimeout& timeout = CTimeout(CTimeout::eDefault), 90 THttpRetries retries = null); 91 92 /// Shortcut for POST request with custom headers. Each request uses a separate 93 /// session, no data like cookies is shared between multiple requests. 94 /// @sa CHttpSession::Post() 95 NCBI_XCONNECT_EXPORT 96 CHttpResponse g_HttpPost(const CUrl& url, 97 const CHttpHeaders& headers, 98 CTempString data, 99 CTempString content_type = CTempString(), 100 const CTimeout& timeout = CTimeout(CTimeout::eDefault), 101 THttpRetries retries = null); 102 103 /// Shortcut for PUT request. Each request uses a separate session, 104 /// no data like cookies is shared between multiple requests. 105 /// @sa CHttpSession::Put() 106 NCBI_XCONNECT_EXPORT 107 CHttpResponse g_HttpPut(const CUrl& url, 108 CTempString data, 109 CTempString content_type = CTempString(), 110 const CTimeout& timeout = CTimeout(CTimeout::eDefault), 111 THttpRetries retries = null); 112 113 /// Shortcut for PUT request with custom headers. Each request uses a separate 114 /// session, no data like cookies is shared between multiple requests. 115 /// @sa CHttpSession::Put() 116 NCBI_XCONNECT_EXPORT 117 CHttpResponse g_HttpPut(const CUrl& url, 118 const CHttpHeaders& headers, 119 CTempString data, 120 CTempString content_type = CTempString(), 121 const CTimeout& timeout = CTimeout(CTimeout::eDefault), 122 THttpRetries retries = null); 123 124 class CHttpSession_Base; 125 126 127 class NCBI_XCONNECT_EXPORT CHttpHeaders : public CObject 128 { 129 public: 130 /// Create empty headers list. CHttpHeaders(void)131 CHttpHeaders(void) {} 132 133 /// Some standard HTTP headers. 134 enum EHeaderName { 135 eCacheControl = 0, 136 eContentLength, 137 eContentType, 138 eCookie, 139 eDate, 140 eExpires, 141 eLocation, 142 eRange, 143 eReferer, 144 eSetCookie, 145 eUserAgent, 146 eHost 147 }; 148 149 /// Helper class allowing to use both strings and enums as header names. 150 /// The class should not be used explicitly - all conversions are automatic. 151 class CHeaderNameConverter { 152 public: CHeaderNameConverter(const char * name)153 CHeaderNameConverter(const char* name) 154 : m_Name(name) {} CHeaderNameConverter(const string & name)155 CHeaderNameConverter(const string& name) 156 : m_Name(name) {} CHeaderNameConverter(CTempString name)157 CHeaderNameConverter(CTempString name) 158 : m_Name(name) {} CHeaderNameConverter(CHttpHeaders::EHeaderName name)159 CHeaderNameConverter(CHttpHeaders::EHeaderName name) 160 : m_Name(CHttpHeaders::GetHeaderName(name)) {} GetName(void)161 CTempString GetName(void) { return m_Name; } 162 private: 163 CTempString m_Name; 164 }; 165 166 /// List of header values (may be required for headers with multiple values 167 /// like Cookie). 168 typedef vector<string> THeaderValues; 169 /// Map of header name-values, case-insensitive. 170 typedef map<string, THeaderValues, PNocase> THeaders; 171 172 /// Check if there's at least one header with the name. 173 bool HasValue(CHeaderNameConverter name) const; 174 175 /// Get number of values with the given name. 176 size_t CountValues(CHeaderNameConverter name) const; 177 178 /// Get value of the header or empty string. If multiple values 179 /// exist, return the last one. 180 const string& GetValue(CHeaderNameConverter name) const; 181 182 /// Get all values with the given name. 183 const THeaderValues& GetAllValues(CHeaderNameConverter name) const; 184 185 /// Remove all existing values with the name, set the new value. 186 /// Throw exception if the name is a reserved one and can not be 187 /// set directly (NCBI-SID, NCBI-PHID). These values should be 188 /// set through CRequestContext, the headers will be added by 189 /// CConn_HttpStream automatically. 190 void SetValue(CHeaderNameConverter name, CTempString value); 191 192 /// Add new value with the name (multiple values are allowed with 193 /// the same name, the order is preserved). 194 /// Throw exception if the name is a reserved one and can not be 195 /// set directly (NCBI-SID, NCBI-PHID). These values should be 196 /// set through CRequestContext, the headers will be added by 197 /// CConn_HttpStream automatically. 198 void AddValue(CHeaderNameConverter name, CTempString value); 199 200 /// Remove all values with the given name. 201 void Clear(CHeaderNameConverter name); 202 203 /// Remove all headers. 204 void ClearAll(void); 205 206 /// Clear any existing values and copy all headers from 'headers' 207 /// to this object. 208 void Assign(const CHttpHeaders& headers); 209 210 /// Add values from 'headers' to this object. When merging values 211 /// with the same name, the new values are added after the existing 212 /// ones, so that the new values have higher priority. 213 void Merge(const CHttpHeaders& headers); 214 ~CHttpHeaders(void)215 virtual ~CHttpHeaders(void) {} 216 217 private: 218 friend class CHttpResponse; 219 friend class CHttpRequest; 220 221 // Prohibit copying headers. 222 CHttpHeaders(const CHttpHeaders&); 223 CHttpHeaders& operator=(const CHttpHeaders&); 224 225 // Check if the name is a reserved one (NCBI-SID, NCBI-PHID). 226 // If yes, log error - these headers must be set in 227 // CRequestContext, not directly. 228 // Return 'false' if the header name is not reserved and a value can 229 // be set safely. 230 bool x_IsReservedHeader(CTempString name) const; 231 232 THeaders m_Headers; 233 234 public: 235 /// Parse headers from the string (usually provided by a stream callback). 236 /// The new headers are added to the existing ones. 237 void ParseHttpHeader(const CTempString& headers); 238 239 /// Get all headers as a single string as required by CConn_HttpStream. 240 /// Each header line is terminated by a single HTTP_EOL. 241 string GetHttpHeader(void) const; 242 Get() const243 const THeaders& Get() const { return m_Headers; } 244 245 /// Get string representation of the given name. 246 static const char* GetHeaderName(EHeaderName name); 247 }; 248 249 250 /// Interface for custom form data providers. 251 class NCBI_XCONNECT_EXPORT CFormDataProvider_Base : public CObject 252 { 253 public: 254 /// Get content type. Returns empty string by default, indicating 255 /// no Content-Type header should be used for the part. GetContentType(void) const256 virtual string GetContentType(void) const { return string(); } 257 258 /// Get optional filename to be shown in Content-Disposition header. GetFileName(void) const259 virtual string GetFileName(void) const { return string(); } 260 261 /// Write user data to the stream. 262 virtual void WriteData(CNcbiOstream& out) const = 0; 263 ~CFormDataProvider_Base(void)264 virtual ~CFormDataProvider_Base(void) {} 265 }; 266 267 268 /// POST request data 269 class NCBI_XCONNECT_EXPORT CHttpFormData : public CObject 270 { 271 public: 272 /// Supported content types for POST requests. 273 enum EContentType { 274 eFormUrlEncoded, ///< 'application/x-www-form-urlencoded', default 275 eMultipartFormData ///< 'multipart/form-data' 276 }; 277 278 /// Add name=value pair. The data of this type can be sent using either 279 /// eFormUrlEncoded or eMultipartFormData content types. 280 /// @param entry_name 281 /// Name of the form input. The name must not be empty, otherwise an 282 /// exception is thrown. Multiple values with the same name are allowed. 283 /// @param value 284 /// Value for the input. If the form content type is eFormUrlEncoded, 285 /// the value will be URL encoded properly. Otherwise the value is sent as-is. 286 /// URL-encoded form data allows only one value per entry, otherwise 287 /// exception will be thrown when sending the data. 288 /// @param content_type 289 /// Content type for the entry used if the form content type is 290 /// eMultipartFormData. If not set, the protocol assumes 'text/plain' 291 /// content type. Not used when sending eFormUrlEncoded content. 292 void AddEntry(CTempString entry_name, 293 CTempString value, 294 CTempString content_type = CTempString()); 295 296 /// Add file entry. The form content type is automatically set to 297 /// eMultipartFormData and can not be changed later. 298 /// @param entry_name 299 /// Name of the form input responsible for selecting files. Multiple 300 /// files can be added with the same entry name. The name must not be 301 /// empty, otherwise an exception is thrown. 302 /// @param file_name 303 /// Path to the local file to be sent. The file must exist and be 304 /// readable during the call to WriteFormData, otherwise an exception 305 /// will be thrown. 306 /// @param content_type 307 /// Can be used to set content type for each file. If not set, the 308 /// protocol assumes it to be 'application/octet-stream'. 309 void AddFile(CTempString entry_name, 310 CTempString file_name, 311 CTempString content_type = CTempString()); 312 313 /// Add custom data provider. The data written by the provider is 314 /// properly prefixed with Content-Disposition, boundary, Content-Type etc. 315 /// The form content type is automatically set to eMultipartFormData and 316 /// can not be changed later. 317 /// @param entry_name 318 /// Name of the form input responsible for the data. Multiple providers 319 /// can be added with the same entry name. The name must not be empty, 320 /// otherwise an exception is thrown. 321 /// @param provider 322 /// An instance of CFormDataProvider_Base derived class. The object must 323 /// be created in heap. 324 void AddProvider(CTempString entry_name, 325 CFormDataProvider_Base* provider); 326 327 /// Check if the form data is empty (no entries have been added). 328 bool IsEmpty(void) const; 329 330 /// Clear all form data, reset content type to the default eFormUrlEncoded. 331 void Clear(void); 332 333 /// Write form data to the stream using the selected form content type. 334 /// If the data is not valid (e.g. a file does not exist or can not be 335 /// read), throw CHttpSessionException. 336 void WriteFormData(CNcbiOstream& out) const; 337 338 /// Get current content type. GetContentType(void) const339 EContentType GetContentType(void) const { return m_ContentType; } 340 /// Set content type for the form data. If the new content type conflicts 341 /// with the types of entries already added, throw an exception (e.g. 342 /// files/providers require eMultipartFormData content type). 343 /// @note Content types for individual entries can be set when adding 344 /// an entry (see AddEntry, AddFile, AddProvider). 345 void SetContentType(EContentType content_type); 346 ~CHttpFormData(void)347 virtual ~CHttpFormData(void) {} 348 349 private: 350 friend class CHttpRequest; 351 352 // Create new data object. The default content type is eFormUrlEncoded. 353 CHttpFormData(void); 354 355 // Prohibit copying. 356 CHttpFormData(const CHttpFormData&); 357 CHttpFormData& operator=(const CHttpFormData&); 358 359 struct SFormData { 360 string m_Value; 361 string m_ContentType; 362 }; 363 364 typedef vector<SFormData> TValues; 365 typedef map<string, TValues> TEntries; 366 typedef vector< CRef<CFormDataProvider_Base> > TProviders; 367 typedef map<string, TProviders> TProviderEntries; 368 369 EContentType m_ContentType; 370 TEntries m_Entries; // Normal entries 371 TProviderEntries m_Providers; // Files and custom providers 372 mutable string m_Boundary; // Main boundary string 373 374 public: 375 /// Get the form content type as a string. 376 string GetContentTypeStr(void) const; 377 378 /// Generate a new random string to be used as multipart boundary. 379 static string CreateBoundary(void); 380 }; 381 382 383 /// HTTP response 384 class NCBI_XCONNECT_EXPORT CHttpResponse : public CObject 385 { 386 public: 387 /// Get incoming HTTP headers. Headers(void) const388 const CHttpHeaders& Headers(void) const { return *m_Headers; } 389 390 /// Get input stream. If the status code indicates that there's 391 /// no content to be read, throw CHttpSessionException. The actual 392 /// request body (e.g. error page) can be read using ErrorStream(). 393 CNcbiIstream& ContentStream(void) const; 394 395 /// Get input stream containing error message (e.g. 404 page) 396 /// If the status code indicates that valid content is available 397 /// the method throws CHttpSessionException. 398 CNcbiIstream& ErrorStream(void) const; 399 400 /// Get actual resource location. This may be different from the 401 /// requested URL in case of redirects. GetLocation(void) const402 const CUrl& GetLocation(void) const { return m_Location; } 403 404 /// Get response status code. GetStatusCode(void) const405 int GetStatusCode(void) const { return m_StatusCode; } 406 407 /// Get response status text. GetStatusText(void) const408 const string& GetStatusText(void) const { return m_StatusText; } 409 410 /// Check if the requested content can be read from the content stream. 411 /// This is true for status codes 2xx. If there's no content available, 412 /// ContentStream() will throw an exception and response body can be 413 /// accessed using ErrorStream(). 414 /// @note This method returns true even if the content stream is empty 415 /// (e.g. after HEAD request), it's based on status code only. 416 bool CanGetContentStream(void) const; 417 ~CHttpResponse(void)418 virtual ~CHttpResponse(void) {} 419 420 private: 421 friend class CHttpRequest; 422 423 CHttpResponse(CHttpSession_Base& session, const CUrl& url, shared_ptr<iostream> stream = {}); 424 425 // Update response headers and location, parse cookies and store them in the session. 426 void x_Update(CHttpHeaders::THeaders headers, int status_code, string status_text); 427 428 CRef<CHttpSession_Base> m_Session; 429 CUrl m_Url; // Original URL 430 CUrl m_Location; // Redirection or the original URL. 431 shared_ptr<iostream> m_Stream; 432 CRef<CHttpHeaders> m_Headers; 433 int m_StatusCode; 434 string m_StatusText; 435 }; 436 437 438 /// HTTP request 439 class NCBI_XCONNECT_EXPORT CHttpRequest 440 { 441 public: 442 /// Get HTTP headers to be sent. Headers(void)443 CHttpHeaders& Headers(void) { return *m_Headers; } 444 445 /// Get form data to be sent with POST request. Throw an exception 446 /// if the selected method is not POST or if the request is already 447 /// being executed (after calling ContentStream() but before Execute()). 448 CHttpFormData& FormData(void); 449 450 /// Get output stream to write user data. 451 /// Headers are sent automatically when opening the stream. 452 /// No changes can be made to the request after getting the stream 453 /// until it is completed by calling Execute(). 454 /// Throws an exception if the selected request method does not 455 /// support sending data or if the existing form data is not empty. 456 /// @note This method automatically adds cookies to the request headers. 457 CNcbiOstream& ContentStream(void); 458 459 /// Send the request, initialize and return the response. The output 460 /// content stream is flushed and closed by this call. 461 /// After executing a request it can be modified (e.g. more headers 462 /// and/or form data added) and re-executed. 463 /// @note This method automatically adds cookies to the request headers. 464 CHttpResponse Execute(void); 465 466 /// Get current timeout. If set to CTimeout::eDefault, the global 467 /// default value is used (or the one from $CONN_TIMEOUT). GetTimeout(void) const468 const CTimeout& GetTimeout(void) const { return m_Timeout; } 469 /// Set new timeout. 470 CHttpRequest& SetTimeout(const CTimeout& timeout); 471 /// Set new timeout in seconds/microseconds. 472 CHttpRequest& SetTimeout(unsigned int sec, unsigned int usec = 0); 473 474 /// Get number of retries. If not set returns the global default 475 /// value ($CONN_MAX_TRY - 1). GetRetries(void) const476 THttpRetries GetRetries(void) const { return m_Retries; } 477 /// Set number of retries. If not set, the global default 478 /// value is used ($CONN_MAX_TRY - 1). SetRetries(THttpRetries retries)479 void SetRetries(THttpRetries retries) { m_Retries = retries; } 480 481 /// Get current deadline for Execute(). 482 /// For now, effective only for if waiting for actual response 483 /// (as opposed to a recognized 'retry later' response), infinite by default. 484 /// @sa Execute() GetRetryProcessing() GetDeadline() const485 const CTimeout& GetDeadline() const { return m_Deadline; } 486 /// Set new deadline for Execute(). 487 /// @sa Execute() SetRetryProcessing() 488 CHttpRequest& SetDeadline(const CTimeout& deadline); 489 490 /// Return whether Execute() will wait for actual response. 491 /// If on, will wait for deadline expired or actual response 492 /// (as opposed to a recognized 'retry later' response), off by default. 493 /// @sa Execute() GetDeadline() GetRetryProcessing() const494 ESwitch GetRetryProcessing() const { return m_RetryProcessing; } 495 /// Set whether Execute() should wait for actual response. 496 /// @sa Execute() SetDeadline() 497 CHttpRequest& SetRetryProcessing(ESwitch on_off); 498 499 /// Set callback to adjust URL after resolving service location. 500 /// The callback must take a CUrl reference and return bool: 501 /// bool AdjustUrlCallback(CUrl& url); 502 /// The callback should return true for the adjusted URL to be used to 503 /// make the request, or false if the changes should be discarded. 504 template<class TCallback> SetAdjustUrlCallback(TCallback callback)505 void SetAdjustUrlCallback(TCallback callback) { 506 m_AdjustUrl.Reset(new CAdjustUrlCallback<TCallback>(callback)); 507 } 508 509 private: 510 friend class CHttpSession_Base; 511 friend class CHttpSessionImpl1x; 512 friend class CHttpSessionImpl2; 513 514 CHttpRequest(CHttpSession_Base& session, const CUrl& url, EReqMethod method); 515 516 class CAdjustUrlCallback_Base : public CObject { 517 public: ~CAdjustUrlCallback_Base(void)518 virtual ~CAdjustUrlCallback_Base(void) {} 519 virtual bool AdjustUrl(CUrl& url) = 0; 520 }; 521 522 template<class TCallback> 523 class CAdjustUrlCallback : public CAdjustUrlCallback_Base { 524 public: CAdjustUrlCallback(TCallback & callback)525 CAdjustUrlCallback(TCallback& callback) : m_Callback(callback) {} AdjustUrl(CUrl & url)526 virtual bool AdjustUrl(CUrl& url) { return m_Callback(url); } 527 private: 528 TCallback m_Callback; 529 }; 530 531 // Open connection, initialize response. 532 void x_InitConnection(bool use_form_data); 533 void x_InitConnection2(shared_ptr<iostream> stream, bool is_service); 534 535 bool x_CanSendData(void) const; 536 537 // Find cookies matching the url, add or replace 'Cookie' header with the 538 // new values. 539 void x_AddCookieHeader(const CUrl& url, bool initial); 540 541 void x_AdjustHeaders(bool use_form_data); 542 void x_UpdateResponse(CHttpHeaders::THeaders headers, int status_code, string status_text); 543 544 // CConn_HttpStream callback for parsing headers. 545 // 'user_data' must point to a CHttpRequest object. 546 static EHTTP_HeaderParse sx_ParseHeader(const char*, void*, int); 547 // CConn_HttpStream callback for handling retries and redirects. 548 // 'user_data' must point to a CHttpRequest object. 549 static int sx_Adjust(SConnNetInfo* net_info, 550 void* user_data, 551 unsigned int failure_count); 552 553 CRef<CHttpSession_Base> m_Session; 554 CUrl m_Url; 555 bool m_IsService; 556 EReqMethod m_Method; 557 CRef<CHttpHeaders> m_Headers; 558 CRef<CHttpFormData> m_FormData; 559 shared_ptr<iostream> m_Stream; 560 CRef<CHttpResponse> m_Response; // current response or null 561 CTimeout m_Timeout; 562 THttpRetries m_Retries; 563 CTimeout m_Deadline; 564 ESwitch m_RetryProcessing; 565 CRef<CAdjustUrlCallback_Base> m_AdjustUrl; 566 }; 567 568 569 /// HTTP session class, holding common data for multiple requests. 570 class NCBI_XCONNECT_EXPORT CHttpSession_Base : public CObject, 571 virtual protected CConnIniter 572 { 573 public: 574 /// Supported request methods, proxy for EReqMethod. 575 /// @sa EReqMethod 576 enum ERequestMethod { 577 eHead = eReqMethod_Head, 578 eGet = eReqMethod_Get, 579 ePost = eReqMethod_Post, 580 ePut = eReqMethod_Put, 581 ePatch = eReqMethod_Patch, 582 eDelete = eReqMethod_Delete 583 }; 584 585 /// Initialize request. This does not open connection to the server. 586 /// A user can set headers/form-data before opening the stream and 587 /// sending the actual request. 588 /// The default request method is GET. 589 CHttpRequest NewRequest(const CUrl& url, ERequestMethod method = eGet); 590 591 /// Shortcut for GET requests. 592 /// @param url 593 /// URL to send request to. 594 /// @sa NewRequest() CHttpRequest 595 CHttpResponse Get(const CUrl& url, 596 const CTimeout& timeout = CTimeout(CTimeout::eDefault), 597 THttpRetries retries = null); 598 599 /// Shortcut for POST requests. 600 /// @param url 601 /// URL to send request to. 602 /// @param data 603 /// Data to be sent with the request. The data is sent as-is, 604 /// any required encoding must be performed by the caller. 605 /// @param content_type 606 /// Content-type. If empty, application/x-www-form-urlencoded 607 /// is used. 608 /// @sa NewRequest() CHttpRequest 609 CHttpResponse Post(const CUrl& url, 610 CTempString data, 611 CTempString content_type = CTempString(), 612 const CTimeout& timeout = CTimeout(CTimeout::eDefault), 613 THttpRetries retries = null); 614 615 /// Shortcut for PUT requests. 616 /// @param url 617 /// URL to send request to. 618 /// @param data 619 /// Data to be sent with the request. The data is sent as-is, 620 /// any required encoding must be performed by the caller. 621 /// @param content_type 622 /// Content-type. If empty, application/x-www-form-urlencoded 623 /// is used. 624 /// @sa NewRequest() CHttpRequest 625 CHttpResponse Put(const CUrl& url, 626 CTempString data, 627 CTempString content_type = CTempString(), 628 const CTimeout& timeout = CTimeout(CTimeout::eDefault), 629 THttpRetries retries = null); 630 631 /// Get all stored cookies. Cookies(void) const632 const CHttpCookies& Cookies(void) const { return m_Cookies; } 633 /// Get all stored cookies, non-const. Cookies(void)634 CHttpCookies& Cookies(void) { return m_Cookies; } 635 636 /// HTTP protocol version. 637 enum EProtocol { 638 eHTTP_10, ///< HTTP/1.0 639 eHTTP_11, ///< HTTP/1.1 640 eHTTP_2, ///< HTTP/2 641 }; 642 643 /// Get protocol version. GetProtocol(void) const644 EProtocol GetProtocol(void) const { return m_Protocol; } SetProtocol(EProtocol protocol)645 void SetProtocol(EProtocol protocol) { m_Protocol = protocol; } 646 647 /// Get flags passed to CConn_HttpStream. 648 /// @sa SetHttpFlags GetHttpFlags(void) const649 THTTP_Flags GetHttpFlags(void) const { return m_HttpFlags; } 650 /// Set flags passed to CConn_HttpStream. When sending request, 651 /// fHTTP_AdjustOnRedirect is always added to the flags. 652 /// @sa GetHttpFlags SetHttpFlags(THTTP_Flags flags)653 void SetHttpFlags(THTTP_Flags flags) { m_HttpFlags = flags; } 654 655 CHttpSession_Base(void); ~CHttpSession_Base(void)656 virtual ~CHttpSession_Base(void) {} 657 658 private: 659 friend class CHttpRequest; 660 friend class CHttpResponse; 661 662 virtual void x_StartRequest(EProtocol protocol, CHttpRequest& req, bool use_form_data) = 0; 663 virtual bool x_Downgrade(CHttpResponse& resp, EProtocol& protocol) const = 0; 664 665 // Save cookies returned by a response. 666 void x_SetCookies(const CHttpHeaders::THeaderValues& cookies, 667 const CUrl* url); 668 // Get a single 'Cookie' header line for the url. 669 string x_GetCookies(const CUrl& url) const; 670 671 EProtocol m_Protocol; 672 THTTP_Flags m_HttpFlags; 673 CHttpCookies m_Cookies; 674 }; 675 676 677 template <class TImpl> 678 class CHttpSessionTmpl : public CHttpSession_Base 679 { x_StartRequest(EProtocol protocol,CHttpRequest & req,bool use_form_data)680 void x_StartRequest(EProtocol protocol, CHttpRequest& req, bool use_form_data) override 681 { 682 TImpl::StartRequest(protocol, req, use_form_data); 683 } 684 x_Downgrade(CHttpResponse & resp,EProtocol & protocol) const685 bool x_Downgrade(CHttpResponse& resp, EProtocol& protocol) const override 686 { 687 return TImpl::Downgrade(resp, protocol); 688 } 689 }; 690 691 692 class CHttpSessionImpl1x 693 { 694 friend class CHttpSessionTmpl<CHttpSessionImpl1x>; 695 StartRequest(CHttpSession_Base::EProtocol _DEBUG_ARG (protocol),CHttpRequest & req,bool use_form_data)696 static void StartRequest(CHttpSession_Base::EProtocol _DEBUG_ARG(protocol), CHttpRequest& req, bool use_form_data) 697 { 698 _ASSERT(protocol <= CHttpSession_Base::eHTTP_11); 699 req.x_InitConnection(use_form_data); 700 } 701 Downgrade(CHttpResponse &,CHttpSession_Base::EProtocol &)702 static bool Downgrade(CHttpResponse&, CHttpSession_Base::EProtocol&) 703 { 704 return false; 705 } 706 }; 707 708 709 /// @sa CHttpSession_Base 710 using CHttpSession = CHttpSessionTmpl<CHttpSessionImpl1x>; 711 712 713 ///////////////////////////////////////////////////////////////////////////// 714 /// 715 /// CHttpSessionException -- 716 /// 717 /// Exceptions used by CHttpSession, CHttpRequest and CHttpResponse 718 /// classes. 719 720 class NCBI_XCONNECT_EXPORT CHttpSessionException : public CException 721 { 722 public: 723 enum EErrCode { 724 eBadRequest, ///< Error initializing or sending a request. 725 eBadContentType, ///< Content-type conflicts with the data. 726 eBadFormDataName, ///< Empty or bad name in form data. 727 eBadFormData, ///< Bad form data (e.g. unreadable file). 728 eBadStream, ///< Wrong stream used to read content or error. 729 eOther 730 }; 731 732 virtual const char* GetErrCodeString(void) const override; 733 734 NCBI_EXCEPTION_DEFAULT(CHttpSessionException, CException); 735 }; 736 737 738 END_NCBI_SCOPE 739 740 741 /* @} */ 742 743 #endif /* CONNECT___NCBI_HTTP_SESSION__HPP */ 744