2 * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
4 * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
16 * its contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include "FrameLoader.h"
35 #include "ArchiveFactory.h"
38 #include "CachedPage.h"
40 #include "DOMImplementation.h"
41 #include "DOMWindow.h"
42 #include "DocLoader.h"
44 #include "DocumentLoader.h"
46 #include "EditorClient.h"
49 #include "EventNames.h"
50 #include "FloatRect.h"
51 #include "FormState.h"
53 #include "FrameLoadRequest.h"
54 #include "FrameLoaderClient.h"
55 #include "FrameTree.h"
56 #include "FrameView.h"
57 #include "HTMLAnchorElement.h"
58 #include "HTMLFormElement.h"
59 #include "HTMLFrameElement.h"
60 #include "HTMLNames.h"
61 #include "HTMLObjectElement.h"
62 #include "HTTPParsers.h"
63 #include "HistoryItem.h"
64 #include "IconDatabase.h"
65 #include "IconLoader.h"
66 #include "InspectorController.h"
68 #include "MIMETypeRegistry.h"
69 #include "MainResourceLoader.h"
71 #include "PageCache.h"
72 #include "PageGroup.h"
73 #include "PluginData.h"
74 #include "PluginDocument.h"
75 #include "ProgressTracker.h"
76 #include "RenderPart.h"
77 #include "RenderView.h"
78 #include "RenderWidget.h"
79 #include "ResourceHandle.h"
80 #include "ResourceRequest.h"
81 #include "ScriptController.h"
82 #include "ScriptSourceCode.h"
83 #include "ScriptValue.h"
84 #include "SecurityOrigin.h"
85 #include "SegmentedString.h"
87 #include "TextResourceDecoder.h"
88 #include "WindowFeatures.h"
89 #include "XMLHttpRequest.h"
90 #include "XMLTokenizer.h"
91 #include <wtf/CurrentTime.h>
92 #include <wtf/StdLibExtras.h>
94 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
95 #include "ApplicationCache.h"
96 #include "ApplicationCacheResource.h"
100 #include "SVGDocument.h"
101 #include "SVGLocatable.h"
102 #include "SVGNames.h"
103 #include "SVGPreserveAspectRatio.h"
104 #include "SVGSVGElement.h"
105 #include "SVGViewElement.h"
106 #include "SVGViewSpec.h"
112 using namespace SVGNames;
114 using namespace HTMLNames;
116 #if USE(LOW_BANDWIDTH_DISPLAY)
117 const unsigned int cMaxPendingSourceLengthInLowBandwidthDisplay = 128 * 1024;
120 typedef HashSet<String, CaseFoldingHash> LocalSchemesMap;
122 struct FormSubmission {
123 FormSubmission(const char* action, const String& url, PassRefPtr<FormData> formData,
124 const String& target, const String& contentType, const String& boundary,
125 PassRefPtr<Event> event, bool lockHistory, bool lockBackForwardList)
130 , contentType(contentType)
133 , lockHistory(lockHistory)
134 , lockBackForwardList(lockBackForwardList)
140 RefPtr<FormData> formData;
146 bool lockBackForwardList;
149 struct ScheduledRedirection {
150 enum Type { redirection, locationChange, historyNavigation, locationChangeDuringLoad };
157 bool lockBackForwardList;
161 ScheduledRedirection(double delay, const String& url, bool lockHistory, bool lockBackForwardList, bool wasUserGesture, bool refresh)
166 , lockHistory(lockHistory)
167 , lockBackForwardList(lockBackForwardList)
168 , wasUserGesture(wasUserGesture)
169 , wasRefresh(refresh)
173 ScheduledRedirection(Type locationChangeType, const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool wasUserGesture, bool refresh)
174 : type(locationChangeType)
179 , lockHistory(lockHistory)
180 , lockBackForwardList(lockBackForwardList)
181 , wasUserGesture(wasUserGesture)
182 , wasRefresh(refresh)
186 explicit ScheduledRedirection(int historyNavigationSteps)
187 : type(historyNavigation)
189 , historySteps(historyNavigationSteps)
191 , wasUserGesture(false)
197 static double storedTimeOfLastCompletedLoad;
198 static FrameLoader::LocalLoadPolicy localLoadPolicy = FrameLoader::AllowLocalLoadsForLocalOnly;
200 bool isBackForwardLoadType(FrameLoadType type)
203 case FrameLoadTypeStandard:
204 case FrameLoadTypeReload:
205 case FrameLoadTypeReloadFromOrigin:
206 case FrameLoadTypeSame:
207 case FrameLoadTypeRedirectWithLockedBackForwardList:
208 case FrameLoadTypeReplace:
210 case FrameLoadTypeBack:
211 case FrameLoadTypeForward:
212 case FrameLoadTypeIndexedBackForward:
215 ASSERT_NOT_REACHED();
219 static int numRequests(Document* document)
224 return document->docLoader()->requestCount();
227 FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client)
230 , m_state(FrameStateCommittedPage)
231 , m_loadType(FrameLoadTypeStandard)
232 , m_policyLoadType(FrameLoadTypeStandard)
233 , m_delegateIsHandlingProvisionalLoadError(false)
234 , m_delegateIsDecidingNavigationPolicy(false)
235 , m_delegateIsHandlingUnimplementablePolicy(false)
236 , m_firstLayoutDone(false)
237 , m_quickRedirectComing(false)
238 , m_sentRedirectNotification(false)
239 , m_inStopAllLoaders(false)
240 , m_navigationDuringLoad(false)
241 , m_isExecutingJavaScriptFormAction(false)
242 , m_isRunningScript(false)
243 , m_didCallImplicitClose(false)
244 , m_wasUnloadEventEmitted(false)
245 , m_isComplete(false)
246 , m_isLoadingMainResource(false)
247 , m_cancellingWithLoadInProgress(false)
248 , m_needsClear(false)
249 , m_receivedData(false)
250 , m_encodingWasChosenByUser(false)
251 , m_containsPlugIns(false)
252 , m_redirectionTimer(this, &FrameLoader::redirectionTimerFired)
253 , m_checkCompletedTimer(this, &FrameLoader::checkCompletedTimerFired)
254 , m_checkLoadCompleteTimer(this, &FrameLoader::checkLoadCompleteTimerFired)
256 , m_openedByDOM(false)
257 , m_creatingInitialEmptyDocument(false)
258 , m_isDisplayingInitialEmptyDocument(false)
259 , m_committedFirstRealDocumentLoad(false)
260 , m_didPerformFirstNavigation(false)
262 , m_didDispatchDidCommitLoad(false)
264 #if USE(LOW_BANDWIDTH_DISPLAY)
265 , m_useLowBandwidthDisplay(true)
266 , m_finishedParsingDuringLowBandwidthDisplay(false)
267 , m_needToSwitchOutLowBandwidthDisplay(false)
270 , m_forceReloadWmlDeck(false)
275 FrameLoader::~FrameLoader()
279 HashSet<Frame*>::iterator end = m_openedFrames.end();
280 for (HashSet<Frame*>::iterator it = m_openedFrames.begin(); it != end; ++it)
281 (*it)->loader()->m_opener = 0;
283 m_client->frameLoaderDestroyed();
286 void FrameLoader::init()
288 // this somewhat odd set of steps is needed to give the frame an initial empty document
289 m_isDisplayingInitialEmptyDocument = false;
290 m_creatingInitialEmptyDocument = true;
291 setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(KURL("")), SubstituteData()).get());
292 setProvisionalDocumentLoader(m_policyDocumentLoader.get());
293 setState(FrameStateProvisional);
294 m_provisionalDocumentLoader->setResponse(ResourceResponse(KURL(), "text/html", 0, String(), String()));
295 m_provisionalDocumentLoader->finishedLoading();
296 begin(KURL(), false);
298 m_frame->document()->cancelParsing();
299 m_creatingInitialEmptyDocument = false;
300 m_didCallImplicitClose = true;
303 void FrameLoader::setDefersLoading(bool defers)
305 if (m_documentLoader)
306 m_documentLoader->setDefersLoading(defers);
307 if (m_provisionalDocumentLoader)
308 m_provisionalDocumentLoader->setDefersLoading(defers);
309 if (m_policyDocumentLoader)
310 m_policyDocumentLoader->setDefersLoading(defers);
313 Frame* FrameLoader::createWindow(FrameLoader* frameLoaderForFrameLookup, const FrameLoadRequest& request, const WindowFeatures& features, bool& created)
315 ASSERT(!features.dialog || request.frameName().isEmpty());
317 if (!request.frameName().isEmpty() && request.frameName() != "_blank") {
318 Frame* frame = frameLoaderForFrameLookup->frame()->tree()->find(request.frameName());
319 if (frame && shouldAllowNavigation(frame)) {
320 if (!request.resourceRequest().url().isEmpty())
321 frame->loader()->loadFrameRequestWithFormAndValues(request, false, false, 0, 0, HashMap<String, String>());
322 if (Page* page = frame->page())
323 page->chrome()->focus();
329 // FIXME: Setting the referrer should be the caller's responsibility.
330 FrameLoadRequest requestWithReferrer = request;
331 requestWithReferrer.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
332 addHTTPOriginIfNeeded(requestWithReferrer.resourceRequest(), outgoingOrigin());
334 Page* oldPage = m_frame->page();
338 Page* page = oldPage->chrome()->createWindow(m_frame, requestWithReferrer, features);
342 Frame* frame = page->mainFrame();
343 if (request.frameName() != "_blank")
344 frame->tree()->setName(request.frameName());
346 page->chrome()->setToolbarsVisible(features.toolBarVisible || features.locationBarVisible);
347 page->chrome()->setStatusbarVisible(features.statusBarVisible);
348 page->chrome()->setScrollbarsVisible(features.scrollbarsVisible);
349 page->chrome()->setMenubarVisible(features.menuBarVisible);
350 page->chrome()->setResizable(features.resizable);
352 // 'x' and 'y' specify the location of the window, while 'width' and 'height'
353 // specify the size of the page. We can only resize the window, so
354 // adjust for the difference between the window size and the page size.
356 FloatRect windowRect = page->chrome()->windowRect();
357 FloatSize pageSize = page->chrome()->pageRect().size();
359 windowRect.setX(features.x);
361 windowRect.setY(features.y);
362 if (features.widthSet)
363 windowRect.setWidth(features.width + (windowRect.width() - pageSize.width()));
364 if (features.heightSet)
365 windowRect.setHeight(features.height + (windowRect.height() - pageSize.height()));
366 page->chrome()->setWindowRect(windowRect);
368 page->chrome()->show();
374 bool FrameLoader::canHandleRequest(const ResourceRequest& request)
376 return m_client->canHandleRequest(request);
379 void FrameLoader::changeLocation(const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool userGesture, bool refresh)
381 changeLocation(completeURL(url), referrer, lockHistory, lockBackForwardList, userGesture, refresh);
385 void FrameLoader::changeLocation(const KURL& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool userGesture, bool refresh)
387 RefPtr<Frame> protect(m_frame);
389 ResourceRequest request(url, referrer, refresh ? ReloadIgnoringCacheData : UseProtocolCachePolicy);
391 if (executeIfJavaScriptURL(request.url(), userGesture))
394 urlSelected(request, "_self", 0, lockHistory, lockBackForwardList, userGesture);
397 void FrameLoader::urlSelected(const FrameLoadRequest& request, Event* event, bool lockHistory, bool lockBackForwardList)
399 FrameLoadRequest copy = request;
400 if (copy.resourceRequest().httpReferrer().isEmpty())
401 copy.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
402 addHTTPOriginIfNeeded(copy.resourceRequest(), outgoingOrigin());
404 loadFrameRequestWithFormAndValues(copy, lockHistory, lockBackForwardList, event, 0, HashMap<String, String>());
407 void FrameLoader::urlSelected(const ResourceRequest& request, const String& _target, Event* triggeringEvent, bool lockHistory, bool lockBackForwardList, bool userGesture)
409 if (executeIfJavaScriptURL(request.url(), userGesture, false))
412 String target = _target;
413 if (target.isEmpty())
414 target = m_frame->document()->baseTarget();
416 FrameLoadRequest frameRequest(request, target);
418 urlSelected(frameRequest, triggeringEvent, lockHistory, lockBackForwardList);
421 bool FrameLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String& urlString, const AtomicString& frameName)
423 #if USE(LOW_BANDWIDTH_DISPLAY)
424 // don't create sub-frame during low bandwidth display
425 if (frame()->document()->inLowBandwidthDisplay()) {
426 m_needToSwitchOutLowBandwidthDisplay = true;
431 // Support for <frame src="javascript:string">
434 if (protocolIs(urlString, "javascript")) {
435 scriptURL = completeURL(urlString); // completeURL() encodes the URL.
438 url = completeURL(urlString);
440 Frame* frame = ownerElement->contentFrame();
442 frame->loader()->scheduleLocationChange(url.string(), m_outgoingReferrer, true, true, userGestureHint());
444 frame = loadSubframe(ownerElement, url, frameName, m_outgoingReferrer);
449 if (!scriptURL.isEmpty())
450 frame->loader()->executeIfJavaScriptURL(scriptURL);
455 Frame* FrameLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const String& name, const String& referrer)
457 bool allowsScrolling = true;
458 int marginWidth = -1;
459 int marginHeight = -1;
460 if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag)) {
461 HTMLFrameElementBase* o = static_cast<HTMLFrameElementBase*>(ownerElement);
462 allowsScrolling = o->scrollingMode() != ScrollbarAlwaysOff;
463 marginWidth = o->getMarginWidth();
464 marginHeight = o->getMarginHeight();
467 if (!canLoad(url, referrer)) {
468 FrameLoader::reportLocalLoadFailed(m_frame, url.string());
472 bool hideReferrer = shouldHideReferrer(url, referrer);
473 RefPtr<Frame> frame = m_client->createFrame(url, name, ownerElement, hideReferrer ? String() : referrer,
474 allowsScrolling, marginWidth, marginHeight);
477 checkCallImplicitClose();
481 frame->loader()->m_isComplete = false;
483 RenderObject* renderer = ownerElement->renderer();
484 FrameView* view = frame->view();
485 if (renderer && renderer->isWidget() && view)
486 static_cast<RenderWidget*>(renderer)->setWidget(view);
488 checkCallImplicitClose();
490 // In these cases, the synchronous load would have finished
491 // before we could connect the signals, so make sure to send the
492 // completed() signal for the child by hand
493 // FIXME: In this case the Frame will have finished loading before
494 // it's being added to the child list. It would be a good idea to
495 // create the child first, then invoke the loader separately.
496 if (url.isEmpty() || url == blankURL()) {
497 frame->loader()->completed();
498 frame->loader()->checkCompleted();
504 void FrameLoader::submitFormAgain()
506 if (m_isRunningScript)
508 OwnPtr<FormSubmission> form(m_deferredFormSubmission.release());
511 submitForm(form->action, form->url, form->formData, form->target, form->contentType, form->boundary, form->event.get(), form->lockHistory, form->lockBackForwardList);
514 void FrameLoader::submitForm(const char* action, const String& url, PassRefPtr<FormData> formData,
515 const String& target, const String& contentType, const String& boundary, Event* event, bool lockHistory, bool lockBackForwardList)
519 if (!m_frame->page())
522 KURL u = completeURL(url.isNull() ? "" : url);
523 // FIXME: Do we really need to special-case an empty URL?
524 // Would it be better to just go on with the form submisson and let the I/O fail?
528 if (u.protocolIs("javascript")) {
529 m_isExecutingJavaScriptFormAction = true;
530 executeIfJavaScriptURL(u, false, false);
531 m_isExecutingJavaScriptFormAction = false;
535 if (m_isRunningScript) {
536 if (m_deferredFormSubmission)
538 m_deferredFormSubmission.set(new FormSubmission(action, url, formData, target, contentType, boundary, event, lockHistory, lockBackForwardList));
542 formData->generateFiles(m_frame->page()->chrome()->client());
544 FrameLoadRequest frameRequest;
546 if (!m_outgoingReferrer.isEmpty())
547 frameRequest.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
549 frameRequest.setFrameName(target.isEmpty() ? m_frame->document()->baseTarget() : target);
551 // Handle mailto: forms
552 bool isMailtoForm = equalIgnoringCase(u.protocol(), "mailto");
553 if (isMailtoForm && strcmp(action, "GET") != 0) {
554 // Append body= for POST mailto, replace the whole query string for GET one.
555 String body = formData->flattenToString();
556 String query = u.query();
557 if (!query.isEmpty())
559 u.setQuery(query + body);
562 if (strcmp(action, "GET") == 0) {
563 u.setQuery(formData->flattenToString());
566 frameRequest.resourceRequest().setHTTPBody(formData.get());
567 frameRequest.resourceRequest().setHTTPMethod("POST");
569 // construct some user headers if necessary
570 if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
571 frameRequest.resourceRequest().setHTTPContentType(contentType);
572 else // contentType must be "multipart/form-data"
573 frameRequest.resourceRequest().setHTTPContentType(contentType + "; boundary=" + boundary);
576 frameRequest.resourceRequest().setURL(u);
577 addHTTPOriginIfNeeded(frameRequest.resourceRequest(), outgoingOrigin());
579 submitForm(frameRequest, event, lockHistory, lockBackForwardList);
582 void FrameLoader::stopLoading(bool sendUnload)
584 if (m_frame->document() && m_frame->document()->tokenizer())
585 m_frame->document()->tokenizer()->stopParsing();
588 if (m_frame->document()) {
589 if (m_didCallImplicitClose && !m_wasUnloadEventEmitted) {
590 Node* currentFocusedNode = m_frame->document()->focusedNode();
591 if (currentFocusedNode)
592 currentFocusedNode->aboutToUnload();
593 m_frame->document()->dispatchWindowEvent(eventNames().unloadEvent, false, false);
594 if (m_frame->document())
595 m_frame->document()->updateRendering();
596 m_wasUnloadEventEmitted = true;
597 if (m_frame->eventHandler()->pendingFrameUnloadEventCount())
598 m_frame->eventHandler()->clearPendingFrameUnloadEventCount();
599 if (m_frame->eventHandler()->pendingFrameBeforeUnloadEventCount())
600 m_frame->eventHandler()->clearPendingFrameBeforeUnloadEventCount();
603 if (m_frame->document() && !m_frame->document()->inPageCache())
604 m_frame->document()->removeAllEventListenersFromAllNodes();
607 m_isComplete = true; // to avoid calling completed() in finishedParsing() (David)
608 m_isLoadingMainResource = false;
609 m_didCallImplicitClose = true; // don't want that one either
611 if (m_frame->document() && m_frame->document()->parsing()) {
613 m_frame->document()->setParsing(false);
616 m_workingURL = KURL();
618 if (Document* doc = m_frame->document()) {
619 if (DocLoader* docLoader = doc->docLoader())
620 cache()->loader()->cancelRequests(docLoader);
623 doc->stopDatabases();
627 // tell all subframes to stop as well
628 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
629 child->loader()->stopLoading(sendUnload);
633 #if USE(LOW_BANDWIDTH_DISPLAY)
634 if (m_frame->document() && m_frame->document()->inLowBandwidthDisplay()) {
635 // Since loading is forced to stop, reset the state without really switching.
636 m_needToSwitchOutLowBandwidthDisplay = false;
637 switchOutLowBandwidthDisplayIfReady();
642 void FrameLoader::stop()
644 // http://bugs.webkit.org/show_bug.cgi?id=10854
645 // The frame's last ref may be removed and it will be deleted by checkCompleted().
646 RefPtr<Frame> protector(m_frame);
648 if (m_frame->document()->tokenizer())
649 m_frame->document()->tokenizer()->stopParsing();
650 m_frame->document()->finishParsing();
653 m_iconLoader->stopLoading();
656 bool FrameLoader::closeURL()
660 m_frame->editor()->clearUndoRedoOperations();
664 void FrameLoader::cancelRedirection(bool cancelWithLoadInProgress)
666 m_cancellingWithLoadInProgress = cancelWithLoadInProgress;
668 stopRedirectionTimer();
670 m_scheduledRedirection.clear();
673 KURL FrameLoader::iconURL()
675 // If this isn't a top level frame, return nothing
676 if (m_frame->tree() && m_frame->tree()->parent())
679 // If we have an iconURL from a Link element, return that
680 if (!m_frame->document()->iconURL().isEmpty())
681 return KURL(m_frame->document()->iconURL());
683 // Don't return a favicon iconURL unless we're http or https
684 if (!m_URL.protocolIs("http") && !m_URL.protocolIs("https"))
688 url.setProtocol(m_URL.protocol());
689 url.setHost(m_URL.host());
690 if (int port = m_URL.port())
692 url.setPath("/favicon.ico");
696 bool FrameLoader::didOpenURL(const KURL& url)
698 if (m_scheduledRedirection && m_scheduledRedirection->type == ScheduledRedirection::locationChangeDuringLoad)
699 // A redirect was scheduled before the document was created.
700 // This can happen when one frame changes another frame's location.
704 m_frame->editor()->clearLastEditCommand();
707 m_isComplete = false;
708 m_isLoadingMainResource = true;
709 m_didCallImplicitClose = false;
711 m_frame->setJSStatusBarText(String());
712 m_frame->setJSDefaultStatusBarText(String());
715 if ((m_URL.protocolIs("http") || m_URL.protocolIs("https")) && !m_URL.host().isEmpty() && m_URL.path().isEmpty())
717 m_workingURL = m_URL;
724 void FrameLoader::didExplicitOpen()
726 m_isComplete = false;
727 m_didCallImplicitClose = false;
729 // Calling document.open counts as committing the first real document load.
730 m_committedFirstRealDocumentLoad = true;
732 // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
733 // from a subsequent window.document.open / window.document.write call.
734 // Cancelling redirection here works for all cases because document.open
735 // implicitly precedes document.write.
737 if (m_frame->document()->url() != blankURL())
738 m_URL = m_frame->document()->url();
741 bool FrameLoader::executeIfJavaScriptURL(const KURL& url, bool userGesture, bool replaceDocument)
743 if (!url.protocolIs("javascript"))
746 String script = decodeURLEscapeSequences(url.string().substring(strlen("javascript:")));
747 ScriptValue result = executeScript(script, userGesture);
750 if (!result.getString(scriptResult))
753 SecurityOrigin* currentSecurityOrigin = 0;
754 currentSecurityOrigin = m_frame->document()->securityOrigin();
756 // FIXME: We should always replace the document, but doing so
757 // synchronously can cause crashes:
758 // http://bugs.webkit.org/show_bug.cgi?id=16782
759 if (replaceDocument) {
760 begin(m_URL, true, currentSecurityOrigin);
768 ScriptValue FrameLoader::executeScript(const String& script, bool forceUserGesture)
770 return executeScript(ScriptSourceCode(script, forceUserGesture ? KURL() : m_URL));
773 ScriptValue FrameLoader::executeScript(const ScriptSourceCode& sourceCode)
775 if (!m_frame->script()->isEnabled() || m_frame->script()->isPaused())
776 return ScriptValue();
778 bool wasRunningScript = m_isRunningScript;
779 m_isRunningScript = true;
781 ScriptValue result = m_frame->script()->evaluate(sourceCode);
783 if (!wasRunningScript) {
784 m_isRunningScript = false;
786 Document::updateDocumentsRendering();
792 void FrameLoader::cancelAndClear()
800 m_frame->script()->updatePlatformScriptObjects();
803 void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects)
805 m_frame->editor()->clear();
809 m_needsClear = false;
811 if (!m_frame->document()->inPageCache()) {
812 m_frame->document()->cancelParsing();
813 m_frame->document()->stopActiveDOMObjects();
814 if (m_frame->document()->attached()) {
815 m_frame->document()->willRemove();
816 m_frame->document()->detach();
818 m_frame->document()->removeFocusedNodeOfSubtree(m_frame->document());
822 // Do this after detaching the document so that the unload event works.
823 if (clearWindowProperties) {
824 m_frame->clearDOMWindow();
825 m_frame->script()->clearWindowShell();
828 m_frame->selection()->clear();
829 m_frame->eventHandler()->clear();
831 m_frame->view()->clear();
833 m_frame->setSelectionGranularity(CharacterGranularity);
835 // Do not drop the document before the ScriptController and view are cleared
836 // as some destructors might still try to access the document.
837 m_frame->setDocument(0);
840 m_containsPlugIns = false;
842 if (clearScriptObjects)
843 m_frame->script()->clearScriptObjects();
845 m_redirectionTimer.stop();
846 m_scheduledRedirection.clear();
848 m_checkCompletedTimer.stop();
849 m_checkLoadCompleteTimer.stop();
851 m_receivedData = false;
852 m_isDisplayingInitialEmptyDocument = false;
854 if (!m_encodingWasChosenByUser)
855 m_encoding = String();
858 void FrameLoader::receivedFirstData()
860 begin(m_workingURL, false);
862 dispatchDidCommitLoad();
863 dispatchWindowObjectAvailable();
865 String ptitle = m_documentLoader->title();
866 // If we have a title let the WebView know about it.
867 if (!ptitle.isNull())
868 m_client->dispatchDidReceiveTitle(ptitle);
870 m_workingURL = KURL();
874 if (!m_documentLoader)
876 if (!parseHTTPRefresh(m_documentLoader->response().httpHeaderField("Refresh"), false, delay, url))
880 url = m_URL.string();
882 url = m_frame->document()->completeURL(url).string();
884 scheduleHTTPRedirection(delay, url);
887 const String& FrameLoader::responseMIMEType() const
889 return m_responseMIMEType;
892 void FrameLoader::setResponseMIMEType(const String& type)
894 m_responseMIMEType = type;
897 void FrameLoader::begin()
902 void FrameLoader::begin(const KURL& url, bool dispatch, SecurityOrigin* origin)
904 // We need to take a reference to the security origin because |clear|
905 // might destroy the document that owns it.
906 RefPtr<SecurityOrigin> forcedSecurityOrigin = origin;
908 bool resetScripting = !(m_isDisplayingInitialEmptyDocument && m_frame->document()->securityOrigin()->isSecureTransitionTo(url));
909 clear(resetScripting, resetScripting);
911 m_frame->script()->updatePlatformScriptObjects();
914 m_isComplete = false;
915 m_didCallImplicitClose = false;
916 m_isLoadingMainResource = true;
917 m_isDisplayingInitialEmptyDocument = m_creatingInitialEmptyDocument;
920 ref.setUser(String());
921 ref.setPass(String());
922 ref.setRef(String());
923 m_outgoingReferrer = ref.string();
926 RefPtr<Document> document;
928 if (!m_isDisplayingInitialEmptyDocument && m_client->shouldUsePluginDocument(m_responseMIMEType))
929 document = PluginDocument::create(m_frame);
931 document = DOMImplementation::createDocument(m_responseMIMEType, m_frame, m_frame->inViewSourceMode());
932 m_frame->setDocument(document);
935 dispatchWindowObjectAvailable();
937 document->setURL(m_URL);
939 document->setDecoder(m_decoder.get());
940 if (forcedSecurityOrigin)
941 document->setSecurityOrigin(forcedSecurityOrigin.get());
943 m_frame->domWindow()->setURL(document->url());
944 m_frame->domWindow()->setSecurityOrigin(document->securityOrigin());
946 updatePolicyBaseURL();
948 Settings* settings = document->settings();
949 document->docLoader()->setAutoLoadImages(settings && settings->loadsImagesAutomatically());
951 if (m_documentLoader) {
952 String dnsPrefetchControl = m_documentLoader->response().httpHeaderField("X-DNS-Prefetch-Control");
953 if (!dnsPrefetchControl.isEmpty())
954 document->parseDNSPrefetchControlHeader(dnsPrefetchControl);
957 #if FRAME_LOADS_USER_STYLESHEET
958 KURL userStyleSheet = settings ? settings->userStyleSheetLocation() : KURL();
959 if (!userStyleSheet.isEmpty())
960 m_frame->setUserStyleSheetLocation(userStyleSheet);
963 restoreDocumentState();
965 document->implicitOpen();
968 m_frame->view()->setContentsSize(IntSize());
970 #if USE(LOW_BANDWIDTH_DISPLAY)
971 // Low bandwidth display is a first pass display without external resources
972 // used to give an instant visual feedback. We currently only enable it for
973 // HTML documents in the top frame.
974 if (document->isHTMLDocument() && !m_frame->tree()->parent() && m_useLowBandwidthDisplay) {
975 m_pendingSourceInLowBandwidthDisplay = String();
976 m_finishedParsingDuringLowBandwidthDisplay = false;
977 m_needToSwitchOutLowBandwidthDisplay = false;
978 document->setLowBandwidthDisplay(true);
983 void FrameLoader::write(const char* str, int len, bool flush)
985 if (len == 0 && !flush)
991 Tokenizer* tokenizer = m_frame->document()->tokenizer();
992 if (tokenizer && tokenizer->wantsRawData()) {
994 tokenizer->writeRawData(str, len);
999 Settings* settings = m_frame->settings();
1000 m_decoder = TextResourceDecoder::create(m_responseMIMEType, settings ? settings->defaultTextEncodingName() : String());
1001 if (m_encoding.isEmpty()) {
1002 Frame* parentFrame = m_frame->tree()->parent();
1003 if (parentFrame && parentFrame->document()->securityOrigin()->canAccess(m_frame->document()->securityOrigin()))
1004 m_decoder->setEncoding(parentFrame->document()->inputEncoding(), TextResourceDecoder::DefaultEncoding);
1006 m_decoder->setEncoding(m_encoding,
1007 m_encodingWasChosenByUser ? TextResourceDecoder::UserChosenEncoding : TextResourceDecoder::EncodingFromHTTPHeader);
1009 m_frame->document()->setDecoder(m_decoder.get());
1012 String decoded = m_decoder->decode(str, len);
1014 decoded += m_decoder->flush();
1015 if (decoded.isEmpty())
1018 #if USE(LOW_BANDWIDTH_DISPLAY)
1019 if (m_frame->document()->inLowBandwidthDisplay())
1020 m_pendingSourceInLowBandwidthDisplay.append(decoded);
1023 if (!m_receivedData) {
1024 m_receivedData = true;
1025 if (m_decoder->encoding().usesVisualOrdering())
1026 m_frame->document()->setVisuallyOrdered();
1027 m_frame->document()->recalcStyle(Node::Force);
1031 ASSERT(!tokenizer->wantsRawData());
1032 tokenizer->write(decoded, true);
1036 void FrameLoader::write(const String& str)
1041 if (!m_receivedData) {
1042 m_receivedData = true;
1043 m_frame->document()->setParseMode(Document::Strict);
1046 if (Tokenizer* tokenizer = m_frame->document()->tokenizer())
1047 tokenizer->write(str, true);
1050 void FrameLoader::end()
1052 m_isLoadingMainResource = false;
1053 endIfNotLoadingMainResource();
1056 void FrameLoader::endIfNotLoadingMainResource()
1058 if (m_isLoadingMainResource || !m_frame->page() || !m_frame->document())
1061 // http://bugs.webkit.org/show_bug.cgi?id=10854
1062 // The frame's last ref may be removed and it can be deleted by checkCompleted(),
1063 // so we'll add a protective refcount
1064 RefPtr<Frame> protector(m_frame);
1066 // make sure nothing's left in there
1068 m_frame->document()->finishParsing();
1069 #if USE(LOW_BANDWIDTH_DISPLAY)
1070 if (m_frame->document()->inLowBandwidthDisplay()) {
1071 m_finishedParsingDuringLowBandwidthDisplay = true;
1072 switchOutLowBandwidthDisplayIfReady();
1077 void FrameLoader::iconLoadDecisionAvailable()
1079 if (!m_mayLoadIconLater)
1081 LOG(IconDatabase, "FrameLoader %p was told a load decision is available for its icon", this);
1083 m_mayLoadIconLater = false;
1086 void FrameLoader::startIconLoader()
1088 // FIXME: We kick off the icon loader when the frame is done receiving its main resource.
1089 // But we should instead do it when we're done parsing the head element.
1090 if (!isLoadingMainFrame())
1093 if (!iconDatabase() || !iconDatabase()->isEnabled())
1096 KURL url(iconURL());
1097 String urlString(url.string());
1098 if (urlString.isEmpty())
1101 // If we're not reloading and the icon database doesn't say to load now then bail before we actually start the load
1102 if (loadType() != FrameLoadTypeReload && loadType() != FrameLoadTypeReloadFromOrigin) {
1103 IconLoadDecision decision = iconDatabase()->loadDecisionForIconURL(urlString, m_documentLoader.get());
1104 if (decision == IconLoadNo) {
1105 LOG(IconDatabase, "FrameLoader::startIconLoader() - Told not to load this icon, committing iconURL %s to database for pageURL mapping", urlString.ascii().data());
1106 commitIconURLToIconDatabase(url);
1108 // We were told not to load this icon - that means this icon is already known by the database
1109 // 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
1110 // has done it. This is after registering for the notification so the WebView can call the appropriate delegate method.
1111 // Otherwise if the icon data *is* available, notify the delegate
1112 if (!iconDatabase()->iconDataKnownForIconURL(urlString)) {
1113 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());
1114 m_client->registerForIconNotification();
1115 iconDatabase()->iconForPageURL(m_URL.string(), IntSize(0, 0));
1116 iconDatabase()->iconForPageURL(originalRequestURL().string(), IntSize(0, 0));
1118 m_client->dispatchDidReceiveIcon();
1123 if (decision == IconLoadUnknown) {
1124 // In this case, we may end up loading the icon later, but we still want to commit the icon url mapping to the database
1125 // 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
1126 // We also tell the client to register for the notification that the icon is received now so it isn't missed in case the
1127 // icon is later read in from disk
1128 LOG(IconDatabase, "FrameLoader %p might load icon %s later", this, urlString.ascii().data());
1129 m_mayLoadIconLater = true;
1130 m_client->registerForIconNotification();
1131 commitIconURLToIconDatabase(url);
1136 // This is either a reload or the icon database said "yes, load the icon", so kick off the load!
1138 m_iconLoader.set(IconLoader::create(m_frame).release());
1140 m_iconLoader->startLoading();
1143 void FrameLoader::setLocalLoadPolicy(LocalLoadPolicy policy)
1145 localLoadPolicy = policy;
1148 bool FrameLoader::restrictAccessToLocal()
1150 return localLoadPolicy != FrameLoader::AllowLocalLoadsForAll;
1153 bool FrameLoader::allowSubstituteDataAccessToLocal()
1155 return localLoadPolicy != FrameLoader::AllowLocalLoadsForLocalOnly;
1158 static LocalSchemesMap& localSchemes()
1160 DEFINE_STATIC_LOCAL(LocalSchemesMap, localSchemes, ());
1162 if (localSchemes.isEmpty()) {
1163 localSchemes.add("file");
1165 localSchemes.add("applewebdata");
1168 localSchemes.add("qrc");
1172 return localSchemes;
1175 void FrameLoader::commitIconURLToIconDatabase(const KURL& icon)
1177 ASSERT(iconDatabase());
1178 LOG(IconDatabase, "Committing iconURL %s to database for pageURLs %s and %s", icon.string().ascii().data(), m_URL.string().ascii().data(), originalRequestURL().string().ascii().data());
1179 iconDatabase()->setIconURLForPageURL(icon.string(), m_URL.string());
1180 iconDatabase()->setIconURLForPageURL(icon.string(), originalRequestURL().string());
1183 void FrameLoader::restoreDocumentState()
1185 Document* doc = m_frame->document();
1187 HistoryItem* itemToRestore = 0;
1189 switch (loadType()) {
1190 case FrameLoadTypeReload:
1191 case FrameLoadTypeReloadFromOrigin:
1192 case FrameLoadTypeSame:
1193 case FrameLoadTypeReplace:
1195 case FrameLoadTypeBack:
1196 case FrameLoadTypeForward:
1197 case FrameLoadTypeIndexedBackForward:
1198 case FrameLoadTypeRedirectWithLockedBackForwardList:
1199 case FrameLoadTypeStandard:
1200 itemToRestore = m_currentHistoryItem.get();
1206 LOG(Loading, "WebCoreLoading %s: restoring form state from %p", m_frame->tree()->name().string().utf8().data(), itemToRestore);
1207 doc->setStateForNewFormElements(itemToRestore->documentState());
1210 void FrameLoader::gotoAnchor()
1212 // If our URL has no ref, then we have no place we need to jump to.
1213 // OTOH If CSS target was set previously, we want to set it to 0, recalc
1214 // and possibly repaint because :target pseudo class may have been
1215 // set (see bug 11321).
1216 if (!m_URL.hasRef() && !m_frame->document()->cssTarget())
1219 String ref = m_URL.ref();
1220 if (gotoAnchor(ref))
1223 // Try again after decoding the ref, based on the document's encoding.
1225 gotoAnchor(decodeURLEscapeSequences(ref, m_decoder->encoding()));
1228 void FrameLoader::finishedParsing()
1230 if (m_creatingInitialEmptyDocument)
1233 // This can be called from the Frame's destructor, in which case we shouldn't protect ourselves
1234 // because doing so will cause us to re-enter the destructor when protector goes out of scope.
1235 // Null-checking the FrameView indicates whether or not we're in the destructor.
1236 RefPtr<Frame> protector = m_frame->view() ? m_frame : 0;
1238 m_client->dispatchDidFinishDocumentLoad();
1242 if (!m_frame->view())
1243 return; // We are being destroyed by something checkCompleted called.
1245 // Check if the scrollbars are really needed for the content.
1246 // If not, remove them, relayout, and repaint.
1247 m_frame->view()->restoreScrollbar();
1252 void FrameLoader::loadDone()
1257 void FrameLoader::checkCompleted()
1259 // Any frame that hasn't completed yet?
1260 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1261 if (!child->loader()->m_isComplete)
1264 // Have we completed before?
1268 // Are we still parsing?
1269 if (m_frame->document()->parsing())
1272 // Still waiting for images/scripts?
1273 if (numRequests(m_frame->document()))
1276 #if USE(LOW_BANDWIDTH_DISPLAY)
1277 // as switch will be called, don't complete yet
1278 if (m_frame->document()->inLowBandwidthDisplay() && m_needToSwitchOutLowBandwidthDisplay)
1283 m_isComplete = true;
1285 RefPtr<Frame> protect(m_frame);
1286 checkCallImplicitClose(); // if we didn't do it before
1288 // Do not start a redirection timer for subframes here.
1289 // That is deferred until the parent is completed.
1290 if (m_scheduledRedirection && !m_frame->tree()->parent())
1291 startRedirectionTimer();
1294 if (m_frame->page())
1295 checkLoadComplete();
1298 void FrameLoader::checkCompletedTimerFired(Timer<FrameLoader>*)
1303 void FrameLoader::scheduleCheckCompleted()
1305 if (!m_checkCompletedTimer.isActive())
1306 m_checkCompletedTimer.startOneShot(0);
1309 void FrameLoader::checkLoadCompleteTimerFired(Timer<FrameLoader>*)
1311 if (!m_frame->page())
1313 checkLoadComplete();
1316 void FrameLoader::scheduleCheckLoadComplete()
1318 if (!m_checkLoadCompleteTimer.isActive())
1319 m_checkLoadCompleteTimer.startOneShot(0);
1322 void FrameLoader::checkCallImplicitClose()
1324 if (m_didCallImplicitClose || m_frame->document()->parsing())
1327 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1328 if (!child->loader()->m_isComplete) // still got a frame running -> too early
1331 m_didCallImplicitClose = true;
1332 m_wasUnloadEventEmitted = false;
1333 m_frame->document()->implicitClose();
1336 KURL FrameLoader::baseURL() const
1338 ASSERT(m_frame->document());
1339 return m_frame->document()->baseURL();
1342 String FrameLoader::baseTarget() const
1344 ASSERT(m_frame->document());
1345 return m_frame->document()->baseTarget();
1348 KURL FrameLoader::completeURL(const String& url)
1350 ASSERT(m_frame->document());
1351 return m_frame->document()->completeURL(url);
1354 void FrameLoader::scheduleHTTPRedirection(double delay, const String& url)
1356 if (delay < 0 || delay > INT_MAX / 1000)
1359 if (!m_frame->page())
1362 // We want a new history item if the refresh timeout is > 1 second.
1363 if (!m_scheduledRedirection || delay <= m_scheduledRedirection->delay)
1364 scheduleRedirection(new ScheduledRedirection(delay, url, true, delay <= 1, false, false));
1367 void FrameLoader::scheduleLocationChange(const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool wasUserGesture)
1369 if (!m_frame->page())
1372 // If the URL we're going to navigate to is the same as the current one, except for the
1373 // fragment part, we don't need to schedule the location change.
1374 KURL parsedURL(url);
1375 if (parsedURL.hasRef() && equalIgnoringRef(m_URL, parsedURL)) {
1376 changeLocation(url, referrer, lockHistory, lockBackForwardList, wasUserGesture);
1380 // Handle a location change of a page with no document as a special case.
1381 // This may happen when a frame changes the location of another frame.
1382 bool duringLoad = !m_committedFirstRealDocumentLoad;
1384 // If a redirect was scheduled during a load, then stop the current load.
1385 // Otherwise when the current load transitions from a provisional to a
1386 // committed state, pending redirects may be cancelled.
1388 if (m_provisionalDocumentLoader)
1389 m_provisionalDocumentLoader->stopLoading();
1393 ScheduledRedirection::Type type = duringLoad
1394 ? ScheduledRedirection::locationChangeDuringLoad : ScheduledRedirection::locationChange;
1395 scheduleRedirection(new ScheduledRedirection(type, url, referrer, lockHistory, lockBackForwardList, wasUserGesture, false));
1398 void FrameLoader::scheduleRefresh(bool wasUserGesture)
1400 if (!m_frame->page())
1403 ScheduledRedirection::Type type = ScheduledRedirection::locationChange;
1404 scheduleRedirection(new ScheduledRedirection(type, m_URL.string(), m_outgoingReferrer, true, true, wasUserGesture, true));
1407 bool FrameLoader::isLocationChange(const ScheduledRedirection& redirection)
1409 switch (redirection.type) {
1410 case ScheduledRedirection::redirection:
1412 case ScheduledRedirection::historyNavigation:
1413 case ScheduledRedirection::locationChange:
1414 case ScheduledRedirection::locationChangeDuringLoad:
1417 ASSERT_NOT_REACHED();
1421 void FrameLoader::scheduleHistoryNavigation(int steps)
1423 if (!m_frame->page())
1426 // navigation will always be allowed in the 0 steps case, which is OK because that's supposed to force a reload.
1427 if (!canGoBackOrForward(steps)) {
1428 cancelRedirection();
1432 // If the steps to navigate is not zero (which needs to force a reload), and if we think the navigation is going to be a fragment load
1433 // (when the URL we're going to navigate to is the same as the current one, except for the fragment part - but not exactly the same because that's a reload),
1434 // then we don't need to schedule the navigation.
1436 KURL destination = historyURL(steps);
1437 // FIXME: This doesn't seem like a reliable way to tell whether or not the load will be a fragment load.
1438 if (equalIgnoringRef(m_URL, destination) && m_URL != destination) {
1439 goBackOrForward(steps);
1444 scheduleRedirection(new ScheduledRedirection(steps));
1447 void FrameLoader::goBackOrForward(int distance)
1452 Page* page = m_frame->page();
1455 BackForwardList* list = page->backForwardList();
1459 HistoryItem* item = list->itemAtIndex(distance);
1462 int forwardListCount = list->forwardListCount();
1463 if (forwardListCount > 0)
1464 item = list->itemAtIndex(forwardListCount);
1466 int backListCount = list->backListCount();
1467 if (backListCount > 0)
1468 item = list->itemAtIndex(-backListCount);
1472 ASSERT(item); // we should not reach this line with an empty back/forward list
1474 page->goToItem(item, FrameLoadTypeIndexedBackForward);
1477 void FrameLoader::redirectionTimerFired(Timer<FrameLoader>*)
1479 ASSERT(m_frame->page());
1481 OwnPtr<ScheduledRedirection> redirection(m_scheduledRedirection.release());
1483 switch (redirection->type) {
1484 case ScheduledRedirection::redirection:
1485 case ScheduledRedirection::locationChange:
1486 case ScheduledRedirection::locationChangeDuringLoad:
1487 changeLocation(redirection->url, redirection->referrer,
1488 redirection->lockHistory, redirection->lockBackForwardList, redirection->wasUserGesture, redirection->wasRefresh);
1490 case ScheduledRedirection::historyNavigation:
1491 if (redirection->historySteps == 0) {
1492 // Special case for go(0) from a frame -> reload only the frame
1493 urlSelected(m_URL, "", 0, redirection->lockHistory, redirection->lockBackForwardList, redirection->wasUserGesture);
1496 // go(i!=0) from a frame navigates into the history of the frame only,
1497 // in both IE and NS (but not in Mozilla). We can't easily do that.
1498 goBackOrForward(redirection->historySteps);
1502 ASSERT_NOT_REACHED();
1506 In the case of saving state about a page with frames, we store a tree of items that mirrors the frame tree.
1507 The item that was the target of the user's navigation is designated as the "targetItem".
1508 When this method is called with doClip=YES we're able to create the whole tree except for the target's children,
1509 which will be loaded in the future. That part of the tree will be filled out as the child loads are committed.
1511 void FrameLoader::loadURLIntoChildFrame(const KURL& url, const String& referer, Frame* childFrame)
1514 HistoryItem* parentItem = currentHistoryItem();
1515 FrameLoadType loadType = this->loadType();
1516 FrameLoadType childLoadType = FrameLoadTypeRedirectWithLockedBackForwardList;
1518 KURL workingURL = url;
1520 // If we're moving in the backforward list, we might want to replace the content
1521 // of this child frame with whatever was there at that point.
1522 if (parentItem && parentItem->children().size() && isBackForwardLoadType(loadType)) {
1523 HistoryItem* childItem = parentItem->childItemWithName(childFrame->tree()->name());
1525 // Use the original URL to ensure we get all the side-effects, such as
1526 // onLoad handlers, of any redirects that happened. An example of where
1527 // this is needed is Radar 3213556.
1528 workingURL = KURL(childItem->originalURLString());
1529 childLoadType = loadType;
1530 childFrame->loader()->setProvisionalHistoryItem(childItem);
1534 RefPtr<Archive> subframeArchive = activeDocumentLoader()->popArchiveForSubframe(childFrame->tree()->name());
1536 if (subframeArchive)
1537 childFrame->loader()->loadArchive(subframeArchive.release());
1539 childFrame->loader()->loadURL(workingURL, referer, String(), false, childLoadType, 0, 0);
1542 void FrameLoader::loadArchive(PassRefPtr<Archive> prpArchive)
1544 RefPtr<Archive> archive = prpArchive;
1546 ArchiveResource* mainResource = archive->mainResource();
1547 ASSERT(mainResource);
1551 SubstituteData substituteData(mainResource->data(), mainResource->mimeType(), mainResource->textEncoding(), KURL());
1553 ResourceRequest request(mainResource->url());
1555 request.applyWebArchiveHackForMail();
1558 RefPtr<DocumentLoader> documentLoader = m_client->createDocumentLoader(request, substituteData);
1559 documentLoader->addAllArchiveResources(archive.get());
1560 load(documentLoader.get());
1563 String FrameLoader::encoding() const
1565 if (m_encodingWasChosenByUser && !m_encoding.isEmpty())
1567 if (m_decoder && m_decoder->encoding().isValid())
1568 return m_decoder->encoding().name();
1569 Settings* settings = m_frame->settings();
1570 return settings ? settings->defaultTextEncodingName() : String();
1573 bool FrameLoader::gotoAnchor(const String& name)
1575 ASSERT(m_frame->document());
1577 if (!m_frame->document()->haveStylesheetsLoaded()) {
1578 m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(true);
1582 m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(false);
1584 Element* anchorNode = m_frame->document()->findAnchor(name);
1587 if (m_frame->document()->isSVGDocument()) {
1588 if (name.startsWith("xpointer(")) {
1589 // We need to parse the xpointer reference here
1590 } else if (name.startsWith("svgView(")) {
1591 RefPtr<SVGSVGElement> svg = static_cast<SVGDocument*>(m_frame->document())->rootElement();
1592 if (!svg->currentView()->parseViewSpec(name))
1594 svg->setUseCurrentView(true);
1596 if (anchorNode && anchorNode->hasTagName(SVGNames::viewTag)) {
1597 RefPtr<SVGViewElement> viewElement = anchorNode->hasTagName(SVGNames::viewTag) ? static_cast<SVGViewElement*>(anchorNode) : 0;
1598 if (viewElement.get()) {
1599 RefPtr<SVGSVGElement> svg = static_cast<SVGSVGElement*>(SVGLocatable::nearestViewportElement(viewElement.get()));
1600 svg->inheritViewAttributes(viewElement.get());
1604 // FIXME: need to decide which <svg> to focus on, and zoom to that one
1605 // FIXME: need to actually "highlight" the viewTarget(s)
1609 m_frame->document()->setCSSTarget(anchorNode); // Setting to null will clear the current target.
1611 // Implement the rule that "" and "top" both mean top of page as in other browsers.
1612 if (!anchorNode && !(name.isEmpty() || equalIgnoringCase(name, "top")))
1615 // We need to update the layout before scrolling, otherwise we could
1616 // really mess things up if an anchor scroll comes at a bad moment.
1617 m_frame->document()->updateRendering();
1618 // Only do a layout if changes have occurred that make it necessary.
1619 if (m_frame->view() && m_frame->contentRenderer() && m_frame->contentRenderer()->needsLayout())
1620 m_frame->view()->layout();
1622 // Scroll nested layers and frames to reveal the anchor.
1623 // Align to the top and to the closest side (this matches other browsers).
1624 RenderObject* renderer;
1627 renderer = m_frame->document()->renderer(); // top of document
1629 renderer = anchorNode->renderer();
1630 rect = anchorNode->getRect();
1633 renderer->enclosingLayer()->scrollRectToVisible(rect, true, RenderLayer::gAlignToEdgeIfNeeded, RenderLayer::gAlignTopAlways);
1638 bool FrameLoader::requestObject(RenderPart* renderer, const String& url, const AtomicString& frameName,
1639 const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues)
1641 if (url.isEmpty() && mimeType.isEmpty())
1644 #if USE(LOW_BANDWIDTH_DISPLAY)
1645 // don't care object during low bandwidth display
1646 if (frame()->document()->inLowBandwidthDisplay()) {
1647 m_needToSwitchOutLowBandwidthDisplay = true;
1654 completedURL = completeURL(url);
1657 if (shouldUsePlugin(completedURL, mimeType, renderer->hasFallbackContent(), useFallback)) {
1658 Settings* settings = m_frame->settings();
1659 if (!settings || !settings->arePluginsEnabled() ||
1660 (!settings->isJavaEnabled() && MIMETypeRegistry::isJavaAppletMIMEType(mimeType)))
1662 return loadPlugin(renderer, completedURL, mimeType, paramNames, paramValues, useFallback);
1665 ASSERT(renderer->node()->hasTagName(objectTag) || renderer->node()->hasTagName(embedTag));
1666 HTMLPlugInElement* element = static_cast<HTMLPlugInElement*>(renderer->node());
1668 // FIXME: OK to always make a new frame? When does the old frame get removed?
1669 return loadSubframe(element, completedURL, frameName, m_outgoingReferrer);
1672 bool FrameLoader::shouldUsePlugin(const KURL& url, const String& mimeType, bool hasFallback, bool& useFallback)
1674 if (m_client->shouldUsePluginDocument(mimeType)) {
1675 useFallback = false;
1679 // Allow other plug-ins to win over QuickTime because if the user has installed a plug-in that
1680 // can handle TIFF (which QuickTime can also handle) they probably intended to override QT.
1681 if (m_frame->page() && (mimeType == "image/tiff" || mimeType == "image/tif" || mimeType == "image/x-tiff")) {
1682 const PluginData* pluginData = m_frame->page()->pluginData();
1683 String pluginName = pluginData ? pluginData->pluginNameForMimeType(mimeType) : String();
1684 if (!pluginName.isEmpty() && !pluginName.contains("QuickTime", false))
1688 ObjectContentType objectType = m_client->objectContentType(url, mimeType);
1689 // If an object's content can't be handled and it has no fallback, let
1690 // it be handled as a plugin to show the broken plugin icon.
1691 useFallback = objectType == ObjectContentNone && hasFallback;
1692 return objectType == ObjectContentNone || objectType == ObjectContentNetscapePlugin || objectType == ObjectContentOtherPlugin;
1695 static HTMLPlugInElement* toPlugInElement(Node* node)
1700 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
1701 ASSERT(node->hasTagName(objectTag) || node->hasTagName(embedTag)
1702 || node->hasTagName(videoTag) || node->hasTagName(audioTag)
1703 || node->hasTagName(appletTag));
1705 ASSERT(node->hasTagName(objectTag) || node->hasTagName(embedTag)
1706 || node->hasTagName(appletTag));
1709 return static_cast<HTMLPlugInElement*>(node);
1712 bool FrameLoader::loadPlugin(RenderPart* renderer, const KURL& url, const String& mimeType,
1713 const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback)
1717 if (renderer && !useFallback) {
1718 HTMLPlugInElement* element = toPlugInElement(renderer->node());
1720 if (!canLoad(url, String(), frame()->document())) {
1721 FrameLoader::reportLocalLoadFailed(m_frame, url.string());
1725 widget = m_client->createPlugin(IntSize(renderer->contentWidth(), renderer->contentHeight()),
1726 element, url, paramNames, paramValues, mimeType,
1727 m_frame->document()->isPluginDocument());
1729 renderer->setWidget(widget);
1730 m_containsPlugIns = true;
1737 void FrameLoader::clearRecordedFormValues()
1739 m_formAboutToBeSubmitted = 0;
1740 m_formValuesAboutToBeSubmitted.clear();
1743 void FrameLoader::setFormAboutToBeSubmitted(PassRefPtr<HTMLFormElement> element)
1745 m_formAboutToBeSubmitted = element;
1748 void FrameLoader::recordFormValue(const String& name, const String& value)
1750 m_formValuesAboutToBeSubmitted.set(name, value);
1753 void FrameLoader::parentCompleted()
1755 if (m_scheduledRedirection && !m_redirectionTimer.isActive())
1756 startRedirectionTimer();
1759 String FrameLoader::outgoingReferrer() const
1761 return m_outgoingReferrer;
1764 String FrameLoader::outgoingOrigin() const
1766 return m_frame->document()->securityOrigin()->toString();
1769 Frame* FrameLoader::opener()
1774 void FrameLoader::setOpener(Frame* opener)
1777 m_opener->loader()->m_openedFrames.remove(m_frame);
1779 opener->loader()->m_openedFrames.add(m_frame);
1782 if (m_frame->document()) {
1783 m_frame->document()->initSecurityContext();
1784 m_frame->domWindow()->setSecurityOrigin(m_frame->document()->securityOrigin());
1788 bool FrameLoader::openedByDOM() const
1790 return m_openedByDOM;
1793 void FrameLoader::setOpenedByDOM()
1795 m_openedByDOM = true;
1798 void FrameLoader::handleFallbackContent()
1800 HTMLFrameOwnerElement* owner = m_frame->ownerElement();
1801 if (!owner || !owner->hasTagName(objectTag))
1803 static_cast<HTMLObjectElement*>(owner)->renderFallbackContent();
1806 void FrameLoader::provisionalLoadStarted()
1808 Page* page = m_frame->page();
1810 // this is used to update the current history item
1811 // in the event of a navigation aytime during loading
1812 m_navigationDuringLoad = false;
1814 Document *document = page->mainFrame()->document();
1815 m_navigationDuringLoad = !page->mainFrame()->loader()->isComplete() || (document && document->processingLoadEvent());
1818 m_firstLayoutDone = false;
1819 cancelRedirection(true);
1820 m_client->provisionalLoadStarted();
1823 bool FrameLoader::userGestureHint()
1825 Frame* frame = m_frame->tree()->top();
1826 if (!frame->script()->isEnabled())
1827 return true; // If JavaScript is disabled, a user gesture must have initiated the navigation.
1828 return frame->script()->processingUserGesture(); // FIXME: Use pageIsProcessingUserGesture.
1831 void FrameLoader::didNotOpenURL(const KURL& url)
1833 if (m_submittedFormURL == url)
1834 m_submittedFormURL = KURL();
1837 void FrameLoader::resetMultipleFormSubmissionProtection()
1839 m_submittedFormURL = KURL();
1842 void FrameLoader::setEncoding(const String& name, bool userChosen)
1844 if (!m_workingURL.isEmpty())
1845 receivedFirstData();
1847 m_encodingWasChosenByUser = userChosen;
1850 void FrameLoader::addData(const char* bytes, int length)
1852 ASSERT(m_workingURL.isEmpty());
1853 ASSERT(m_frame->document());
1854 ASSERT(m_frame->document()->parsing());
1855 write(bytes, length);
1858 bool FrameLoader::canCachePageContainingThisFrame()
1860 return m_documentLoader
1861 && m_documentLoader->mainDocumentError().isNull()
1862 && !m_frame->tree()->childCount()
1863 // FIXME: If we ever change this so that frames with plug-ins will be cached,
1864 // we need to make sure that we don't cache frames that have outstanding NPObjects
1865 // (objects created by the plug-in). Since there is no way to pause/resume a Netscape plug-in,
1866 // they would need to be destroyed and then recreated, and there is no way that we can recreate
1867 // the right NPObjects. See <rdar://problem/5197041> for more information.
1868 && !m_containsPlugIns
1869 && !m_URL.protocolIs("https")
1870 && !m_frame->document()->hasWindowEventListener(eventNames().unloadEvent)
1871 #if ENABLE(DATABASE)
1872 && !m_frame->document()->hasOpenDatabases()
1874 && !m_frame->document()->usingGeolocation()
1875 && m_currentHistoryItem
1876 && !isQuickRedirectComing()
1877 && !m_documentLoader->isLoadingInAPISense()
1878 && !m_documentLoader->isStopping()
1879 && m_frame->document()->canSuspendActiveDOMObjects()
1880 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
1881 // FIXME: We should investigating caching frames that have an associated
1882 // application cache. <rdar://problem/5917899> tracks that work.
1883 && !m_documentLoader->applicationCache()
1884 && !m_documentLoader->candidateApplicationCacheGroup()
1886 && m_client->canCachePage()
1890 bool FrameLoader::canCachePage()
1893 logCanCachePageDecision();
1896 // Cache the page, if possible.
1897 // Don't write to the cache if in the middle of a redirect, since we will want to
1898 // store the final page we end up on.
1899 // No point writing to the cache on a reload or loadSame, since we will just write
1900 // over it again when we leave that page.
1901 // FIXME: <rdar://problem/4886592> - We should work out the complexities of caching pages with frames as they
1902 // are the most interesting pages on the web, and often those that would benefit the most from caching!
1903 FrameLoadType loadType = this->loadType();
1905 return !m_frame->tree()->parent()
1906 && canCachePageContainingThisFrame()
1908 && m_frame->page()->backForwardList()->enabled()
1909 && m_frame->page()->backForwardList()->capacity() > 0
1910 && m_frame->page()->settings()->usesPageCache()
1911 && loadType != FrameLoadTypeReload
1912 && loadType != FrameLoadTypeReloadFromOrigin
1913 && loadType != FrameLoadTypeSame
1918 static String& pageCacheLogPrefix(int indentLevel)
1920 static int previousIndent = -1;
1921 DEFINE_STATIC_LOCAL(String, prefix, ());
1923 if (indentLevel != previousIndent) {
1924 previousIndent = indentLevel;
1926 for (int i = 0; i < previousIndent; ++i)
1933 static void pageCacheLog(const String& prefix, const String& message)
1935 LOG(PageCache, "%s%s", prefix.utf8().data(), message.utf8().data());
1938 #define PCLOG(...) pageCacheLog(pageCacheLogPrefix(indentLevel), String::format(__VA_ARGS__))
1940 void FrameLoader::logCanCachePageDecision()
1942 // Only bother logging for main frames that have actually loaded and have content.
1943 if (m_creatingInitialEmptyDocument)
1945 KURL currentURL = m_documentLoader ? m_documentLoader->url() : KURL();
1946 if (currentURL.isEmpty())
1949 int indentLevel = 0;
1950 PCLOG("--------\n Determining if page can be cached:");
1952 bool cannotCache = !logCanCacheFrameDecision(1);
1954 FrameLoadType loadType = this->loadType();
1956 if (m_frame->tree()->parent())
1957 { PCLOG(" -Frame has a parent frame"); cannotCache = true; }
1958 if (!m_frame->page()) {
1959 PCLOG(" -There is no Page object");
1963 if (!m_frame->page()->backForwardList()->enabled())
1964 { PCLOG(" -The back/forward list is disabled"); cannotCache = true; }
1965 if (!(m_frame->page()->backForwardList()->capacity() > 0))
1966 { PCLOG(" -The back/forward list has a 0 capacity"); cannotCache = true; }
1967 if (!m_frame->page()->settings()->usesPageCache())
1968 { PCLOG(" -Page settings says b/f cache disabled"); cannotCache = true; }
1969 if (loadType == FrameLoadTypeReload)
1970 { PCLOG(" -Load type is: Reload"); cannotCache = true; }
1971 if (loadType == FrameLoadTypeReloadFromOrigin)
1972 { PCLOG(" -Load type is: Reload from origin"); cannotCache = true; }
1973 if (loadType == FrameLoadTypeSame)
1974 { PCLOG(" -Load type is: Same"); cannotCache = true; }
1977 PCLOG(cannotCache ? " Page CANNOT be cached\n--------" : " Page CAN be cached\n--------");
1980 bool FrameLoader::logCanCacheFrameDecision(int indentLevel)
1982 // Only bother logging for frames that have actually loaded and have content.
1983 if (m_creatingInitialEmptyDocument)
1985 KURL currentURL = m_documentLoader ? m_documentLoader->url() : KURL();
1986 if (currentURL.isEmpty())
1990 KURL newURL = m_provisionalDocumentLoader ? m_provisionalDocumentLoader->url() : KURL();
1991 if (!newURL.isEmpty())
1992 PCLOG(" Determining if frame can be cached navigating from (%s) to (%s):", currentURL.string().utf8().data(), newURL.string().utf8().data());
1994 PCLOG(" Determining if subframe with URL (%s) can be cached:", currentURL.string().utf8().data());
1996 bool cannotCache = false;
1999 if (!m_documentLoader) {
2000 PCLOG(" -There is no DocumentLoader object");
2004 if (!m_documentLoader->mainDocumentError().isNull())
2005 { PCLOG(" -Main document has an error"); cannotCache = true; }
2006 if (m_frame->tree()->childCount())
2007 { PCLOG(" -Frame has child frames"); cannotCache = true; }
2008 if (m_containsPlugIns)
2009 { PCLOG(" -Frame contains plugins"); cannotCache = true; }
2010 if (m_URL.protocolIs("https"))
2011 { PCLOG(" -Frame is HTTPS"); cannotCache = true; }
2012 if (m_frame->document()->hasWindowEventListener(eventNames().unloadEvent))
2013 { PCLOG(" -Frame has an unload event listener"); cannotCache = true; }
2014 #if ENABLE(DATABASE)
2015 if (m_frame->document()->hasOpenDatabases())
2016 { PCLOG(" -Frame has open database handles"); cannotCache = true; }
2018 if (m_frame->document()->usingGeolocation())
2019 { PCLOG(" -Frame uses Geolocation"); cannotCache = true; }
2020 if (!m_currentHistoryItem)
2021 { PCLOG(" -No current history item"); cannotCache = true; }
2022 if (isQuickRedirectComing())
2023 { PCLOG(" -Quick redirect is coming"); cannotCache = true; }
2024 if (m_documentLoader->isLoadingInAPISense())
2025 { PCLOG(" -DocumentLoader is still loading in API sense"); cannotCache = true; }
2026 if (m_documentLoader->isStopping())
2027 { PCLOG(" -DocumentLoader is in the middle of stopping"); cannotCache = true; }
2028 if (!m_frame->document()->canSuspendActiveDOMObjects())
2029 { PCLOG(" -The document cannot suspect its active DOM Objects"); cannotCache = true; }
2030 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
2031 if (m_documentLoader->applicationCache())
2032 { PCLOG(" -The DocumentLoader has an active application cache"); cannotCache = true; }
2033 if (m_documentLoader->candidateApplicationCacheGroup())
2034 { PCLOG(" -The DocumentLoader has a candidateApplicationCacheGroup"); cannotCache = true; }
2036 if (!m_client->canCachePage())
2037 { PCLOG(" -The client says this frame cannot be cached"); cannotCache = true; }
2040 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2041 if (!child->loader()->logCanCacheFrameDecision(indentLevel + 1))
2044 PCLOG(cannotCache ? " Frame CANNOT be cached" : " Frame CAN be cached");
2047 return !cannotCache;
2051 void FrameLoader::updatePolicyBaseURL()
2053 if (m_frame->tree()->parent())
2054 setPolicyBaseURL(m_frame->tree()->parent()->document()->policyBaseURL());
2056 setPolicyBaseURL(m_URL);
2059 void FrameLoader::setPolicyBaseURL(const KURL& url)
2061 m_frame->document()->setPolicyBaseURL(url);
2062 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2063 child->loader()->setPolicyBaseURL(url);
2066 // This does the same kind of work that didOpenURL does, except it relies on the fact
2067 // that a higher level already checked that the URLs match and the scrolling is the right thing to do.
2068 void FrameLoader::scrollToAnchor(const KURL& url)
2071 updateHistoryForAnchorScroll();
2073 // If we were in the autoscroll/panScroll mode we want to stop it before following the link to the anchor
2074 m_frame->eventHandler()->stopAutoscrollTimer();
2078 // It's important to model this as a load that starts and immediately finishes.
2079 // Otherwise, the parent frame may think we never finished loading.
2080 m_isComplete = false;
2084 bool FrameLoader::isComplete() const
2086 return m_isComplete;
2089 void FrameLoader::scheduleRedirection(ScheduledRedirection* redirection)
2091 ASSERT(m_frame->page());
2093 stopRedirectionTimer();
2094 m_scheduledRedirection.set(redirection);
2095 if (!m_isComplete && redirection->type != ScheduledRedirection::redirection)
2097 if (m_isComplete || redirection->type != ScheduledRedirection::redirection)
2098 startRedirectionTimer();
2101 void FrameLoader::startRedirectionTimer()
2103 ASSERT(m_frame->page());
2104 ASSERT(m_scheduledRedirection);
2106 m_redirectionTimer.stop();
2107 m_redirectionTimer.startOneShot(m_scheduledRedirection->delay);
2109 switch (m_scheduledRedirection->type) {
2110 case ScheduledRedirection::redirection:
2111 case ScheduledRedirection::locationChange:
2112 case ScheduledRedirection::locationChangeDuringLoad:
2113 clientRedirected(KURL(m_scheduledRedirection->url),
2114 m_scheduledRedirection->delay,
2115 currentTime() + m_redirectionTimer.nextFireInterval(),
2116 m_scheduledRedirection->lockBackForwardList,
2117 m_isExecutingJavaScriptFormAction);
2119 case ScheduledRedirection::historyNavigation:
2120 // Don't report history navigations.
2123 ASSERT_NOT_REACHED();
2126 void FrameLoader::stopRedirectionTimer()
2128 if (!m_redirectionTimer.isActive())
2131 m_redirectionTimer.stop();
2133 if (m_scheduledRedirection) {
2134 switch (m_scheduledRedirection->type) {
2135 case ScheduledRedirection::redirection:
2136 case ScheduledRedirection::locationChange:
2137 case ScheduledRedirection::locationChangeDuringLoad:
2138 clientRedirectCancelledOrFinished(m_cancellingWithLoadInProgress);
2140 case ScheduledRedirection::historyNavigation:
2141 // Don't report history navigations.
2144 ASSERT_NOT_REACHED();
2148 void FrameLoader::completed()
2150 RefPtr<Frame> protect(m_frame);
2151 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2152 child->loader()->parentCompleted();
2153 if (Frame* parent = m_frame->tree()->parent())
2154 parent->loader()->checkCompleted();
2158 void FrameLoader::started()
2160 for (Frame* frame = m_frame; frame; frame = frame->tree()->parent())
2161 frame->loader()->m_isComplete = false;
2164 bool FrameLoader::containsPlugins() const
2166 return m_containsPlugIns;
2169 void FrameLoader::prepareForLoadStart()
2171 if (Page* page = m_frame->page())
2172 page->progress()->progressStarted(m_frame);
2173 m_client->dispatchDidStartProvisionalLoad();
2176 void FrameLoader::setupForReplace()
2178 setState(FrameStateProvisional);
2179 m_provisionalDocumentLoader = m_documentLoader;
2180 m_documentLoader = 0;
2184 void FrameLoader::setupForReplaceByMIMEType(const String& newMIMEType)
2186 activeDocumentLoader()->setupForReplaceByMIMEType(newMIMEType);
2189 void FrameLoader::loadFrameRequestWithFormAndValues(const FrameLoadRequest& request, bool lockHistory, bool lockBackForwardList, Event* event,
2190 HTMLFormElement* submitForm, const HashMap<String, String>& formValues)
2192 RefPtr<FormState> formState;
2194 formState = FormState::create(submitForm, formValues, m_frame);
2196 KURL url = request.resourceRequest().url();
2199 String argsReferrer = request.resourceRequest().httpReferrer();
2200 if (!argsReferrer.isEmpty())
2201 referrer = argsReferrer;
2203 referrer = m_outgoingReferrer;
2205 ASSERT(frame()->document());
2206 if (url.protocolIs("file")) {
2207 if (!canLoad(url, String(), frame()->document()) && !canLoad(url, referrer)) {
2208 FrameLoader::reportLocalLoadFailed(m_frame, url.string());
2213 if (shouldHideReferrer(url, referrer))
2214 referrer = String();
2216 FrameLoadType loadType;
2217 if (request.resourceRequest().cachePolicy() == ReloadIgnoringCacheData)
2218 loadType = FrameLoadTypeReload;
2219 else if (lockBackForwardList)
2220 loadType = FrameLoadTypeRedirectWithLockedBackForwardList;
2222 loadType = FrameLoadTypeStandard;
2224 if (request.resourceRequest().httpMethod() == "POST")
2225 loadPostRequest(request.resourceRequest(), referrer, request.frameName(), lockHistory, loadType, event, formState.release());
2227 loadURL(request.resourceRequest().url(), referrer, request.frameName(), lockHistory, loadType, event, formState.release());
2229 Frame* targetFrame = findFrameForNavigation(request.frameName());
2230 if (targetFrame && targetFrame != m_frame)
2231 if (Page* page = targetFrame->page())
2232 page->chrome()->focus();
2235 void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType newLoadType,
2236 Event* event, PassRefPtr<FormState> prpFormState)
2238 RefPtr<FormState> formState = prpFormState;
2239 bool isFormSubmission = formState;
2241 ResourceRequest request(newURL);
2242 if (!referrer.isEmpty()) {
2243 request.setHTTPReferrer(referrer);
2244 RefPtr<SecurityOrigin> referrerOrigin = SecurityOrigin::createFromString(referrer);
2245 addHTTPOriginIfNeeded(request, referrerOrigin->toString());
2247 addExtraFieldsToRequest(request, newLoadType, true, event || isFormSubmission);
2248 if (newLoadType == FrameLoadTypeReload || newLoadType == FrameLoadTypeReloadFromOrigin)
2249 request.setCachePolicy(ReloadIgnoringCacheData);
2251 ASSERT(newLoadType != FrameLoadTypeSame);
2253 NavigationAction action(newURL, newLoadType, isFormSubmission, event);
2255 if (!frameName.isEmpty()) {
2256 if (Frame* targetFrame = findFrameForNavigation(frameName))
2257 targetFrame->loader()->loadURL(newURL, referrer, String(), lockHistory, newLoadType, event, formState);
2259 checkNewWindowPolicy(action, request, formState, frameName);
2263 RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader;
2265 bool sameURL = shouldTreatURLAsSameAsCurrent(newURL);
2267 // Make sure to do scroll to anchor processing even if the URL is
2268 // exactly the same so pages with '#' links and DHTML side effects
2270 if (shouldScrollToAnchor(isFormSubmission, newLoadType, newURL)) {
2271 oldDocumentLoader->setTriggeringAction(action);
2273 checkNavigationPolicy(request, oldDocumentLoader.get(), formState,
2274 callContinueFragmentScrollAfterNavigationPolicy, this);
2276 // must grab this now, since this load may stop the previous load and clear this flag
2277 bool isRedirect = m_quickRedirectComing;
2278 loadWithNavigationAction(request, action, lockHistory, newLoadType, formState);
2280 m_quickRedirectComing = false;
2281 if (m_provisionalDocumentLoader)
2282 m_provisionalDocumentLoader->setIsClientRedirect(true);
2284 // Example of this case are sites that reload the same URL with a different cookie
2285 // driving the generated content, or a master frame with links that drive a target
2286 // frame, where the user has clicked on the same link repeatedly.
2287 m_loadType = FrameLoadTypeSame;
2291 void FrameLoader::load(const ResourceRequest& request, bool lockHistory)
2293 load(request, SubstituteData(), lockHistory);
2296 void FrameLoader::load(const ResourceRequest& request, const SubstituteData& substituteData, bool lockHistory)
2298 if (m_inStopAllLoaders)
2301 // FIXME: is this the right place to reset loadType? Perhaps this should be done after loading is finished or aborted.
2302 m_loadType = FrameLoadTypeStandard;
2303 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, substituteData);
2304 if (lockHistory && m_documentLoader)
2305 loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory() : m_documentLoader->clientRedirectSourceForHistory());
2309 void FrameLoader::load(const ResourceRequest& request, const String& frameName, bool lockHistory)
2311 if (frameName.isEmpty()) {
2312 load(request, lockHistory);
2316 Frame* frame = findFrameForNavigation(frameName);
2318 frame->loader()->load(request, lockHistory);
2322 checkNewWindowPolicy(NavigationAction(request.url(), NavigationTypeOther), request, 0, frameName);
2325 void FrameLoader::loadWithNavigationAction(const ResourceRequest& request, const NavigationAction& action, bool lockHistory, FrameLoadType type, PassRefPtr<FormState> formState)
2327 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, SubstituteData());
2328 if (lockHistory && m_documentLoader)
2329 loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory() : m_documentLoader->clientRedirectSourceForHistory());
2331 loader->setTriggeringAction(action);
2332 if (m_documentLoader)
2333 loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
2335 loadWithDocumentLoader(loader.get(), type, formState);
2338 void FrameLoader::load(DocumentLoader* newDocumentLoader)
2340 ResourceRequest& r = newDocumentLoader->request();
2341 addExtraFieldsToMainResourceRequest(r);
2344 if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->originalRequest().url())) {
2345 r.setCachePolicy(ReloadIgnoringCacheData);
2346 type = FrameLoadTypeSame;
2348 type = FrameLoadTypeStandard;
2350 if (m_documentLoader)
2351 newDocumentLoader->setOverrideEncoding(m_documentLoader->overrideEncoding());
2353 // When we loading alternate content for an unreachable URL that we're
2354 // visiting in the history list, we treat it as a reload so the history list
2355 // is appropriately maintained.
2357 // FIXME: This seems like a dangerous overloading of the meaning of "FrameLoadTypeReload" ...
2358 // shouldn't a more explicit type of reload be defined, that means roughly
2359 // "load without affecting history" ?
2360 if (shouldReloadToHandleUnreachableURL(newDocumentLoader)) {
2361 ASSERT(type == FrameLoadTypeStandard);
2362 type = FrameLoadTypeReload;
2365 loadWithDocumentLoader(newDocumentLoader, type, 0);
2368 void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType type, PassRefPtr<FormState> prpFormState)
2370 ASSERT(m_client->hasWebView());
2372 // Unfortunately the view must be non-nil, this is ultimately due
2373 // to parser requiring a FrameView. We should fix this dependency.
2375 ASSERT(m_frame->view());
2377 m_policyLoadType = type;
2378 RefPtr<FormState> formState = prpFormState;
2379 bool isFormSubmission = formState;
2381 const KURL& newURL = loader->request().url();
2383 if (shouldScrollToAnchor(isFormSubmission, m_policyLoadType, newURL)) {
2384 RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader;
2385 NavigationAction action(newURL, m_policyLoadType, isFormSubmission);
2387 oldDocumentLoader->setTriggeringAction(action);
2389 checkNavigationPolicy(loader->request(), oldDocumentLoader.get(), formState,
2390 callContinueFragmentScrollAfterNavigationPolicy, this);
2392 if (Frame* parent = m_frame->tree()->parent())
2393 loader->setOverrideEncoding(parent->loader()->documentLoader()->overrideEncoding());
2396 setPolicyDocumentLoader(loader);
2398 checkNavigationPolicy(loader->request(), loader, formState,
2399 callContinueLoadAfterNavigationPolicy, this);
2403 bool FrameLoader::canLoad(const KURL& url, const String& referrer, const Document* doc)
2405 // We can always load any URL that isn't considered local (e.g. http URLs)
2406 if (!shouldTreatURLAsLocal(url.string()))
2409 // If we were provided a document, we let its local file policy dictate the result,
2410 // otherwise we allow local loads only if the supplied referrer is also local.
2412 return doc->securityOrigin()->canLoadLocalResources();
2413 else if (!referrer.isEmpty())
2414 return shouldTreatURLAsLocal(referrer);
2419 void FrameLoader::reportLocalLoadFailed(Frame* frame, const String& url)
2421 ASSERT(!url.isEmpty());
2425 frame->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, "Not allowed to load local resource: " + url, 0, String());
2428 bool FrameLoader::shouldHideReferrer(const KURL& url, const String& referrer)
2430 bool referrerIsSecureURL = protocolIs(referrer, "https");
2431 bool referrerIsWebURL = referrerIsSecureURL || protocolIs(referrer, "http");
2433 if (!referrerIsWebURL)
2436 if (!referrerIsSecureURL)
2439 bool URLIsSecureURL = url.protocolIs("https");
2441 return !URLIsSecureURL;
2444 const ResourceRequest& FrameLoader::initialRequest() const
2446 return activeDocumentLoader()->originalRequest();
2449 void FrameLoader::receivedData(const char* data, int length)
2451 activeDocumentLoader()->receivedData(data, length);
2454 void FrameLoader::handleUnimplementablePolicy(const ResourceError& error)
2456 m_delegateIsHandlingUnimplementablePolicy = true;
2457 m_client->dispatchUnableToImplementPolicy(error);
2458 m_delegateIsHandlingUnimplementablePolicy = false;
2461 void FrameLoader::cannotShowMIMEType(const ResourceResponse& response)
2463 handleUnimplementablePolicy(m_client->cannotShowMIMETypeError(response));
2466 ResourceError FrameLoader::interruptionForPolicyChangeError(const ResourceRequest& request)
2468 return m_client->interruptForPolicyChangeError(request);
2471 void FrameLoader::checkNavigationPolicy(const ResourceRequest& newRequest, NavigationPolicyDecisionFunction function, void* argument)
2473 checkNavigationPolicy(newRequest, activeDocumentLoader(), 0, function, argument);
2476 void FrameLoader::checkContentPolicy(const String& MIMEType, ContentPolicyDecisionFunction function, void* argument)
2478 ASSERT(activeDocumentLoader());
2480 // Always show content with valid substitute data.
2481 if (activeDocumentLoader()->substituteData().isValid()) {
2482 function(argument, PolicyUse);
2487 // Respect the hidden FTP Directory Listing pref so it can be tested even if the policy delegate might otherwise disallow it
2488 Settings* settings = m_frame->settings();
2489 if (settings && settings->forceFTPDirectoryListings() && MIMEType == "application/x-ftp-directory") {
2490 function(argument, PolicyUse);
2495 m_policyCheck.set(function, argument);
2496 m_client->dispatchDecidePolicyForMIMEType(&FrameLoader::continueAfterContentPolicy,
2497 MIMEType, activeDocumentLoader()->request());
2500 bool FrameLoader::shouldReloadToHandleUnreachableURL(DocumentLoader* docLoader)
2502 KURL unreachableURL = docLoader->unreachableURL();
2504 if (unreachableURL.isEmpty())
2507 if (!isBackForwardLoadType(m_policyLoadType))
2510 // We only treat unreachableURLs specially during the delegate callbacks
2511 // for provisional load errors and navigation policy decisions. The former
2512 // case handles well-formed URLs that can't be loaded, and the latter
2513 // case handles malformed URLs and unknown schemes. Loading alternate content
2514 // at other times behaves like a standard load.
2515 DocumentLoader* compareDocumentLoader = 0;
2516 if (m_delegateIsDecidingNavigationPolicy || m_delegateIsHandlingUnimplementablePolicy)
2517 compareDocumentLoader = m_policyDocumentLoader.get();
2518 else if (m_delegateIsHandlingProvisionalLoadError)
2519 compareDocumentLoader = m_provisionalDocumentLoader.get();
2521 return compareDocumentLoader && unreachableURL == compareDocumentLoader->request().url();
2524 void FrameLoader::reloadWithOverrideEncoding(const String& encoding)
2526 if (!m_documentLoader)
2529 ResourceRequest request = m_documentLoader->request();
2530 KURL unreachableURL = m_documentLoader->unreachableURL();
2531 if (!unreachableURL.isEmpty())
2532 request.setURL(unreachableURL);
2534 request.setCachePolicy(ReturnCacheDataElseLoad);
2536 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, SubstituteData());
2537 setPolicyDocumentLoader(loader.get());
2539 loader->setOverrideEncoding(encoding);
2541 loadWithDocumentLoader(loader.get(), FrameLoadTypeReload, 0);
2544 void FrameLoader::reload(bool endToEndReload)
2546 if (!m_documentLoader)
2549 // If a window is created by javascript, its main frame can have an empty but non-nil URL.
2550 // Reloading in this case will lose the current contents (see 4151001).
2551 if (m_documentLoader->request().url().isEmpty())
2554 ResourceRequest initialRequest = m_documentLoader->request();
2556 // Replace error-page URL with the URL we were trying to reach.
2557 KURL unreachableURL = m_documentLoader->unreachableURL();
2558 if (!unreachableURL.isEmpty())
2559 initialRequest.setURL(unreachableURL);
2561 // Create a new document loader for the reload, this will become m_documentLoader eventually,
2562 // but first it has to be the "policy" document loader, and then the "provisional" document loader.
2563 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(initialRequest, SubstituteData());
2565 ResourceRequest& request = loader->request();
2567 // FIXME: We don't have a mechanism to revalidate the main resource without reloading at the moment.
2568 request.setCachePolicy(ReloadIgnoringCacheData);
2570 // If we're about to re-post, set up action so the application can warn the user.
2571 if (request.httpMethod() == "POST")
2572 loader->setTriggeringAction(NavigationAction(request.url(), NavigationTypeFormResubmitted));
2574 loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
2576 loadWithDocumentLoader(loader.get(), endToEndReload ? FrameLoadTypeReloadFromOrigin : FrameLoadTypeReload, 0);
2579 static bool canAccessAncestor(const SecurityOrigin* activeSecurityOrigin, Frame* targetFrame)
2581 // targetFrame can be NULL when we're trying to navigate a top-level frame
2582 // that has a NULL opener.
2586 for (Frame* ancestorFrame = targetFrame; ancestorFrame; ancestorFrame = ancestorFrame->tree()->parent()) {
2587 Document* ancestorDocument = ancestorFrame->document();
2588 if (!ancestorDocument)
2591 const SecurityOrigin* ancestorSecurityOrigin = ancestorDocument->securityOrigin();
2592 if (activeSecurityOrigin->canAccess(ancestorSecurityOrigin))
2599 bool FrameLoader::shouldAllowNavigation(Frame* targetFrame) const
2601 // The navigation change is safe if the active frame is:
2602 // - in the same security origin as the target or one of the target's
2605 // Or the target frame is:
2606 // - a top-level frame in the frame hierarchy and the active frame can
2607 // navigate the target frame's opener per above.
2612 // Performance optimization.
2613 if (m_frame == targetFrame)
2616 // Let a frame navigate the top-level window that contains it. This is
2617 // important to allow because it lets a site "frame-bust" (escape from a
2618 // frame created by another web site).
2619 if (targetFrame == m_frame->tree()->top())
2622 Document* activeDocument = m_frame->document();
2623 ASSERT(activeDocument);
2624 const SecurityOrigin* activeSecurityOrigin = activeDocument->securityOrigin();
2626 // For top-level windows, check the opener.
2627 if (!targetFrame->tree()->parent() && canAccessAncestor(activeSecurityOrigin, targetFrame->loader()->opener()))
2630 // In general, check the frame's ancestors.
2631 if (canAccessAncestor(activeSecurityOrigin, targetFrame))
2634 Settings* settings = targetFrame->settings();
2635 if (settings && !settings->privateBrowsingEnabled()) {
2636 Document* targetDocument = targetFrame->document();
2637 // FIXME: this error message should contain more specifics of why the navigation change is not allowed.
2638 String message = String::format("Unsafe JavaScript attempt to initiate a navigation change for frame with URL %s from frame with URL %s.\n",
2639 targetDocument->url().string().utf8().data(), activeDocument->url().string().utf8().data());
2641 // FIXME: should we print to the console of the activeFrame as well?
2642 targetFrame->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, message, 1, String());
2648 void FrameLoader::stopLoadingSubframes()
2650 for (RefPtr<Frame> child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2651 child->loader()->stopAllLoaders();
2654 void FrameLoader::stopAllLoaders()
2656 // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
2657 if (m_inStopAllLoaders)
2660 m_inStopAllLoaders = true;
2664 stopLoadingSubframes();
2665 if (m_provisionalDocumentLoader)
2666 m_provisionalDocumentLoader->stopLoading();
2667 if (m_documentLoader)
2668 m_documentLoader->stopLoading();
2670 setProvisionalDocumentLoader(0);
2672 if (m_documentLoader)
2673 m_documentLoader->clearArchiveResources();
2675 m_inStopAllLoaders = false;
2678 void FrameLoader::stopForUserCancel(bool deferCheckLoadComplete)
2682 if (deferCheckLoadComplete)
2683 scheduleCheckLoadComplete();
2684 else if (m_frame->page())
2685 checkLoadComplete();
2688 DocumentLoader* FrameLoader::activeDocumentLoader() const
2690 if (m_state == FrameStateProvisional)
2691 return m_provisionalDocumentLoader.get();
2692 return m_documentLoader.get();
2695 bool FrameLoader::isLoading() const
2697 DocumentLoader* docLoader = activeDocumentLoader();
2700 return docLoader->isLoadingMainResource() || docLoader->isLoadingSubresources() || docLoader->isLoadingPlugIns();
2703 bool FrameLoader::frameHasLoaded() const
2705 return m_committedFirstRealDocumentLoad || (m_provisionalDocumentLoader && !m_creatingInitialEmptyDocument);
2708 void FrameLoader::setDocumentLoader(DocumentLoader* loader)
2710 if (!loader && !m_documentLoader)
2713 ASSERT(loader != m_documentLoader);
2714 ASSERT(!loader || loader->frameLoader() == this);
2716 m_client->prepareForDataSourceReplacement();
2718 if (m_documentLoader)
2719 m_documentLoader->detachFromFrame();
2721 m_documentLoader = loader;
2724 void FrameLoader::setPolicyDocumentLoader(DocumentLoader* loader)
2726 if (m_policyDocumentLoader == loader)
2731 loader->setFrame(m_frame);
2732 if (m_policyDocumentLoader
2733 && m_policyDocumentLoader != m_provisionalDocumentLoader
2734 && m_policyDocumentLoader != m_documentLoader)
2735 m_policyDocumentLoader->detachFromFrame();
2737 m_policyDocumentLoader = loader;
2740 void FrameLoader::setProvisionalDocumentLoader(DocumentLoader* loader)
2742 ASSERT(!loader || !m_provisionalDocumentLoader);
2743 ASSERT(!loader || loader->frameLoader() == this);
2745 if (m_provisionalDocumentLoader && m_provisionalDocumentLoader != m_documentLoader)
2746 m_provisionalDocumentLoader->detachFromFrame();
2748 m_provisionalDocumentLoader = loader;
2751 double FrameLoader::timeOfLastCompletedLoad()
2753 return storedTimeOfLastCompletedLoad;
2756 void FrameLoader::setState(FrameState newState)
2760 if (newState == FrameStateProvisional)
2761 provisionalLoadStarted();
2762 else if (newState == FrameStateComplete) {
2763 frameLoadCompleted();
2764 storedTimeOfLastCompletedLoad = currentTime();
2765 if (m_documentLoader)
2766 m_documentLoader->stopRecordingResponses();
2770 void FrameLoader::clearProvisionalLoad()
2772 setProvisionalDocumentLoader(0);
2773 if (Page* page = m_frame->page())
2774 page->progress()->progressCompleted(m_frame);
2775 setState(FrameStateComplete);
2778 void FrameLoader::markLoadComplete()
2780 setState(FrameStateComplete);
2783 void FrameLoader::commitProvisionalLoad(PassRefPtr<CachedPage> prpCachedPage)
2785 RefPtr<CachedPage> cachedPage = prpCachedPage;
2786 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
2788 LOG(Loading, "WebCoreLoading %s: About to commit provisional load from previous URL %s", m_frame->tree()->name().string().utf8().data(), m_URL.string().utf8().data());
2790 // Check to see if we need to cache the page we are navigating away from into the back/forward cache.
2791 // We are doing this here because we know for sure that a new page is about to be loaded.
2792 cachePageForHistoryItem(m_currentHistoryItem.get());
2794 if (m_loadType != FrameLoadTypeReplace)
2795 closeOldDataSources();
2797 if (!cachedPage && !m_creatingInitialEmptyDocument)
2798 m_client->makeRepresentation(pdl.get());
2800 transitionToCommitted(cachedPage);
2802 // Call clientRedirectCancelledOrFinished() here so that the frame load delegate is notified that the redirect's
2803 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
2804 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are
2805 // just about to commit a new page, there cannot possibly be a pending redirect at this point.
2806 if (m_sentRedirectNotification)
2807 clientRedirectCancelledOrFinished(false);
2809 if (cachedPage && cachedPage->document()) {
2811 cachedPage->clear();
2813 KURL url = pdl->substituteData().responseURL();
2817 url = pdl->responseURL();
2824 LOG(Loading, "WebCoreLoading %s: Finished committing provisional load to URL %s", m_frame->tree()->name().string().utf8().data(), m_URL.string().utf8().data());
2826 if (m_loadType == FrameLoadTypeStandard && m_documentLoader->isClientRedirect())
2827 updateHistoryForClientRedirect();
2829 if (m_documentLoader->isLoadingFromCachedPage()) {
2830 m_frame->document()->documentDidBecomeActive();
2832 // Force a layout to update view size and thereby update scrollbars.
2833 m_client->forceLayout();
2835 const ResponseVector& responses = m_documentLoader->responses();
2836 size_t count = responses.size();
2837 for (size_t i = 0; i < count; i++) {
2838 const ResourceResponse& response = responses[i];
2839 // FIXME: If the WebKit client changes or cancels the request, this is not respected.
2840 ResourceError error;
2841 unsigned long identifier;
2842 ResourceRequest request(response.url());
2843 requestFromDelegate(request, identifier, error);
2844 // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
2845 // However, with today's computers and networking speeds, this won't happen in practice.
2846 // Could be an issue with a giant local file.
2847 sendRemainingDelegateMessages(identifier, response, static_cast<int>(response.expectedContentLength()), error);
2850 pageCache()->remove(m_currentHistoryItem.get());
2852 m_documentLoader->setPrimaryLoadComplete(true);
2854 // FIXME: Why only this frame and not parent frames?
2855 checkLoadCompleteForThisFrame();
2859 void FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage)
2861 ASSERT(m_client->hasWebView());
2862 ASSERT(m_state == FrameStateProvisional);
2864 if (m_state != FrameStateProvisional)
2867 m_client->setCopiesOnScroll();
2868 updateHistoryForCommit();
2870 // The call to closeURL() invokes the unload event handler, which can execute arbitrary
2871 // JavaScript. If the script initiates a new load, we need to abandon the current load,
2872 // or the two will stomp each other.
2873 DocumentLoader* pdl = m_provisionalDocumentLoader.get();
2874 if (m_documentLoader)
2876 if (pdl != m_provisionalDocumentLoader)
2879 // Nothing else can interupt this commit - set the Provisional->Committed transition in stone
2880 if (m_documentLoader)
2881 m_documentLoader->stopLoadingSubresources();
2882 if (m_documentLoader)
2883 m_documentLoader->stopLoadingPlugIns();
2885 setDocumentLoader(m_provisionalDocumentLoader.get());
2886 setProvisionalDocumentLoader(0);
2887 setState(FrameStateCommittedPage);
2889 // Handle adding the URL to the back/forward list.
2890 DocumentLoader* dl = m_documentLoader.get();
2891 String ptitle = dl->title();
2893 switch (m_loadType) {
2894 case FrameLoadTypeForward:
2895 case FrameLoadTypeBack:
2896 case FrameLoadTypeIndexedBackForward:
2897 if (Page* page = m_frame->page())
2898 if (page->backForwardList()) {
2899 updateHistoryForBackForwardNavigation();
2901 // Create a document view for this document, or used the cached view.
2903 DocumentLoader* cachedDocumentLoader = cachedPage->documentLoader();
2904 ASSERT(cachedDocumentLoader);
2905 cachedDocumentLoader->setFrame(m_frame);
2906 m_client->transitionToCommittedFromCachedFrame(cachedPage->cachedMainFrame());
2909 m_client->transitionToCommittedForNewPage();
2913 case FrameLoadTypeReload:
2914 case FrameLoadTypeReloadFromOrigin:
2915 case FrameLoadTypeSame:
2916 case FrameLoadTypeReplace:
2917 updateHistoryForReload();
2918 m_client->transitionToCommittedForNewPage();
2921 case FrameLoadTypeStandard:
2922 updateHistoryForStandardLoad();
2923 #ifndef BUILDING_ON_TIGER
2924 // This code was originally added for a Leopard performance imporvement. We decided to
2925 // ifdef it to fix correctness issues on Tiger documented in <rdar://problem/5441823>.
2926 if (m_frame->view())
2927 m_frame->view()->setScrollbarsSuppressed(true);
2929 m_client->transitionToCommittedForNewPage();
2932 case FrameLoadTypeRedirectWithLockedBackForwardList:
2933 updateHistoryForRedirectWithLockedBackForwardList();
2934 m_client->transitionToCommittedForNewPage();
2937 // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is).
2938 // An exception should be thrown if we're in the FrameLoadTypeUninitialized state.
2940 ASSERT_NOT_REACHED();
2943 m_responseMIMEType = dl->responseMIMEType();
2945 // Tell the client we've committed this URL.
2946 ASSERT(m_frame->view());
2948 if (m_creatingInitialEmptyDocument)
2951 m_committedFirstRealDocumentLoad = true;
2953 // For non-cached HTML pages, these methods are called in FrameLoader::begin.
2954 if (cachedPage || !m_client->hasHTMLView()) {
2955 dispatchDidCommitLoad();
2957 // If we have a title let the WebView know about it.
2958 if (!ptitle.isNull())
2959 m_client->dispatchDidReceiveTitle(ptitle);
2963 void FrameLoader::clientRedirectCancelledOrFinished(bool cancelWithLoadInProgress)
2965 // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
2966 // the redirect succeeded. We should either rename this API, or add a new method, like
2967 // -webView:didFinishClientRedirectForFrame:
2968 m_client->dispatchDidCancelClientRedirect();
2970 if (!cancelWithLoadInProgress)
2971 m_quickRedirectComing = false;
2973 m_sentRedirectNotification = false;
2976 void FrameLoader::clientRedirected(const KURL& url, double seconds, double fireDate, bool lockBackForwardList, bool isJavaScriptFormAction)
2978 m_client->dispatchWillPerformClientRedirect(url, seconds, fireDate);
2980 // Remember that we sent a redirect notification to the frame load delegate so that when we commit
2981 // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
2982 m_sentRedirectNotification = true;
2984 // If a "quick" redirect comes in an, we set a special mode so we treat the next
2985 // load as part of the same navigation. If we don't have a document loader, we have
2986 // no "original" load on which to base a redirect, so we treat the redirect as a normal load.
2987 m_quickRedirectComing = lockBackForwardList && m_documentLoader && !isJavaScriptFormAction;
2991 void FrameLoader::setForceReloadWmlDeck(bool reload)
2993 m_forceReloadWmlDeck = reload;
2997 bool FrameLoader::shouldReload(const KURL& currentURL, const KURL& destinationURL)
3000 // As for WML deck, sometimes it's supposed to be reloaded even if the same URL with fragment
3001 if (m_forceReloadWmlDeck)
3005 // This function implements the rule: "Don't reload if navigating by fragment within
3006 // the same URL, but do reload if going to a new URL or to the same URL with no
3007 // fragment identifier at all."
3008 if (!destinationURL.hasRef())
3010 return !equalIgnoringRef(currentURL, destinationURL);
3013 void FrameLoader::closeOldDataSources()
3015 // FIXME: Is it important for this traversal to be postorder instead of preorder?
3016 // If so, add helpers for postorder traversal, and use them. If not, then lets not
3017 // use a recursive algorithm here.
3018 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
3019 child->loader()->closeOldDataSources();
3021 if (m_documentLoader)
3022 m_client->dispatchWillClose();
3024 m_client->setMainFrameDocumentReady(false); // stop giving out the actual DOMDocument to observers
3027 void FrameLoader::open(CachedPage& cachedPage)
3029 ASSERT(!m_frame->tree()->parent());
3030 ASSERT(m_frame->page());
3031 ASSERT(m_frame->page()->mainFrame() == m_frame);
3033 cancelRedirection();
3035 // We still have to close the previous part page.
3038 // Delete old status bar messages (if it _was_ activated on last URL).
3039 if (m_frame->script()->isEnabled()) {
3040 m_frame->setJSStatusBarText(String());
3041 m_frame->setJSDefaultStatusBarText(String());
3044 open(*cachedPage.cachedMainFrame());
3049 void FrameLoader::open(CachedFrame& cachedFrame)
3051 m_isComplete = false;
3053 // Don't re-emit the load event.
3054 m_didCallImplicitClose = true;
3056 KURL url = cachedFrame.url();
3058 if ((url.protocolIs("http") || url.protocolIs("https")) && !url.host().isEmpty() && url.path().isEmpty())
3068 Document* document = cachedFrame.document();
3070 document->setInPageCache(false);
3072 m_needsClear = true;
3073 m_isComplete = false;
3074 m_didCallImplicitClose = false;
3075 m_outgoingReferrer = url.string();
3077 FrameView* view = cachedFrame.view();
3079 // When navigating to a CachedFrame its FrameView should never be null. If it is we'll crash in creative ways downstream.
3082 view->setWasScrolledByUser(false);
3083 m_frame->setView(view);
3085 m_frame->setDocument(document);
3086 m_frame->setDOMWindow(cachedFrame.domWindow());
3087 m_frame->domWindow()->setURL(document->url());
3088 m_frame->domWindow()->setSecurityOrigin(document->securityOrigin());
3090 m_decoder = document->decoder();
3092 updatePolicyBaseURL();
3094 cachedFrame.restore();
3097 bool FrameLoader::isStopping() const
3099 return activeDocumentLoader()->isStopping();
3102 void FrameLoader::finishedLoading()
3104 // Retain because the stop may release the last reference to it.
3105 RefPtr<Frame> protect(m_frame);
3107 RefPtr<DocumentLoader> dl = activeDocumentLoader();
3108 dl->finishedLoading();
3109 if (!dl->mainDocumentError().isNull() || !dl->frameLoader())
3111 dl->setPrimaryLoadComplete(true);
3112 m_client->dispatchDidLoadMainResource(dl.get());
3113 checkLoadComplete();
3116 bool FrameLoader::isHostedByObjectElement() const
3118 HTMLFrameOwnerElement* owner = m_frame->ownerElement();
3119 return owner && owner->hasTagName(objectTag);
3122 bool FrameLoader::isLoadingMainFrame() const
3124 Page* page = m_frame->page();
3125 return page && m_frame == page->mainFrame();
3128 bool FrameLoader::canShowMIMEType(const String& MIMEType) const
3130 return m_client->canShowMIMEType(MIMEType);
3133 bool FrameLoader::representationExistsForURLScheme(const String& URLScheme)
3135 return m_client->representationExistsForURLScheme(URLScheme);
3138 String FrameLoader::generatedMIMETypeForURLScheme(const String& URLScheme)
3140 return m_client->generatedMIMETypeForURLScheme(URLScheme);
3143 void FrameLoader::cancelContentPolicyCheck()
3145 m_client->cancelPolicyCheck();
3146 m_policyCheck.clear();
3149 void FrameLoader::didReceiveServerRedirectForProvisionalLoadForFrame()
3151 m_client->dispatchDidReceiveServerRedirectForProvisionalLoad();
3154 void FrameLoader::finishedLoadingDocument(DocumentLoader* loader)
3156 // FIXME: Platforms shouldn't differ here!
3157 #if PLATFORM(WIN) || PLATFORM(CHROMIUM)
3158 if (m_creatingInitialEmptyDocument)
3162 // If loading a webarchive, run through webarchive machinery
3163 const String& responseMIMEType = loader->responseMIMEType();
3165 // FIXME: Mac's FrameLoaderClient::finishedLoading() method does work that is required even with Archive loads
3166 // so we still need to call it. Other platforms should only call finishLoading for non-archive loads
3167 // That work should be factored out so this #ifdef can be removed
3169 m_client->finishedLoading(loader);
3170 if (!ArchiveFactory::isArchiveMimeType(responseMIMEType))
3173 if (!ArchiveFactory::isArchiveMimeType(responseMIMEType)) {
3174 m_client->finishedLoading(loader);
3179 RefPtr<Archive> archive(ArchiveFactory::create(loader->mainResourceData().get(), responseMIMEType));
3183 loader->addAllArchiveResources(archive.get());
3185 ArchiveResource* mainResource = archive->mainResource();
3186 loader->setParsedArchiveData(mainResource->data());
3187 continueLoadWithData(mainResource->data(), mainResource->mimeType(), mainResource->textEncoding(), mainResource->url());
3190 bool FrameLoader::isReplacing() const
3192 return m_loadType == FrameLoadTypeReplace;
3195 void FrameLoader::setReplacing()
3197 m_loadType = FrameLoadTypeReplace;
3200 void FrameLoader::revertToProvisional(DocumentLoader* loader)
3202 m_client->revertToProvisionalState(loader);
3205 bool FrameLoader::subframeIsLoading() const
3207 // It's most likely that the last added frame is the last to load so we walk backwards.
3208 for (Frame* child = m_frame->tree()->lastChild(); child; child = child->tree()->previousSibling()) {
3209 FrameLoader* childLoader = child->loader();
3210 DocumentLoader* documentLoader = childLoader->documentLoader();
3211 if (documentLoader && documentLoader->isLoadingInAPISense())
3213 documentLoader = childLoader->provisionalDocumentLoader();
3214 if (documentLoader && documentLoader->isLoadingInAPISense())
3220 void FrameLoader::willChangeTitle(DocumentLoader* loader)
3222 m_client->willChangeTitle(loader);
3225 FrameLoadType FrameLoader::loadType() const
3230 CachePolicy FrameLoader::cachePolicy() const
3233 return CachePolicyVerify;
3235 if (m_loadType == FrameLoadTypeReloadFromOrigin)
3236 return CachePolicyReload;
3238 if (Frame* parentFrame = m_frame->tree()->parent()) {
3239 CachePolicy parentCachePolicy = parentFrame->loader()->cachePolicy();
3240 if (parentCachePolicy != CachePolicyVerify)
3241 return parentCachePolicy;
3244 if (m_loadType == FrameLoadTypeReload)
3245 return CachePolicyRevalidate;
3247 return CachePolicyVerify;
3250 void FrameLoader::stopPolicyCheck()
3252 m_client->cancelPolicyCheck();
3253 PolicyCheck check = m_policyCheck;
3254 m_policyCheck.clear();
3258 void FrameLoader::checkLoadCompleteForThisFrame()
3260 ASSERT(m_client->hasWebView());
3263 case FrameStateProvisional: {
3264 if (m_delegateIsHandlingProvisionalLoadError)
3267 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
3271 // If we've received any errors we may be stuck in the provisional state and actually complete.
3272 const ResourceError& error = pdl->mainDocumentError();
3276 // Check all children first.
3277 RefPtr<HistoryItem> item;
3278 if (Page* page = m_frame->page())
3279 if (isBackForwardLoadType(loadType()) && m_frame == page->mainFrame())
3280 item = m_currentHistoryItem;
3282 bool shouldReset = true;
3283 if (!pdl->isLoadingInAPISense()) {
3284 m_delegateIsHandlingProvisionalLoadError = true;
3285 m_client->dispatchDidFailProvisionalLoad(error);
3286 m_delegateIsHandlingProvisionalLoadError = false;
3288 // FIXME: can stopping loading here possibly have any effect, if isLoading is false,
3289 // which it must be to be in this branch of the if? And is it OK to just do a full-on
3290 // stopAllLoaders instead of stopLoadingSubframes?
3291 stopLoadingSubframes();
3294 // Finish resetting the load state, but only if another load hasn't been started by the
3295 // delegate callback.
3296 if (pdl == m_provisionalDocumentLoader)
3297 clearProvisionalLoad();
3298 else if (m_provisionalDocumentLoader) {
3299 KURL unreachableURL = m_provisionalDocumentLoader->unreachableURL();
3300 if (!unreachableURL.isEmpty() && unreachableURL == pdl->request().url())
3301 shouldReset = false;
3304 if (shouldReset && item)
3305 if (Page* page = m_frame->page()) {
3306 page->backForwardList()->goToItem(item.get());
3307 Settings* settings = m_frame->settings();
3308 page->setGlobalHistoryItem((!settings || settings->privateBrowsingEnabled()) ? 0 : item.get());
3313 case FrameStateCommittedPage: {
3314 DocumentLoader* dl = m_documentLoader.get();
3315 if (!dl || dl->isLoadingInAPISense())
3320 // FIXME: Is this subsequent work important if we already navigated away?
3321 // Maybe there are bugs because of that, or extra work we can skip because
3322 // the new page is ready.
3324 m_client->forceLayoutForNonHTML();
3326 // If the user had a scroll point, scroll to it, overriding the anchor point if any.
3327 if (Page* page = m_frame->page())
3328 if ((isBackForwardLoadType(m_loadType) || m_loadType == FrameLoadTypeReload || m_loadType == FrameLoadTypeReloadFromOrigin) && page->backForwardList())
3329 restoreScrollPositionAndViewState();
3331 if (m_creatingInitialEmptyDocument || !m_committedFirstRealDocumentLoad)
3334 const ResourceError& error = dl->mainDocumentError();
3336 m_didDispatchDidCommitLoad = false;
3338 if (!error.isNull())
3339 m_client->dispatchDidFailLoad(error);
3341 m_client->dispatchDidFinishLoad();
3343 if (Page* page = m_frame->page())
3344 page->progress()->progressCompleted(m_frame);
3348 case FrameStateComplete:
3349 frameLoadCompleted();
3353 ASSERT_NOT_REACHED();
3356 void FrameLoader::continueAfterContentPolicy(PolicyAction policy)
3358 PolicyCheck check = m_policyCheck;
3359 m_policyCheck.clear();
3363 void FrameLoader::continueLoadAfterWillSubmitForm(PolicyAction)
3365 if (!m_provisionalDocumentLoader)
3368 // DocumentLoader calls back to our prepareForLoadStart
3369 m_provisionalDocumentLoader->prepareForLoadStart();
3371 // The load might be cancelled inside of prepareForLoadStart(), nulling out the m_provisionalDocumentLoader,
3372 // so we need to null check it again.
3373 if (!m_provisionalDocumentLoader)
3376 DocumentLoader* activeDocLoader = activeDocumentLoader();
3377 if (activeDocLoader && activeDocLoader->isLoadingMainResource())
3380 m_provisionalDocumentLoader->setLoadingFromCachedPage(false);
3382 unsigned long identifier = 0;
3384 if (Page* page = m_frame->page()) {
3385 identifier = page->progress()->createUniqueIdentifier();
3386 dispatchAssignIdentifierToInitialRequest(identifier, m_provisionalDocumentLoader.get(), m_provisionalDocumentLoader->originalRequest());
3389 if (!m_provisionalDocumentLoader->startLoadingMainResource(identifier))
3390 m_provisionalDocumentLoader->updateLoading();
3393 void FrameLoader::didFirstLayout()
3395 if (Page* page = m_frame->page())
3396 if (isBackForwardLoadType(m_loadType) && page->backForwardList())
3397 restoreScrollPositionAndViewState();
3399 m_firstLayoutDone = true;
3400 m_client->dispatchDidFirstLayout();
3403 void FrameLoader::didFirstVisuallyNonEmptyLayout()
3405 m_client->dispatchDidFirstVisuallyNonEmptyLayout();
3408 void FrameLoader::frameLoadCompleted()
3410 // Note: Can be called multiple times.
3412 m_client->frameLoadCompleted();
3414 // Even if already complete, we might have set a previous item on a frame that
3415 // didn't do any data loading on the past transaction. Make sure to clear these out.
3416 setPreviousHistoryItem(0);
3418 // After a canceled provisional load, firstLayoutDone is false.
3419 // Reset it to true if we're displaying a page.
3420 if (m_documentLoader)
3421 m_firstLayoutDone = true;
3424 bool FrameLoader::firstLayoutDone() const
3426 return m_firstLayoutDone;
3429 bool FrameLoader::isQuickRedirectComing() const
3431 return m_quickRedirectComing;
3434 void FrameLoader::detachChildren()
3436 // FIXME: Is it really necessary to do this in reverse order?
3438 for (Frame* child = m_frame->tree()->lastChild(); child; child = previous) {
3439 previous = child->tree()->previousSibling();
3440 child->loader()->detachFromParent();
3444 void FrameLoader::closeAndRemoveChild(Frame* child)
3446 child->tree()->detachFromParent();
3449 if (child->ownerElement())
3450 child->page()->decrementFrameCount();
3451 child->pageDestroyed();
3453 m_frame->tree()->removeChild(child);
3456 void FrameLoader::recursiveCheckLoadComplete()
3458 Vector<RefPtr<Frame>, 10> frames;
3460 for (RefPtr<Frame> frame = m_frame->tree()->firstChild(); frame; frame = frame->tree()->nextSibling())
3461 frames.append(frame);
3463 unsigned size = frames.size();
3464 for (unsigned i = 0; i < size; i++)
3465 frames[i]->loader()->recursiveCheckLoadComplete();
3467 checkLoadCompleteForThisFrame();
3470 // Called every time a resource is completely loaded, or an error is received.
3471 void FrameLoader::checkLoadComplete()
3473 ASSERT(m_client->hasWebView());
3475 // FIXME: Always traversing the entire frame tree is a bit inefficient, but
3476 // is currently needed in order to null out the previous history item for all frames.
3477 if (Page* page = m_frame->page())
3478 page->mainFrame()->loader()->recursiveCheckLoadComplete();
3481 int FrameLoader::numPendingOrLoadingRequests(bool recurse) const
3484 return numRequests(m_frame->document());
3487 for (Frame* frame = m_frame; frame; frame = frame->tree()->traverseNext(m_frame))
3488 count += numRequests(frame->document());
3492 void FrameLoader::submitForm(const FrameLoadRequest& request, Event* event, bool lockHistory, bool lockBackForwardList)
3494 // FIXME: We'd like to remove this altogether and fix the multiple form submission issue another way.
3495 // We do not want to submit more than one form from the same page,
3496 // nor do we want to submit a single form more than once.
3497 // This flag prevents these from happening; not sure how other browsers prevent this.
3498 // The flag is reset in each time we start handle a new mouse or key down event, and
3499 // also in setView since this part may get reused for a page from the back/forward cache.
3500 // The form multi-submit logic here is only needed when we are submitting a form that affects this frame.
3501 // FIXME: Frame targeting is only one of the ways the submission could end up doing something other
3502 // than replacing this frame's content, so this check is flawed. On the other hand, the check is hardly
3503 // needed any more now that we reset m_submittedFormURL on each mouse or key down event.
3504 Frame* target = m_frame->tree()->find(request.frameName());
3505 if (m_frame->tree()->isDescendantOf(target)) {
3506 if (m_submittedFormURL == request.resourceRequest().url())
3508 m_submittedFormURL = request.resourceRequest().url();
3511 loadFrameRequestWithFormAndValues(request, lockHistory, lockBackForwardList, event, m_formAboutToBeSubmitted.get(), m_formValuesAboutToBeSubmitted);
3513 clearRecordedFormValues();
3516 String FrameLoader::userAgent(const KURL& url) const
3518 return m_client->userAgent(url);
3521 void FrameLoader::tokenizerProcessedData()
3523 // ASSERT(m_frame->page());
3524 // ASSERT(m_frame->document());
3529 void FrameLoader::handledOnloadEvents()
3531 m_client->dispatchDidHandleOnloadEvents();
3534 void FrameLoader::frameDetached()
3537 m_frame->document()->stopActiveDOMObjects();
3541 void FrameLoader::detachFromParent()
3543 RefPtr<Frame> protect(m_frame);
3547 saveScrollPositionAndViewStateToItem(currentHistoryItem());
3550 if (Page* page = m_frame->page())
3551 page->inspectorController()->frameDetachedFromParent(m_frame);
3553 m_client->detachedFromParent2();
3554 setDocumentLoader(0);
3555 m_client->detachedFromParent3();
3556 if (Frame* parent = m_frame->tree()->parent()) {
3557 parent->loader()->closeAndRemoveChild(m_frame);
3558 parent->loader()->scheduleCheckCompleted();
3560 m_frame->setView(0);
3561 m_frame->pageDestroyed();
3565 void FrameLoader::addExtraFieldsToSubresourceRequest(ResourceRequest& request)
3567 addExtraFieldsToRequest(request, m_loadType, false, false);
3570 void FrameLoader::addExtraFieldsToMainResourceRequest(ResourceRequest& request)
3572 addExtraFieldsToRequest(request, m_loadType, true, false);
3575 void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, FrameLoadType loadType, bool mainResource, bool cookiePolicyURLFromRequest)
3577 // These modifications are only necessary for HTTP and HTTPS.
3578 if (!request.url().isEmpty() && !request.url().protocolInHTTPFamily())
3581 applyUserAgent(request);
3583 if (loadType == FrameLoadTypeReload) {
3584 request.setCachePolicy(ReloadIgnoringCacheData);
3585 request.setHTTPHeaderField("Cache-Control", "max-age=0");
3586 } else if (loadType == FrameLoadTypeReloadFromOrigin) {
3587 request.setCachePolicy(ReloadIgnoringCacheData);
3588 request.setHTTPHeaderField("Cache-Control", "no-cache");
3589 request.setHTTPHeaderField("Pragma", "no-cache");
3592 // Don't set the cookie policy URL if it's already been set.
3593 if (request.mainDocumentURL().isEmpty()) {
3594 if (mainResource && (isLoadingMainFrame() || cookiePolicyURLFromRequest))
3595 request.setMainDocumentURL(request.url());
3596 else if (Page* page = m_frame->page())
3597 request.setMainDocumentURL(page->mainFrame()->loader()->url());
3601 request.setHTTPAccept("application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5");
3603 // Make sure we send the Origin header.
3604 addHTTPOriginIfNeeded(request, String());
3606 // Always try UTF-8. If that fails, try frame encoding (if any) and then the default.
3607 // For a newly opened frame with an empty URL, encoding() should not be used,