[Curl] Create classes dedicated to handle SSL related tasks
[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 "CookieJarCurl.h"
30 #include "CurlSSLHandle.h"
31 #include "URL.h"
32
33 #include <wtf/Lock.h>
34 #include <wtf/NeverDestroyed.h>
35 #include <wtf/Noncopyable.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 // CurlGlobal --------------------------------------------
57 // to make the initialization of libcurl happen before other initialization of CurlContext
58
59 class CurlGlobal {
60 protected:
61     CurlGlobal()
62     {
63         curl_global_init(CURL_GLOBAL_ALL);
64     }
65     
66     virtual ~CurlGlobal()
67     {
68         curl_global_cleanup();
69     }
70 };
71
72 // CurlShareHandle --------------------------------------------
73
74 class CurlShareHandle {
75     WTF_MAKE_NONCOPYABLE(CurlShareHandle);
76
77 public:
78     CurlShareHandle();
79     ~CurlShareHandle();
80
81     CURLSH* handle() const { return m_shareHandle; }
82
83 private:
84     static void lockCallback(CURL*, curl_lock_data, curl_lock_access, void*);
85     static void unlockCallback(CURL*, curl_lock_data, void*);
86     static Lock* mutexFor(curl_lock_data);
87
88     CURLSH* m_shareHandle { nullptr };
89 };
90
91 // CurlContext --------------------------------------------
92
93 class CurlContext : public CurlGlobal {
94     WTF_MAKE_NONCOPYABLE(CurlContext);
95
96 public:
97     struct ProxyInfo {
98         String host;
99         unsigned long port;
100         CurlProxyType type { CurlProxyType::Invalid };
101         String username;
102         String password;
103
104         const String url() const;
105     };
106
107     static const char* const errorDomain;
108
109     static CurlContext& singleton()
110     {
111         static CurlContext shared;
112         return shared;
113     }
114
115     virtual ~CurlContext();
116
117     const CurlShareHandle& shareHandle() { return m_shareHandle; }
118
119     // Cookie
120     const char* getCookieJarFileName() const { return m_cookieJarFileName.data(); }
121     void setCookieJarFileName(const char* cookieJarFileName) { m_cookieJarFileName = CString(cookieJarFileName); }
122     CookieJarCurl& cookieJar() { return *m_cookieJar; }
123
124     // Proxy
125     const ProxyInfo& proxyInfo() const { return m_proxy; }
126     void setProxyInfo(const ProxyInfo& info) { m_proxy = info;  }
127     void setProxyInfo(const String& host = emptyString(), unsigned long port = 0, CurlProxyType = CurlProxyType::HTTP, const String& username = emptyString(), const String& password = emptyString());
128
129     // SSL
130     CurlSSLHandle& sslHandle() { return m_sslHandle; }
131
132 #ifndef NDEBUG
133     FILE* getLogFile() const { return m_logFile; }
134     bool isVerbose() const { return m_verbose; }
135 #endif
136
137 private:
138     ProxyInfo m_proxy;
139     CString m_cookieJarFileName;
140     CurlShareHandle m_shareHandle;
141     std::unique_ptr<CookieJarCurl> m_cookieJar;
142     CurlSSLHandle m_sslHandle;
143
144     CurlContext();
145     void initCookieSession();
146
147
148 #ifndef NDEBUG
149     FILE* m_logFile { nullptr };
150     bool m_verbose { false };
151 #endif
152 };
153
154 // CurlMultiHandle --------------------------------------------
155
156 class CurlMultiHandle {
157     WTF_MAKE_NONCOPYABLE(CurlMultiHandle);
158
159 public:
160     CurlMultiHandle();
161     ~CurlMultiHandle();
162
163     CURLMcode addHandle(CURL*);
164     CURLMcode removeHandle(CURL*);
165
166     CURLMcode getFdSet(fd_set&, fd_set&, fd_set&, int&);
167     CURLMcode perform(int&);
168     CURLMsg* readInfo(int&);
169
170 private:
171     CURLM* m_multiHandle { nullptr };
172 };
173
174 // CurlSList -------------------------------------------------
175
176 class CurlSList {
177 public:
178     CurlSList() { }
179     ~CurlSList() { clear(); }
180
181     operator struct curl_slist** () { return &m_list; }
182
183     const struct curl_slist* head() const { return m_list; }
184     bool isEmpty() const { return !m_list; }
185     void clear()
186     {
187         if (m_list) {
188             curl_slist_free_all(m_list);
189             m_list = nullptr;
190         }
191     }
192
193     void append(const char* str) { m_list = curl_slist_append(m_list, str); }
194     void append(const String& str) { append(str.latin1().data()); }
195
196 private:
197     struct curl_slist* m_list { nullptr };
198 };
199
200 // CurlHandle -------------------------------------------------
201
202 class HTTPHeaderMap;
203 class NetworkLoadMetrics;
204
205 class CurlHandle {
206     WTF_MAKE_NONCOPYABLE(CurlHandle);
207
208 public:
209     enum VerifyPeer {
210         VerifyPeerDisable = 0L,
211         VerifyPeerEnable = 1L
212     };
213
214     enum VerifyHost {
215         VerifyHostLooseNameCheck = 0,
216         VerifyHostStrictNameCheck = 2
217     };
218
219     CurlHandle();
220     ~CurlHandle();
221
222     CURL* handle() const { return m_handle; }
223
224     void initialize();
225
226     CURLcode perform();
227     CURLcode pause(int);
228
229     CURLcode errorCode() const { return m_errorCode; }
230     void setErrorCode(CURLcode errorCode) { m_errorCode = errorCode; }
231
232     const String errorDescription() const;
233
234     void enableShareHandle();
235
236     void* privateData() const { return m_privateData; }
237     void setPrivateData(void* userData) { m_privateData = userData; }
238
239     void setUrl(const String&);
240     const char* url() const { return m_url; }
241
242     void appendRequestHeaders(const HTTPHeaderMap&);
243     void appendRequestHeader(const String&, const String&);
244     void appendRequestHeader(const String&);
245     void enableRequestHeaders();
246
247     void enableHttpGetRequest();
248     void enableHttpHeadRequest();
249     void enableHttpPostRequest();
250     void setPostFields(const char*, long);
251     void setPostFieldLarge(curl_off_t);
252     void enableHttpPutRequest();
253     void setInFileSizeLarge(curl_off_t);
254     void setHttpCustomRequest(const String&);
255
256     void enableAcceptEncoding();
257     void enableAllowedProtocols();
258
259     void enableFollowLocation();
260     void enableAutoReferer();
261
262     void enableHttpAuthentication(long);
263     void setHttpAuthUserPass(const String&, const String&);
264
265     void setCACertPath(const char*);
266     void setSslVerifyPeer(VerifyPeer);
267     void setSslVerifyHost(VerifyHost);
268     void setSslCert(const char*);
269     void setSslCertType(const char*);
270     void setSslKeyPassword(const char*);
271
272     void enableCookieJarIfExists();
273     void setCookieList(const char*);
274     void fetchCookieList(CurlSList &cookies) const;
275
276     void enableProxyIfExists();
277
278     void enableTimeout();
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     URL getEffectiveURL();
288     std::optional<uint16_t> getPrimaryPort();
289     std::optional<long> getResponseCode();
290     std::optional<long long> getContentLenghtDownload();
291     std::optional<long> getHttpAuthAvail();
292     std::optional<NetworkLoadMetrics> getTimes();
293
294     static long long maxCurlOffT();
295
296 #ifndef NDEBUG
297     void enableVerboseIfUsed();
298     void enableStdErrIfUsed();
299 #endif
300
301 private:
302     void clearUrl();
303
304     static int expectedSizeOfCurlOffT();
305
306     CURL* m_handle { nullptr };
307     char m_errorBuffer[CURL_ERROR_SIZE] { };
308     CURLcode m_errorCode;
309
310     char* m_url { nullptr };
311     void* m_privateData { nullptr };
312     CurlSList m_requestHeaders;
313 };
314
315 }