Merge MainResourceLoader's SubstituteData loading + others into DocumentLoader
[WebKit-https.git] / Source / WebCore / loader / DocumentLoader.cpp
1 /*
2  * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
3  * Copyright (C) 2011 Google Inc. All rights reserved.
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 "DocumentLoader.h"
32
33 #include "ApplicationCacheHost.h"
34 #include "ArchiveResourceCollection.h"
35 #include "CachedPage.h"
36 #include "CachedResourceLoader.h"
37 #include "DOMWindow.h"
38 #include "Document.h"
39 #include "DocumentParser.h"
40 #include "DocumentWriter.h"
41 #include "Event.h"
42 #include "FormState.h"
43 #include "Frame.h"
44 #include "FrameLoader.h"
45 #include "FrameLoaderClient.h"
46 #include "FrameTree.h"
47 #include "HTMLFormElement.h"
48 #include "HistoryItem.h"
49 #include "InspectorInstrumentation.h"
50 #include "Logging.h"
51 #include "MainResourceLoader.h"
52 #include "MemoryCache.h"
53 #include "Page.h"
54 #include "ProgressTracker.h"
55 #include "ResourceBuffer.h"
56 #include "SchemeRegistry.h"
57 #include "Settings.h"
58 #include "TextResourceDecoder.h"
59 #include "WebCoreMemoryInstrumentation.h"
60 #include <wtf/Assertions.h>
61 #include <wtf/MemoryInstrumentationHashMap.h>
62 #include <wtf/MemoryInstrumentationHashSet.h>
63 #include <wtf/MemoryInstrumentationVector.h>
64 #include <wtf/text/CString.h>
65 #include <wtf/text/WTFString.h>
66 #include <wtf/unicode/Unicode.h>
67
68 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
69 #include "ArchiveFactory.h"
70 #endif
71
72 #if USE(CONTENT_FILTERING)
73 #include "ContentFilter.h"
74 #endif
75
76 namespace WebCore {
77
78 static void cancelAll(const ResourceLoaderSet& loaders)
79 {
80     Vector<RefPtr<ResourceLoader> > loadersCopy;
81     copyToVector(loaders, loadersCopy);
82     size_t size = loadersCopy.size();
83     for (size_t i = 0; i < size; ++i)
84         loadersCopy[i]->cancel();
85 }
86
87 static void setAllDefersLoading(const ResourceLoaderSet& loaders, bool defers)
88 {
89     Vector<RefPtr<ResourceLoader> > loadersCopy;
90     copyToVector(loaders, loadersCopy);
91     size_t size = loadersCopy.size();
92     for (size_t i = 0; i < size; ++i)
93         loadersCopy[i]->setDefersLoading(defers);
94 }
95
96 DocumentLoader::DocumentLoader(const ResourceRequest& req, const SubstituteData& substituteData)
97     : m_deferMainResourceDataLoad(true)
98     , m_frame(0)
99     , m_cachedResourceLoader(CachedResourceLoader::create(this))
100     , m_writer(m_frame)
101     , m_originalRequest(req)
102     , m_substituteData(substituteData)
103     , m_originalRequestCopy(req)
104     , m_request(req)
105     , m_committed(false)
106     , m_isStopping(false)
107     , m_gotFirstByte(false)
108     , m_isClientRedirect(false)
109     , m_isLoadingMultipartContent(false)
110     , m_loadingEmptyDocument(false)
111     , m_wasOnloadHandled(false)
112     , m_stopRecordingResponses(false)
113     , m_substituteResourceDeliveryTimer(this, &DocumentLoader::substituteResourceDeliveryTimerFired)
114     , m_didCreateGlobalHistoryEntry(false)
115     , m_timeOfLastDataReceived(0.0)
116     , m_identifierForLoadWithoutResourceLoader(0)
117     , m_dataLoadTimer(this, &DocumentLoader::handleSubstituteDataLoadNow)
118     , m_waitingForContentPolicy(false)
119     , m_applicationCacheHost(adoptPtr(new ApplicationCacheHost(this)))
120 {
121 }
122
123 FrameLoader* DocumentLoader::frameLoader() const
124 {
125     if (!m_frame)
126         return 0;
127     return m_frame->loader();
128 }
129
130 ResourceLoader* DocumentLoader::mainResourceLoader() const
131 {
132     return m_mainResourceLoader ? m_mainResourceLoader->loader() : 0;
133 }
134
135 DocumentLoader::~DocumentLoader()
136 {
137     ASSERT(!m_frame || frameLoader()->activeDocumentLoader() != this || !isLoading());
138     if (m_iconLoadDecisionCallback)
139         m_iconLoadDecisionCallback->invalidate();
140     if (m_iconDataCallback)
141         m_iconDataCallback->invalidate();
142     m_cachedResourceLoader->clearDocumentLoader();
143 }
144
145 PassRefPtr<ResourceBuffer> DocumentLoader::mainResourceData() const
146 {
147     if (m_mainResourceData)
148         return m_mainResourceData;
149     if (m_substituteData.isValid())
150         return ResourceBuffer::create(m_substituteData.content()->data(), m_substituteData.content()->size());
151     if (m_mainResourceLoader)
152         return m_mainResourceLoader->resourceData();
153     return 0;
154 }
155
156 Document* DocumentLoader::document() const
157 {
158     if (m_frame && m_frame->loader()->documentLoader() == this)
159         return m_frame->document();
160     return 0;
161 }
162
163 const ResourceRequest& DocumentLoader::originalRequest() const
164 {
165     return m_originalRequest;
166 }
167
168 const ResourceRequest& DocumentLoader::originalRequestCopy() const
169 {
170     return m_originalRequestCopy;
171 }
172
173 const ResourceRequest& DocumentLoader::request() const
174 {
175     return m_request;
176 }
177
178 ResourceRequest& DocumentLoader::request()
179 {
180     return m_request;
181 }
182
183 const KURL& DocumentLoader::url() const
184 {
185     return request().url();
186 }
187
188 void DocumentLoader::replaceRequestURLForSameDocumentNavigation(const KURL& url)
189 {
190     m_originalRequestCopy.setURL(url);
191     m_request.setURL(url);
192 }
193
194 void DocumentLoader::setRequest(const ResourceRequest& req)
195 {
196     // Replacing an unreachable URL with alternate content looks like a server-side
197     // redirect at this point, but we can replace a committed dataSource.
198     bool handlingUnreachableURL = false;
199
200     handlingUnreachableURL = m_substituteData.isValid() && !m_substituteData.failingURL().isEmpty();
201
202     if (handlingUnreachableURL)
203         m_committed = false;
204
205     // We should never be getting a redirect callback after the data
206     // source is committed, except in the unreachable URL case. It 
207     // would be a WebFoundation bug if it sent a redirect callback after commit.
208     ASSERT(!m_committed);
209
210     m_request = req;
211 }
212
213 void DocumentLoader::setMainDocumentError(const ResourceError& error)
214 {
215     m_mainDocumentError = error;    
216     frameLoader()->client()->setMainDocumentError(this, error);
217 }
218
219 void DocumentLoader::mainReceivedError(const ResourceError& error)
220 {
221     ASSERT(!error.isNull());
222     if (m_applicationCacheHost->maybeLoadFallbackForMainError(request(), error))
223         return;
224
225     if (m_identifierForLoadWithoutResourceLoader) {
226         ASSERT(!mainResourceLoader());
227         frameLoader()->client()->dispatchDidFailLoading(this, m_identifierForLoadWithoutResourceLoader, error);
228     }
229
230     // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred.
231     // See <rdar://problem/6304600> for more details.
232 #if !USE(CF)
233     ASSERT(!m_frame->page()->defersLoading());
234 #endif
235
236     m_applicationCacheHost->failedLoadingMainResource();
237
238     if (!frameLoader())
239         return;
240     setMainDocumentError(error);
241     clearMainResourceLoader();
242     frameLoader()->receivedMainResourceError(error);
243 }
244
245 // Cancels the data source's pending loads.  Conceptually, a data source only loads
246 // one document at a time, but one document may have many related resources. 
247 // stopLoading will stop all loads initiated by the data source, 
248 // but not loads initiated by child frames' data sources -- that's the WebFrame's job.
249 void DocumentLoader::stopLoading()
250 {
251     RefPtr<Frame> protectFrame(m_frame);
252     RefPtr<DocumentLoader> protectLoader(this);
253
254     // In some rare cases, calling FrameLoader::stopLoading could cause isLoading() to return false.
255     // (This can happen when there's a single XMLHttpRequest currently loading and stopLoading causes it
256     // to stop loading. Because of this, we need to save it so we don't return early.
257     bool loading = isLoading();
258     
259     if (m_committed) {
260         // Attempt to stop the frame if the document loader is loading, or if it is done loading but
261         // still  parsing. Failure to do so can cause a world leak.
262         Document* doc = m_frame->document();
263         
264         if (loading || doc->parsing())
265             m_frame->loader()->stopLoading(UnloadEventPolicyNone);
266     }
267
268     // Always cancel multipart loaders
269     cancelAll(m_multipartSubresourceLoaders);
270
271     // Appcache uses ResourceHandle directly, DocumentLoader doesn't count these loads.
272     m_applicationCacheHost->stopLoadingInFrame(m_frame);
273     
274 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
275     clearArchiveResources();
276 #endif
277
278     if (!loading) {
279         // If something above restarted loading we might run into mysterious crashes like 
280         // https://bugs.webkit.org/show_bug.cgi?id=62764 and <rdar://problem/9328684>
281         ASSERT(!isLoading());
282         return;
283     }
284
285     // We might run in to infinite recursion if we're stopping loading as the result of 
286     // detaching from the frame, so break out of that recursion here.
287     // See <rdar://problem/9673866> for more details.
288     if (m_isStopping)
289         return;
290
291     m_isStopping = true;
292
293     FrameLoader* frameLoader = DocumentLoader::frameLoader();
294     
295     if (m_mainResourceLoader)
296         // Stop the main resource loader and let it send the cancelled message.
297         cancelMainResourceLoad(frameLoader->cancelledError(m_request));
298     else if (!m_subresourceLoaders.isEmpty())
299         // The main resource loader already finished loading. Set the cancelled error on the 
300         // document and let the subresourceLoaders send individual cancelled messages below.
301         setMainDocumentError(frameLoader->cancelledError(m_request));
302     else
303         // If there are no resource loaders, we need to manufacture a cancelled message.
304         // (A back/forward navigation has no resource loaders because its resources are cached.)
305         mainReceivedError(frameLoader->cancelledError(m_request));
306     
307     stopLoadingSubresources();
308     stopLoadingPlugIns();
309     
310     m_isStopping = false;
311 }
312
313 void DocumentLoader::commitIfReady()
314 {
315     if (!m_committed) {
316         m_committed = true;
317         frameLoader()->commitProvisionalLoad();
318     }
319 }
320
321 bool DocumentLoader::isLoading() const
322 {
323     // FIXME: This should always be enabled, but it seems to cause
324     // http/tests/security/feed-urls-from-remote.html to timeout on Mac WK1
325     // see http://webkit.org/b/110554 and http://webkit.org/b/110401
326 #if ENABLE(THREADED_HTML_PARSER)
327     if (document() && document()->hasActiveParser())
328         return true;
329 #endif
330     return isLoadingMainResource() || !m_subresourceLoaders.isEmpty() || !m_plugInStreamLoaders.isEmpty();
331 }
332
333 void DocumentLoader::finishedLoading(double finishTime)
334 {
335     // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred.
336     // See <rdar://problem/6304600> for more details.
337 #if !USE(CF)
338     ASSERT(!m_frame->page()->defersLoading() || InspectorInstrumentation::isDebuggerPaused(m_frame));
339 #endif
340
341     RefPtr<DocumentLoader> protect(this);
342
343     if (m_identifierForLoadWithoutResourceLoader) {
344         frameLoader()->notifier()->dispatchDidFinishLoading(this, m_identifierForLoadWithoutResourceLoader, finishTime);
345         m_identifierForLoadWithoutResourceLoader = 0;
346     }
347
348 #if USE(CONTENT_FILTERING)
349     if (m_contentFilter && m_contentFilter->needsMoreData()) {
350         m_contentFilter->finishedAddingData();
351         int length;
352         const char* data = m_contentFilter->getReplacementData(length);
353         if (data)
354             receivedData(data, length);
355     }
356 #endif
357
358     maybeFinishLoadingMultipartContent();
359
360     double responseEndTime = finishTime;
361     if (!responseEndTime)
362         responseEndTime = m_timeOfLastDataReceived;
363     if (!responseEndTime)
364         responseEndTime = monotonicallyIncreasingTime();
365     timing()->setResponseEnd(responseEndTime);
366
367     commitIfReady();
368     if (!frameLoader())
369         return;
370
371     if (!maybeCreateArchive()) {
372         // If this is an empty document, it will not have actually been created yet. Commit dummy data so that
373         // DocumentWriter::begin() gets called and creates the Document.
374         if (!m_gotFirstByte)
375             commitData(0, 0);
376         frameLoader()->client()->finishedLoading(this);
377     }
378
379     m_writer.end();
380     if (!m_mainDocumentError.isNull())
381         return;
382     clearMainResourceLoader();
383     if (!frameLoader()->stateMachine()->creatingInitialEmptyDocument())
384         frameLoader()->checkLoadComplete();
385
386     // If the document specified an application cache manifest, it violates the author's intent if we store it in the memory cache
387     // and deny the appcache the chance to intercept it in the future, so remove from the memory cache.
388     if (frame() && m_mainResourceLoader) {
389         if (m_mainResourceLoader->cachedMainResource() && frame()->document()->hasManifest())
390             memoryCache()->remove(m_mainResourceLoader->cachedMainResource());
391     }
392     m_applicationCacheHost->finishedLoadingMainResource();
393 }
394
395 bool DocumentLoader::isPostOrRedirectAfterPost(const ResourceRequest& newRequest, const ResourceResponse& redirectResponse)
396 {
397     if (newRequest.httpMethod() == "POST")
398         return true;
399
400     int status = redirectResponse.httpStatusCode();
401     if (((status >= 301 && status <= 303) || status == 307)
402         && m_originalRequest.httpMethod() == "POST")
403         return true;
404
405     return false;
406 }
407
408 void DocumentLoader::handleSubstituteDataLoadNow(DocumentLoaderTimer*)
409 {
410     KURL url = m_substituteData.responseURL();
411     if (url.isEmpty())
412         url = m_request.url();
413     ResourceResponse response(url, m_substituteData.mimeType(), m_substituteData.content()->size(), m_substituteData.textEncoding(), "");
414     responseReceived(response);
415 }
416
417 void DocumentLoader::startDataLoadTimer()
418 {
419     m_dataLoadTimer.startOneShot(0);
420
421 #if HAVE(RUNLOOP_TIMER)
422     if (SchedulePairHashSet* scheduledPairs = m_frame->page()->scheduledRunLoopPairs())
423         m_dataLoadTimer.schedule(*scheduledPairs);
424 #endif
425 }
426
427 void DocumentLoader::handleSubstituteDataLoadSoon()
428 {
429     if (deferMainResourceDataLoad())
430         startDataLoadTimer();
431     else
432         handleSubstituteDataLoadNow(0);
433 }
434
435 void DocumentLoader::willSendRequest(ResourceRequest& newRequest, const ResourceResponse& redirectResponse)
436 {
437     // Note that there are no asserts here as there are for the other callbacks. This is due to the
438     // fact that this "callback" is sent when starting every load, and the state of callback
439     // deferrals plays less of a part in this function in preventing the bad behavior deferring 
440     // callbacks is meant to prevent.
441     ASSERT(!newRequest.isNull());
442
443     if (!frameLoader()->checkIfFormActionAllowedByCSP(newRequest.url())) {
444         cancelMainResourceLoad(frameLoader()->cancelledError(newRequest));
445         return;
446     }
447
448     ASSERT(timing()->fetchStart());
449     if (!redirectResponse.isNull()) {
450         // If the redirecting url is not allowed to display content from the target origin,
451         // then block the redirect.
452         RefPtr<SecurityOrigin> redirectingOrigin = SecurityOrigin::create(redirectResponse.url());
453         if (!redirectingOrigin->canDisplay(newRequest.url())) {
454             FrameLoader::reportLocalLoadFailed(m_frame, newRequest.url().string());
455             cancelMainResourceLoad(frameLoader()->cancelledError(newRequest));
456             return;
457         }
458         timing()->addRedirect(redirectResponse.url(), newRequest.url());
459     }
460
461     // Update cookie policy base URL as URL changes, except for subframes, which use the
462     // URL of the main frame which doesn't change when we redirect.
463     if (frameLoader()->isLoadingMainFrame())
464         newRequest.setFirstPartyForCookies(newRequest.url());
465
466     // If we're fielding a redirect in response to a POST, force a load from origin, since
467     // this is a common site technique to return to a page viewing some data that the POST
468     // just modified.
469     // Also, POST requests always load from origin, but this does not affect subresources.
470     if (newRequest.cachePolicy() == UseProtocolCachePolicy && isPostOrRedirectAfterPost(newRequest, redirectResponse))
471         newRequest.setCachePolicy(ReloadIgnoringCacheData);
472
473     Frame* top = m_frame->tree()->top();
474     if (top != m_frame) {
475         if (!frameLoader()->mixedContentChecker()->canDisplayInsecureContent(top->document()->securityOrigin(), newRequest.url())) {
476             cancelMainResourceLoad(frameLoader()->cancelledError(newRequest));
477             return;
478         }
479     }
480
481     setRequest(newRequest);
482
483     if (!redirectResponse.isNull()) {
484         // We checked application cache for initial URL, now we need to check it for redirected one.
485         ASSERT(!m_substituteData.isValid());
486         m_applicationCacheHost->maybeLoadMainResourceForRedirect(newRequest, m_substituteData);
487         if (m_substituteData.isValid())
488             m_identifierForLoadWithoutResourceLoader = mainResourceLoader()->identifier();
489     }
490
491     // FIXME: Ideally we'd stop the I/O until we hear back from the navigation policy delegate
492     // listener. But there's no way to do that in practice. So instead we cancel later if the
493     // listener tells us to. In practice that means the navigation policy needs to be decided
494     // synchronously for these redirect cases.
495     if (!redirectResponse.isNull())
496         frameLoader()->policyChecker()->checkNavigationPolicy(newRequest, callContinueAfterNavigationPolicy, this);
497 }
498
499 void DocumentLoader::callContinueAfterNavigationPolicy(void* argument, const ResourceRequest& request, PassRefPtr<FormState>, bool shouldContinue)
500 {
501     static_cast<DocumentLoader*>(argument)->continueAfterNavigationPolicy(request, shouldContinue);
502 }
503
504 void DocumentLoader::continueAfterNavigationPolicy(const ResourceRequest&, bool shouldContinue)
505 {
506     if (!shouldContinue)
507         stopLoadingForPolicyChange();
508     else if (m_substituteData.isValid()) {
509         // A redirect resulted in loading substitute data.
510         ASSERT(timing()->redirectCount());
511
512         // We need to remove our reference to the CachedResource in favor of a SubstituteData load.
513         // This will probably trigger the cancellation of the CachedResource's underlying ResourceLoader, though there is a
514         // small chance that the resource is being loaded by a different Frame, preventing the ResourceLoader from being cancelled.
515         // If the ResourceLoader is indeed cancelled, it would normally send resource load callbacks.
516         // However, from an API perspective, this isn't a cancellation. Therefore, sever our relationship with the network load,
517         // but prevent the ResourceLoader from sending ResourceLoadNotifier callbacks.
518         RefPtr<ResourceLoader> resourceLoader = m_mainResourceLoader->loader();
519         ASSERT(resourceLoader->shouldSendResourceLoadCallbacks());
520         resourceLoader->setSendCallbackPolicy(DoNotSendCallbacks);
521         m_mainResourceLoader->clearResource();
522         resourceLoader->setSendCallbackPolicy(SendCallbacks);
523         handleSubstituteDataLoadSoon();
524     }
525 }
526
527 void DocumentLoader::responseReceived(const ResourceResponse& response)
528 {
529     bool willLoadFallback = m_applicationCacheHost->maybeLoadFallbackForMainResponse(request(), response);
530
531     // The memory cache doesn't understand the application cache or its caching rules. So if a main resource is served
532     // from the application cache, ensure we don't save the result for future use.
533     bool shouldRemoveResourceFromCache = willLoadFallback;
534 #if PLATFORM(CHROMIUM)
535     // chromium's ApplicationCacheHost implementation always returns true for maybeLoadFallbackForMainResponse(). However, all responses loaded
536     // from appcache will have a non-zero appCacheID().
537     if (response.appCacheID())
538         shouldRemoveResourceFromCache = true;
539 #endif
540     if (shouldRemoveResourceFromCache)
541         memoryCache()->remove(m_mainResourceLoader->cachedMainResource());
542
543     if (willLoadFallback)
544         return;
545
546     DEFINE_STATIC_LOCAL(AtomicString, xFrameOptionHeader, ("x-frame-options", AtomicString::ConstructFromLiteral));
547     HTTPHeaderMap::const_iterator it = response.httpHeaderFields().find(xFrameOptionHeader);
548     if (it != response.httpHeaderFields().end()) {
549         String content = it->value;
550         unsigned long identifier = m_identifierForLoadWithoutResourceLoader ? m_identifierForLoadWithoutResourceLoader : mainResourceLoader()->identifier();
551         if (frameLoader()->shouldInterruptLoadForXFrameOptions(content, response.url(), identifier)) {
552             InspectorInstrumentation::continueAfterXFrameOptionsDenied(m_frame, this, identifier, response);
553             String message = "Refused to display '" + response.url().elidedString() + "' in a frame because it set 'X-Frame-Options' to '" + content + "'.";
554             frame()->document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message, identifier);
555             cancelMainResourceLoad(frameLoader()->cancelledError(m_request));
556             return;
557         }
558     }
559
560     // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred.
561     // See <rdar://problem/6304600> for more details.
562 #if !USE(CF)
563     ASSERT(!m_frame->page()->defersLoading());
564 #endif
565
566     if (m_isLoadingMultipartContent) {
567         setupForReplace();
568         m_mainResourceLoader->cachedMainResource()->clear();
569     } else if (response.isMultipart()) {
570         FeatureObserver::observe(m_frame->document(), FeatureObserver::MultipartMainResource);
571         m_isLoadingMultipartContent = true;
572     }
573
574     setResponse(response);
575
576     if (m_identifierForLoadWithoutResourceLoader)
577         frameLoader()->notifier()->dispatchDidReceiveResponse(this, m_identifierForLoadWithoutResourceLoader, m_response, 0);
578
579     ASSERT(!m_waitingForContentPolicy);
580     m_waitingForContentPolicy = true;
581
582     // Always show content with valid substitute data.
583     if (m_substituteData.isValid()) {
584         continueAfterContentPolicy(PolicyUse);
585         return;
586     }
587
588 #if ENABLE(FTPDIR)
589     // Respect the hidden FTP Directory Listing pref so it can be tested even if the policy delegate might otherwise disallow it
590     Settings* settings = m_frame->settings();
591     if (settings && settings->forceFTPDirectoryListings() && m_response.mimeType() == "application/x-ftp-directory") {
592         continueAfterContentPolicy(PolicyUse);
593         return;
594     }
595 #endif
596
597 #if USE(CONTENT_FILTERING)
598     if (response.url().protocolIs("https") && ContentFilter::isEnabled())
599         m_contentFilter = ContentFilter::create(response);
600 #endif
601
602     frameLoader()->policyChecker()->checkContentPolicy(m_response, callContinueAfterContentPolicy, this);
603 }
604
605 void DocumentLoader::callContinueAfterContentPolicy(void* argument, PolicyAction policy)
606 {
607     static_cast<DocumentLoader*>(argument)->continueAfterContentPolicy(policy);
608 }
609
610 void DocumentLoader::continueAfterContentPolicy(PolicyAction policy)
611 {
612     ASSERT(m_waitingForContentPolicy);
613     m_waitingForContentPolicy = false;
614     if (isStopping())
615         return;
616
617     KURL url = m_request.url();
618     const String& mimeType = m_response.mimeType();
619     
620     switch (policy) {
621     case PolicyUse: {
622         // Prevent remote web archives from loading because they can claim to be from any domain and thus avoid cross-domain security checks (4120255).
623         bool isRemoteWebArchive = (equalIgnoringCase("application/x-webarchive", mimeType)
624 #if PLATFORM(GTK)
625             || equalIgnoringCase("message/rfc822", mimeType)
626 #endif
627             || equalIgnoringCase("multipart/related", mimeType))
628             && !m_substituteData.isValid() && !SchemeRegistry::shouldTreatURLSchemeAsLocal(url.protocol());
629         if (!frameLoader()->client()->canShowMIMEType(mimeType) || isRemoteWebArchive) {
630             frameLoader()->policyChecker()->cannotShowMIMEType(m_response);
631             // Check reachedTerminalState since the load may have already been canceled inside of _handleUnimplementablePolicyWithErrorCode::.
632             stopLoadingForPolicyChange();
633             return;
634         }
635         break;
636     }
637
638     case PolicyDownload: {
639         // The main CachedResource can be null, e.g. when loading a substitute resource from application cache.
640         if (!m_mainResourceLoader->cachedMainResource()) {
641             mainReceivedError(frameLoader()->client()->cannotShowURLError(m_request));
642             return;
643         }
644         InspectorInstrumentation::continueWithPolicyDownload(m_frame, this, mainResourceLoader()->identifier(), m_response);
645
646         // When starting the request, we didn't know that it would result in download and not navigation. Now we know that main document URL didn't change.
647         // Download may use this knowledge for purposes unrelated to cookies, notably for setting file quarantine data.
648         frameLoader()->setOriginalURLForDownloadRequest(m_request);
649         frameLoader()->client()->convertMainResourceLoadToDownload(this, m_request, m_response);
650
651         // It might have gone missing
652         if (mainResourceLoader())
653             mainResourceLoader()->didFail(interruptedForPolicyChangeError());
654         return;
655     }
656     case PolicyIgnore:
657         InspectorInstrumentation::continueWithPolicyIgnore(m_frame, this, mainResourceLoader()->identifier(), m_response);
658         stopLoadingForPolicyChange();
659         return;
660     
661     default:
662         ASSERT_NOT_REACHED();
663     }
664
665     if (m_response.isHTTP()) {
666         int status = m_response.httpStatusCode();
667         if (status < 200 || status >= 300) {
668             bool hostedByObject = frameLoader()->isHostedByObjectElement();
669
670             frameLoader()->handleFallbackContent();
671             // object elements are no longer rendered after we fallback, so don't
672             // keep trying to process data from their load
673
674             if (hostedByObject)
675                 cancelMainResourceLoad(frameLoader()->cancelledError(m_request));
676         }
677     }
678
679     if (!isStopping() && m_substituteData.isValid()) {
680         if (m_substituteData.content()->size())
681             receivedData(m_substituteData.content()->data(), m_substituteData.content()->size());
682         if (isLoadingMainResource())
683             finishedLoading(0);
684     }
685 }
686
687 void DocumentLoader::commitLoad(const char* data, int length)
688 {
689     // Both unloading the old page and parsing the new page may execute JavaScript which destroys the datasource
690     // by starting a new load, so retain temporarily.
691     RefPtr<Frame> protectFrame(m_frame);
692     RefPtr<DocumentLoader> protectLoader(this);
693
694     commitIfReady();
695     FrameLoader* frameLoader = DocumentLoader::frameLoader();
696     if (!frameLoader)
697         return;
698 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
699     if (ArchiveFactory::isArchiveMimeType(response().mimeType()))
700         return;
701 #endif
702     frameLoader->client()->committedLoad(this, data, length);
703 }
704
705 ResourceError DocumentLoader::interruptedForPolicyChangeError() const
706 {
707     return frameLoader()->client()->interruptedForPolicyChangeError(request());
708 }
709
710 void DocumentLoader::stopLoadingForPolicyChange()
711 {
712     ResourceError error = interruptedForPolicyChangeError();
713     error.setIsCancellation(true);
714     cancelMainResourceLoad(error);
715 }
716
717 void DocumentLoader::commitData(const char* bytes, size_t length)
718 {
719     if (!m_gotFirstByte) {
720         m_gotFirstByte = true;
721         m_writer.begin(documentURL(), false);
722         m_writer.setDocumentWasLoadedAsPartOfNavigation();
723
724         if (frameLoader()->stateMachine()->creatingInitialEmptyDocument())
725             return;
726         
727 #if ENABLE(MHTML)
728         // The origin is the MHTML file, we need to set the base URL to the document encoded in the MHTML so
729         // relative URLs are resolved properly.
730         if (m_archive && m_archive->type() == Archive::MHTML)
731             m_frame->document()->setBaseURLOverride(m_archive->mainResource()->url());
732 #endif
733
734         // Call receivedFirstData() exactly once per load. We should only reach this point multiple times
735         // for multipart loads, and FrameLoader::isReplacing() will be true after the first time.
736         if (!isMultipartReplacingLoad())
737             frameLoader()->receivedFirstData();
738
739         bool userChosen = true;
740         String encoding = overrideEncoding();
741         if (encoding.isNull()) {
742             userChosen = false;
743             encoding = response().textEncodingName();
744 #if ENABLE(WEB_ARCHIVE)
745             if (m_archive && m_archive->type() == Archive::WebArchive)
746                 encoding = m_archive->mainResource()->textEncoding();
747 #endif
748         }
749         m_writer.setEncoding(encoding, userChosen);
750     }
751     ASSERT(m_frame->document()->parsing());
752     m_writer.addData(bytes, length);
753 }
754
755 void DocumentLoader::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
756 {
757     MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::Loader);
758     info.addMember(m_frame, "frame");
759     info.addMember(m_cachedResourceLoader, "cachedResourceLoader");
760     info.addMember(m_mainResourceLoader, "mainResourceLoader");
761     info.addMember(m_mainResourceData, "mainResourceData");
762     info.addMember(m_subresourceLoaders, "subresourceLoaders");
763     info.addMember(m_multipartSubresourceLoaders, "multipartSubresourceLoaders");
764     info.addMember(m_plugInStreamLoaders, "plugInStreamLoaders");
765     info.addMember(m_substituteData, "substituteData");
766     info.addMember(m_pageTitle.string(), "pageTitle.string()");
767     info.addMember(m_overrideEncoding, "overrideEncoding");
768     info.addMember(m_responses, "responses");
769     info.addMember(m_originalRequest, "originalRequest");
770     info.addMember(m_originalRequestCopy, "originalRequestCopy");
771     info.addMember(m_request, "request");
772     info.addMember(m_response, "response");
773     info.addMember(m_lastCheckedRequest, "lastCheckedRequest");
774     info.addMember(m_responses, "responses");
775     info.addMember(m_pendingSubstituteResources, "pendingSubstituteResources");
776     info.addMember(m_substituteResourceDeliveryTimer, "substituteResourceDeliveryTimer");
777     info.addMember(m_archiveResourceCollection, "archiveResourceCollection");
778 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
779     info.addMember(m_archive, "archive");
780     info.addMember(m_parsedArchiveData, "parsedArchiveData");
781 #endif
782     info.addMember(m_resourcesClientKnowsAbout, "resourcesClientKnowsAbout");
783     info.addMember(m_resourcesLoadedFromMemoryCacheForClientNotification, "resourcesLoadedFromMemoryCacheForClientNotification");
784     info.addMember(m_clientRedirectSourceForHistory, "clientRedirectSourceForHistory");
785     info.addMember(m_iconLoadDecisionCallback, "iconLoadDecisionCallback");
786     info.addMember(m_iconDataCallback, "iconDataCallback");
787     info.addMember(m_applicationCacheHost, "applicationCacheHost");
788 }
789
790 void DocumentLoader::receivedData(const char* data, int length)
791 {
792     ASSERT(data);
793     ASSERT(length);
794     ASSERT(!m_response.isNull());
795
796 #if USE(CFNETWORK) || PLATFORM(MAC)
797     // Workaround for <rdar://problem/6060782>
798     if (m_response.isNull())
799         setResponse(ResourceResponse(KURL(), "text/html", 0, String(), String()));
800 #endif
801
802     // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred.
803     // See <rdar://problem/6304600> for more details.
804 #if !USE(CF)
805     ASSERT(!m_frame->page()->defersLoading());
806 #endif
807
808 #if USE(CONTENT_FILTERING)
809     bool loadWasBlockedBeforeFinishing = false;
810     if (m_contentFilter && m_contentFilter->needsMoreData()) {
811         m_contentFilter->addData(data, length);
812
813         if (m_contentFilter->needsMoreData()) {
814             // Since the filter still needs more data to make a decision,
815             // transition back to the committed state so that we don't partially
816             // load content that might later be blocked.
817             commitLoad(0, 0);
818             return;
819         }
820
821         data = m_contentFilter->getReplacementData(length);
822         loadWasBlockedBeforeFinishing = m_contentFilter->didBlockData();
823     }
824 #endif
825
826     if (m_identifierForLoadWithoutResourceLoader)
827         frameLoader()->notifier()->dispatchDidReceiveData(this, m_identifierForLoadWithoutResourceLoader, data, length, -1);
828
829     m_applicationCacheHost->mainResourceDataReceived(data, length, -1, false);
830     m_timeOfLastDataReceived = monotonicallyIncreasingTime();
831
832     if (!isMultipartReplacingLoad())
833         commitLoad(data, length);
834
835 #if USE(CONTENT_FILTERING)
836     if (loadWasBlockedBeforeFinishing)
837         cancelMainResourceLoad(frameLoader()->cancelledError(m_request));
838 #endif
839 }
840
841 void DocumentLoader::setupForReplace()
842 {
843     if (!mainResourceData())
844         return;
845     
846     maybeFinishLoadingMultipartContent();
847     maybeCreateArchive();
848     m_writer.end();
849     frameLoader()->setReplacing();
850     m_gotFirstByte = false;
851     
852     stopLoadingSubresources();
853     stopLoadingPlugIns();
854 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
855     clearArchiveResources();
856 #endif
857 }
858
859 void DocumentLoader::checkLoadComplete()
860 {
861     if (!m_frame || isLoading())
862         return;
863 #if !ENABLE(THREADED_HTML_PARSER)
864     // This ASSERT triggers with the threaded HTML parser.
865     // See https://bugs.webkit.org/show_bug.cgi?id=110937
866     ASSERT(this == frameLoader()->activeDocumentLoader());
867 #endif
868     m_frame->document()->domWindow()->finishedLoading();
869 }
870
871 void DocumentLoader::setFrame(Frame* frame)
872 {
873     if (m_frame == frame)
874         return;
875     ASSERT(frame && !m_frame);
876     m_frame = frame;
877     m_writer.setFrame(frame);
878     attachToFrame();
879 }
880
881 void DocumentLoader::attachToFrame()
882 {
883     ASSERT(m_frame);
884 }
885
886 void DocumentLoader::detachFromFrame()
887 {
888     ASSERT(m_frame);
889     RefPtr<Frame> protectFrame(m_frame);
890     RefPtr<DocumentLoader> protectLoader(this);
891
892     // It never makes sense to have a document loader that is detached from its
893     // frame have any loads active, so go ahead and kill all the loads.
894     stopLoading();
895
896     m_applicationCacheHost->setDOMApplicationCache(0);
897     InspectorInstrumentation::loaderDetachedFromFrame(m_frame, this);
898     m_frame = 0;
899 }
900
901 void DocumentLoader::clearMainResourceLoader()
902 {
903     if (m_mainResourceLoader) {
904         m_mainResourceData = m_mainResourceLoader->resourceData();
905         m_mainResourceLoader = 0;
906     }
907     m_loadingEmptyDocument = false;
908
909     if (this == frameLoader()->activeDocumentLoader())
910         checkLoadComplete();
911 }
912
913 bool DocumentLoader::isLoadingInAPISense() const
914 {
915     // Once a frame has loaded, we no longer need to consider subresources,
916     // but we still need to consider subframes.
917     if (frameLoader()->state() != FrameStateComplete) {
918         if (m_frame->settings()->needsIsLoadingInAPISenseQuirk() && !m_subresourceLoaders.isEmpty())
919             return true;
920     
921         Document* doc = m_frame->document();
922         if ((isLoadingMainResource() || !m_frame->document()->loadEventFinished()) && isLoading())
923             return true;
924         if (m_cachedResourceLoader->requestCount())
925             return true;
926         if (doc->processingLoadEvent())
927             return true;
928         if (doc->hasActiveParser())
929             return true;
930     }
931     return frameLoader()->subframeIsLoading();
932 }
933
934 bool DocumentLoader::maybeCreateArchive()
935 {
936 #if !ENABLE(WEB_ARCHIVE) && !ENABLE(MHTML)
937     return false;
938 #else
939     
940     // Give the archive machinery a crack at this document. If the MIME type is not an archive type, it will return 0.
941     RefPtr<ResourceBuffer> mainResourceBuffer = mainResourceData();
942     m_archive = ArchiveFactory::create(m_response.url(), mainResourceBuffer ? mainResourceBuffer->sharedBuffer() : 0, m_response.mimeType());
943     if (!m_archive)
944         return false;
945     
946     addAllArchiveResources(m_archive.get());
947     ArchiveResource* mainResource = m_archive->mainResource();
948     m_parsedArchiveData = mainResource->data();
949     m_writer.setMIMEType(mainResource->mimeType());
950     
951     ASSERT(m_frame->document());
952     commitData(mainResource->data()->data(), mainResource->data()->size());
953     return true;
954 #endif // !ENABLE(WEB_ARCHIVE) && !ENABLE(MHTML)
955 }
956
957 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
958 void DocumentLoader::setArchive(PassRefPtr<Archive> archive)
959 {
960     m_archive = archive;
961     addAllArchiveResources(m_archive.get());
962 }
963
964 void DocumentLoader::addAllArchiveResources(Archive* archive)
965 {
966     if (!m_archiveResourceCollection)
967         m_archiveResourceCollection = adoptPtr(new ArchiveResourceCollection);
968         
969     ASSERT(archive);
970     if (!archive)
971         return;
972         
973     m_archiveResourceCollection->addAllResources(archive);
974 }
975
976 // FIXME: Adding a resource directly to a DocumentLoader/ArchiveResourceCollection seems like bad design, but is API some apps rely on.
977 // Can we change the design in a manner that will let us deprecate that API without reducing functionality of those apps?
978 void DocumentLoader::addArchiveResource(PassRefPtr<ArchiveResource> resource)
979 {
980     if (!m_archiveResourceCollection)
981         m_archiveResourceCollection = adoptPtr(new ArchiveResourceCollection);
982         
983     ASSERT(resource);
984     if (!resource)
985         return;
986         
987     m_archiveResourceCollection->addResource(resource);
988 }
989
990 PassRefPtr<Archive> DocumentLoader::popArchiveForSubframe(const String& frameName, const KURL& url)
991 {
992     return m_archiveResourceCollection ? m_archiveResourceCollection->popSubframeArchive(frameName, url) : PassRefPtr<Archive>(0);
993 }
994
995 void DocumentLoader::clearArchiveResources()
996 {
997     m_archiveResourceCollection.clear();
998     m_substituteResourceDeliveryTimer.stop();
999 }
1000
1001 SharedBuffer* DocumentLoader::parsedArchiveData() const
1002 {
1003     return m_parsedArchiveData.get();
1004 }
1005 #endif // ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
1006
1007 ArchiveResource* DocumentLoader::archiveResourceForURL(const KURL& url) const
1008 {
1009     if (!m_archiveResourceCollection)
1010         return 0;
1011         
1012     ArchiveResource* resource = m_archiveResourceCollection->archiveResourceForURL(url);
1013
1014     return resource && !resource->shouldIgnoreWhenUnarchiving() ? resource : 0;
1015 }
1016
1017 PassRefPtr<ArchiveResource> DocumentLoader::mainResource() const
1018 {
1019     const ResourceResponse& r = response();
1020     
1021     RefPtr<ResourceBuffer> mainResourceBuffer = mainResourceData();
1022     RefPtr<SharedBuffer> data = mainResourceBuffer ? mainResourceBuffer->sharedBuffer() : 0;
1023     if (!data)
1024         data = SharedBuffer::create();
1025         
1026     return ArchiveResource::create(data, r.url(), r.mimeType(), r.textEncodingName(), frame()->tree()->uniqueName());
1027 }
1028
1029 PassRefPtr<ArchiveResource> DocumentLoader::subresource(const KURL& url) const
1030 {
1031     if (!isCommitted())
1032         return 0;
1033     
1034     CachedResource* resource = m_cachedResourceLoader->cachedResource(url);
1035     if (!resource || !resource->isLoaded())
1036         return archiveResourceForURL(url);
1037
1038     if (resource->type() == CachedResource::MainResource)
1039         return 0;
1040
1041     // FIXME: This has the side effect of making the resource non-purgeable.
1042     // It would be better if it didn't have this permanent effect.
1043     if (!resource->makePurgeable(false))
1044         return 0;
1045
1046     ResourceBuffer* data = resource->resourceBuffer();
1047     if (!data)
1048         return 0;
1049
1050     return ArchiveResource::create(data->sharedBuffer(), url, resource->response());
1051 }
1052
1053 void DocumentLoader::getSubresources(Vector<PassRefPtr<ArchiveResource> >& subresources) const
1054 {
1055     if (!isCommitted())
1056         return;
1057
1058     const CachedResourceLoader::DocumentResourceMap& allResources = m_cachedResourceLoader->allCachedResources();
1059     CachedResourceLoader::DocumentResourceMap::const_iterator end = allResources.end();
1060     for (CachedResourceLoader::DocumentResourceMap::const_iterator it = allResources.begin(); it != end; ++it) {
1061         RefPtr<ArchiveResource> subresource = this->subresource(KURL(ParsedURLString, it->value->url()));
1062         if (subresource)
1063             subresources.append(subresource.release());
1064     }
1065
1066     return;
1067 }
1068
1069 void DocumentLoader::deliverSubstituteResourcesAfterDelay()
1070 {
1071     if (m_pendingSubstituteResources.isEmpty())
1072         return;
1073     ASSERT(m_frame && m_frame->page());
1074     if (m_frame->page()->defersLoading())
1075         return;
1076     if (!m_substituteResourceDeliveryTimer.isActive())
1077         m_substituteResourceDeliveryTimer.startOneShot(0);
1078 }
1079
1080 void DocumentLoader::substituteResourceDeliveryTimerFired(Timer<DocumentLoader>*)
1081 {
1082     if (m_pendingSubstituteResources.isEmpty())
1083         return;
1084     ASSERT(m_frame && m_frame->page());
1085     if (m_frame->page()->defersLoading())
1086         return;
1087
1088     SubstituteResourceMap copy;
1089     copy.swap(m_pendingSubstituteResources);
1090
1091     SubstituteResourceMap::const_iterator end = copy.end();
1092     for (SubstituteResourceMap::const_iterator it = copy.begin(); it != end; ++it) {
1093         RefPtr<ResourceLoader> loader = it->key;
1094         SubstituteResource* resource = it->value.get();
1095         
1096         if (resource) {
1097             SharedBuffer* data = resource->data();
1098         
1099             loader->didReceiveResponse(resource->response());
1100
1101             // Calling ResourceLoader::didReceiveResponse can end up cancelling the load,
1102             // so we need to check if the loader has reached its terminal state.
1103             if (loader->reachedTerminalState())
1104                 return;
1105
1106             loader->didReceiveData(data->data(), data->size(), data->size(), DataPayloadWholeResource);
1107
1108             // Calling ResourceLoader::didReceiveData can end up cancelling the load,
1109             // so we need to check if the loader has reached its terminal state.
1110             if (loader->reachedTerminalState())
1111                 return;
1112
1113             loader->didFinishLoading(0);
1114         } else {
1115             // A null resource means that we should fail the load.
1116             // FIXME: Maybe we should use another error here - something like "not in cache".
1117             loader->didFail(loader->cannotShowURLError());
1118         }
1119     }
1120 }
1121
1122 #ifndef NDEBUG
1123 bool DocumentLoader::isSubstituteLoadPending(ResourceLoader* loader) const
1124 {
1125     return m_pendingSubstituteResources.contains(loader);
1126 }
1127 #endif
1128
1129 void DocumentLoader::cancelPendingSubstituteLoad(ResourceLoader* loader)
1130 {
1131     if (m_pendingSubstituteResources.isEmpty())
1132         return;
1133     m_pendingSubstituteResources.remove(loader);
1134     if (m_pendingSubstituteResources.isEmpty())
1135         m_substituteResourceDeliveryTimer.stop();
1136 }
1137
1138 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
1139 bool DocumentLoader::scheduleArchiveLoad(ResourceLoader* loader, const ResourceRequest& request)
1140 {
1141     if (ArchiveResource* resource = archiveResourceForURL(request.url())) {
1142         m_pendingSubstituteResources.set(loader, resource);
1143         deliverSubstituteResourcesAfterDelay();
1144         return true;
1145     }
1146
1147     if (!m_archive)
1148         return false;
1149
1150     switch (m_archive->type()) {
1151 #if ENABLE(WEB_ARCHIVE)
1152     case Archive::WebArchive:
1153         // WebArchiveDebugMode means we fail loads instead of trying to fetch them from the network if they're not in the archive.
1154         return m_frame->settings() && m_frame->settings()->webArchiveDebugModeEnabled() && ArchiveFactory::isArchiveMimeType(responseMIMEType());
1155 #endif
1156 #if ENABLE(MHTML)
1157     case Archive::MHTML:
1158         return true; // Always fail the load for resources not included in the MHTML.
1159 #endif
1160     default:
1161         return false;
1162     }
1163 }
1164 #endif // ENABLE(WEB_ARCHIVE)
1165
1166 void DocumentLoader::addResponse(const ResourceResponse& r)
1167 {
1168     if (!m_stopRecordingResponses)
1169         m_responses.append(r);
1170 }
1171
1172 void DocumentLoader::stopRecordingResponses()
1173 {
1174     m_stopRecordingResponses = true;
1175     m_responses.shrinkToFit();
1176 }
1177
1178 void DocumentLoader::setTitle(const StringWithDirection& title)
1179 {
1180     if (m_pageTitle == title)
1181         return;
1182
1183     frameLoader()->willChangeTitle(this);
1184     m_pageTitle = title;
1185     frameLoader()->didChangeTitle(this);
1186 }
1187
1188 KURL DocumentLoader::urlForHistory() const
1189 {
1190     // Return the URL to be used for history and B/F list.
1191     // Returns nil for WebDataProtocol URLs that aren't alternates 
1192     // for unreachable URLs, because these can't be stored in history.
1193     if (m_substituteData.isValid())
1194         return unreachableURL();
1195
1196     return m_originalRequestCopy.url();
1197 }
1198
1199 bool DocumentLoader::urlForHistoryReflectsFailure() const
1200 {
1201     return m_substituteData.isValid() || m_response.httpStatusCode() >= 400;
1202 }
1203
1204 const KURL& DocumentLoader::originalURL() const
1205 {
1206     return m_originalRequestCopy.url();
1207 }
1208
1209 const KURL& DocumentLoader::requestURL() const
1210 {
1211     return request().url();
1212 }
1213
1214 const KURL& DocumentLoader::responseURL() const
1215 {
1216     return m_response.url();
1217 }
1218
1219 KURL DocumentLoader::documentURL() const
1220 {
1221     KURL url = substituteData().responseURL();
1222 #if ENABLE(WEB_ARCHIVE)
1223     if (url.isEmpty() && m_archive && m_archive->type() == Archive::WebArchive)
1224         url = m_archive->mainResource()->url();
1225 #endif
1226     if (url.isEmpty())
1227         url = requestURL();
1228     if (url.isEmpty())
1229         url = responseURL();
1230     return url;
1231 }
1232
1233 const String& DocumentLoader::responseMIMEType() const
1234 {
1235     return m_response.mimeType();
1236 }
1237
1238 const KURL& DocumentLoader::unreachableURL() const
1239 {
1240     return m_substituteData.failingURL();
1241 }
1242
1243 void DocumentLoader::setDefersLoading(bool defers)
1244 {
1245     if (m_mainResourceLoader)
1246         m_mainResourceLoader->setDefersLoading(defers);
1247     setAllDefersLoading(m_subresourceLoaders, defers);
1248     setAllDefersLoading(m_plugInStreamLoaders, defers);
1249     if (!defers)
1250         deliverSubstituteResourcesAfterDelay();
1251 }
1252
1253 void DocumentLoader::setMainResourceDataBufferingPolicy(DataBufferingPolicy dataBufferingPolicy)
1254 {
1255     if (m_mainResourceLoader)
1256         m_mainResourceLoader->setDataBufferingPolicy(dataBufferingPolicy);
1257 }
1258
1259 void DocumentLoader::stopLoadingPlugIns()
1260 {
1261     cancelAll(m_plugInStreamLoaders);
1262 }
1263
1264 void DocumentLoader::stopLoadingSubresources()
1265 {
1266     cancelAll(m_subresourceLoaders);
1267 }
1268
1269 void DocumentLoader::addSubresourceLoader(ResourceLoader* loader)
1270 {
1271     // The main resource's underlying ResourceLoader will ask to be added here.
1272     // It is much simpler to handle special casing of main resource loads if we don't
1273     // let it be added. In the main resource load case, m_mainResourceLoader->loader()
1274     // will still be null at this point, but m_gotFirstByte should be false here if and only
1275     // if we are just starting the main resource load.
1276     if (!m_gotFirstByte)
1277         return;
1278     ASSERT(!m_subresourceLoaders.contains(loader));
1279     ASSERT(!m_mainResourceLoader || m_mainResourceLoader->loader() != loader);
1280     m_subresourceLoaders.add(loader);
1281 }
1282
1283 void DocumentLoader::removeSubresourceLoader(ResourceLoader* loader)
1284 {
1285     if (!m_subresourceLoaders.contains(loader))
1286         return;
1287     m_subresourceLoaders.remove(loader);
1288     checkLoadComplete();
1289     if (Frame* frame = m_frame)
1290         frame->loader()->checkLoadComplete();
1291 }
1292
1293 void DocumentLoader::addPlugInStreamLoader(ResourceLoader* loader)
1294 {
1295     m_plugInStreamLoaders.add(loader);
1296 }
1297
1298 void DocumentLoader::removePlugInStreamLoader(ResourceLoader* loader)
1299 {
1300     m_plugInStreamLoaders.remove(loader);
1301     checkLoadComplete();
1302 }
1303
1304 bool DocumentLoader::isLoadingMainResource() const
1305 {
1306     return !!m_mainResourceLoader || m_loadingEmptyDocument;
1307 }
1308
1309 bool DocumentLoader::isMultipartReplacingLoad() const
1310 {
1311     return isLoadingMultipartContent() && frameLoader()->isReplacing();
1312 }
1313
1314 bool DocumentLoader::maybeLoadEmpty()
1315 {
1316     bool shouldLoadEmpty = !m_substituteData.isValid() && (m_request.url().isEmpty() || SchemeRegistry::shouldLoadURLSchemeAsEmptyDocument(m_request.url().protocol()));
1317     if (!shouldLoadEmpty && !frameLoader()->client()->representationExistsForURLScheme(m_request.url().protocol()))
1318         return false;
1319
1320     m_loadingEmptyDocument = true;
1321     if (m_request.url().isEmpty() && !frameLoader()->stateMachine()->creatingInitialEmptyDocument())
1322         m_request.setURL(blankURL());
1323     String mimeType = shouldLoadEmpty ? "text/html" : frameLoader()->client()->generatedMIMETypeForURLScheme(m_request.url().protocol());
1324     setResponse(ResourceResponse(m_request.url(), mimeType, 0, String(), String()));
1325     finishedLoading(monotonicallyIncreasingTime());
1326     return true;
1327 }
1328
1329 void DocumentLoader::startLoadingMainResource()
1330 {
1331     m_mainDocumentError = ResourceError();
1332     timing()->markNavigationStart();
1333     ASSERT(!m_mainResourceLoader);
1334
1335     if (maybeLoadEmpty())
1336         return;
1337
1338     m_mainResourceLoader = MainResourceLoader::create(this);
1339
1340     // FIXME: Is there any way the extra fields could have not been added by now?
1341     // If not, it would be great to remove this line of code.
1342     // Note that currently, some requests may have incorrect extra fields even if this function has been called,
1343     // because we pass a wrong loadType (see FIXME in addExtraFieldsToMainResourceRequest()).
1344     frameLoader()->addExtraFieldsToMainResourceRequest(m_request);
1345
1346     ASSERT(timing()->navigationStart());
1347     ASSERT(!timing()->fetchStart());
1348     timing()->markFetchStart();
1349     willSendRequest(m_request, ResourceResponse());
1350
1351     // willSendRequest() may lead to our Frame being detached or cancelling the load via nulling the ResourceRequest.
1352     if (!m_frame || m_request.isNull())
1353         return;
1354
1355     m_applicationCacheHost->maybeLoadMainResource(m_request, m_substituteData);
1356
1357     if (m_substituteData.isValid()) {
1358         m_identifierForLoadWithoutResourceLoader = m_frame->page()->progress()->createUniqueIdentifier();
1359         frameLoader()->notifier()->assignIdentifierToInitialRequest(m_identifierForLoadWithoutResourceLoader, this, m_request);
1360         frameLoader()->notifier()->dispatchWillSendRequest(this, m_identifierForLoadWithoutResourceLoader, m_request, ResourceResponse());
1361         handleSubstituteDataLoadSoon();
1362         return;
1363     }
1364
1365     ResourceRequest request(m_request);
1366     m_mainResourceLoader->load(m_request);
1367
1368     if (m_request.isNull()) {
1369         m_mainResourceLoader = 0;
1370         // If the load was aborted by clearing m_request, it's possible the ApplicationCacheHost
1371         // is now in a state where starting an empty load will be inconsistent. Replace it with
1372         // a new ApplicationCacheHost.
1373         m_applicationCacheHost = adoptPtr(new ApplicationCacheHost(this));
1374         maybeLoadEmpty();
1375         return;
1376     }
1377
1378     if (!mainResourceLoader()) {
1379         m_identifierForLoadWithoutResourceLoader = m_frame->page()->progress()->createUniqueIdentifier();
1380         frameLoader()->notifier()->assignIdentifierToInitialRequest(m_identifierForLoadWithoutResourceLoader, this, request);
1381         frameLoader()->notifier()->dispatchWillSendRequest(this, m_identifierForLoadWithoutResourceLoader, request, ResourceResponse());
1382     }
1383
1384     // A bunch of headers are set when the underlying ResourceLoader is created, and m_request needs to include those.
1385     if (mainResourceLoader())
1386         request = mainResourceLoader()->originalRequest();
1387     // If there was a fragment identifier on m_request, the cache will have stripped it. m_request should include
1388     // the fragment identifier, so add that back in.
1389     if (equalIgnoringFragmentIdentifier(m_request.url(), request.url()))
1390         request.setURL(m_request.url());
1391     setRequest(request);
1392 }
1393
1394 void DocumentLoader::cancelMainResourceLoad(const ResourceError& error)
1395 {
1396     ASSERT(!error.isNull());
1397     RefPtr<DocumentLoader> protect(this);
1398
1399     m_dataLoadTimer.stop();
1400     if (m_waitingForContentPolicy) {
1401         frameLoader()->policyChecker()->cancelCheck();
1402         ASSERT(m_waitingForContentPolicy);
1403         m_waitingForContentPolicy = false;
1404     }
1405
1406     if (mainResourceLoader())
1407         mainResourceLoader()->cancel(error);
1408
1409     mainReceivedError(error);
1410 }
1411
1412 void DocumentLoader::subresourceLoaderFinishedLoadingOnePart(ResourceLoader* loader)
1413 {
1414     m_multipartSubresourceLoaders.add(loader);
1415     m_subresourceLoaders.remove(loader);
1416     checkLoadComplete();
1417     if (Frame* frame = m_frame)
1418         frame->loader()->checkLoadComplete();    
1419 }
1420
1421 void DocumentLoader::maybeFinishLoadingMultipartContent()
1422 {
1423     if (!isMultipartReplacingLoad())
1424         return;
1425
1426     frameLoader()->setupForReplace();
1427     m_committed = false;
1428     RefPtr<ResourceBuffer> resourceData = mainResourceData();
1429     commitLoad(resourceData->data(), resourceData->size());
1430 }
1431
1432 void DocumentLoader::iconLoadDecisionAvailable()
1433 {
1434     if (m_frame)
1435         m_frame->loader()->icon()->loadDecisionReceived(iconDatabase().synchronousLoadDecisionForIconURL(frameLoader()->icon()->url(), this));
1436 }
1437
1438 static void iconLoadDecisionCallback(IconLoadDecision decision, void* context)
1439 {
1440     static_cast<DocumentLoader*>(context)->continueIconLoadWithDecision(decision);
1441 }
1442
1443 void DocumentLoader::getIconLoadDecisionForIconURL(const String& urlString)
1444 {
1445     if (m_iconLoadDecisionCallback)
1446         m_iconLoadDecisionCallback->invalidate();
1447     m_iconLoadDecisionCallback = IconLoadDecisionCallback::create(this, iconLoadDecisionCallback);
1448     iconDatabase().loadDecisionForIconURL(urlString, m_iconLoadDecisionCallback);
1449 }
1450
1451 void DocumentLoader::continueIconLoadWithDecision(IconLoadDecision decision)
1452 {
1453     ASSERT(m_iconLoadDecisionCallback);
1454     m_iconLoadDecisionCallback = 0;
1455     if (m_frame)
1456         m_frame->loader()->icon()->continueLoadWithDecision(decision);
1457 }
1458
1459 static void iconDataCallback(SharedBuffer*, void*)
1460 {
1461     // FIXME: Implement this once we know what parts of WebCore actually need the icon data returned.
1462 }
1463
1464 void DocumentLoader::getIconDataForIconURL(const String& urlString)
1465 {   
1466     if (m_iconDataCallback)
1467         m_iconDataCallback->invalidate();
1468     m_iconDataCallback = IconDataCallback::create(this, iconDataCallback);
1469     iconDatabase().iconDataForIconURL(urlString, m_iconDataCallback);
1470 }
1471
1472 void DocumentLoader::handledOnloadEvents()
1473 {
1474     m_wasOnloadHandled = true;
1475     applicationCacheHost()->stopDeferringEvents();
1476 }
1477
1478 } // namespace WebCore