| /* |
| * Copyright (C) 2013 Apple Inc. All rights reserved. |
| * Copyright (C) 2018 Sony Interactive Entertainment Inc. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #pragma once |
| |
| #include "CurlProxySettings.h" |
| #include "CurlSSLHandle.h" |
| |
| #include <wtf/Lock.h> |
| #include <wtf/NeverDestroyed.h> |
| #include <wtf/Noncopyable.h> |
| #include <wtf/Seconds.h> |
| #include <wtf/Threading.h> |
| #include <wtf/URL.h> |
| |
| #if OS(WINDOWS) |
| #include <windows.h> |
| #include <winsock2.h> |
| #endif |
| |
| #include <curl/curl.h> |
| |
| namespace WebCore { |
| |
| // Values taken from http://www.browserscope.org/ following |
| // the rule "Do What Every Other Modern Browser Is Doing". |
| const long CurlDefaultMaxConnects { -1 }; // -1 : Does not set CURLMOPT_MAXCONNECTS |
| const long CurlDefaultMaxTotalConnections { 17 }; |
| const long CurlDefaultMaxHostConnections { 6 }; |
| |
| // CurlGlobal -------------------------------------------- |
| // to make the initialization of libcurl happen before other initialization of CurlContext |
| |
| class CurlGlobal { |
| protected: |
| CurlGlobal() |
| { |
| curl_global_init(CURL_GLOBAL_ALL); |
| } |
| |
| virtual ~CurlGlobal() |
| { |
| curl_global_cleanup(); |
| } |
| }; |
| |
| // CurlShareHandle -------------------------------------------- |
| |
| class CurlShareHandle { |
| WTF_MAKE_NONCOPYABLE(CurlShareHandle); |
| |
| public: |
| CurlShareHandle(); |
| ~CurlShareHandle(); |
| |
| CURLSH* handle() const { return m_shareHandle; } |
| |
| private: |
| static void lockCallback(CURL*, curl_lock_data, curl_lock_access, void*); |
| static void unlockCallback(CURL*, curl_lock_data, void*); |
| static Lock* mutexFor(curl_lock_data); |
| |
| CURLSH* m_shareHandle { nullptr }; |
| }; |
| |
| // CurlContext -------------------------------------------- |
| |
| class CurlRequestScheduler; |
| |
| class CurlContext : public CurlGlobal { |
| WTF_MAKE_NONCOPYABLE(CurlContext); |
| friend NeverDestroyed<CurlContext>; |
| public: |
| WEBCORE_EXPORT static CurlContext& singleton(); |
| |
| virtual ~CurlContext(); |
| |
| const CurlShareHandle& shareHandle() { return m_shareHandle; } |
| |
| CurlRequestScheduler& scheduler() { return *m_scheduler; } |
| |
| // Proxy |
| const CurlProxySettings& proxySettings() const { return m_proxySettings; } |
| void setProxySettings(CurlProxySettings&& settings) { m_proxySettings = WTFMove(settings); } |
| void setProxyUserPass(const String& user, const String& password) { m_proxySettings.setUserPass(user, password); } |
| void setDefaultProxyAuthMethod() { m_proxySettings.setDefaultAuthMethod(); } |
| void setProxyAuthMethod(long authMethod) { m_proxySettings.setAuthMethod(authMethod); } |
| |
| // SSL |
| CurlSSLHandle& sslHandle() { return m_sslHandle; } |
| |
| // HTTP/2 |
| bool isHttp2Enabled() const; |
| |
| // Timeout |
| Seconds dnsCacheTimeout() const { return m_dnsCacheTimeout; } |
| Seconds connectTimeout() const { return m_connectTimeout; } |
| Seconds defaultTimeoutInterval() const { return m_defaultTimeoutInterval; } |
| |
| #ifndef NDEBUG |
| FILE* getLogFile() const { return m_logFile; } |
| bool isVerbose() const { return m_verbose; } |
| #endif |
| |
| private: |
| CurlContext(); |
| void initShareHandle(); |
| |
| CurlProxySettings m_proxySettings; |
| CurlShareHandle m_shareHandle; |
| CurlSSLHandle m_sslHandle; |
| std::unique_ptr<CurlRequestScheduler> m_scheduler; |
| |
| Seconds m_dnsCacheTimeout { Seconds::fromMinutes(5) }; |
| Seconds m_connectTimeout { 30.0 }; |
| Seconds m_defaultTimeoutInterval { 60.0 }; |
| |
| #ifndef NDEBUG |
| FILE* m_logFile { nullptr }; |
| bool m_verbose { false }; |
| #endif |
| }; |
| |
| // CurlMultiHandle -------------------------------------------- |
| |
| class CurlMultiHandle { |
| WTF_MAKE_FAST_ALLOCATED; |
| WTF_MAKE_NONCOPYABLE(CurlMultiHandle); |
| |
| public: |
| CurlMultiHandle(); |
| ~CurlMultiHandle(); |
| |
| void setMaxConnects(long); |
| void setMaxTotalConnections(long); |
| void setMaxHostConnections(long); |
| |
| CURLMcode addHandle(CURL*); |
| CURLMcode removeHandle(CURL*); |
| |
| CURLMcode getFdSet(fd_set&, fd_set&, fd_set&, int&); |
| CURLMcode perform(int&); |
| CURLMsg* readInfo(int&); |
| |
| private: |
| CURLM* m_multiHandle { nullptr }; |
| }; |
| |
| // CurlSList ------------------------------------------------- |
| |
| class CurlSList { |
| public: |
| CurlSList() { } |
| ~CurlSList() { clear(); } |
| |
| operator struct curl_slist** () { return &m_list; } |
| |
| const struct curl_slist* head() const { return m_list; } |
| bool isEmpty() const { return !m_list; } |
| void clear() |
| { |
| if (m_list) { |
| curl_slist_free_all(m_list); |
| m_list = nullptr; |
| } |
| } |
| |
| void append(const char* str) { m_list = curl_slist_append(m_list, str); } |
| void append(const String& str) { append(str.latin1().data()); } |
| |
| private: |
| struct curl_slist* m_list { nullptr }; |
| }; |
| |
| // CurlHandle ------------------------------------------------- |
| |
| class CertificateInfo; |
| class CurlSSLVerifier; |
| class HTTPHeaderMap; |
| class NetworkLoadMetrics; |
| |
| class CurlHandle { |
| WTF_MAKE_FAST_ALLOCATED; |
| WTF_MAKE_NONCOPYABLE(CurlHandle); |
| |
| public: |
| enum class VerifyPeer { |
| Disable = 0L, |
| Enable = 1L |
| }; |
| |
| enum class VerifyHost { |
| LooseNameCheck = 0, |
| StrictNameCheck = 2 |
| }; |
| |
| CurlHandle(); |
| virtual ~CurlHandle(); |
| |
| CURL* handle() const { return m_handle; } |
| const URL& url() const { return m_url; } |
| |
| CURLcode perform(); |
| CURLcode pause(int); |
| |
| static const String errorDescription(CURLcode); |
| |
| void enableShareHandle(); |
| |
| void setUrl(const URL&); |
| void enableSSLForHost(const String&); |
| |
| void appendRequestHeaders(const HTTPHeaderMap&); |
| void appendRequestHeader(const String& name, const String& value); |
| void appendRequestHeader(const String& name); |
| void removeRequestHeader(const String& name); |
| |
| void enableHttp(); |
| void enableHttpGetRequest(); |
| void enableHttpHeadRequest(); |
| void enableHttpPostRequest(); |
| void setPostFields(const char*, long); |
| void setPostFieldLarge(curl_off_t); |
| void enableHttpPutRequest(); |
| void setInFileSizeLarge(curl_off_t); |
| void setHttpCustomRequest(const String&); |
| |
| void enableConnectionOnly(); |
| |
| void enableAcceptEncoding(); |
| void enableAllowedProtocols(); |
| |
| void setHttpAuthUserPass(const String&, const String&, long authType = CURLAUTH_ANY); |
| |
| void disableServerTrustEvaluation(); |
| void setCACertPath(const char*); |
| void setSslVerifyPeer(VerifyPeer); |
| void setSslVerifyHost(VerifyHost); |
| void setSslCert(const char*); |
| void setSslCertType(const char*); |
| void setSslKeyPassword(const char*); |
| void setSslCipherList(const char*); |
| |
| void enableProxyIfExists(); |
| |
| void setDnsCacheTimeout(Seconds); |
| void setConnectTimeout(Seconds); |
| void setTimeout(Seconds); |
| |
| // Callback function |
| void setHeaderCallbackFunction(curl_write_callback, void*); |
| void setWriteCallbackFunction(curl_write_callback, void*); |
| void setReadCallbackFunction(curl_read_callback, void*); |
| void setSslCtxCallbackFunction(curl_ssl_ctx_callback, void*); |
| void setDebugCallbackFunction(curl_debug_callback, void*); |
| |
| // Status |
| Optional<String> getProxyUrl(); |
| Optional<long> getResponseCode(); |
| Optional<long> getHttpConnectCode(); |
| Optional<long long> getContentLength(); |
| Optional<long> getHttpAuthAvail(); |
| Optional<long> getProxyAuthAvail(); |
| Optional<long> getHttpVersion(); |
| Optional<NetworkLoadMetrics> getNetworkLoadMetrics(const WTF::Seconds& domainLookupStart); |
| void addExtraNetworkLoadMetrics(NetworkLoadMetrics&); |
| |
| int sslErrors() const; |
| Optional<CertificateInfo> certificateInfo() const; |
| |
| static long long maxCurlOffT(); |
| |
| #ifndef NDEBUG |
| void enableVerboseIfUsed(); |
| void enableStdErrIfUsed(); |
| #endif |
| |
| private: |
| void enableRequestHeaders(); |
| static int expectedSizeOfCurlOffT(); |
| |
| static CURLcode willSetupSslCtxCallback(CURL*, void* sslCtx, void* userData); |
| CURLcode willSetupSslCtx(void* sslCtx); |
| |
| CURL* m_handle { nullptr }; |
| char m_errorBuffer[CURL_ERROR_SIZE] { }; |
| |
| URL m_url; |
| CurlSList m_requestHeaders; |
| std::unique_ptr<CurlSSLVerifier> m_sslVerifier; |
| }; |
| |
| class CurlSocketHandle : public CurlHandle { |
| WTF_MAKE_NONCOPYABLE(CurlSocketHandle); |
| |
| public: |
| struct WaitResult { |
| bool readable { false }; |
| bool writable { false }; |
| }; |
| |
| CurlSocketHandle(const URL&, Function<void(CURLcode)>&& errorHandler); |
| |
| bool connect(); |
| size_t send(const uint8_t*, size_t); |
| Optional<size_t> receive(uint8_t*, size_t); |
| Optional<WaitResult> wait(const Seconds& timeout, bool alsoWaitForWrite); |
| |
| private: |
| Function<void(CURLcode)> m_errorHandler; |
| }; |
| |
| } // namespace WebCore |