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