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