[Curl] Use SQLite database in cookie jar implementation for Curl port
[WebKit-https.git] / Source / WebCore / platform / network / curl / CurlRequest.cpp
1 /*
2  * Copyright (C) 2017 Sony Interactive Entertainment Inc.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  * 
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "CurlRequest.h"
28
29 #if USE(CURL)
30
31 #include "CurlRequestClient.h"
32 #include "CurlRequestScheduler.h"
33 #include "MIMETypeRegistry.h"
34 #include "ResourceError.h"
35 #include "SharedBuffer.h"
36 #include <wtf/MainThread.h>
37
38 namespace WebCore {
39
40 CurlRequest::CurlRequest(const ResourceRequest&request, CurlRequestClient* client, bool shouldSuspend, bool enableMultipart)
41     : m_request(request.isolatedCopy())
42     , m_shouldSuspend(shouldSuspend)
43     , m_enableMultipart(enableMultipart)
44     , m_formDataStream(m_request.httpBody())
45 {
46     ASSERT(isMainThread());
47
48     setClient(client);
49 }
50
51 void CurlRequest::setUserPass(const String& user, const String& password)
52 {
53     ASSERT(isMainThread());
54
55     m_user = user.isolatedCopy();
56     m_password = password.isolatedCopy();
57 }
58
59 void CurlRequest::start(bool isSyncRequest)
60 {
61     // The pausing of transfer does not work with protocols, like file://.
62     // Therefore, PAUSE can not be done in didReceiveData().
63     // It means that the same logic as http:// can not be used.
64     // In the file scheme, invokeDidReceiveResponse() is done first. 
65     // Then StartWithJobManager is called with completeDidReceiveResponse and start transfer with libcurl.
66
67     // http : didReceiveHeader => didReceiveData[PAUSE] => invokeDidReceiveResponse => (MainThread)curlDidReceiveResponse => completeDidReceiveResponse[RESUME] => didReceiveData
68     // file : invokeDidReceiveResponseForFile => (MainThread)curlDidReceiveResponse => completeDidReceiveResponse => didReceiveData
69
70     ASSERT(isMainThread());
71
72     m_isSyncRequest = isSyncRequest;
73
74     auto url = m_request.url().isolatedCopy();
75
76     if (!m_isSyncRequest) {
77         // For asynchronous, use CurlRequestScheduler. Curl processes runs on sub thread.
78         if (url.isLocalFile())
79             invokeDidReceiveResponseForFile(url);
80         else
81             startWithJobManager();
82     } else {
83         // For synchronous, does not use CurlRequestScheduler. Curl processes runs on main thread.
84         // curl_easy_perform blocks until the transfer is finished.
85         retain();
86         if (url.isLocalFile())
87             invokeDidReceiveResponseForFile(url);
88
89         setupTransfer();
90         CURLcode resultCode = m_curlHandle->perform();
91         didCompleteTransfer(resultCode);
92         release();
93     }
94 }
95
96 void CurlRequest::startWithJobManager()
97 {
98     ASSERT(isMainThread());
99
100     CurlRequestScheduler::singleton().add(this);
101 }
102
103 void CurlRequest::cancel()
104 {
105     ASSERT(isMainThread());
106
107     if (isCompletedOrCancelled())
108         return;
109
110     m_cancelled = true;
111
112     if (!m_isSyncRequest) {
113         auto& scheduler = CurlRequestScheduler::singleton();
114
115         if (needToInvokeDidCancelTransfer()) {
116             scheduler.callOnWorkerThread([protectedThis = makeRef(*this)]() {
117                 protectedThis->didCancelTransfer();
118             });
119         } else
120             scheduler.cancel(this);
121     } else {
122         if (needToInvokeDidCancelTransfer())
123             didCancelTransfer();
124     }
125
126     setRequestPaused(false);
127     setCallbackPaused(false);
128 }
129
130 void CurlRequest::suspend()
131 {
132     ASSERT(isMainThread());
133
134     setRequestPaused(true);
135 }
136
137 void CurlRequest::resume()
138 {
139     ASSERT(isMainThread());
140
141     setRequestPaused(false);
142 }
143
144 /* `this` is protected inside this method. */
145 void CurlRequest::callClient(WTF::Function<void(CurlRequestClient&)> task)
146 {
147     if (isMainThread()) {
148         if (CurlRequestClient* client = m_client) {
149             RefPtr<CurlRequestClient> protectedClient(client);
150             task(*client);
151         }
152     } else {
153         callOnMainThread([protectedThis = makeRef(*this), task = WTFMove(task)]() mutable {
154             if (CurlRequestClient* client = protectedThis->m_client) {
155                 RefPtr<CurlRequestClient> protectedClient(client);
156                 task(*client);
157             }
158         });
159     }
160 }
161
162 CURL* CurlRequest::setupTransfer()
163 {
164     auto& sslHandle = CurlContext::singleton().sslHandle();
165
166     m_curlHandle = std::make_unique<CurlHandle>();
167
168     m_curlHandle->initialize();
169     m_curlHandle->setUrl(m_request.url());
170     m_curlHandle->appendRequestHeaders(m_request.httpHeaderFields());
171
172     const auto& method = m_request.httpMethod();
173     if (method == "GET")
174         m_curlHandle->enableHttpGetRequest();
175     else if (method == "POST")
176         setupPOST(m_request);
177     else if (method == "PUT")
178         setupPUT(m_request);
179     else if (method == "HEAD")
180         m_curlHandle->enableHttpHeadRequest();
181     else {
182         m_curlHandle->setHttpCustomRequest(method);
183         setupPUT(m_request);
184     }
185
186     if (!m_user.isEmpty() || !m_password.isEmpty()) {
187         m_curlHandle->enableHttpAuthentication(CURLAUTH_ANY);
188         m_curlHandle->setHttpAuthUserPass(m_user, m_password);
189     }
190
191     m_curlHandle->setHeaderCallbackFunction(didReceiveHeaderCallback, this);
192     m_curlHandle->setWriteCallbackFunction(didReceiveDataCallback, this);
193
194     m_curlHandle->enableShareHandle();
195     m_curlHandle->enableAllowedProtocols();
196     m_curlHandle->enableAcceptEncoding();
197     m_curlHandle->enableTimeout();
198
199     long timeoutMilliseconds = (m_request.timeoutInterval() > 0.0) ? static_cast<long>(m_request.timeoutInterval() * 1000.0) : 0;
200     m_curlHandle->setTimeout(timeoutMilliseconds);
201
202     m_curlHandle->enableProxyIfExists();
203
204     m_curlHandle->setSslVerifyPeer(CurlHandle::VerifyPeer::Enable);
205     m_curlHandle->setSslVerifyHost(CurlHandle::VerifyHost::StrictNameCheck);
206
207     auto sslClientCertificate = sslHandle.getSSLClientCertificate(m_request.url().host());
208     if (sslClientCertificate) {
209         m_curlHandle->setSslCert(sslClientCertificate->first.utf8().data());
210         m_curlHandle->setSslCertType("P12");
211         m_curlHandle->setSslKeyPassword(sslClientCertificate->second.utf8().data());
212     }
213
214     if (sslHandle.shouldIgnoreSSLErrors())
215         m_curlHandle->setSslVerifyPeer(CurlHandle::VerifyPeer::Disable);
216     else
217         m_curlHandle->setSslCtxCallbackFunction(willSetupSslCtxCallback, this);
218
219     m_curlHandle->setCACertPath(sslHandle.getCACertPath());
220
221     if (m_shouldSuspend)
222         suspend();
223
224 #ifndef NDEBUG
225     m_curlHandle->enableVerboseIfUsed();
226     m_curlHandle->enableStdErrIfUsed();
227 #endif
228
229     return m_curlHandle->handle();
230 }
231
232 CURLcode CurlRequest::willSetupSslCtx(void* sslCtx)
233 {
234     m_sslVerifier = std::make_unique<CurlSSLVerifier>(m_curlHandle.get(), m_request.url().host(), sslCtx);
235
236     return CURLE_OK;
237 }
238
239 // This is called to obtain HTTP POST or PUT data.
240 // Iterate through FormData elements and upload files.
241 // Carefully respect the given buffer size and fill the rest of the data at the next calls.
242
243 size_t CurlRequest::willSendData(char* buffer, size_t blockSize, size_t numberOfBlocks)
244 {
245     if (isCompletedOrCancelled())
246         return CURL_READFUNC_ABORT;
247
248     if (!blockSize || !numberOfBlocks)
249         return CURL_READFUNC_ABORT;
250
251     // Check for overflow.
252     if (blockSize > (std::numeric_limits<size_t>::max() / numberOfBlocks))
253         return CURL_READFUNC_ABORT;
254
255     size_t bufferSize = blockSize * numberOfBlocks;
256     auto sendBytes = m_formDataStream.read(buffer, bufferSize);
257     if (!sendBytes) {
258         // Something went wrong so error the job.
259         return CURL_READFUNC_ABORT;
260     }
261
262     callClient([this, totalReadSize = m_formDataStream.totalReadSize(), totalSize = m_formDataStream.totalSize()](CurlRequestClient& client) {
263         client.curlDidSendData(totalReadSize, totalSize);
264     });
265
266     return *sendBytes;
267 }
268
269 // This is being called for each HTTP header in the response. This includes '\r\n'
270 // for the last line of the header.
271
272 size_t CurlRequest::didReceiveHeader(String&& header)
273 {
274     static const auto emptyLineCRLF = "\r\n";
275     static const auto emptyLineLF = "\n";
276
277     if (isCompletedOrCancelled())
278         return 0;
279
280     // libcurl sends all headers that libcurl received to application.
281     // So, in digest authentication, a block of response headers are received twice consecutively from libcurl.
282     // For example, when authentication succeeds, the first block is "401 Authorization", and the second block is "200 OK".
283     // Also, "100 Continue" and "200 Connection Established" do the same behavior.
284     // In this process, deletes the first block to send a correct headers to WebCore.
285     if (m_didReceiveResponse) {
286         m_didReceiveResponse = false;
287         m_response = CurlResponse { };
288         m_multipartHandle = nullptr;
289     }
290
291     auto receiveBytes = static_cast<size_t>(header.length());
292
293     // The HTTP standard requires to use \r\n but for compatibility it recommends to accept also \n.
294     if ((header != emptyLineCRLF) && (header != emptyLineLF)) {
295         m_response.headers.append(WTFMove(header));
296         return receiveBytes;
297     }
298
299     long statusCode = 0;
300     if (auto code = m_curlHandle->getResponseCode())
301         statusCode = *code;
302
303     long httpConnectCode = 0;
304     if (auto code = m_curlHandle->getHttpConnectCode())
305         httpConnectCode = *code;
306
307     m_didReceiveResponse = true;
308
309     m_response.url = m_request.url();
310     m_response.statusCode = statusCode;
311
312     if (auto length = m_curlHandle->getContentLength())
313         m_response.expectedContentLength = *length;
314
315     if (auto port = m_curlHandle->getPrimaryPort())
316         m_response.connectPort = *port;
317
318     if (auto auth = m_curlHandle->getHttpAuthAvail())
319         m_response.availableHttpAuth = *auth;
320
321     if (auto version = m_curlHandle->getHttpVersion())
322         m_response.httpVersion = *version;
323
324     if (auto metrics = m_curlHandle->getNetworkLoadMetrics())
325         m_networkLoadMetrics = *metrics;
326
327     if (m_enableMultipart)
328         m_multipartHandle = CurlMultipartHandle::createIfNeeded(*this, m_response);
329
330     // Response will send at didReceiveData() or didCompleteTransfer()
331     // to receive continueDidRceiveResponse() for asynchronously.
332
333     return receiveBytes;
334 }
335
336 // called with data after all headers have been processed via headerCallback
337
338 size_t CurlRequest::didReceiveData(Ref<SharedBuffer>&& buffer)
339 {
340     if (isCompletedOrCancelled())
341         return 0;
342
343     if (needToInvokeDidReceiveResponse()) {
344         if (!m_isSyncRequest) {
345             // For asynchronous, pause until completeDidReceiveResponse() is called.
346             setCallbackPaused(true);
347             invokeDidReceiveResponse(m_response, Action::ReceiveData);
348             return CURL_WRITEFUNC_PAUSE;
349         }
350
351         // For synchronous, completeDidReceiveResponse() is called in invokeDidReceiveResponse().
352         // In this case, pause is unnecessary.
353         invokeDidReceiveResponse(m_response, Action::None);
354     }
355
356     auto receiveBytes = buffer->size();
357
358     writeDataToDownloadFileIfEnabled(buffer);
359
360     if (receiveBytes) {
361         if (m_multipartHandle)
362             m_multipartHandle->didReceiveData(buffer);
363         else {
364             callClient([buffer = WTFMove(buffer)](CurlRequestClient& client) mutable {
365                 client.curlDidReceiveBuffer(WTFMove(buffer));
366             });
367         }
368     }
369
370     return receiveBytes;
371 }
372
373 void CurlRequest::didReceiveHeaderFromMultipart(const Vector<String>& headers)
374 {
375     if (isCompletedOrCancelled())
376         return;
377
378     CurlResponse response = m_response.isolatedCopy();
379     response.expectedContentLength = 0;
380     response.headers.clear();
381
382     for (auto header : headers)
383         response.headers.append(header);
384
385     invokeDidReceiveResponse(response, Action::None);
386 }
387
388 void CurlRequest::didReceiveDataFromMultipart(Ref<SharedBuffer>&& buffer)
389 {
390     if (isCompletedOrCancelled())
391         return;
392
393     auto receiveBytes = buffer->size();
394
395     if (receiveBytes) {
396         callClient([buffer = WTFMove(buffer)](CurlRequestClient& client) mutable {
397             client.curlDidReceiveBuffer(WTFMove(buffer));
398         });
399     }
400 }
401
402 void CurlRequest::didCompleteTransfer(CURLcode result)
403 {
404     if (m_cancelled) {
405         m_curlHandle = nullptr;
406         return;
407     }
408
409     if (result == CURLE_OK) {
410         if (needToInvokeDidReceiveResponse()) {
411             // Processing of didReceiveResponse() has not been completed. (For example, HEAD method)
412             // When completeDidReceiveResponse() is called, didCompleteTransfer() will be called again.
413
414             m_finishedResultCode = result;
415             invokeDidReceiveResponse(m_response, Action::FinishTransfer);
416         } else {
417             if (m_multipartHandle)
418                 m_multipartHandle->didComplete();
419
420             if (auto metrics = m_curlHandle->getNetworkLoadMetrics())
421                 m_networkLoadMetrics = *metrics;
422
423             finalizeTransfer();
424             callClient([](CurlRequestClient& client) {
425                 client.curlDidComplete();
426             });
427         }
428     } else {
429         auto type = (result == CURLE_OPERATION_TIMEDOUT && m_request.timeoutInterval() > 0.0) ? ResourceError::Type::Timeout : ResourceError::Type::General;
430         auto resourceError = ResourceError::httpError(result, m_request.url(), type);
431         if (m_sslVerifier && m_sslVerifier->sslErrors())
432             resourceError.setSslErrors(m_sslVerifier->sslErrors());
433
434         finalizeTransfer();
435         callClient([error = resourceError.isolatedCopy()](CurlRequestClient& client) {
436             client.curlDidFailWithError(error);
437         });
438     }
439 }
440
441 void CurlRequest::didCancelTransfer()
442 {
443     finalizeTransfer();
444     cleanupDownloadFile();
445 }
446
447 void CurlRequest::finalizeTransfer()
448 {
449     closeDownloadFile();
450     m_formDataStream.clean();
451     m_sslVerifier = nullptr;
452     m_multipartHandle = nullptr;
453     m_curlHandle = nullptr;
454 }
455
456 void CurlRequest::setupPUT(ResourceRequest& request)
457 {
458     m_curlHandle->enableHttpPutRequest();
459
460     // Disable the Expect: 100 continue header
461     m_curlHandle->removeRequestHeader("Expect");
462
463     auto elementSize = m_formDataStream.elementSize();
464     if (!elementSize)
465         return;
466
467     setupSendData(true);
468 }
469
470 void CurlRequest::setupPOST(ResourceRequest& request)
471 {
472     m_curlHandle->enableHttpPostRequest();
473
474     auto elementSize = m_formDataStream.elementSize();
475     if (!elementSize)
476         return;
477
478     // Do not stream for simple POST data
479     if (elementSize == 1) {
480         auto postData = m_formDataStream.getPostData();
481         if (postData && postData->size())
482             m_curlHandle->setPostFields(postData->data(), postData->size());
483     } else
484         setupSendData(false);
485 }
486
487 void CurlRequest::setupSendData(bool forPutMethod)
488 {
489     // curl guesses that we want chunked encoding as long as we specify the header
490     if (m_formDataStream.shouldUseChunkTransfer())
491         m_curlHandle->appendRequestHeader("Transfer-Encoding: chunked");
492     else {
493         if (forPutMethod)
494             m_curlHandle->setInFileSizeLarge(static_cast<curl_off_t>(m_formDataStream.totalSize()));
495         else
496             m_curlHandle->setPostFieldLarge(static_cast<curl_off_t>(m_formDataStream.totalSize()));
497     }
498
499     m_curlHandle->setReadCallbackFunction(willSendDataCallback, this);
500 }
501
502 void CurlRequest::invokeDidReceiveResponseForFile(URL& url)
503 {
504     // Since the code in didReceiveHeader() will not have run for local files
505     // the code to set the URL and fire didReceiveResponse is never run,
506     // which means the ResourceLoader's response does not contain the URL.
507     // Run the code here for local files to resolve the issue.
508
509     ASSERT(isMainThread());
510     ASSERT(url.isLocalFile());
511
512     m_response.url = url;
513     m_response.statusCode = 200;
514
515     // Determine the MIME type based on the path.
516     m_response.headers.append(String("Content-Type: " + MIMETypeRegistry::getMIMETypeForPath(m_response.url.path())));
517
518     if (!m_isSyncRequest) {
519         // DidReceiveResponse must not be called immediately
520         CurlRequestScheduler::singleton().callOnWorkerThread([protectedThis = makeRef(*this)]() {
521             protectedThis->invokeDidReceiveResponse(protectedThis->m_response, Action::StartTransfer);
522         });
523     } else {
524         // For synchronous, completeDidReceiveResponse() is called in platformContinueSynchronousDidReceiveResponse().
525         invokeDidReceiveResponse(m_response, Action::None);
526     }
527 }
528
529 void CurlRequest::invokeDidReceiveResponse(const CurlResponse& response, Action behaviorAfterInvoke)
530 {
531     ASSERT(!m_didNotifyResponse || m_multipartHandle);
532
533     m_didNotifyResponse = true;
534     m_actionAfterInvoke = behaviorAfterInvoke;
535
536     callClient([response = response.isolatedCopy()](CurlRequestClient& client) {
537         client.curlDidReceiveResponse(response);
538     });
539 }
540
541 void CurlRequest::completeDidReceiveResponse()
542 {
543     ASSERT(isMainThread());
544     ASSERT(m_didNotifyResponse);
545     ASSERT(!m_didReturnFromNotify || m_multipartHandle);
546
547     if (isCancelled())
548         return;
549
550     if (m_actionAfterInvoke != Action::StartTransfer && isCompleted())
551         return;
552
553     m_didReturnFromNotify = true;
554
555     if (m_actionAfterInvoke == Action::ReceiveData) {
556         // Resume transfer
557         setCallbackPaused(false);
558     } else if (m_actionAfterInvoke == Action::StartTransfer) {
559         // Start transfer for file scheme
560         startWithJobManager();
561     } else if (m_actionAfterInvoke == Action::FinishTransfer) {
562         if (!m_isSyncRequest) {
563             CurlRequestScheduler::singleton().callOnWorkerThread([protectedThis = makeRef(*this), finishedResultCode = m_finishedResultCode]() {
564                 protectedThis->didCompleteTransfer(finishedResultCode);
565             });
566         } else
567             didCompleteTransfer(m_finishedResultCode);
568     }
569 }
570
571 void CurlRequest::setRequestPaused(bool paused)
572 {
573     auto wasPaused = isPaused();
574
575     m_isPausedOfRequest = paused;
576
577     if (isPaused() == wasPaused)
578         return;
579
580     pausedStatusChanged();
581 }
582
583 void CurlRequest::setCallbackPaused(bool paused)
584 {
585     auto wasPaused = isPaused();
586
587     m_isPausedOfCallback = paused;
588
589     if (isPaused() == wasPaused)
590         return;
591
592     // In this case, PAUSE will be executed within didReceiveData(). Change pause state and return.
593     if (paused)
594         return;
595
596     pausedStatusChanged();
597 }
598
599 void CurlRequest::pausedStatusChanged()
600 {
601     if (isCompletedOrCancelled())
602         return;
603
604     if (!m_isSyncRequest && isMainThread()) {
605         CurlRequestScheduler::singleton().callOnWorkerThread([protectedThis = makeRef(*this), paused = isPaused()]() {
606             if (protectedThis->isCompletedOrCancelled())
607                 return;
608
609             auto error = protectedThis->m_curlHandle->pause(paused ? CURLPAUSE_ALL : CURLPAUSE_CONT);
610             if ((error != CURLE_OK) && !paused) {
611                 // Restarting the handle has failed so just cancel it.
612                 callOnMainThread([protectedThis = makeRef(protectedThis.get())]() {
613                     protectedThis->cancel();
614                 });
615             }
616         });
617     } else {
618         auto error = m_curlHandle->pause(isPaused() ? CURLPAUSE_ALL : CURLPAUSE_CONT);
619         if ((error != CURLE_OK) && !isPaused())
620             cancel();
621     }
622 }
623
624 void CurlRequest::enableDownloadToFile()
625 {
626     LockHolder locker(m_downloadMutex);
627     m_isEnabledDownloadToFile = true;
628 }
629
630 const String& CurlRequest::getDownloadedFilePath()
631 {
632     LockHolder locker(m_downloadMutex);
633     return m_downloadFilePath;
634 }
635
636 void CurlRequest::writeDataToDownloadFileIfEnabled(const SharedBuffer& buffer)
637 {
638     {
639         LockHolder locker(m_downloadMutex);
640
641         if (!m_isEnabledDownloadToFile)
642             return;
643
644         if (m_downloadFilePath.isEmpty())
645             m_downloadFilePath = FileSystem::openTemporaryFile("download", m_downloadFileHandle);
646     }
647
648     if (m_downloadFileHandle != FileSystem::invalidPlatformFileHandle)
649         FileSystem::writeToFile(m_downloadFileHandle, buffer.data(), buffer.size());
650 }
651
652 void CurlRequest::closeDownloadFile()
653 {
654     LockHolder locker(m_downloadMutex);
655
656     if (m_downloadFileHandle == FileSystem::invalidPlatformFileHandle)
657         return;
658
659     FileSystem::closeFile(m_downloadFileHandle);
660     m_downloadFileHandle = FileSystem::invalidPlatformFileHandle;
661 }
662
663 void CurlRequest::cleanupDownloadFile()
664 {
665     LockHolder locker(m_downloadMutex);
666
667     if (!m_downloadFilePath.isEmpty()) {
668         FileSystem::deleteFile(m_downloadFilePath);
669         m_downloadFilePath = String();
670     }
671 }
672
673 CURLcode CurlRequest::willSetupSslCtxCallback(CURL*, void* sslCtx, void* userData)
674 {
675     return static_cast<CurlRequest*>(userData)->willSetupSslCtx(sslCtx);
676 }
677
678 size_t CurlRequest::willSendDataCallback(char* ptr, size_t blockSize, size_t numberOfBlocks, void* userData)
679 {
680     return static_cast<CurlRequest*>(userData)->willSendData(ptr, blockSize, numberOfBlocks);
681 }
682
683 size_t CurlRequest::didReceiveHeaderCallback(char* ptr, size_t blockSize, size_t numberOfBlocks, void* userData)
684 {
685     return static_cast<CurlRequest*>(userData)->didReceiveHeader(String(ptr, blockSize * numberOfBlocks));
686 }
687
688 size_t CurlRequest::didReceiveDataCallback(char* ptr, size_t blockSize, size_t numberOfBlocks, void* userData)
689 {
690     return static_cast<CurlRequest*>(userData)->didReceiveData(SharedBuffer::create(ptr, blockSize * numberOfBlocks));
691 }
692
693 }
694
695 #endif