ebc37b0c101c73441feb942eadda5171ee88cf42
[WebKit-https.git] / Source / WebKit2 / WebProcess / Downloads / cf / DownloadCFNet.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
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 "Download.h"
28
29 #include "DataReference.h"
30 #include "NotImplemented.h"
31
32 #pragma warning(push, 0)
33 #include <WebCore/LoaderRunLoopCF.h>
34 #include <WebCore/ResourceError.h>
35 #include <WebCore/ResourceHandle.h>
36 #include <WebCore/ResourceResponse.h>
37 #pragma warning(pop)
38
39 using namespace WebCore;
40
41 namespace WebKit {
42
43 // CFURLDownload Callbacks ----------------------------------------------------------------
44 static void didStartCallback(CFURLDownloadRef download, const void* clientInfo);
45 static CFURLRequestRef willSendRequestCallback(CFURLDownloadRef download, CFURLRequestRef request, CFURLResponseRef redirectionResponse, const void* clientInfo);
46 static void didReceiveAuthenticationChallengeCallback(CFURLDownloadRef download, CFURLAuthChallengeRef challenge, const void* clientInfo);
47 static void didReceiveResponseCallback(CFURLDownloadRef download, CFURLResponseRef response, const void* clientInfo);
48 static void willResumeWithResponseCallback(CFURLDownloadRef download, CFURLResponseRef response, UInt64 startingByte, const void* clientInfo);
49 static void didReceiveDataCallback(CFURLDownloadRef download, CFIndex length, const void* clientInfo);
50 static Boolean shouldDecodeDataOfMIMETypeCallback(CFURLDownloadRef download, CFStringRef encodingType, const void* clientInfo);
51 static void decideDestinationWithSuggestedObjectNameCallback(CFURLDownloadRef download, CFStringRef objectName, const void* clientInfo);
52 static void didCreateDestinationCallback(CFURLDownloadRef download, CFURLRef path, const void* clientInfo);
53 static void didFinishCallback(CFURLDownloadRef download, const void* clientInfo);
54 static void didFailCallback(CFURLDownloadRef download, CFErrorRef error, const void* clientInfo);
55
56 void Download::start(WebPage* initiatingWebPage)
57 {
58     ASSERT(!m_download);
59
60     CFURLRequestRef cfRequest = m_request.cfURLRequest();
61
62     CFURLDownloadClient client = {0, this, 0, 0, 0, didStartCallback, willSendRequestCallback, didReceiveAuthenticationChallengeCallback, 
63                                   didReceiveResponseCallback, willResumeWithResponseCallback, didReceiveDataCallback, shouldDecodeDataOfMIMETypeCallback, 
64                                   decideDestinationWithSuggestedObjectNameCallback, didCreateDestinationCallback, didFinishCallback, didFailCallback};
65     m_download.adoptCF(CFURLDownloadCreate(0, cfRequest, &client));
66
67     // FIXME: Allow this to be changed by the client.
68     CFURLDownloadSetDeletesUponFailure(m_download.get(), false);
69
70     CFURLDownloadScheduleWithCurrentMessageQueue(m_download.get());
71     CFURLDownloadScheduleDownloadWithRunLoop(m_download.get(), loaderRunLoop(), kCFRunLoopDefaultMode);
72 }
73
74 void Download::startWithHandle(WebPage* initiatingPage, ResourceHandle* handle, const ResourceRequest& initialRequest, const ResourceResponse& response)
75 {
76     ASSERT(!m_download);
77
78     CFURLConnectionRef connection = handle->connection();
79     if (!connection)
80         return;
81
82     CFURLDownloadClient client = {0, this, 0, 0, 0, didStartCallback, willSendRequestCallback, didReceiveAuthenticationChallengeCallback, 
83                                   didReceiveResponseCallback, willResumeWithResponseCallback, didReceiveDataCallback, shouldDecodeDataOfMIMETypeCallback,
84                                   decideDestinationWithSuggestedObjectNameCallback, didCreateDestinationCallback, didFinishCallback, didFailCallback};
85
86     m_download.adoptCF(CFURLDownloadCreateAndStartWithLoadingConnection(0, connection, initialRequest.cfURLRequest(), response.cfURLResponse(), &client));
87
88     // It is possible for CFURLDownloadCreateAndStartWithLoadingConnection() to fail if the passed in CFURLConnection is not in a "downloadable state"
89     // However, we should never hit that case
90     if (!m_download)
91         ASSERT_NOT_REACHED();
92
93     // The CFURLDownload either starts successfully and retains the CFURLConnection, 
94     // or it fails to creating and we have a now-useless connection with a dangling ref. 
95     // Either way, we need to release the connection to balance out ref counts
96     handle->releaseConnectionForDownload();
97     CFRelease(connection);
98 }
99
100 void Download::cancel()
101 {
102     notImplemented();
103 }
104
105 void Download::platformInvalidate()
106 {
107     m_download = nullptr;
108 }
109
110 // CFURLDownload Callbacks ----------------------------------------------------------------
111 static Download* downloadFromClientInfo(const void* clientInfo)
112 {
113     return reinterpret_cast<Download*>(const_cast<void*>(clientInfo));
114 }
115
116 void didStartCallback(CFURLDownloadRef, const void* clientInfo)
117
118     downloadFromClientInfo(clientInfo)->didStart(); 
119 }
120
121 CFURLRequestRef willSendRequestCallback(CFURLDownloadRef, CFURLRequestRef request, CFURLResponseRef redirectionResponse, const void* clientInfo)
122
123     // CFNetwork requires us to return a retained request.
124     CFRetain(request);
125     return request;
126 }
127
128 void didReceiveAuthenticationChallengeCallback(CFURLDownloadRef, CFURLAuthChallengeRef challenge, const void* clientInfo)
129
130     // FIXME: implement.
131     notImplemented();
132 }
133
134 void didReceiveResponseCallback(CFURLDownloadRef, CFURLResponseRef response, const void* clientInfo)
135 {
136     downloadFromClientInfo(clientInfo)->didReceiveResponse(ResourceResponse(response)); 
137 }
138
139 void willResumeWithResponseCallback(CFURLDownloadRef, CFURLResponseRef response, UInt64 startingByte, const void* clientInfo)
140
141     // FIXME: implement.
142     notImplemented();
143 }
144
145 void didReceiveDataCallback(CFURLDownloadRef, CFIndex length, const void* clientInfo)
146
147     downloadFromClientInfo(clientInfo)->didReceiveData(length);
148 }
149
150 Boolean shouldDecodeDataOfMIMETypeCallback(CFURLDownloadRef, CFStringRef encodingType, const void* clientInfo)
151
152     return downloadFromClientInfo(clientInfo)->shouldDecodeSourceDataOfMIMEType(encodingType);
153 }
154
155 void decideDestinationWithSuggestedObjectNameCallback(CFURLDownloadRef cfURLDownloadRef, CFStringRef objectName, const void* clientInfo)
156
157     Download* download = downloadFromClientInfo(clientInfo);
158     bool allowOverwrite;
159     String destination = download->decideDestinationWithSuggestedFilename(objectName, allowOverwrite);
160     if (destination.isNull())
161         return;
162
163     RetainPtr<CFStringRef> cfPath(AdoptCF, CFStringCreateWithCharactersNoCopy(0, reinterpret_cast<const UniChar*>(destination.characters()), destination.length(), kCFAllocatorNull));
164     RetainPtr<CFURLRef> pathURL(AdoptCF, CFURLCreateWithFileSystemPath(0, cfPath.get(), kCFURLWindowsPathStyle, false));
165     CFURLDownloadSetDestination(cfURLDownloadRef, pathURL.get(), allowOverwrite);
166 }
167
168 void didCreateDestinationCallback(CFURLDownloadRef, CFURLRef url, const void* clientInfo)
169
170     RetainPtr<CFStringRef> path(AdoptCF, CFURLCopyFileSystemPath(url, kCFURLWindowsPathStyle));
171     String result(path.get());
172     downloadFromClientInfo(clientInfo)->didCreateDestination(result);
173 }
174
175 void didFinishCallback(CFURLDownloadRef, const void* clientInfo)
176
177     downloadFromClientInfo(clientInfo)->didFinish();
178 }
179
180 void didFailCallback(CFURLDownloadRef, CFErrorRef error, const void* clientInfo)
181
182     CoreIPC::DataReference dataReference(0, 0);
183     downloadFromClientInfo(clientInfo)->didFail(ResourceError(error), dataReference);
184 }
185
186 } // namespace WebKit