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