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