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