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