dd64af957b1e6dad0bbb38ef3c76f3f5d32f3139
[WebKit-https.git] / Source / WebCore / platform / network / curl / CurlContext.cpp
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 #include "config.h"
28
29 #if USE(CURL)
30 #include "CurlContext.h"
31 #include "HTTPHeaderMap.h"
32 #include <wtf/MainThread.h>
33 #include <wtf/text/CString.h>
34
35 #if OS(WINDOWS)
36 #include "WebCoreBundleWin.h"
37 #include <shlobj.h>
38 #include <shlwapi.h>
39 #endif
40
41 #if USE(CF)
42 #include <wtf/RetainPtr.h>
43 #endif
44
45 using namespace WebCore;
46
47 namespace WebCore {
48
49 static CString certificatePath()
50 {
51     char* envPath = getenv("CURL_CA_BUNDLE_PATH");
52     if (envPath)
53         return envPath;
54
55 #if USE(CF)
56     CFBundleRef webKitBundleRef = webKitBundle();
57     if (webKitBundleRef) {
58         RetainPtr<CFURLRef> certURLRef = adoptCF(CFBundleCopyResourceURL(webKitBundleRef, CFSTR("cacert"), CFSTR("pem"), CFSTR("certificates")));
59         if (certURLRef) {
60             char path[MAX_PATH];
61             CFURLGetFileSystemRepresentation(certURLRef.get(), false, reinterpret_cast<UInt8*>(path), MAX_PATH);
62             return path;
63         }
64     }
65 #endif
66
67     return CString();
68 }
69
70 static CString cookieJarPath()
71 {
72     char* cookieJarPath = getenv("CURL_COOKIE_JAR_PATH");
73     if (cookieJarPath)
74         return cookieJarPath;
75
76 #if OS(WINDOWS)
77     char executablePath[MAX_PATH];
78     char appDataDirectory[MAX_PATH];
79     char cookieJarFullPath[MAX_PATH];
80     char cookieJarDirectory[MAX_PATH];
81
82     if (FAILED(::SHGetFolderPathA(0, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, 0, 0, appDataDirectory))
83         || FAILED(::GetModuleFileNameA(0, executablePath, MAX_PATH)))
84         return "cookies.dat";
85
86     ::PathRemoveExtensionA(executablePath);
87     LPSTR executableName = ::PathFindFileNameA(executablePath);
88     sprintf_s(cookieJarDirectory, MAX_PATH, "%s/%s", appDataDirectory, executableName);
89     sprintf_s(cookieJarFullPath, MAX_PATH, "%s/cookies.dat", cookieJarDirectory);
90
91     if (::SHCreateDirectoryExA(0, cookieJarDirectory, 0) != ERROR_SUCCESS
92         && ::GetLastError() != ERROR_FILE_EXISTS
93         && ::GetLastError() != ERROR_ALREADY_EXISTS)
94         return "cookies.dat";
95
96     return cookieJarFullPath;
97 #else
98     return "cookies.dat";
99 #endif
100 }
101
102 // CurlContext -------------------------------------------------------------------
103
104 const char* const CurlContext::errorDomain = "CurlErrorDomain";
105
106 CurlContext::CurlContext()
107 : m_cookieJarFileName { cookieJarPath() }
108 , m_certificatePath { certificatePath() }
109 {
110     initCookieSession();
111
112     m_ignoreSSLErrors = getenv("WEBKIT_IGNORE_SSL_ERRORS");
113
114 #ifndef NDEBUG
115     m_verbose = getenv("DEBUG_CURL");
116
117     char* logFile = getenv("CURL_LOG_FILE");
118     if (logFile)
119         m_logFile = fopen(logFile, "a");
120 #endif
121 }
122
123 CurlContext::~CurlContext()
124 {
125 #ifndef NDEBUG
126     if (m_logFile)
127         fclose(m_logFile);
128 #endif
129 }
130
131 // Cookie =======================
132
133 void CurlContext::initCookieSession()
134 {
135     // Curl saves both persistent cookies, and session cookies to the cookie file.
136     // The session cookies should be deleted before starting a new session.
137
138     CURL* curl = curl_easy_init();
139
140     if (!curl)
141         return;
142
143     curl_easy_setopt(curl, CURLOPT_SHARE, m_shareHandle.handle());
144
145     if (!m_cookieJarFileName.isNull()) {
146         curl_easy_setopt(curl, CURLOPT_COOKIEFILE, m_cookieJarFileName.data());
147         curl_easy_setopt(curl, CURLOPT_COOKIEJAR, m_cookieJarFileName.data());
148     }
149
150     curl_easy_setopt(curl, CURLOPT_COOKIESESSION, 1);
151
152     curl_easy_cleanup(curl);
153 }
154
155 // Proxy =======================
156
157 const String CurlContext::ProxyInfo::url() const
158 {
159     String userPass;
160     if (username.length() || password.length())
161         userPass = username + ":" + password + "@";
162
163     return String("http://") + userPass + host + ":" + String::number(port);
164 }
165
166 void CurlContext::setProxyInfo(const String& host,
167     unsigned long port,
168     CurlProxyType type,
169     const String& username,
170     const String& password)
171 {
172     ProxyInfo info;
173
174     info.host = host;
175     info.port = port;
176     info.type = type;
177     info.username = username;
178     info.password = password;
179
180     setProxyInfo(info);
181 }
182
183
184
185 // CurlShareHandle --------------------------------------------
186
187 CurlShareHandle::CurlShareHandle()
188 {
189     m_shareHandle = curl_share_init();
190     curl_share_setopt(m_shareHandle, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE);
191     curl_share_setopt(m_shareHandle, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
192     curl_share_setopt(m_shareHandle, CURLSHOPT_LOCKFUNC, lockCallback);
193     curl_share_setopt(m_shareHandle, CURLSHOPT_UNLOCKFUNC, unlockCallback);
194 }
195
196 CurlShareHandle::~CurlShareHandle()
197 {
198     if (m_shareHandle) {
199         curl_share_cleanup(m_shareHandle);
200         m_shareHandle = nullptr;
201     }
202 }
203
204 void CurlShareHandle::lockCallback(CURL*, curl_lock_data data, curl_lock_access, void*)
205 {
206     if (Lock* mutex = mutexFor(data))
207         mutex->lock();
208 }
209
210 void CurlShareHandle::unlockCallback(CURL*, curl_lock_data data, void*)
211 {
212     if (Lock* mutex = mutexFor(data))
213         mutex->unlock();
214 }
215
216 Lock* CurlShareHandle::mutexFor(curl_lock_data data)
217 {
218     static NeverDestroyed<Lock> cookieMutex;
219     static NeverDestroyed<Lock> dnsMutex;
220     static NeverDestroyed<Lock> shareMutex;
221
222     switch (data) {
223     case CURL_LOCK_DATA_COOKIE:
224         return &cookieMutex.get();
225     case CURL_LOCK_DATA_DNS:
226         return &dnsMutex.get();
227     case CURL_LOCK_DATA_SHARE:
228         return &shareMutex.get();
229     default:
230         ASSERT_NOT_REACHED();
231         return nullptr;
232     }
233 }
234
235 // CurlMultiHandle --------------------------------------------
236
237 CurlMultiHandle::CurlMultiHandle()
238 {
239     CurlContext::singleton();
240
241     m_multiHandle = curl_multi_init();
242 }
243
244 CurlMultiHandle::~CurlMultiHandle()
245 {
246     if (m_multiHandle) {
247         curl_multi_cleanup(m_multiHandle);
248         m_multiHandle = nullptr;
249     }
250 }
251
252 CURLMcode CurlMultiHandle::addHandle(CURL* handle)
253 {
254     return curl_multi_add_handle(m_multiHandle, handle);
255 }
256
257 CURLMcode CurlMultiHandle::removeHandle(CURL* handle)
258 {
259     return curl_multi_remove_handle(m_multiHandle, handle);
260 }
261
262 CURLMcode CurlMultiHandle::getFdSet(fd_set& readFdSet, fd_set& writeFdSet, fd_set& excFdSet, int& maxFd)
263 {
264     FD_ZERO(&readFdSet);
265     FD_ZERO(&writeFdSet);
266     FD_ZERO(&excFdSet);
267     maxFd = 0;
268
269     return curl_multi_fdset(m_multiHandle, &readFdSet, &writeFdSet, &excFdSet, &maxFd);
270 }
271
272 CURLMcode CurlMultiHandle::perform(int& runningHandles)
273 {
274     return curl_multi_perform(m_multiHandle, &runningHandles);
275 }
276
277 CURLMsg* CurlMultiHandle::readInfo(int& messagesInQueue)
278 {
279     return curl_multi_info_read(m_multiHandle, &messagesInQueue);
280 }
281
282 // CurlHandle -------------------------------------------------
283
284 CurlHandle::CurlHandle()
285 {
286     CurlContext::singleton();
287
288     m_handle = curl_easy_init();
289     curl_easy_setopt(m_handle, CURLOPT_ERRORBUFFER, m_errorBuffer);
290     curl_easy_setopt(m_handle, CURLOPT_PRIVATE, this);
291 }
292
293 CurlHandle::~CurlHandle()
294 {
295     clearUrl();
296
297     curl_easy_cleanup(m_handle);
298 }
299
300 const String CurlHandle::errorDescription() const
301 {
302     return String(curl_easy_strerror(m_errorCode));
303 }
304
305 CURLcode CurlHandle::perform()
306 {
307     m_errorCode = curl_easy_perform(m_handle);
308     return m_errorCode;
309 }
310
311 CURLcode CurlHandle::pause(int bitmask)
312 {
313     m_errorCode = curl_easy_pause(m_handle, CURLPAUSE_ALL);
314     return m_errorCode;
315 }
316
317 void CurlHandle::enableShareHandle()
318 {
319     curl_easy_setopt(m_handle, CURLOPT_SHARE, CurlContext::singleton().shareHandle().handle());
320 }
321
322 void CurlHandle::setUrl(const String& url)
323 {
324     clearUrl();
325
326     // url is in ASCII so latin1() will only convert it to char* without character translation.
327     m_url = fastStrDup(url.latin1().data());
328     curl_easy_setopt(m_handle, CURLOPT_URL, m_url);
329 }
330
331 void CurlHandle::clearUrl()
332 {
333     if (m_url) {
334         fastFree(m_url);
335         m_url = nullptr;
336     }
337 }
338
339 void CurlHandle::appendRequestHeaders(const HTTPHeaderMap& headers)
340 {
341     if (headers.size()) {
342         for (auto& entry : headers) {
343             auto& value = entry.value;
344             appendRequestHeader(entry.key, entry.value);
345         }
346
347         enableRequestHeaders();
348     }
349 }
350
351 void CurlHandle::appendRequestHeader(const String& name, const String& value)
352 {
353     String header(name);
354
355     if (value.isEmpty()) {
356         // Insert the ; to tell curl that this header has an empty value.
357         header.append(";");
358     } else {
359         header.append(": ");
360         header.append(value);
361     }
362
363     appendRequestHeader(header);
364 }
365
366 void CurlHandle::appendRequestHeader(const String& header)
367 {
368     m_requestHeaders.append(header);
369 }
370
371 void CurlHandle::enableRequestHeaders()
372 {
373     if (!m_requestHeaders.isEmpty()) {
374         const struct curl_slist* headers = m_requestHeaders.head();
375         curl_easy_setopt(m_handle, CURLOPT_HTTPHEADER, headers);
376     }
377 }
378
379 void CurlHandle::enableHttpGetRequest()
380 {
381     curl_easy_setopt(m_handle, CURLOPT_HTTPGET, 1L);
382 }
383
384 void CurlHandle::enableHttpHeadRequest()
385 {
386     curl_easy_setopt(m_handle, CURLOPT_NOBODY, 1L);
387 }
388
389 void CurlHandle::enableHttpPostRequest()
390 {
391     curl_easy_setopt(m_handle, CURLOPT_POST, 1L);
392     curl_easy_setopt(m_handle, CURLOPT_POSTFIELDSIZE, 0L);
393 }
394
395 void CurlHandle::setPostFields(const char* data, long size)
396 {
397     curl_easy_setopt(m_handle, CURLOPT_POSTFIELDS, data);
398     curl_easy_setopt(m_handle, CURLOPT_POSTFIELDSIZE, size);
399 }
400
401 void CurlHandle::setPostFieldLarge(curl_off_t size)
402 {
403     if (expectedSizeOfCurlOffT() != sizeof(long long))
404         size = static_cast<int>(size);
405
406     curl_easy_setopt(m_handle, CURLOPT_POSTFIELDSIZE_LARGE, size);
407 }
408
409 void CurlHandle::enableHttpPutRequest()
410 {
411     curl_easy_setopt(m_handle, CURLOPT_UPLOAD, 1L);
412     curl_easy_setopt(m_handle, CURLOPT_INFILESIZE, 0L);
413 }
414
415 void CurlHandle::setInFileSizeLarge(curl_off_t size)
416 {
417     if (expectedSizeOfCurlOffT() != sizeof(long long))
418         size = static_cast<int>(size);
419
420     curl_easy_setopt(m_handle, CURLOPT_INFILESIZE_LARGE, size);
421 }
422
423 void CurlHandle::setHttpCustomRequest(const String& method)
424 {
425     curl_easy_setopt(m_handle, CURLOPT_CUSTOMREQUEST, method.ascii().data());
426 }
427
428 void CurlHandle::enableAcceptEncoding()
429 {
430     // enable all supported built-in compressions (gzip and deflate) through Accept-Encoding:
431     curl_easy_setopt(m_handle, CURLOPT_ENCODING, "");
432 }
433
434 void CurlHandle::enableAllowedProtocols()
435 {
436     static const long allowedProtocols = CURLPROTO_FILE | CURLPROTO_FTP | CURLPROTO_FTPS | CURLPROTO_HTTP | CURLPROTO_HTTPS;
437
438     curl_easy_setopt(m_handle, CURLOPT_PROTOCOLS, allowedProtocols);
439     curl_easy_setopt(m_handle, CURLOPT_REDIR_PROTOCOLS, allowedProtocols);
440 }
441
442 void CurlHandle::enableFollowLocation()
443 {
444     static const long maxNumberOfRedirectCount = 10;
445
446     curl_easy_setopt(m_handle, CURLOPT_FOLLOWLOCATION, 1L);
447     curl_easy_setopt(m_handle, CURLOPT_MAXREDIRS, maxNumberOfRedirectCount);
448 }
449
450 void CurlHandle::enableAutoReferer()
451 {
452     curl_easy_setopt(m_handle, CURLOPT_AUTOREFERER, 1L);
453 }
454
455 void CurlHandle::enableHttpAuthentication(long option)
456 {
457     curl_easy_setopt(m_handle, CURLOPT_HTTPAUTH, option);
458 }
459
460 void CurlHandle::setHttpAuthUserPass(const String& user, const String& password)
461 {
462     String userpass = emptyString();
463
464     if (!user.isEmpty() || !password.isEmpty())
465         userpass = user + ":" + password;
466
467     curl_easy_setopt(m_handle, CURLOPT_USERPWD, userpass.utf8().data());
468 }
469
470 void CurlHandle::enableCAInfoIfExists()
471 {
472     const char* certPath = CurlContext::singleton().getCertificatePath();
473     if (certPath)
474         curl_easy_setopt(m_handle, CURLOPT_CAINFO, certPath);
475 }
476
477 void CurlHandle::setSslVerifyPeer(VerifyPeer verifyPeer)
478 {
479     curl_easy_setopt(m_handle, CURLOPT_SSL_VERIFYPEER, static_cast<long>(verifyPeer));
480 }
481
482 void CurlHandle::setSslVerifyHost(VerifyHost verifyHost)
483 {
484     curl_easy_setopt(m_handle, CURLOPT_SSL_VERIFYHOST, static_cast<long>(verifyHost));
485 }
486
487 void CurlHandle::setSslCert(const char* cert)
488 {
489     curl_easy_setopt(m_handle, CURLOPT_SSLCERT, cert);
490 }
491
492 void CurlHandle::setSslCertType(const char* type)
493 {
494     curl_easy_setopt(m_handle, CURLOPT_SSLCERTTYPE, type);
495 }
496
497 void CurlHandle::setSslKeyPassword(const char* password)
498 {
499     curl_easy_setopt(m_handle, CURLOPT_KEYPASSWD, password);
500 }
501
502 void CurlHandle::enableCookieJarIfExists()
503 {
504     const char* cookieJar = CurlContext::singleton().getCookieJarFileName();
505     if (cookieJar)
506         curl_easy_setopt(m_handle, CURLOPT_COOKIEJAR, cookieJar);
507 }
508
509 void CurlHandle::setCookieList(const char* cookieList)
510 {
511     if (!cookieList)
512         return;
513
514     curl_easy_setopt(m_handle, CURLOPT_COOKIELIST, cookieList);
515 }
516
517 void CurlHandle::fetchCookieList(CurlSList &cookies) const
518 {
519     curl_easy_getinfo(m_handle, CURLINFO_COOKIELIST, static_cast<struct curl_slist**>(cookies));
520 }
521
522 void CurlHandle::enableProxyIfExists()
523 {
524     auto& proxy = CurlContext::singleton().proxyInfo();
525
526     if (proxy.type != CurlProxyType::Invalid) {
527         curl_easy_setopt(m_handle, CURLOPT_PROXY, proxy.url().utf8().data());
528         curl_easy_setopt(m_handle, CURLOPT_PROXYTYPE, proxy.type);
529     }
530 }
531
532 void CurlHandle::enableTimeout()
533 {
534     static const long dnsCacheTimeout = 5 * 60; // [sec.]
535
536     curl_easy_setopt(m_handle, CURLOPT_DNS_CACHE_TIMEOUT, dnsCacheTimeout);
537 }
538
539 void CurlHandle::setHeaderCallbackFunction(curl_write_callback callbackFunc, void* userData)
540 {
541     curl_easy_setopt(m_handle, CURLOPT_HEADERFUNCTION, callbackFunc);
542     curl_easy_setopt(m_handle, CURLOPT_HEADERDATA, userData);
543 }
544
545 void CurlHandle::setWriteCallbackFunction(curl_write_callback callbackFunc, void* userData)
546 {
547     curl_easy_setopt(m_handle, CURLOPT_WRITEFUNCTION, callbackFunc);
548     curl_easy_setopt(m_handle, CURLOPT_WRITEDATA, userData);
549 }
550
551 void CurlHandle::setReadCallbackFunction(curl_read_callback callbackFunc, void* userData)
552 {
553     curl_easy_setopt(m_handle, CURLOPT_READFUNCTION, callbackFunc);
554     curl_easy_setopt(m_handle, CURLOPT_READDATA, userData);
555 }
556
557 void CurlHandle::setSslCtxCallbackFunction(curl_ssl_ctx_callback callbackFunc, void* userData)
558 {
559     curl_easy_setopt(m_handle, CURLOPT_SSL_CTX_DATA, userData);
560     curl_easy_setopt(m_handle, CURLOPT_SSL_CTX_FUNCTION, callbackFunc);
561 }
562
563 URL CurlHandle::getEffectiveURL() const
564 {
565     CURLcode errCd = CURLE_FAILED_INIT;
566     char* url = nullptr;
567
568     if (m_handle)
569         errCd = curl_easy_getinfo(m_handle, CURLINFO_EFFECTIVE_URL, &url);
570
571     if ((errCd == CURLE_OK) && url)
572         return URL(URL(), url);
573
574     return URL();
575 }
576
577 CURLcode CurlHandle::getPrimaryPort(long& port)
578 {
579     CURLcode errCd = CURLE_FAILED_INIT;
580     port = 0;
581
582     if (m_handle)
583         errCd = curl_easy_getinfo(m_handle, CURLINFO_PRIMARY_PORT, &port);
584
585     return errCd;
586 }
587
588 CURLcode CurlHandle::getResponseCode(long& responseCode)
589 {
590     CURLcode errCd = CURLE_FAILED_INIT;
591     responseCode = 0L;
592
593     if (m_handle)
594         errCd = curl_easy_getinfo(m_handle, CURLINFO_RESPONSE_CODE, &responseCode);
595
596     return errCd;
597 }
598
599 CURLcode CurlHandle::getContentLenghtDownload(long long& contentLength)
600 {
601     CURLcode errCd = CURLE_FAILED_INIT;
602     contentLength = 0;
603
604     if (m_handle) {
605         double tmpContentLength = 0;
606
607         errCd = curl_easy_getinfo(m_handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &tmpContentLength);
608         if (errCd == CURLE_OK)
609             contentLength = static_cast<long long>(tmpContentLength);
610     }
611
612     return errCd;
613 }
614
615 CURLcode CurlHandle::getHttpAuthAvail(long& httpAuthAvail)
616 {
617     CURLcode errCd = CURLE_FAILED_INIT;
618
619     if (m_handle)
620         errCd = curl_easy_getinfo(m_handle, CURLINFO_HTTPAUTH_AVAIL, &httpAuthAvail);
621
622     return errCd;
623 }
624
625 CURLcode CurlHandle::getTimes(double& namelookup, double& connect, double& appconnect, double& pretransfer)
626 {
627     CURLcode errCd = CURLE_FAILED_INIT;
628
629     if (!m_handle)
630         return errCd;
631
632     errCd = curl_easy_getinfo(m_handle, CURLINFO_NAMELOOKUP_TIME, &namelookup);
633     if (errCd != CURLE_OK)
634         return errCd;
635
636     errCd = curl_easy_getinfo(m_handle, CURLINFO_CONNECT_TIME, &connect);
637     if (errCd != CURLE_OK)
638         return errCd;
639
640     errCd = curl_easy_getinfo(m_handle, CURLINFO_APPCONNECT_TIME, &appconnect);
641     if (errCd != CURLE_OK)
642         return errCd;
643
644     errCd = curl_easy_getinfo(m_handle, CURLINFO_PRETRANSFER_TIME, &pretransfer);
645     if (errCd != CURLE_OK)
646         return errCd;
647
648     return errCd;
649 }
650
651 long long CurlHandle::maxCurlOffT()
652 {
653     static const long long maxCurlOffT = (1LL << (expectedSizeOfCurlOffT() * 8 - 1)) - 1;
654
655     return maxCurlOffT;
656 }
657
658 int CurlHandle::expectedSizeOfCurlOffT()
659 {
660     // The size of a curl_off_t could be different in WebKit and in cURL depending on
661     // compilation flags of both.
662     static int expectedSizeOfCurlOffT = 0;
663     if (!expectedSizeOfCurlOffT) {
664         curl_version_info_data* infoData = curl_version_info(CURLVERSION_NOW);
665         if (infoData->features & CURL_VERSION_LARGEFILE)
666             expectedSizeOfCurlOffT = sizeof(long long);
667         else
668             expectedSizeOfCurlOffT = sizeof(int);
669     }
670
671     return expectedSizeOfCurlOffT;
672 }
673
674 #ifndef NDEBUG
675
676 void CurlHandle::enableVerboseIfUsed()
677 {
678     if (CurlContext::singleton().isVerbose())
679         curl_easy_setopt(m_handle, CURLOPT_VERBOSE, 1);
680 }
681
682 void CurlHandle::enableStdErrIfUsed()
683 {
684     if (CurlContext::singleton().getLogFile())
685         curl_easy_setopt(m_handle, CURLOPT_VERBOSE, 1);
686 }
687
688 #endif
689
690 }
691
692 #endif