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