Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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 "core/loader/DocumentLoader.h"
32
33 #include "core/FetchInitiatorTypeNames.h"
34 #include "core/dom/Document.h"
35 #include "core/dom/DocumentParser.h"
36 #include "core/events/Event.h"
37 #include "core/fetch/MemoryCache.h"
38 #include "core/fetch/ResourceFetcher.h"
39 #include "core/fetch/ResourceLoader.h"
40 #include "core/html/HTMLFrameOwnerElement.h"
41 #include "core/html/parser/TextResourceDecoder.h"
42 #include "core/inspector/InspectorInstrumentation.h"
43 #include "core/loader/FrameLoader.h"
44 #include "core/loader/FrameLoaderClient.h"
45 #include "core/loader/UniqueIdentifier.h"
46 #include "core/loader/appcache/ApplicationCacheHost.h"
47 #include "core/frame/LocalDOMWindow.h"
48 #include "core/frame/LocalFrame.h"
49 #include "core/frame/csp/ContentSecurityPolicy.h"
50 #include "core/page/FrameTree.h"
51 #include "core/page/Page.h"
52 #include "core/frame/Settings.h"
53 #include "core/inspector/ConsoleMessage.h"
54 #include "platform/Logging.h"
55 #include "platform/UserGestureIndicator.h"
56 #include "platform/mhtml/ArchiveResource.h"
57 #include "platform/mhtml/ArchiveResourceCollection.h"
58 #include "platform/mhtml/MHTMLArchive.h"
59 #include "platform/plugins/PluginData.h"
60 #include "platform/weborigin/SchemeRegistry.h"
61 #include "platform/weborigin/SecurityPolicy.h"
62 #include "public/platform/Platform.h"
63 #include "public/platform/WebMimeRegistry.h"
64 #include "public/platform/WebThreadedDataReceiver.h"
65 #include "wtf/Assertions.h"
66 #include "wtf/text/WTFString.h"
67
68 namespace blink {
69
70 static bool isArchiveMIMEType(const String& mimeType)
71 {
72     return mimeType == "multipart/related";
73 }
74
75 DocumentLoader::DocumentLoader(LocalFrame* frame, const ResourceRequest& req, const SubstituteData& substituteData)
76     : m_frame(frame)
77     , m_fetcher(ResourceFetcher::create(this))
78     , m_originalRequest(req)
79     , m_substituteData(substituteData)
80     , m_request(req)
81     , m_committed(false)
82     , m_isClientRedirect(false)
83     , m_replacesCurrentHistoryItem(false)
84     , m_loadingMainResource(false)
85     , m_timeOfLastDataReceived(0.0)
86     , m_applicationCacheHost(adoptPtr(new ApplicationCacheHost(this)))
87 {
88 }
89
90 FrameLoader* DocumentLoader::frameLoader() const
91 {
92     if (!m_frame)
93         return 0;
94     return &m_frame->loader();
95 }
96
97 ResourceLoader* DocumentLoader::mainResourceLoader() const
98 {
99     return m_mainResource ? m_mainResource->loader() : 0;
100 }
101
102 DocumentLoader::~DocumentLoader()
103 {
104     ASSERT(!m_frame || !isLoading());
105     m_fetcher->clearDocumentLoader();
106     clearMainResourceHandle();
107 }
108
109 unsigned long DocumentLoader::mainResourceIdentifier() const
110 {
111     return m_mainResource ? m_mainResource->identifier() : 0;
112 }
113
114 Document* DocumentLoader::document() const
115 {
116     if (m_frame && m_frame->loader().documentLoader() == this)
117         return m_frame->document();
118     return 0;
119 }
120
121 const ResourceRequest& DocumentLoader::originalRequest() const
122 {
123     return m_originalRequest;
124 }
125
126 const ResourceRequest& DocumentLoader::request() const
127 {
128     return m_request;
129 }
130
131 const KURL& DocumentLoader::url() const
132 {
133     return m_request.url();
134 }
135
136 void DocumentLoader::updateForSameDocumentNavigation(const KURL& newURL, SameDocumentNavigationSource sameDocumentNavigationSource)
137 {
138     KURL oldURL = m_request.url();
139     m_originalRequest.setURL(newURL);
140     m_request.setURL(newURL);
141     if (sameDocumentNavigationSource == SameDocumentNavigationHistoryApi) {
142         m_request.setHTTPMethod("GET");
143         m_request.setHTTPBody(nullptr);
144     }
145     clearRedirectChain();
146     if (m_isClientRedirect)
147         appendRedirect(oldURL);
148     appendRedirect(newURL);
149 }
150
151 const KURL& DocumentLoader::urlForHistory() const
152 {
153     return unreachableURL().isEmpty() ? url() : unreachableURL();
154 }
155
156 void DocumentLoader::setMainDocumentError(const ResourceError& error)
157 {
158     m_mainDocumentError = error;
159 }
160
161 void DocumentLoader::mainReceivedError(const ResourceError& error)
162 {
163     ASSERT(!error.isNull());
164     ASSERT(!mainResourceLoader() || !mainResourceLoader()->defersLoading() || InspectorInstrumentation::isDebuggerPaused(m_frame));
165     m_applicationCacheHost->failedLoadingMainResource();
166     if (!frameLoader())
167         return;
168     setMainDocumentError(error);
169     clearMainResourceLoader();
170     frameLoader()->receivedMainResourceError(error);
171     clearMainResourceHandle();
172 }
173
174 // Cancels the data source's pending loads.  Conceptually, a data source only loads
175 // one document at a time, but one document may have many related resources.
176 // stopLoading will stop all loads initiated by the data source,
177 // but not loads initiated by child frames' data sources -- that's the WebFrame's job.
178 void DocumentLoader::stopLoading()
179 {
180     RefPtr<LocalFrame> protectFrame(m_frame);
181     RefPtr<DocumentLoader> protectLoader(this);
182
183     // In some rare cases, calling FrameLoader::stopLoading could cause isLoading() to return false.
184     // (This can happen when there's a single XMLHttpRequest currently loading and stopLoading causes it
185     // to stop loading. Because of this, we need to save it so we don't return early.
186     bool loading = isLoading();
187
188     if (m_committed) {
189         // Attempt to stop the frame if the document loader is loading, or if it is done loading but
190         // still  parsing. Failure to do so can cause a world leak.
191         Document* doc = m_frame->document();
192
193         if (loading || doc->parsing())
194             m_frame->loader().stopLoading();
195     }
196
197     if (!loading) {
198         m_fetcher->stopFetching();
199         return;
200     }
201
202     if (m_loadingMainResource) {
203         // Stop the main resource loader and let it send the cancelled message.
204         cancelMainResourceLoad(ResourceError::cancelledError(m_request.url()));
205     } else if (m_fetcher->isFetching()) {
206         // The main resource loader already finished loading. Set the cancelled error on the
207         // document and let the resourceLoaders send individual cancelled messages below.
208         setMainDocumentError(ResourceError::cancelledError(m_request.url()));
209     } else {
210         // If there are no resource loaders, we need to manufacture a cancelled message.
211         // (A back/forward navigation has no resource loaders because its resources are cached.)
212         mainReceivedError(ResourceError::cancelledError(m_request.url()));
213     }
214
215     m_fetcher->stopFetching();
216 }
217
218 void DocumentLoader::commitIfReady()
219 {
220     if (!m_committed) {
221         m_committed = true;
222         frameLoader()->commitProvisionalLoad();
223     }
224 }
225
226 bool DocumentLoader::isLoading() const
227 {
228     if (document() && document()->hasActiveParser())
229         return true;
230
231     return m_loadingMainResource || m_fetcher->isFetching();
232 }
233
234 void DocumentLoader::notifyFinished(Resource* resource)
235 {
236     ASSERT_UNUSED(resource, m_mainResource == resource);
237     ASSERT(m_mainResource);
238
239     RefPtr<DocumentLoader> protect(this);
240
241     if (!m_mainResource->errorOccurred() && !m_mainResource->wasCanceled()) {
242         finishedLoading(m_mainResource->loadFinishTime());
243         return;
244     }
245
246     mainReceivedError(m_mainResource->resourceError());
247 }
248
249 void DocumentLoader::finishedLoading(double finishTime)
250 {
251     ASSERT(!mainResourceLoader() || !mainResourceLoader()->defersLoading() || InspectorInstrumentation::isDebuggerPaused(m_frame));
252
253     RefPtr<DocumentLoader> protect(this);
254
255     double responseEndTime = finishTime;
256     if (!responseEndTime)
257         responseEndTime = m_timeOfLastDataReceived;
258     if (!responseEndTime)
259         responseEndTime = monotonicallyIncreasingTime();
260     timing()->setResponseEnd(responseEndTime);
261
262     commitIfReady();
263     if (!frameLoader())
264         return;
265
266     if (!maybeCreateArchive()) {
267         // If this is an empty document, it will not have actually been created yet. Commit dummy data so that
268         // DocumentWriter::begin() gets called and creates the Document.
269         if (!m_writer)
270             commitData(0, 0);
271     }
272
273     endWriting(m_writer.get());
274
275     if (!m_mainDocumentError.isNull())
276         return;
277     clearMainResourceLoader();
278     if (!frameLoader()->stateMachine()->creatingInitialEmptyDocument())
279         frameLoader()->checkLoadComplete();
280
281     // If the document specified an application cache manifest, it violates the author's intent if we store it in the memory cache
282     // and deny the appcache the chance to intercept it in the future, so remove from the memory cache.
283     if (m_frame) {
284         if (m_mainResource && m_frame->document()->hasAppCacheManifest())
285             memoryCache()->remove(m_mainResource.get());
286     }
287     m_applicationCacheHost->finishedLoadingMainResource();
288     clearMainResourceHandle();
289 }
290
291 bool DocumentLoader::isRedirectAfterPost(const ResourceRequest& newRequest, const ResourceResponse& redirectResponse)
292 {
293     int status = redirectResponse.httpStatusCode();
294     if (((status >= 301 && status <= 303) || status == 307)
295         && m_originalRequest.httpMethod() == "POST")
296         return true;
297
298     return false;
299 }
300
301 bool DocumentLoader::shouldContinueForNavigationPolicy(const ResourceRequest& request, ContentSecurityPolicyCheck shouldCheckMainWorldContentSecurityPolicy, bool isTransitionNavigation)
302 {
303     // Don't ask if we are loading an empty URL.
304     if (request.url().isEmpty() || m_substituteData.isValid())
305         return true;
306
307     // If we're loading content into a subframe, check against the parent's Content Security Policy
308     // and kill the load if that check fails, unless we should bypass the main world's CSP.
309     // FIXME: CSP checks are broken for OOPI. For now, this policy always allows frames with a remote parent...
310     if ((shouldCheckMainWorldContentSecurityPolicy == CheckContentSecurityPolicy) && (m_frame->deprecatedLocalOwner() && !m_frame->deprecatedLocalOwner()->document().contentSecurityPolicy()->allowChildFrameFromSource(request.url()))) {
311         // Fire a load event, as timing attacks would otherwise reveal that the
312         // frame was blocked. This way, it looks like every other cross-origin
313         // page load.
314         m_frame->document()->enforceSandboxFlags(SandboxOrigin);
315         m_frame->owner()->dispatchLoad();
316         return false;
317     }
318
319     NavigationPolicy policy = m_triggeringAction.policy();
320     policy = frameLoader()->client()->decidePolicyForNavigation(request, this, policy, isTransitionNavigation);
321     if (policy == NavigationPolicyCurrentTab)
322         return true;
323     if (policy == NavigationPolicyIgnore)
324         return false;
325     if (!LocalDOMWindow::allowPopUp(*m_frame) && !UserGestureIndicator::processingUserGesture())
326         return false;
327     frameLoader()->client()->loadURLExternally(request, policy);
328     return false;
329 }
330
331 void DocumentLoader::redirectReceived(Resource* resource, ResourceRequest& request, const ResourceResponse& redirectResponse)
332 {
333     ASSERT_UNUSED(resource, resource == m_mainResource);
334     willSendRequest(request, redirectResponse);
335 }
336
337 void DocumentLoader::updateRequest(Resource* resource, const ResourceRequest& request)
338 {
339     ASSERT_UNUSED(resource, resource == m_mainResource);
340     m_request = request;
341 }
342
343 static bool isFormSubmission(NavigationType type)
344 {
345     return type == NavigationTypeFormSubmitted || type == NavigationTypeFormResubmitted;
346 }
347
348 void DocumentLoader::willSendRequest(ResourceRequest& newRequest, const ResourceResponse& redirectResponse)
349 {
350     // Note that there are no asserts here as there are for the other callbacks. This is due to the
351     // fact that this "callback" is sent when starting every load, and the state of callback
352     // deferrals plays less of a part in this function in preventing the bad behavior deferring
353     // callbacks is meant to prevent.
354     ASSERT(!newRequest.isNull());
355     if (isFormSubmission(m_triggeringAction.type()) && !m_frame->document()->contentSecurityPolicy()->allowFormAction(newRequest.url())) {
356         cancelMainResourceLoad(ResourceError::cancelledError(newRequest.url()));
357         return;
358     }
359
360     ASSERT(timing()->fetchStart());
361     if (!redirectResponse.isNull()) {
362         // If the redirecting url is not allowed to display content from the target origin,
363         // then block the redirect.
364         RefPtr<SecurityOrigin> redirectingOrigin = SecurityOrigin::create(redirectResponse.url());
365         if (!redirectingOrigin->canDisplay(newRequest.url())) {
366             FrameLoader::reportLocalLoadFailed(m_frame, newRequest.url().string());
367             cancelMainResourceLoad(ResourceError::cancelledError(newRequest.url()));
368             return;
369         }
370         timing()->addRedirect(redirectResponse.url(), newRequest.url());
371     }
372
373     // If we're fielding a redirect in response to a POST, force a load from origin, since
374     // this is a common site technique to return to a page viewing some data that the POST
375     // just modified.
376     if (newRequest.cachePolicy() == UseProtocolCachePolicy && isRedirectAfterPost(newRequest, redirectResponse))
377         newRequest.setCachePolicy(ReloadBypassingCache);
378
379     // If this is a sub-frame, check for mixed content blocking against the parent frame.
380     if (Frame* parent = m_frame->tree().parent()) {
381         if (parent->isLocalFrame() && !toLocalFrame(parent)->loader().mixedContentChecker()->canFrameInsecureContent(toLocalFrame(parent)->document()->securityOrigin(), newRequest.url())) {
382             cancelMainResourceLoad(ResourceError::cancelledError(newRequest.url()));
383             return;
384         }
385     }
386
387     m_request = newRequest;
388
389     if (redirectResponse.isNull())
390         return;
391
392     appendRedirect(newRequest.url());
393     frameLoader()->client()->dispatchDidReceiveServerRedirectForProvisionalLoad();
394     if (!shouldContinueForNavigationPolicy(newRequest, CheckContentSecurityPolicy))
395         cancelMainResourceLoad(ResourceError::cancelledError(m_request.url()));
396 }
397
398 static bool canShowMIMEType(const String& mimeType, Page* page)
399 {
400     if (blink::Platform::current()->mimeRegistry()->supportsMIMEType(mimeType) == blink::WebMimeRegistry::IsSupported)
401         return true;
402     PluginData* pluginData = page->pluginData();
403     return !mimeType.isEmpty() && pluginData && pluginData->supportsMimeType(mimeType);
404 }
405
406 bool DocumentLoader::shouldContinueForResponse() const
407 {
408     if (m_substituteData.isValid())
409         return true;
410
411     int statusCode = m_response.httpStatusCode();
412     if (statusCode == 204 || statusCode == 205) {
413         // The server does not want us to replace the page contents.
414         return false;
415     }
416
417     if (contentDispositionType(m_response.httpHeaderField("Content-Disposition")) == ContentDispositionAttachment) {
418         // The server wants us to download instead of replacing the page contents.
419         // Downloading is handled by the embedder, but we still get the initial
420         // response so that we can ignore it and clean up properly.
421         return false;
422     }
423
424     if (!canShowMIMEType(m_response.mimeType(), m_frame->page()))
425         return false;
426
427     // Prevent remote web archives from loading because they can claim to be from any domain and thus avoid cross-domain security checks.
428     if (equalIgnoringCase("multipart/related", m_response.mimeType()) && !SchemeRegistry::shouldTreatURLSchemeAsLocal(m_request.url().protocol()))
429         return false;
430
431     return true;
432 }
433
434 void DocumentLoader::responseReceived(Resource* resource, const ResourceResponse& response)
435 {
436     ASSERT_UNUSED(resource, m_mainResource == resource);
437     RefPtr<DocumentLoader> protect(this);
438
439     m_applicationCacheHost->didReceiveResponseForMainResource(response);
440
441     // The memory cache doesn't understand the application cache or its caching rules. So if a main resource is served
442     // from the application cache, ensure we don't save the result for future use. All responses loaded
443     // from appcache will have a non-zero appCacheID().
444     if (response.appCacheID())
445         memoryCache()->remove(m_mainResource.get());
446
447     DEFINE_STATIC_LOCAL(AtomicString, xFrameOptionHeader, ("x-frame-options", AtomicString::ConstructFromLiteral));
448     HTTPHeaderMap::const_iterator it = response.httpHeaderFields().find(xFrameOptionHeader);
449     if (it != response.httpHeaderFields().end()) {
450         String content = it->value;
451         ASSERT(m_mainResource);
452         unsigned long identifier = mainResourceIdentifier();
453         ASSERT(identifier);
454         if (frameLoader()->shouldInterruptLoadForXFrameOptions(content, response.url(), identifier)) {
455             InspectorInstrumentation::continueAfterXFrameOptionsDenied(m_frame, this, identifier, response);
456             String message = "Refused to display '" + response.url().elidedString() + "' in a frame because it set 'X-Frame-Options' to '" + content + "'.";
457             RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, message);
458             consoleMessage->setRequestIdentifier(identifier);
459             frame()->document()->addMessage(consoleMessage.release());
460             frame()->document()->enforceSandboxFlags(SandboxOrigin);
461             if (FrameOwner* owner = frame()->owner())
462                 owner->dispatchLoad();
463
464             // The load event might have detached this frame. In that case, the load will already have been cancelled during detach.
465             if (frameLoader())
466                 cancelMainResourceLoad(ResourceError::cancelledError(m_request.url()));
467             return;
468         }
469     }
470
471     ASSERT(!mainResourceLoader() || !mainResourceLoader()->defersLoading());
472
473     m_response = response;
474
475     if (isArchiveMIMEType(m_response.mimeType()) && m_mainResource->dataBufferingPolicy() != BufferData)
476         m_mainResource->setDataBufferingPolicy(BufferData);
477
478     if (!shouldContinueForResponse()) {
479         InspectorInstrumentation::continueWithPolicyIgnore(m_frame, this, m_mainResource->identifier(), m_response);
480         cancelMainResourceLoad(ResourceError::cancelledError(m_request.url()));
481         return;
482     }
483
484     if (m_response.isHTTP()) {
485         int status = m_response.httpStatusCode();
486         // FIXME: Fallback content only works if the parent is in the same processs.
487         if ((status < 200 || status >= 300) && m_frame->owner()) {
488             if (!m_frame->deprecatedLocalOwner()) {
489                 ASSERT_NOT_REACHED();
490             } else if (m_frame->deprecatedLocalOwner()->isObjectElement()) {
491                 m_frame->deprecatedLocalOwner()->renderFallbackContent();
492                 // object elements are no longer rendered after we fallback, so don't
493                 // keep trying to process data from their load
494                 cancelMainResourceLoad(ResourceError::cancelledError(m_request.url()));
495             }
496         }
497     }
498 }
499
500 void DocumentLoader::ensureWriter(const AtomicString& mimeType, const KURL& overridingURL)
501 {
502     if (m_writer)
503         return;
504
505     const AtomicString& encoding = overrideEncoding().isNull() ? response().textEncodingName() : overrideEncoding();
506     m_writer = createWriterFor(m_frame, 0, url(), mimeType, encoding, false);
507     m_writer->setDocumentWasLoadedAsPartOfNavigation();
508     // This should be set before receivedFirstData().
509     if (!overridingURL.isEmpty())
510         m_frame->document()->setBaseURLOverride(overridingURL);
511
512     // Call receivedFirstData() exactly once per load.
513     frameLoader()->receivedFirstData();
514     m_frame->document()->maybeHandleHttpRefresh(m_response.httpHeaderField("Refresh"), Document::HttpRefreshFromHeader);
515 }
516
517 void DocumentLoader::commitData(const char* bytes, size_t length)
518 {
519     ensureWriter(m_response.mimeType());
520     ASSERT(m_frame->document()->parsing());
521     m_writer->addData(bytes, length);
522 }
523
524 void DocumentLoader::dataReceived(Resource* resource, const char* data, int length)
525 {
526     ASSERT(data);
527     ASSERT(length);
528     ASSERT_UNUSED(resource, resource == m_mainResource);
529     ASSERT(!m_response.isNull());
530     ASSERT(!mainResourceLoader() || !mainResourceLoader()->defersLoading());
531
532     // Both unloading the old page and parsing the new page may execute JavaScript which destroys the datasource
533     // by starting a new load, so retain temporarily.
534     RefPtr<LocalFrame> protectFrame(m_frame);
535     RefPtr<DocumentLoader> protectLoader(this);
536
537     m_applicationCacheHost->mainResourceDataReceived(data, length);
538     m_timeOfLastDataReceived = monotonicallyIncreasingTime();
539
540     commitIfReady();
541     if (!frameLoader())
542         return;
543     if (isArchiveMIMEType(response().mimeType()))
544         return;
545     commitData(data, length);
546
547     // If we are sending data to MediaDocument, we should stop here
548     // and cancel the request.
549     if (m_frame && m_frame->document()->isMediaDocument())
550         cancelMainResourceLoad(ResourceError::cancelledError(m_request.url()));
551 }
552
553 void DocumentLoader::clearRedirectChain()
554 {
555     m_redirectChain.clear();
556 }
557
558 void DocumentLoader::appendRedirect(const KURL& url)
559 {
560     m_redirectChain.append(url);
561 }
562
563 void DocumentLoader::detachFromFrame()
564 {
565     ASSERT(m_frame);
566     RefPtr<LocalFrame> protectFrame(m_frame);
567     RefPtr<DocumentLoader> protectLoader(this);
568
569     // It never makes sense to have a document loader that is detached from its
570     // frame have any loads active, so go ahead and kill all the loads.
571     stopLoading();
572
573     m_applicationCacheHost->setApplicationCache(0);
574     InspectorInstrumentation::loaderDetachedFromFrame(m_frame, this);
575     m_frame = 0;
576 }
577
578 void DocumentLoader::clearMainResourceLoader()
579 {
580     m_loadingMainResource = false;
581 }
582
583 void DocumentLoader::clearMainResourceHandle()
584 {
585     if (!m_mainResource)
586         return;
587     m_mainResource->removeClient(this);
588     m_mainResource = 0;
589 }
590
591 bool DocumentLoader::maybeCreateArchive()
592 {
593     // Only the top-frame can load MHTML.
594     if (m_frame->tree().parent())
595         return false;
596
597     // Give the archive machinery a crack at this document. If the MIME type is not an archive type, it will return 0.
598     if (!isArchiveMIMEType(m_response.mimeType()))
599         return false;
600
601     ASSERT(m_mainResource);
602     m_archive = MHTMLArchive::create(m_response.url(), m_mainResource->resourceBuffer());
603     // Invalid MHTML.
604     if (!m_archive || !m_archive->mainResource()) {
605         m_archive.clear();
606         return false;
607     }
608
609     addAllArchiveResources(m_archive.get());
610     ArchiveResource* mainResource = m_archive->mainResource();
611
612     // The origin is the MHTML file, we need to set the base URL to the document encoded in the MHTML so
613     // relative URLs are resolved properly.
614     ensureWriter(mainResource->mimeType(), m_archive->mainResource()->url());
615
616     // The Document has now been created.
617     document()->enforceSandboxFlags(SandboxAll);
618
619     commitData(mainResource->data()->data(), mainResource->data()->size());
620     return true;
621 }
622
623 void DocumentLoader::addAllArchiveResources(MHTMLArchive* archive)
624 {
625     ASSERT(archive);
626     if (!m_archiveResourceCollection)
627         m_archiveResourceCollection = ArchiveResourceCollection::create();
628     m_archiveResourceCollection->addAllResources(archive);
629 }
630
631 void DocumentLoader::prepareSubframeArchiveLoadIfNeeded()
632 {
633     if (!m_frame->tree().parent() || !m_frame->tree().parent()->isLocalFrame())
634         return;
635
636     ArchiveResourceCollection* parentCollection = toLocalFrame(m_frame->tree().parent())->loader().documentLoader()->m_archiveResourceCollection.get();
637     if (!parentCollection)
638         return;
639
640     m_archive = parentCollection->popSubframeArchive(m_frame->tree().uniqueName(), m_request.url());
641
642     if (!m_archive)
643         return;
644     addAllArchiveResources(m_archive.get());
645
646     ArchiveResource* mainResource = m_archive->mainResource();
647     m_substituteData = SubstituteData(mainResource->data(), mainResource->mimeType(), mainResource->textEncoding(), KURL());
648 }
649
650 bool DocumentLoader::scheduleArchiveLoad(Resource* cachedResource, const ResourceRequest& request)
651 {
652     if (!m_archive)
653         return false;
654
655     ASSERT(m_archiveResourceCollection);
656     ArchiveResource* archiveResource = m_archiveResourceCollection->archiveResourceForURL(request.url());
657     if (!archiveResource) {
658         cachedResource->error(Resource::LoadError);
659         return true;
660     }
661
662     cachedResource->setLoading(true);
663     cachedResource->responseReceived(archiveResource->response());
664     SharedBuffer* data = archiveResource->data();
665     if (data)
666         cachedResource->appendData(data->data(), data->size());
667     cachedResource->finish();
668     return true;
669 }
670
671 const AtomicString& DocumentLoader::responseMIMEType() const
672 {
673     return m_response.mimeType();
674 }
675
676 const KURL& DocumentLoader::unreachableURL() const
677 {
678     return m_substituteData.failingURL();
679 }
680
681 void DocumentLoader::setDefersLoading(bool defers)
682 {
683     // Multiple frames may be loading the same main resource simultaneously. If deferral state changes,
684     // each frame's DocumentLoader will try to send a setDefersLoading() to the same underlying ResourceLoader. Ensure only
685     // the "owning" DocumentLoader does so, as setDefersLoading() is not resilient to setting the same value repeatedly.
686     if (mainResourceLoader() && mainResourceLoader()->isLoadedBy(m_fetcher.get()))
687         mainResourceLoader()->setDefersLoading(defers);
688
689     m_fetcher->setDefersLoading(defers);
690 }
691
692 bool DocumentLoader::maybeLoadEmpty()
693 {
694     bool shouldLoadEmpty = !m_substituteData.isValid() && (m_request.url().isEmpty() || SchemeRegistry::shouldLoadURLSchemeAsEmptyDocument(m_request.url().protocol()));
695     if (!shouldLoadEmpty)
696         return false;
697
698     if (m_request.url().isEmpty() && !frameLoader()->stateMachine()->creatingInitialEmptyDocument())
699         m_request.setURL(blankURL());
700     m_response = ResourceResponse(m_request.url(), "text/html", 0, nullAtom, String());
701     finishedLoading(monotonicallyIncreasingTime());
702     return true;
703 }
704
705 void DocumentLoader::startLoadingMainResource()
706 {
707     RefPtr<DocumentLoader> protect(this);
708     m_mainDocumentError = ResourceError();
709     timing()->markNavigationStart();
710     ASSERT(!m_mainResource);
711     ASSERT(!m_loadingMainResource);
712     m_loadingMainResource = true;
713
714     if (maybeLoadEmpty())
715         return;
716
717     ASSERT(timing()->navigationStart());
718     ASSERT(!timing()->fetchStart());
719     timing()->markFetchStart();
720     willSendRequest(m_request, ResourceResponse());
721
722     // willSendRequest() may lead to our LocalFrame being detached or cancelling the load via nulling the ResourceRequest.
723     if (!m_frame || m_request.isNull())
724         return;
725
726     m_applicationCacheHost->willStartLoadingMainResource(m_request);
727     prepareSubframeArchiveLoadIfNeeded();
728
729     ResourceRequest request(m_request);
730     DEFINE_STATIC_LOCAL(ResourceLoaderOptions, mainResourceLoadOptions,
731         (SniffContent, DoNotBufferData, AllowStoredCredentials, ClientRequestedCredentials, CheckContentSecurityPolicy, DocumentContext));
732     FetchRequest cachedResourceRequest(request, FetchInitiatorTypeNames::document, mainResourceLoadOptions);
733     m_mainResource = m_fetcher->fetchMainResource(cachedResourceRequest, m_substituteData);
734     if (!m_mainResource) {
735         m_request = ResourceRequest();
736         // If the load was aborted by clearing m_request, it's possible the ApplicationCacheHost
737         // is now in a state where starting an empty load will be inconsistent. Replace it with
738         // a new ApplicationCacheHost.
739         m_applicationCacheHost = adoptPtr(new ApplicationCacheHost(this));
740         maybeLoadEmpty();
741         return;
742     }
743     m_mainResource->addClient(this);
744
745     // A bunch of headers are set when the underlying ResourceLoader is created, and m_request needs to include those.
746     if (mainResourceLoader())
747         request = mainResourceLoader()->originalRequest();
748     // If there was a fragment identifier on m_request, the cache will have stripped it. m_request should include
749     // the fragment identifier, so add that back in.
750     if (equalIgnoringFragmentIdentifier(m_request.url(), request.url()))
751         request.setURL(m_request.url());
752     m_request = request;
753 }
754
755 void DocumentLoader::cancelMainResourceLoad(const ResourceError& resourceError)
756 {
757     RefPtr<DocumentLoader> protect(this);
758     ResourceError error = resourceError.isNull() ? ResourceError::cancelledError(m_request.url()) : resourceError;
759
760     if (mainResourceLoader())
761         mainResourceLoader()->cancel(error);
762
763     mainReceivedError(error);
764 }
765
766 void DocumentLoader::attachThreadedDataReceiver(PassOwnPtr<blink::WebThreadedDataReceiver> threadedDataReceiver)
767 {
768     if (mainResourceLoader())
769         mainResourceLoader()->attachThreadedDataReceiver(threadedDataReceiver);
770 }
771
772 void DocumentLoader::endWriting(DocumentWriter* writer)
773 {
774     ASSERT_UNUSED(writer, m_writer == writer);
775     m_writer->end();
776     m_writer.clear();
777 }
778
779 PassRefPtrWillBeRawPtr<DocumentWriter> DocumentLoader::createWriterFor(LocalFrame* frame, const Document* ownerDocument, const KURL& url, const AtomicString& mimeType, const AtomicString& encoding, bool dispatch)
780 {
781     // Create a new document before clearing the frame, because it may need to
782     // inherit an aliased security context.
783     DocumentInit init(url, frame);
784     init.withNewRegistrationContext();
785
786     // In some rare cases, we'll re-used a LocalDOMWindow for a new Document. For example,
787     // when a script calls window.open("..."), the browser gives JavaScript a window
788     // synchronously but kicks off the load in the window asynchronously. Web sites
789     // expect that modifications that they make to the window object synchronously
790     // won't be blown away when the network load commits. To make that happen, we
791     // "securely transition" the existing LocalDOMWindow to the Document that results from
792     // the network load. See also SecurityContext::isSecureTransitionTo.
793     bool shouldReuseDefaultView = frame->loader().stateMachine()->isDisplayingInitialEmptyDocument() && frame->document()->isSecureTransitionTo(url);
794
795     frame->loader().clear();
796
797     if (frame->document())
798         frame->document()->prepareForDestruction();
799
800     if (!shouldReuseDefaultView)
801         frame->setDOMWindow(LocalDOMWindow::create(*frame));
802
803     RefPtrWillBeRawPtr<Document> document = frame->domWindow()->installNewDocument(mimeType, init);
804     if (ownerDocument) {
805         document->setCookieURL(ownerDocument->cookieURL());
806         document->setSecurityOrigin(ownerDocument->securityOrigin());
807         if (ownerDocument->isTransitionDocument())
808             document->setIsTransitionDocument();
809     }
810
811     frame->loader().didBeginDocument(dispatch);
812
813     return DocumentWriter::create(document.get(), mimeType, encoding);
814 }
815
816 const AtomicString& DocumentLoader::mimeType() const
817 {
818     if (m_writer)
819         return m_writer->mimeType();
820     return m_response.mimeType();
821 }
822
823 void DocumentLoader::setUserChosenEncoding(const String& charset)
824 {
825     if (m_writer)
826         m_writer->setUserChosenEncoding(charset);
827 }
828
829 // This is only called by ScriptController::executeScriptIfJavaScriptURL
830 // and always contains the result of evaluating a javascript: url.
831 // This is the <iframe src="javascript:'html'"> case.
832 void DocumentLoader::replaceDocument(const String& source, Document* ownerDocument)
833 {
834     m_frame->loader().stopAllLoaders();
835     m_writer = createWriterFor(m_frame, ownerDocument, m_frame->document()->url(), mimeType(), m_writer ? m_writer->encoding() : emptyAtom, true);
836     if (!source.isNull())
837         m_writer->appendReplacingData(source);
838     endWriting(m_writer.get());
839 }
840
841 } // namespace blink