[WTF] Remove StaticLock
[WebKit-https.git] / Source / WebCore / platform / network / curl / CurlContext.h
1 /*
2  * Copyright (C) 2013 Apple Inc.  All rights reserved.
3  * Copyright (C) 2017 Sony Interactive Entertainment Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
25  */
26
27 #pragma once
28
29 #include "CurlSSLHandle.h"
30 #include "URL.h"
31
32 #include <wtf/Lock.h>
33 #include <wtf/NeverDestroyed.h>
34 #include <wtf/Noncopyable.h>
35 #include <wtf/Seconds.h>
36 #include <wtf/Threading.h>
37
38 #if OS(WINDOWS)
39 #include <windows.h>
40 #include <winsock2.h>
41 #endif
42
43 #include <curl/curl.h>
44
45 namespace WebCore {
46
47 enum class CurlProxyType {
48     Invalid = -1,
49     HTTP = CURLPROXY_HTTP,
50     Socks4 = CURLPROXY_SOCKS4,
51     Socks4A = CURLPROXY_SOCKS4A,
52     Socks5 = CURLPROXY_SOCKS5,
53     Socks5Hostname = CURLPROXY_SOCKS5_HOSTNAME
54 };
55
56 // Values taken from http://www.browserscope.org/ following
57 // the rule "Do What Every Other Modern Browser Is Doing".
58 const long CurlDefaultMaxConnects { -1 }; // -1 : Does not set CURLMOPT_MAXCONNECTS
59 const long CurlDefaultMaxTotalConnections { 17 };
60 const long CurlDefaultMaxHostConnections { 6 };
61
62 // CurlGlobal --------------------------------------------
63 // to make the initialization of libcurl happen before other initialization of CurlContext
64
65 class CurlGlobal {
66 protected:
67     CurlGlobal()
68     {
69         curl_global_init(CURL_GLOBAL_ALL);
70     }
71     
72     virtual ~CurlGlobal()
73     {
74         curl_global_cleanup();
75     }
76 };
77
78 // CurlShareHandle --------------------------------------------
79
80 class CurlShareHandle {
81     WTF_MAKE_NONCOPYABLE(CurlShareHandle);
82
83 public:
84     CurlShareHandle();
85     ~CurlShareHandle();
86
87     CURLSH* handle() const { return m_shareHandle; }
88
89 private:
90     static void lockCallback(CURL*, curl_lock_data, curl_lock_access, void*);
91     static void unlockCallback(CURL*, curl_lock_data, void*);
92     static Lock* mutexFor(curl_lock_data);
93
94     CURLSH* m_shareHandle { nullptr };
95 };
96
97 // CurlContext --------------------------------------------
98
99 class CurlRequestScheduler;
100
101 class CurlContext : public CurlGlobal {
102     WTF_MAKE_NONCOPYABLE(CurlContext);
103     friend NeverDestroyed<CurlContext>;
104 public:
105     struct ProxyInfo {
106         String host;
107         unsigned long port;
108         CurlProxyType type { CurlProxyType::Invalid };
109         String username;
110         String password;
111
112         const String url() const;
113     };
114
115     WEBCORE_EXPORT static CurlContext& singleton();
116
117     virtual ~CurlContext();
118
119     const CurlShareHandle& shareHandle() { return m_shareHandle; }
120
121     CurlRequestScheduler& scheduler() { return *m_scheduler; }
122
123     // Proxy
124     const ProxyInfo& proxyInfo() const { return m_proxy; }
125     void setProxyInfo(const ProxyInfo& info) { m_proxy = info;  }
126     void setProxyInfo(const String& host = emptyString(), unsigned long port = 0, CurlProxyType = CurlProxyType::HTTP, const String& username = emptyString(), const String& password = emptyString());
127
128     // SSL
129     CurlSSLHandle& sslHandle() { return m_sslHandle; }
130
131     // HTTP/2
132     bool isHttp2Enabled() const;
133
134     // Timeout
135     Seconds dnsCacheTimeout() const { return m_dnsCacheTimeout; }
136     Seconds connectTimeout() const { return m_connectTimeout; }
137
138 #ifndef NDEBUG
139     FILE* getLogFile() const { return m_logFile; }
140     bool isVerbose() const { return m_verbose; }
141 #endif
142
143 private:
144     CurlContext();
145     void initShareHandle();
146
147     ProxyInfo m_proxy;
148     CurlShareHandle m_shareHandle;
149     CurlSSLHandle m_sslHandle;
150     std::unique_ptr<CurlRequestScheduler> m_scheduler;
151
152     Seconds m_dnsCacheTimeout { Seconds::fromMinutes(5) };
153     Seconds m_connectTimeout { 30.0 };
154
155 #ifndef NDEBUG
156     FILE* m_logFile { nullptr };
157     bool m_verbose { false };
158 #endif
159 };
160
161 // CurlMultiHandle --------------------------------------------
162
163 class CurlMultiHandle {
164     WTF_MAKE_NONCOPYABLE(CurlMultiHandle);
165
166 public:
167     CurlMultiHandle();
168     ~CurlMultiHandle();
169
170     void setMaxConnects(long);
171     void setMaxTotalConnections(long);
172     void setMaxHostConnections(long);
173
174     CURLMcode addHandle(CURL*);
175     CURLMcode removeHandle(CURL*);
176
177     CURLMcode getFdSet(fd_set&, fd_set&, fd_set&, int&);
178     CURLMcode perform(int&);
179     CURLMsg* readInfo(int&);
180
181 private:
182     CURLM* m_multiHandle { nullptr };
183 };
184
185 // CurlSList -------------------------------------------------
186
187 class CurlSList {
188 public:
189     CurlSList() { }
190     ~CurlSList() { clear(); }
191
192     operator struct curl_slist** () { return &m_list; }
193
194     const struct curl_slist* head() const { return m_list; }
195     bool isEmpty() const { return !m_list; }
196     void clear()
197     {
198         if (m_list) {
199             curl_slist_free_all(m_list);
200             m_list = nullptr;
201         }
202     }
203
204     void append(const char* str) { m_list = curl_slist_append(m_list, str); }
205     void append(const String& str) { append(str.latin1().data()); }
206
207 private:
208     struct curl_slist* m_list { nullptr };
209 };
210
211 // CurlHandle -------------------------------------------------
212
213 class HTTPHeaderMap;
214 class NetworkLoadMetrics;
215
216 class CurlHandle {
217     WTF_MAKE_NONCOPYABLE(CurlHandle);
218
219 public:
220     enum class VerifyPeer {
221         Disable = 0L,
222         Enable = 1L
223     };
224
225     enum class VerifyHost {
226         LooseNameCheck = 0,
227         StrictNameCheck = 2
228     };
229
230     CurlHandle();
231     virtual ~CurlHandle();
232
233     CURL* handle() const { return m_handle; }
234
235     void initialize();
236
237     CURLcode perform();
238     CURLcode pause(int);
239
240     static const String errorDescription(CURLcode);
241
242     void enableShareHandle();
243
244     void setUrl(const URL&);
245
246     void appendRequestHeaders(const HTTPHeaderMap&);
247     void appendRequestHeader(const String& name, const String& value);
248     void appendRequestHeader(const String& name);
249     void removeRequestHeader(const String& name);
250
251     void enableHttp();
252     void enableHttpGetRequest();
253     void enableHttpHeadRequest();
254     void enableHttpPostRequest();
255     void setPostFields(const char*, long);
256     void setPostFieldLarge(curl_off_t);
257     void enableHttpPutRequest();
258     void setInFileSizeLarge(curl_off_t);
259     void setHttpCustomRequest(const String&);
260
261     void enableAcceptEncoding();
262     void enableAllowedProtocols();
263
264     void enableHttpAuthentication(long);
265     void setHttpAuthUserPass(const String&, const String&);
266
267     void setCACertPath(const char*);
268     void setSslVerifyPeer(VerifyPeer);
269     void setSslVerifyHost(VerifyHost);
270     void setSslCert(const char*);
271     void setSslCertType(const char*);
272     void setSslKeyPassword(const char*);
273
274     void enableProxyIfExists();
275
276     void setDnsCacheTimeout(Seconds);
277     void setConnectTimeout(Seconds);
278     void setTimeout(Seconds);
279
280     // Callback function
281     void setHeaderCallbackFunction(curl_write_callback, void*);
282     void setWriteCallbackFunction(curl_write_callback, void*);
283     void setReadCallbackFunction(curl_read_callback, void*);
284     void setSslCtxCallbackFunction(curl_ssl_ctx_callback, void*);
285
286     // Status
287     std::optional<uint16_t> getPrimaryPort();
288     std::optional<long> getResponseCode();
289     std::optional<long> getHttpConnectCode();
290     std::optional<long long> getContentLength();
291     std::optional<long> getHttpAuthAvail();
292     std::optional<long> getHttpVersion();
293     std::optional<NetworkLoadMetrics> getNetworkLoadMetrics();
294
295     static long long maxCurlOffT();
296
297 #ifndef NDEBUG
298     void enableVerboseIfUsed();
299     void enableStdErrIfUsed();
300 #endif
301
302 private:
303     void enableRequestHeaders();
304     static int expectedSizeOfCurlOffT();
305
306     CURL* m_handle { nullptr };
307     char m_errorBuffer[CURL_ERROR_SIZE] { };
308
309     CurlSList m_requestHeaders;
310 };
311
312 } // namespace WebCore