2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
4 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
5 * Copyright (C) 2008 Alp Toker <alp@atoker.com>
6 * Copyright (C) Research In Motion Limited 2009. All rights reserved.
7 * Copyright (C) 2011 Kris Jordan <krisjordan@gmail.com>
8 * Copyright (C) 2011 Google Inc. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
20 * its contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
24 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
27 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 #include "FrameLoader.h"
38 #include "AXObjectCache.h"
39 #include "ApplicationCacheHost.h"
40 #include "BackForwardController.h"
41 #include "BeforeUnloadEvent.h"
42 #include "MemoryCache.h"
43 #include "CachedPage.h"
44 #include "CachedResourceLoader.h"
46 #include "ChromeClient.h"
48 #include "ContentSecurityPolicy.h"
49 #include "DatabaseContext.h"
50 #include "DOMImplementation.h"
51 #include "DOMWindow.h"
53 #include "DocumentLoadTiming.h"
54 #include "DocumentLoader.h"
56 #include "EditorClient.h"
59 #include "EventNames.h"
60 #include "FloatRect.h"
61 #include "FormState.h"
62 #include "FormSubmission.h"
64 #include "FrameLoadRequest.h"
65 #include "FrameLoaderClient.h"
66 #include "FrameNetworkingContext.h"
67 #include "FrameTree.h"
68 #include "FrameView.h"
69 #include "HTMLAnchorElement.h"
70 #include "HTMLFormElement.h"
71 #include "HTMLNames.h"
72 #include "HTMLObjectElement.h"
73 #include "HTTPParsers.h"
74 #include "HistoryItem.h"
75 #include "InspectorController.h"
76 #include "InspectorInstrumentation.h"
78 #include "MIMETypeRegistry.h"
79 #include "MainResourceLoader.h"
80 #include "MemoryInstrumentation.h"
82 #include "PageCache.h"
83 #include "PageTransitionEvent.h"
84 #include "PluginData.h"
85 #include "PluginDatabase.h"
86 #include "PluginDocument.h"
87 #include "ProgressTracker.h"
88 #include "ResourceHandle.h"
89 #include "ResourceRequest.h"
90 #include "SchemeRegistry.h"
91 #include "ScriptCallStack.h"
92 #include "ScriptCallStackFactory.h"
93 #include "ScriptController.h"
94 #include "ScriptSourceCode.h"
95 #include "ScrollAnimator.h"
96 #include "SecurityOrigin.h"
97 #include "SecurityPolicy.h"
98 #include "SegmentedString.h"
99 #include "SerializedScriptValue.h"
100 #include "Settings.h"
101 #include "TextResourceDecoder.h"
102 #include "WindowFeatures.h"
103 #include "XMLDocumentParser.h"
104 #include <wtf/CurrentTime.h>
105 #include <wtf/StdLibExtras.h>
106 #include <wtf/text/CString.h>
107 #include <wtf/text/WTFString.h>
109 #if ENABLE(SHARED_WORKERS)
110 #include "SharedWorkerRepository.h"
114 #include "SVGDocument.h"
115 #include "SVGLocatable.h"
116 #include "SVGNames.h"
117 #include "SVGPreserveAspectRatio.h"
118 #include "SVGSVGElement.h"
119 #include "SVGViewElement.h"
120 #include "SVGViewSpec.h"
123 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
129 using namespace HTMLNames;
132 using namespace SVGNames;
135 static const char defaultAcceptHeader[] = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
136 static double storedTimeOfLastCompletedLoad;
138 bool isBackForwardLoadType(FrameLoadType type)
141 case FrameLoadTypeStandard:
142 case FrameLoadTypeReload:
143 case FrameLoadTypeReloadFromOrigin:
144 case FrameLoadTypeSame:
145 case FrameLoadTypeRedirectWithLockedBackForwardList:
146 case FrameLoadTypeReplace:
148 case FrameLoadTypeBack:
149 case FrameLoadTypeForward:
150 case FrameLoadTypeIndexedBackForward:
153 ASSERT_NOT_REACHED();
157 // This is not in the FrameLoader class to emphasize that it does not depend on
158 // private FrameLoader data, and to avoid increasing the number of public functions
159 // with access to private data. Since only this .cpp file needs it, making it
160 // non-member lets us exclude it from the header file, thus keeping FrameLoader.h's
163 static bool isDocumentSandboxed(Frame* frame, SandboxFlags mask)
165 return frame->document() && frame->document()->isSandboxed(mask);
168 FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client)
171 , m_policyChecker(frame)
174 , m_subframeLoader(frame)
176 , m_state(FrameStateCommittedPage)
177 , m_loadType(FrameLoadTypeStandard)
178 , m_delegateIsHandlingProvisionalLoadError(false)
179 , m_quickRedirectComing(false)
180 , m_sentRedirectNotification(false)
181 , m_inStopAllLoaders(false)
182 , m_isExecutingJavaScriptFormAction(false)
183 , m_didCallImplicitClose(false)
184 , m_wasUnloadEventEmitted(false)
185 , m_pageDismissalEventBeingDispatched(NoDismissal)
186 , m_isComplete(false)
187 , m_needsClear(false)
188 , m_checkTimer(this, &FrameLoader::checkTimerFired)
189 , m_shouldCallCheckCompleted(false)
190 , m_shouldCallCheckLoadComplete(false)
192 , m_didPerformFirstNavigation(false)
193 , m_loadingFromCachedPage(false)
194 , m_suppressOpenerInNewFrame(false)
195 , m_forcedSandboxFlags(SandboxNone)
199 FrameLoader::~FrameLoader()
203 HashSet<Frame*>::iterator end = m_openedFrames.end();
204 for (HashSet<Frame*>::iterator it = m_openedFrames.begin(); it != end; ++it)
205 (*it)->loader()->m_opener = 0;
207 m_client->frameLoaderDestroyed();
209 if (m_networkingContext)
210 m_networkingContext->invalidate();
213 void FrameLoader::init()
215 // This somewhat odd set of steps gives the frame an initial empty document.
216 // It would be better if this could be done with even fewer steps.
217 m_stateMachine.advanceTo(FrameLoaderStateMachine::CreatingInitialEmptyDocument);
218 setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(KURL(ParsedURLString, emptyString())), SubstituteData()).get());
219 setProvisionalDocumentLoader(m_policyDocumentLoader.get());
220 setState(FrameStateProvisional);
221 m_provisionalDocumentLoader->setResponse(ResourceResponse(KURL(), "text/html", 0, String(), String()));
222 m_provisionalDocumentLoader->finishedLoading();
223 ASSERT(!m_frame->document());
224 m_documentLoader->writer()->begin(KURL(), false);
225 m_documentLoader->writer()->end();
226 m_frame->document()->cancelParsing();
227 m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocument);
228 m_didCallImplicitClose = true;
230 m_networkingContext = m_client->createNetworkingContext();
233 void FrameLoader::setDefersLoading(bool defers)
235 if (m_documentLoader)
236 m_documentLoader->setDefersLoading(defers);
237 if (m_provisionalDocumentLoader)
238 m_provisionalDocumentLoader->setDefersLoading(defers);
239 if (m_policyDocumentLoader)
240 m_policyDocumentLoader->setDefersLoading(defers);
241 history()->setDefersLoading(defers);
244 m_frame->navigationScheduler()->startTimer();
245 startCheckCompleteTimer();
249 void FrameLoader::changeLocation(SecurityOrigin* securityOrigin, const KURL& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool refresh)
251 urlSelected(FrameLoadRequest(securityOrigin, ResourceRequest(url, referrer, refresh ? ReloadIgnoringCacheData : UseProtocolCachePolicy), "_self"),
252 0, lockHistory, lockBackForwardList, MaybeSendReferrer, ReplaceDocumentIfJavaScriptURL);
255 void FrameLoader::urlSelected(const KURL& url, const String& passedTarget, PassRefPtr<Event> triggeringEvent, bool lockHistory, bool lockBackForwardList, ShouldSendReferrer shouldSendReferrer)
257 urlSelected(FrameLoadRequest(m_frame->document()->securityOrigin(), ResourceRequest(url), passedTarget),
258 triggeringEvent, lockHistory, lockBackForwardList, shouldSendReferrer, DoNotReplaceDocumentIfJavaScriptURL);
261 // The shouldReplaceDocumentIfJavaScriptURL parameter will go away when the FIXME to eliminate the
262 // corresponding parameter from ScriptController::executeIfJavaScriptURL() is addressed.
263 void FrameLoader::urlSelected(const FrameLoadRequest& passedRequest, PassRefPtr<Event> triggeringEvent, bool lockHistory, bool lockBackForwardList, ShouldSendReferrer shouldSendReferrer, ShouldReplaceDocumentIfJavaScriptURL shouldReplaceDocumentIfJavaScriptURL)
265 ASSERT(!m_suppressOpenerInNewFrame);
267 RefPtr<Frame> protect(m_frame);
268 FrameLoadRequest frameRequest(passedRequest);
270 if (m_frame->script()->executeIfJavaScriptURL(frameRequest.resourceRequest().url(), shouldReplaceDocumentIfJavaScriptURL))
273 if (frameRequest.frameName().isEmpty())
274 frameRequest.setFrameName(m_frame->document()->baseTarget());
276 if (shouldSendReferrer == NeverSendReferrer)
277 m_suppressOpenerInNewFrame = true;
278 if (frameRequest.resourceRequest().httpReferrer().isEmpty())
279 frameRequest.resourceRequest().setHTTPReferrer(outgoingReferrer());
280 addHTTPOriginIfNeeded(frameRequest.resourceRequest(), outgoingOrigin());
282 loadFrameRequest(frameRequest, lockHistory, lockBackForwardList, triggeringEvent, 0, shouldSendReferrer);
284 m_suppressOpenerInNewFrame = false;
287 void FrameLoader::submitForm(PassRefPtr<FormSubmission> submission)
289 ASSERT(submission->method() == FormSubmission::PostMethod || submission->method() == FormSubmission::GetMethod);
291 // FIXME: Find a good spot for these.
292 ASSERT(submission->data());
293 ASSERT(submission->state());
294 ASSERT(!submission->state()->sourceDocument()->frame() || submission->state()->sourceDocument()->frame() == m_frame);
296 if (!m_frame->page())
299 if (submission->action().isEmpty())
302 if (isDocumentSandboxed(m_frame, SandboxForms))
305 if (protocolIsJavaScript(submission->action())) {
306 if (!m_frame->document()->contentSecurityPolicy()->allowFormAction(KURL(submission->action())))
308 m_isExecutingJavaScriptFormAction = true;
309 m_frame->script()->executeIfJavaScriptURL(submission->action(), DoNotReplaceDocumentIfJavaScriptURL);
310 m_isExecutingJavaScriptFormAction = false;
314 Frame* targetFrame = findFrameForNavigation(submission->target(), submission->state()->sourceDocument());
316 if (!DOMWindow::allowPopUp(m_frame) && !ScriptController::processingUserGesture())
319 targetFrame = m_frame;
321 submission->clearTarget();
323 if (!targetFrame->page())
326 // FIXME: We'd like to remove this altogether and fix the multiple form submission issue another way.
328 // We do not want to submit more than one form from the same page, nor do we want to submit a single
329 // form more than once. This flag prevents these from happening; not sure how other browsers prevent this.
330 // The flag is reset in each time we start handle a new mouse or key down event, and
331 // also in setView since this part may get reused for a page from the back/forward cache.
332 // The form multi-submit logic here is only needed when we are submitting a form that affects this frame.
334 // FIXME: Frame targeting is only one of the ways the submission could end up doing something other
335 // than replacing this frame's content, so this check is flawed. On the other hand, the check is hardly
336 // needed any more now that we reset m_submittedFormURL on each mouse or key down event.
338 if (m_frame->tree()->isDescendantOf(targetFrame)) {
339 if (m_submittedFormURL == submission->requestURL())
341 m_submittedFormURL = submission->requestURL();
344 submission->data()->generateFiles(m_frame->document());
345 submission->setReferrer(outgoingReferrer());
346 submission->setOrigin(outgoingOrigin());
348 targetFrame->navigationScheduler()->scheduleFormSubmission(submission);
351 void FrameLoader::stopLoading(UnloadEventPolicy unloadEventPolicy)
353 if (m_frame->document() && m_frame->document()->parser())
354 m_frame->document()->parser()->stopParsing();
356 if (unloadEventPolicy != UnloadEventPolicyNone) {
357 if (m_frame->document()) {
358 if (m_didCallImplicitClose && !m_wasUnloadEventEmitted) {
359 Node* currentFocusedNode = m_frame->document()->focusedNode();
360 if (currentFocusedNode)
361 currentFocusedNode->aboutToUnload();
362 if (m_pageDismissalEventBeingDispatched == NoDismissal) {
363 if (unloadEventPolicy == UnloadEventPolicyUnloadAndPageHide) {
364 m_pageDismissalEventBeingDispatched = PageHideDismissal;
365 m_frame->document()->domWindow()->dispatchEvent(PageTransitionEvent::create(eventNames().pagehideEvent, m_frame->document()->inPageCache()), m_frame->document());
367 if (!m_frame->document()->inPageCache()) {
368 RefPtr<Event> unloadEvent(Event::create(eventNames().unloadEvent, false, false));
369 // The DocumentLoader (and thus its DocumentLoadTiming) might get destroyed
370 // while dispatching the event, so protect it to prevent writing the end
371 // time into freed memory.
372 RefPtr<DocumentLoader> documentLoader = m_provisionalDocumentLoader;
373 m_pageDismissalEventBeingDispatched = UnloadDismissal;
374 if (documentLoader && !documentLoader->timing()->unloadEventStart() && !documentLoader->timing()->unloadEventEnd()) {
375 DocumentLoadTiming* timing = documentLoader->timing();
376 ASSERT(timing->navigationStart());
377 timing->markUnloadEventStart();
378 m_frame->document()->domWindow()->dispatchEvent(unloadEvent, m_frame->document());
379 timing->markUnloadEventEnd();
381 m_frame->document()->domWindow()->dispatchEvent(unloadEvent, m_frame->document());
384 m_pageDismissalEventBeingDispatched = NoDismissal;
385 if (m_frame->document())
386 m_frame->document()->updateStyleIfNeeded();
387 m_wasUnloadEventEmitted = true;
391 // Dispatching the unload event could have made m_frame->document() null.
392 if (m_frame->document() && !m_frame->document()->inPageCache()) {
393 // Don't remove event listeners from a transitional empty document (see bug 28716 for more information).
394 bool keepEventListeners = m_stateMachine.isDisplayingInitialEmptyDocument() && m_provisionalDocumentLoader
395 && m_frame->document()->isSecureTransitionTo(m_provisionalDocumentLoader->url());
397 if (!keepEventListeners)
398 m_frame->document()->removeAllEventListeners();
402 m_isComplete = true; // to avoid calling completed() in finishedParsing()
403 m_didCallImplicitClose = true; // don't want that one either
405 if (m_frame->document() && m_frame->document()->parsing()) {
407 m_frame->document()->setParsing(false);
410 if (Document* doc = m_frame->document()) {
411 // FIXME: HTML5 doesn't tell us to set the state to complete when aborting, but we do anyway to match legacy behavior.
412 // http://www.w3.org/Bugs/Public/show_bug.cgi?id=10537
413 doc->setReadyState(Document::Complete);
415 #if ENABLE(SQL_DATABASE)
416 // FIXME: Should the DatabaseContext watch for something like ActiveDOMObject::stop() rather than being special-cased here?
417 DatabaseContext::stopDatabases(doc, 0);
421 // FIXME: This will cancel redirection timer, which really needs to be restarted when restoring the frame from b/f cache.
422 m_frame->navigationScheduler()->cancel();
425 void FrameLoader::stop()
427 // http://bugs.webkit.org/show_bug.cgi?id=10854
428 // The frame's last ref may be removed and it will be deleted by checkCompleted().
429 RefPtr<Frame> protector(m_frame);
431 if (DocumentParser* parser = m_frame->document()->parser()) {
432 parser->stopParsing();
436 icon()->stopLoader();
439 bool FrameLoader::closeURL()
441 history()->saveDocumentState();
443 // Should only send the pagehide event here if the current document exists and has not been placed in the page cache.
444 Document* currentDocument = m_frame->document();
445 stopLoading(currentDocument && !currentDocument->inPageCache() ? UnloadEventPolicyUnloadAndPageHide : UnloadEventPolicyUnloadOnly);
447 m_frame->editor()->clearUndoRedoOperations();
451 bool FrameLoader::didOpenURL()
453 if (m_frame->navigationScheduler()->redirectScheduledDuringLoad()) {
454 // A redirect was scheduled before the document was created.
455 // This can happen when one frame changes another frame's location.
459 m_frame->navigationScheduler()->cancel();
460 m_frame->editor()->clearLastEditCommand();
462 m_isComplete = false;
463 m_didCallImplicitClose = false;
465 // If we are still in the process of initializing an empty document then
466 // its frame is not in a consistent state for rendering, so avoid setJSStatusBarText
467 // since it may cause clients to attempt to render the frame.
468 if (!m_stateMachine.creatingInitialEmptyDocument()) {
469 DOMWindow* window = m_frame->document()->domWindow();
470 window->setStatus(String());
471 window->setDefaultStatus(String());
479 void FrameLoader::didExplicitOpen()
481 m_isComplete = false;
482 m_didCallImplicitClose = false;
484 // Calling document.open counts as committing the first real document load.
485 if (!m_stateMachine.committedFirstRealDocumentLoad())
486 m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit);
488 // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
489 // from a subsequent window.document.open / window.document.write call.
490 // Canceling redirection here works for all cases because document.open
491 // implicitly precedes document.write.
492 m_frame->navigationScheduler()->cancel();
496 void FrameLoader::cancelAndClear()
498 m_frame->navigationScheduler()->cancel();
503 clear(m_frame->document(), false);
504 m_frame->script()->updatePlatformScriptObjects();
507 void FrameLoader::clear(Document* newDocument, bool clearWindowProperties, bool clearScriptObjects, bool clearFrameView)
509 m_frame->editor()->clear();
513 m_needsClear = false;
515 if (!m_frame->document()->inPageCache()) {
516 m_frame->document()->cancelParsing();
517 m_frame->document()->stopActiveDOMObjects();
518 if (m_frame->document()->attached()) {
519 m_frame->document()->prepareForDestruction();
520 m_frame->document()->removeFocusedNodeOfSubtree(m_frame->document());
524 // Do this after detaching the document so that the unload event works.
525 if (clearWindowProperties) {
526 InspectorInstrumentation::frameWindowDiscarded(m_frame, m_frame->document()->domWindow());
527 m_frame->document()->domWindow()->resetUnlessSuspendedForPageCache();
528 m_frame->script()->clearWindowShell(newDocument->domWindow(), m_frame->document()->inPageCache());
531 m_frame->selection()->clear();
532 m_frame->eventHandler()->clear();
533 if (clearFrameView && m_frame->view())
534 m_frame->view()->clear();
536 // Do not drop the document before the ScriptController and view are cleared
537 // as some destructors might still try to access the document.
538 m_frame->setDocument(0);
540 m_subframeLoader.clear();
542 if (clearScriptObjects)
543 m_frame->script()->clearScriptObjects();
545 m_frame->script()->enableEval();
547 m_frame->navigationScheduler()->clear();
550 m_shouldCallCheckCompleted = false;
551 m_shouldCallCheckLoadComplete = false;
553 if (m_stateMachine.isDisplayingInitialEmptyDocument() && m_stateMachine.committedFirstRealDocumentLoad())
554 m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
557 void FrameLoader::receivedFirstData()
559 dispatchDidCommitLoad();
560 dispatchDidClearWindowObjectsInAllWorlds();
561 dispatchGlobalObjectAvailableInAllWorlds();
563 if (m_documentLoader) {
564 StringWithDirection ptitle = m_documentLoader->title();
565 // If we have a title let the WebView know about it.
566 if (!ptitle.isNull())
567 m_client->dispatchDidReceiveTitle(ptitle);
570 if (!m_documentLoader)
572 if (m_frame->document()->isViewSource())
577 if (!parseHTTPRefresh(m_documentLoader->response().httpHeaderField("Refresh"), false, delay, url))
580 url = m_frame->document()->url().string();
582 url = m_frame->document()->completeURL(url).string();
584 m_frame->navigationScheduler()->scheduleRedirect(delay, url);
587 void FrameLoader::setOutgoingReferrer(const KURL& url)
589 m_outgoingReferrer = url.strippedForUseAsReferrer();
592 void FrameLoader::didBeginDocument(bool dispatch)
595 m_isComplete = false;
596 m_didCallImplicitClose = false;
597 m_frame->document()->setReadyState(Document::Loading);
599 if (m_pendingStateObject) {
600 m_frame->document()->statePopped(m_pendingStateObject.get());
601 m_pendingStateObject.clear();
605 dispatchDidClearWindowObjectsInAllWorlds();
607 updateFirstPartyForCookies();
608 m_frame->document()->initContentSecurityPolicy();
610 Settings* settings = m_frame->document()->settings();
611 m_frame->document()->cachedResourceLoader()->setAutoLoadImages(settings && settings->loadsImagesAutomatically());
613 if (m_documentLoader) {
614 String dnsPrefetchControl = m_documentLoader->response().httpHeaderField("X-DNS-Prefetch-Control");
615 if (!dnsPrefetchControl.isEmpty())
616 m_frame->document()->parseDNSPrefetchControlHeader(dnsPrefetchControl);
618 String contentSecurityPolicy = m_documentLoader->response().httpHeaderField("X-WebKit-CSP");
619 if (!contentSecurityPolicy.isEmpty())
620 m_frame->document()->contentSecurityPolicy()->didReceiveHeader(contentSecurityPolicy, ContentSecurityPolicy::EnforcePolicy);
622 String reportOnlyContentSecurityPolicy = m_documentLoader->response().httpHeaderField("X-WebKit-CSP-Report-Only");
623 if (!reportOnlyContentSecurityPolicy.isEmpty())
624 m_frame->document()->contentSecurityPolicy()->didReceiveHeader(reportOnlyContentSecurityPolicy, ContentSecurityPolicy::ReportOnly);
627 history()->restoreDocumentState();
630 void FrameLoader::finishedParsing()
632 m_frame->injectUserScripts(InjectAtDocumentEnd);
634 if (m_stateMachine.creatingInitialEmptyDocument())
637 // This can be called from the Frame's destructor, in which case we shouldn't protect ourselves
638 // because doing so will cause us to re-enter the destructor when protector goes out of scope.
639 // Null-checking the FrameView indicates whether or not we're in the destructor.
640 RefPtr<Frame> protector = m_frame->view() ? m_frame : 0;
642 m_client->dispatchDidFinishDocumentLoad();
646 if (!m_frame->view())
647 return; // We are being destroyed by something checkCompleted called.
649 // Check if the scrollbars are really needed for the content.
650 // If not, remove them, relayout, and repaint.
651 m_frame->view()->restoreScrollbar();
652 scrollToFragmentWithParentBoundary(m_frame->document()->url());
655 void FrameLoader::loadDone()
660 bool FrameLoader::allChildrenAreComplete() const
662 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) {
663 if (!child->loader()->m_isComplete)
669 bool FrameLoader::allAncestorsAreComplete() const
671 for (Frame* ancestor = m_frame; ancestor; ancestor = ancestor->tree()->parent()) {
672 if (!ancestor->loader()->m_isComplete)
678 void FrameLoader::checkCompleted()
680 m_shouldCallCheckCompleted = false;
683 m_frame->view()->checkStopDelayingDeferredRepaints();
685 // Have we completed before?
689 // Are we still parsing?
690 if (m_frame->document()->parsing())
693 // Still waiting for images/scripts?
694 if (m_frame->document()->cachedResourceLoader()->requestCount())
697 // Still waiting for elements that don't go through a FrameLoader?
698 if (m_frame->document()->isDelayingLoadEvent())
701 // Any frame that hasn't completed yet?
702 if (!allChildrenAreComplete())
707 m_requestedHistoryItem = 0;
708 m_frame->document()->setReadyState(Document::Complete);
710 RefPtr<Frame> protect(m_frame);
711 checkCallImplicitClose(); // if we didn't do it before
713 m_frame->navigationScheduler()->startTimer();
720 void FrameLoader::checkTimerFired(Timer<FrameLoader>*)
722 RefPtr<Frame> protect(m_frame);
724 if (Page* page = m_frame->page()) {
725 if (page->defersLoading())
728 if (m_shouldCallCheckCompleted)
730 if (m_shouldCallCheckLoadComplete)
734 void FrameLoader::startCheckCompleteTimer()
736 if (!(m_shouldCallCheckCompleted || m_shouldCallCheckLoadComplete))
738 if (m_checkTimer.isActive())
740 m_checkTimer.startOneShot(0);
743 void FrameLoader::scheduleCheckCompleted()
745 m_shouldCallCheckCompleted = true;
746 startCheckCompleteTimer();
749 void FrameLoader::scheduleCheckLoadComplete()
751 m_shouldCallCheckLoadComplete = true;
752 startCheckCompleteTimer();
755 void FrameLoader::checkCallImplicitClose()
757 if (m_didCallImplicitClose || m_frame->document()->parsing() || m_frame->document()->isDelayingLoadEvent())
760 if (!allChildrenAreComplete())
761 return; // still got a frame running -> too early
763 m_didCallImplicitClose = true;
764 m_wasUnloadEventEmitted = false;
765 m_frame->document()->implicitClose();
768 void FrameLoader::loadURLIntoChildFrame(const KURL& url, const String& referer, Frame* childFrame)
772 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
773 RefPtr<Archive> subframeArchive = activeDocumentLoader()->popArchiveForSubframe(childFrame->tree()->uniqueName(), url);
774 if (subframeArchive) {
775 childFrame->loader()->loadArchive(subframeArchive.release());
778 #endif // ENABLE(WEB_ARCHIVE)
780 HistoryItem* parentItem = history()->currentItem();
781 // If we're moving in the back/forward list, we might want to replace the content
782 // of this child frame with whatever was there at that point.
783 if (parentItem && parentItem->children().size() && isBackForwardLoadType(loadType())
784 && !m_frame->document()->loadEventFinished()) {
785 HistoryItem* childItem = parentItem->childItemWithTarget(childFrame->tree()->uniqueName());
787 childFrame->loader()->loadDifferentDocumentItem(childItem, loadType());
792 childFrame->loader()->loadURL(url, referer, "_self", false, FrameLoadTypeRedirectWithLockedBackForwardList, 0, 0);
795 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
796 void FrameLoader::loadArchive(PassRefPtr<Archive> archive)
798 ArchiveResource* mainResource = archive->mainResource();
799 ASSERT(mainResource);
803 SubstituteData substituteData(mainResource->data(), mainResource->mimeType(), mainResource->textEncoding(), KURL());
805 ResourceRequest request(mainResource->url());
807 request.applyWebArchiveHackForMail();
810 RefPtr<DocumentLoader> documentLoader = m_client->createDocumentLoader(request, substituteData);
811 documentLoader->setArchive(archive.get());
812 load(documentLoader.get());
814 #endif // ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
816 ObjectContentType FrameLoader::defaultObjectContentType(const KURL& url, const String& mimeTypeIn, bool shouldPreferPlugInsForImages)
818 String mimeType = mimeTypeIn;
819 String decodedPath = decodeURLEscapeSequences(url.path());
820 String extension = decodedPath.substring(decodedPath.reverseFind('.') + 1);
822 // We don't use MIMETypeRegistry::getMIMETypeForPath() because it returns "application/octet-stream" upon failure
823 if (mimeType.isEmpty())
824 mimeType = MIMETypeRegistry::getMIMETypeForExtension(extension);
826 #if !PLATFORM(MAC) && !PLATFORM(CHROMIUM) && !PLATFORM(EFL) // Mac has no PluginDatabase, nor does Chromium or EFL
827 if (mimeType.isEmpty())
828 mimeType = PluginDatabase::installedPlugins()->MIMETypeForExtension(extension);
831 if (mimeType.isEmpty())
832 return ObjectContentFrame; // Go ahead and hope that we can display the content.
834 #if !PLATFORM(MAC) && !PLATFORM(CHROMIUM) && !PLATFORM(EFL) // Mac has no PluginDatabase, nor does Chromium or EFL
835 bool plugInSupportsMIMEType = PluginDatabase::installedPlugins()->isMIMETypeRegistered(mimeType);
837 bool plugInSupportsMIMEType = false;
840 if (MIMETypeRegistry::isSupportedImageMIMEType(mimeType))
841 return shouldPreferPlugInsForImages && plugInSupportsMIMEType ? WebCore::ObjectContentNetscapePlugin : WebCore::ObjectContentImage;
843 if (plugInSupportsMIMEType)
844 return WebCore::ObjectContentNetscapePlugin;
846 if (MIMETypeRegistry::isSupportedNonImageMIMEType(mimeType))
847 return WebCore::ObjectContentFrame;
849 return WebCore::ObjectContentNone;
852 String FrameLoader::outgoingReferrer() const
854 // See http://www.whatwg.org/specs/web-apps/current-work/#fetching-resources
855 // for why we walk the parent chain for srcdoc documents.
856 Frame* frame = m_frame;
857 while (frame->document()->isSrcdocDocument()) {
858 frame = frame->tree()->parent();
859 // Srcdoc documents cannot be top-level documents, by definition,
860 // because they need to be contained in iframes with the srcdoc.
863 return frame->loader()->m_outgoingReferrer;
866 String FrameLoader::outgoingOrigin() const
868 return m_frame->document()->securityOrigin()->toString();
871 bool FrameLoader::isMixedContent(SecurityOrigin* context, const KURL& url)
873 if (context->protocol() != "https")
874 return false; // We only care about HTTPS security origins.
876 // We're in a secure context, so |url| is mixed content if it's insecure.
877 return !SecurityOrigin::isSecure(url);
880 bool FrameLoader::checkIfDisplayInsecureContent(SecurityOrigin* context, const KURL& url)
882 if (!isMixedContent(context, url))
885 Settings* settings = m_frame->settings();
886 bool allowed = m_client->allowDisplayingInsecureContent(settings && settings->allowDisplayOfInsecureContent(), context, url);
887 String message = (allowed ? emptyString() : "[blocked] ") + "The page at " +
888 m_frame->document()->url().string() + " displayed insecure content from " + url.string() + ".\n";
890 m_frame->document()->domWindow()->console()->addMessage(HTMLMessageSource, LogMessageType, WarningMessageLevel, message);
893 m_client->didDisplayInsecureContent();
898 bool FrameLoader::checkIfRunInsecureContent(SecurityOrigin* context, const KURL& url)
900 if (!isMixedContent(context, url))
903 Settings* settings = m_frame->settings();
904 bool allowed = m_client->allowRunningInsecureContent(settings && settings->allowRunningOfInsecureContent(), context, url);
905 String message = (allowed ? emptyString() : "[blocked] ") + "The page at " +
906 m_frame->document()->url().string() + " ran insecure content from " + url.string() + ".\n";
908 m_frame->document()->domWindow()->console()->addMessage(HTMLMessageSource, LogMessageType, WarningMessageLevel, message);
911 m_client->didRunInsecureContent(context, url);
916 bool FrameLoader::checkIfFormActionAllowedByCSP(const KURL& url) const
918 if (m_submittedFormURL.isEmpty())
921 return m_frame->document()->contentSecurityPolicy()->allowFormAction(url);
924 Frame* FrameLoader::opener()
929 void FrameLoader::setOpener(Frame* opener)
932 m_opener->loader()->m_openedFrames.remove(m_frame);
934 opener->loader()->m_openedFrames.add(m_frame);
937 if (m_frame->document())
938 m_frame->document()->initSecurityContext();
941 // FIXME: This does not belong in FrameLoader!
942 void FrameLoader::handleFallbackContent()
944 HTMLFrameOwnerElement* owner = m_frame->ownerElement();
945 if (!owner || !owner->hasTagName(objectTag))
947 static_cast<HTMLObjectElement*>(owner)->renderFallbackContent();
950 void FrameLoader::provisionalLoadStarted()
952 if (m_stateMachine.firstLayoutDone())
953 m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
954 m_frame->navigationScheduler()->cancel(true);
955 m_client->provisionalLoadStarted();
958 void FrameLoader::resetMultipleFormSubmissionProtection()
960 m_submittedFormURL = KURL();
963 void FrameLoader::updateFirstPartyForCookies()
965 if (m_frame->tree()->parent())
966 setFirstPartyForCookies(m_frame->tree()->parent()->document()->firstPartyForCookies());
968 setFirstPartyForCookies(m_frame->document()->url());
971 void FrameLoader::setFirstPartyForCookies(const KURL& url)
973 for (Frame* frame = m_frame; frame; frame = frame->tree()->traverseNext(m_frame))
974 frame->document()->setFirstPartyForCookies(url);
977 // This does the same kind of work that didOpenURL does, except it relies on the fact
978 // that a higher level already checked that the URLs match and the scrolling is the right thing to do.
979 void FrameLoader::loadInSameDocument(const KURL& url, SerializedScriptValue* stateObject, bool isNewNavigation)
981 // If we have a state object, we cannot also be a new navigation.
982 ASSERT(!stateObject || (stateObject && !isNewNavigation));
984 // Update the data source's request with the new URL to fake the URL change
985 KURL oldURL = m_frame->document()->url();
986 m_frame->document()->setURL(url);
987 setOutgoingReferrer(url);
988 documentLoader()->replaceRequestURLForSameDocumentNavigation(url);
989 if (isNewNavigation && !shouldTreatURLAsSameAsCurrent(url) && !stateObject) {
990 // NB: must happen after replaceRequestURLForSameDocumentNavigation(), since we add
991 // based on the current request. Must also happen before we openURL and displace the
992 // scroll position, since adding the BF item will save away scroll state.
994 // NB2: If we were loading a long, slow doc, and the user fragment navigated before
995 // it was done, currItem is now set the that slow doc, and prevItem is whatever was
996 // before it. Adding the b/f item will bump the slow doc down to prevItem, even
997 // though its load is not yet done. I think this all works out OK, for one because
998 // we have already saved away the scroll and doc state for the long slow load,
999 // but it's not an obvious case.
1001 history()->updateBackForwardListForFragmentScroll();
1004 bool hashChange = equalIgnoringFragmentIdentifier(url, oldURL) && url.fragmentIdentifier() != oldURL.fragmentIdentifier();
1006 history()->updateForSameDocumentNavigation();
1008 // If we were in the autoscroll/panScroll mode we want to stop it before following the link to the anchor
1010 m_frame->eventHandler()->stopAutoscrollTimer();
1012 // It's important to model this as a load that starts and immediately finishes.
1013 // Otherwise, the parent frame may think we never finished loading.
1016 // We need to scroll to the fragment whether or not a hash change occurred, since
1017 // the user might have scrolled since the previous navigation.
1018 scrollToFragmentWithParentBoundary(url);
1020 m_isComplete = false;
1023 if (isNewNavigation) {
1024 // This will clear previousItem from the rest of the frame tree that didn't
1025 // doing any loading. We need to make a pass on this now, since for fragment
1026 // navigation we'll not go through a real load and reach Completed state.
1027 checkLoadComplete();
1030 m_client->dispatchDidNavigateWithinPage();
1032 m_frame->document()->statePopped(stateObject ? stateObject : SerializedScriptValue::nullValue());
1033 m_client->dispatchDidPopStateWithinPage();
1036 m_frame->document()->enqueueHashchangeEvent(oldURL, url);
1037 m_client->dispatchDidChangeLocationWithinPage();
1040 // FrameLoaderClient::didFinishLoad() tells the internal load delegate the load finished with no error
1041 m_client->didFinishLoad();
1044 bool FrameLoader::isComplete() const
1046 return m_isComplete;
1049 void FrameLoader::completed()
1051 RefPtr<Frame> protect(m_frame);
1053 for (Frame* descendant = m_frame->tree()->traverseNext(m_frame); descendant; descendant = descendant->tree()->traverseNext(m_frame))
1054 descendant->navigationScheduler()->startTimer();
1056 if (Frame* parent = m_frame->tree()->parent())
1057 parent->loader()->checkCompleted();
1059 if (m_frame->view())
1060 m_frame->view()->maintainScrollPositionAtAnchor(0);
1063 void FrameLoader::started()
1065 for (Frame* frame = m_frame; frame; frame = frame->tree()->parent())
1066 frame->loader()->m_isComplete = false;
1069 void FrameLoader::prepareForHistoryNavigation()
1071 // If there is no currentItem, but we still want to engage in
1072 // history navigation we need to manufacture one, and update
1073 // the state machine of this frame to impersonate having
1075 RefPtr<HistoryItem> currentItem = history()->currentItem();
1077 currentItem = HistoryItem::create();
1078 currentItem->setLastVisitWasFailure(true);
1079 history()->setCurrentItem(currentItem.get());
1080 frame()->page()->backForward()->setCurrentItem(currentItem.get());
1082 ASSERT(stateMachine()->isDisplayingInitialEmptyDocument());
1083 stateMachine()->advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit);
1084 stateMachine()->advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
1088 void FrameLoader::prepareForLoadStart()
1090 if (Page* page = m_frame->page())
1091 page->progress()->progressStarted(m_frame);
1092 m_client->dispatchDidStartProvisionalLoad();
1094 // Notify accessibility.
1095 if (AXObjectCache::accessibilityEnabled()) {
1096 AXObjectCache::AXLoadingEvent loadingEvent = loadType() == FrameLoadTypeReload ? AXObjectCache::AXLoadingReloaded : AXObjectCache::AXLoadingStarted;
1097 m_frame->document()->axObjectCache()->frameLoadingEventNotification(m_frame, loadingEvent);
1101 void FrameLoader::setupForReplace()
1103 setState(FrameStateProvisional);
1104 m_provisionalDocumentLoader = m_documentLoader;
1105 m_documentLoader = 0;
1109 void FrameLoader::loadFrameRequest(const FrameLoadRequest& request, bool lockHistory, bool lockBackForwardList,
1110 PassRefPtr<Event> event, PassRefPtr<FormState> formState, ShouldSendReferrer shouldSendReferrer)
1112 // Protect frame from getting blown away inside dispatchBeforeLoadEvent in loadWithDocumentLoader.
1113 RefPtr<Frame> protect(m_frame);
1115 KURL url = request.resourceRequest().url();
1117 ASSERT(m_frame->document());
1118 if (!request.requester()->canDisplay(url)) {
1119 reportLocalLoadFailed(m_frame, url.string());
1123 String argsReferrer = request.resourceRequest().httpReferrer();
1124 if (argsReferrer.isEmpty())
1125 argsReferrer = outgoingReferrer();
1127 String referrer = SecurityPolicy::generateReferrerHeader(m_frame->document()->referrerPolicy(), url, argsReferrer);
1128 if (shouldSendReferrer == NeverSendReferrer)
1129 referrer = String();
1131 FrameLoadType loadType;
1132 if (request.resourceRequest().cachePolicy() == ReloadIgnoringCacheData)
1133 loadType = FrameLoadTypeReload;
1134 else if (lockBackForwardList)
1135 loadType = FrameLoadTypeRedirectWithLockedBackForwardList;
1137 loadType = FrameLoadTypeStandard;
1139 if (request.resourceRequest().httpMethod() == "POST")
1140 loadPostRequest(request.resourceRequest(), referrer, request.frameName(), lockHistory, loadType, event, formState.get());
1142 loadURL(request.resourceRequest().url(), referrer, request.frameName(), lockHistory, loadType, event, formState.get());
1144 // FIXME: It's possible this targetFrame will not be the same frame that was targeted by the actual
1145 // load if frame names have changed.
1146 Frame* sourceFrame = formState ? formState->sourceDocument()->frame() : m_frame;
1148 sourceFrame = m_frame;
1149 Frame* targetFrame = sourceFrame->loader()->findFrameForNavigation(request.frameName());
1150 if (targetFrame && targetFrame != sourceFrame) {
1151 if (Page* page = targetFrame->page())
1152 page->chrome()->focus();
1156 void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType newLoadType,
1157 PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState)
1159 if (m_inStopAllLoaders)
1162 RefPtr<FormState> formState = prpFormState;
1163 bool isFormSubmission = formState;
1165 ResourceRequest request(newURL);
1166 if (!referrer.isEmpty()) {
1167 request.setHTTPReferrer(referrer);
1168 RefPtr<SecurityOrigin> referrerOrigin = SecurityOrigin::createFromString(referrer);
1169 addHTTPOriginIfNeeded(request, referrerOrigin->toString());
1171 addExtraFieldsToRequest(request, newLoadType, true);
1172 if (newLoadType == FrameLoadTypeReload || newLoadType == FrameLoadTypeReloadFromOrigin)
1173 request.setCachePolicy(ReloadIgnoringCacheData);
1175 ASSERT(newLoadType != FrameLoadTypeSame);
1177 // The search for a target frame is done earlier in the case of form submission.
1178 Frame* targetFrame = isFormSubmission ? 0 : findFrameForNavigation(frameName);
1179 if (targetFrame && targetFrame != m_frame) {
1180 targetFrame->loader()->loadURL(newURL, referrer, "_self", lockHistory, newLoadType, event, formState.release());
1184 if (m_pageDismissalEventBeingDispatched != NoDismissal)
1187 NavigationAction action(request, newLoadType, isFormSubmission, event);
1189 if (!targetFrame && !frameName.isEmpty()) {
1190 policyChecker()->checkNewWindowPolicy(action, FrameLoader::callContinueLoadAfterNewWindowPolicy,
1191 request, formState.release(), frameName, this);
1195 RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader;
1197 bool sameURL = shouldTreatURLAsSameAsCurrent(newURL);
1198 const String& httpMethod = request.httpMethod();
1200 // Make sure to do scroll to fragment processing even if the URL is
1201 // exactly the same so pages with '#' links and DHTML side effects
1203 if (shouldPerformFragmentNavigation(isFormSubmission, httpMethod, newLoadType, newURL)) {
1204 oldDocumentLoader->setTriggeringAction(action);
1205 policyChecker()->stopCheck();
1206 policyChecker()->setLoadType(newLoadType);
1207 policyChecker()->checkNavigationPolicy(request, oldDocumentLoader.get(), formState.release(),
1208 callContinueFragmentScrollAfterNavigationPolicy, this);
1210 // must grab this now, since this load may stop the previous load and clear this flag
1211 bool isRedirect = m_quickRedirectComing;
1212 loadWithNavigationAction(request, action, lockHistory, newLoadType, formState.release());
1214 m_quickRedirectComing = false;
1215 if (m_provisionalDocumentLoader)
1216 m_provisionalDocumentLoader->setIsClientRedirect(true);
1217 } else if (sameURL && newLoadType != FrameLoadTypeReload && newLoadType != FrameLoadTypeReloadFromOrigin)
1218 // Example of this case are sites that reload the same URL with a different cookie
1219 // driving the generated content, or a master frame with links that drive a target
1220 // frame, where the user has clicked on the same link repeatedly.
1221 m_loadType = FrameLoadTypeSame;
1225 SubstituteData FrameLoader::defaultSubstituteDataForURL(const KURL& url)
1227 if (!shouldTreatURLAsSrcdocDocument(url))
1228 return SubstituteData();
1229 String srcdoc = m_frame->ownerElement()->fastGetAttribute(srcdocAttr);
1230 ASSERT(!srcdoc.isNull());
1231 CString encodedSrcdoc = srcdoc.utf8();
1232 return SubstituteData(SharedBuffer::create(encodedSrcdoc.data(), encodedSrcdoc.length()), "text/html", "UTF-8", KURL());
1235 void FrameLoader::load(const ResourceRequest& request, bool lockHistory)
1237 load(request, defaultSubstituteDataForURL(request.url()), lockHistory);
1240 void FrameLoader::load(const ResourceRequest& request, const SubstituteData& substituteData, bool lockHistory)
1242 if (m_inStopAllLoaders)
1245 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, substituteData);
1246 if (lockHistory && m_documentLoader)
1247 loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory().string() : m_documentLoader->clientRedirectSourceForHistory());
1251 void FrameLoader::load(const ResourceRequest& request, const String& frameName, bool lockHistory)
1253 if (frameName.isEmpty()) {
1254 load(request, lockHistory);
1258 Frame* frame = findFrameForNavigation(frameName);
1260 frame->loader()->load(request, lockHistory);
1264 policyChecker()->checkNewWindowPolicy(NavigationAction(request, NavigationTypeOther), FrameLoader::callContinueLoadAfterNewWindowPolicy, request, 0, frameName, this);
1267 void FrameLoader::loadWithNavigationAction(const ResourceRequest& request, const NavigationAction& action, bool lockHistory, FrameLoadType type, PassRefPtr<FormState> formState)
1269 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, defaultSubstituteDataForURL(request.url()));
1270 if (lockHistory && m_documentLoader)
1271 loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory().string() : m_documentLoader->clientRedirectSourceForHistory());
1273 loader->setTriggeringAction(action);
1274 if (m_documentLoader)
1275 loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
1277 loadWithDocumentLoader(loader.get(), type, formState);
1280 void FrameLoader::load(DocumentLoader* newDocumentLoader)
1282 ResourceRequest& r = newDocumentLoader->request();
1283 addExtraFieldsToMainResourceRequest(r);
1286 if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->originalRequest().url())) {
1287 r.setCachePolicy(ReloadIgnoringCacheData);
1288 type = FrameLoadTypeSame;
1289 } else if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->unreachableURL()) && m_loadType == FrameLoadTypeReload)
1290 type = FrameLoadTypeReload;
1292 type = FrameLoadTypeStandard;
1294 if (m_documentLoader)
1295 newDocumentLoader->setOverrideEncoding(m_documentLoader->overrideEncoding());
1297 // When we loading alternate content for an unreachable URL that we're
1298 // visiting in the history list, we treat it as a reload so the history list
1299 // is appropriately maintained.
1301 // FIXME: This seems like a dangerous overloading of the meaning of "FrameLoadTypeReload" ...
1302 // shouldn't a more explicit type of reload be defined, that means roughly
1303 // "load without affecting history" ?
1304 if (shouldReloadToHandleUnreachableURL(newDocumentLoader)) {
1305 // shouldReloadToHandleUnreachableURL() returns true only when the original load type is back-forward.
1306 // In this case we should save the document state now. Otherwise the state can be lost because load type is
1307 // changed and updateForBackForwardNavigation() will not be called when loading is committed.
1308 history()->saveDocumentAndScrollState();
1310 ASSERT(type == FrameLoadTypeStandard);
1311 type = FrameLoadTypeReload;
1314 loadWithDocumentLoader(newDocumentLoader, type, 0);
1317 void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType type, PassRefPtr<FormState> prpFormState)
1319 // Retain because dispatchBeforeLoadEvent may release the last reference to it.
1320 RefPtr<Frame> protect(m_frame);
1322 ASSERT(m_client->hasWebView());
1324 // Unfortunately the view must be non-nil, this is ultimately due
1325 // to parser requiring a FrameView. We should fix this dependency.
1327 ASSERT(m_frame->view());
1329 if (m_pageDismissalEventBeingDispatched != NoDismissal)
1332 if (m_frame->document())
1333 m_previousUrl = m_frame->document()->url();
1335 policyChecker()->setLoadType(type);
1336 RefPtr<FormState> formState = prpFormState;
1337 bool isFormSubmission = formState;
1339 const KURL& newURL = loader->request().url();
1340 const String& httpMethod = loader->request().httpMethod();
1342 if (shouldPerformFragmentNavigation(isFormSubmission, httpMethod, policyChecker()->loadType(), newURL)) {
1343 RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader;
1344 NavigationAction action(loader->request(), policyChecker()->loadType(), isFormSubmission);
1346 oldDocumentLoader->setTriggeringAction(action);
1347 policyChecker()->stopCheck();
1348 policyChecker()->checkNavigationPolicy(loader->request(), oldDocumentLoader.get(), formState,
1349 callContinueFragmentScrollAfterNavigationPolicy, this);
1351 if (Frame* parent = m_frame->tree()->parent())
1352 loader->setOverrideEncoding(parent->loader()->documentLoader()->overrideEncoding());
1354 policyChecker()->stopCheck();
1355 setPolicyDocumentLoader(loader);
1356 if (loader->triggeringAction().isEmpty())
1357 loader->setTriggeringAction(NavigationAction(loader->request(), policyChecker()->loadType(), isFormSubmission));
1359 if (Element* ownerElement = m_frame->ownerElement()) {
1360 // We skip dispatching the beforeload event if we've already
1361 // committed a real document load because the event would leak
1362 // subsequent activity by the frame which the parent frame isn't
1363 // supposed to learn. For example, if the child frame navigated to
1364 // a new URL, the parent frame shouldn't learn the URL.
1365 if (!m_stateMachine.committedFirstRealDocumentLoad()
1366 && !ownerElement->dispatchBeforeLoadEvent(loader->request().url().string())) {
1367 continueLoadAfterNavigationPolicy(loader->request(), formState, false);
1372 policyChecker()->checkNavigationPolicy(loader->request(), loader, formState,
1373 callContinueLoadAfterNavigationPolicy, this);
1377 void FrameLoader::reportLocalLoadFailed(Frame* frame, const String& url)
1379 ASSERT(!url.isEmpty());
1383 frame->document()->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Not allowed to load local resource: " + url);
1386 const ResourceRequest& FrameLoader::initialRequest() const
1388 return activeDocumentLoader()->originalRequest();
1391 bool FrameLoader::willLoadMediaElementURL(KURL& url)
1393 ResourceRequest request(url);
1395 unsigned long identifier;
1396 ResourceError error;
1397 requestFromDelegate(request, identifier, error);
1398 notifier()->sendRemainingDelegateMessages(m_documentLoader.get(), identifier, ResourceResponse(url, String(), -1, String(), String()), 0, -1, -1, error);
1400 url = request.url();
1402 return error.isNull();
1405 bool FrameLoader::shouldReloadToHandleUnreachableURL(DocumentLoader* docLoader)
1407 KURL unreachableURL = docLoader->unreachableURL();
1409 if (unreachableURL.isEmpty())
1412 if (!isBackForwardLoadType(policyChecker()->loadType()))
1415 // We only treat unreachableURLs specially during the delegate callbacks
1416 // for provisional load errors and navigation policy decisions. The former
1417 // case handles well-formed URLs that can't be loaded, and the latter
1418 // case handles malformed URLs and unknown schemes. Loading alternate content
1419 // at other times behaves like a standard load.
1420 DocumentLoader* compareDocumentLoader = 0;
1421 if (policyChecker()->delegateIsDecidingNavigationPolicy() || policyChecker()->delegateIsHandlingUnimplementablePolicy())
1422 compareDocumentLoader = m_policyDocumentLoader.get();
1423 else if (m_delegateIsHandlingProvisionalLoadError)
1424 compareDocumentLoader = m_provisionalDocumentLoader.get();
1426 return compareDocumentLoader && unreachableURL == compareDocumentLoader->request().url();
1429 void FrameLoader::reloadWithOverrideEncoding(const String& encoding)
1431 if (!m_documentLoader)
1434 ResourceRequest request = m_documentLoader->request();
1435 KURL unreachableURL = m_documentLoader->unreachableURL();
1436 if (!unreachableURL.isEmpty())
1437 request.setURL(unreachableURL);
1439 request.setCachePolicy(ReturnCacheDataElseLoad);
1441 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, defaultSubstituteDataForURL(request.url()));
1442 setPolicyDocumentLoader(loader.get());
1444 loader->setOverrideEncoding(encoding);
1446 loadWithDocumentLoader(loader.get(), FrameLoadTypeReload, 0);
1449 void FrameLoader::reloadWithOverrideURL(const KURL& overrideUrl, bool endToEndReload)
1451 if (!m_documentLoader)
1454 if (overrideUrl.isEmpty())
1457 ResourceRequest request = m_documentLoader->request();
1458 request.setURL(overrideUrl);
1459 reloadWithRequest(request, endToEndReload);
1462 void FrameLoader::reload(bool endToEndReload)
1464 if (!m_documentLoader)
1467 // If a window is created by javascript, its main frame can have an empty but non-nil URL.
1468 // Reloading in this case will lose the current contents (see 4151001).
1469 if (m_documentLoader->request().url().isEmpty())
1472 // Replace error-page URL with the URL we were trying to reach.
1473 ResourceRequest initialRequest = m_documentLoader->request();
1474 KURL unreachableURL = m_documentLoader->unreachableURL();
1475 if (!unreachableURL.isEmpty())
1476 initialRequest.setURL(unreachableURL);
1478 reloadWithRequest(initialRequest, endToEndReload);
1481 void FrameLoader::reloadWithRequest(const ResourceRequest& initialRequest, bool endToEndReload)
1483 ASSERT(m_documentLoader);
1485 // Create a new document loader for the reload, this will become m_documentLoader eventually,
1486 // but first it has to be the "policy" document loader, and then the "provisional" document loader.
1487 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(initialRequest, defaultSubstituteDataForURL(initialRequest.url()));
1489 ResourceRequest& request = loader->request();
1491 // FIXME: We don't have a mechanism to revalidate the main resource without reloading at the moment.
1492 request.setCachePolicy(ReloadIgnoringCacheData);
1494 // If we're about to re-post, set up action so the application can warn the user.
1495 if (request.httpMethod() == "POST")
1496 loader->setTriggeringAction(NavigationAction(request, NavigationTypeFormResubmitted));
1498 loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
1500 loadWithDocumentLoader(loader.get(), endToEndReload ? FrameLoadTypeReloadFromOrigin : FrameLoadTypeReload, 0);
1503 void FrameLoader::stopAllLoaders(ClearProvisionalItemPolicy clearProvisionalItemPolicy)
1505 ASSERT(!m_frame->document() || !m_frame->document()->inPageCache());
1506 if (m_pageDismissalEventBeingDispatched != NoDismissal)
1509 // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
1510 if (m_inStopAllLoaders)
1513 // Calling stopLoading() on the provisional document loader can blow away
1514 // the frame from underneath.
1515 RefPtr<Frame> protect(m_frame);
1517 m_inStopAllLoaders = true;
1519 policyChecker()->stopCheck();
1521 // If no new load is in progress, we should clear the provisional item from history
1522 // before we call stopLoading.
1523 if (clearProvisionalItemPolicy == ShouldClearProvisionalItem)
1524 history()->setProvisionalItem(0);
1526 for (RefPtr<Frame> child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1527 child->loader()->stopAllLoaders(clearProvisionalItemPolicy);
1528 if (m_provisionalDocumentLoader)
1529 m_provisionalDocumentLoader->stopLoading();
1530 if (m_documentLoader)
1531 m_documentLoader->stopLoading();
1533 setProvisionalDocumentLoader(0);
1535 m_checkTimer.stop();
1537 m_inStopAllLoaders = false;
1540 void FrameLoader::stopForUserCancel(bool deferCheckLoadComplete)
1544 if (deferCheckLoadComplete)
1545 scheduleCheckLoadComplete();
1546 else if (m_frame->page())
1547 checkLoadComplete();
1550 DocumentLoader* FrameLoader::activeDocumentLoader() const
1552 if (m_state == FrameStateProvisional)
1553 return m_provisionalDocumentLoader.get();
1554 return m_documentLoader.get();
1557 bool FrameLoader::isLoading() const
1559 DocumentLoader* docLoader = activeDocumentLoader();
1562 return docLoader->isLoading();
1565 bool FrameLoader::frameHasLoaded() const
1567 return m_stateMachine.committedFirstRealDocumentLoad() || (m_provisionalDocumentLoader && !m_stateMachine.creatingInitialEmptyDocument());
1570 void FrameLoader::setDocumentLoader(DocumentLoader* loader)
1572 if (!loader && !m_documentLoader)
1575 ASSERT(loader != m_documentLoader);
1576 ASSERT(!loader || loader->frameLoader() == this);
1578 m_client->prepareForDataSourceReplacement();
1580 if (m_documentLoader)
1581 m_documentLoader->detachFromFrame();
1583 m_documentLoader = loader;
1585 // The following abomination is brought to you by the unload event.
1586 // The detachChildren() call above may trigger a child frame's unload event,
1587 // which could do something obnoxious like call document.write("") on
1588 // the main frame, which results in detaching children while detaching children.
1589 // This can cause the new m_documentLoader to be detached from its Frame*, but still
1590 // be alive. To make matters worse, DocumentLoaders with a null Frame* aren't supposed
1591 // to happen when they're still alive (and many places below us on the stack think the
1592 // DocumentLoader is still usable). Ergo, we reattach loader to its Frame, and pretend
1593 // like nothing ever happened.
1594 if (m_documentLoader && !m_documentLoader->frame()) {
1595 ASSERT(!m_documentLoader->isLoading());
1596 m_documentLoader->setFrame(m_frame);
1600 void FrameLoader::setPolicyDocumentLoader(DocumentLoader* loader)
1602 if (m_policyDocumentLoader == loader)
1607 loader->setFrame(m_frame);
1608 if (m_policyDocumentLoader
1609 && m_policyDocumentLoader != m_provisionalDocumentLoader
1610 && m_policyDocumentLoader != m_documentLoader)
1611 m_policyDocumentLoader->detachFromFrame();
1613 m_policyDocumentLoader = loader;
1616 void FrameLoader::setProvisionalDocumentLoader(DocumentLoader* loader)
1618 ASSERT(!loader || !m_provisionalDocumentLoader);
1619 ASSERT(!loader || loader->frameLoader() == this);
1621 if (m_provisionalDocumentLoader && m_provisionalDocumentLoader != m_documentLoader)
1622 m_provisionalDocumentLoader->detachFromFrame();
1624 m_provisionalDocumentLoader = loader;
1627 double FrameLoader::timeOfLastCompletedLoad()
1629 return storedTimeOfLastCompletedLoad;
1632 void FrameLoader::setState(FrameState newState)
1636 if (newState == FrameStateProvisional)
1637 provisionalLoadStarted();
1638 else if (newState == FrameStateComplete) {
1639 frameLoadCompleted();
1640 storedTimeOfLastCompletedLoad = currentTime();
1641 if (m_documentLoader)
1642 m_documentLoader->stopRecordingResponses();
1646 void FrameLoader::clearProvisionalLoad()
1648 setProvisionalDocumentLoader(0);
1649 if (Page* page = m_frame->page())
1650 page->progress()->progressCompleted(m_frame);
1651 setState(FrameStateComplete);
1654 void FrameLoader::commitProvisionalLoad()
1656 RefPtr<CachedPage> cachedPage = m_loadingFromCachedPage ? pageCache()->get(history()->provisionalItem()) : 0;
1657 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
1659 LOG(PageCache, "WebCoreLoading %s: About to commit provisional load from previous URL '%s' to new URL '%s'", m_frame->tree()->uniqueName().string().utf8().data(),
1660 m_frame->document() ? m_frame->document()->url().string().utf8().data() : "",
1661 pdl ? pdl->url().string().utf8().data() : "<no provisional DocumentLoader>");
1663 // Check to see if we need to cache the page we are navigating away from into the back/forward cache.
1664 // We are doing this here because we know for sure that a new page is about to be loaded.
1665 HistoryItem* item = history()->currentItem();
1666 if (!m_frame->tree()->parent() && pageCache()->canCache(m_frame->page()) && !item->isInPageCache())
1667 pageCache()->add(item, m_frame->page());
1669 if (m_loadType != FrameLoadTypeReplace)
1670 closeOldDataSources();
1672 if (!cachedPage && !m_stateMachine.creatingInitialEmptyDocument())
1673 m_client->makeRepresentation(pdl.get());
1675 transitionToCommitted(cachedPage);
1678 // Check if the destination page is allowed to access the previous page's timing information.
1679 RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(pdl->request().url());
1680 m_documentLoader->timing()->setHasSameOriginAsPreviousDocument(securityOrigin->canRequest(m_previousUrl));
1683 // Call clientRedirectCancelledOrFinished() here so that the frame load delegate is notified that the redirect's
1684 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
1685 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are
1686 // just about to commit a new page, there cannot possibly be a pending redirect at this point.
1687 if (m_sentRedirectNotification)
1688 clientRedirectCancelledOrFinished(false);
1690 if (cachedPage && cachedPage->document()) {
1691 prepareForCachedPageRestore();
1692 cachedPage->restore(m_frame->page());
1694 dispatchDidCommitLoad();
1696 // If we have a title let the WebView know about it.
1697 StringWithDirection title = m_documentLoader->title();
1698 if (!title.isNull())
1699 m_client->dispatchDidReceiveTitle(title);
1705 LOG(Loading, "WebCoreLoading %s: Finished committing provisional load to URL %s", m_frame->tree()->uniqueName().string().utf8().data(),
1706 m_frame->document() ? m_frame->document()->url().string().utf8().data() : "");
1708 if (m_loadType == FrameLoadTypeStandard && m_documentLoader->isClientRedirect())
1709 history()->updateForClientRedirect();
1711 if (m_loadingFromCachedPage) {
1712 m_frame->document()->documentDidResumeFromPageCache();
1714 // Force a layout to update view size and thereby update scrollbars.
1715 m_frame->view()->forceLayout();
1717 const ResponseVector& responses = m_documentLoader->responses();
1718 size_t count = responses.size();
1719 for (size_t i = 0; i < count; i++) {
1720 const ResourceResponse& response = responses[i];
1721 // FIXME: If the WebKit client changes or cancels the request, this is not respected.
1722 ResourceError error;
1723 unsigned long identifier;
1724 ResourceRequest request(response.url());
1725 requestFromDelegate(request, identifier, error);
1726 // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
1727 // However, with today's computers and networking speeds, this won't happen in practice.
1728 // Could be an issue with a giant local file.
1729 notifier()->sendRemainingDelegateMessages(m_documentLoader.get(), identifier, response, 0, static_cast<int>(response.expectedContentLength()), 0, error);
1732 pageCache()->remove(history()->currentItem());
1734 // FIXME: Why only this frame and not parent frames?
1735 checkLoadCompleteForThisFrame();
1739 void FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage)
1741 ASSERT(m_client->hasWebView());
1742 ASSERT(m_state == FrameStateProvisional);
1744 if (m_state != FrameStateProvisional)
1747 if (FrameView* view = m_frame->view()) {
1748 if (ScrollAnimator* scrollAnimator = view->existingScrollAnimator())
1749 scrollAnimator->cancelAnimations();
1752 m_client->setCopiesOnScroll();
1753 history()->updateForCommit();
1755 // The call to closeURL() invokes the unload event handler, which can execute arbitrary
1756 // JavaScript. If the script initiates a new load, we need to abandon the current load,
1757 // or the two will stomp each other.
1758 DocumentLoader* pdl = m_provisionalDocumentLoader.get();
1759 if (m_documentLoader)
1761 if (pdl != m_provisionalDocumentLoader)
1764 // Nothing else can interupt this commit - set the Provisional->Committed transition in stone
1765 if (m_documentLoader)
1766 m_documentLoader->stopLoadingSubresources();
1767 if (m_documentLoader)
1768 m_documentLoader->stopLoadingPlugIns();
1770 setDocumentLoader(m_provisionalDocumentLoader.get());
1771 setProvisionalDocumentLoader(0);
1772 setState(FrameStateCommittedPage);
1774 #if ENABLE(TOUCH_EVENTS)
1775 if (isLoadingMainFrame())
1776 m_frame->page()->chrome()->client()->needTouchEvents(false);
1779 // Handle adding the URL to the back/forward list.
1780 DocumentLoader* dl = m_documentLoader.get();
1782 switch (m_loadType) {
1783 case FrameLoadTypeForward:
1784 case FrameLoadTypeBack:
1785 case FrameLoadTypeIndexedBackForward:
1786 if (m_frame->page()) {
1787 // If the first load within a frame is a navigation within a back/forward list that was attached
1788 // without any of the items being loaded then we need to update the history in a similar manner as
1789 // for a standard load with the exception of updating the back/forward list (<rdar://problem/8091103>).
1790 if (!m_stateMachine.committedFirstRealDocumentLoad() && isLoadingMainFrame())
1791 history()->updateForStandardLoad(HistoryController::UpdateAllExceptBackForwardList);
1793 history()->updateForBackForwardNavigation();
1795 // For cached pages, CachedFrame::restore will take care of firing the popstate event with the history item's state object
1796 if (history()->currentItem() && !cachedPage)
1797 m_pendingStateObject = history()->currentItem()->stateObject();
1799 // Create a document view for this document, or used the cached view.
1801 DocumentLoader* cachedDocumentLoader = cachedPage->documentLoader();
1802 ASSERT(cachedDocumentLoader);
1803 cachedDocumentLoader->setFrame(m_frame);
1804 m_client->transitionToCommittedFromCachedFrame(cachedPage->cachedMainFrame());
1807 m_client->transitionToCommittedForNewPage();
1811 case FrameLoadTypeReload:
1812 case FrameLoadTypeReloadFromOrigin:
1813 case FrameLoadTypeSame:
1814 case FrameLoadTypeReplace:
1815 history()->updateForReload();
1816 m_client->transitionToCommittedForNewPage();
1819 case FrameLoadTypeStandard:
1820 history()->updateForStandardLoad();
1821 if (m_frame->view())
1822 m_frame->view()->setScrollbarsSuppressed(true);
1823 m_client->transitionToCommittedForNewPage();
1826 case FrameLoadTypeRedirectWithLockedBackForwardList:
1827 history()->updateForRedirectWithLockedBackForwardList();
1828 m_client->transitionToCommittedForNewPage();
1831 // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is).
1832 // An exception should be thrown if we're in the FrameLoadTypeUninitialized state.
1834 ASSERT_NOT_REACHED();
1837 m_documentLoader->writer()->setMIMEType(dl->responseMIMEType());
1839 // Tell the client we've committed this URL.
1840 ASSERT(m_frame->view());
1842 if (m_stateMachine.creatingInitialEmptyDocument())
1845 if (!m_stateMachine.committedFirstRealDocumentLoad())
1846 m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit);
1849 void FrameLoader::clientRedirectCancelledOrFinished(bool cancelWithLoadInProgress)
1851 // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
1852 // the redirect succeeded. We should either rename this API, or add a new method, like
1853 // -webView:didFinishClientRedirectForFrame:
1854 m_client->dispatchDidCancelClientRedirect();
1856 if (!cancelWithLoadInProgress)
1857 m_quickRedirectComing = false;
1859 m_sentRedirectNotification = false;
1862 void FrameLoader::clientRedirected(const KURL& url, double seconds, double fireDate, bool lockBackForwardList)
1864 m_client->dispatchWillPerformClientRedirect(url, seconds, fireDate);
1866 // Remember that we sent a redirect notification to the frame load delegate so that when we commit
1867 // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
1868 m_sentRedirectNotification = true;
1870 // If a "quick" redirect comes in, we set a special mode so we treat the next
1871 // load as part of the original navigation. If we don't have a document loader, we have
1872 // no "original" load on which to base a redirect, so we treat the redirect as a normal load.
1873 // Loads triggered by JavaScript form submissions never count as quick redirects.
1874 m_quickRedirectComing = (lockBackForwardList || history()->currentItemShouldBeReplaced()) && m_documentLoader && !m_isExecutingJavaScriptFormAction;
1877 bool FrameLoader::shouldReload(const KURL& currentURL, const KURL& destinationURL)
1879 // This function implements the rule: "Don't reload if navigating by fragment within
1880 // the same URL, but do reload if going to a new URL or to the same URL with no
1881 // fragment identifier at all."
1882 if (!destinationURL.hasFragmentIdentifier())
1884 return !equalIgnoringFragmentIdentifier(currentURL, destinationURL);
1887 void FrameLoader::closeOldDataSources()
1889 // FIXME: Is it important for this traversal to be postorder instead of preorder?
1890 // If so, add helpers for postorder traversal, and use them. If not, then lets not
1891 // use a recursive algorithm here.
1892 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1893 child->loader()->closeOldDataSources();
1895 if (m_documentLoader)
1896 m_client->dispatchWillClose();
1898 m_client->setMainFrameDocumentReady(false); // stop giving out the actual DOMDocument to observers
1901 void FrameLoader::prepareForCachedPageRestore()
1903 ASSERT(!m_frame->tree()->parent());
1904 ASSERT(m_frame->page());
1905 ASSERT(m_frame->page()->mainFrame() == m_frame);
1907 m_frame->navigationScheduler()->cancel();
1909 // We still have to close the previous part page.
1912 // Delete old status bar messages (if it _was_ activated on last URL).
1913 if (m_frame->script()->canExecuteScripts(NotAboutToExecuteScript)) {
1914 DOMWindow* window = m_frame->document()->domWindow();
1915 window->setStatus(String());
1916 window->setDefaultStatus(String());
1920 void FrameLoader::open(CachedFrameBase& cachedFrame)
1922 m_isComplete = false;
1924 // Don't re-emit the load event.
1925 m_didCallImplicitClose = true;
1927 KURL url = cachedFrame.url();
1929 // FIXME: I suspect this block of code doesn't do anything.
1930 if (url.protocolIsInHTTPFamily() && !url.host().isEmpty() && url.path().isEmpty())
1934 Document* document = cachedFrame.document();
1936 ASSERT(document->domWindow());
1938 clear(document, true, true, cachedFrame.isMainFrame());
1940 document->setInPageCache(false);
1942 m_needsClear = true;
1943 m_isComplete = false;
1944 m_didCallImplicitClose = false;
1945 m_outgoingReferrer = url.string();
1947 FrameView* view = cachedFrame.view();
1949 // When navigating to a CachedFrame its FrameView should never be null. If it is we'll crash in creative ways downstream.
1951 view->setWasScrolledByUser(false);
1953 // Use the current ScrollView's frame rect.
1954 if (m_frame->view())
1955 view->setFrameRect(m_frame->view()->frameRect());
1956 m_frame->setView(view);
1958 m_frame->setDocument(document);
1959 document->domWindow()->resumeFromPageCache();
1961 updateFirstPartyForCookies();
1963 cachedFrame.restore();
1966 bool FrameLoader::isHostedByObjectElement() const
1968 HTMLFrameOwnerElement* owner = m_frame->ownerElement();
1969 return owner && owner->hasTagName(objectTag);
1972 bool FrameLoader::isLoadingMainFrame() const
1974 Page* page = m_frame->page();
1975 return page && m_frame == page->mainFrame();
1978 bool FrameLoader::isReplacing() const
1980 return m_loadType == FrameLoadTypeReplace;
1983 void FrameLoader::setReplacing()
1985 m_loadType = FrameLoadTypeReplace;
1988 bool FrameLoader::subframeIsLoading() const
1990 // It's most likely that the last added frame is the last to load so we walk backwards.
1991 for (Frame* child = m_frame->tree()->lastChild(); child; child = child->tree()->previousSibling()) {
1992 FrameLoader* childLoader = child->loader();
1993 DocumentLoader* documentLoader = childLoader->documentLoader();
1994 if (documentLoader && documentLoader->isLoadingInAPISense())
1996 documentLoader = childLoader->provisionalDocumentLoader();
1997 if (documentLoader && documentLoader->isLoadingInAPISense())
1999 documentLoader = childLoader->policyDocumentLoader();
2006 void FrameLoader::willChangeTitle(DocumentLoader* loader)
2008 m_client->willChangeTitle(loader);
2011 FrameLoadType FrameLoader::loadType() const
2016 CachePolicy FrameLoader::subresourceCachePolicy() const
2019 return CachePolicyVerify;
2021 if (m_loadType == FrameLoadTypeReloadFromOrigin)
2022 return CachePolicyReload;
2024 if (Frame* parentFrame = m_frame->tree()->parent()) {
2025 CachePolicy parentCachePolicy = parentFrame->loader()->subresourceCachePolicy();
2026 if (parentCachePolicy != CachePolicyVerify)
2027 return parentCachePolicy;
2030 if (m_loadType == FrameLoadTypeReload)
2031 return CachePolicyRevalidate;
2033 const ResourceRequest& request(documentLoader()->request());
2035 if (request.cachePolicy() == ReloadIgnoringCacheData && !equalIgnoringCase(request.httpMethod(), "post") && ResourceRequest::useQuickLookResourceCachingQuirks())
2036 return CachePolicyRevalidate;
2039 if (request.cachePolicy() == ReturnCacheDataElseLoad)
2040 return CachePolicyHistoryBuffer;
2042 return CachePolicyVerify;
2045 void FrameLoader::checkLoadCompleteForThisFrame()
2047 ASSERT(m_client->hasWebView());
2049 Settings* settings = m_frame->settings();
2052 case FrameStateProvisional: {
2053 if (m_delegateIsHandlingProvisionalLoadError)
2056 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
2060 // If we've received any errors we may be stuck in the provisional state and actually complete.
2061 const ResourceError& error = pdl->mainDocumentError();
2065 // Check all children first.
2066 RefPtr<HistoryItem> item;
2067 if (Page* page = m_frame->page())
2068 if (isBackForwardLoadType(loadType()))
2069 // Reset the back forward list to the last committed history item at the top level.
2070 item = page->mainFrame()->loader()->history()->currentItem();
2072 // Only reset if we aren't already going to a new provisional item.
2073 bool shouldReset = !history()->provisionalItem();
2074 if (!pdl->isLoadingInAPISense() || pdl->isStopping()) {
2075 m_delegateIsHandlingProvisionalLoadError = true;
2076 m_client->dispatchDidFailProvisionalLoad(error);
2077 m_delegateIsHandlingProvisionalLoadError = false;
2079 ASSERT(!pdl->isLoading());
2081 // If we're in the middle of loading multipart data, we need to restore the document loader.
2082 if (isReplacing() && !m_documentLoader.get())
2083 setDocumentLoader(m_provisionalDocumentLoader.get());
2085 // Finish resetting the load state, but only if another load hasn't been started by the
2086 // delegate callback.
2087 if (pdl == m_provisionalDocumentLoader)
2088 clearProvisionalLoad();
2089 else if (activeDocumentLoader()) {
2090 KURL unreachableURL = activeDocumentLoader()->unreachableURL();
2091 if (!unreachableURL.isEmpty() && unreachableURL == pdl->request().url())
2092 shouldReset = false;
2095 if (shouldReset && item)
2096 if (Page* page = m_frame->page()) {
2097 page->backForward()->setCurrentItem(item.get());
2098 m_frame->loader()->client()->updateGlobalHistoryItemForPage();
2103 case FrameStateCommittedPage: {
2104 DocumentLoader* dl = m_documentLoader.get();
2105 if (!dl || (dl->isLoadingInAPISense() && !dl->isStopping()))
2108 setState(FrameStateComplete);
2110 // FIXME: Is this subsequent work important if we already navigated away?
2111 // Maybe there are bugs because of that, or extra work we can skip because
2112 // the new page is ready.
2114 m_client->forceLayoutForNonHTML();
2116 // If the user had a scroll point, scroll to it, overriding the anchor point if any.
2117 if (m_frame->page()) {
2118 if (isBackForwardLoadType(m_loadType) || m_loadType == FrameLoadTypeReload || m_loadType == FrameLoadTypeReloadFromOrigin)
2119 history()->restoreScrollPositionAndViewState();
2122 if (m_stateMachine.creatingInitialEmptyDocument() || !m_stateMachine.committedFirstRealDocumentLoad())
2125 if (!settings->needsDidFinishLoadOrderQuirk()) {
2126 if (Page* page = m_frame->page()) {
2127 page->progress()->progressCompleted(m_frame);
2129 if (m_frame == page->mainFrame())
2130 page->resetRelevantPaintedObjectCounter();
2134 const ResourceError& error = dl->mainDocumentError();
2136 AXObjectCache::AXLoadingEvent loadingEvent;
2137 if (!error.isNull()) {
2138 m_client->dispatchDidFailLoad(error);
2139 loadingEvent = AXObjectCache::AXLoadingFailed;
2141 m_client->dispatchDidFinishLoad();
2142 loadingEvent = AXObjectCache::AXLoadingFinished;
2145 if (settings->needsDidFinishLoadOrderQuirk()) {
2146 if (Page* page = m_frame->page()) {
2147 page->progress()->progressCompleted(m_frame);
2149 if (m_frame == page->mainFrame())
2150 page->resetRelevantPaintedObjectCounter();
2154 // Notify accessibility.
2155 if (AXObjectCache::accessibilityEnabled())
2156 m_frame->document()->axObjectCache()->frameLoadingEventNotification(m_frame, loadingEvent);
2161 case FrameStateComplete:
2162 m_loadType = FrameLoadTypeStandard;
2163 frameLoadCompleted();
2167 ASSERT_NOT_REACHED();
2170 void FrameLoader::continueLoadAfterWillSubmitForm()
2172 if (!m_provisionalDocumentLoader)
2175 prepareForLoadStart();
2177 // The load might be cancelled inside of prepareForLoadStart(), nulling out the m_provisionalDocumentLoader,
2178 // so we need to null check it again.
2179 if (!m_provisionalDocumentLoader)
2182 DocumentLoader* activeDocLoader = activeDocumentLoader();
2183 if (activeDocLoader && activeDocLoader->isLoadingMainResource())
2186 m_loadingFromCachedPage = false;
2187 m_provisionalDocumentLoader->startLoadingMainResource();
2190 static KURL originatingURLFromBackForwardList(Page* page)
2192 // FIXME: Can this logic be replaced with m_frame->document()->firstPartyForCookies()?
2193 // It has the same meaning of "page a user thinks is the current one".
2196 int backCount = page->backForward()->backCount();
2197 for (int backIndex = 0; backIndex <= backCount; backIndex++) {
2198 // FIXME: At one point we had code here to check a "was user gesture" flag.
2199 // Do we need to restore that logic?
2200 HistoryItem* historyItem = page->backForward()->itemAtIndex(-backIndex);
2204 originalURL = historyItem->originalURL();
2205 if (!originalURL.isNull())
2212 void FrameLoader::setOriginalURLForDownloadRequest(ResourceRequest& request)
2216 // If there is no referrer, assume that the download was initiated directly, so current document is
2217 // completely unrelated to it. See <rdar://problem/5294691>.
2218 // FIXME: Referrer is not sent in many other cases, so we will often miss this important information.
2219 // Find a better way to decide whether the download was unrelated to current document.
2220 if (!request.httpReferrer().isNull()) {
2221 // find the first item in the history that was originated by the user
2222 originalURL = originatingURLFromBackForwardList(m_frame->page());
2225 if (originalURL.isNull())
2226 originalURL = request.url();
2228 if (!originalURL.protocol().isEmpty() && !originalURL.host().isEmpty()) {
2229 unsigned port = originalURL.port();
2231 // Original URL is needed to show the user where a file was downloaded from. We should make a URL that won't result in downloading the file again.
2232 // FIXME: Using host-only URL is a very heavy-handed approach. We should attempt to provide the actual page where the download was initiated from, as a reminder to the user.
2233 String hostOnlyURLString;
2235 hostOnlyURLString = makeString(originalURL.protocol(), "://", originalURL.host(), ":", String::number(port));
2237 hostOnlyURLString = makeString(originalURL.protocol(), "://", originalURL.host());
2239 // FIXME: Rename firstPartyForCookies back to mainDocumentURL. It was a mistake to think that it was only used for cookies.
2240 request.setFirstPartyForCookies(KURL(KURL(), hostOnlyURLString));
2244 void FrameLoader::didFirstLayout()
2246 if (m_frame->page() && isBackForwardLoadType(m_loadType))
2247 history()->restoreScrollPositionAndViewState();
2249 if (m_stateMachine.committedFirstRealDocumentLoad() && !m_stateMachine.isDisplayingInitialEmptyDocument() && !m_stateMachine.firstLayoutDone())
2250 m_stateMachine.advanceTo(FrameLoaderStateMachine::FirstLayoutDone);
2252 m_client->dispatchDidFirstLayout();
2255 void FrameLoader::didFirstVisuallyNonEmptyLayout()
2257 m_client->dispatchDidFirstVisuallyNonEmptyLayout();
2260 void FrameLoader::didNewFirstVisuallyNonEmptyLayout()
2262 m_client->dispatchDidNewFirstVisuallyNonEmptyLayout();
2265 void FrameLoader::frameLoadCompleted()
2267 // Note: Can be called multiple times.
2269 m_client->frameLoadCompleted();
2271 history()->updateForFrameLoadCompleted();
2273 // After a canceled provisional load, firstLayoutDone is false.
2274 // Reset it to true if we're displaying a page.
2275 if (m_documentLoader && m_stateMachine.committedFirstRealDocumentLoad() && !m_stateMachine.isDisplayingInitialEmptyDocument() && !m_stateMachine.firstLayoutDone())
2276 m_stateMachine.advanceTo(FrameLoaderStateMachine::FirstLayoutDone);
2279 void FrameLoader::detachChildren()
2281 typedef Vector<RefPtr<Frame> > FrameVector;
2282 FrameVector childrenToDetach;
2283 childrenToDetach.reserveCapacity(m_frame->tree()->childCount());
2284 for (Frame* child = m_frame->tree()->lastChild(); child; child = child->tree()->previousSibling())
2285 childrenToDetach.append(child);
2286 FrameVector::iterator end = childrenToDetach.end();
2287 for (FrameVector::iterator it = childrenToDetach.begin(); it != end; it++)
2288 (*it)->loader()->detachFromParent();
2291 void FrameLoader::closeAndRemoveChild(Frame* child)
2293 child->tree()->detachFromParent();
2296 if (child->ownerElement() && child->page())
2297 child->page()->decrementFrameCount();
2298 child->willDetachPage();
2299 child->detachFromPage();
2301 m_frame->tree()->removeChild(child);
2304 // Called every time a resource is completely loaded or an error is received.
2305 void FrameLoader::checkLoadComplete()
2307 ASSERT(m_client->hasWebView());
2309 m_shouldCallCheckLoadComplete = false;
2311 // FIXME: Always traversing the entire frame tree is a bit inefficient, but
2312 // is currently needed in order to null out the previous history item for all frames.
2313 if (Page* page = m_frame->page()) {
2314 Vector<RefPtr<Frame>, 10> frames;
2315 for (RefPtr<Frame> frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext())
2316 frames.append(frame);
2317 // To process children before their parents, iterate the vector backwards.
2318 for (size_t i = frames.size(); i; --i)
2319 frames[i - 1]->loader()->checkLoadCompleteForThisFrame();
2323 int FrameLoader::numPendingOrLoadingRequests(bool recurse) const
2326 return m_frame->document()->cachedResourceLoader()->requestCount();
2329 for (Frame* frame = m_frame; frame; frame = frame->tree()->traverseNext(m_frame))
2330 count += frame->document()->cachedResourceLoader()->requestCount();
2334 String FrameLoader::userAgent(const KURL& url) const
2336 String userAgent = m_client->userAgent(url);
2337 InspectorInstrumentation::applyUserAgentOverride(m_frame, &userAgent);
2341 void FrameLoader::handledOnloadEvents()
2343 m_client->dispatchDidHandleOnloadEvents();
2345 if (documentLoader())
2346 documentLoader()->handledOnloadEvents();
2349 void FrameLoader::frameDetached()
2352 m_frame->document()->stopActiveDOMObjects();
2356 void FrameLoader::detachFromParent()
2358 RefPtr<Frame> protect(m_frame);
2361 history()->saveScrollPositionAndViewStateToItem(history()->currentItem());
2363 // stopAllLoaders() needs to be called after detachChildren(), because detachedChildren()
2364 // will trigger the unload event handlers of any child frames, and those event
2365 // handlers might start a new subresource load in this frame.
2368 InspectorInstrumentation::frameDetachedFromParent(m_frame);
2370 detachViewsAndDocumentLoader();
2372 if (Frame* parent = m_frame->tree()->parent()) {
2373 parent->loader()->closeAndRemoveChild(m_frame);
2374 parent->loader()->scheduleCheckCompleted();
2376 m_frame->setView(0);
2377 m_frame->willDetachPage();
2378 m_frame->detachFromPage();
2382 void FrameLoader::detachViewsAndDocumentLoader()
2384 m_client->detachedFromParent2();
2385 setDocumentLoader(0);
2386 m_client->detachedFromParent3();
2389 void FrameLoader::addExtraFieldsToSubresourceRequest(ResourceRequest& request)
2391 addExtraFieldsToRequest(request, m_loadType, false);
2394 void FrameLoader::addExtraFieldsToMainResourceRequest(ResourceRequest& request)
2396 addExtraFieldsToRequest(request, m_loadType, true);
2399 void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, FrameLoadType loadType, bool mainResource)
2401 // Don't set the cookie policy URL if it's already been set.
2402 // But make sure to set it on all requests, as it has significance beyond the cookie policy for all protocols (<rdar://problem/6616664>).
2403 if (request.firstPartyForCookies().isEmpty()) {
2404 if (mainResource && isLoadingMainFrame())
2405 request.setFirstPartyForCookies(request.url());
2406 else if (Document* document = m_frame->document())
2407 request.setFirstPartyForCookies(document->firstPartyForCookies());
2410 // The remaining modifications are only necessary for HTTP and HTTPS.
2411 if (!request.url().isEmpty() && !request.url().protocolIsInHTTPFamily())
2414 applyUserAgent(request);
2416 // If we inherit cache policy from a main resource, we use the DocumentLoader's
2417 // original request cache policy for two reasons:
2418 // 1. For POST requests, we mutate the cache policy for the main resource,
2419 // but we do not want this to apply to subresources
2420 // 2. Delegates that modify the cache policy using willSendRequest: should
2421 // not affect any other resources. Such changes need to be done
2423 if (!mainResource) {
2424 if (request.isConditional())
2425 request.setCachePolicy(ReloadIgnoringCacheData);
2426 else if (documentLoader()->isLoadingInAPISense())
2427 request.setCachePolicy(documentLoader()->originalRequest().cachePolicy());
2429 request.setCachePolicy(UseProtocolCachePolicy);
2430 } else if (loadType == FrameLoadTypeReload || loadType == FrameLoadTypeReloadFromOrigin || request.isConditional())
2431 request.setCachePolicy(ReloadIgnoringCacheData);
2432 else if (isBackForwardLoadType(loadType) && m_stateMachine.committedFirstRealDocumentLoad())
2433 request.setCachePolicy(ReturnCacheDataElseLoad);
2435 if (request.cachePolicy() == ReloadIgnoringCacheData) {
2436 if (loadType == FrameLoadTypeReload)
2437 request.setHTTPHeaderField("Cache-Control", "max-age=0");
2438 else if (loadType == FrameLoadTypeReloadFromOrigin) {
2439 request.setHTTPHeaderField("Cache-Control", "no-cache");
2440 request.setHTTPHeaderField("Pragma", "no-cache");
2445 request.setHTTPAccept(defaultAcceptHeader);
2447 // Make sure we send the Origin header.
2448 addHTTPOriginIfNeeded(request, String());
2450 // Always try UTF-8. If that fails, try frame encoding (if any) and then the default.
2451 Settings* settings = m_frame->settings();
2452 request.setResponseContentDispositionEncodingFallbackArray("UTF-8", m_frame->document()->encoding(), settings ? settings->defaultTextEncodingName() : String());
2455 void FrameLoader::addHTTPOriginIfNeeded(ResourceRequest& request, const String& origin)
2457 if (!request.httpOrigin().isEmpty())
2458 return; // Request already has an Origin header.
2460 // Don't send an Origin header for GET or HEAD to avoid privacy issues.
2461 // For example, if an intranet page has a hyperlink to an external web
2462 // site, we don't want to include the Origin of the request because it
2463 // will leak the internal host name. Similar privacy concerns have lead
2464 // to the widespread suppression of the Referer header at the network
2466 if (request.httpMethod() == "GET" || request.httpMethod() == "HEAD")
2469 // For non-GET and non-HEAD methods, always send an Origin header so the
2470 // server knows we support this feature.
2472 if (origin.isEmpty()) {
2473 // If we don't know what origin header to attach, we attach the value
2474 // for an empty origin.
2475 request.setHTTPOrigin(SecurityOrigin::createUnique()->toString());
2479 request.setHTTPOrigin(origin);
2482 void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType loadType, PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState)
2484 RefPtr<FormState> formState = prpFormState;
2486 // Previously when this method was reached, the original FrameLoadRequest had been deconstructed to build a
2487 // bunch of parameters that would come in here and then be built back up to a ResourceRequest. In case
2488 // any caller depends on the immutability of the original ResourceRequest, I'm rebuilding a ResourceRequest
2489 // from scratch as it did all along.
2490 const KURL& url = inRequest.url();
2491 RefPtr<FormData> formData = inRequest.httpBody();
2492 const String& contentType = inRequest.httpContentType();
2493 String origin = inRequest.httpOrigin();
2495 ResourceRequest workingResourceRequest(url);
2497 if (!referrer.isEmpty())
2498 workingResourceRequest.setHTTPReferrer(referrer);
2499 workingResourceRequest.setHTTPOrigin(origin);
2500 workingResourceRequest.setHTTPMethod("POST");
2501 workingResourceRequest.setHTTPBody(formData);
2502 workingResourceRequest.setHTTPContentType(contentType);
2503 addExtraFieldsToRequest(workingResourceRequest, loadType, true);
2505 NavigationAction action(workingResourceRequest, loadType, true, event);
2507 if (!frameName.isEmpty()) {
2508 // The search for a target frame is done earlier in the case of form submission.
2509 if (Frame* targetFrame = formState ? 0 : findFrameForNavigation(frameName))
2510 targetFrame->loader()->loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, formState.release());
2512 policyChecker()->checkNewWindowPolicy(action, FrameLoader::callContinueLoadAfterNewWindowPolicy, workingResourceRequest, formState.release(), frameName, this);
2514 // must grab this now, since this load may stop the previous load and clear this flag
2515 bool isRedirect = m_quickRedirectComing;
2516 loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, formState.release());
2518 m_quickRedirectComing = false;
2519 if (m_provisionalDocumentLoader)
2520 m_provisionalDocumentLoader->setIsClientRedirect(true);
2525 unsigned long FrameLoader::loadResourceSynchronously(const ResourceRequest& request, StoredCredentials storedCredentials, ResourceError& error, ResourceResponse& response, Vector<char>& data)
2527 ASSERT(m_frame->document());
2528 String referrer = SecurityPolicy::generateReferrerHeader(m_frame->document()->referrerPolicy(), request.url(), outgoingReferrer());
2530 ResourceRequest initialRequest = request;
2531 initialRequest.setTimeoutInterval(10);
2533 if (!referrer.isEmpty())
2534 initialRequest.setHTTPReferrer(referrer);
2535 addHTTPOriginIfNeeded(initialRequest, outgoingOrigin());
2537 if (Page* page = m_frame->page())
2538 initialRequest.setFirstPartyForCookies(page->mainFrame()->loader()->documentLoader()->request().url());
2540 addExtraFieldsToSubresourceRequest(initialRequest);
2542 unsigned long identifier = 0;
2543 ResourceRequest newRequest(initialRequest);
2544 requestFromDelegate(newRequest, identifier, error);
2546 if (error.isNull()) {
2547 ASSERT(!newRequest.isNull());
2549 if (!documentLoader()->applicationCacheHost()->maybeLoadSynchronously(newRequest, error, response, data)) {
2550 ResourceHandle::loadResourceSynchronously(networkingContext(), newRequest, storedCredentials, error, response, data);
2551 documentLoader()->applicationCacheHost()->maybeLoadFallbackSynchronously(newRequest, error, response, data);
2554 int encodedDataLength = response.resourceLoadInfo() ? static_cast<int>(response.resourceLoadInfo()->encodedDataLength) : -1;
2555 notifier()->sendRemainingDelegateMessages(m_documentLoader.get(), identifier, response, data.data(), data.size(), encodedDataLength, error);
2559 const ResourceRequest& FrameLoader::originalRequest() const
2561 return activeDocumentLoader()->originalRequestCopy();
2564 void FrameLoader::receivedMainResourceError(const ResourceError& error)
2566 // Retain because the stop may release the last reference to it.
2567 RefPtr<Frame> protect(m_frame);
2569 RefPtr<DocumentLoader> loader = activeDocumentLoader();
2570 // FIXME: Don't want to do this if an entirely new load is going, so should check
2571 // that both data sources on the frame are either this or nil.
2573 if (m_client->shouldFallBack(error))
2574 handleFallbackContent();
2576 if (m_state == FrameStateProvisional && m_provisionalDocumentLoader) {
2577 if (m_submittedFormURL == m_provisionalDocumentLoader->originalRequestCopy().url())
2578 m_submittedFormURL = KURL();
2580 // We might have made a page cache item, but now we're bailing out due to an error before we ever
2581 // transitioned to the new page (before WebFrameState == commit). The goal here is to restore any state
2582 // so that the existing view (that wenever got far enough to replace) can continue being used.
2583 history()->invalidateCurrentItemCachedPage();
2585 // Call clientRedirectCancelledOrFinished here so that the frame load delegate is notified that the redirect's
2586 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
2587 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are definitely
2588 // not going to use this provisional resource, as it was cancelled, notify the frame load delegate that the redirect
2590 if (m_sentRedirectNotification)
2591 clientRedirectCancelledOrFinished(false);
2595 if (m_frame->page())
2596 checkLoadComplete();
2599 void FrameLoader::callContinueFragmentScrollAfterNavigationPolicy(void* argument,
2600 const ResourceRequest& request, PassRefPtr<FormState>, bool shouldContinue)
2602 FrameLoader* loader = static_cast<FrameLoader*>(argument);
2603 loader->continueFragmentScrollAfterNavigationPolicy(request, shouldContinue);
2606 void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequest& request, bool shouldContinue)
2608 m_quickRedirectComing = false;
2610 if (!shouldContinue)
2613 // If we have a provisional request for a different document, a fragment scroll should cancel it.
2614 if (m_provisionalDocumentLoader && !equalIgnoringFragmentIdentifier(m_provisionalDocumentLoader->request().url(), request.url())) {
2615 m_provisionalDocumentLoader->stopLoading();
2616 setProvisionalDocumentLoader(0);
2619 bool isRedirect = m_quickRedirectComing || policyChecker()->loadType() == FrameLoadTypeRedirectWithLockedBackForwardList;
2620 loadInSameDocument(request.url(), 0, !isRedirect);
2623 bool FrameLoader::shouldPerformFragmentNavigation(bool isFormSubmission, const String& httpMethod, FrameLoadType loadType, const KURL& url)
2625 // We don't do this if we are submitting a form with method other than "GET", explicitly reloading,
2626 // currently displaying a frameset, or if the URL does not have a fragment.
2627 // These rules were originally based on what KHTML was doing in KHTMLPart::openURL.
2629 // FIXME: What about load types other than Standard and Reload?
2631 return (!isFormSubmission || equalIgnoringCase(httpMethod, "GET"))
2632 && loadType != FrameLoadTypeReload
2633 && loadType != FrameLoadTypeReloadFromOrigin
2634 && loadType != FrameLoadTypeSame
2635 && !shouldReload(m_frame->document()->url(), url)
2636 // We don't want to just scroll if a link from within a
2637 // frameset is trying to reload the frameset into _top.
2638 && !m_frame->document()->isFrameSet();
2641 void FrameLoader::scrollToFragmentWithParentBoundary(const KURL& url)
2643 FrameView* view = m_frame->view();
2647 // Leaking scroll position to a cross-origin ancestor would permit the so-called "framesniffing" attack.
2648 RefPtr<Frame> boundaryFrame(url.hasFragmentIdentifier() ? m_frame->document()->findUnsafeParentScrollPropagationBoundary() : 0);
2651 boundaryFrame->view()->setSafeToPropagateScrollToParent(false);
2653 view->scrollToFragment(url);
2656 boundaryFrame->view()->setSafeToPropagateScrollToParent(true);
2659 void FrameLoader::callContinueLoadAfterNavigationPolicy(void* argument,
2660 const ResourceRequest& request, PassRefPtr<FormState> formState, bool shouldContinue)
2662 FrameLoader* loader = static_cast<FrameLoader*>(argument);
2663 loader->continueLoadAfterNavigationPolicy(request, formState, shouldContinue);
2666 bool FrameLoader::shouldClose()
2668 Page* page = m_frame->page();
2669 Chrome* chrome = page ? page->chrome() : 0;
2670 if (!chrome || !chrome->canRunBeforeUnloadConfirmPanel())
2673 // Store all references to each subframe in advance since beforeunload's event handler may modify frame
2674 Vector<RefPtr<Frame> > targetFrames;
2675 targetFrames.append(m_frame);
2676 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->traverseNext(m_frame))
2677 targetFrames.append(child);
2679 bool shouldClose = false;
2681 NavigationDisablerForBeforeUnload navigationDisabler;
2684 for (i = 0; i < targetFrames.size(); i++) {
2685 if (!targetFrames[i]->tree()->isDescendantOf(m_frame))
2687 if (!targetFrames[i]->loader()->fireBeforeUnloadEvent(chrome))
2691 if (i == targetFrames.size())
2696 m_submittedFormURL = KURL();
2701 bool FrameLoader::fireBeforeUnloadEvent(Chrome* chrome)
2703 DOMWindow* domWindow = m_frame->document()->domWindow();
2707 RefPtr<Document> document = m_frame->document();
2708 if (!document->body())
2711 RefPtr<BeforeUnloadEvent> beforeUnloadEvent = BeforeUnloadEvent::create();
2712 m_pageDismissalEventBeingDispatched = BeforeUnloadDismissal;
2713 domWindow->dispatchEvent(beforeUnloadEvent.get(), domWindow->document());
2714 m_pageDismissalEventBeingDispatched = NoDismissal;
2716 if (!beforeUnloadEvent->defaultPrevented())
2717 document->defaultEventHandler(beforeUnloadEvent.get());
2718 if (beforeUnloadEvent->result().isNull())
2721 String text = document->displayStringModifiedByEncoding(beforeUnloadEvent->result());
2722 return chrome->runBeforeUnloadConfirmPanel(text, m_frame);
2725 void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, PassRefPtr<FormState> formState, bool shouldContinue)
2727 // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
2728 // nil policyDataSource because loading the alternate page will have passed
2729 // through this method already, nested; otherwise, policyDataSource should still be set.
2730 ASSERT(m_policyDocumentLoader || !m_provisionalDocumentLoader->unreachableURL().isEmpty());
2732 bool isTargetItem = history()->provisionalItem() ? history()->provisionalItem()->isTargetItem() : false;
2734 // Two reasons we can't continue:
2735 // 1) Navigation policy delegate said we can't so request is nil. A primary case of this
2736 // is the user responding Cancel to the form repost nag sheet.
2737 // 2) User responded Cancel to an alert popped up by the before unload event handler.
2738 bool canContinue = shouldContinue && shouldClose();
2741 // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we
2742 // need to report that the client redirect was cancelled.
2743 if (m_quickRedirectComing)
2744 clientRedirectCancelledOrFinished(false);
2746 setPolicyDocumentLoader(0);
2748 // If the navigation request came from the back/forward menu, and we punt on it, we have the
2749 // problem that we have optimistically moved the b/f cursor already, so move it back. For sanity,
2750 // we only do this when punting a navigation for the target frame or top-level frame.
2751 if ((isTargetItem || isLoadingMainFrame()) && isBackForwardLoadType(policyChecker()->loadType())) {
2752 if (Page* page = m_frame->page()) {
2753 Frame* mainFrame = page->mainFrame();
2754 if (HistoryItem* resetItem = mainFrame->loader()->history()->currentItem()) {
2755 page->backForward()->setCurrentItem(resetItem);
2756 m_frame->loader()->client()->updateGlobalHistoryItemForPage();
2763 FrameLoadType type = policyChecker()->loadType();
2764 // A new navigation is in progress, so don't clear the history's provisional item.
2765 stopAllLoaders(ShouldNotClearProvisionalItem);
2767 // <rdar://problem/6250856> - In certain circumstances on pages with multiple frames, stopAllLoaders()
2768 // might detach the current FrameLoader, in which case we should bail on this newly defunct load.
2769 if (!m_frame->page())
2772 #if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(INSPECTOR)
2773 if (Page* page = m_frame->page()) {
2774 if (page->mainFrame() == m_frame)
2775 m_frame->page()->inspectorController()->resume();
2779 setProvisionalDocumentLoader(m_policyDocumentLoader.get());
2781 setState(FrameStateProvisional);
2783 setPolicyDocumentLoader(0);
2785 if (isBackForwardLoadType(type) && history()->provisionalItem()->isInPageCache()) {
2786 loadProvisionalItemFromCachedPage();
2791 m_client->dispatchWillSubmitForm(&PolicyChecker::continueLoadAfterWillSubmitForm, formState);
2793 continueLoadAfterWillSubmitForm();
2796 void FrameLoader::callContinueLoadAfterNewWindowPolicy(void* argument,
2797 const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue)
2799 FrameLoader* loader = static_cast<FrameLoader*>(argument);
2800 loader->continueLoadAfterNewWindowPolicy(request, formState, frameName, action, shouldContinue);
2803 void FrameLoader::continueLoadAfterNewWindowPolicy(const ResourceRequest& request,
2804 PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue)
2806 if (!shouldContinue)
2809 RefPtr<Frame> frame = m_frame;
2810 RefPtr<Frame> mainFrame = m_client->dispatchCreatePage(action);
2814 if (frameName != "_blank")
2815 mainFrame->tree()->setName(frameName);
2817 mainFrame->page()->setOpenedByDOM();
2818 mainFrame->loader()->m_client->dispatchShow();
2819 if (!m_suppressOpenerInNewFrame) {
2820 mainFrame->loader()->setOpener(frame.get());
2821 mainFrame->document()->setReferrerPolicy(frame->document()->referrerPolicy());
2823 mainFrame->loader()->loadWithNavigationAction(request, NavigationAction(request), false, FrameLoadTypeStandard, formState);
2826 void FrameLoader::requestFromDelegate(ResourceRequest& request, unsigned long& identifier, ResourceError& error)
2828 ASSERT(!request.isNull());
2831 if (Page* page = m_frame->page()) {
2832 identifier = page->progress()->createUniqueIdentifier();
2833 notifier()->assignIdentifierToInitialRequest(identifier, m_documentLoader.get(), request);
2836 ResourceRequest newRequest(request);
2837 notifier()->dispatchWillSendRequest(m_documentLoader.get(), identifier, newRequest, ResourceResponse());
2839 if (newRequest.isNull())
2840 error = cancelledError(request);
2842 error = ResourceError();
2844 request = newRequest;
2847 void FrameLoader::loadedResourceFromMemoryCache(CachedResource* resource)
2849 Page* page = m_frame->page();
2853 if (!resource->sendResourceLoadCallbacks() || m_documentLoader->haveToldClientAboutLoad(resource->url()))
2856 if (!page->areMemoryCacheClientCallsEnabled()) {
2857 InspectorInstrumentation::didLoadResourceFromMemoryCache(page, m_documentLoader.get(), resource);
2858 m_documentLoader->recordMemoryCacheLoadForFutureClientNotification(resource->url());
2859 m_documentLoader->didTellClientAboutLoad(resource->url());
2863 ResourceRequest request(resource->url());
2864 if (m_client->dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(), request, resource->response(), resource->encodedSize())) {
2865 InspectorInstrumentation::didLoadResourceFromMemoryCache(page, m_documentLoader.get(), resource);
2866 m_documentLoader->didTellClientAboutLoad(resource->url());
2870 unsigned long identifier;
2871 ResourceError error;
2872 requestFromDelegate(request, identifier, error);
2873 InspectorInstrumentation::markResourceAsCached(page, identifier);
2874 notifier()->sendRemainingDelegateMessages(m_documentLoader.get(), identifier, resource->response(), 0, resource->encodedSize(), 0, error);
2877 void FrameLoader::applyUserAgent(ResourceRequest& request)
2879 String userAgent = this->userAgent(request.url());
2880 ASSERT(!userAgent.isNull());
2881 request.setHTTPUserAgent(userAgent);
2884 bool FrameLoader::shouldInterruptLoadForXFrameOptions(const String& content, const KURL& url)
2886 Frame* topFrame = m_frame->tree()->top();
2887 if (m_frame == topFrame)
2890 if (equalIgnoringCase(content, "deny"))
2893 if (equalIgnoringCase(content, "sameorigin")) {
2894 RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url);
2895 if (!origin->isSameSchemeHostPort(topFrame->document()->securityOrigin()))
2902 void FrameLoader::loadProvisionalItemFromCachedPage()
2904 DocumentLoader* provisionalLoader = provisionalDocumentLoader();
2905 LOG(PageCache, "WebCorePageCache: Loading provisional DocumentLoader %p with URL '%s' from CachedPage", provisionalDocumentLoader(), provisionalDocumentLoader()->url().string().utf8().data());
2907 prepareForLoadStart();
2909 m_loadingFromCachedPage = true;
2911 // Should have timing data from previous time(s) the page was shown.
2912 ASSERT(provisionalLoader->timing()->navigationStart());
2913 provisionalLoader->resetTiming();
2914 provisionalLoader->timing()->markNavigationStart(frame());
2916 provisionalLoader->setCommitted(true);
2917 commitProvisionalLoad();
2920 bool FrameLoader::shouldTreatURLAsSameAsCurrent(const KURL& url) const
2922 if (!history()->currentItem())
2924 return url == history()->currentItem()->url() || url == history()->currentItem()->originalURL();
2927 bool FrameLoader::shouldTreatURLAsSrcdocDocument(const KURL& url) const
2929 if (!equalIgnoringCase(url.string(), "about:srcdoc"))
2931 HTMLFrameOwnerElement* ownerElement = m_frame->ownerElement();
2934 if (!ownerElement->hasTagName(iframeTag))
2936 return ownerElement->fastHasAttribute(srcdocAttr);
2939 void FrameLoader::checkDidPerformFirstNavigation()
2941 Page* page = m_frame->page();
2945 if (!m_didPerformFirstNavigation && page->backForward()->currentItem() && !page->backForward()->backItem() && !page->backForward()->forwardItem()) {
2946 m_didPerformFirstNavigation = true;
2947 m_client->didPerformFirstNavigation();
2951 Frame* FrameLoader::findFrameForNavigation(const AtomicString& name, Document* activeDocument)
2953 Frame* frame = m_frame->tree()->find(name);
2955 // From http://www.whatwg.org/specs/web-apps/current-work/#seamlessLinks:
2957 // If the source browsing context is the same as the browsing context
2958 // being navigated, and this browsing context has its seamless browsing
2959 // context flag set, and the browsing context being navigated was not
2960 // chosen using an explicit self-navigation override, then find the
2961 // nearest ancestor browsing context that does not have its seamless
2962 // browsing context flag set, and continue these steps as if that
2963 // browsing context was the one that was going to be navigated instead.
2964 if (frame == m_frame && name != "_self" && m_frame->document()->shouldDisplaySeamlesslyWithParent()) {
2965 for (Frame* ancestor = m_frame; ancestor; ancestor = ancestor->tree()->parent()) {
2966 if (!ancestor->document()->shouldDisplaySeamlesslyWithParent()) {
2971 ASSERT(frame != m_frame);
2974 if (activeDocument) {
2975 if (!activeDocument->canNavigate(frame))
2978 // FIXME: Eventually all callers should supply the actual activeDocument
2979 // so we can call canNavigate with the right document.
2980 if (!m_frame->document()->canNavigate(frame))
2987 void FrameLoader::loadSameDocumentItem(HistoryItem* item)
2989 ASSERT(item->documentSequenceNumber() == history()->currentItem()->documentSequenceNumber());
2991 // Save user view state to the current history item here since we don't do a normal load.
2992 // FIXME: Does form state need to be saved here too?
2993 history()->saveScrollPositionAndViewStateToItem(history()->currentItem());
2994 if (FrameView* view = m_frame->view())
2995 view->setWasScrolledByUser(false);
2997 history()->setCurrentItem(item);
2999 // loadInSameDocument() actually changes the URL and notifies load delegates of a "fake" load
3000 loadInSameDocument(item->url(), item->stateObject(), false);
3002 // Restore user view state from the current history item here since we don't do a normal load.
3003 history()->restoreScrollPositionAndViewState();
3006 // FIXME: This function should really be split into a couple pieces, some of
3007 // which should be methods of HistoryController and some of which should be
3008 // methods of FrameLoader.
3009 void FrameLoader::loadDifferentDocumentItem(HistoryItem* item, FrameLoadType loadType)
3011 // Remember this item so we can traverse any child items as child frames load
3012 history()->setProvisionalItem(item);
3014 if (CachedPage* cachedPage = pageCache()->get(item)) {
3015 loadWithDocumentLoader(cachedPage->documentLoader(), loadType, 0);
3019 KURL itemURL = item->url();
3020 KURL itemOriginalURL = item->originalURL();
3022 if (documentLoader())
3023 currentURL = documentLoader()->url();
3024 RefPtr<FormData> formData = item->formData();
3026 ResourceRequest request(itemURL);
3028 if (!item->referrer().isNull())
3029 request.setHTTPReferrer(item->referrer());
3031 // If this was a repost that failed the page cache, we might try to repost the form.
3032 NavigationAction action;
3034 formData->generateFiles(m_frame->document());
3036 request.setHTTPMethod("POST");
3037 request.setHTTPBody(formData);
3038 request.setHTTPContentType(item->formContentType());
3039 RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::createFromString(item->referrer());
3040 addHTTPOriginIfNeeded(request, securityOrigin->toString());
3042 // Make sure to add extra fields to the request after the Origin header is added for the FormData case.
3043 // See https://bugs.webkit.org/show_bug.cgi?id=22194 for more discussion.
3044 addExtraFieldsToRequest(request, m_loadType, true);
3046 // FIXME: Slight hack to test if the NSURL cache contains the page we're going to.
3047 // We want to know this before talking to the policy delegate, since it affects whether
3048 // we show the DoYouReallyWantToRepost nag.
3050 // This trick has a small bug (3123893) where we might find a cache hit, but then
3051 // have the item vanish when we try to use it in the ensuing nav. This should be
3052 // extremely rare, but in that case the user will get an error on the navigation.
3054 if (ResourceHandle::willLoadFromCache(request, m_frame))
3055 action = NavigationAction(request, loadType, false);
3057 request.setCachePolicy(ReloadIgnoringCacheData);
3058 action = NavigationAction(request, NavigationTypeFormResubmitted);
3062 case FrameLoadTypeReload:
3063 case FrameLoadTypeReloadFromOrigin:
3064 request.setCachePolicy(ReloadIgnoringCacheData);
3066 case FrameLoadTypeBack:
3067 case FrameLoadTypeForward:
3068 case FrameLoadTypeIndexedBackForward:
3069 // If the first load within a frame is a navigation within a back/forward list that was attached
3070 // without any of the items being loaded then we should use the default caching policy (<rdar://problem/8131355>).
3071 if (m_stateMachine.committedFirstRealDocumentLoad() && !itemURL.protocolIs("https"))
3072 request.setCachePolicy(ReturnCacheDataElseLoad);
3074 case FrameLoadTypeStandard:
3075 case FrameLoadTypeRedirectWithLockedBackForwardList:
3077 case FrameLoadTypeSame:
3079 ASSERT_NOT_REACHED();
3082 addExtraFieldsToRequest(request, m_loadType, true);
3084 ResourceRequest requestForOriginalURL(request);
3085 requestForOriginalURL.setURL(itemOriginalURL);
3086 action = NavigationAction(requestForOriginalURL, loadType, false);
3089 loadWithNavigationAction(request, action, false, loadType, 0);
3092 // Loads content into this frame, as specified by history item
3093 void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType)
3095 m_requestedHistoryItem = item;
3096 HistoryItem* currentItem = history()->currentItem();
3097 bool sameDocumentNavigation = currentItem && item->shouldDoSameDocumentNavigationTo(currentItem);
3099 if (sameDocumentNavigation)
3100 loadSameDocumentItem(item);
3102 loadDifferentDocumentItem(item, loadType);
3105 ResourceError FrameLoader::cancelledError(const ResourceRequest& request) const
3107 ResourceError error = m_client->cancelledError(request);
3108 error.setIsCancellation(true);
3112 void FrameLoader::setTitle(const StringWithDirection& title)
3114 documentLoader()->setTitle(title);
3117 String FrameLoader::referrer() const
3119 return m_documentLoader ? m_documentLoader->request().httpReferrer() : "";
3122 void FrameLoader::dispatchDocumentElementAvailable()
3124 m_frame->injectUserScripts(InjectAtDocumentStart);
3125 m_client->documentElementAvailable();
3128 void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds()
3130 if (!m_frame->script()->canExecuteScripts(NotAboutToExecuteScript))
3133 Vector<RefPtr<DOMWrapperWorld> > worlds;
3134 ScriptController::getAllWorlds(worlds);
3135 for (size_t i = 0; i < worlds.size(); ++i)
3136 dispatchDidClearWindowObjectInWorld(worlds[i].get());
3139 void FrameLoader::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld* world)
3141 if (!m_frame->script()->canExecuteScripts(NotAboutToExecuteScript) || !m_frame->script()->existingWindowShell(world))
3144 m_client->dispatchDidClearWindowObjectInWorld(world);
3146 #if ENABLE(INSPECTOR)
3147 if (Page* page = m_frame->page())
3148 page->inspectorController()->didClearWindowObjectInWorld(m_frame, world);
3151 InspectorInstrumentation::didClearWindowObjectInWorld(m_frame, world);
3154 void FrameLoader::dispatchGlobalObjectAvailableInAllWorlds()
3156 Vector<RefPtr<DOMWrapperWorld> > worlds;
3157 ScriptController::getAllWorlds(worlds);
3158 for (size_t i = 0; i < worlds.size(); ++i)
3159 m_client->dispatchGlobalObjectAvailable(worlds[i].get());
3162 SandboxFlags FrameLoader::effectiveSandboxFlags() const
3164 SandboxFlags flags = m_forcedSandboxFlags;
3165 if (Frame* parentFrame = m_frame->tree()->parent())
3166 flags |= parentFrame->document()->sandboxFlags();
3167 if (HTMLFrameOwnerElement* ownerElement = m_frame->ownerElement())
3168 flags |= ownerElement->sandboxFlags();
3172 void FrameLoader::didChangeTitle(DocumentLoader* loader)
3174 m_client->didChangeTitle(loader);
3176 if (loader == m_documentLoader) {
3177 // Must update the entries in the back-forward list too.
3178 history()->setCurrentItemTitle(loader->title());
3179 // This must go through the WebFrame because it has the right notion of the current b/f item.
3180 m_client->setTitle(loader->title(), loader->urlForHistory());
3181 m_client->setMainFrameDocumentReady(true); // update observers with new DOMDocument
3182 m_client->dispatchDidReceiveTitle(loader->title());
3186 void FrameLoader::didChangeIcons(IconType type)
3188 m_client->dispatchDidChangeIcons(type);
3191 void FrameLoader::dispatchDidCommitLoad()
3193 if (m_stateMachine.creatingInitialEmptyDocument())
3196 m_client->dispatchDidCommitLoad();
3198 if (isLoadingMainFrame())
3199 m_frame->page()->resetSeenPlugins();
3201 InspectorInstrumentation::didCommitLoad(m_frame, m_documentLoader.get());
3204 void FrameLoader::tellClientAboutPastMemoryCacheLoads()
3206 ASSERT(m_frame->page());
3207 ASSERT(m_frame->page()->areMemoryCacheClientCallsEnabled());
3209 if (!m_documentLoader)
3212 Vector<String> pastLoads;
3213 m_documentLoader->takeMemoryCacheLoadsForClientNotification(pastLoads);
3215 size_t size = pastLoads.size();
3216 for (size_t i = 0; i < size; ++i) {
3217 CachedResource* resource = memoryCache()->resourceForURL(KURL(ParsedURLString, pastLoads[i]));
3219 // FIXME: These loads, loaded from cache, but now gone from the cache by the time
3220 // Page::setMemoryCacheClientCallsEnabled(true) is called, will not be seen by the client.
3221 // Consider if there's some efficient way of remembering enough to deliver this client call.
3222 // We have the URL, but not the rest of the response or the length.
3226 ResourceRequest request(resource->url());
3227 m_client->dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(), request, resource->response(), resource->encodedSize());
3231 NetworkingContext* FrameLoader::networkingContext() const
3233 return m_networkingContext.get();
3236 void FrameLoader::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
3238 MemoryClassInfo info(memoryObjectInfo, this, MemoryInstrumentation::Loader);
3239 info.addInstrumentedMember(m_documentLoader.get());
3240 info.addInstrumentedMember(m_provisionalDocumentLoader.get());
3241 info.addInstrumentedMember(m_policyDocumentLoader.get());
3242 info.addMember(m_outgoingReferrer);
3243 info.addInstrumentedHashSet(m_openedFrames);
3246 bool FrameLoaderClient::hasHTMLView() const
3251 Frame* createWindow(Frame* openerFrame, Frame* lookupFrame, const FrameLoadRequest& request, const WindowFeatures& features, bool& created)
3253 ASSERT(!features.dialog || request.frameName().isEmpty());
3255 if (!request.frameName().isEmpty() && request.frameName() != "_blank") {
3256 if (Frame* frame = lookupFrame->loader()->findFrameForNavigation(request.frameName(), openerFrame->document())) {
3257 if (Page* page = frame->page())
3258 page->chrome()->focus();
3264 // Sandboxed frames cannot open new auxiliary browsing contexts.
3265 if (isDocumentSandboxed(openerFrame, SandboxPopups))
3268 // FIXME: Setting the referrer should be the caller's responsibility.
3269 FrameLoadRequest requestWithReferrer = request;
3270 requestWithReferrer.resourceRequest().setHTTPReferrer(openerFrame->loader()->outgoingReferrer());
3271 FrameLoader::addHTTPOriginIfNeeded(requestWithReferrer.resourceRequest(), openerFrame->loader()->outgoingOrigin());
3273 Page* oldPage = openerFrame->page();
3277 NavigationAction action(requestWithReferrer.resourceRequest());
3278 Page* page = oldPage->chrome()->createWindow(openerFrame, requestWithReferrer, features, action);
3282 Frame* frame = page->mainFrame();
3284 frame->loader()->forceSandboxFlags(openerFrame->document()->sandboxFlags());
3286 if (request.frameName() != "_blank")
3287 frame->tree()->setName(request.frameName());
3289 page->chrome()->setToolbarsVisible(features.toolBarVisible || features.locationBarVisible);
3290 page->chrome()->setStatusbarVisible(features.statusBarVisible);
3291 page->chrome()->setScrollbarsVisible(features.scrollbarsVisible);
3292 page->chrome()->setMenubarVisible(features.menuBarVisible);
3293 page->chrome()->setResizable(features.resizable);
3295 // 'x' and 'y' specify the location of the window, while 'width' and 'height'
3296 // specify the size of the page. We can only resize the window, so
3297 // adjust for the difference between the window size and the page size.
3299 FloatRect windowRect = page->chrome()->windowRect();
3300 FloatSize pageSize = page->chrome()->pageRect().size();
3302 windowRect.setX(features.x);
3304 windowRect.setY(features.y);
3305 if (features.widthSet)
3306 windowRect.setWidth(features.width + (windowRect.width() - pageSize.width()));
3307 if (features.heightSet)
3308 windowRect.setHeight(features.height + (windowRect.height() - pageSize.height()));
3309 page->chrome()->setWindowRect(windowRect);
3311 page->chrome()->show();
3317 } // namespace WebCore