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