05c820623e6b268cc947cfa9fbd2b41cedc4a88a
[WebKit-https.git] / Source / WebCore / loader / FrameLoader.cpp
1 /*
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.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
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 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.
22  *
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.
33  */
34
35 #include "config.h"
36 #include "FrameLoader.h"
37
38 #include "AXObjectCache.h"
39 #include "ApplicationCacheHost.h"
40 #include "BackForwardController.h"
41 #include "BeforeUnloadEvent.h"
42 #include "CachedPage.h"
43 #include "CachedResourceLoader.h"
44 #include "Chrome.h"
45 #include "ChromeClient.h"
46 #include "ContentSecurityPolicy.h"
47 #include "DOMImplementation.h"
48 #include "DOMWindow.h"
49 #include "DatabaseManager.h"
50 #include "DiagnosticLoggingClient.h"
51 #include "DiagnosticLoggingKeys.h"
52 #include "Document.h"
53 #include "DocumentLoadTiming.h"
54 #include "DocumentLoader.h"
55 #include "Editor.h"
56 #include "EditorClient.h"
57 #include "Element.h"
58 #include "Event.h"
59 #include "EventHandler.h"
60 #include "EventNames.h"
61 #include "FloatRect.h"
62 #include "FormState.h"
63 #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 "HTMLInputElement.h"
72 #include "HTMLNames.h"
73 #include "HTMLObjectElement.h"
74 #include "HTMLParserIdioms.h"
75 #include "HTTPHeaderNames.h"
76 #include "HTTPParsers.h"
77 #include "HistoryController.h"
78 #include "HistoryItem.h"
79 #include "IconController.h"
80 #include "InspectorController.h"
81 #include "InspectorInstrumentation.h"
82 #include "LoaderStrategy.h"
83 #include "Logging.h"
84 #include "MIMETypeRegistry.h"
85 #include "MainFrame.h"
86 #include "MemoryCache.h"
87 #include "Page.h"
88 #include "PageCache.h"
89 #include "PageThrottler.h"
90 #include "PageTransitionEvent.h"
91 #include "PlatformStrategies.h"
92 #include "PluginData.h"
93 #include "PluginDocument.h"
94 #include "PolicyChecker.h"
95 #include "ProgressTracker.h"
96 #include "ResourceHandle.h"
97 #include "ResourceRequest.h"
98 #include "SVGDocument.h"
99 #include "SVGLocatable.h"
100 #include "SVGNames.h"
101 #include "SVGPreserveAspectRatio.h"
102 #include "SVGViewElement.h"
103 #include "SVGViewSpec.h"
104 #include "SchemeRegistry.h"
105 #include "ScriptController.h"
106 #include "ScriptSourceCode.h"
107 #include "ScrollAnimator.h"
108 #include "SecurityOrigin.h"
109 #include "SecurityPolicy.h"
110 #include "SegmentedString.h"
111 #include "SerializedScriptValue.h"
112 #include "Settings.h"
113 #include "SubframeLoader.h"
114 #include "TextResourceDecoder.h"
115 #include "WindowFeatures.h"
116 #include "XMLDocumentParser.h"
117 #include <wtf/CurrentTime.h>
118 #include <wtf/Ref.h>
119 #include <wtf/StdLibExtras.h>
120 #include <wtf/text/CString.h>
121 #include <wtf/text/WTFString.h>
122
123 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
124 #include "Archive.h"
125 #endif
126
127 #if PLATFORM(IOS)
128 #include "DocumentType.h"
129 #include "MemoryPressureHandler.h"
130 #include "ResourceLoader.h"
131 #include "RuntimeApplicationChecksIOS.h"
132 #include "SystemMemory.h"
133 #include "WKContentObservation.h"
134 #endif
135
136 namespace WebCore {
137
138 using namespace HTMLNames;
139 using namespace SVGNames;
140
141 static const char defaultAcceptHeader[] = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
142
143 #if PLATFORM(IOS)
144 const int memoryLevelThresholdToPrunePageCache = 20;
145 #endif
146
147 bool isBackForwardLoadType(FrameLoadType type)
148 {
149     switch (type) {
150     case FrameLoadType::Standard:
151     case FrameLoadType::Reload:
152     case FrameLoadType::ReloadFromOrigin:
153     case FrameLoadType::Same:
154     case FrameLoadType::RedirectWithLockedBackForwardList:
155     case FrameLoadType::Replace:
156         return false;
157     case FrameLoadType::Back:
158     case FrameLoadType::Forward:
159     case FrameLoadType::IndexedBackForward:
160         return true;
161     }
162     ASSERT_NOT_REACHED();
163     return false;
164 }
165
166 // This is not in the FrameLoader class to emphasize that it does not depend on
167 // private FrameLoader data, and to avoid increasing the number of public functions
168 // with access to private data.  Since only this .cpp file needs it, making it
169 // non-member lets us exclude it from the header file, thus keeping FrameLoader.h's
170 // API simpler.
171 //
172 static bool isDocumentSandboxed(Frame* frame, SandboxFlags mask)
173 {
174     return frame->document() && frame->document()->isSandboxed(mask);
175 }
176
177 class FrameLoader::FrameProgressTracker {
178 public:
179     explicit FrameProgressTracker(Frame& frame)
180         : m_frame(frame)
181         , m_inProgress(false)
182     {
183     }
184
185     ~FrameProgressTracker()
186     {
187         if (m_inProgress && m_frame.page())
188             m_frame.page()->progress().progressCompleted(m_frame);
189     }
190
191     void progressStarted()
192     {
193         ASSERT(m_frame.page());
194         if (!m_inProgress)
195             m_frame.page()->progress().progressStarted(m_frame);
196         m_inProgress = true;
197     }
198
199     void progressCompleted()
200     {
201         ASSERT(m_inProgress);
202         ASSERT(m_frame.page());
203         m_inProgress = false;
204         m_frame.page()->progress().progressCompleted(m_frame);
205     }
206
207 private:
208     Frame& m_frame;
209     bool m_inProgress;
210 };
211
212 FrameLoader::FrameLoader(Frame& frame, FrameLoaderClient& client)
213     : m_frame(frame)
214     , m_client(client)
215     , m_policyChecker(std::make_unique<PolicyChecker>(frame))
216     , m_history(std::make_unique<HistoryController>(frame))
217     , m_notifier(frame)
218     , m_subframeLoader(std::make_unique<SubframeLoader>(frame))
219     , m_icon(std::make_unique<IconController>(frame))
220     , m_mixedContentChecker(frame)
221     , m_state(FrameStateProvisional)
222     , m_loadType(FrameLoadType::Standard)
223     , m_delegateIsHandlingProvisionalLoadError(false)
224     , m_quickRedirectComing(false)
225     , m_sentRedirectNotification(false)
226     , m_inStopAllLoaders(false)
227     , m_isExecutingJavaScriptFormAction(false)
228     , m_didCallImplicitClose(true)
229     , m_wasUnloadEventEmitted(false)
230     , m_pageDismissalEventBeingDispatched(NoDismissal)
231     , m_isComplete(false)
232     , m_needsClear(false)
233     , m_checkTimer(*this, &FrameLoader::checkTimerFired)
234     , m_shouldCallCheckCompleted(false)
235     , m_shouldCallCheckLoadComplete(false)
236     , m_opener(nullptr)
237     , m_loadingFromCachedPage(false)
238     , m_currentNavigationHasShownBeforeUnloadConfirmPanel(false)
239     , m_loadsSynchronously(false)
240     , m_forcedSandboxFlags(SandboxNone)
241 {
242 }
243
244 FrameLoader::~FrameLoader()
245 {
246     setOpener(nullptr);
247
248     HashSet<Frame*>::iterator end = m_openedFrames.end();
249     for (HashSet<Frame*>::iterator it = m_openedFrames.begin(); it != end; ++it)
250         (*it)->loader().m_opener = 0;
251
252     m_client.frameLoaderDestroyed();
253
254     if (m_networkingContext)
255         m_networkingContext->invalidate();
256 }
257
258 void FrameLoader::init()
259 {
260     // This somewhat odd set of steps gives the frame an initial empty document.
261     setPolicyDocumentLoader(m_client.createDocumentLoader(ResourceRequest(URL(ParsedURLString, emptyString())), SubstituteData()).get());
262     setProvisionalDocumentLoader(m_policyDocumentLoader.get());
263     m_provisionalDocumentLoader->startLoadingMainResource();
264
265     Ref<Frame> protect(m_frame);
266     m_frame.document()->cancelParsing();
267     m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocument);
268
269     m_networkingContext = m_client.createNetworkingContext();
270     m_progressTracker = std::make_unique<FrameProgressTracker>(m_frame);
271 }
272
273 #if PLATFORM(IOS)
274 void FrameLoader::initForSynthesizedDocument(const URL&)
275 {
276     // FIXME: We need to initialize the document URL to the specified URL. Currently the URL is empty and hence
277     // FrameLoader::checkCompleted() will overwrite the URL of the document to be activeDocumentLoader()->documentURL().
278
279     RefPtr<DocumentLoader> loader = m_client.createDocumentLoader(ResourceRequest(URL(ParsedURLString, emptyString())), SubstituteData());
280     loader->setFrame(&m_frame);
281     loader->setResponse(ResourceResponse(URL(), ASCIILiteral("text/html"), 0, String()));
282     loader->setCommitted(true);
283     setDocumentLoader(loader.get());
284
285     m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocument);
286     m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit);
287     m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
288     m_client.transitionToCommittedForNewPage();
289
290     m_didCallImplicitClose = true;
291     m_isComplete = true;
292     m_state = FrameStateComplete;
293     m_needsClear = true;
294
295     m_networkingContext = m_client.createNetworkingContext();
296     m_progressTracker = std::make_unique<FrameProgressTracker>(m_frame);
297 }
298 #endif
299
300 void FrameLoader::setDefersLoading(bool defers)
301 {
302     if (m_documentLoader)
303         m_documentLoader->setDefersLoading(defers);
304     if (m_provisionalDocumentLoader)
305         m_provisionalDocumentLoader->setDefersLoading(defers);
306     if (m_policyDocumentLoader)
307         m_policyDocumentLoader->setDefersLoading(defers);
308     history().setDefersLoading(defers);
309
310     if (!defers) {
311         m_frame.navigationScheduler().startTimer();
312         startCheckCompleteTimer();
313     }
314 }
315
316 void FrameLoader::changeLocation(SecurityOrigin* securityOrigin, const URL& url, const String& referrer, LockHistory lockHistory, LockBackForwardList lockBackForwardList, bool refresh, AllowNavigationToInvalidURL allowNavigationToInvalidURL)
317 {
318     urlSelected(FrameLoadRequest(securityOrigin, ResourceRequest(url, referrer, refresh ? ReloadIgnoringCacheData : UseProtocolCachePolicy), "_self"),
319         0, lockHistory, lockBackForwardList, MaybeSendReferrer, ReplaceDocumentIfJavaScriptURL, allowNavigationToInvalidURL);
320 }
321
322 void FrameLoader::urlSelected(const URL& url, const String& passedTarget, PassRefPtr<Event> triggeringEvent, LockHistory lockHistory, LockBackForwardList lockBackForwardList, ShouldSendReferrer shouldSendReferrer)
323 {
324     urlSelected(FrameLoadRequest(m_frame.document()->securityOrigin(), ResourceRequest(url), passedTarget),
325         triggeringEvent, lockHistory, lockBackForwardList, shouldSendReferrer, DoNotReplaceDocumentIfJavaScriptURL, AllowNavigationToInvalidURL::Yes);
326 }
327
328 // The shouldReplaceDocumentIfJavaScriptURL parameter will go away when the FIXME to eliminate the
329 // corresponding parameter from ScriptController::executeIfJavaScriptURL() is addressed.
330 void FrameLoader::urlSelected(const FrameLoadRequest& passedRequest, PassRefPtr<Event> triggeringEvent, LockHistory lockHistory, LockBackForwardList lockBackForwardList, ShouldSendReferrer shouldSendReferrer, ShouldReplaceDocumentIfJavaScriptURL shouldReplaceDocumentIfJavaScriptURL, AllowNavigationToInvalidURL allowNavigationToInvalidURL)
331 {
332     Ref<Frame> protect(m_frame);
333     FrameLoadRequest frameRequest(passedRequest);
334
335     if (m_frame.script().executeIfJavaScriptURL(frameRequest.resourceRequest().url(), shouldReplaceDocumentIfJavaScriptURL))
336         return;
337
338     if (frameRequest.frameName().isEmpty())
339         frameRequest.setFrameName(m_frame.document()->baseTarget());
340
341     addHTTPOriginIfNeeded(frameRequest.resourceRequest(), outgoingOrigin());
342
343     NewFrameOpenerPolicy openerPolicy = (shouldSendReferrer == NeverSendReferrer) ? NewFrameOpenerPolicy::Suppress : NewFrameOpenerPolicy::Allow;
344
345     loadFrameRequest(frameRequest, lockHistory, lockBackForwardList, triggeringEvent, 0, shouldSendReferrer, allowNavigationToInvalidURL, openerPolicy);
346 }
347
348 void FrameLoader::submitForm(PassRefPtr<FormSubmission> submission)
349 {
350     ASSERT(submission->method() == FormSubmission::PostMethod || submission->method() == FormSubmission::GetMethod);
351
352     // FIXME: Find a good spot for these.
353     ASSERT(submission->data());
354     ASSERT(submission->state());
355     ASSERT(!submission->state()->sourceDocument()->frame() || submission->state()->sourceDocument()->frame() == &m_frame);
356     
357     if (!m_frame.page())
358         return;
359     
360     if (submission->action().isEmpty())
361         return;
362
363     if (isDocumentSandboxed(&m_frame, SandboxForms)) {
364         // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists.
365         m_frame.document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, "Blocked form submission to '" + submission->action().stringCenterEllipsizedToLength() + "' because the form's frame is sandboxed and the 'allow-forms' permission is not set.");
366         return;
367     }
368
369     if (protocolIsJavaScript(submission->action())) {
370         if (!m_frame.document()->contentSecurityPolicy()->allowFormAction(URL(submission->action())))
371             return;
372         m_isExecutingJavaScriptFormAction = true;
373         Ref<Frame> protect(m_frame);
374         m_frame.script().executeIfJavaScriptURL(submission->action(), DoNotReplaceDocumentIfJavaScriptURL);
375         m_isExecutingJavaScriptFormAction = false;
376         return;
377     }
378
379     Frame* targetFrame = findFrameForNavigation(submission->target(), submission->state()->sourceDocument());
380     if (!targetFrame) {
381         if (!DOMWindow::allowPopUp(&m_frame) && !ScriptController::processingUserGesture())
382             return;
383
384         // FIXME: targetFrame can be 0 for two distinct reasons:
385         // 1. The frame was not found by name, so we should try opening a new window.
386         // 2. The frame was found, but navigating it was not allowed, e.g. by HTML5 sandbox or by origin checks.
387         // Continuing form submission makes no sense in the latter case.
388         // There is a repeat check after timer fires, so this is not a correctness issue.
389
390         targetFrame = &m_frame;
391     } else
392         submission->clearTarget();
393
394     if (!targetFrame->page())
395         return;
396
397     // FIXME: We'd like to remove this altogether and fix the multiple form submission issue another way.
398
399     // We do not want to submit more than one form from the same page, nor do we want to submit a single
400     // form more than once. This flag prevents these from happening; not sure how other browsers prevent this.
401     // The flag is reset in each time we start handle a new mouse or key down event, and
402     // also in setView since this part may get reused for a page from the back/forward cache.
403     // The form multi-submit logic here is only needed when we are submitting a form that affects this frame.
404
405     // FIXME: Frame targeting is only one of the ways the submission could end up doing something other
406     // than replacing this frame's content, so this check is flawed. On the other hand, the check is hardly
407     // needed any more now that we reset m_submittedFormURL on each mouse or key down event.
408
409     if (m_frame.tree().isDescendantOf(targetFrame)) {
410         if (m_submittedFormURL == submission->requestURL())
411             return;
412         m_submittedFormURL = submission->requestURL();
413     }
414
415     submission->data()->generateFiles(m_frame.document());
416     submission->setReferrer(outgoingReferrer());
417     submission->setOrigin(outgoingOrigin());
418
419     targetFrame->navigationScheduler().scheduleFormSubmission(submission);
420 }
421
422 void FrameLoader::stopLoading(UnloadEventPolicy unloadEventPolicy)
423 {
424     if (m_frame.document() && m_frame.document()->parser())
425         m_frame.document()->parser()->stopParsing();
426
427     if (unloadEventPolicy != UnloadEventPolicyNone) {
428         if (m_frame.document()) {
429             if (m_didCallImplicitClose && !m_wasUnloadEventEmitted) {
430                 Element* currentFocusedElement = m_frame.document()->focusedElement();
431                 if (currentFocusedElement && currentFocusedElement->toInputElement())
432                     currentFocusedElement->toInputElement()->endEditing();
433                 if (m_pageDismissalEventBeingDispatched == NoDismissal) {
434                     if (unloadEventPolicy == UnloadEventPolicyUnloadAndPageHide) {
435                         m_pageDismissalEventBeingDispatched = PageHideDismissal;
436                         m_frame.document()->domWindow()->dispatchEvent(PageTransitionEvent::create(eventNames().pagehideEvent, m_frame.document()->inPageCache()), m_frame.document());
437                     }
438
439                     // FIXME: update Page Visibility state here.
440                     // https://bugs.webkit.org/show_bug.cgi?id=116770
441
442                     if (!m_frame.document()->inPageCache()) {
443                         RefPtr<Event> unloadEvent(Event::create(eventNames().unloadEvent, false, false));
444                         // The DocumentLoader (and thus its DocumentLoadTiming) might get destroyed
445                         // while dispatching the event, so protect it to prevent writing the end
446                         // time into freed memory.
447                         RefPtr<DocumentLoader> documentLoader = m_provisionalDocumentLoader;
448                         m_pageDismissalEventBeingDispatched = UnloadDismissal;
449                         if (documentLoader && !documentLoader->timing().unloadEventStart() && !documentLoader->timing().unloadEventEnd()) {
450                             DocumentLoadTiming& timing = documentLoader->timing();
451                             ASSERT(timing.navigationStart());
452                             timing.markUnloadEventStart();
453                             m_frame.document()->domWindow()->dispatchEvent(unloadEvent, m_frame.document());
454                             timing.markUnloadEventEnd();
455                         } else
456                             m_frame.document()->domWindow()->dispatchEvent(unloadEvent, m_frame.document());
457                     }
458                 }
459                 m_pageDismissalEventBeingDispatched = NoDismissal;
460                 if (m_frame.document())
461                     m_frame.document()->updateStyleIfNeeded();
462                 m_wasUnloadEventEmitted = true;
463             }
464         }
465
466         // Dispatching the unload event could have made m_frame.document() null.
467         if (m_frame.document() && !m_frame.document()->inPageCache()) {
468             // Don't remove event listeners from a transitional empty document (see bug 28716 for more information).
469             bool keepEventListeners = m_stateMachine.isDisplayingInitialEmptyDocument() && m_provisionalDocumentLoader
470                 && m_frame.document()->isSecureTransitionTo(m_provisionalDocumentLoader->url());
471
472             if (!keepEventListeners)
473                 m_frame.document()->removeAllEventListeners();
474         }
475     }
476
477     m_isComplete = true; // to avoid calling completed() in finishedParsing()
478     m_didCallImplicitClose = true; // don't want that one either
479
480     if (m_frame.document() && m_frame.document()->parsing()) {
481         finishedParsing();
482         m_frame.document()->setParsing(false);
483     }
484
485     if (Document* doc = m_frame.document()) {
486         // FIXME: HTML5 doesn't tell us to set the state to complete when aborting, but we do anyway to match legacy behavior.
487         // http://www.w3.org/Bugs/Public/show_bug.cgi?id=10537
488         doc->setReadyState(Document::Complete);
489
490         // FIXME: Should the DatabaseManager watch for something like ActiveDOMObject::stop() rather than being special-cased here?
491         DatabaseManager::manager().stopDatabases(doc, 0);
492     }
493
494     // FIXME: This will cancel redirection timer, which really needs to be restarted when restoring the frame from b/f cache.
495     m_frame.navigationScheduler().cancel();
496 }
497
498 void FrameLoader::stop()
499 {
500     // http://bugs.webkit.org/show_bug.cgi?id=10854
501     // The frame's last ref may be removed and it will be deleted by checkCompleted().
502     Ref<Frame> protect(m_frame);
503
504     if (DocumentParser* parser = m_frame.document()->parser()) {
505         parser->stopParsing();
506         parser->finish();
507     }
508     
509     icon().stopLoader();
510 }
511
512 void FrameLoader::willTransitionToCommitted()
513 {
514     // This function is called when a frame is still fully in place (not cached, not detached), but will be replaced.
515
516     if (m_frame.editor().hasComposition()) {
517         // The text was already present in DOM, so it's better to confirm than to cancel the composition.
518         m_frame.editor().confirmComposition();
519         if (EditorClient* editorClient = m_frame.editor().client()) {
520             editorClient->respondToChangedSelection(&m_frame);
521             editorClient->discardedComposition(&m_frame);
522         }
523     }
524 }
525
526 bool FrameLoader::closeURL()
527 {
528     history().saveDocumentState();
529
530     Document* currentDocument = m_frame.document();
531     UnloadEventPolicy unloadEventPolicy;
532     if (m_frame.page() && m_frame.page()->chrome().client().isSVGImageChromeClient()) {
533         // If this is the SVGDocument of an SVGImage, no need to dispatch events or recalcStyle.
534         unloadEventPolicy = UnloadEventPolicyNone;
535     } else {
536         // Should only send the pagehide event here if the current document exists and has not been placed in the page cache.
537         unloadEventPolicy = currentDocument && !currentDocument->inPageCache() ? UnloadEventPolicyUnloadAndPageHide : UnloadEventPolicyUnloadOnly;
538     }
539
540     stopLoading(unloadEventPolicy);
541     
542     m_frame.editor().clearUndoRedoOperations();
543     return true;
544 }
545
546 bool FrameLoader::didOpenURL()
547 {
548     if (m_frame.navigationScheduler().redirectScheduledDuringLoad()) {
549         // A redirect was scheduled before the document was created.
550         // This can happen when one frame changes another frame's location.
551         return false;
552     }
553
554     m_frame.navigationScheduler().cancel();
555     m_frame.editor().clearLastEditCommand();
556
557     m_isComplete = false;
558     m_didCallImplicitClose = false;
559
560     // If we are still in the process of initializing an empty document then
561     // its frame is not in a consistent state for rendering, so avoid setJSStatusBarText
562     // since it may cause clients to attempt to render the frame.
563     if (!m_stateMachine.creatingInitialEmptyDocument()) {
564         DOMWindow* window = m_frame.document()->domWindow();
565         window->setStatus(String());
566         window->setDefaultStatus(String());
567     }
568
569     started();
570
571     return true;
572 }
573
574 void FrameLoader::didExplicitOpen()
575 {
576     m_isComplete = false;
577     m_didCallImplicitClose = false;
578
579     // Calling document.open counts as committing the first real document load.
580     if (!m_stateMachine.committedFirstRealDocumentLoad())
581         m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit);
582     
583     // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
584     // from a subsequent window.document.open / window.document.write call. 
585     // Canceling redirection here works for all cases because document.open 
586     // implicitly precedes document.write.
587     m_frame.navigationScheduler().cancel();
588 }
589
590
591 void FrameLoader::cancelAndClear()
592 {
593     m_frame.navigationScheduler().cancel();
594
595     if (!m_isComplete)
596         closeURL();
597
598     clear(m_frame.document(), false);
599     m_frame.script().updatePlatformScriptObjects();
600 }
601
602 void FrameLoader::clear(Document* newDocument, bool clearWindowProperties, bool clearScriptObjects, bool clearFrameView)
603 {
604     m_frame.editor().clear();
605
606     if (!m_needsClear)
607         return;
608     m_needsClear = false;
609     
610     if (!m_frame.document()->inPageCache()) {
611         m_frame.document()->cancelParsing();
612         m_frame.document()->stopActiveDOMObjects();
613         bool hadLivingRenderTree = m_frame.document()->hasLivingRenderTree();
614         m_frame.document()->prepareForDestruction();
615         if (hadLivingRenderTree)
616             m_frame.document()->removeFocusedNodeOfSubtree(m_frame.document());
617     }
618
619     // Do this after detaching the document so that the unload event works.
620     if (clearWindowProperties) {
621         InspectorInstrumentation::frameWindowDiscarded(&m_frame, m_frame.document()->domWindow());
622         m_frame.document()->domWindow()->resetUnlessSuspendedForPageCache();
623         m_frame.script().clearWindowShell(newDocument->domWindow(), m_frame.document()->inPageCache());
624     }
625
626     m_frame.selection().prepareForDestruction();
627     m_frame.eventHandler().clear();
628     if (clearFrameView && m_frame.view())
629         m_frame.view()->clear();
630
631     // Do not drop the document before the ScriptController and view are cleared
632     // as some destructors might still try to access the document.
633     m_frame.setDocument(0);
634
635     subframeLoader().clear();
636
637     if (clearScriptObjects)
638         m_frame.script().clearScriptObjects();
639
640     m_frame.script().enableEval();
641
642     m_frame.navigationScheduler().clear();
643
644     m_checkTimer.stop();
645     m_shouldCallCheckCompleted = false;
646     m_shouldCallCheckLoadComplete = false;
647
648     if (m_stateMachine.isDisplayingInitialEmptyDocument() && m_stateMachine.committedFirstRealDocumentLoad())
649         m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
650 }
651
652 void FrameLoader::receivedFirstData()
653 {
654     dispatchDidCommitLoad();
655     dispatchDidClearWindowObjectsInAllWorlds();
656     dispatchGlobalObjectAvailableInAllWorlds();
657
658     if (m_documentLoader) {
659         StringWithDirection ptitle = m_documentLoader->title();
660         // If we have a title let the WebView know about it.
661         if (!ptitle.isNull())
662             m_client.dispatchDidReceiveTitle(ptitle);
663     }
664
665     if (!m_documentLoader)
666         return;
667
668     double delay;
669     String urlString;
670     if (!parseHTTPRefresh(m_documentLoader->response().httpHeaderField(HTTPHeaderName::Refresh), false, delay, urlString))
671         return;
672     URL completedURL;
673     if (urlString.isEmpty())
674         completedURL = m_frame.document()->url();
675     else
676         completedURL = m_frame.document()->completeURL(urlString);
677
678     if (!protocolIsJavaScript(completedURL))
679         m_frame.navigationScheduler().scheduleRedirect(delay, completedURL);
680     else {
681         String message = "Refused to refresh " + m_frame.document()->url().stringCenterEllipsizedToLength() + " to a javascript: URL";
682         m_frame.document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, message);
683     }
684 }
685
686 void FrameLoader::setOutgoingReferrer(const URL& url)
687 {
688     m_outgoingReferrer = url.strippedForUseAsReferrer();
689 }
690
691 void FrameLoader::didBeginDocument(bool dispatch)
692 {
693     m_needsClear = true;
694     m_isComplete = false;
695     m_didCallImplicitClose = false;
696     m_frame.document()->setReadyState(Document::Loading);
697
698     if (m_pendingStateObject) {
699         m_frame.document()->statePopped(m_pendingStateObject.get());
700         m_pendingStateObject.clear();
701     }
702
703     if (dispatch)
704         dispatchDidClearWindowObjectsInAllWorlds();
705
706     updateFirstPartyForCookies();
707     m_frame.document()->initContentSecurityPolicy();
708
709     const Settings& settings = m_frame.settings();
710     m_frame.document()->cachedResourceLoader().setImagesEnabled(settings.areImagesEnabled());
711     m_frame.document()->cachedResourceLoader().setAutoLoadImages(settings.loadsImagesAutomatically());
712
713     if (m_documentLoader) {
714         String dnsPrefetchControl = m_documentLoader->response().httpHeaderField(HTTPHeaderName::XDNSPrefetchControl);
715         if (!dnsPrefetchControl.isEmpty())
716             m_frame.document()->parseDNSPrefetchControlHeader(dnsPrefetchControl);
717
718         String policyValue = m_documentLoader->response().httpHeaderField(HTTPHeaderName::ContentSecurityPolicy);
719         if (!policyValue.isEmpty())
720             m_frame.document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::Enforce);
721
722         policyValue = m_documentLoader->response().httpHeaderField(HTTPHeaderName::ContentSecurityPolicyReportOnly);
723         if (!policyValue.isEmpty())
724             m_frame.document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::Report);
725
726         policyValue = m_documentLoader->response().httpHeaderField(HTTPHeaderName::XWebKitCSP);
727         if (!policyValue.isEmpty())
728             m_frame.document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::PrefixedEnforce);
729
730         policyValue = m_documentLoader->response().httpHeaderField(HTTPHeaderName::XWebKitCSPReportOnly);
731         if (!policyValue.isEmpty())
732             m_frame.document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::PrefixedReport);
733
734         String headerContentLanguage = m_documentLoader->response().httpHeaderField(HTTPHeaderName::ContentLanguage);
735         if (!headerContentLanguage.isEmpty()) {
736             size_t commaIndex = headerContentLanguage.find(',');
737             headerContentLanguage.truncate(commaIndex); // notFound == -1 == don't truncate
738             headerContentLanguage = headerContentLanguage.stripWhiteSpace(isHTMLSpace);
739             if (!headerContentLanguage.isEmpty())
740                 m_frame.document()->setContentLanguage(headerContentLanguage);
741         }
742     }
743
744     history().restoreDocumentState();
745 }
746
747 void FrameLoader::finishedParsing()
748 {
749     m_frame.injectUserScripts(InjectAtDocumentEnd);
750
751     if (m_stateMachine.creatingInitialEmptyDocument())
752         return;
753
754     // This can be called from the Frame's destructor, in which case we shouldn't protect ourselves
755     // because doing so will cause us to re-enter the destructor when protector goes out of scope.
756     // Null-checking the FrameView indicates whether or not we're in the destructor.
757     RefPtr<Frame> protector = m_frame.view() ? &m_frame : 0;
758
759     m_client.dispatchDidFinishDocumentLoad();
760
761     checkCompleted();
762
763     if (!m_frame.view())
764         return; // We are being destroyed by something checkCompleted called.
765
766     // Check if the scrollbars are really needed for the content.
767     // If not, remove them, relayout, and repaint.
768     m_frame.view()->restoreScrollbar();
769     scrollToFragmentWithParentBoundary(m_frame.document()->url());
770 }
771
772 void FrameLoader::loadDone()
773 {
774     checkCompleted();
775 }
776
777 bool FrameLoader::allChildrenAreComplete() const
778 {
779     for (Frame* child = m_frame.tree().firstChild(); child; child = child->tree().nextSibling()) {
780         if (!child->loader().m_isComplete)
781             return false;
782     }
783     return true;
784 }
785
786 bool FrameLoader::allAncestorsAreComplete() const
787 {
788     for (Frame* ancestor = &m_frame; ancestor; ancestor = ancestor->tree().parent()) {
789         if (!ancestor->loader().m_isComplete)
790             return false;
791     }
792     return true;
793 }
794
795 void FrameLoader::checkCompleted()
796 {
797     m_shouldCallCheckCompleted = false;
798
799     // Have we completed before?
800     if (m_isComplete)
801         return;
802
803     // Are we still parsing?
804     if (m_frame.document()->parsing())
805         return;
806
807     // Still waiting for images/scripts?
808     if (m_frame.document()->cachedResourceLoader().requestCount())
809         return;
810
811     // Still waiting for elements that don't go through a FrameLoader?
812     if (m_frame.document()->isDelayingLoadEvent())
813         return;
814
815     // Any frame that hasn't completed yet?
816     if (!allChildrenAreComplete())
817         return;
818
819     // Important not to protect earlier in this function, because earlier parts
820     // of this function can be called in the frame's destructor, and it's not legal
821     // to ref an object while it's being destroyed.
822     Ref<Frame> protect(m_frame);
823
824     // OK, completed.
825     m_isComplete = true;
826     m_requestedHistoryItem = 0;
827     m_frame.document()->setReadyState(Document::Complete);
828
829 #if PLATFORM(IOS)
830     if (m_frame.document()->url().isEmpty()) {
831         // We need to update the document URL of a PDF document to be non-empty so that both back/forward history navigation
832         // between PDF pages and fragment navigation works. See <rdar://problem/9544769> for more details.
833         // FIXME: Is there a better place for this code, say DocumentLoader? Also, we should explicitly only update the URL
834         // of the document when it's a PDFDocument object instead of assuming that a Document object with an empty URL is a PDFDocument.
835         // FIXME: This code is incorrect for a synthesized document (which also has an empty URL). The URL for a synthesized
836         // document should be the URL specified to FrameLoader::initForSynthesizedDocument().
837         m_frame.document()->setURL(activeDocumentLoader()->documentURL());
838     }
839 #endif
840
841     checkCallImplicitClose(); // if we didn't do it before
842
843     m_frame.navigationScheduler().startTimer();
844
845     completed();
846     if (m_frame.page())
847         checkLoadComplete();
848 }
849
850 void FrameLoader::checkTimerFired()
851 {
852     Ref<Frame> protect(m_frame);
853
854     if (Page* page = m_frame.page()) {
855         if (page->defersLoading())
856             return;
857     }
858     if (m_shouldCallCheckCompleted)
859         checkCompleted();
860     if (m_shouldCallCheckLoadComplete)
861         checkLoadComplete();
862 }
863
864 void FrameLoader::startCheckCompleteTimer()
865 {
866     if (!(m_shouldCallCheckCompleted || m_shouldCallCheckLoadComplete))
867         return;
868     if (m_checkTimer.isActive())
869         return;
870     m_checkTimer.startOneShot(0);
871 }
872
873 void FrameLoader::scheduleCheckCompleted()
874 {
875     m_shouldCallCheckCompleted = true;
876     startCheckCompleteTimer();
877 }
878
879 void FrameLoader::scheduleCheckLoadComplete()
880 {
881     m_shouldCallCheckLoadComplete = true;
882     startCheckCompleteTimer();
883 }
884
885 void FrameLoader::checkCallImplicitClose()
886 {
887     if (m_didCallImplicitClose || m_frame.document()->parsing() || m_frame.document()->isDelayingLoadEvent())
888         return;
889
890     if (!allChildrenAreComplete())
891         return; // still got a frame running -> too early
892
893     m_didCallImplicitClose = true;
894     m_wasUnloadEventEmitted = false;
895     m_frame.document()->implicitClose();
896 }
897
898 void FrameLoader::loadURLIntoChildFrame(const URL& url, const String& referer, Frame* childFrame)
899 {
900     ASSERT(childFrame);
901
902 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
903     RefPtr<Archive> subframeArchive = activeDocumentLoader()->popArchiveForSubframe(childFrame->tree().uniqueName(), url);
904     if (subframeArchive) {
905         childFrame->loader().loadArchive(subframeArchive.release());
906         return;
907     }
908 #endif // ENABLE(WEB_ARCHIVE)
909
910     HistoryItem* parentItem = history().currentItem();
911     // If we're moving in the back/forward list, we might want to replace the content
912     // of this child frame with whatever was there at that point.
913     if (parentItem && parentItem->children().size() && isBackForwardLoadType(loadType()) 
914         && !m_frame.document()->loadEventFinished()) {
915         HistoryItem* childItem = parentItem->childItemWithTarget(childFrame->tree().uniqueName());
916         if (childItem) {
917             childFrame->loader().m_requestedHistoryItem = childItem;
918             childFrame->loader().loadDifferentDocumentItem(*childItem, loadType(), MayAttemptCacheOnlyLoadForFormSubmissionItem);
919             return;
920         }
921     }
922
923     childFrame->loader().loadURL(url, referer, "_self", LockHistory::No, FrameLoadType::RedirectWithLockedBackForwardList, 0, 0, AllowNavigationToInvalidURL::Yes, NewFrameOpenerPolicy::Suppress);
924 }
925
926 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
927 void FrameLoader::loadArchive(PassRefPtr<Archive> archive)
928 {
929     ArchiveResource* mainResource = archive->mainResource();
930     ASSERT(mainResource);
931     if (!mainResource)
932         return;
933         
934     SubstituteData substituteData(mainResource->data(), mainResource->mimeType(), mainResource->textEncoding(), URL());
935     
936     ResourceRequest request(mainResource->url());
937 #if PLATFORM(MAC)
938     request.applyWebArchiveHackForMail();
939 #endif
940
941     RefPtr<DocumentLoader> documentLoader = m_client.createDocumentLoader(request, substituteData);
942     documentLoader->setArchive(archive.get());
943     load(documentLoader.get());
944 }
945 #endif // ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
946
947 String FrameLoader::outgoingReferrer() const
948 {
949     // See http://www.whatwg.org/specs/web-apps/current-work/#fetching-resources
950     // for why we walk the parent chain for srcdoc documents.
951     Frame* frame = &m_frame;
952     while (frame->document()->isSrcdocDocument()) {
953         frame = frame->tree().parent();
954         // Srcdoc documents cannot be top-level documents, by definition,
955         // because they need to be contained in iframes with the srcdoc.
956         ASSERT(frame);
957     }
958     return frame->loader().m_outgoingReferrer;
959 }
960
961 String FrameLoader::outgoingOrigin() const
962 {
963     return m_frame.document()->securityOrigin()->toString();
964 }
965
966 bool FrameLoader::checkIfFormActionAllowedByCSP(const URL& url) const
967 {
968     if (m_submittedFormURL.isEmpty())
969         return true;
970
971     return m_frame.document()->contentSecurityPolicy()->allowFormAction(url);
972 }
973
974 Frame* FrameLoader::opener()
975 {
976     return m_opener;
977 }
978
979 void FrameLoader::setOpener(Frame* opener)
980 {
981     if (m_opener && !opener)
982         m_client.didDisownOpener();
983
984     if (m_opener)
985         m_opener->loader().m_openedFrames.remove(&m_frame);
986     if (opener)
987         opener->loader().m_openedFrames.add(&m_frame);
988     m_opener = opener;
989
990     if (m_frame.document())
991         m_frame.document()->initSecurityContext();
992 }
993
994 // FIXME: This does not belong in FrameLoader!
995 void FrameLoader::handleFallbackContent()
996 {
997     HTMLFrameOwnerElement* owner = m_frame.ownerElement();
998     if (!is<HTMLObjectElement>(owner))
999         return;
1000     downcast<HTMLObjectElement>(*owner).renderFallbackContent();
1001 }
1002
1003 void FrameLoader::provisionalLoadStarted()
1004 {
1005     if (m_stateMachine.firstLayoutDone())
1006         m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
1007     m_frame.navigationScheduler().cancel(true);
1008     m_client.provisionalLoadStarted();
1009 }
1010
1011 void FrameLoader::resetMultipleFormSubmissionProtection()
1012 {
1013     m_submittedFormURL = URL();
1014 }
1015
1016 void FrameLoader::updateFirstPartyForCookies()
1017 {
1018     if (m_frame.tree().parent())
1019         setFirstPartyForCookies(m_frame.tree().parent()->document()->firstPartyForCookies());
1020     else
1021         setFirstPartyForCookies(m_frame.document()->url());
1022 }
1023
1024 void FrameLoader::setFirstPartyForCookies(const URL& url)
1025 {
1026     for (Frame* frame = &m_frame; frame; frame = frame->tree().traverseNext(&m_frame))
1027         frame->document()->setFirstPartyForCookies(url);
1028 }
1029
1030 // This does the same kind of work that didOpenURL does, except it relies on the fact
1031 // that a higher level already checked that the URLs match and the scrolling is the right thing to do.
1032 void FrameLoader::loadInSameDocument(const URL& url, PassRefPtr<SerializedScriptValue> stateObject, bool isNewNavigation)
1033 {
1034     // If we have a state object, we cannot also be a new navigation.
1035     ASSERT(!stateObject || (stateObject && !isNewNavigation));
1036
1037     // Update the data source's request with the new URL to fake the URL change
1038     URL oldURL = m_frame.document()->url();
1039     m_frame.document()->setURL(url);
1040     setOutgoingReferrer(url);
1041     documentLoader()->replaceRequestURLForSameDocumentNavigation(url);
1042     if (isNewNavigation && !shouldTreatURLAsSameAsCurrent(url) && !stateObject) {
1043         // NB: must happen after replaceRequestURLForSameDocumentNavigation(), since we add 
1044         // based on the current request. Must also happen before we openURL and displace the 
1045         // scroll position, since adding the BF item will save away scroll state.
1046         
1047         // NB2: If we were loading a long, slow doc, and the user fragment navigated before
1048         // it was done, currItem is now set the that slow doc, and prevItem is whatever was
1049         // before it.  Adding the b/f item will bump the slow doc down to prevItem, even
1050         // though its load is not yet done.  I think this all works out OK, for one because
1051         // we have already saved away the scroll and doc state for the long slow load,
1052         // but it's not an obvious case.
1053
1054         history().updateBackForwardListForFragmentScroll();
1055     }
1056     
1057     bool hashChange = equalIgnoringFragmentIdentifier(url, oldURL) && url.fragmentIdentifier() != oldURL.fragmentIdentifier();
1058     
1059     history().updateForSameDocumentNavigation();
1060
1061     // If we were in the autoscroll/panScroll mode we want to stop it before following the link to the anchor
1062     if (hashChange)
1063         m_frame.eventHandler().stopAutoscrollTimer();
1064     
1065     // It's important to model this as a load that starts and immediately finishes.
1066     // Otherwise, the parent frame may think we never finished loading.
1067     started();
1068
1069     // We need to scroll to the fragment whether or not a hash change occurred, since
1070     // the user might have scrolled since the previous navigation.
1071     scrollToFragmentWithParentBoundary(url);
1072     
1073     m_isComplete = false;
1074     checkCompleted();
1075
1076     if (isNewNavigation) {
1077         // This will clear previousItem from the rest of the frame tree that didn't
1078         // doing any loading. We need to make a pass on this now, since for fragment
1079         // navigation we'll not go through a real load and reach Completed state.
1080         checkLoadComplete();
1081     }
1082
1083     m_client.dispatchDidNavigateWithinPage();
1084
1085     m_frame.document()->statePopped(stateObject ? stateObject : SerializedScriptValue::nullValue());
1086     m_client.dispatchDidPopStateWithinPage();
1087     
1088     if (hashChange) {
1089         m_frame.document()->enqueueHashchangeEvent(oldURL, url);
1090         m_client.dispatchDidChangeLocationWithinPage();
1091     }
1092     
1093     // FrameLoaderClient::didFinishLoad() tells the internal load delegate the load finished with no error
1094     m_client.didFinishLoad();
1095 }
1096
1097 bool FrameLoader::isComplete() const
1098 {
1099     return m_isComplete;
1100 }
1101
1102 void FrameLoader::completed()
1103 {
1104     Ref<Frame> protect(m_frame);
1105
1106     for (Frame* descendant = m_frame.tree().traverseNext(&m_frame); descendant; descendant = descendant->tree().traverseNext(&m_frame))
1107         descendant->navigationScheduler().startTimer();
1108
1109     if (Frame* parent = m_frame.tree().parent())
1110         parent->loader().checkCompleted();
1111
1112     if (m_frame.view())
1113         m_frame.view()->maintainScrollPositionAtAnchor(nullptr);
1114     m_activityAssertion = nullptr;
1115 }
1116
1117 void FrameLoader::started()
1118 {
1119     if (m_frame.page())
1120         m_activityAssertion = m_frame.page()->pageThrottler().pageLoadActivityToken();
1121     for (Frame* frame = &m_frame; frame; frame = frame->tree().parent())
1122         frame->loader().m_isComplete = false;
1123 }
1124
1125 void FrameLoader::prepareForLoadStart()
1126 {
1127     m_progressTracker->progressStarted();
1128     m_client.dispatchDidStartProvisionalLoad();
1129
1130     if (AXObjectCache::accessibilityEnabled()) {
1131         if (AXObjectCache* cache = m_frame.document()->existingAXObjectCache()) {
1132             AXObjectCache::AXLoadingEvent loadingEvent = loadType() == FrameLoadType::Reload ? AXObjectCache::AXLoadingReloaded : AXObjectCache::AXLoadingStarted;
1133             cache->frameLoadingEventNotification(&m_frame, loadingEvent);
1134         }
1135     }
1136 }
1137
1138 void FrameLoader::setupForReplace()
1139 {
1140     m_client.revertToProvisionalState(m_documentLoader.get());
1141     setState(FrameStateProvisional);
1142     m_provisionalDocumentLoader = m_documentLoader;
1143     m_documentLoader = 0;
1144     detachChildren();
1145 }
1146
1147 void FrameLoader::loadFrameRequest(const FrameLoadRequest& request, LockHistory lockHistory, LockBackForwardList lockBackForwardList,
1148     PassRefPtr<Event> event, PassRefPtr<FormState> formState, ShouldSendReferrer shouldSendReferrer, AllowNavigationToInvalidURL allowNavigationToInvalidURL, NewFrameOpenerPolicy openerPolicy)
1149 {    
1150     // Protect frame from getting blown away inside dispatchBeforeLoadEvent in loadWithDocumentLoader.
1151     Ref<Frame> protect(m_frame);
1152
1153     URL url = request.resourceRequest().url();
1154
1155     ASSERT(m_frame.document());
1156     if (!request.requester()->canDisplay(url)) {
1157         reportLocalLoadFailed(&m_frame, url.stringCenterEllipsizedToLength());
1158         return;
1159     }
1160
1161     String argsReferrer = request.resourceRequest().httpReferrer();
1162     if (argsReferrer.isEmpty())
1163         argsReferrer = outgoingReferrer();
1164
1165     String referrer = SecurityPolicy::generateReferrerHeader(m_frame.document()->referrerPolicy(), url, argsReferrer);
1166     if (shouldSendReferrer == NeverSendReferrer)
1167         referrer = String();
1168     
1169     FrameLoadType loadType;
1170     if (request.resourceRequest().cachePolicy() == ReloadIgnoringCacheData)
1171         loadType = FrameLoadType::Reload;
1172     else if (lockBackForwardList == LockBackForwardList::Yes)
1173         loadType = FrameLoadType::RedirectWithLockedBackForwardList;
1174     else
1175         loadType = FrameLoadType::Standard;
1176
1177     if (request.resourceRequest().httpMethod() == "POST")
1178         loadPostRequest(request.resourceRequest(), referrer, request.frameName(), lockHistory, loadType, event, formState.get(), allowNavigationToInvalidURL, openerPolicy);
1179     else
1180         loadURL(request.resourceRequest().url(), referrer, request.frameName(), lockHistory, loadType, event, formState.get(), allowNavigationToInvalidURL, openerPolicy);
1181
1182     // FIXME: It's possible this targetFrame will not be the same frame that was targeted by the actual
1183     // load if frame names have changed.
1184     Frame* sourceFrame = formState ? formState->sourceDocument()->frame() : &m_frame;
1185     if (!sourceFrame)
1186         sourceFrame = &m_frame;
1187     Frame* targetFrame = sourceFrame->loader().findFrameForNavigation(request.frameName());
1188     if (targetFrame && targetFrame != sourceFrame) {
1189         if (Page* page = targetFrame->page())
1190             page->chrome().focus();
1191     }
1192 }
1193
1194 void FrameLoader::loadURL(const URL& newURL, const String& referrer, const String& frameName, LockHistory lockHistory, FrameLoadType newLoadType,
1195     PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState, AllowNavigationToInvalidURL allowNavigationToInvalidURL, NewFrameOpenerPolicy openerPolicy)
1196 {
1197     if (m_inStopAllLoaders)
1198         return;
1199
1200     Ref<Frame> protect(m_frame);
1201
1202     RefPtr<FormState> formState = prpFormState;
1203     bool isFormSubmission = formState;
1204     
1205     ResourceRequest request(newURL);
1206     if (!referrer.isEmpty()) {
1207         request.setHTTPReferrer(referrer);
1208         RefPtr<SecurityOrigin> referrerOrigin = SecurityOrigin::createFromString(referrer);
1209         addHTTPOriginIfNeeded(request, referrerOrigin->toString());
1210     }
1211 #if ENABLE(CACHE_PARTITIONING)
1212     if (&m_frame.tree().top() != &m_frame)
1213         request.setDomainForCachePartition(m_frame.tree().top().document()->securityOrigin()->domainForCachePartition());
1214 #endif
1215     addExtraFieldsToRequest(request, newLoadType, true);
1216     if (newLoadType == FrameLoadType::Reload || newLoadType == FrameLoadType::ReloadFromOrigin)
1217         request.setCachePolicy(ReloadIgnoringCacheData);
1218
1219     ASSERT(newLoadType != FrameLoadType::Same);
1220
1221     // The search for a target frame is done earlier in the case of form submission.
1222     Frame* targetFrame = isFormSubmission ? 0 : findFrameForNavigation(frameName);
1223     if (targetFrame && targetFrame != &m_frame) {
1224         targetFrame->loader().loadURL(newURL, referrer, "_self", lockHistory, newLoadType, event, formState.release(), allowNavigationToInvalidURL, openerPolicy);
1225         return;
1226     }
1227
1228     if (m_pageDismissalEventBeingDispatched != NoDismissal)
1229         return;
1230
1231     NavigationAction action(request, newLoadType, isFormSubmission, event);
1232
1233     if (!targetFrame && !frameName.isEmpty()) {
1234         policyChecker().checkNewWindowPolicy(action, request, formState.release(), frameName, [this, allowNavigationToInvalidURL, openerPolicy](const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue) {
1235             continueLoadAfterNewWindowPolicy(request, formState, frameName, action, shouldContinue, allowNavigationToInvalidURL, openerPolicy);
1236         });
1237         return;
1238     }
1239
1240     RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader;
1241
1242     bool sameURL = shouldTreatURLAsSameAsCurrent(newURL);
1243     const String& httpMethod = request.httpMethod();
1244     
1245     // Make sure to do scroll to fragment processing even if the URL is
1246     // exactly the same so pages with '#' links and DHTML side effects
1247     // work properly.
1248     if (shouldPerformFragmentNavigation(isFormSubmission, httpMethod, newLoadType, newURL)) {
1249         oldDocumentLoader->setTriggeringAction(action);
1250         oldDocumentLoader->setLastCheckedRequest(ResourceRequest());
1251         policyChecker().stopCheck();
1252         policyChecker().setLoadType(newLoadType);
1253         policyChecker().checkNavigationPolicy(request, oldDocumentLoader.get(), formState.release(), [this](const ResourceRequest& request, PassRefPtr<FormState>, bool shouldContinue) {
1254             continueFragmentScrollAfterNavigationPolicy(request, shouldContinue);
1255         });
1256         return;
1257     }
1258
1259     // must grab this now, since this load may stop the previous load and clear this flag
1260     bool isRedirect = m_quickRedirectComing;
1261     loadWithNavigationAction(request, action, lockHistory, newLoadType, formState.release(), allowNavigationToInvalidURL);
1262     if (isRedirect) {
1263         m_quickRedirectComing = false;
1264         if (m_provisionalDocumentLoader)
1265             m_provisionalDocumentLoader->setIsClientRedirect(true);
1266     } else if (sameURL && newLoadType != FrameLoadType::Reload && newLoadType != FrameLoadType::ReloadFromOrigin) {
1267         // Example of this case are sites that reload the same URL with a different cookie
1268         // driving the generated content, or a master frame with links that drive a target
1269         // frame, where the user has clicked on the same link repeatedly.
1270         m_loadType = FrameLoadType::Same;
1271     }
1272 }
1273
1274 SubstituteData FrameLoader::defaultSubstituteDataForURL(const URL& url)
1275 {
1276     if (!shouldTreatURLAsSrcdocDocument(url))
1277         return SubstituteData();
1278     String srcdoc = m_frame.ownerElement()->fastGetAttribute(srcdocAttr);
1279     ASSERT(!srcdoc.isNull());
1280     CString encodedSrcdoc = srcdoc.utf8();
1281     return SubstituteData(SharedBuffer::create(encodedSrcdoc.data(), encodedSrcdoc.length()), "text/html", "UTF-8", URL());
1282 }
1283
1284 void FrameLoader::load(const FrameLoadRequest& passedRequest)
1285 {
1286     FrameLoadRequest request(passedRequest);
1287
1288     if (m_inStopAllLoaders)
1289         return;
1290
1291     if (!request.frameName().isEmpty()) {
1292         Frame* frame = findFrameForNavigation(request.frameName());
1293         if (frame) {
1294             request.setShouldCheckNewWindowPolicy(false);
1295             if (&frame->loader() != this) {
1296                 frame->loader().load(request);
1297                 return;
1298             }
1299         }
1300     }
1301
1302     if (request.shouldCheckNewWindowPolicy()) {
1303         policyChecker().checkNewWindowPolicy(NavigationAction(request.resourceRequest(), NavigationTypeOther), request.resourceRequest(), nullptr, request.frameName(), [this](const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue) {
1304             continueLoadAfterNewWindowPolicy(request, formState, frameName, action, shouldContinue, AllowNavigationToInvalidURL::Yes, NewFrameOpenerPolicy::Suppress);
1305         });
1306
1307         return;
1308     }
1309
1310     if (!request.hasSubstituteData())
1311         request.setSubstituteData(defaultSubstituteDataForURL(request.resourceRequest().url()));
1312
1313     RefPtr<DocumentLoader> loader = m_client.createDocumentLoader(request.resourceRequest(), request.substituteData());
1314     load(loader.get());
1315 }
1316
1317 void FrameLoader::loadWithNavigationAction(const ResourceRequest& request, const NavigationAction& action, LockHistory lockHistory, FrameLoadType type, PassRefPtr<FormState> formState, AllowNavigationToInvalidURL allowNavigationToInvalidURL)
1318 {
1319     RefPtr<DocumentLoader> loader = m_client.createDocumentLoader(request, defaultSubstituteDataForURL(request.url()));
1320     if (lockHistory == LockHistory::Yes && m_documentLoader)
1321         loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory().string() : m_documentLoader->clientRedirectSourceForHistory());
1322
1323     loader->setTriggeringAction(action);
1324     if (m_documentLoader)
1325         loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
1326
1327     loadWithDocumentLoader(loader.get(), type, formState, allowNavigationToInvalidURL);
1328 }
1329
1330 void FrameLoader::load(DocumentLoader* newDocumentLoader)
1331 {
1332     ResourceRequest& r = newDocumentLoader->request();
1333     addExtraFieldsToMainResourceRequest(r);
1334     FrameLoadType type;
1335
1336     if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->originalRequest().url())) {
1337         r.setCachePolicy(ReloadIgnoringCacheData);
1338         type = FrameLoadType::Same;
1339     } else if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->unreachableURL()) && m_loadType == FrameLoadType::Reload)
1340         type = FrameLoadType::Reload;
1341     else
1342         type = FrameLoadType::Standard;
1343
1344     if (m_documentLoader)
1345         newDocumentLoader->setOverrideEncoding(m_documentLoader->overrideEncoding());
1346     
1347     // When we loading alternate content for an unreachable URL that we're
1348     // visiting in the history list, we treat it as a reload so the history list 
1349     // is appropriately maintained.
1350     //
1351     // FIXME: This seems like a dangerous overloading of the meaning of "FrameLoadType::Reload" ...
1352     // shouldn't a more explicit type of reload be defined, that means roughly 
1353     // "load without affecting history" ? 
1354     if (shouldReloadToHandleUnreachableURL(newDocumentLoader)) {
1355         // shouldReloadToHandleUnreachableURL() returns true only when the original load type is back-forward.
1356         // In this case we should save the document state now. Otherwise the state can be lost because load type is
1357         // changed and updateForBackForwardNavigation() will not be called when loading is committed.
1358         history().saveDocumentAndScrollState();
1359
1360         ASSERT(type == FrameLoadType::Standard);
1361         type = FrameLoadType::Reload;
1362     }
1363
1364     loadWithDocumentLoader(newDocumentLoader, type, 0, AllowNavigationToInvalidURL::Yes);
1365 }
1366
1367 static void logNavigation(MainFrame& frame, FrameLoadType type)
1368 {
1369     String navigationDescription;
1370     switch (type) {
1371     case FrameLoadType::Standard:
1372         navigationDescription = ASCIILiteral("standard");
1373         break;
1374     case FrameLoadType::Back:
1375         navigationDescription = ASCIILiteral("back");
1376         break;
1377     case FrameLoadType::Forward:
1378         navigationDescription = ASCIILiteral("forward");
1379         break;
1380     case FrameLoadType::IndexedBackForward:
1381         navigationDescription = ASCIILiteral("indexedBackForward");
1382         break;
1383     case FrameLoadType::Reload:
1384         navigationDescription = ASCIILiteral("reload");
1385         break;
1386     case FrameLoadType::Same:
1387         navigationDescription = ASCIILiteral("same");
1388         break;
1389     case FrameLoadType::ReloadFromOrigin:
1390         navigationDescription = ASCIILiteral("reloadFromOrigin");
1391         break;
1392     case FrameLoadType::Replace:
1393     case FrameLoadType::RedirectWithLockedBackForwardList:
1394         // Not logging those for now.
1395         return;
1396     }
1397     frame.diagnosticLoggingClient().logDiagnosticMessage(DiagnosticLoggingKeys::navigationKey(), navigationDescription);
1398 }
1399
1400 void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType type, PassRefPtr<FormState> prpFormState, AllowNavigationToInvalidURL allowNavigationToInvalidURL)
1401 {
1402     // Retain because dispatchBeforeLoadEvent may release the last reference to it.
1403     Ref<Frame> protect(m_frame);
1404
1405     ASSERT(m_client.hasWebView());
1406
1407     // Unfortunately the view must be non-nil, this is ultimately due
1408     // to parser requiring a FrameView.  We should fix this dependency.
1409
1410     ASSERT(m_frame.view());
1411
1412     if (m_pageDismissalEventBeingDispatched != NoDismissal)
1413         return;
1414
1415     if (m_frame.document())
1416         m_previousURL = m_frame.document()->url();
1417
1418     // Log main frame navigation types.
1419     if (m_frame.isMainFrame())
1420         logNavigation(static_cast<MainFrame&>(m_frame), type);
1421
1422     policyChecker().setLoadType(type);
1423     RefPtr<FormState> formState = prpFormState;
1424     bool isFormSubmission = formState;
1425
1426     const URL& newURL = loader->request().url();
1427     const String& httpMethod = loader->request().httpMethod();
1428
1429     if (shouldPerformFragmentNavigation(isFormSubmission, httpMethod, policyChecker().loadType(), newURL)) {
1430         RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader;
1431         NavigationAction action(loader->request(), policyChecker().loadType(), isFormSubmission);
1432
1433         oldDocumentLoader->setTriggeringAction(action);
1434         oldDocumentLoader->setLastCheckedRequest(ResourceRequest());
1435         policyChecker().stopCheck();
1436         policyChecker().checkNavigationPolicy(loader->request(), oldDocumentLoader.get(), formState, [this](const ResourceRequest& request, PassRefPtr<FormState>, bool shouldContinue) {
1437             continueFragmentScrollAfterNavigationPolicy(request, shouldContinue);
1438         });
1439         return;
1440     }
1441
1442     if (Frame* parent = m_frame.tree().parent())
1443         loader->setOverrideEncoding(parent->loader().documentLoader()->overrideEncoding());
1444
1445     policyChecker().stopCheck();
1446     setPolicyDocumentLoader(loader);
1447     if (loader->triggeringAction().isEmpty())
1448         loader->setTriggeringAction(NavigationAction(loader->request(), policyChecker().loadType(), isFormSubmission));
1449
1450     if (Element* ownerElement = m_frame.ownerElement()) {
1451         // We skip dispatching the beforeload event if we've already
1452         // committed a real document load because the event would leak
1453         // subsequent activity by the frame which the parent frame isn't
1454         // supposed to learn. For example, if the child frame navigated to
1455         // a new URL, the parent frame shouldn't learn the URL.
1456         if (!m_stateMachine.committedFirstRealDocumentLoad()
1457             && !ownerElement->dispatchBeforeLoadEvent(loader->request().url().string())) {
1458             continueLoadAfterNavigationPolicy(loader->request(), formState, false, allowNavigationToInvalidURL);
1459             return;
1460         }
1461     }
1462
1463     policyChecker().checkNavigationPolicy(loader->request(), loader, formState, [this, allowNavigationToInvalidURL](const ResourceRequest& request, PassRefPtr<FormState> formState, bool shouldContinue) {
1464         continueLoadAfterNavigationPolicy(request, formState, shouldContinue, allowNavigationToInvalidURL);
1465     });
1466 }
1467
1468 void FrameLoader::reportLocalLoadFailed(Frame* frame, const String& url)
1469 {
1470     ASSERT(!url.isEmpty());
1471     if (!frame)
1472         return;
1473
1474     frame->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, "Not allowed to load local resource: " + url);
1475 }
1476
1477 const ResourceRequest& FrameLoader::initialRequest() const
1478 {
1479     return activeDocumentLoader()->originalRequest();
1480 }
1481
1482 bool FrameLoader::willLoadMediaElementURL(URL& url)
1483 {
1484 #if PLATFORM(IOS)
1485     // MobileStore depends on the iOS 4.0 era client delegate method because webView:resource:willSendRequest:redirectResponse:fromDataSource
1486     // doesn't let them tell when a load request is coming from a media element. See <rdar://problem/8266916> for more details.
1487     if (applicationIsMobileStore())
1488         return m_client.shouldLoadMediaElementURL(url);
1489 #endif
1490
1491     ResourceRequest request(url);
1492
1493     unsigned long identifier;
1494     ResourceError error;
1495     requestFromDelegate(request, identifier, error);
1496     notifier().sendRemainingDelegateMessages(m_documentLoader.get(), identifier, request, ResourceResponse(url, String(), -1, String()), 0, -1, -1, error);
1497
1498     url = request.url();
1499
1500     return error.isNull();
1501 }
1502
1503 bool FrameLoader::shouldReloadToHandleUnreachableURL(DocumentLoader* docLoader)
1504 {
1505     URL unreachableURL = docLoader->unreachableURL();
1506
1507     if (unreachableURL.isEmpty())
1508         return false;
1509
1510     if (!isBackForwardLoadType(policyChecker().loadType()))
1511         return false;
1512
1513     // We only treat unreachableURLs specially during the delegate callbacks
1514     // for provisional load errors and navigation policy decisions. The former
1515     // case handles well-formed URLs that can't be loaded, and the latter
1516     // case handles malformed URLs and unknown schemes. Loading alternate content
1517     // at other times behaves like a standard load.
1518     DocumentLoader* compareDocumentLoader = 0;
1519     if (policyChecker().delegateIsDecidingNavigationPolicy() || policyChecker().delegateIsHandlingUnimplementablePolicy())
1520         compareDocumentLoader = m_policyDocumentLoader.get();
1521     else if (m_delegateIsHandlingProvisionalLoadError)
1522         compareDocumentLoader = m_provisionalDocumentLoader.get();
1523
1524     return compareDocumentLoader && unreachableURL == compareDocumentLoader->request().url();
1525 }
1526
1527 void FrameLoader::reloadWithOverrideEncoding(const String& encoding)
1528 {
1529     if (!m_documentLoader)
1530         return;
1531
1532     ResourceRequest request = m_documentLoader->request();
1533     URL unreachableURL = m_documentLoader->unreachableURL();
1534     if (!unreachableURL.isEmpty())
1535         request.setURL(unreachableURL);
1536
1537     // FIXME: If the resource is a result of form submission and is not cached, the form will be silently resubmitted.
1538     // We should ask the user for confirmation in this case.
1539     request.setCachePolicy(ReturnCacheDataElseLoad);
1540
1541     RefPtr<DocumentLoader> loader = m_client.createDocumentLoader(request, defaultSubstituteDataForURL(request.url()));
1542     setPolicyDocumentLoader(loader.get());
1543
1544     loader->setOverrideEncoding(encoding);
1545
1546     loadWithDocumentLoader(loader.get(), FrameLoadType::Reload, 0, AllowNavigationToInvalidURL::Yes);
1547 }
1548
1549 void FrameLoader::reload(bool endToEndReload)
1550 {
1551     if (!m_documentLoader)
1552         return;
1553
1554     // If a window is created by javascript, its main frame can have an empty but non-nil URL.
1555     // Reloading in this case will lose the current contents (see 4151001).
1556     if (m_documentLoader->request().url().isEmpty())
1557         return;
1558
1559     // Replace error-page URL with the URL we were trying to reach.
1560     ResourceRequest initialRequest = m_documentLoader->request();
1561     URL unreachableURL = m_documentLoader->unreachableURL();
1562     if (!unreachableURL.isEmpty())
1563         initialRequest.setURL(unreachableURL);
1564
1565     // Create a new document loader for the reload, this will become m_documentLoader eventually,
1566     // but first it has to be the "policy" document loader, and then the "provisional" document loader.
1567     RefPtr<DocumentLoader> loader = m_client.createDocumentLoader(initialRequest, defaultSubstituteDataForURL(initialRequest.url()));
1568
1569     ResourceRequest& request = loader->request();
1570
1571     // FIXME: We don't have a mechanism to revalidate the main resource without reloading at the moment.
1572     request.setCachePolicy(ReloadIgnoringCacheData);
1573
1574     // If we're about to re-post, set up action so the application can warn the user.
1575     if (request.httpMethod() == "POST")
1576         loader->setTriggeringAction(NavigationAction(request, NavigationTypeFormResubmitted));
1577
1578     loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
1579     
1580     loadWithDocumentLoader(loader.get(), endToEndReload ? FrameLoadType::ReloadFromOrigin : FrameLoadType::Reload, 0, AllowNavigationToInvalidURL::Yes);
1581 }
1582
1583 void FrameLoader::stopAllLoaders(ClearProvisionalItemPolicy clearProvisionalItemPolicy)
1584 {
1585     ASSERT(!m_frame.document() || !m_frame.document()->inPageCache());
1586     if (m_pageDismissalEventBeingDispatched != NoDismissal)
1587         return;
1588
1589     // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
1590     if (m_inStopAllLoaders)
1591         return;
1592     
1593     // Calling stopLoading() on the provisional document loader can blow away
1594     // the frame from underneath.
1595     Ref<Frame> protect(m_frame);
1596
1597     m_inStopAllLoaders = true;
1598
1599     policyChecker().stopCheck();
1600
1601     // If no new load is in progress, we should clear the provisional item from history
1602     // before we call stopLoading.
1603     if (clearProvisionalItemPolicy == ShouldClearProvisionalItem)
1604         history().setProvisionalItem(0);
1605
1606     for (RefPtr<Frame> child = m_frame.tree().firstChild(); child; child = child->tree().nextSibling())
1607         child->loader().stopAllLoaders(clearProvisionalItemPolicy);
1608     if (m_provisionalDocumentLoader)
1609         m_provisionalDocumentLoader->stopLoading();
1610     if (m_documentLoader)
1611         m_documentLoader->stopLoading();
1612
1613     setProvisionalDocumentLoader(0);
1614
1615     m_checkTimer.stop();
1616
1617     m_inStopAllLoaders = false;    
1618 }
1619
1620 void FrameLoader::stopForUserCancel(bool deferCheckLoadComplete)
1621 {
1622     stopAllLoaders();
1623
1624 #if PLATFORM(IOS)
1625     // Lay out immediately when stopping to immediately clear the old page if we just committed this one
1626     // but haven't laid out/painted yet.
1627     // FIXME: Is this behavior specific to iOS? Or should we expose a setting to toggle this behavior?
1628     if (m_frame.view() && !m_frame.view()->didFirstLayout())
1629         m_frame.view()->layout();
1630 #endif
1631
1632     if (deferCheckLoadComplete)
1633         scheduleCheckLoadComplete();
1634     else if (m_frame.page())
1635         checkLoadComplete();
1636 }
1637
1638 DocumentLoader* FrameLoader::activeDocumentLoader() const
1639 {
1640     if (m_state == FrameStateProvisional)
1641         return m_provisionalDocumentLoader.get();
1642     return m_documentLoader.get();
1643 }
1644
1645 bool FrameLoader::isLoading() const
1646 {
1647     DocumentLoader* docLoader = activeDocumentLoader();
1648     if (!docLoader)
1649         return false;
1650     return docLoader->isLoading();
1651 }
1652
1653 bool FrameLoader::frameHasLoaded() const
1654 {
1655     return m_stateMachine.committedFirstRealDocumentLoad() || (m_provisionalDocumentLoader && !m_stateMachine.creatingInitialEmptyDocument()); 
1656 }
1657
1658 void FrameLoader::setDocumentLoader(DocumentLoader* loader)
1659 {
1660     if (!loader && !m_documentLoader)
1661         return;
1662     
1663     ASSERT(loader != m_documentLoader);
1664     ASSERT(!loader || loader->frameLoader() == this);
1665
1666     m_client.prepareForDataSourceReplacement();
1667     detachChildren();
1668
1669     // detachChildren() can trigger this frame's unload event, and therefore
1670     // script can run and do just about anything. For example, an unload event that calls
1671     // document.write("") on its parent frame can lead to a recursive detachChildren()
1672     // invocation for this frame. In that case, we can end up at this point with a
1673     // loader that hasn't been deleted but has been detached from its frame. Such a
1674     // DocumentLoader has been sufficiently detached that we'll end up in an inconsistent
1675     // state if we try to use it.
1676     if (loader && !loader->frame())
1677         return;
1678
1679     if (m_documentLoader)
1680         m_documentLoader->detachFromFrame();
1681
1682     m_documentLoader = loader;
1683 }
1684
1685 void FrameLoader::setPolicyDocumentLoader(DocumentLoader* loader)
1686 {
1687     if (m_policyDocumentLoader == loader)
1688         return;
1689
1690     if (loader)
1691         loader->setFrame(&m_frame);
1692     if (m_policyDocumentLoader
1693             && m_policyDocumentLoader != m_provisionalDocumentLoader
1694             && m_policyDocumentLoader != m_documentLoader)
1695         m_policyDocumentLoader->detachFromFrame();
1696
1697     m_policyDocumentLoader = loader;
1698 }
1699
1700 void FrameLoader::setProvisionalDocumentLoader(DocumentLoader* loader)
1701 {
1702     ASSERT(!loader || !m_provisionalDocumentLoader);
1703     ASSERT(!loader || loader->frameLoader() == this);
1704
1705     if (m_provisionalDocumentLoader && m_provisionalDocumentLoader != m_documentLoader)
1706         m_provisionalDocumentLoader->detachFromFrame();
1707
1708     m_provisionalDocumentLoader = loader;
1709 }
1710
1711 void FrameLoader::setState(FrameState newState)
1712 {    
1713     m_state = newState;
1714     
1715     if (newState == FrameStateProvisional)
1716         provisionalLoadStarted();
1717     else if (newState == FrameStateComplete) {
1718         frameLoadCompleted();
1719         if (m_documentLoader)
1720             m_documentLoader->stopRecordingResponses();
1721     }
1722 }
1723
1724 void FrameLoader::clearProvisionalLoad()
1725 {
1726     setProvisionalDocumentLoader(0);
1727     m_progressTracker->progressCompleted();
1728     setState(FrameStateComplete);
1729 }
1730
1731 void FrameLoader::commitProvisionalLoad()
1732 {
1733     RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
1734     Ref<Frame> protect(m_frame);
1735
1736     std::unique_ptr<CachedPage> cachedPage;
1737     if (m_loadingFromCachedPage && history().provisionalItem())
1738         cachedPage = PageCache::singleton().take(*history().provisionalItem(), m_frame.page());
1739
1740     LOG(PageCache, "WebCoreLoading %s: About to commit provisional load from previous URL '%s' to new URL '%s'", m_frame.tree().uniqueName().string().utf8().data(),
1741         m_frame.document() ? m_frame.document()->url().stringCenterEllipsizedToLength().utf8().data() : "",
1742         pdl ? pdl->url().stringCenterEllipsizedToLength().utf8().data() : "<no provisional DocumentLoader>");
1743
1744 #if PLATFORM(IOS)
1745     // In the case where we are not navigating to a cached page, and the system is under (speculative) memory pressure,
1746     // we can try to preemptively release some of the pages in the cache.
1747     // FIXME: Right now the capacity is 1 on iOS devices with 256 MB of RAM, so this will always blow away the whole
1748     // page cache. We could still preemptively prune the page cache while navigating to a cached page if capacity > 1.
1749     // See <rdar://problem/11779846> for more details.
1750     if (!cachedPage) {
1751         if (memoryPressureHandler().isUnderMemoryPressure()) {
1752             LOG(MemoryPressure, "Pruning page cache because under memory pressure at: %s", __PRETTY_FUNCTION__);
1753             LOG(PageCache, "Pruning page cache to 0 due to memory pressure");
1754             // Don't cache any page if we are under memory pressure.
1755             PageCache::singleton().pruneToSizeNow(0, PruningReason::MemoryPressure);
1756         } else if (systemMemoryLevel() <= memoryLevelThresholdToPrunePageCache) {
1757             LOG(MemoryPressure, "Pruning page cache because system memory level is %d at: %s", systemMemoryLevel(), __PRETTY_FUNCTION__);
1758             auto& pageCache = PageCache::singleton();
1759             LOG(PageCache, "Pruning page cache to %d due to low memory (level %d less or equal to %d threshold)", pageCache.maxSize() / 2, systemMemoryLevel(), memoryLevelThresholdToPrunePageCache);
1760             pageCache.pruneToSizeNow(pageCache.maxSize() / 2, PruningReason::MemoryPressure);
1761         }
1762     }
1763 #endif
1764
1765     willTransitionToCommitted();
1766
1767     // Check to see if we need to cache the page we are navigating away from into the back/forward cache.
1768     // We are doing this here because we know for sure that a new page is about to be loaded.
1769     HistoryItem& item = *history().currentItem();
1770     if (!m_frame.tree().parent() && PageCache::singleton().canCache(m_frame.page()) && !item.isInPageCache())
1771         PageCache::singleton().add(item, *m_frame.page());
1772
1773     if (m_loadType != FrameLoadType::Replace)
1774         closeOldDataSources();
1775
1776     if (!cachedPage && !m_stateMachine.creatingInitialEmptyDocument())
1777         m_client.makeRepresentation(pdl.get());
1778
1779     transitionToCommitted(cachedPage.get());
1780
1781     if (pdl && m_documentLoader) {
1782         // Check if the destination page is allowed to access the previous page's timing information.
1783         Ref<SecurityOrigin> securityOrigin(SecurityOrigin::create(pdl->request().url()));
1784         m_documentLoader->timing().setHasSameOriginAsPreviousDocument(securityOrigin.get().canRequest(m_previousURL));
1785     }
1786
1787     // Call clientRedirectCancelledOrFinished() here so that the frame load delegate is notified that the redirect's
1788     // status has changed, if there was a redirect.  The frame load delegate may have saved some state about
1789     // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:.  Since we are
1790     // just about to commit a new page, there cannot possibly be a pending redirect at this point.
1791     if (m_sentRedirectNotification)
1792         clientRedirectCancelledOrFinished(false);
1793     
1794     if (cachedPage && cachedPage->document()) {
1795 #if PLATFORM(IOS)
1796         // FIXME: CachedPage::restore() would dispatch viewport change notification. However UIKit expects load
1797         // commit to happen before any changes to viewport arguments and dealing with this there is difficult.
1798         m_frame.page()->chrome().setDispatchViewportDataDidChangeSuppressed(true);
1799 #endif
1800         prepareForCachedPageRestore();
1801
1802         // FIXME: This API should be turned around so that we ground CachedPage into the Page.
1803         cachedPage->restore(*m_frame.page());
1804
1805         dispatchDidCommitLoad();
1806 #if PLATFORM(IOS)
1807         m_frame.page()->chrome().setDispatchViewportDataDidChangeSuppressed(false);
1808         m_frame.page()->chrome().dispatchViewportPropertiesDidChange(m_frame.page()->viewportArguments());
1809 #endif
1810         // If we have a title let the WebView know about it. 
1811         StringWithDirection title = m_documentLoader->title();
1812         if (!title.isNull())
1813             m_client.dispatchDidReceiveTitle(title);
1814
1815         checkCompleted();
1816     } else
1817         didOpenURL();
1818
1819     LOG(Loading, "WebCoreLoading %s: Finished committing provisional load to URL %s", m_frame.tree().uniqueName().string().utf8().data(),
1820         m_frame.document() ? m_frame.document()->url().stringCenterEllipsizedToLength().utf8().data() : "");
1821
1822     if (m_loadType == FrameLoadType::Standard && m_documentLoader->isClientRedirect())
1823         history().updateForClientRedirect();
1824
1825     if (m_loadingFromCachedPage) {
1826 #if PLATFORM(IOS)
1827         // Note, didReceiveDocType is expected to be called for cached pages. See <rdar://problem/5906758> for more details.
1828         if (m_frame.document()->doctype() && m_frame.page())
1829             m_frame.page()->chrome().didReceiveDocType(&m_frame);
1830 #endif
1831         m_frame.document()->documentDidResumeFromPageCache();
1832
1833         // Force a layout to update view size and thereby update scrollbars.
1834 #if PLATFORM(IOS)
1835         if (!m_client.forceLayoutOnRestoreFromPageCache())
1836             m_frame.view()->forceLayout();
1837 #else
1838         m_frame.view()->forceLayout();
1839 #endif
1840
1841         const ResponseVector& responses = m_documentLoader->responses();
1842         size_t count = responses.size();
1843         for (size_t i = 0; i < count; i++) {
1844             const ResourceResponse& response = responses[i];
1845             // FIXME: If the WebKit client changes or cancels the request, this is not respected.
1846             ResourceError error;
1847             unsigned long identifier;
1848             ResourceRequest request(response.url());
1849             requestFromDelegate(request, identifier, error);
1850             // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
1851             // However, with today's computers and networking speeds, this won't happen in practice.
1852             // Could be an issue with a giant local file.
1853             notifier().sendRemainingDelegateMessages(m_documentLoader.get(), identifier, request, response, 0, static_cast<int>(response.expectedContentLength()), 0, error);
1854         }
1855
1856         // FIXME: Why only this frame and not parent frames?
1857         checkLoadCompleteForThisFrame();
1858     }
1859 }
1860
1861 void FrameLoader::transitionToCommitted(CachedPage* cachedPage)
1862 {
1863     ASSERT(m_client.hasWebView());
1864     ASSERT(m_state == FrameStateProvisional);
1865
1866     if (m_state != FrameStateProvisional)
1867         return;
1868
1869     if (FrameView* view = m_frame.view()) {
1870         if (ScrollAnimator* scrollAnimator = view->existingScrollAnimator())
1871             scrollAnimator->cancelAnimations();
1872     }
1873
1874     m_client.setCopiesOnScroll();
1875     history().updateForCommit();
1876
1877     // The call to closeURL() invokes the unload event handler, which can execute arbitrary
1878     // JavaScript. If the script initiates a new load, we need to abandon the current load,
1879     // or the two will stomp each other.
1880     DocumentLoader* pdl = m_provisionalDocumentLoader.get();
1881     if (m_documentLoader)
1882         closeURL();
1883     if (pdl != m_provisionalDocumentLoader)
1884         return;
1885
1886     // Nothing else can interupt this commit - set the Provisional->Committed transition in stone
1887     if (m_documentLoader)
1888         m_documentLoader->stopLoadingSubresources();
1889     if (m_documentLoader)
1890         m_documentLoader->stopLoadingPlugIns();
1891
1892     setDocumentLoader(m_provisionalDocumentLoader.get());
1893     setProvisionalDocumentLoader(0);
1894
1895     if (pdl != m_documentLoader) {
1896         ASSERT(m_state == FrameStateComplete);
1897         return;
1898     }
1899
1900     setState(FrameStateCommittedPage);
1901
1902 #if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS)
1903     if (m_frame.isMainFrame())
1904         m_frame.page()->chrome().client().needTouchEvents(false);
1905 #endif
1906
1907     // Handle adding the URL to the back/forward list.
1908     DocumentLoader* dl = m_documentLoader.get();
1909
1910     switch (m_loadType) {
1911     case FrameLoadType::Forward:
1912     case FrameLoadType::Back:
1913     case FrameLoadType::IndexedBackForward:
1914         if (m_frame.page()) {
1915             // If the first load within a frame is a navigation within a back/forward list that was attached
1916             // without any of the items being loaded then we need to update the history in a similar manner as
1917             // for a standard load with the exception of updating the back/forward list (<rdar://problem/8091103>).
1918             if (!m_stateMachine.committedFirstRealDocumentLoad() && m_frame.isMainFrame())
1919                 history().updateForStandardLoad(HistoryController::UpdateAllExceptBackForwardList);
1920
1921             history().updateForBackForwardNavigation();
1922
1923             // For cached pages, CachedFrame::restore will take care of firing the popstate event with the history item's state object
1924             if (history().currentItem() && !cachedPage)
1925                 m_pendingStateObject = history().currentItem()->stateObject();
1926
1927             // Create a document view for this document, or used the cached view.
1928             if (cachedPage) {
1929                 DocumentLoader* cachedDocumentLoader = cachedPage->documentLoader();
1930                 ASSERT(cachedDocumentLoader);
1931                 cachedDocumentLoader->setFrame(&m_frame);
1932                 m_client.transitionToCommittedFromCachedFrame(cachedPage->cachedMainFrame());
1933             } else
1934                 m_client.transitionToCommittedForNewPage();
1935         }
1936         break;
1937
1938     case FrameLoadType::Reload:
1939     case FrameLoadType::ReloadFromOrigin:
1940     case FrameLoadType::Same:
1941     case FrameLoadType::Replace:
1942         history().updateForReload();
1943         m_client.transitionToCommittedForNewPage();
1944         break;
1945
1946     case FrameLoadType::Standard:
1947         history().updateForStandardLoad();
1948         if (m_frame.view())
1949             m_frame.view()->setScrollbarsSuppressed(true);
1950         m_client.transitionToCommittedForNewPage();
1951         break;
1952
1953     case FrameLoadType::RedirectWithLockedBackForwardList:
1954         history().updateForRedirectWithLockedBackForwardList();
1955         m_client.transitionToCommittedForNewPage();
1956         break;
1957
1958     // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is).
1959     // An exception should be thrown if we're in the FrameLoadTypeUninitialized state.
1960     default:
1961         ASSERT_NOT_REACHED();
1962     }
1963
1964     m_documentLoader->writer().setMIMEType(dl->responseMIMEType());
1965
1966     // Tell the client we've committed this URL.
1967     ASSERT(m_frame.view());
1968
1969     if (m_stateMachine.creatingInitialEmptyDocument())
1970         return;
1971
1972     if (!m_stateMachine.committedFirstRealDocumentLoad())
1973         m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit);
1974 }
1975
1976 void FrameLoader::clientRedirectCancelledOrFinished(bool cancelWithLoadInProgress)
1977 {
1978     // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
1979     // the redirect succeeded.  We should either rename this API, or add a new method, like
1980     // -webView:didFinishClientRedirectForFrame:
1981     m_client.dispatchDidCancelClientRedirect();
1982
1983     if (!cancelWithLoadInProgress)
1984         m_quickRedirectComing = false;
1985
1986     m_sentRedirectNotification = false;
1987 }
1988
1989 void FrameLoader::clientRedirected(const URL& url, double seconds, double fireDate, LockBackForwardList lockBackForwardList)
1990 {
1991     m_client.dispatchWillPerformClientRedirect(url, seconds, fireDate);
1992     
1993     // Remember that we sent a redirect notification to the frame load delegate so that when we commit
1994     // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
1995     m_sentRedirectNotification = true;
1996     
1997     // If a "quick" redirect comes in, we set a special mode so we treat the next
1998     // load as part of the original navigation. If we don't have a document loader, we have
1999     // no "original" load on which to base a redirect, so we treat the redirect as a normal load.
2000     // Loads triggered by JavaScript form submissions never count as quick redirects.
2001     m_quickRedirectComing = (lockBackForwardList == LockBackForwardList::Yes || history().currentItemShouldBeReplaced()) && m_documentLoader && !m_isExecutingJavaScriptFormAction;
2002 }
2003
2004 bool FrameLoader::shouldReload(const URL& currentURL, const URL& destinationURL)
2005 {
2006     // This function implements the rule: "Don't reload if navigating by fragment within
2007     // the same URL, but do reload if going to a new URL or to the same URL with no
2008     // fragment identifier at all."
2009     if (!destinationURL.hasFragmentIdentifier())
2010         return true;
2011     return !equalIgnoringFragmentIdentifier(currentURL, destinationURL);
2012 }
2013
2014 void FrameLoader::closeOldDataSources()
2015 {
2016     // FIXME: Is it important for this traversal to be postorder instead of preorder?
2017     // If so, add helpers for postorder traversal, and use them. If not, then lets not
2018     // use a recursive algorithm here.
2019     for (Frame* child = m_frame.tree().firstChild(); child; child = child->tree().nextSibling())
2020         child->loader().closeOldDataSources();
2021     
2022     if (m_documentLoader)
2023         m_client.dispatchWillClose();
2024
2025     m_client.setMainFrameDocumentReady(false); // stop giving out the actual DOMDocument to observers
2026 }
2027
2028 void FrameLoader::prepareForCachedPageRestore()
2029 {
2030     ASSERT(!m_frame.tree().parent());
2031     ASSERT(m_frame.page());
2032     ASSERT(m_frame.isMainFrame());
2033
2034     m_frame.navigationScheduler().cancel();
2035
2036     // We still have to close the previous part page.
2037     closeURL();
2038     
2039     // Delete old status bar messages (if it _was_ activated on last URL).
2040     if (m_frame.script().canExecuteScripts(NotAboutToExecuteScript)) {
2041         DOMWindow* window = m_frame.document()->domWindow();
2042         window->setStatus(String());
2043         window->setDefaultStatus(String());
2044     }
2045 }
2046
2047 void FrameLoader::open(CachedFrameBase& cachedFrame)
2048 {
2049     m_isComplete = false;
2050     
2051     // Don't re-emit the load event.
2052     m_didCallImplicitClose = true;
2053
2054     URL url = cachedFrame.url();
2055
2056     // FIXME: I suspect this block of code doesn't do anything.
2057     if (url.protocolIsInHTTPFamily() && !url.host().isEmpty() && url.path().isEmpty())
2058         url.setPath("/");
2059
2060     started();
2061     Document* document = cachedFrame.document();
2062     ASSERT(document);
2063     ASSERT(document->domWindow());
2064
2065     clear(document, true, true, cachedFrame.isMainFrame());
2066
2067     document->setInPageCache(false);
2068
2069     m_needsClear = true;
2070     m_isComplete = false;
2071     m_didCallImplicitClose = false;
2072     m_outgoingReferrer = url.string();
2073
2074     FrameView* view = cachedFrame.view();
2075     
2076     // When navigating to a CachedFrame its FrameView should never be null.  If it is we'll crash in creative ways downstream.
2077     ASSERT(view);
2078     view->setWasScrolledByUser(false);
2079
2080     // Use the current ScrollView's frame rect.
2081     if (m_frame.view())
2082         view->setFrameRect(m_frame.view()->frameRect());
2083     m_frame.setView(view);
2084     
2085     m_frame.setDocument(document);
2086     document->domWindow()->resumeFromPageCache();
2087
2088     updateFirstPartyForCookies();
2089
2090     cachedFrame.restore();
2091 }
2092
2093 bool FrameLoader::isHostedByObjectElement() const
2094 {
2095     HTMLFrameOwnerElement* owner = m_frame.ownerElement();
2096     return owner && owner->hasTagName(objectTag);
2097 }
2098
2099 bool FrameLoader::isReplacing() const
2100 {
2101     return m_loadType == FrameLoadType::Replace;
2102 }
2103
2104 void FrameLoader::setReplacing()
2105 {
2106     m_loadType = FrameLoadType::Replace;
2107 }
2108
2109 bool FrameLoader::subframeIsLoading() const
2110 {
2111     // It's most likely that the last added frame is the last to load so we walk backwards.
2112     for (Frame* child = m_frame.tree().lastChild(); child; child = child->tree().previousSibling()) {
2113         FrameLoader& childLoader = child->loader();
2114         DocumentLoader* documentLoader = childLoader.documentLoader();
2115         if (documentLoader && documentLoader->isLoadingInAPISense())
2116             return true;
2117         documentLoader = childLoader.provisionalDocumentLoader();
2118         if (documentLoader && documentLoader->isLoadingInAPISense())
2119             return true;
2120         documentLoader = childLoader.policyDocumentLoader();
2121         if (documentLoader)
2122             return true;
2123     }
2124     return false;
2125 }
2126
2127 void FrameLoader::willChangeTitle(DocumentLoader* loader)
2128 {
2129     m_client.willChangeTitle(loader);
2130 }
2131
2132 FrameLoadType FrameLoader::loadType() const
2133 {
2134     return m_loadType;
2135 }
2136     
2137 CachePolicy FrameLoader::subresourceCachePolicy() const
2138 {
2139     if (m_isComplete)
2140         return CachePolicyVerify;
2141
2142     if (m_loadType == FrameLoadType::ReloadFromOrigin)
2143         return CachePolicyReload;
2144
2145     if (Frame* parentFrame = m_frame.tree().parent()) {
2146         CachePolicy parentCachePolicy = parentFrame->loader().subresourceCachePolicy();
2147         if (parentCachePolicy != CachePolicyVerify)
2148             return parentCachePolicy;
2149     }
2150     
2151     switch (m_loadType) {
2152     case FrameLoadType::Reload:
2153         return CachePolicyRevalidate;
2154     case FrameLoadType::Back:
2155     case FrameLoadType::Forward:
2156     case FrameLoadType::IndexedBackForward:
2157         return CachePolicyHistoryBuffer;
2158     case FrameLoadType::ReloadFromOrigin:
2159         ASSERT_NOT_REACHED(); // Already handled above.
2160         return CachePolicyReload;
2161     case FrameLoadType::RedirectWithLockedBackForwardList:
2162     case FrameLoadType::Replace:
2163     case FrameLoadType::Same:
2164     case FrameLoadType::Standard:
2165         return CachePolicyVerify;
2166     }
2167
2168     RELEASE_ASSERT_NOT_REACHED();
2169     return CachePolicyVerify;
2170 }
2171
2172 void FrameLoader::checkLoadCompleteForThisFrame()
2173 {
2174     ASSERT(m_client.hasWebView());
2175
2176     switch (m_state) {
2177         case FrameStateProvisional: {
2178             if (m_delegateIsHandlingProvisionalLoadError)
2179                 return;
2180
2181             RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
2182             if (!pdl)
2183                 return;
2184                 
2185             // If we've received any errors we may be stuck in the provisional state and actually complete.
2186             const ResourceError& error = pdl->mainDocumentError();
2187             if (error.isNull())
2188                 return;
2189
2190             // Check all children first.
2191             RefPtr<HistoryItem> item;
2192             if (Page* page = m_frame.page())
2193                 if (isBackForwardLoadType(loadType()))
2194                     // Reset the back forward list to the last committed history item at the top level.
2195                     item = page->mainFrame().loader().history().currentItem();
2196                 
2197             // Only reset if we aren't already going to a new provisional item.
2198             bool shouldReset = !history().provisionalItem();
2199             if (!pdl->isLoadingInAPISense() || pdl->isStopping()) {
2200                 m_delegateIsHandlingProvisionalLoadError = true;
2201                 m_client.dispatchDidFailProvisionalLoad(error);
2202                 m_delegateIsHandlingProvisionalLoadError = false;
2203
2204                 ASSERT(!pdl->isLoading());
2205
2206                 // If we're in the middle of loading multipart data, we need to restore the document loader.
2207                 if (isReplacing() && !m_documentLoader.get())
2208                     setDocumentLoader(m_provisionalDocumentLoader.get());
2209
2210                 // Finish resetting the load state, but only if another load hasn't been started by the
2211                 // delegate callback.
2212                 if (pdl == m_provisionalDocumentLoader)
2213                     clearProvisionalLoad();
2214                 else if (activeDocumentLoader()) {
2215                     URL unreachableURL = activeDocumentLoader()->unreachableURL();
2216                     if (!unreachableURL.isEmpty() && unreachableURL == pdl->request().url())
2217                         shouldReset = false;
2218                 }
2219             }
2220             if (shouldReset && item)
2221                 if (Page* page = m_frame.page()) {
2222                     page->backForward().setCurrentItem(item.get());
2223                     m_frame.loader().client().updateGlobalHistoryItemForPage();
2224                 }
2225             return;
2226         }
2227         
2228         case FrameStateCommittedPage: {
2229             DocumentLoader* dl = m_documentLoader.get();            
2230             if (!dl || (dl->isLoadingInAPISense() && !dl->isStopping()))
2231                 return;
2232
2233             setState(FrameStateComplete);
2234
2235             // FIXME: Is this subsequent work important if we already navigated away?
2236             // Maybe there are bugs because of that, or extra work we can skip because
2237             // the new page is ready.
2238
2239             m_client.forceLayoutForNonHTML();
2240              
2241             // If the user had a scroll point, scroll to it, overriding the anchor point if any.
2242             if (m_frame.page()) {
2243                 if (isBackForwardLoadType(m_loadType) || m_loadType == FrameLoadType::Reload || m_loadType == FrameLoadType::ReloadFromOrigin)
2244                     history().restoreScrollPositionAndViewState();
2245             }
2246
2247             if (m_stateMachine.creatingInitialEmptyDocument() || !m_stateMachine.committedFirstRealDocumentLoad())
2248                 return;
2249
2250             m_progressTracker->progressCompleted();
2251             Page* page = m_frame.page();
2252             if (page) {
2253                 if (m_frame.isMainFrame())
2254                     page->resetRelevantPaintedObjectCounter();
2255             }
2256
2257             const ResourceError& error = dl->mainDocumentError();
2258
2259             AXObjectCache::AXLoadingEvent loadingEvent;
2260             if (!error.isNull()) {
2261                 m_client.dispatchDidFailLoad(error);
2262                 loadingEvent = AXObjectCache::AXLoadingFailed;
2263             } else {
2264                 m_client.dispatchDidFinishLoad();
2265                 loadingEvent = AXObjectCache::AXLoadingFinished;
2266             }
2267
2268             // Notify accessibility.
2269             if (AXObjectCache* cache = m_frame.document()->existingAXObjectCache())
2270                 cache->frameLoadingEventNotification(&m_frame, loadingEvent);
2271
2272             if (page)
2273                 page->mainFrame().diagnosticLoggingClient().logDiagnosticMessageWithResult(DiagnosticLoggingKeys::pageLoadedKey(), emptyString(), error.isNull() ? DiagnosticLoggingResultPass : DiagnosticLoggingResultFail);
2274
2275             return;
2276         }
2277         
2278         case FrameStateComplete:
2279             m_loadType = FrameLoadType::Standard;
2280             frameLoadCompleted();
2281             return;
2282     }
2283
2284     ASSERT_NOT_REACHED();
2285 }
2286
2287 void FrameLoader::continueLoadAfterWillSubmitForm()
2288 {
2289     if (!m_provisionalDocumentLoader)
2290         return;
2291
2292     prepareForLoadStart();
2293     
2294     // The load might be cancelled inside of prepareForLoadStart(), nulling out the m_provisionalDocumentLoader, 
2295     // so we need to null check it again.
2296     if (!m_provisionalDocumentLoader)
2297         return;
2298
2299     DocumentLoader* activeDocLoader = activeDocumentLoader();
2300     if (activeDocLoader && activeDocLoader->isLoadingMainResource())
2301         return;
2302
2303     m_loadingFromCachedPage = false;
2304     m_provisionalDocumentLoader->startLoadingMainResource();
2305 }
2306
2307 static URL originatingURLFromBackForwardList(Page* page)
2308 {
2309     // FIXME: Can this logic be replaced with m_frame.document()->firstPartyForCookies()?
2310     // It has the same meaning of "page a user thinks is the current one".
2311
2312     URL originalURL;
2313     int backCount = page->backForward().backCount();
2314     for (int backIndex = 0; backIndex <= backCount; backIndex++) {
2315         // FIXME: At one point we had code here to check a "was user gesture" flag.
2316         // Do we need to restore that logic?
2317         HistoryItem* historyItem = page->backForward().itemAtIndex(-backIndex);
2318         if (!historyItem)
2319             continue;
2320
2321         originalURL = historyItem->originalURL(); 
2322         if (!originalURL.isNull()) 
2323             return originalURL;
2324     }
2325
2326     return URL();
2327 }
2328
2329 void FrameLoader::setOriginalURLForDownloadRequest(ResourceRequest& request)
2330 {
2331     URL originalURL;
2332     
2333     // If there is no referrer, assume that the download was initiated directly, so current document is
2334     // completely unrelated to it. See <rdar://problem/5294691>.
2335     // FIXME: Referrer is not sent in many other cases, so we will often miss this important information.
2336     // Find a better way to decide whether the download was unrelated to current document.
2337     if (!request.httpReferrer().isNull()) {
2338         // find the first item in the history that was originated by the user
2339         originalURL = originatingURLFromBackForwardList(m_frame.page());
2340     }
2341
2342     if (originalURL.isNull())
2343         originalURL = request.url();
2344
2345     if (!originalURL.protocol().isEmpty() && !originalURL.host().isEmpty()) {
2346         unsigned port = originalURL.port();
2347
2348         // 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.
2349         // 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.
2350         String hostOnlyURLString;
2351         if (port)
2352             hostOnlyURLString = makeString(originalURL.protocol(), "://", originalURL.host(), ':', String::number(port));
2353         else
2354             hostOnlyURLString = makeString(originalURL.protocol(), "://", originalURL.host());
2355
2356         // FIXME: Rename firstPartyForCookies back to mainDocumentURL. It was a mistake to think that it was only used for cookies.
2357         request.setFirstPartyForCookies(URL(URL(), hostOnlyURLString));
2358     }
2359 }
2360
2361 void FrameLoader::didLayout(LayoutMilestones milestones)
2362 {
2363     ASSERT(m_frame.isMainFrame());
2364
2365     m_client.dispatchDidLayout(milestones);
2366 }
2367
2368 void FrameLoader::didFirstLayout()
2369 {
2370 #if PLATFORM(IOS)
2371     // Only send layout-related delegate callbacks synchronously for the main frame to
2372     // avoid reentering layout for the main frame while delivering a layout-related delegate
2373     // callback for a subframe.
2374     if (&m_frame != &m_frame.page()->mainFrame())
2375         return;
2376 #endif
2377     if (m_frame.page() && isBackForwardLoadType(m_loadType))
2378         history().restoreScrollPositionAndViewState();
2379
2380     if (m_stateMachine.committedFirstRealDocumentLoad() && !m_stateMachine.isDisplayingInitialEmptyDocument() && !m_stateMachine.firstLayoutDone())
2381         m_stateMachine.advanceTo(FrameLoaderStateMachine::FirstLayoutDone);
2382 }
2383
2384 void FrameLoader::frameLoadCompleted()
2385 {
2386     // Note: Can be called multiple times.
2387
2388     m_client.frameLoadCompleted();
2389
2390     history().updateForFrameLoadCompleted();
2391
2392     // After a canceled provisional load, firstLayoutDone is false.
2393     // Reset it to true if we're displaying a page.
2394     if (m_documentLoader && m_stateMachine.committedFirstRealDocumentLoad() && !m_stateMachine.isDisplayingInitialEmptyDocument() && !m_stateMachine.firstLayoutDone())
2395         m_stateMachine.advanceTo(FrameLoaderStateMachine::FirstLayoutDone);
2396 }
2397
2398 void FrameLoader::detachChildren()
2399 {
2400     Vector<Ref<Frame>, 16> childrenToDetach;
2401     childrenToDetach.reserveInitialCapacity(m_frame.tree().childCount());
2402     for (Frame* child = m_frame.tree().lastChild(); child; child = child->tree().previousSibling())
2403         childrenToDetach.uncheckedAppend(*child);
2404     for (unsigned i = 0; i < childrenToDetach.size(); ++i)
2405         childrenToDetach[i]->loader().detachFromParent();
2406 }
2407
2408 void FrameLoader::closeAndRemoveChild(Frame* child)
2409 {
2410     child->tree().detachFromParent();
2411
2412     child->setView(0);
2413     if (child->ownerElement() && child->page())
2414         child->page()->decrementSubframeCount();
2415     child->willDetachPage();
2416     child->detachFromPage();
2417
2418     m_frame.tree().removeChild(child);
2419 }
2420
2421 // Called every time a resource is completely loaded or an error is received.
2422 void FrameLoader::checkLoadComplete()
2423 {
2424     ASSERT(m_client.hasWebView());
2425     
2426     m_shouldCallCheckLoadComplete = false;
2427
2428     if (!m_frame.page())
2429         return;
2430
2431     // FIXME: Always traversing the entire frame tree is a bit inefficient, but 
2432     // is currently needed in order to null out the previous history item for all frames.
2433     Vector<Ref<Frame>, 16> frames;
2434     for (Frame* frame = &m_frame.mainFrame(); frame; frame = frame->tree().traverseNext())
2435         frames.append(*frame);
2436
2437     // To process children before their parents, iterate the vector backwards.
2438     for (unsigned i = frames.size(); i; --i)
2439         frames[i - 1]->loader().checkLoadCompleteForThisFrame();
2440 }
2441
2442 int FrameLoader::numPendingOrLoadingRequests(bool recurse) const
2443 {
2444     if (!recurse)
2445         return m_frame.document()->cachedResourceLoader().requestCount();
2446
2447     int count = 0;
2448     for (Frame* frame = &m_frame; frame; frame = frame->tree().traverseNext(&m_frame))
2449         count += frame->document()->cachedResourceLoader().requestCount();
2450     return count;
2451 }
2452
2453 String FrameLoader::userAgent(const URL& url) const
2454 {
2455     return m_client.userAgent(url);
2456 }
2457
2458 void FrameLoader::handledOnloadEvents()
2459 {
2460     m_client.dispatchDidHandleOnloadEvents();
2461
2462     if (documentLoader())
2463         documentLoader()->handledOnloadEvents();
2464 }
2465
2466 void FrameLoader::frameDetached()
2467 {
2468     stopAllLoaders();
2469     m_frame.document()->stopActiveDOMObjects();
2470     detachFromParent();
2471 }
2472
2473 void FrameLoader::detachFromParent()
2474 {
2475     Ref<Frame> protect(m_frame);
2476
2477     closeURL();
2478     history().saveScrollPositionAndViewStateToItem(history().currentItem());
2479     detachChildren();
2480     // stopAllLoaders() needs to be called after detachChildren(), because detachedChildren()
2481     // will trigger the unload event handlers of any child frames, and those event
2482     // handlers might start a new subresource load in this frame.
2483     stopAllLoaders();
2484
2485     InspectorInstrumentation::frameDetachedFromParent(m_frame);
2486
2487     detachViewsAndDocumentLoader();
2488
2489     m_progressTracker = nullptr;
2490
2491     if (Frame* parent = m_frame.tree().parent()) {
2492         parent->loader().closeAndRemoveChild(&m_frame);
2493         parent->loader().scheduleCheckCompleted();
2494     } else {
2495         m_frame.setView(0);
2496         m_frame.willDetachPage();
2497         m_frame.detachFromPage();
2498     }
2499 }
2500
2501 void FrameLoader::detachViewsAndDocumentLoader()
2502 {
2503     m_client.detachedFromParent2();
2504     setDocumentLoader(0);
2505     m_client.detachedFromParent3();
2506 }
2507     
2508 void FrameLoader::addExtraFieldsToSubresourceRequest(ResourceRequest& request)
2509 {
2510     addExtraFieldsToRequest(request, m_loadType, false);
2511 }
2512
2513 void FrameLoader::addExtraFieldsToMainResourceRequest(ResourceRequest& request)
2514 {
2515     // FIXME: Using m_loadType seems wrong for some callers.
2516     // If we are only preparing to load the main resource, that is previous load's load type!
2517     addExtraFieldsToRequest(request, m_loadType, true);
2518 }
2519
2520 void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, FrameLoadType loadType, bool mainResource)
2521 {
2522     // Don't set the cookie policy URL if it's already been set.
2523     // But make sure to set it on all requests regardless of protocol, as it has significance beyond the cookie policy (<rdar://problem/6616664>).
2524     if (request.firstPartyForCookies().isEmpty()) {
2525         if (mainResource && m_frame.isMainFrame())
2526             request.setFirstPartyForCookies(request.url());
2527         else if (Document* document = m_frame.document())
2528             request.setFirstPartyForCookies(document->firstPartyForCookies());
2529     }
2530
2531     // The remaining modifications are only necessary for HTTP and HTTPS.
2532     if (!request.url().isEmpty() && !request.url().protocolIsInHTTPFamily())
2533         return;
2534
2535     applyUserAgent(request);
2536
2537     if (!mainResource) {
2538         if (request.isConditional())
2539             request.setCachePolicy(ReloadIgnoringCacheData);
2540         else if (documentLoader()->isLoadingInAPISense()) {
2541             // If we inherit cache policy from a main resource, we use the DocumentLoader's
2542             // original request cache policy for two reasons:
2543             // 1. For POST requests, we mutate the cache policy for the main resource,
2544             //    but we do not want this to apply to subresources
2545             // 2. Delegates that modify the cache policy using willSendRequest: should
2546             //    not affect any other resources. Such changes need to be done
2547             //    per request.
2548             ResourceRequestCachePolicy mainDocumentOriginalCachePolicy = documentLoader()->originalRequest().cachePolicy();
2549             // Back-forward navigations try to load main resource from cache only to avoid re-submitting form data, and start over (with a warning dialog) if that fails.
2550             // This policy is set on initial request too, but should not be inherited.
2551             ResourceRequestCachePolicy subresourceCachePolicy = (mainDocumentOriginalCachePolicy == ReturnCacheDataDontLoad) ? ReturnCacheDataElseLoad : mainDocumentOriginalCachePolicy;
2552             request.setCachePolicy(subresourceCachePolicy);
2553         } else
2554             request.setCachePolicy(UseProtocolCachePolicy);
2555
2556     // FIXME: Other FrameLoader functions have duplicated code for setting cache policy of main request when reloading.
2557     // It seems better to manage it explicitly than to hide the logic inside addExtraFieldsToRequest().
2558     } else if (loadType == FrameLoadType::Reload || loadType == FrameLoadType::ReloadFromOrigin || request.isConditional())
2559         request.setCachePolicy(ReloadIgnoringCacheData);
2560
2561     if (request.cachePolicy() == ReloadIgnoringCacheData) {
2562         if (loadType == FrameLoadType::Reload)
2563             request.setHTTPHeaderField(HTTPHeaderName::CacheControl, "max-age=0");
2564         else if (loadType == FrameLoadType::ReloadFromOrigin) {
2565             request.setHTTPHeaderField(HTTPHeaderName::CacheControl, "no-cache");
2566             request.setHTTPHeaderField(HTTPHeaderName::Pragma, "no-cache");
2567         }
2568     }
2569     
2570     if (mainResource)
2571         request.setHTTPAccept(defaultAcceptHeader);
2572
2573     // Make sure we send the Origin header.
2574     addHTTPOriginIfNeeded(request, String());
2575
2576     // Only set fallback array if it's still empty (later attempts may be incorrect, see bug 117818).
2577     if (request.responseContentDispositionEncodingFallbackArray().isEmpty()) {
2578         // Always try UTF-8. If that fails, try frame encoding (if any) and then the default.
2579         request.setResponseContentDispositionEncodingFallbackArray("UTF-8", m_frame.document()->encoding(), m_frame.settings().defaultTextEncodingName());
2580     }
2581 }
2582
2583 void FrameLoader::addHTTPOriginIfNeeded(ResourceRequest& request, const String& origin)
2584 {
2585     if (!request.httpOrigin().isEmpty())
2586         return;  // Request already has an Origin header.
2587
2588     // Don't send an Origin header for GET or HEAD to avoid privacy issues.
2589     // For example, if an intranet page has a hyperlink to an external web
2590     // site, we don't want to include the Origin of the request because it
2591     // will leak the internal host name. Similar privacy concerns have lead
2592     // to the widespread suppression of the Referer header at the network
2593     // layer.
2594     if (request.httpMethod() == "GET" || request.httpMethod() == "HEAD")
2595         return;
2596
2597     // For non-GET and non-HEAD methods, always send an Origin header so the
2598     // server knows we support this feature.
2599
2600     if (origin.isEmpty()) {
2601         // If we don't know what origin header to attach, we attach the value
2602         // for an empty origin.
2603         request.setHTTPOrigin(SecurityOrigin::createUnique()->toString());
2604         return;
2605     }
2606
2607     request.setHTTPOrigin(origin);
2608 }
2609
2610 void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String& referrer, const String& frameName, LockHistory lockHistory, FrameLoadType loadType, PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState, AllowNavigationToInvalidURL allowNavigationToInvalidURL, NewFrameOpenerPolicy openerPolicy)
2611 {
2612     RefPtr<FormState> formState = prpFormState;
2613
2614     // Previously when this method was reached, the original FrameLoadRequest had been deconstructed to build a 
2615     // bunch of parameters that would come in here and then be built back up to a ResourceRequest.  In case
2616     // any caller depends on the immutability of the original ResourceRequest, I'm rebuilding a ResourceRequest
2617     // from scratch as it did all along.
2618     const URL& url = inRequest.url();
2619     RefPtr<FormData> formData = inRequest.httpBody();
2620     const String& contentType = inRequest.httpContentType();
2621     String origin = inRequest.httpOrigin();
2622
2623     ResourceRequest workingResourceRequest(url);    
2624
2625     if (!referrer.isEmpty())
2626         workingResourceRequest.setHTTPReferrer(referrer);
2627     workingResourceRequest.setHTTPOrigin(origin);
2628     workingResourceRequest.setHTTPMethod("POST");
2629     workingResourceRequest.setHTTPBody(formData);
2630     workingResourceRequest.setHTTPContentType(contentType);
2631     addExtraFieldsToRequest(workingResourceRequest, loadType, true);
2632
2633     NavigationAction action(workingResourceRequest, loadType, true, event);
2634
2635     if (!frameName.isEmpty()) {
2636         // The search for a target frame is done earlier in the case of form submission.
2637         if (Frame* targetFrame = formState ? 0 : findFrameForNavigation(frameName)) {
2638             targetFrame->loader().loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, formState.release(), allowNavigationToInvalidURL);
2639             return;
2640         }
2641
2642         policyChecker().checkNewWindowPolicy(action, workingResourceRequest, formState.release(), frameName, [this, allowNavigationToInvalidURL, openerPolicy](const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue) {
2643             continueLoadAfterNewWindowPolicy(request, formState, frameName, action, shouldContinue, allowNavigationToInvalidURL, openerPolicy);
2644         });
2645         return;
2646     }
2647
2648     // must grab this now, since this load may stop the previous load and clear this flag
2649     bool isRedirect = m_quickRedirectComing;
2650     loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, formState.release(), allowNavigationToInvalidURL);
2651     if (isRedirect) {
2652         m_quickRedirectComing = false;
2653         if (m_provisionalDocumentLoader)
2654             m_provisionalDocumentLoader->setIsClientRedirect(true);
2655     }
2656 }
2657
2658 unsigned long FrameLoader::loadResourceSynchronously(const ResourceRequest& request, StoredCredentials storedCredentials, ClientCredentialPolicy clientCredentialPolicy, ResourceError& error, ResourceResponse& response, Vector<char>& data)
2659 {
2660     ASSERT(m_frame.document());
2661     String referrer = SecurityPolicy::generateReferrerHeader(m_frame.document()->referrerPolicy(), request.url(), outgoingReferrer());
2662     
2663     ResourceRequest initialRequest = request;
2664     initialRequest.setTimeoutInterval(10);
2665     
2666     if (!referrer.isEmpty())
2667         initialRequest.setHTTPReferrer(referrer);
2668     addHTTPOriginIfNeeded(initialRequest, outgoingOrigin());
2669
2670     initialRequest.setFirstPartyForCookies(m_frame.mainFrame().loader().documentLoader()->request().url());
2671     
2672     addExtraFieldsToSubresourceRequest(initialRequest);
2673
2674     unsigned long identifier = 0;    
2675     ResourceRequest newRequest(initialRequest);
2676     requestFromDelegate(newRequest, identifier, error);
2677
2678     if (error.isNull()) {
2679         ASSERT(!newRequest.isNull());
2680         
2681         if (!documentLoader()->applicationCacheHost()->maybeLoadSynchronously(newRequest, error, response, data)) {
2682             platformStrategies()->loaderStrategy()->loadResourceSynchronously(networkingContext(), identifier, newRequest, storedCredentials, clientCredentialPolicy, error, response, data);
2683             documentLoader()->applicationCacheHost()->maybeLoadFallbackSynchronously(newRequest, error, response, data);
2684         }
2685     }
2686     notifier().sendRemainingDelegateMessages(m_documentLoader.get(), identifier, request, response, data.data(), data.size(), -1, error);
2687     return identifier;
2688 }
2689
2690 const ResourceRequest& FrameLoader::originalRequest() const
2691 {
2692     return activeDocumentLoader()->originalRequestCopy();
2693 }
2694
2695 void FrameLoader::receivedMainResourceError(const ResourceError& error)
2696 {
2697     // Retain because the stop may release the last reference to it.
2698     Ref<Frame> protect(m_frame);
2699
2700     RefPtr<DocumentLoader> loader = activeDocumentLoader();
2701     // FIXME: Don't want to do this if an entirely new load is going, so should check
2702     // that both data sources on the frame are either this or nil.
2703     stop();
2704     if (m_client.shouldFallBack(error))
2705         handleFallbackContent();
2706
2707     if (m_state == FrameStateProvisional && m_provisionalDocumentLoader) {
2708         if (m_submittedFormURL == m_provisionalDocumentLoader->originalRequestCopy().url())
2709             m_submittedFormURL = URL();
2710             
2711         // We might have made a page cache item, but now we're bailing out due to an error before we ever
2712         // transitioned to the new page (before WebFrameState == commit).  The goal here is to restore any state
2713         // so that the existing view (that wenever got far enough to replace) can continue being used.
2714         history().invalidateCurrentItemCachedPage();
2715         
2716         // Call clientRedirectCancelledOrFinished here so that the frame load delegate is notified that the redirect's
2717         // status has changed, if there was a redirect. The frame load delegate may have saved some state about
2718         // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are definitely
2719         // not going to use this provisional resource, as it was cancelled, notify the frame load delegate that the redirect
2720         // has ended.
2721         if (m_sentRedirectNotification)
2722             clientRedirectCancelledOrFinished(false);
2723     }
2724
2725     checkCompleted();
2726     if (m_frame.page())
2727         checkLoadComplete();
2728 }
2729
2730 void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequest& request, bool shouldContinue)
2731 {
2732     m_quickRedirectComing = false;
2733
2734     if (!shouldContinue)
2735         return;
2736
2737     // If we have a provisional request for a different document, a fragment scroll should cancel it.
2738     if (m_provisionalDocumentLoader && !equalIgnoringFragmentIdentifier(m_provisionalDocumentLoader->request().url(), request.url())) {
2739         m_provisionalDocumentLoader->stopLoading();
2740         setProvisionalDocumentLoader(0);
2741     }
2742
2743     bool isRedirect = m_quickRedirectComing || policyChecker().loadType() == FrameLoadType::RedirectWithLockedBackForwardList;
2744     loadInSameDocument(request.url(), 0, !isRedirect);
2745 }
2746
2747 bool FrameLoader::shouldPerformFragmentNavigation(bool isFormSubmission, const String& httpMethod, FrameLoadType loadType, const URL& url)
2748 {
2749     // We don't do this if we are submitting a form with method other than "GET", explicitly reloading,
2750     // currently displaying a frameset, or if the URL does not have a fragment.
2751     // These rules were originally based on what KHTML was doing in KHTMLPart::openURL.
2752
2753     // FIXME: What about load types other than Standard and Reload?
2754
2755     return (!isFormSubmission || equalIgnoringCase(httpMethod, "GET"))
2756         && loadType != FrameLoadType::Reload
2757         && loadType != FrameLoadType::ReloadFromOrigin
2758         && loadType != FrameLoadType::Same
2759         && !shouldReload(m_frame.document()->url(), url)
2760         // We don't want to just scroll if a link from within a
2761         // frameset is trying to reload the frameset into _top.
2762         && !m_frame.document()->isFrameSet();
2763 }
2764
2765 void FrameLoader::scrollToFragmentWithParentBoundary(const URL& url)
2766 {
2767     FrameView* view = m_frame.view();
2768     if (!view)
2769         return;
2770
2771     // Leaking scroll position to a cross-origin ancestor would permit the so-called "framesniffing" attack.
2772     RefPtr<Frame> boundaryFrame(url.hasFragmentIdentifier() ? m_frame.document()->findUnsafeParentScrollPropagationBoundary() : 0);
2773
2774     if (boundaryFrame)
2775         boundaryFrame->view()->setSafeToPropagateScrollToParent(false);
2776
2777     view->scrollToFragment(url);
2778
2779     if (boundaryFrame)
2780         boundaryFrame->view()->setSafeToPropagateScrollToParent(true);
2781 }
2782
2783 bool FrameLoader::shouldClose()
2784 {
2785     Page* page = m_frame.page();
2786     if (!page)
2787         return true;
2788     if (!page->chrome().canRunBeforeUnloadConfirmPanel())
2789         return true;
2790
2791     // Store all references to each subframe in advance since beforeunload's event handler may modify frame
2792     Vector<Ref<Frame>, 16> targetFrames;
2793     targetFrames.append(m_frame);
2794     for (Frame* child = m_frame.tree().firstChild(); child; child = child->tree().traverseNext(&m_frame))
2795         targetFrames.append(*child);
2796
2797     bool shouldClose = false;
2798     {
2799         NavigationDisablerForBeforeUnload navigationDisabler;
2800         size_t i;
2801
2802         for (i = 0; i < targetFrames.size(); i++) {
2803             if (!targetFrames[i]->tree().isDescendantOf(&m_frame))
2804                 continue;
2805             if (!targetFrames[i]->loader().handleBeforeUnloadEvent(page->chrome(), this))
2806                 break;
2807         }
2808
2809         if (i == targetFrames.size())
2810             shouldClose = true;
2811     }
2812
2813     if (!shouldClose)
2814         m_submittedFormURL = URL();
2815
2816     m_currentNavigationHasShownBeforeUnloadConfirmPanel = false;
2817     return shouldClose;
2818 }
2819
2820 bool FrameLoader::handleBeforeUnloadEvent(Chrome& chrome, FrameLoader* frameLoaderBeingNavigated)
2821 {
2822     DOMWindow* domWindow = m_frame.document()->domWindow();
2823     if (!domWindow)
2824         return true;
2825
2826     RefPtr<Document> document = m_frame.document();
2827     if (!document->bodyOrFrameset())
2828         return true;
2829     
2830     RefPtr<BeforeUnloadEvent> beforeUnloadEvent = BeforeUnloadEvent::create();
2831     m_pageDismissalEventBeingDispatched = BeforeUnloadDismissal;
2832
2833     // We store the frame's page in a local variable because the frame might get detached inside dispatchEvent.
2834     Page* page = m_frame.page();
2835     page->incrementFrameHandlingBeforeUnloadEventCount();
2836     domWindow->dispatchEvent(beforeUnloadEvent.get(), domWindow->document());
2837     page->decrementFrameHandlingBeforeUnloadEventCount();
2838
2839     m_pageDismissalEventBeingDispatched = NoDismissal;
2840
2841     if (!beforeUnloadEvent->defaultPrevented())
2842         document->defaultEventHandler(beforeUnloadEvent.get());
2843     if (beforeUnloadEvent->returnValue().isNull())
2844         return true;
2845
2846     // If the navigating FrameLoader has already shown a beforeunload confirmation panel for the current navigation attempt,
2847     // this frame is not allowed to cause another one to be shown.
2848     if (frameLoaderBeingNavigated->m_currentNavigationHasShownBeforeUnloadConfirmPanel) {
2849         document->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Blocked attempt to show multiple beforeunload confirmation dialogs for the same navigation."));
2850         return true;
2851     }
2852
2853     // We should only display the beforeunload dialog for an iframe if its SecurityOrigin matches all
2854     // ancestor frame SecurityOrigins up through the navigating FrameLoader.
2855     if (frameLoaderBeingNavigated != this) {
2856         Frame* parentFrame = m_frame.tree().parent();
2857         while (parentFrame) {
2858             Document* parentDocument = parentFrame->document();
2859             if (!parentDocument)
2860                 return true;
2861             if (!m_frame.document() || !m_frame.document()->securityOrigin()->canAccess(parentDocument->securityOrigin())) {
2862                 document->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Blocked attempt to show beforeunload confirmation dialog on behalf of a frame with different security origin. Protocols, domains, and ports must match."));
2863                 return true;
2864             }
2865             
2866             if (&parentFrame->loader() == frameLoaderBeingNavigated)
2867                 break;
2868             
2869             parentFrame = parentFrame->tree().parent();
2870         }
2871         
2872         // The navigatingFrameLoader should always be in our ancestory.
2873         ASSERT(parentFrame);
2874         ASSERT(&parentFrame->loader() == frameLoaderBeingNavigated);
2875     }
2876
2877     frameLoaderBeingNavigated->m_currentNavigationHasShownBeforeUnloadConfirmPanel = true;
2878
2879     String text = document->displayStringModifiedByEncoding(beforeUnloadEvent->returnValue());
2880     return chrome.runBeforeUnloadConfirmPanel(text, &m_frame);
2881 }
2882
2883 void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest& request, PassRefPtr<FormState> formState, bool shouldContinue, AllowNavigationToInvalidURL allowNavigationToInvalidURL)
2884 {
2885     // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
2886     // nil policyDataSource because loading the alternate page will have passed
2887     // through this method already, nested; otherwise, policyDataSource should still be set.
2888     ASSERT(m_policyDocumentLoader || !m_provisionalDocumentLoader->unreachableURL().isEmpty());
2889
2890     bool isTargetItem = history().provisionalItem() ? history().provisionalItem()->isTargetItem() : false;
2891
2892     bool urlIsDisallowed = allowNavigationToInvalidURL == AllowNavigationToInvalidURL::No && !request.url().isValid();
2893
2894     // Three reasons we can't continue:
2895     //    1) Navigation policy delegate said we can't so request is nil. A primary case of this 
2896     //       is the user responding Cancel to the form repost nag sheet.
2897     //    2) User responded Cancel to an alert popped up by the before unload event handler.
2898     //    3) The request's URL is invalid and navigation to invalid URLs is disallowed.
2899     bool canContinue = shouldContinue && shouldClose() && !urlIsDisallowed;
2900
2901     if (!canContinue) {
2902         // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we 
2903         // need to report that the client redirect was cancelled.
2904         // FIXME: The client should be told about ignored non-quick redirects, too.
2905         if (m_quickRedirectComing)
2906             clientRedirectCancelledOrFinished(false);
2907
2908         setPolicyDocumentLoader(0);
2909
2910         // If the navigation request came from the back/forward menu, and we punt on it, we have the 
2911         // problem that we have optimistically moved the b/f cursor already, so move it back.  For sanity, 
2912         // we only do this when punting a navigation for the target frame or top-level frame.  
2913         if ((isTargetItem || m_frame.isMainFrame()) && isBackForwardLoadType(policyChecker().loadType())) {
2914             if (Page* page = m_frame.page()) {
2915                 if (HistoryItem* resetItem = m_frame.mainFrame().loader().history().currentItem()) {
2916                     page->backForward().setCurrentItem(resetItem);
2917                     m_frame.loader().client().updateGlobalHistoryItemForPage();
2918                 }
2919             }
2920         }
2921         return;
2922     }
2923
2924     FrameLoadType type = policyChecker().loadType();
2925     // A new navigation is in progress, so don't clear the history's provisional item.
2926     stopAllLoaders(ShouldNotClearProvisionalItem);
2927     
2928     // <rdar://problem/6250856> - In certain circumstances on pages with multiple frames, stopAllLoaders()
2929     // might detach the current FrameLoader, in which case we should bail on this newly defunct load. 
2930     if (!m_frame.page())
2931         return;
2932
2933     if (Page* page = m_frame.page()) {
2934         if (m_frame.isMainFrame())
2935             page->inspectorController().resume();
2936     }
2937
2938     setProvisionalDocumentLoader(m_policyDocumentLoader.get());
2939     m_loadType = type;
2940     setState(FrameStateProvisional);
2941
2942     setPolicyDocumentLoader(0);
2943
2944     if (isBackForwardLoadType(type) && history().provisionalItem()->isInPageCache()) {
2945         loadProvisionalItemFromCachedPage();
2946         return;
2947     }
2948
2949     if (!formState) {
2950         continueLoadAfterWillSubmitForm();
2951         return;
2952     }
2953
2954     m_client.dispatchWillSubmitForm(formState, [this](PolicyAction action) {
2955         policyChecker().continueLoadAfterWillSubmitForm(action);
2956     });
2957 }
2958
2959 void FrameLoader::continueLoadAfterNewWindowPolicy(const ResourceRequest& request,
2960     PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue, AllowNavigationToInvalidURL allowNavigationToInvalidURL, NewFrameOpenerPolicy openerPolicy)
2961 {
2962     if (!shouldContinue)
2963         return;
2964
2965     Ref<Frame> frame(m_frame);
2966     RefPtr<Frame> mainFrame = m_client.dispatchCreatePage(action);
2967     if (!mainFrame)
2968         return;
2969
2970     if (frameName != "_blank")
2971         mainFrame->tree().setName(frameName);
2972
2973     mainFrame->page()->setOpenedByDOM();
2974     mainFrame->loader().m_client.dispatchShow();
2975     if (openerPolicy == NewFrameOpenerPolicy::Allow) {
2976         mainFrame->loader().setOpener(frame.ptr());
2977         mainFrame->document()->setReferrerPolicy(frame->document()->referrerPolicy());
2978     }
2979     mainFrame->loader().loadWithNavigationAction(request, NavigationAction(request), LockHistory::No, FrameLoadType::Standard, formState, allowNavigationToInvalidURL);
2980 }
2981
2982 void FrameLoader::requestFromDelegate(ResourceRequest& request, unsigned long& identifier, ResourceError& error)
2983 {
2984     ASSERT(!request.isNull());
2985
2986     identifier = 0;
2987     if (Page* page = m_frame.page()) {
2988         identifier = page->progress().createUniqueIdentifier();
2989         notifier().assignIdentifierToInitialRequest(identifier, m_documentLoader.get(), request);
2990     }
2991
2992     ResourceRequest newRequest(request);
2993     notifier().dispatchWillSendRequest(m_documentLoader.get(), identifier, newRequest, ResourceResponse());
2994
2995     if (newRequest.isNull())
2996         error = cancelledError(request);
2997     else
2998         error = ResourceError();
2999
3000     request = newRequest;
3001 }
3002
3003 void FrameLoader::loadedResourceFromMemoryCache(CachedResource* resource, ResourceRequest& newRequest)
3004 {
3005     Page* page = m_frame.page();
3006     if (!page)
3007         return;
3008
3009     if (!resource->shouldSendResourceLoadCallbacks() || m_documentLoader->haveToldClientAboutLoad(resource->url()))
3010         return;
3011
3012     // Main resource delegate messages are synthesized in MainResourceLoader, so we must not send them here.
3013     if (resource->type() == CachedResource::MainResource)
3014         return;
3015
3016     if (!page->areMemoryCacheClientCallsEnabled()) {
3017         InspectorInstrumentation::didLoadResourceFromMemoryCache(*page, m_documentLoader.get(), resource);
3018         m_documentLoader->recordMemoryCacheLoadForFutureClientNotification(resource->resourceRequest());
3019         m_documentLoader->didTellClientAboutLoad(resource->url());
3020         return;
3021     }
3022
3023     if (m_client.dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(), newRequest, resource->response(), resource->encodedSize())) {
3024         InspectorInstrumentation::didLoadResourceFromMemoryCache(*page, m_documentLoader.get(), resource);
3025         m_documentLoader->didTellClientAboutLoad(resource->url());
3026         return;
3027     }
3028
3029     unsigned long identifier;
3030     ResourceError error;
3031     requestFromDelegate(newRequest, identifier, error);
3032     InspectorInstrumentation::markResourceAsCached(*page, identifier);
3033     notifier().sendRemainingDelegateMessages(m_documentLoader.get(), identifier, newRequest, resource->response(), 0, resource->encodedSize(), 0, error);
3034 }
3035
3036 void FrameLoader::applyUserAgent(ResourceRequest& request)
3037 {
3038     String userAgent = this->userAgent(request.url());
3039     ASSERT(!userAgent.isNull());
3040     request.setHTTPUserAgent(userAgent);
3041 }
3042
3043 bool FrameLoader::shouldInterruptLoadForXFrameOptions(const String& content, const URL& url, unsigned long requestIdentifier)
3044 {
3045     Frame& topFrame = m_frame.tree().top();
3046     if (&m_frame == &topFrame)
3047         return false;
3048
3049     XFrameOptionsDisposition disposition = parseXFrameOptionsHeader(content);
3050
3051     switch (disposition) {
3052     case XFrameOptionsSameOrigin: {
3053         RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url);
3054         if (!origin->isSameSchemeHostPort(topFrame.document()->securityOrigin()))
3055             return true;
3056         for (Frame* frame = m_frame.tree().parent(); frame; frame = frame->tree().parent()) {
3057             if (!origin->isSameSchemeHostPort(frame->document()->securityOrigin()))
3058                 break;
3059         }
3060         return false;
3061     }
3062     case XFrameOptionsDeny:
3063         return true;
3064     case XFrameOptionsAllowAll:
3065         return false;
3066     case XFrameOptionsConflict:
3067         m_frame.document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, "Multiple 'X-Frame-Options' headers with conflicting values ('" + content + "') encountered when loading '" + url.stringCenterEllipsizedToLength() + "'. Falling back to 'DENY'.", requestIdentifier);
3068         return true;
3069     case XFrameOptionsInvalid:
3070         m_frame.document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, "Invalid 'X-Frame-Options' header encountered when loading '" + url.stringCenterEllipsizedToLength() + "': '" + content + "' is not a recognized directive. The header will be ignored.", requestIdentifier);
3071         return false;
3072     case XFrameOptionsNone:
3073         return false;
3074     }
3075     ASSERT_NOT_REACHED();
3076     return false;
3077 }
3078
3079 void FrameLoader::loadProvisionalItemFromCachedPage()
3080 {
3081     DocumentLoader* provisionalLoader = provisionalDocumentLoader();
3082     LOG(PageCache, "WebCorePageCache: Loading provisional DocumentLoader %p with URL '%s' from CachedPage", provisionalDocumentLoader(), provisionalDocumentLoader()->url().stringCenterEllipsizedToLength().utf8().data());
3083
3084     prepareForLoadStart();
3085
3086     m_loadingFromCachedPage = true;
3087
3088     // Should have timing data from previous time(s) the page was shown.
3089     ASSERT(provisionalLoader->timing().navigationStart());
3090     provisionalLoader->resetTiming();
3091     provisionalLoader->timing().markNavigationStart();
3092
3093     provisionalLoader->setCommitted(true);
3094     commitProvisionalLoad();
3095 }
3096
3097 bool FrameLoader::shouldTreatURLAsSameAsCurrent(const URL& url) const
3098 {
3099     if (!history().currentItem())
3100         return false;
3101     return url == history().currentItem()->url() || url == history().currentItem()->originalURL();
3102 }
3103
3104 bool FrameLoader::shouldTreatURLAsSrcdocDocument(const URL& url) const
3105 {
3106     if (!equalIgnoringCase(url.string(), "about:srcdoc"))
3107         return false;
3108     HTMLFrameOwnerElement* ownerElement = m_frame.ownerElement();
3109     if (!ownerElement)
3110         return false;
3111     if (!ownerElement->hasTagName(iframeTag))
3112         return false;
3113     return ownerElement->fastHasAttribute(srcdocAttr);
3114 }
3115
3116 Frame* FrameLoader::findFrameForNavigation(const AtomicString& name, Document* activeDocument)
3117 {
3118     Frame* frame = m_frame.tree().find(name);
3119
3120     // FIXME: Eventually all callers should supply the actual activeDocument so we can call canNavigate with the right document.
3121     if (!activeDocument)
3122         activeDocument = m_frame.document();
3123
3124     if (!activeDocument->canNavigate(frame))
3125         return nullptr;
3126
3127     return frame;
3128 }
3129
3130 void FrameLoader::loadSameDocumentItem(HistoryItem& item)
3131 {
3132     ASSERT(item.documentSequenceNumber() == history().currentItem()->documentSequenceNumber());
3133
3134     // Save user view state to the current history item here since we don't do a normal load.
3135     // FIXME: Does form state need to be saved here too?
3136     history().saveScrollPositionAndViewStateToItem(history().currentItem());
3137     if (FrameView* view = m_frame.view())
3138         view->setWasScrolledByUser(false);
3139
3140     history().setCurrentItem(item);
3141         
3142     // loadInSameDocument() actually changes the URL and notifies load delegates of a "fake" load
3143     loadInSameDocument(item.url(), item.stateObject(), false);
3144
3145     // Restore user view state from the current history item here since we don't do a normal load.
3146     history().restoreScrollPositionAndViewState();
3147 }
3148
3149 // FIXME: This function should really be split into a couple pieces, some of
3150 // which should be methods of HistoryController and some of which should be
3151 // methods of FrameLoader.
3152 void FrameLoader::loadDifferentDocumentItem(HistoryItem& item, FrameLoadType loadType, FormSubmissionCacheLoadPolicy cacheLoadPolicy)
3153 {
3154     // Remember this item so we can traverse any child items as child frames load
3155     history().setProvisionalItem(&item);
3156
3157     if (CachedPage* cachedPage = PageCache::singleton().get(item, m_frame.page())) {
3158         auto documentLoader = cachedPage->documentLoader();
3159         documentLoader->setTriggeringAction(NavigationAction(documentLoader->request(), loadType, false));
3160         documentLoader->setLastCheckedRequest(ResourceRequest());
3161         loadWithDocumentLoader(documentLoader, loadType, 0, AllowNavigationToInvalidURL::Yes);
3162         return;
3163     }
3164
3165     URL itemURL = item.url();
3166     URL itemOriginalURL = item.originalURL();
3167     URL currentURL;
3168     if (documentLoader())
3169         currentURL = documentLoader()->url();
3170     RefPtr<FormData> formData = item.formData();
3171
3172     ResourceRequest request(itemURL);
3173
3174     if (!item.referrer().isNull())
3175         request.setHTTPReferrer(item.referrer());
3176     
3177     // If this was a repost that failed the page cache, we might try to repost the form.
3178     NavigationAction action;
3179     if (formData) {
3180         formData->generateFiles(m_frame.document());
3181
3182         request.setHTTPMethod("POST");
3183         request.setHTTPBody(formData);
3184         request.setHTTPContentType(item.formContentType());
3185         RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::createFromString(item.referrer());
3186         addHTTPOriginIfNeeded(request, securityOrigin->toString());
3187
3188         // Make sure to add extra fields to the request after the Origin header is added for the FormData case.
3189         // See https://bugs.webkit.org/show_bug.cgi?id=22194 for more discussion.
3190         addExtraFieldsToRequest(request, loadType, true);
3191         
3192         // FIXME: Slight hack to test if the NSURL cache contains the page we're going to.
3193         // We want to know this before talking to the policy delegate, since it affects whether 
3194         // we show the DoYouReallyWantToRepost nag.
3195         //
3196         // This trick has a small bug (3123893) where we might find a cache hit, but then
3197         // have the item vanish when we try to use it in the ensuing nav.  This should be
3198         // extremely rare, but in that case the user will get an error on the navigation.
3199         
3200         if (cacheLoadPolicy == MayAttemptCacheOnlyLoadForFormSubmissionItem) {
3201             request.setCachePolicy(ReturnCacheDataDontLoad);
3202             action = NavigationAction(request, loadType, false);
3203         } else {
3204             request.setCachePolicy(ReturnCacheDataElseLoad);
3205             action = NavigationAction(request, NavigationTypeFormResubmitted);
3206         }
3207     } else {
3208         switch (loadType) {
3209         case FrameLoadType::Reload:
3210         case FrameLoadType::ReloadFromOrigin:
3211             request.setCachePolicy(ReloadIgnoringCacheData);
3212             break;
3213         case FrameLoadType::Back:
3214         case FrameLoadType::Forward:
3215         case FrameLoadType::IndexedBackForward:
3216             // If the first load within a frame is a navigation within a back/forward list that was attached 
3217             // without any of the items being loaded then we should use the default caching policy (<rdar://problem/8131355>).
3218             if (m_stateMachine.committedFirstRealDocumentLoad())
3219                 request.setCachePolicy(ReturnCacheDataElseLoad);
3220             break;
3221         case FrameLoadType::Standard:
3222         case FrameLoadType::RedirectWithLockedBackForwardList:
3223             break;
3224         case FrameLoadType::Same:
3225         default:
3226             ASSERT_NOT_REACHED();
3227         }
3228
3229         addExtraFieldsToRequest(request, loadType, true);
3230
3231         ResourceRequest requestForOriginalURL(request);
3232         requestForOriginalURL.setURL(itemOriginalURL);
3233         action = NavigationAction(requestForOriginalURL, loadType, false);
3234     }
3235
3236     loadWithNavigationAction(request, action, LockHistory::No, loadType, 0, AllowNavigationToInvalidURL::Yes);
3237 }
3238
3239 // Loads content into this frame, as specified by history item
3240 void FrameLoader::loadItem(HistoryItem& item, FrameLoadType loadType)
3241 {
3242     m_requestedHistoryItem = &item;
3243     HistoryItem* currentItem = history().currentItem();
3244     bool sameDocumentNavigation = currentItem && item.shouldDoSameDocumentNavigationTo(*currentItem);
3245
3246     if (sameDocumentNavigation)
3247         loadSameDocumentItem(item);
3248     else
3249         loadDifferentDocumentItem(item, loadType, MayAttemptCacheOnlyLoadForFormSubmissionItem);
3250 }
3251
3252 void FrameLoader::retryAfterFailedCacheOnlyMainResourceLoad()
3253 {
3254     ASSERT(m_state == FrameStateProvisional);
3255     ASSERT(!m_loadingFromCachedPage);
3256     // We only use cache-only loads to avoid resubmitting forms.
3257     ASSERT(isBackForwardLoadType(m_loadType));
3258     ASSERT(history().provisionalItem());
3259     ASSERT(history().provisionalItem()->formData());
3260     ASSERT(history().provisionalItem() == m_requestedHistoryItem.get());
3261
3262     FrameLoadType loadType = m_loadType;
3263     HistoryItem& item = *history().provisionalItem();
3264
3265     stopAllLoaders(ShouldNotClearProvisionalItem);
3266     loadDifferentDocumentItem(item, loadType, MayNotAttemptCacheOnlyLoadForFormSubmissionItem);
3267 }
3268
3269 ResourceError FrameLoader::cancelledError(const ResourceRequest& request) const
3270 {
3271     ResourceError error = m_client.cancelledError(request);
3272     error.setIsCancellation(true);
3273     return error;
3274 }
3275
3276 #if PLATFORM(IOS)
3277 RetainPtr<CFDictionaryRef> FrameLoader::connectionProperties(ResourceLoader* loader)
3278 {
3279     return m_client.connectionProperties(loader->documentLoader(), loader->identifier());
3280 }
3281 #endif
3282
3283 String FrameLoader::referrer() const
3284 {
3285     return m_documentLoader ? m_documentLoader->request().httpReferrer() : "";
3286 }
3287
3288 void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds()
3289 {
3290     if (!m_frame.script().canExecuteScripts(NotAboutToExecuteScript))
3291         return;
3292
3293     Vector<Ref<DOMWrapperWorld>> worlds;
3294     ScriptController::getAllWorlds(worlds);
3295     for (auto& world : worlds)
3296         dispatchDidClearWindowObjectInWorld(world);
3297 }
3298
3299 void FrameLoader::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld& world)
3300 {
3301     if (!m_frame.script().canExecuteScripts(NotAboutToExecuteScript) || !m_frame.script().existingWindowShell(world))
3302         return;
3303
3304     m_client.dispatchDidClearWindowObjectInWorld(world);
3305
3306     if (Page* page = m_frame.page())
3307         page->inspectorController().didClearWindowObjectInWorld(m_frame, world);
3308
3309     InspectorInstrumentation::didClearWindowObjectInWorld(m_frame, world);
3310 }
3311
3312 void FrameLoader::dispatchGlobalObjectAvailableInAllWorlds()
3313 {
3314     Vector<Ref<DOMWrapperWorld>> worlds;
3315     ScriptController::getAllWorlds(worlds);
3316     for (auto& world : worlds)
3317         m_client.dispatchGlobalObjectAvailable(world);
3318 }
3319
3320 SandboxFlags FrameLoader::effectiveSandboxFlags() const
3321 {
3322     SandboxFlags flags = m_forcedSandboxFlags;
3323     if (Frame* parentFrame = m_frame.tree().parent())
3324         flags |= parentFrame->document()->sandboxFlags();
3325     if (HTMLFrameOwnerElement* ownerElement = m_frame.ownerElement())
3326         flags |= ownerElement->sandboxFlags();
3327     return flags;
3328 }
3329
3330 void FrameLoader::didChangeTitle(DocumentLoader* loader)
3331 {
3332     m_client.didChangeTitle(loader);
3333
3334     if (loader == m_documentLoader) {
3335         // Must update the entries in the back-forward list too.
3336         history().setCurrentItemTitle(loader->title());
3337         // This must go through the WebFrame because it has the right notion of the current b/f item.
3338         m_client.setTitle(loader->title(), loader->urlForHistory());
3339         m_client.setMainFrameDocumentReady(true); // update observers with new DOMDocument
3340         m_client.dispatchDidReceiveTitle(loader->title());
3341     }
3342
3343 #if ENABLE(REMOTE_INSPECTOR)
3344     if (m_frame.isMainFrame())
3345         m_frame.page()->remoteInspectorInformationDidChange();
3346 #endif
3347 }
3348
3349 void FrameLoader::didChangeIcons(IconType type)
3350 {
3351     m_client.dispatchDidChangeIcons(type);
3352 }
3353
3354 void FrameLoader::dispatchDidCommitLoad()
3355 {
3356     if (m_stateMachine.creatingInitialEmptyDocument())
3357         return;
3358
3359     m_client.dispatchDidCommitLoad();
3360
3361     if (m_frame.isMainFrame()) {
3362         m_frame.page()->resetSeenPlugins();
3363         m_frame.page()->resetSeenMediaEngines();
3364     }
3365
3366     InspectorInstrumentation::didCommitLoad(m_frame, m_documentLoader.get());
3367
3368 #if ENABLE(REMOTE_INSPECTOR)
3369     if (m_frame.isMainFrame())
3370         m_frame.page()->remoteInspectorInformationDidChange();
3371 #endif
3372 }
3373
3374 void FrameLoader::tellClientAboutPastMemoryCacheLoads()
3375 {
3376     ASSERT(m_frame.page());
3377     ASSERT(m_frame.page()->areMemoryCacheClientCallsEnabled());
3378
3379     if (!m_documentLoader)
3380         return;
3381
3382     Vector<ResourceRequest> pastLoads;
3383     m_documentLoader->takeMemoryCacheLoadsForClientNotification(pastLoads);
3384
3385     size_t size = pastLoads.size();
3386     for (size_t i = 0; i < size; ++i) {
3387         CachedResource* resource = MemoryCache::singleton().resourceForRequest(pastLoads[i], m_frame.page()->sessionID());
3388
3389         // FIXME: These loads, loaded from cache, but now gone from the cache by the time
3390         // Page::setMemoryCacheClientCallsEnabled(true) is called, will not be seen by the client.
3391         // Consider if there's some efficient way of remembering enough to deliver this client call.
3392         // We have the URL, but not the rest of the response or the length.
3393         if (!resource)
3394             continue;
3395
3396         ResourceRequest request(resource->url());
3397         m_client.dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(), request, resource->response(), resource->encodedSize());
3398     }
3399 }
3400
3401 NetworkingContext* FrameLoader::networkingContext() const
3402 {
3403     return m_networkingContext.get();
3404 }
3405
3406 void FrameLoader::loadProgressingStatusChanged()
3407 {
3408     if (auto* view = m_frame.mainFrame().view())
3409         view->loadProgressingStatusChanged();
3410 }
3411
3412 void FrameLoader::forcePageTransitionIfNeeded()
3413 {
3414     m_client.forcePageTransitionIfNeeded();
3415 }
3416
3417 bool FrameLoaderClient::hasHTMLView() const
3418 {
3419     return true;
3420 }
3421
3422 PassRefPtr<Frame> createWindow(Frame* openerFrame, Frame* lookupFrame, const FrameLoadRequest& request, const WindowFeatures& features, bool& created)
3423 {
3424     ASSERT(!features.dialog || request.frameName().isEmpty());
3425
3426     created = false;
3427
3428     if (!request.frameName().isEmpty() && request.frameName() != "_blank") {
3429         if (RefPtr<Frame> frame = lookupFrame->loader().findFrameForNavigation(request.frameName(), openerFrame->document())) {
3430             if (request.frameName() != "_self") {
3431                 if (Page* page = frame->page())
3432                     page->chrome().focus();
3433             }
3434             return frame.release();
3435         }
3436     }
3437
3438     // Sandboxed frames cannot open new auxiliary browsing contexts.
3439     if (isDocumentSandboxed(openerFrame, SandboxPopups)) {
3440         // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists.
3441         openerFrame->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, "Blocked opening '" + request.resourceRequest().url().stringCenterEllipsizedToLength() + "' in a new window because the request was made in a sandboxed frame whose 'allow-popups' permission is not set.");
3442         return nullptr;
3443     }
3444
3445     // FIXME: Setting the referrer should be the caller's responsibility.
3446     FrameLoadRequest requestWithReferrer = request;
3447     String referrer = SecurityPolicy::generateReferrerHeader(openerFrame->document()->referrerPolicy(), request.resourceRequest().url(), openerFrame->loader().outgoingReferrer());
3448     if (!referrer.isEmpty())
3449         requestWithReferrer.resourceRequest().setHTTPReferrer(referrer);
3450     FrameLoader::addHTTPOriginIfNeeded(requestWithReferrer.resourceRequest(), openerFrame->loader().outgoingOrigin());
3451
3452     Page* oldPage = openerFrame->page();
3453     if (!oldPage)
3454         return nullptr;
3455
3456     Page* page = oldPage->chrome().createWindow(openerFrame, requestWithReferrer, features, NavigationAction(requestWithReferrer.resourceRequest()));
3457     if (!page)
3458         return nullptr;
3459
3460     RefPtr<Frame> frame = &page->mainFrame();
3461
3462     frame->loader().forceSandboxFlags(openerFrame->document()->sandboxFlags());
3463
3464     if (request.frameName() != "_blank")
3465         frame->tree().setName(request.frameName());
3466
3467     page->chrome().setToolbarsVisible(features.toolBarVisible || features.locationBarVisible);
3468
3469     if (!frame->page())
3470         return nullptr;
3471     page->chrome().setStatusbarVisible(features.statusBarVisible);
3472
3473     if (!frame->page())
3474         return nullptr;
3475     page->chrome().setScrollbarsVisible(features.scrollbarsVisible);
3476
3477     if (!frame->page())
3478         return nullptr;
3479     page->chrome().setMenubarVisible(features.menuBarVisible);
3480
3481     if (!frame->page())
3482         return nullptr;
3483     page->chrome().setResizable(features.resizable);
3484
3485     // 'x' and 'y' specify the location of the window, while 'width' and 'height'
3486     // specify the size of the viewport. We can only resize the window, so adjust
3487     // for the difference between the window size and the viewport size.
3488
3489     // FIXME: We should reconcile the initialization of viewport arguments between iOS and non-IOS.
3490 #if !PLATFORM(IOS)
3491     FloatSize viewportSize = page->chrome().pageRect().size();
3492     FloatRect windowRect = page->chrome().windowRect();
3493     if (features.xSet)
3494         windowRect.setX(features.x);
3495     if (features.ySet)
3496         windowRect.setY(features.y);
3497     // Zero width and height mean using default size, not minumum one.
3498     if (features.widthSet && features.width)
3499         windowRect.setWidth(features.width + (windowRect.width() - viewportSize.width()));
3500     if (features.heightSet && features.height)
3501         windowRect.setHeight(features.height + (windowRect.height() - viewportSize.height()));
3502
3503     // Ensure non-NaN values, minimum size as well as being within valid screen area.
3504     FloatRect newWindowRect = DOMWindow::adjustWindowRect(page, windowRect);
3505
3506     if (!frame->page())
3507         return nullptr;
3508     page->chrome().setWindowRect(newWindowRect);
3509 #else
3510     // On iOS, width and height refer to the viewport dimensions.
3511     ViewportArguments arguments;
3512     // Zero width and height mean using default size, not minimum one.
3513     if (features.widthSet && features.width)
3514         arguments.width = features.width;
3515     if (features.heightSet && features.height)
3516         arguments.height = features.height;
3517     frame->setViewportArguments(arguments);
3518 #endif
3519
3520     if (!frame->page())
3521         return nullptr;
3522     page->chrome().show();
3523
3524     created = true;
3525     return frame.release();
3526 }
3527
3528 } // namespace WebCore