e0a80f455b06a2f58ccfbdf68394666e13954abc
[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     m_curlHandle->enableCookieJarIfExists();
204
205     m_curlHandle->setSslVerifyPeer(CurlHandle::VerifyPeer::Enable);
206     m_curlHandle->setSslVerifyHost(CurlHandle::VerifyHost::StrictNameCheck);
207
208     auto sslClientCertificate = sslHandle.getSSLClientCertificate(m_request.url().host());
209     if (sslClientCertificate) {
210         m_curlHandle->setSslCert(sslClientCertificate->first.utf8().data());
211         m_curlHandle->setSslCertType("P12");
212         m_curlHandle->setSslKeyPassword(sslClientCertificate->second.utf8().data());
213     }
214
215     if (sslHandle.shouldIgnoreSSLErrors())
216         m_curlHandle->setSslVerifyPeer(CurlHandle::VerifyPeer::Disable);
217     else
218         m_curlHandle->setSslCtxCallbackFunction(willSetupSslCtxCallback, this);
219
220     m_curlHandle->setCACertPath(sslHandle.getCACertPath());
221
222     if (m_shouldSuspend)
223         suspend();
224
225 #ifndef NDEBUG
226     m_curlHandle->enableVerboseIfUsed();
227     m_curlHandle->enableStdErrIfUsed();
228 #endif
229
230     return m_curlHandle->handle();
231 }
232
233 CURLcode CurlRequest::willSetupSslCtx(void* sslCtx)
234 {
235     m_sslVerifier = std::make_unique<CurlSSLVerifier>(m_curlHandle.get(), m_request.url().host(), sslCtx);
236
237     return CURLE_OK;
238 }
239
240 // This is called to obtain HTTP POST or PUT data.
241 // Iterate through FormData elements and upload files.
242 // Carefully respect the given buffer size and fill the rest of the data at the next calls.
243
244 size_t CurlRequest::willSendData(char* buffer, size_t blockSize, size_t numberOfBlocks)
245 {
246     if (isCompletedOrCancelled())
247         return CURL_READFUNC_ABORT;
248
249     if (!blockSize || !numberOfBlocks)
250         return CURL_READFUNC_ABORT;
251
252     // Check for overflow.
253     if (blockSize > (std::numeric_limits<size_t>::max() / numberOfBlocks))
254         return CURL_READFUNC_ABORT;
255
256     size_t bufferSize = blockSize * numberOfBlocks;
257     auto sendBytes = m_formDataStream.read(buffer, bufferSize);
258     if (!sendBytes) {
259         // Something went wrong so error the job.
260         return CURL_READFUNC_ABORT;
261     }
262
263     callClient([this, totalReadSize = m_formDataStream.totalReadSize(), totalSize = m_formDataStream.totalSize()](CurlRequestClient& client) {
264         client.curlDidSendData(totalReadSize, totalSize);
265     });
266
267     return *sendBytes;
268 }
269
270 // This is being called for each HTTP header in the response. This includes '\r\n'
271 // for the last line of the header.
272
273 size_t CurlRequest::didReceiveHeader(String&& header)
274 {
275     static const auto emptyLineCRLF = "\r\n";
276     static const auto emptyLineLF = "\n";
277
278     if (isCompletedOrCancelled())
279         return 0;
280
281     // libcurl sends all headers that libcurl received to application.
282     // So, in digest authentication, a block of response headers are received twice consecutively from libcurl.
283     // For example, when authentication succeeds, the first block is "401 Authorization", and the second block is "200 OK".
284     // Also, "100 Continue" and "200 Connection Established" do the same behavior.
285     // In this process, deletes the first block to send a correct headers to WebCore.
286     if (m_didReceiveResponse) {
287         m_didReceiveResponse = false;
288         m_response = CurlResponse { };
289         m_multipartHandle = nullptr;
290     }
291
292     auto receiveBytes = static_cast<size_t>(header.length());
293
294     // The HTTP standard requires to use \r\n but for compatibility it recommends to accept also \n.
295     if ((header != emptyLineCRLF) && (header != emptyLineLF)) {
296         m_response.headers.append(WTFMove(header));
297         return receiveBytes;
298     }
299
300     long statusCode = 0;
301     if (auto code = m_curlHandle->getResponseCode())
302         statusCode = *code;
303
304     long httpConnectCode = 0;
305     if (auto code = m_curlHandle->getHttpConnectCode())
306         httpConnectCode = *code;
307
308     m_didReceiveResponse = true;
309
310     m_response.url = m_request.url();
311     m_response.statusCode = statusCode;
312
313     if (auto length = m_curlHandle->getContentLength())
314         m_response.expectedContentLength = *length;
315
316     if (auto port = m_curlHandle->getPrimaryPort())
317         m_response.connectPort = *port;
318
319     if (auto auth = m_curlHandle->getHttpAuthAvail())
320         m_response.availableHttpAuth = *auth;
321
322     if (auto version = m_curlHandle->getHttpVersion())
323         m_response.httpVersion = *version;
324
325     if (auto metrics = m_curlHandle->getNetworkLoadMetrics())
326         m_networkLoadMetrics = *metrics;
327
328     if (m_enableMultipart)
329         m_multipartHandle = CurlMultipartHandle::createIfNeeded(*this, m_response);
330
331     // Response will send at didReceiveData() or didCompleteTransfer()
332     // to receive continueDidRceiveResponse() for asynchronously.
333
334     return receiveBytes;
335 }
336
337 // called with data after all headers have been processed via headerCallback
338
339 size_t CurlRequest::didReceiveData(Ref<SharedBuffer>&& buffer)
340 {
341     if (isCompletedOrCancelled())
342         return 0;
343
344     if (needToInvokeDidReceiveResponse()) {
345         if (!m_isSyncRequest) {
346             // For asynchronous, pause until completeDidReceiveResponse() is called.
347             setCallbackPaused(true);
348             invokeDidReceiveResponse(m_response, Action::ReceiveData);
349             return CURL_WRITEFUNC_PAUSE;
350         }
351
352         // For synchronous, completeDidReceiveResponse() is called in invokeDidReceiveResponse().
353         // In this case, pause is unnecessary.
354         invokeDidReceiveResponse(m_response, Action::None);
355     }
356
357     auto receiveBytes = buffer->size();
358
359     writeDataToDownloadFileIfEnabled(buffer);
360
361     if (receiveBytes) {
362         if (m_multipartHandle)
363             m_multipartHandle->didReceiveData(buffer);
364         else {
365             callClient([buffer = WTFMove(buffer)](CurlRequestClient& client) mutable {
366                 client.curlDidReceiveBuffer(WTFMove(buffer));
367             });
368         }
369     }
370
371     return receiveBytes;
372 }
373
374 void CurlRequest::didReceiveHeaderFromMultipart(const Vector<String>& headers)
375 {
376     if (isCompletedOrCancelled())
377         return;
378
379     CurlResponse response = m_response.isolatedCopy();
380     response.expectedContentLength = 0;
381     response.headers.clear();
382
383     for (auto header : headers)
384         response.headers.append(header);
385
386     invokeDidReceiveResponse(response, Action::None);
387 }
388
389 void CurlRequest::didReceiveDataFromMultipart(Ref<SharedBuffer>&& buffer)
390 {
391     if (isCompletedOrCancelled())
392         return;
393
394     auto receiveBytes = buffer->size();
395
396     if (receiveBytes) {
397         callClient([buffer = WTFMove(buffer)](CurlRequestClient& client) mutable {
398             client.curlDidReceiveBuffer(WTFMove(buffer));
399         });
400     }
401 }
402
403 void CurlRequest::didCompleteTransfer(CURLcode result)
404 {
405     if (m_cancelled) {
406         m_curlHandle = nullptr;
407         return;
408     }
409
410     if (result == CURLE_OK) {
411         if (needToInvokeDidReceiveResponse()) {
412             // Processing of didReceiveResponse() has not been completed. (For example, HEAD method)
413             // When completeDidReceiveResponse() is called, didCompleteTransfer() will be called again.
414
415             m_finishedResultCode = result;
416             invokeDidReceiveResponse(m_response, Action::FinishTransfer);
417         } else {
418             if (m_multipartHandle)
419                 m_multipartHandle->didComplete();
420
421             if (auto metrics = m_curlHandle->getNetworkLoadMetrics())
422                 m_networkLoadMetrics = *metrics;
423
424             finalizeTransfer();
425             callClient([](CurlRequestClient& client) {
426                 client.curlDidComplete();
427             });
428         }
429     } else {
430         auto type = (result == CURLE_OPERATION_TIMEDOUT && m_request.timeoutInterval() > 0.0) ? ResourceError::Type::Timeout : ResourceError::Type::General;
431         auto resourceError = ResourceError::httpError(result, m_request.url(), type);
432         if (m_sslVerifier && m_sslVerifier->sslErrors())
433             resourceError.setSslErrors(m_sslVerifier->sslErrors());
434
435         finalizeTransfer();
436         callClient([error = resourceError.isolatedCopy()](CurlRequestClient& client) {
437             client.curlDidFailWithError(error);
438         });
439     }
440 }
441
442 void CurlRequest::didCancelTransfer()
443 {
444     finalizeTransfer();
445     cleanupDownloadFile();
446 }
447
448 void CurlRequest::finalizeTransfer()
449 {
450     closeDownloadFile();
451     m_formDataStream.clean();
452     m_sslVerifier = nullptr;
453     m_multipartHandle = nullptr;
454     m_curlHandle = nullptr;
455 }
456
457 void CurlRequest::setupPUT(ResourceRequest& request)
458 {
459     m_curlHandle->enableHttpPutRequest();
460
461     // Disable the Expect: 100 continue header
462     m_curlHandle->removeRequestHeader("Expect");
463
464     auto elementSize = m_formDataStream.elementSize();
465     if (!elementSize)
466         return;
467
468     setupSendData(true);
469 }
470
471 void CurlRequest::setupPOST(ResourceRequest& request)
472 {
473     m_curlHandle->enableHttpPostRequest();
474
475     auto elementSize = m_formDataStream.elementSize();
476     if (!elementSize)
477         return;
478
479     // Do not stream for simple POST data
480     if (elementSize == 1) {
481         auto postData = m_formDataStream.getPostData();
482         if (postData && postData->size())
483             m_curlHandle->setPostFields(postData->data(), postData->size());
484     } else
485         setupSendData(false);
486 }
487
488 void CurlRequest::setupSendData(bool forPutMethod)
489 {
490     // curl guesses that we want chunked encoding as long as we specify the header
491     if (m_formDataStream.shouldUseChunkTransfer())
492         m_curlHandle->appendRequestHeader("Transfer-Encoding: chunked");
493     else {
494         if (forPutMethod)
495             m_curlHandle->setInFileSizeLarge(static_cast<curl_off_t>(m_formDataStream.totalSize()));
496         else
497             m_curlHandle->setPostFieldLarge(static_cast<curl_off_t>(m_formDataStream.totalSize()));
498     }
499
500     m_curlHandle->setReadCallbackFunction(willSendDataCallback, this);
501 }
502
503 void CurlRequest::invokeDidReceiveResponseForFile(URL& url)
504 {
505     // Since the code in didReceiveHeader() will not have run for local files
506     // the code to set the URL and fire didReceiveResponse is never run,
507     // which means the ResourceLoader's response does not contain the URL.
508     // Run the code here for local files to resolve the issue.
509
510     ASSERT(isMainThread());
511     ASSERT(url.isLocalFile());
512
513     m_response.url = url;
514     m_response.statusCode = 200;
515
516     // Determine the MIME type based on the path.
517     m_response.headers.append(String("Content-Type: " + MIMETypeRegistry::getMIMETypeForPath(m_response.url.path())));
518
519     if (!m_isSyncRequest) {
520         // DidReceiveResponse must not be called immediately
521         CurlRequestScheduler::singleton().callOnWorkerThread([protectedThis = makeRef(*this)]() {
522             protectedThis->invokeDidReceiveResponse(protectedThis->m_response, Action::StartTransfer);
523         });
524     } else {
525         // For synchronous, completeDidReceiveResponse() is called in platformContinueSynchronousDidReceiveResponse().
526         invokeDidReceiveResponse(m_response, Action::None);
527     }
528 }
529
530 void CurlRequest::invokeDidReceiveResponse(const CurlResponse& response, Action behaviorAfterInvoke)
531 {
532     ASSERT(!m_didNotifyResponse || m_multipartHandle);
533
534     m_didNotifyResponse = true;
535     m_actionAfterInvoke = behaviorAfterInvoke;
536
537     callClient([response = response.isolatedCopy()](CurlRequestClient& client) {
538         client.curlDidReceiveResponse(response);
539     });
540 }
541
542 void CurlRequest::completeDidReceiveResponse()
543 {
544     ASSERT(isMainThread());
545     ASSERT(m_didNotifyResponse);
546     ASSERT(!m_didReturnFromNotify || m_multipartHandle);
547
548     if (isCancelled())
549         return;
550
551     if (m_actionAfterInvoke != Action::StartTransfer && isCompleted())
552         return;
553
554     m_didReturnFromNotify = true;
555
556     if (m_actionAfterInvoke == Action::ReceiveData) {
557         // Resume transfer
558         setCallbackPaused(false);
559     } else if (m_actionAfterInvoke == Action::StartTransfer) {
560         // Start transfer for file scheme
561         startWithJobManager();
562     } else if (m_actionAfterInvoke == Action::FinishTransfer) {
563         if (!m_isSyncRequest) {
564             CurlRequestScheduler::singleton().callOnWorkerThread([protectedThis = makeRef(*this), finishedResultCode = m_finishedResultCode]() {
565                 protectedThis->didCompleteTransfer(finishedResultCode);
566             });
567         } else
568             didCompleteTransfer(m_finishedResultCode);
569     }
570 }
571
572 void CurlRequest::setRequestPaused(bool paused)
573 {
574     auto wasPaused = isPaused();
575
576     m_isPausedOfRequest = paused;
577
578     if (isPaused() == wasPaused)
579         return;
580
581     pausedStatusChanged();
582 }
583
584 void CurlRequest::setCallbackPaused(bool paused)
585 {
586     auto wasPaused = isPaused();
587
588     m_isPausedOfCallback = paused;
589
590     if (isPaused() == wasPaused)
591         return;
592
593     // In this case, PAUSE will be executed within didReceiveData(). Change pause state and return.
594     if (paused)
595         return;
596
597     pausedStatusChanged();
598 }
599
600 void CurlRequest::pausedStatusChanged()
601 {
602     if (isCompletedOrCancelled())
603         return;
604
605     if (!m_isSyncRequest && isMainThread()) {
606         CurlRequestScheduler::singleton().callOnWorkerThread([protectedThis = makeRef(*this), paused = isPaused()]() {
607             if (protectedThis->isCompletedOrCancelled())
608                 return;
609
610             auto error = protectedThis->m_curlHandle->pause(paused ? CURLPAUSE_ALL : CURLPAUSE_CONT);
611             if ((error != CURLE_OK) && !paused) {
612                 // Restarting the handle has failed so just cancel it.
613                 callOnMainThread([protectedThis = makeRef(protectedThis.get())]() {
614                     protectedThis->cancel();
615                 });
616             }
617         });
618     } else {
619         auto error = m_curlHandle->pause(isPaused() ? CURLPAUSE_ALL : CURLPAUSE_CONT);
620         if ((error != CURLE_OK) && !isPaused())
621             cancel();
622     }
623 }
624
625 void CurlRequest::enableDownloadToFile()
626 {
627     LockHolder locker(m_downloadMutex);
628     m_isEnabledDownloadToFile = true;
629 }
630
631 const String& CurlRequest::getDownloadedFilePath()
632 {
633     LockHolder locker(m_downloadMutex);
634     return m_downloadFilePath;
635 }
636
637 void CurlRequest::writeDataToDownloadFileIfEnabled(const SharedBuffer& buffer)
638 {
639     {
640         LockHolder locker(m_downloadMutex);
641
642         if (!m_isEnabledDownloadToFile)
643             return;
644
645         if (m_downloadFilePath.isEmpty())
646             m_downloadFilePath = FileSystem::openTemporaryFile("download", m_downloadFileHandle);
647     }
648
649     if (m_downloadFileHandle != FileSystem::invalidPlatformFileHandle)
650         FileSystem::writeToFile(m_downloadFileHandle, buffer.data(), buffer.size());
651 }
652
653 void CurlRequest::closeDownloadFile()
654 {
655     LockHolder locker(m_downloadMutex);
656
657     if (m_downloadFileHandle == FileSystem::invalidPlatformFileHandle)
658         return;
659
660     FileSystem::closeFile(m_downloadFileHandle);
661     m_downloadFileHandle = FileSystem::invalidPlatformFileHandle;
662 }
663
664 void CurlRequest::cleanupDownloadFile()
665 {
666     LockHolder locker(m_downloadMutex);
667
668     if (!m_downloadFilePath.isEmpty()) {
669         FileSystem::deleteFile(m_downloadFilePath);
670         m_downloadFilePath = String();
671     }
672 }
673
674 CURLcode CurlRequest::willSetupSslCtxCallback(CURL*, void* sslCtx, void* userData)
675 {
676     return static_cast<CurlRequest*>(userData)->willSetupSslCtx(sslCtx);
677 }
678
679 size_t CurlRequest::willSendDataCallback(char* ptr, size_t blockSize, size_t numberOfBlocks, void* userData)
680 {
681     return static_cast<CurlRequest*>(userData)->willSendData(ptr, blockSize, numberOfBlocks);
682 }
683
684 size_t CurlRequest::didReceiveHeaderCallback(char* ptr, size_t blockSize, size_t numberOfBlocks, void* userData)
685 {
686     return static_cast<CurlRequest*>(userData)->didReceiveHeader(String(ptr, blockSize * numberOfBlocks));
687 }
688
689 size_t CurlRequest::didReceiveDataCallback(char* ptr, size_t blockSize, size_t numberOfBlocks, void* userData)
690 {
691     return static_cast<CurlRequest*>(userData)->didReceiveData(SharedBuffer::create(ptr, blockSize * numberOfBlocks));
692 }
693
694 }
695
696 #endif