1/*
2 * Copyright (C) 2006, 2007, 2010, 2011 Apple Inc. All rights reserved.
3 *           (C) 2007 Graham Dennis (graham.dennis@gmail.com)
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 *
9 * 1.  Redistributions of source code must retain the above copyright
10 *     notice, this list of conditions and the following disclaimer.
11 * 2.  Redistributions in binary form must reproduce the above copyright
12 *     notice, this list of conditions and the following disclaimer in the
13 *     documentation and/or other materials provided with the distribution.
14 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 *     its contributors may be used to endorse or promote products derived
16 *     from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include "config.h"
31#include "ResourceLoader.h"
32
33#include "ApplicationCacheHost.h"
34#include "DocumentLoader.h"
35#include "FileStreamProxy.h"
36#include "Frame.h"
37#include "FrameLoader.h"
38#include "FrameLoaderClient.h"
39#include "InspectorInstrumentation.h"
40#include "Page.h"
41#include "ProgressTracker.h"
42#include "ResourceError.h"
43#include "ResourceHandle.h"
44#include "ResourceLoadScheduler.h"
45#include "Settings.h"
46#include "SharedBuffer.h"
47
48namespace WebCore {
49
50PassRefPtr<SharedBuffer> ResourceLoader::resourceData()
51{
52    if (m_resourceData)
53        return m_resourceData;
54
55    if (ResourceHandle::supportsBufferedData() && m_handle)
56        return m_handle->bufferedData();
57
58    return 0;
59}
60
61ResourceLoader::ResourceLoader(Frame* frame, bool sendResourceLoadCallbacks, bool shouldContentSniff)
62    : m_frame(frame)
63    , m_documentLoader(frame->loader()->activeDocumentLoader())
64    , m_identifier(0)
65    , m_reachedTerminalState(false)
66    , m_cancelled(false)
67    , m_calledDidFinishLoad(false)
68    , m_sendResourceLoadCallbacks(sendResourceLoadCallbacks)
69    , m_shouldContentSniff(shouldContentSniff)
70    , m_shouldBufferData(true)
71    , m_defersLoading(frame->page()->defersLoading())
72{
73}
74
75ResourceLoader::~ResourceLoader()
76{
77    ASSERT(m_reachedTerminalState);
78}
79
80void ResourceLoader::releaseResources()
81{
82    ASSERT(!m_reachedTerminalState);
83
84    // It's possible that when we release the handle, it will be
85    // deallocated and release the last reference to this object.
86    // We need to retain to avoid accessing the object after it
87    // has been deallocated and also to avoid reentering this method.
88    RefPtr<ResourceLoader> protector(this);
89
90    m_frame = 0;
91    m_documentLoader = 0;
92
93    // We need to set reachedTerminalState to true before we release
94    // the resources to prevent a double dealloc of WebView <rdar://problem/4372628>
95    m_reachedTerminalState = true;
96
97    m_identifier = 0;
98
99    resourceLoadScheduler()->remove(this);
100
101    if (m_handle) {
102        // Clear out the ResourceHandle's client so that it doesn't try to call
103        // us back after we release it, unless it has been replaced by someone else.
104        if (m_handle->client() == this)
105            m_handle->setClient(0);
106        m_handle = 0;
107    }
108
109    m_resourceData = 0;
110    m_deferredRequest = ResourceRequest();
111}
112
113bool ResourceLoader::init(const ResourceRequest& r)
114{
115    ASSERT(!m_handle);
116    ASSERT(m_request.isNull());
117    ASSERT(m_deferredRequest.isNull());
118    ASSERT(!m_documentLoader->isSubstituteLoadPending(this));
119
120    ResourceRequest clientRequest(r);
121
122    // https://bugs.webkit.org/show_bug.cgi?id=26391
123    // The various plug-in implementations call directly to ResourceLoader::load() instead of piping requests
124    // through FrameLoader. As a result, they miss the FrameLoader::addExtraFieldsToRequest() step which sets
125    // up the 1st party for cookies URL. Until plug-in implementations can be reigned in to pipe through that
126    // method, we need to make sure there is always a 1st party for cookies set.
127    if (clientRequest.firstPartyForCookies().isNull()) {
128        if (Document* document = m_frame->document())
129            clientRequest.setFirstPartyForCookies(document->firstPartyForCookies());
130    }
131
132    willSendRequest(clientRequest, ResourceResponse());
133    if (clientRequest.isNull()) {
134        didFail(frameLoader()->cancelledError(m_request));
135        return false;
136    }
137
138    m_request = clientRequest;
139    return true;
140}
141
142void ResourceLoader::start()
143{
144    ASSERT(!m_handle);
145    ASSERT(!m_request.isNull());
146    ASSERT(m_deferredRequest.isNull());
147
148#if ENABLE(WEB_ARCHIVE)
149    if (m_documentLoader->scheduleArchiveLoad(this, m_request, m_request.url()))
150        return;
151#endif
152
153#if ENABLE(OFFLINE_WEB_APPLICATIONS)
154    if (m_documentLoader->applicationCacheHost()->maybeLoadResource(this, m_request, m_request.url()))
155        return;
156#endif
157
158    if (m_defersLoading) {
159        m_deferredRequest = m_request;
160        return;
161    }
162
163    if (!m_reachedTerminalState)
164        m_handle = ResourceHandle::create(m_frame->loader()->networkingContext(), m_request, this, m_defersLoading, m_shouldContentSniff);
165}
166
167void ResourceLoader::setDefersLoading(bool defers)
168{
169    m_defersLoading = defers;
170    if (m_handle)
171        m_handle->setDefersLoading(defers);
172    if (!defers && !m_deferredRequest.isNull()) {
173        m_request = m_deferredRequest;
174        m_deferredRequest = ResourceRequest();
175        start();
176    }
177}
178
179#if PLATFORM(ANDROID)
180// TODO: This needs upstreaming to WebKit.
181void ResourceLoader::pauseLoad(bool pause)
182{
183    if (m_handle)
184        m_handle->pauseLoad(pause);
185}
186#endif
187
188FrameLoader* ResourceLoader::frameLoader() const
189{
190    if (!m_frame)
191        return 0;
192    return m_frame->loader();
193}
194
195void ResourceLoader::setShouldBufferData(bool shouldBufferData)
196{
197    m_shouldBufferData = shouldBufferData;
198
199    // Reset any already buffered data
200    if (!m_shouldBufferData)
201        m_resourceData = 0;
202}
203
204
205void ResourceLoader::addData(const char* data, int length, bool allAtOnce)
206{
207    if (!m_shouldBufferData)
208        return;
209
210    if (allAtOnce) {
211        m_resourceData = SharedBuffer::create(data, length);
212        return;
213    }
214
215    if (ResourceHandle::supportsBufferedData()) {
216        // Buffer data only if the connection has handed us the data because is has stopped buffering it.
217        if (m_resourceData)
218            m_resourceData->append(data, length);
219    } else {
220        if (!m_resourceData)
221            m_resourceData = SharedBuffer::create(data, length);
222        else
223            m_resourceData->append(data, length);
224    }
225}
226
227void ResourceLoader::clearResourceData()
228{
229    if (m_resourceData)
230        m_resourceData->clear();
231}
232
233void ResourceLoader::willSendRequest(ResourceRequest& request, const ResourceResponse& redirectResponse)
234{
235    // Protect this in this delegate method since the additional processing can do
236    // anything including possibly derefing this; one example of this is Radar 3266216.
237    RefPtr<ResourceLoader> protector(this);
238
239    ASSERT(!m_reachedTerminalState);
240
241    if (m_sendResourceLoadCallbacks) {
242        if (!m_identifier) {
243            m_identifier = m_frame->page()->progress()->createUniqueIdentifier();
244            frameLoader()->notifier()->assignIdentifierToInitialRequest(m_identifier, documentLoader(), request);
245        }
246
247        frameLoader()->notifier()->willSendRequest(this, request, redirectResponse);
248    }
249
250    if (!redirectResponse.isNull())
251        resourceLoadScheduler()->crossOriginRedirectReceived(this, request.url());
252    m_request = request;
253}
254
255void ResourceLoader::didSendData(unsigned long long, unsigned long long)
256{
257}
258
259void ResourceLoader::didReceiveResponse(const ResourceResponse& r)
260{
261    ASSERT(!m_reachedTerminalState);
262
263    // Protect this in this delegate method since the additional processing can do
264    // anything including possibly derefing this; one example of this is Radar 3266216.
265    RefPtr<ResourceLoader> protector(this);
266
267    m_response = r;
268
269    if (FormData* data = m_request.httpBody())
270        data->removeGeneratedFilesIfNeeded();
271
272    if (m_sendResourceLoadCallbacks)
273        frameLoader()->notifier()->didReceiveResponse(this, m_response);
274}
275
276void ResourceLoader::didReceiveData(const char* data, int length, long long encodedDataLength, bool allAtOnce)
277{
278    // The following assertions are not quite valid here, since a subclass
279    // might override didReceiveData in a way that invalidates them. This
280    // happens with the steps listed in 3266216
281    // ASSERT(con == connection);
282    // ASSERT(!m_reachedTerminalState);
283
284    // Protect this in this delegate method since the additional processing can do
285    // anything including possibly derefing this; one example of this is Radar 3266216.
286    RefPtr<ResourceLoader> protector(this);
287
288    addData(data, length, allAtOnce);
289    // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
290    // However, with today's computers and networking speeds, this won't happen in practice.
291    // Could be an issue with a giant local file.
292    if (m_sendResourceLoadCallbacks && m_frame)
293        frameLoader()->notifier()->didReceiveData(this, data, length, static_cast<int>(encodedDataLength));
294}
295
296void ResourceLoader::willStopBufferingData(const char* data, int length)
297{
298    if (!m_shouldBufferData)
299        return;
300
301    ASSERT(!m_resourceData);
302    m_resourceData = SharedBuffer::create(data, length);
303}
304
305void ResourceLoader::didFinishLoading(double finishTime)
306{
307    // If load has been cancelled after finishing (which could happen with a
308    // JavaScript that changes the window location), do nothing.
309    if (m_cancelled)
310        return;
311    ASSERT(!m_reachedTerminalState);
312
313    didFinishLoadingOnePart(finishTime);
314    releaseResources();
315}
316
317void ResourceLoader::didFinishLoadingOnePart(double finishTime)
318{
319    if (m_cancelled)
320        return;
321    ASSERT(!m_reachedTerminalState);
322
323    if (m_calledDidFinishLoad)
324        return;
325    m_calledDidFinishLoad = true;
326    if (m_sendResourceLoadCallbacks)
327        frameLoader()->notifier()->didFinishLoad(this, finishTime);
328}
329
330void ResourceLoader::didFail(const ResourceError& error)
331{
332    if (m_cancelled)
333        return;
334    ASSERT(!m_reachedTerminalState);
335
336    // Protect this in this delegate method since the additional processing can do
337    // anything including possibly derefing this; one example of this is Radar 3266216.
338    RefPtr<ResourceLoader> protector(this);
339
340    if (FormData* data = m_request.httpBody())
341        data->removeGeneratedFilesIfNeeded();
342
343    if (m_sendResourceLoadCallbacks && !m_calledDidFinishLoad)
344        frameLoader()->notifier()->didFailToLoad(this, error);
345
346    releaseResources();
347}
348
349void ResourceLoader::didCancel(const ResourceError& error)
350{
351    ASSERT(!m_cancelled);
352    ASSERT(!m_reachedTerminalState);
353
354    if (FormData* data = m_request.httpBody())
355        data->removeGeneratedFilesIfNeeded();
356
357    // This flag prevents bad behavior when loads that finish cause the
358    // load itself to be cancelled (which could happen with a javascript that
359    // changes the window location). This is used to prevent both the body
360    // of this method and the body of connectionDidFinishLoading: running
361    // for a single delegate. Canceling wins.
362    m_cancelled = true;
363
364    if (m_handle)
365        m_handle->clearAuthentication();
366
367    m_documentLoader->cancelPendingSubstituteLoad(this);
368    if (m_handle) {
369        m_handle->cancel();
370        m_handle = 0;
371    }
372    if (m_sendResourceLoadCallbacks && m_identifier && !m_calledDidFinishLoad)
373        frameLoader()->notifier()->didFailToLoad(this, error);
374
375    releaseResources();
376}
377
378void ResourceLoader::cancel()
379{
380    cancel(ResourceError());
381}
382
383void ResourceLoader::cancel(const ResourceError& error)
384{
385    if (m_reachedTerminalState)
386        return;
387    if (!error.isNull())
388        didCancel(error);
389    else
390        didCancel(cancelledError());
391}
392
393const ResourceResponse& ResourceLoader::response() const
394{
395    return m_response;
396}
397
398ResourceError ResourceLoader::cancelledError()
399{
400    return frameLoader()->cancelledError(m_request);
401}
402
403ResourceError ResourceLoader::blockedError()
404{
405    return frameLoader()->blockedError(m_request);
406}
407
408ResourceError ResourceLoader::cannotShowURLError()
409{
410    return frameLoader()->cannotShowURLError(m_request);
411}
412
413void ResourceLoader::willSendRequest(ResourceHandle*, ResourceRequest& request, const ResourceResponse& redirectResponse)
414{
415#if ENABLE(OFFLINE_WEB_APPLICATIONS)
416    if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForRedirect(this, request, redirectResponse))
417        return;
418#endif
419    willSendRequest(request, redirectResponse);
420}
421
422void ResourceLoader::didSendData(ResourceHandle*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
423{
424    didSendData(bytesSent, totalBytesToBeSent);
425}
426
427void ResourceLoader::didReceiveResponse(ResourceHandle*, const ResourceResponse& response)
428{
429#if ENABLE(OFFLINE_WEB_APPLICATIONS)
430    if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForResponse(this, response))
431        return;
432#endif
433    didReceiveResponse(response);
434}
435
436void ResourceLoader::didReceiveData(ResourceHandle*, const char* data, int length, int encodedDataLength)
437{
438    InspectorInstrumentationCookie cookie = InspectorInstrumentation::willReceiveResourceData(m_frame.get(), identifier());
439    didReceiveData(data, length, encodedDataLength, false);
440    InspectorInstrumentation::didReceiveResourceData(cookie);
441}
442
443void ResourceLoader::didFinishLoading(ResourceHandle*, double finishTime)
444{
445    didFinishLoading(finishTime);
446}
447
448void ResourceLoader::didFail(ResourceHandle*, const ResourceError& error)
449{
450#if ENABLE(OFFLINE_WEB_APPLICATIONS)
451    if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForError(this, error))
452        return;
453#endif
454    didFail(error);
455}
456
457void ResourceLoader::wasBlocked(ResourceHandle*)
458{
459    didFail(blockedError());
460}
461
462void ResourceLoader::cannotShowURL(ResourceHandle*)
463{
464    didFail(cannotShowURLError());
465}
466
467bool ResourceLoader::shouldUseCredentialStorage()
468{
469    RefPtr<ResourceLoader> protector(this);
470    return frameLoader()->shouldUseCredentialStorage(this);
471}
472
473void ResourceLoader::didReceiveAuthenticationChallenge(const AuthenticationChallenge& challenge)
474{
475    // Protect this in this delegate method since the additional processing can do
476    // anything including possibly derefing this; one example of this is Radar 3266216.
477    RefPtr<ResourceLoader> protector(this);
478    frameLoader()->notifier()->didReceiveAuthenticationChallenge(this, challenge);
479}
480
481void ResourceLoader::didCancelAuthenticationChallenge(const AuthenticationChallenge& challenge)
482{
483    // Protect this in this delegate method since the additional processing can do
484    // anything including possibly derefing this; one example of this is Radar 3266216.
485    RefPtr<ResourceLoader> protector(this);
486    frameLoader()->notifier()->didCancelAuthenticationChallenge(this, challenge);
487}
488
489#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
490bool ResourceLoader::canAuthenticateAgainstProtectionSpace(const ProtectionSpace& protectionSpace)
491{
492    RefPtr<ResourceLoader> protector(this);
493    return frameLoader()->canAuthenticateAgainstProtectionSpace(this, protectionSpace);
494}
495#endif
496
497void ResourceLoader::receivedCancellation(const AuthenticationChallenge&)
498{
499    cancel();
500}
501
502void ResourceLoader::willCacheResponse(ResourceHandle*, CacheStoragePolicy& policy)
503{
504    // <rdar://problem/7249553> - There are reports of crashes with this method being called
505    // with a null m_frame->settings(), which can only happen if the frame doesn't have a page.
506    // Sadly we have no reproducible cases of this.
507    // We think that any frame without a page shouldn't have any loads happening in it, yet
508    // there is at least one code path where that is not true.
509    ASSERT(m_frame->settings());
510
511    // When in private browsing mode, prevent caching to disk
512    if (policy == StorageAllowed && m_frame->settings() && m_frame->settings()->privateBrowsingEnabled())
513        policy = StorageAllowedInMemoryOnly;
514}
515
516#if ENABLE(BLOB)
517AsyncFileStream* ResourceLoader::createAsyncFileStream(FileStreamClient* client)
518{
519    // It is OK to simply return a pointer since FileStreamProxy::create adds an extra ref.
520    return FileStreamProxy::create(m_frame->document()->scriptExecutionContext(), client).get();
521}
522#endif
523
524}
525