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