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