1 /*
2 * Copyright (C) 2009 Google 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 are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "config.h"
32 #include "ResourceHandle.h"
33
34 #include "PlatformBridge.h"
35 #include "ResourceHandleClient.h"
36 #include "ResourceRequest.h"
37 #include "SharedBuffer.h"
38
39 #include "WebKit.h"
40 #include "WebKitClient.h"
41 #include "WebURLError.h"
42 #include "WebURLLoader.h"
43 #include "WebURLLoaderClient.h"
44 #include "WebURLRequest.h"
45 #include "WebURLResponse.h"
46 #include "WrappedResourceRequest.h"
47 #include "WrappedResourceResponse.h"
48
49 using namespace WebKit;
50
51 namespace WebCore {
52
53 // ResourceHandleInternal -----------------------------------------------------
54
55 class ResourceHandleInternal : public WebURLLoaderClient {
56 public:
ResourceHandleInternal(const ResourceRequest & request,ResourceHandleClient * client)57 ResourceHandleInternal(const ResourceRequest& request, ResourceHandleClient* client)
58 : m_request(request)
59 , m_owner(0)
60 , m_client(client)
61 , m_state(ConnectionStateNew)
62 {
63 }
64
65 void start();
66 void cancel();
67 void setDefersLoading(bool);
68 bool allowStoredCredentials() const;
69
70 // WebURLLoaderClient methods:
71 virtual void willSendRequest(WebURLLoader*, WebURLRequest&, const WebURLResponse&);
72 virtual void didSendData(
73 WebURLLoader*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent);
74 virtual void didReceiveResponse(WebURLLoader*, const WebURLResponse&);
75 virtual void didReceiveData(WebURLLoader*, const char* data, int dataLength, int encodedDataLength);
76
77 virtual void didReceiveCachedMetadata(WebURLLoader*, const char* data, int dataLength);
78 virtual void didFinishLoading(WebURLLoader*, double finishTime);
79 virtual void didFail(WebURLLoader*, const WebURLError&);
80
81 enum ConnectionState {
82 ConnectionStateNew,
83 ConnectionStateStarted,
84 ConnectionStateReceivedResponse,
85 ConnectionStateReceivingData,
86 ConnectionStateFinishedLoading,
87 ConnectionStateCanceled,
88 ConnectionStateFailed,
89 };
90
91 ResourceRequest m_request;
92 ResourceHandle* m_owner;
93 ResourceHandleClient* m_client;
94 OwnPtr<WebURLLoader> m_loader;
95
96 // Used for sanity checking to make sure we don't experience illegal state
97 // transitions.
98 ConnectionState m_state;
99 };
100
start()101 void ResourceHandleInternal::start()
102 {
103 if (m_state != ConnectionStateNew)
104 CRASH();
105 m_state = ConnectionStateStarted;
106
107 m_loader.set(webKitClient()->createURLLoader());
108 ASSERT(m_loader.get());
109
110 WrappedResourceRequest wrappedRequest(m_request);
111 wrappedRequest.setAllowStoredCredentials(allowStoredCredentials());
112 m_loader->loadAsynchronously(wrappedRequest, this);
113 }
114
cancel()115 void ResourceHandleInternal::cancel()
116 {
117 m_state = ConnectionStateCanceled;
118 m_loader->cancel();
119
120 // Do not make any further calls to the client.
121 m_client = 0;
122 }
123
setDefersLoading(bool value)124 void ResourceHandleInternal::setDefersLoading(bool value)
125 {
126 m_loader->setDefersLoading(value);
127 }
128
allowStoredCredentials() const129 bool ResourceHandleInternal::allowStoredCredentials() const
130 {
131 return m_client && m_client->shouldUseCredentialStorage(m_owner);
132 }
133
willSendRequest(WebURLLoader *,WebURLRequest & request,const WebURLResponse & response)134 void ResourceHandleInternal::willSendRequest(
135 WebURLLoader*, WebURLRequest& request, const WebURLResponse& response)
136 {
137 ASSERT(m_client);
138 ASSERT(!request.isNull());
139 ASSERT(!response.isNull());
140 m_client->willSendRequest(m_owner, request.toMutableResourceRequest(), response.toResourceResponse());
141 }
142
didSendData(WebURLLoader *,unsigned long long bytesSent,unsigned long long totalBytesToBeSent)143 void ResourceHandleInternal::didSendData(
144 WebURLLoader*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
145 {
146 ASSERT(m_client);
147 m_client->didSendData(m_owner, bytesSent, totalBytesToBeSent);
148 }
149
didReceiveResponse(WebURLLoader *,const WebURLResponse & response)150 void ResourceHandleInternal::didReceiveResponse(WebURLLoader*, const WebURLResponse& response)
151 {
152 ASSERT(m_client);
153 ASSERT(!response.isNull());
154 bool isMultipart = response.isMultipartPayload();
155 bool isValidStateTransition = (m_state == ConnectionStateStarted || m_state == ConnectionStateReceivedResponse);
156 // In the case of multipart loads, calls to didReceiveData & didReceiveResponse can be interleaved.
157 if (!isMultipart && !isValidStateTransition)
158 CRASH();
159 m_state = ConnectionStateReceivedResponse;
160 m_client->didReceiveResponse(m_owner, response.toResourceResponse());
161 }
162
didReceiveData(WebURLLoader *,const char * data,int dataLength,int encodedDataLength)163 void ResourceHandleInternal::didReceiveData(WebURLLoader*, const char* data, int dataLength, int encodedDataLength)
164 {
165 ASSERT(m_client);
166 if (m_state != ConnectionStateReceivedResponse && m_state != ConnectionStateReceivingData)
167 CRASH();
168 m_state = ConnectionStateReceivingData;
169
170 m_client->didReceiveData(m_owner, data, dataLength, encodedDataLength);
171 }
172
didReceiveCachedMetadata(WebURLLoader *,const char * data,int dataLength)173 void ResourceHandleInternal::didReceiveCachedMetadata(WebURLLoader*, const char* data, int dataLength)
174 {
175 ASSERT(m_client);
176 if (m_state != ConnectionStateReceivedResponse && m_state != ConnectionStateReceivingData)
177 CRASH();
178
179 m_client->didReceiveCachedMetadata(m_owner, data, dataLength);
180 }
181
didFinishLoading(WebURLLoader *,double finishTime)182 void ResourceHandleInternal::didFinishLoading(WebURLLoader*, double finishTime)
183 {
184 ASSERT(m_client);
185 if (m_state != ConnectionStateReceivedResponse && m_state != ConnectionStateReceivingData)
186 CRASH();
187 m_state = ConnectionStateFinishedLoading;
188 m_client->didFinishLoading(m_owner, finishTime);
189 }
190
didFail(WebURLLoader *,const WebURLError & error)191 void ResourceHandleInternal::didFail(WebURLLoader*, const WebURLError& error)
192 {
193 ASSERT(m_client);
194 m_state = ConnectionStateFailed;
195 m_client->didFail(m_owner, error);
196 }
197
198 // ResourceHandle -------------------------------------------------------------
199
ResourceHandle(const ResourceRequest & request,ResourceHandleClient * client,bool defersLoading,bool shouldContentSniff)200 ResourceHandle::ResourceHandle(const ResourceRequest& request,
201 ResourceHandleClient* client,
202 bool defersLoading,
203 bool shouldContentSniff)
204 : d(new ResourceHandleInternal(request, client))
205 {
206 d->m_owner = this;
207
208 // FIXME: Figure out what to do with the bool params.
209 }
210
create(NetworkingContext * context,const ResourceRequest & request,ResourceHandleClient * client,bool defersLoading,bool shouldContentSniff)211 PassRefPtr<ResourceHandle> ResourceHandle::create(NetworkingContext* context,
212 const ResourceRequest& request,
213 ResourceHandleClient* client,
214 bool defersLoading,
215 bool shouldContentSniff)
216 {
217 RefPtr<ResourceHandle> newHandle = adoptRef(new ResourceHandle(
218 request, client, defersLoading, shouldContentSniff));
219
220 if (newHandle->start(context))
221 return newHandle.release();
222
223 return 0;
224 }
225
firstRequest()226 ResourceRequest& ResourceHandle::firstRequest()
227 {
228 return d->m_request;
229 }
230
client() const231 ResourceHandleClient* ResourceHandle::client() const
232 {
233 return d->m_client;
234 }
235
setClient(ResourceHandleClient * client)236 void ResourceHandle::setClient(ResourceHandleClient* client)
237 {
238 d->m_client = client;
239 }
240
setDefersLoading(bool value)241 void ResourceHandle::setDefersLoading(bool value)
242 {
243 d->setDefersLoading(value);
244 }
245
start(NetworkingContext * context)246 bool ResourceHandle::start(NetworkingContext* context)
247 {
248 d->start();
249 return true;
250 }
251
hasAuthenticationChallenge() const252 bool ResourceHandle::hasAuthenticationChallenge() const
253 {
254 return false;
255 }
256
clearAuthentication()257 void ResourceHandle::clearAuthentication()
258 {
259 }
260
cancel()261 void ResourceHandle::cancel()
262 {
263 d->cancel();
264 }
265
~ResourceHandle()266 ResourceHandle::~ResourceHandle()
267 {
268 d->m_owner = 0;
269 }
270
bufferedData()271 PassRefPtr<SharedBuffer> ResourceHandle::bufferedData()
272 {
273 return 0;
274 }
275
loadsBlocked()276 bool ResourceHandle::loadsBlocked()
277 {
278 return false; // This seems to be related to sync XMLHttpRequest...
279 }
280
281 // static
supportsBufferedData()282 bool ResourceHandle::supportsBufferedData()
283 {
284 return false; // The loader will buffer manually if it needs to.
285 }
286
287 // static
loadResourceSynchronously(NetworkingContext * context,const ResourceRequest & request,StoredCredentials storedCredentials,ResourceError & error,ResourceResponse & response,Vector<char> & data)288 void ResourceHandle::loadResourceSynchronously(NetworkingContext* context,
289 const ResourceRequest& request,
290 StoredCredentials storedCredentials,
291 ResourceError& error,
292 ResourceResponse& response,
293 Vector<char>& data)
294 {
295 OwnPtr<WebURLLoader> loader(webKitClient()->createURLLoader());
296 ASSERT(loader.get());
297
298 WrappedResourceRequest requestIn(request);
299 requestIn.setAllowStoredCredentials(storedCredentials == AllowStoredCredentials);
300 WrappedResourceResponse responseOut(response);
301 WebURLError errorOut;
302 WebData dataOut;
303
304 loader->loadSynchronously(requestIn, responseOut, errorOut, dataOut);
305
306 error = errorOut;
307 data.clear();
308 data.append(dataOut.data(), dataOut.size());
309 }
310
311 // static
willLoadFromCache(ResourceRequest & request,Frame *)312 bool ResourceHandle::willLoadFromCache(ResourceRequest& request, Frame*)
313 {
314 // This method is used to determine if a POST request can be repeated from
315 // cache, but you cannot really know until you actually try to read from the
316 // cache. Even if we checked now, something else could come along and wipe
317 // out the cache entry by the time we fetch it.
318 //
319 // So, we always say yes here, to prevent the FrameLoader from initiating a
320 // reload. Then in FrameLoaderClientImpl::dispatchWillSendRequest, we
321 // fix-up the cache policy of the request to force a load from the cache.
322 //
323 ASSERT(request.httpMethod() == "POST");
324 return true;
325 }
326
327 // static
cacheMetadata(const ResourceResponse & response,const Vector<char> & data)328 void ResourceHandle::cacheMetadata(const ResourceResponse& response, const Vector<char>& data)
329 {
330 PlatformBridge::cacheMetadata(response.url(), response.responseTime(), data);
331 }
332
333 } // namespace WebCore
334