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