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 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 "AsyncFileStream.h"
35#include "AuthenticationChallenge.h"
36#include "DocumentLoader.h"
37#include "Frame.h"
38#include "FrameLoader.h"
39#include "FrameLoaderClient.h"
40#include "InspectorInstrumentation.h"
41#include "LoaderStrategy.h"
42#include "Page.h"
43#include "PlatformStrategies.h"
44#include "ProgressTracker.h"
45#include "ResourceBuffer.h"
46#include "ResourceError.h"
47#include "ResourceHandle.h"
48#include "ResourceLoadScheduler.h"
49#include "SecurityOrigin.h"
50#include "Settings.h"
51#include "SharedBuffer.h"
52#include <wtf/Ref.h>
53
54namespace WebCore {
55
56ResourceLoader::ResourceLoader(Frame* frame, ResourceLoaderOptions options)
57    : m_frame(frame)
58    , m_documentLoader(frame->loader().activeDocumentLoader())
59    , m_identifier(0)
60    , m_reachedTerminalState(false)
61    , m_notifiedLoadComplete(false)
62    , m_cancellationStatus(NotCancelled)
63    , m_defersLoading(frame->page()->defersLoading())
64    , m_options(options)
65{
66}
67
68ResourceLoader::~ResourceLoader()
69{
70    ASSERT(m_reachedTerminalState);
71}
72
73void ResourceLoader::releaseResources()
74{
75    ASSERT(!m_reachedTerminalState);
76
77    // It's possible that when we release the handle, it will be
78    // deallocated and release the last reference to this object.
79    // We need to retain to avoid accessing the object after it
80    // has been deallocated and also to avoid reentering this method.
81    Ref<ResourceLoader> protect(*this);
82
83    m_frame = 0;
84    m_documentLoader = 0;
85
86    // We need to set reachedTerminalState to true before we release
87    // the resources to prevent a double dealloc of WebView <rdar://problem/4372628>
88    m_reachedTerminalState = true;
89
90    platformStrategies()->loaderStrategy()->resourceLoadScheduler()->remove(this);
91    m_identifier = 0;
92
93    if (m_handle) {
94        // Clear out the ResourceHandle's client so that it doesn't try to call
95        // us back after we release it, unless it has been replaced by someone else.
96        if (m_handle->client() == this)
97            m_handle->setClient(0);
98        m_handle = 0;
99    }
100
101    m_resourceData = 0;
102    m_deferredRequest = ResourceRequest();
103}
104
105bool ResourceLoader::init(const ResourceRequest& r)
106{
107    ASSERT(!m_handle);
108    ASSERT(m_request.isNull());
109    ASSERT(m_deferredRequest.isNull());
110    ASSERT(!m_documentLoader->isSubstituteLoadPending(this));
111
112    ResourceRequest clientRequest(r);
113
114#if PLATFORM(IOS)
115    // If the documentLoader was detached while this ResourceLoader was waiting its turn
116    // in ResourceLoadScheduler queue, don't continue.
117    if (!m_documentLoader->frame()) {
118        cancel();
119        return false;
120    }
121#endif
122
123    m_defersLoading = m_frame->page()->defersLoading();
124    if (m_options.securityCheck() == DoSecurityCheck && !m_frame->document()->securityOrigin()->canDisplay(clientRequest.url())) {
125        FrameLoader::reportLocalLoadFailed(m_frame.get(), clientRequest.url().string());
126        releaseResources();
127        return false;
128    }
129
130    // https://bugs.webkit.org/show_bug.cgi?id=26391
131    // The various plug-in implementations call directly to ResourceLoader::load() instead of piping requests
132    // through FrameLoader. As a result, they miss the FrameLoader::addExtraFieldsToRequest() step which sets
133    // up the 1st party for cookies URL. Until plug-in implementations can be reigned in to pipe through that
134    // method, we need to make sure there is always a 1st party for cookies set.
135    if (clientRequest.firstPartyForCookies().isNull()) {
136        if (Document* document = m_frame->document())
137            clientRequest.setFirstPartyForCookies(document->firstPartyForCookies());
138    }
139
140    willSendRequest(clientRequest, ResourceResponse());
141
142#if PLATFORM(IOS)
143    // If this ResourceLoader was stopped as a result of willSendRequest, bail out.
144    if (m_reachedTerminalState)
145        return false;
146#endif
147
148    if (clientRequest.isNull()) {
149        cancel();
150        return false;
151    }
152
153    m_originalRequest = m_request = clientRequest;
154    return true;
155}
156
157void ResourceLoader::start()
158{
159    ASSERT(!m_handle);
160    ASSERT(!m_request.isNull());
161    ASSERT(m_deferredRequest.isNull());
162
163#if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
164    if (m_documentLoader->scheduleArchiveLoad(this, m_request))
165        return;
166#endif
167
168    if (m_documentLoader->applicationCacheHost()->maybeLoadResource(this, m_request, m_request.url()))
169        return;
170
171    if (m_defersLoading) {
172        m_deferredRequest = m_request;
173        return;
174    }
175
176    if (!m_reachedTerminalState)
177        m_handle = ResourceHandle::create(m_frame->loader().networkingContext(), m_request, this, m_defersLoading, m_options.sniffContent() == SniffContent);
178}
179
180void ResourceLoader::setDefersLoading(bool defers)
181{
182    m_defersLoading = defers;
183    if (m_handle)
184        m_handle->setDefersLoading(defers);
185    if (!defers && !m_deferredRequest.isNull()) {
186        m_request = m_deferredRequest;
187        m_deferredRequest = ResourceRequest();
188        start();
189    }
190
191    platformStrategies()->loaderStrategy()->resourceLoadScheduler()->setDefersLoading(this, defers);
192}
193
194FrameLoader* ResourceLoader::frameLoader() const
195{
196    if (!m_frame)
197        return 0;
198    return &m_frame->loader();
199}
200
201void ResourceLoader::setDataBufferingPolicy(DataBufferingPolicy dataBufferingPolicy)
202{
203    m_options.setDataBufferingPolicy(dataBufferingPolicy);
204
205    // Reset any already buffered data
206    if (dataBufferingPolicy == DoNotBufferData)
207        m_resourceData = 0;
208}
209
210void ResourceLoader::willSwitchToSubstituteResource()
211{
212    ASSERT(!m_documentLoader->isSubstituteLoadPending(this));
213    platformStrategies()->loaderStrategy()->resourceLoadScheduler()->remove(this);
214    if (m_handle)
215        m_handle->cancel();
216}
217
218void ResourceLoader::addDataOrBuffer(const char* data, unsigned length, SharedBuffer* buffer, DataPayloadType dataPayloadType)
219{
220    if (m_options.dataBufferingPolicy() == DoNotBufferData)
221        return;
222
223    if (dataPayloadType == DataPayloadWholeResource) {
224        m_resourceData = buffer ? ResourceBuffer::adoptSharedBuffer(buffer) : ResourceBuffer::create(data, length);
225        return;
226    }
227
228    if (!m_resourceData)
229        m_resourceData = buffer ? ResourceBuffer::adoptSharedBuffer(buffer) : ResourceBuffer::create(data, length);
230    else {
231        if (buffer)
232            m_resourceData->append(buffer);
233        else
234            m_resourceData->append(data, length);
235    }
236}
237
238void ResourceLoader::clearResourceData()
239{
240    if (m_resourceData)
241        m_resourceData->clear();
242}
243
244bool ResourceLoader::isSubresourceLoader()
245{
246    return false;
247}
248
249void ResourceLoader::willSendRequest(ResourceRequest& request, const ResourceResponse& redirectResponse)
250{
251    // Protect this in this delegate method since the additional processing can do
252    // anything including possibly derefing this; one example of this is Radar 3266216.
253    Ref<ResourceLoader> protect(*this);
254
255    ASSERT(!m_reachedTerminalState);
256
257#if PLATFORM(IOS)
258    // Ensure an identifier is always set. This ensures that this assetion is not hit:
259    // <rdar://problem/11059794> ASSERTION FAILED: !HashTranslator::equal(KeyTraits::emptyValue(), key) in WebFrameLoaderClient::canAuthenticateAgainstProtectionSpace loading the attached web archive
260    // This is not needed in WebKit2, as it doesn't use m_identifier in WebFrameLoaderClient::canAuthenticateAgainstProtectionSpace
261    if (!m_identifier) {
262        m_identifier = m_frame->page()->progress().createUniqueIdentifier();
263        frameLoader()->notifier().assignIdentifierToInitialRequest(m_identifier, documentLoader(), request);
264
265        // If this ResourceLoader was stopped as a result of assignIdentifierToInitialRequest, bail out
266        if (m_reachedTerminalState)
267            return;
268    }
269#endif
270
271    // We need a resource identifier for all requests, even if FrameLoader is never going to see it (such as with CORS preflight requests).
272    bool createdResourceIdentifier = false;
273    if (!m_identifier) {
274        m_identifier = m_frame->page()->progress().createUniqueIdentifier();
275        createdResourceIdentifier = true;
276    }
277
278    if (m_options.sendLoadCallbacks() == SendCallbacks) {
279        if (createdResourceIdentifier)
280            frameLoader()->notifier().assignIdentifierToInitialRequest(m_identifier, documentLoader(), request);
281
282        frameLoader()->notifier().willSendRequest(this, request, redirectResponse);
283    }
284#if ENABLE(INSPECTOR)
285    else
286        InspectorInstrumentation::willSendRequest(m_frame.get(), m_identifier, m_frame->loader().documentLoader(), request, redirectResponse);
287#endif
288
289    if (!redirectResponse.isNull())
290        platformStrategies()->loaderStrategy()->resourceLoadScheduler()->crossOriginRedirectReceived(this, request.url());
291
292    m_request = request;
293
294    if (!redirectResponse.isNull() && !m_documentLoader->isCommitted())
295        frameLoader()->client().dispatchDidReceiveServerRedirectForProvisionalLoad();
296}
297
298void ResourceLoader::didSendData(unsigned long long, unsigned long long)
299{
300}
301
302void ResourceLoader::didReceiveResponse(const ResourceResponse& r)
303{
304    ASSERT(!m_reachedTerminalState);
305
306    // Protect this in this delegate method since the additional processing can do
307    // anything including possibly derefing this; one example of this is Radar 3266216.
308    Ref<ResourceLoader> protect(*this);
309
310    m_response = r;
311
312    if (FormData* data = m_request.httpBody())
313        data->removeGeneratedFilesIfNeeded();
314
315    if (m_options.sendLoadCallbacks() == SendCallbacks)
316        frameLoader()->notifier().didReceiveResponse(this, m_response);
317}
318
319void ResourceLoader::didReceiveData(const char* data, unsigned length, long long encodedDataLength, DataPayloadType dataPayloadType)
320{
321    // The following assertions are not quite valid here, since a subclass
322    // might override didReceiveData in a way that invalidates them. This
323    // happens with the steps listed in 3266216
324    // ASSERT(con == connection);
325    // ASSERT(!m_reachedTerminalState);
326
327    didReceiveDataOrBuffer(data, length, 0, encodedDataLength, dataPayloadType);
328}
329
330void ResourceLoader::didReceiveBuffer(PassRefPtr<SharedBuffer> buffer, long long encodedDataLength, DataPayloadType dataPayloadType)
331{
332    didReceiveDataOrBuffer(0, 0, buffer, encodedDataLength, dataPayloadType);
333}
334
335void ResourceLoader::didReceiveDataOrBuffer(const char* data, unsigned length, PassRefPtr<SharedBuffer> prpBuffer, long long encodedDataLength, DataPayloadType dataPayloadType)
336{
337    // This method should only get data+length *OR* a SharedBuffer.
338    ASSERT(!prpBuffer || (!data && !length));
339
340    // Protect this in this delegate method since the additional processing can do
341    // anything including possibly derefing this; one example of this is Radar 3266216.
342    Ref<ResourceLoader> protect(*this);
343    RefPtr<SharedBuffer> buffer = prpBuffer;
344
345    addDataOrBuffer(data, length, buffer.get(), dataPayloadType);
346
347    // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
348    // However, with today's computers and networking speeds, this won't happen in practice.
349    // Could be an issue with a giant local file.
350    if (m_options.sendLoadCallbacks() == SendCallbacks && m_frame)
351        frameLoader()->notifier().didReceiveData(this, buffer ? buffer->data() : data, buffer ? buffer->size() : length, static_cast<int>(encodedDataLength));
352}
353
354void ResourceLoader::didFinishLoading(double finishTime)
355{
356    didFinishLoadingOnePart(finishTime);
357
358    // If the load has been cancelled by a delegate in response to didFinishLoad(), do not release
359    // the resources a second time, they have been released by cancel.
360    if (wasCancelled())
361        return;
362    releaseResources();
363}
364
365void ResourceLoader::didFinishLoadingOnePart(double finishTime)
366{
367    // If load has been cancelled after finishing (which could happen with a
368    // JavaScript that changes the window location), do nothing.
369    if (wasCancelled())
370        return;
371    ASSERT(!m_reachedTerminalState);
372
373    if (m_notifiedLoadComplete)
374        return;
375    m_notifiedLoadComplete = true;
376    if (m_options.sendLoadCallbacks() == SendCallbacks)
377        frameLoader()->notifier().didFinishLoad(this, finishTime);
378}
379
380void ResourceLoader::didFail(const ResourceError& error)
381{
382    if (wasCancelled())
383        return;
384    ASSERT(!m_reachedTerminalState);
385
386    // Protect this in this delegate method since the additional processing can do
387    // anything including possibly derefing this; one example of this is Radar 3266216.
388    Ref<ResourceLoader> protect(*this);
389
390    cleanupForError(error);
391    releaseResources();
392}
393
394void ResourceLoader::cleanupForError(const ResourceError& error)
395{
396    if (FormData* data = m_request.httpBody())
397        data->removeGeneratedFilesIfNeeded();
398
399    if (m_notifiedLoadComplete)
400        return;
401    m_notifiedLoadComplete = true;
402    if (m_options.sendLoadCallbacks() == SendCallbacks && m_identifier)
403        frameLoader()->notifier().didFailToLoad(this, error);
404}
405
406void ResourceLoader::didChangePriority(ResourceLoadPriority loadPriority)
407{
408    if (m_handle)
409        m_handle->didChangePriority(loadPriority);
410}
411
412void ResourceLoader::cancel()
413{
414    cancel(ResourceError());
415}
416
417void ResourceLoader::cancel(const ResourceError& error)
418{
419    // If the load has already completed - succeeded, failed, or previously cancelled - do nothing.
420    if (m_reachedTerminalState)
421        return;
422
423    ResourceError nonNullError = error.isNull() ? cancelledError() : error;
424
425    // willCancel() and didFailToLoad() both call out to clients that might do
426    // something causing the last reference to this object to go away.
427    Ref<ResourceLoader> protect(*this);
428
429    // If we re-enter cancel() from inside willCancel(), we want to pick up from where we left
430    // off without re-running willCancel()
431    if (m_cancellationStatus == NotCancelled) {
432        m_cancellationStatus = CalledWillCancel;
433
434        willCancel(nonNullError);
435    }
436
437    // If we re-enter cancel() from inside didFailToLoad(), we want to pick up from where we
438    // left off without redoing any of this work.
439    if (m_cancellationStatus == CalledWillCancel) {
440        m_cancellationStatus = Cancelled;
441
442        if (m_handle)
443            m_handle->clearAuthentication();
444
445        m_documentLoader->cancelPendingSubstituteLoad(this);
446        if (m_handle) {
447            m_handle->cancel();
448            m_handle = 0;
449        }
450        cleanupForError(nonNullError);
451    }
452
453    // If cancel() completed from within the call to willCancel() or didFailToLoad(),
454    // we don't want to redo didCancel() or releasesResources().
455    if (m_reachedTerminalState)
456        return;
457
458    didCancel(nonNullError);
459
460    if (m_cancellationStatus == FinishedCancel)
461        return;
462    m_cancellationStatus = FinishedCancel;
463
464    releaseResources();
465}
466
467ResourceError ResourceLoader::cancelledError()
468{
469    return frameLoader()->cancelledError(m_request);
470}
471
472ResourceError ResourceLoader::blockedError()
473{
474    return frameLoader()->client().blockedError(m_request);
475}
476
477ResourceError ResourceLoader::cannotShowURLError()
478{
479    return frameLoader()->client().cannotShowURLError(m_request);
480}
481
482void ResourceLoader::willSendRequest(ResourceHandle*, ResourceRequest& request, const ResourceResponse& redirectResponse)
483{
484    if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForRedirect(this, request, redirectResponse))
485        return;
486    willSendRequest(request, redirectResponse);
487}
488
489void ResourceLoader::didSendData(ResourceHandle*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
490{
491    didSendData(bytesSent, totalBytesToBeSent);
492}
493
494void ResourceLoader::didReceiveResponse(ResourceHandle*, const ResourceResponse& response)
495{
496    if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForResponse(this, response))
497        return;
498    didReceiveResponse(response);
499}
500
501void ResourceLoader::didReceiveData(ResourceHandle*, const char* data, unsigned length, int encodedDataLength)
502{
503    InspectorInstrumentationCookie cookie = InspectorInstrumentation::willReceiveResourceData(m_frame.get(), identifier(), encodedDataLength);
504    didReceiveData(data, length, encodedDataLength, DataPayloadBytes);
505    InspectorInstrumentation::didReceiveResourceData(cookie);
506}
507
508void ResourceLoader::didReceiveBuffer(ResourceHandle*, PassRefPtr<SharedBuffer> buffer, int encodedDataLength)
509{
510    InspectorInstrumentationCookie cookie = InspectorInstrumentation::willReceiveResourceData(m_frame.get(), identifier(), encodedDataLength);
511    didReceiveBuffer(buffer, encodedDataLength, DataPayloadBytes);
512    InspectorInstrumentation::didReceiveResourceData(cookie);
513}
514
515void ResourceLoader::didFinishLoading(ResourceHandle*, double finishTime)
516{
517    didFinishLoading(finishTime);
518}
519
520void ResourceLoader::didFail(ResourceHandle*, const ResourceError& error)
521{
522    if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForError(this, error))
523        return;
524    didFail(error);
525}
526
527void ResourceLoader::wasBlocked(ResourceHandle*)
528{
529    didFail(blockedError());
530}
531
532void ResourceLoader::cannotShowURL(ResourceHandle*)
533{
534    didFail(cannotShowURLError());
535}
536
537bool ResourceLoader::shouldUseCredentialStorage()
538{
539    if (m_options.allowCredentials() == DoNotAllowStoredCredentials)
540        return false;
541
542    Ref<ResourceLoader> protect(*this);
543    return frameLoader()->client().shouldUseCredentialStorage(documentLoader(), identifier());
544}
545
546void ResourceLoader::didReceiveAuthenticationChallenge(const AuthenticationChallenge& challenge)
547{
548    ASSERT(m_handle->hasAuthenticationChallenge());
549
550    // Protect this in this delegate method since the additional processing can do
551    // anything including possibly derefing this; one example of this is Radar 3266216.
552    Ref<ResourceLoader> protect(*this);
553
554    if (m_options.allowCredentials() == AllowStoredCredentials) {
555        if (m_options.clientCredentialPolicy() == AskClientForAllCredentials || (m_options.clientCredentialPolicy() == DoNotAskClientForCrossOriginCredentials && m_frame->document()->securityOrigin()->canRequest(originalRequest().url()))) {
556            frameLoader()->notifier().didReceiveAuthenticationChallenge(this, challenge);
557            return;
558        }
559    }
560    // Only these platforms provide a way to continue without credentials.
561    // If we can't continue with credentials, we need to cancel the load altogether.
562#if PLATFORM(COCOA) || USE(CFNETWORK) || USE(CURL) || PLATFORM(GTK) || PLATFORM(EFL)
563    challenge.authenticationClient()->receivedRequestToContinueWithoutCredential(challenge);
564    ASSERT(!m_handle || !m_handle->hasAuthenticationChallenge());
565#else
566    didFail(blockedError());
567#endif
568}
569
570void ResourceLoader::didCancelAuthenticationChallenge(const AuthenticationChallenge& challenge)
571{
572    // Protect this in this delegate method since the additional processing can do
573    // anything including possibly derefing this; one example of this is Radar 3266216.
574    Ref<ResourceLoader> protect(*this);
575    frameLoader()->notifier().didCancelAuthenticationChallenge(this, challenge);
576}
577
578#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
579
580bool ResourceLoader::canAuthenticateAgainstProtectionSpace(const ProtectionSpace& protectionSpace)
581{
582    Ref<ResourceLoader> protect(*this);
583    return frameLoader()->client().canAuthenticateAgainstProtectionSpace(documentLoader(), identifier(), protectionSpace);
584}
585
586#endif
587
588#if PLATFORM(IOS)
589
590RetainPtr<CFDictionaryRef> ResourceLoader::connectionProperties(ResourceHandle*)
591{
592    return frameLoader()->connectionProperties(this);
593}
594
595#endif
596
597void ResourceLoader::receivedCancellation(const AuthenticationChallenge&)
598{
599    cancel();
600}
601
602#if PLATFORM(MAC)
603
604void ResourceLoader::schedule(SchedulePair& pair)
605{
606    if (m_handle)
607        m_handle->schedule(pair);
608}
609
610void ResourceLoader::unschedule(SchedulePair& pair)
611{
612    if (m_handle)
613        m_handle->unschedule(pair);
614}
615
616#endif
617
618#if USE(QUICK_LOOK)
619void ResourceLoader::didCreateQuickLookHandle(QuickLookHandle& handle)
620{
621    frameLoader()->client().didCreateQuickLookHandle(handle);
622}
623#endif
624
625}
626