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 "HTMLAppletElement.h"
59 #include "HTMLFormElement.h"
60 #include "HTMLFrameElement.h"
61 #include "HTMLNames.h"
62 #include "HTMLObjectElement.h"
63 #include "HTTPParsers.h"
64 #include "HistoryItem.h"
65 #include "IconDatabase.h"
66 #include "IconLoader.h"
67 #include "InspectorController.h"
69 #include "MIMETypeRegistry.h"
70 #include "MainResourceLoader.h"
72 #include "PageCache.h"
73 #include "PageGroup.h"
74 #include "PluginData.h"
75 #include "PluginDocument.h"
76 #include "ProgressTracker.h"
77 #include "RenderPart.h"
78 #include "RenderView.h"
79 #include "RenderWidget.h"
80 #include "ResourceHandle.h"
81 #include "ResourceRequest.h"
82 #include "ScriptController.h"
83 #include "ScriptSourceCode.h"
84 #include "ScriptValue.h"
85 #include "SecurityOrigin.h"
86 #include "SegmentedString.h"
88 #include "TextResourceDecoder.h"
89 #include "WindowFeatures.h"
90 #include "XMLHttpRequest.h"
91 #include "XMLTokenizer.h"
92 #include <wtf/CurrentTime.h>
93 #include <wtf/StdLibExtras.h>
95 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
96 #include "ApplicationCache.h"
97 #include "ApplicationCacheResource.h"
101 #include "SVGDocument.h"
102 #include "SVGLocatable.h"
103 #include "SVGNames.h"
104 #include "SVGPreserveAspectRatio.h"
105 #include "SVGSVGElement.h"
106 #include "SVGViewElement.h"
107 #include "SVGViewSpec.h"
113 using namespace SVGNames;
115 using namespace HTMLNames;
117 typedef HashSet<String, CaseFoldingHash> URLSchemesMap;
119 static URLSchemesMap& localSchemes()
121 DEFINE_STATIC_LOCAL(URLSchemesMap, localSchemes, ());
123 if (localSchemes.isEmpty()) {
124 localSchemes.add("file");
126 localSchemes.add("applewebdata");
129 localSchemes.add("qrc");
136 static URLSchemesMap& noAccessSchemes()
138 DEFINE_STATIC_LOCAL(URLSchemesMap, noAccessSchemes, ());
140 if (noAccessSchemes.isEmpty())
141 noAccessSchemes.add("data");
143 return noAccessSchemes;
146 struct FormSubmission {
147 FormSubmission(const char* action, const String& url, PassRefPtr<FormData> formData,
148 const String& target, const String& contentType, const String& boundary,
149 PassRefPtr<Event> event, bool lockHistory, bool lockBackForwardList)
154 , contentType(contentType)
157 , lockHistory(lockHistory)
158 , lockBackForwardList(lockBackForwardList)
164 RefPtr<FormData> formData;
170 bool lockBackForwardList;
173 struct ScheduledRedirection {
174 enum Type { redirection, locationChange, historyNavigation, locationChangeDuringLoad };
179 const String referrer;
180 const int historySteps;
181 const bool lockHistory;
182 const bool lockBackForwardList;
183 const bool wasUserGesture;
184 const bool wasRefresh;
186 ScheduledRedirection(double delay, const String& url, bool lockHistory, bool lockBackForwardList, bool wasUserGesture, bool refresh)
191 , lockHistory(lockHistory)
192 , lockBackForwardList(lockBackForwardList)
193 , wasUserGesture(wasUserGesture)
194 , wasRefresh(refresh)
196 ASSERT(!url.isEmpty());
199 ScheduledRedirection(Type locationChangeType, const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool wasUserGesture, bool refresh)
200 : type(locationChangeType)
205 , lockHistory(lockHistory)
206 , lockBackForwardList(lockBackForwardList)
207 , wasUserGesture(wasUserGesture)
208 , wasRefresh(refresh)
210 ASSERT(locationChangeType == locationChange || locationChangeType == locationChangeDuringLoad);
211 ASSERT(!url.isEmpty());
214 explicit ScheduledRedirection(int historyNavigationSteps)
215 : type(historyNavigation)
217 , historySteps(historyNavigationSteps)
219 , lockBackForwardList(false)
220 , wasUserGesture(false)
226 static double storedTimeOfLastCompletedLoad;
227 static FrameLoader::LocalLoadPolicy localLoadPolicy = FrameLoader::AllowLocalLoadsForLocalOnly;
229 bool isBackForwardLoadType(FrameLoadType type)
232 case FrameLoadTypeStandard:
233 case FrameLoadTypeReload:
234 case FrameLoadTypeReloadFromOrigin:
235 case FrameLoadTypeSame:
236 case FrameLoadTypeRedirectWithLockedBackForwardList:
237 case FrameLoadTypeReplace:
239 case FrameLoadTypeBack:
240 case FrameLoadTypeForward:
241 case FrameLoadTypeIndexedBackForward:
244 ASSERT_NOT_REACHED();
248 static int numRequests(Document* document)
253 return document->docLoader()->requestCount();
256 static inline bool canReferToParentFrameEncoding(const Frame* frame, const Frame* parentFrame)
258 return parentFrame && parentFrame->document()->securityOrigin()->canAccess(frame->document()->securityOrigin());
261 FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client)
264 , m_state(FrameStateCommittedPage)
265 , m_loadType(FrameLoadTypeStandard)
266 , m_policyLoadType(FrameLoadTypeStandard)
267 , m_delegateIsHandlingProvisionalLoadError(false)
268 , m_delegateIsDecidingNavigationPolicy(false)
269 , m_delegateIsHandlingUnimplementablePolicy(false)
270 , m_firstLayoutDone(false)
271 , m_quickRedirectComing(false)
272 , m_sentRedirectNotification(false)
273 , m_inStopAllLoaders(false)
274 , m_navigationDuringLoad(false)
275 , m_isExecutingJavaScriptFormAction(false)
276 , m_isRunningScript(false)
277 , m_didCallImplicitClose(false)
278 , m_wasUnloadEventEmitted(false)
279 , m_isComplete(false)
280 , m_isLoadingMainResource(false)
281 , m_cancellingWithLoadInProgress(false)
282 , m_needsClear(false)
283 , m_receivedData(false)
284 , m_encodingWasChosenByUser(false)
285 , m_containsPlugIns(false)
286 , m_redirectionTimer(this, &FrameLoader::redirectionTimerFired)
287 , m_checkCompletedTimer(this, &FrameLoader::checkCompletedTimerFired)
288 , m_checkLoadCompleteTimer(this, &FrameLoader::checkLoadCompleteTimerFired)
290 , m_openedByDOM(false)
291 , m_creatingInitialEmptyDocument(false)
292 , m_isDisplayingInitialEmptyDocument(false)
293 , m_committedFirstRealDocumentLoad(false)
294 , m_didPerformFirstNavigation(false)
296 , m_didDispatchDidCommitLoad(false)
299 , m_forceReloadWmlDeck(false)
304 FrameLoader::~FrameLoader()
308 HashSet<Frame*>::iterator end = m_openedFrames.end();
309 for (HashSet<Frame*>::iterator it = m_openedFrames.begin(); it != end; ++it)
310 (*it)->loader()->m_opener = 0;
312 m_client->frameLoaderDestroyed();
315 void FrameLoader::init()
317 // this somewhat odd set of steps is needed to give the frame an initial empty document
318 m_isDisplayingInitialEmptyDocument = false;
319 m_creatingInitialEmptyDocument = true;
320 setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(KURL("")), SubstituteData()).get());
321 setProvisionalDocumentLoader(m_policyDocumentLoader.get());
322 setState(FrameStateProvisional);
323 m_provisionalDocumentLoader->setResponse(ResourceResponse(KURL(), "text/html", 0, String(), String()));
324 m_provisionalDocumentLoader->finishedLoading();
325 begin(KURL(), false);
327 m_frame->document()->cancelParsing();
328 m_creatingInitialEmptyDocument = false;
329 m_didCallImplicitClose = true;
332 void FrameLoader::setDefersLoading(bool defers)
334 if (m_documentLoader)
335 m_documentLoader->setDefersLoading(defers);
336 if (m_provisionalDocumentLoader)
337 m_provisionalDocumentLoader->setDefersLoading(defers);
338 if (m_policyDocumentLoader)
339 m_policyDocumentLoader->setDefersLoading(defers);
342 Frame* FrameLoader::createWindow(FrameLoader* frameLoaderForFrameLookup, const FrameLoadRequest& request, const WindowFeatures& features, bool& created)
344 ASSERT(!features.dialog || request.frameName().isEmpty());
346 if (!request.frameName().isEmpty() && request.frameName() != "_blank") {
347 Frame* frame = frameLoaderForFrameLookup->frame()->tree()->find(request.frameName());
348 if (frame && shouldAllowNavigation(frame)) {
349 if (!request.resourceRequest().url().isEmpty())
350 frame->loader()->loadFrameRequestWithFormAndValues(request, false, false, 0, 0, HashMap<String, String>());
351 if (Page* page = frame->page())
352 page->chrome()->focus();
358 // FIXME: Setting the referrer should be the caller's responsibility.
359 FrameLoadRequest requestWithReferrer = request;
360 requestWithReferrer.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
361 addHTTPOriginIfNeeded(requestWithReferrer.resourceRequest(), outgoingOrigin());
363 Page* oldPage = m_frame->page();
367 Page* page = oldPage->chrome()->createWindow(m_frame, requestWithReferrer, features);
371 Frame* frame = page->mainFrame();
372 if (request.frameName() != "_blank")
373 frame->tree()->setName(request.frameName());
375 page->chrome()->setToolbarsVisible(features.toolBarVisible || features.locationBarVisible);
376 page->chrome()->setStatusbarVisible(features.statusBarVisible);
377 page->chrome()->setScrollbarsVisible(features.scrollbarsVisible);
378 page->chrome()->setMenubarVisible(features.menuBarVisible);
379 page->chrome()->setResizable(features.resizable);
381 // 'x' and 'y' specify the location of the window, while 'width' and 'height'
382 // specify the size of the page. We can only resize the window, so
383 // adjust for the difference between the window size and the page size.
385 FloatRect windowRect = page->chrome()->windowRect();
386 FloatSize pageSize = page->chrome()->pageRect().size();
388 windowRect.setX(features.x);
390 windowRect.setY(features.y);
391 if (features.widthSet)
392 windowRect.setWidth(features.width + (windowRect.width() - pageSize.width()));
393 if (features.heightSet)
394 windowRect.setHeight(features.height + (windowRect.height() - pageSize.height()));
395 page->chrome()->setWindowRect(windowRect);
397 page->chrome()->show();
403 bool FrameLoader::canHandleRequest(const ResourceRequest& request)
405 return m_client->canHandleRequest(request);
408 void FrameLoader::changeLocation(const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool userGesture, bool refresh)
410 changeLocation(completeURL(url), referrer, lockHistory, lockBackForwardList, userGesture, refresh);
413 void FrameLoader::changeLocation(const KURL& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool userGesture, bool refresh)
415 RefPtr<Frame> protect(m_frame);
417 ResourceRequest request(url, referrer, refresh ? ReloadIgnoringCacheData : UseProtocolCachePolicy);
419 if (executeIfJavaScriptURL(request.url(), userGesture))
422 urlSelected(request, "_self", 0, lockHistory, lockBackForwardList, userGesture);
425 void FrameLoader::urlSelected(const FrameLoadRequest& request, Event* event, bool lockHistory, bool lockBackForwardList)
427 FrameLoadRequest copy = request;
428 if (copy.resourceRequest().httpReferrer().isEmpty())
429 copy.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
430 addHTTPOriginIfNeeded(copy.resourceRequest(), outgoingOrigin());
432 loadFrameRequestWithFormAndValues(copy, lockHistory, lockBackForwardList, event, 0, HashMap<String, String>());
435 void FrameLoader::urlSelected(const ResourceRequest& request, const String& _target, Event* triggeringEvent, bool lockHistory, bool lockBackForwardList, bool userGesture)
437 if (executeIfJavaScriptURL(request.url(), userGesture, false))
440 String target = _target;
441 if (target.isEmpty())
442 target = m_frame->document()->baseTarget();
444 FrameLoadRequest frameRequest(request, target);
446 urlSelected(frameRequest, triggeringEvent, lockHistory, lockBackForwardList);
449 bool FrameLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String& urlString, const AtomicString& frameName)
451 // Support for <frame src="javascript:string">
454 if (protocolIs(urlString, "javascript")) {
455 scriptURL = completeURL(urlString); // completeURL() encodes the URL.
458 url = completeURL(urlString);
460 Frame* frame = ownerElement->contentFrame();
462 frame->loader()->scheduleLocationChange(url.string(), m_outgoingReferrer, true, true, userGestureHint());
464 frame = loadSubframe(ownerElement, url, frameName, m_outgoingReferrer);
469 if (!scriptURL.isEmpty())
470 frame->loader()->executeIfJavaScriptURL(scriptURL);
475 Frame* FrameLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const String& name, const String& referrer)
477 bool allowsScrolling = true;
478 int marginWidth = -1;
479 int marginHeight = -1;
480 if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag)) {
481 HTMLFrameElementBase* o = static_cast<HTMLFrameElementBase*>(ownerElement);
482 allowsScrolling = o->scrollingMode() != ScrollbarAlwaysOff;
483 marginWidth = o->getMarginWidth();
484 marginHeight = o->getMarginHeight();
487 if (!canLoad(url, referrer)) {
488 FrameLoader::reportLocalLoadFailed(m_frame, url.string());
492 bool hideReferrer = shouldHideReferrer(url, referrer);
493 RefPtr<Frame> frame = m_client->createFrame(url, name, ownerElement, hideReferrer ? String() : referrer,
494 allowsScrolling, marginWidth, marginHeight);
497 checkCallImplicitClose();
501 frame->loader()->m_isComplete = false;
503 RenderObject* renderer = ownerElement->renderer();
504 FrameView* view = frame->view();
505 if (renderer && renderer->isWidget() && view)
506 static_cast<RenderWidget*>(renderer)->setWidget(view);
508 checkCallImplicitClose();
510 // In these cases, the synchronous load would have finished
511 // before we could connect the signals, so make sure to send the
512 // completed() signal for the child by hand
513 // FIXME: In this case the Frame will have finished loading before
514 // it's being added to the child list. It would be a good idea to
515 // create the child first, then invoke the loader separately.
516 if (url.isEmpty() || url == blankURL()) {
517 frame->loader()->completed();
518 frame->loader()->checkCompleted();
524 void FrameLoader::submitFormAgain()
526 if (m_isRunningScript)
528 OwnPtr<FormSubmission> form(m_deferredFormSubmission.release());
531 submitForm(form->action, form->url, form->formData, form->target, form->contentType, form->boundary, form->event.get(), form->lockHistory, form->lockBackForwardList);
534 void FrameLoader::submitForm(const char* action, const String& url, PassRefPtr<FormData> formData,
535 const String& target, const String& contentType, const String& boundary, Event* event, bool lockHistory, bool lockBackForwardList)
539 if (!m_frame->page())
542 KURL u = completeURL(url.isNull() ? "" : url);
543 // FIXME: Do we really need to special-case an empty URL?
544 // Would it be better to just go on with the form submisson and let the I/O fail?
548 if (u.protocolIs("javascript")) {
549 m_isExecutingJavaScriptFormAction = true;
550 executeIfJavaScriptURL(u, false, false);
551 m_isExecutingJavaScriptFormAction = false;
555 if (m_isRunningScript) {
556 if (m_deferredFormSubmission)
558 m_deferredFormSubmission.set(new FormSubmission(action, url, formData, target, contentType, boundary, event, lockHistory, lockBackForwardList));
562 formData->generateFiles(m_frame->page()->chrome()->client());
564 FrameLoadRequest frameRequest;
566 if (!m_outgoingReferrer.isEmpty())
567 frameRequest.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
569 frameRequest.setFrameName(target.isEmpty() ? m_frame->document()->baseTarget() : target);
571 // Handle mailto: forms
572 bool isMailtoForm = equalIgnoringCase(u.protocol(), "mailto");
573 if (isMailtoForm && strcmp(action, "GET") != 0) {
574 // Append body= for POST mailto, replace the whole query string for GET one.
575 String body = formData->flattenToString();
576 String query = u.query();
577 if (!query.isEmpty())
579 u.setQuery(query + body);
582 if (strcmp(action, "GET") == 0) {
583 u.setQuery(formData->flattenToString());
586 frameRequest.resourceRequest().setHTTPBody(formData.get());
587 frameRequest.resourceRequest().setHTTPMethod("POST");
589 // construct some user headers if necessary
590 if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
591 frameRequest.resourceRequest().setHTTPContentType(contentType);
592 else // contentType must be "multipart/form-data"
593 frameRequest.resourceRequest().setHTTPContentType(contentType + "; boundary=" + boundary);
596 frameRequest.resourceRequest().setURL(u);
597 addHTTPOriginIfNeeded(frameRequest.resourceRequest(), outgoingOrigin());
599 submitForm(frameRequest, event, lockHistory, lockBackForwardList);
602 void FrameLoader::stopLoading(bool sendUnload)
604 if (m_frame->document() && m_frame->document()->tokenizer())
605 m_frame->document()->tokenizer()->stopParsing();
608 if (m_frame->document()) {
609 if (m_didCallImplicitClose && !m_wasUnloadEventEmitted) {
610 Node* currentFocusedNode = m_frame->document()->focusedNode();
611 if (currentFocusedNode)
612 currentFocusedNode->aboutToUnload();
613 m_frame->document()->dispatchWindowEvent(eventNames().unloadEvent, false, false);
614 if (m_frame->document())
615 m_frame->document()->updateRendering();
616 m_wasUnloadEventEmitted = true;
617 if (m_frame->eventHandler()->pendingFrameUnloadEventCount())
618 m_frame->eventHandler()->clearPendingFrameUnloadEventCount();
619 if (m_frame->eventHandler()->pendingFrameBeforeUnloadEventCount())
620 m_frame->eventHandler()->clearPendingFrameBeforeUnloadEventCount();
623 if (m_frame->document() && !m_frame->document()->inPageCache())
624 m_frame->document()->removeAllEventListenersFromAllNodes();
627 m_isComplete = true; // to avoid calling completed() in finishedParsing() (David)
628 m_isLoadingMainResource = false;
629 m_didCallImplicitClose = true; // don't want that one either
631 if (m_frame->document() && m_frame->document()->parsing()) {
633 m_frame->document()->setParsing(false);
636 m_workingURL = KURL();
638 if (Document* doc = m_frame->document()) {
639 if (DocLoader* docLoader = doc->docLoader())
640 cache()->loader()->cancelRequests(docLoader);
643 doc->stopDatabases();
647 // tell all subframes to stop as well
648 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
649 child->loader()->stopLoading(sendUnload);
654 void FrameLoader::stop()
656 // http://bugs.webkit.org/show_bug.cgi?id=10854
657 // The frame's last ref may be removed and it will be deleted by checkCompleted().
658 RefPtr<Frame> protector(m_frame);
660 if (m_frame->document()->tokenizer())
661 m_frame->document()->tokenizer()->stopParsing();
662 m_frame->document()->finishParsing();
665 m_iconLoader->stopLoading();
668 bool FrameLoader::closeURL()
672 m_frame->editor()->clearUndoRedoOperations();
676 void FrameLoader::cancelRedirection(bool cancelWithLoadInProgress)
678 m_cancellingWithLoadInProgress = cancelWithLoadInProgress;
680 stopRedirectionTimer();
682 m_scheduledRedirection.clear();
685 KURL FrameLoader::iconURL()
687 // If this isn't a top level frame, return nothing
688 if (m_frame->tree() && m_frame->tree()->parent())
691 // If we have an iconURL from a Link element, return that
692 if (!m_frame->document()->iconURL().isEmpty())
693 return KURL(m_frame->document()->iconURL());
695 // Don't return a favicon iconURL unless we're http or https
696 if (!m_URL.protocolIs("http") && !m_URL.protocolIs("https"))
700 url.setProtocol(m_URL.protocol());
701 url.setHost(m_URL.host());
702 if (int port = m_URL.port())
704 url.setPath("/favicon.ico");
708 bool FrameLoader::didOpenURL(const KURL& url)
710 if (m_scheduledRedirection && m_scheduledRedirection->type == ScheduledRedirection::locationChangeDuringLoad)
711 // A redirect was scheduled before the document was created.
712 // This can happen when one frame changes another frame's location.
716 m_frame->editor()->clearLastEditCommand();
719 m_isComplete = false;
720 m_isLoadingMainResource = true;
721 m_didCallImplicitClose = false;
723 m_frame->setJSStatusBarText(String());
724 m_frame->setJSDefaultStatusBarText(String());
727 if ((m_URL.protocolIs("http") || m_URL.protocolIs("https")) && !m_URL.host().isEmpty() && m_URL.path().isEmpty())
729 m_workingURL = m_URL;
736 void FrameLoader::didExplicitOpen()
738 m_isComplete = false;
739 m_didCallImplicitClose = false;
741 // Calling document.open counts as committing the first real document load.
742 m_committedFirstRealDocumentLoad = true;
744 // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
745 // from a subsequent window.document.open / window.document.write call.
746 // Cancelling redirection here works for all cases because document.open
747 // implicitly precedes document.write.
749 if (m_frame->document()->url() != blankURL())
750 m_URL = m_frame->document()->url();
753 bool FrameLoader::executeIfJavaScriptURL(const KURL& url, bool userGesture, bool replaceDocument)
755 if (!url.protocolIs("javascript"))
758 if (m_frame->page() && !m_frame->page()->javaScriptURLsAreAllowed())
761 String script = decodeURLEscapeSequences(url.string().substring(strlen("javascript:")));
762 ScriptValue result = executeScript(script, userGesture);
765 if (!result.getString(scriptResult))
768 SecurityOrigin* currentSecurityOrigin = 0;
769 currentSecurityOrigin = m_frame->document()->securityOrigin();
771 // FIXME: We should always replace the document, but doing so
772 // synchronously can cause crashes:
773 // http://bugs.webkit.org/show_bug.cgi?id=16782
774 if (replaceDocument) {
776 begin(m_URL, true, currentSecurityOrigin);
784 ScriptValue FrameLoader::executeScript(const String& script, bool forceUserGesture)
786 return executeScript(ScriptSourceCode(script, forceUserGesture ? KURL() : m_URL));
789 ScriptValue FrameLoader::executeScript(const ScriptSourceCode& sourceCode)
791 if (!m_frame->script()->isEnabled() || m_frame->script()->isPaused())
792 return ScriptValue();
794 bool wasRunningScript = m_isRunningScript;
795 m_isRunningScript = true;
797 ScriptValue result = m_frame->script()->evaluate(sourceCode);
799 if (!wasRunningScript) {
800 m_isRunningScript = false;
802 Document::updateDocumentsRendering();
808 void FrameLoader::cancelAndClear()
816 m_frame->script()->updatePlatformScriptObjects();
819 void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects)
821 m_frame->editor()->clear();
825 m_needsClear = false;
827 if (!m_frame->document()->inPageCache()) {
828 m_frame->document()->cancelParsing();
829 m_frame->document()->stopActiveDOMObjects();
830 if (m_frame->document()->attached()) {
831 m_frame->document()->willRemove();
832 m_frame->document()->detach();
834 m_frame->document()->removeFocusedNodeOfSubtree(m_frame->document());
838 // Do this after detaching the document so that the unload event works.
839 if (clearWindowProperties) {
840 m_frame->clearDOMWindow();
841 m_frame->script()->clearWindowShell();
844 m_frame->selection()->clear();
845 m_frame->eventHandler()->clear();
847 m_frame->view()->clear();
849 m_frame->setSelectionGranularity(CharacterGranularity);
851 // Do not drop the document before the ScriptController and view are cleared
852 // as some destructors might still try to access the document.
853 m_frame->setDocument(0);
856 m_containsPlugIns = false;
858 if (clearScriptObjects)
859 m_frame->script()->clearScriptObjects();
861 m_redirectionTimer.stop();
862 m_scheduledRedirection.clear();
864 m_checkCompletedTimer.stop();
865 m_checkLoadCompleteTimer.stop();
867 m_receivedData = false;
868 m_isDisplayingInitialEmptyDocument = false;
870 if (!m_encodingWasChosenByUser)
871 m_encoding = String();
874 void FrameLoader::receivedFirstData()
876 begin(m_workingURL, false);
878 dispatchDidCommitLoad();
879 dispatchWindowObjectAvailable();
881 String ptitle = m_documentLoader->title();
882 // If we have a title let the WebView know about it.
883 if (!ptitle.isNull())
884 m_client->dispatchDidReceiveTitle(ptitle);
886 m_workingURL = KURL();
890 if (!m_documentLoader)
892 if (!parseHTTPRefresh(m_documentLoader->response().httpHeaderField("Refresh"), false, delay, url))
896 url = m_URL.string();
898 url = m_frame->document()->completeURL(url).string();
900 scheduleHTTPRedirection(delay, url);
903 const String& FrameLoader::responseMIMEType() const
905 return m_responseMIMEType;
908 void FrameLoader::setResponseMIMEType(const String& type)
910 m_responseMIMEType = type;
913 void FrameLoader::begin()
918 void FrameLoader::begin(const KURL& url, bool dispatch, SecurityOrigin* origin)
920 // We need to take a reference to the security origin because |clear|
921 // might destroy the document that owns it.
922 RefPtr<SecurityOrigin> forcedSecurityOrigin = origin;
924 RefPtr<Document> document;
926 // Create a new document before clearing the frame, because it may need to inherit an aliased security context.
927 if (!m_isDisplayingInitialEmptyDocument && m_client->shouldUsePluginDocument(m_responseMIMEType))
928 document = PluginDocument::create(m_frame);
930 document = DOMImplementation::createDocument(m_responseMIMEType, m_frame, m_frame->inViewSourceMode());
932 bool resetScripting = !(m_isDisplayingInitialEmptyDocument && m_frame->document()->securityOrigin()->isSecureTransitionTo(url));
933 clear(resetScripting, resetScripting);
935 m_frame->script()->updatePlatformScriptObjects();
938 m_isComplete = false;
939 m_didCallImplicitClose = false;
940 m_isLoadingMainResource = true;
941 m_isDisplayingInitialEmptyDocument = m_creatingInitialEmptyDocument;
944 ref.setUser(String());
945 ref.setPass(String());
946 ref.setRef(String());
947 m_outgoingReferrer = ref.string();
950 m_frame->setDocument(document);
953 dispatchWindowObjectAvailable();
955 document->setURL(m_URL);
957 document->setDecoder(m_decoder.get());
958 if (forcedSecurityOrigin)
959 document->setSecurityOrigin(forcedSecurityOrigin.get());
961 m_frame->domWindow()->setURL(document->url());
962 m_frame->domWindow()->setSecurityOrigin(document->securityOrigin());
964 updatePolicyBaseURL();
966 Settings* settings = document->settings();
967 document->docLoader()->setAutoLoadImages(settings && settings->loadsImagesAutomatically());
969 if (m_documentLoader) {
970 String dnsPrefetchControl = m_documentLoader->response().httpHeaderField("X-DNS-Prefetch-Control");
971 if (!dnsPrefetchControl.isEmpty())
972 document->parseDNSPrefetchControlHeader(dnsPrefetchControl);
975 #if FRAME_LOADS_USER_STYLESHEET
976 KURL userStyleSheet = settings ? settings->userStyleSheetLocation() : KURL();
977 if (!userStyleSheet.isEmpty())
978 m_frame->setUserStyleSheetLocation(userStyleSheet);
981 restoreDocumentState();
983 document->implicitOpen();
986 m_frame->view()->setContentsSize(IntSize());
989 void FrameLoader::write(const char* str, int len, bool flush)
991 if (len == 0 && !flush)
997 Tokenizer* tokenizer = m_frame->document()->tokenizer();
998 if (tokenizer && tokenizer->wantsRawData()) {
1000 tokenizer->writeRawData(str, len);
1005 if (Settings* settings = m_frame->settings()) {
1006 m_decoder = TextResourceDecoder::create(m_responseMIMEType,
1007 settings->defaultTextEncodingName(),
1008 settings->usesEncodingDetector());
1009 Frame* parentFrame = m_frame->tree()->parent();
1010 // Set the hint encoding to the parent frame encoding only if
1011 // the parent and the current frames share the security origin.
1012 // We impose this condition because somebody can make a child frame
1013 // containing a carefully crafted html/javascript in one encoding
1014 // that can be mistaken for hintEncoding (or related encoding) by
1015 // an auto detector. When interpreted in the latter, it could be
1016 // an attack vector.
1017 // FIXME: This might be too cautious for non-7bit-encodings and
1018 // we may consider relaxing this later after testing.
1019 if (canReferToParentFrameEncoding(m_frame, parentFrame))
1020 m_decoder->setHintEncoding(parentFrame->document()->decoder());
1022 m_decoder = TextResourceDecoder::create(m_responseMIMEType, String());
1023 Frame* parentFrame = m_frame->tree()->parent();
1024 if (m_encoding.isEmpty()) {
1025 if (canReferToParentFrameEncoding(m_frame, parentFrame))
1026 m_decoder->setEncoding(parentFrame->document()->inputEncoding(), TextResourceDecoder::EncodingFromParentFrame);
1028 m_decoder->setEncoding(m_encoding,
1029 m_encodingWasChosenByUser ? TextResourceDecoder::UserChosenEncoding : TextResourceDecoder::EncodingFromHTTPHeader);
1031 m_frame->document()->setDecoder(m_decoder.get());
1034 String decoded = m_decoder->decode(str, len);
1036 decoded += m_decoder->flush();
1037 if (decoded.isEmpty())
1040 if (!m_receivedData) {
1041 m_receivedData = true;
1042 if (m_decoder->encoding().usesVisualOrdering())
1043 m_frame->document()->setVisuallyOrdered();
1044 m_frame->document()->recalcStyle(Node::Force);
1048 ASSERT(!tokenizer->wantsRawData());
1049 tokenizer->write(decoded, true);
1053 void FrameLoader::write(const String& str)
1058 if (!m_receivedData) {
1059 m_receivedData = true;
1060 m_frame->document()->setParseMode(Document::Strict);
1063 if (Tokenizer* tokenizer = m_frame->document()->tokenizer())
1064 tokenizer->write(str, true);
1067 void FrameLoader::end()
1069 m_isLoadingMainResource = false;
1070 endIfNotLoadingMainResource();
1073 void FrameLoader::endIfNotLoadingMainResource()
1075 if (m_isLoadingMainResource || !m_frame->page() || !m_frame->document())
1078 // http://bugs.webkit.org/show_bug.cgi?id=10854
1079 // The frame's last ref may be removed and it can be deleted by checkCompleted(),
1080 // so we'll add a protective refcount
1081 RefPtr<Frame> protector(m_frame);
1083 // make sure nothing's left in there
1085 m_frame->document()->finishParsing();
1088 void FrameLoader::iconLoadDecisionAvailable()
1090 if (!m_mayLoadIconLater)
1092 LOG(IconDatabase, "FrameLoader %p was told a load decision is available for its icon", this);
1094 m_mayLoadIconLater = false;
1097 void FrameLoader::startIconLoader()
1099 // FIXME: We kick off the icon loader when the frame is done receiving its main resource.
1100 // But we should instead do it when we're done parsing the head element.
1101 if (!isLoadingMainFrame())
1104 if (!iconDatabase() || !iconDatabase()->isEnabled())
1107 KURL url(iconURL());
1108 String urlString(url.string());
1109 if (urlString.isEmpty())
1112 // If we're not reloading and the icon database doesn't say to load now then bail before we actually start the load
1113 if (loadType() != FrameLoadTypeReload && loadType() != FrameLoadTypeReloadFromOrigin) {
1114 IconLoadDecision decision = iconDatabase()->loadDecisionForIconURL(urlString, m_documentLoader.get());
1115 if (decision == IconLoadNo) {
1116 LOG(IconDatabase, "FrameLoader::startIconLoader() - Told not to load this icon, committing iconURL %s to database for pageURL mapping", urlString.ascii().data());
1117 commitIconURLToIconDatabase(url);
1119 // We were told not to load this icon - that means this icon is already known by the database
1120 // 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
1121 // has done it. This is after registering for the notification so the WebView can call the appropriate delegate method.
1122 // Otherwise if the icon data *is* available, notify the delegate
1123 if (!iconDatabase()->iconDataKnownForIconURL(urlString)) {
1124 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());
1125 m_client->registerForIconNotification();
1126 iconDatabase()->iconForPageURL(m_URL.string(), IntSize(0, 0));
1127 iconDatabase()->iconForPageURL(originalRequestURL().string(), IntSize(0, 0));
1129 m_client->dispatchDidReceiveIcon();
1134 if (decision == IconLoadUnknown) {
1135 // In this case, we may end up loading the icon later, but we still want to commit the icon url mapping to the database
1136 // 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
1137 // We also tell the client to register for the notification that the icon is received now so it isn't missed in case the
1138 // icon is later read in from disk
1139 LOG(IconDatabase, "FrameLoader %p might load icon %s later", this, urlString.ascii().data());
1140 m_mayLoadIconLater = true;
1141 m_client->registerForIconNotification();
1142 commitIconURLToIconDatabase(url);
1147 // This is either a reload or the icon database said "yes, load the icon", so kick off the load!
1149 m_iconLoader.set(IconLoader::create(m_frame).release());
1151 m_iconLoader->startLoading();
1154 void FrameLoader::setLocalLoadPolicy(LocalLoadPolicy policy)
1156 localLoadPolicy = policy;
1159 bool FrameLoader::restrictAccessToLocal()
1161 return localLoadPolicy != FrameLoader::AllowLocalLoadsForAll;
1164 bool FrameLoader::allowSubstituteDataAccessToLocal()
1166 return localLoadPolicy != FrameLoader::AllowLocalLoadsForLocalOnly;
1169 void FrameLoader::commitIconURLToIconDatabase(const KURL& icon)
1171 ASSERT(iconDatabase());
1172 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());
1173 iconDatabase()->setIconURLForPageURL(icon.string(), m_URL.string());
1174 iconDatabase()->setIconURLForPageURL(icon.string(), originalRequestURL().string());
1177 void FrameLoader::restoreDocumentState()
1179 Document* doc = m_frame->document();
1181 HistoryItem* itemToRestore = 0;
1183 switch (loadType()) {
1184 case FrameLoadTypeReload:
1185 case FrameLoadTypeReloadFromOrigin:
1186 case FrameLoadTypeSame:
1187 case FrameLoadTypeReplace:
1189 case FrameLoadTypeBack:
1190 case FrameLoadTypeForward:
1191 case FrameLoadTypeIndexedBackForward:
1192 case FrameLoadTypeRedirectWithLockedBackForwardList:
1193 case FrameLoadTypeStandard:
1194 itemToRestore = m_currentHistoryItem.get();
1200 LOG(Loading, "WebCoreLoading %s: restoring form state from %p", m_frame->tree()->name().string().utf8().data(), itemToRestore);
1201 doc->setStateForNewFormElements(itemToRestore->documentState());
1204 void FrameLoader::gotoAnchor()
1206 // If our URL has no ref, then we have no place we need to jump to.
1207 // OTOH If CSS target was set previously, we want to set it to 0, recalc
1208 // and possibly repaint because :target pseudo class may have been
1209 // set (see bug 11321).
1210 if (!m_URL.hasRef() && !m_frame->document()->cssTarget())
1213 String ref = m_URL.ref();
1214 if (gotoAnchor(ref))
1217 // Try again after decoding the ref, based on the document's encoding.
1219 gotoAnchor(decodeURLEscapeSequences(ref, m_decoder->encoding()));
1222 void FrameLoader::finishedParsing()
1224 if (m_creatingInitialEmptyDocument)
1227 // This can be called from the Frame's destructor, in which case we shouldn't protect ourselves
1228 // because doing so will cause us to re-enter the destructor when protector goes out of scope.
1229 // Null-checking the FrameView indicates whether or not we're in the destructor.
1230 RefPtr<Frame> protector = m_frame->view() ? m_frame : 0;
1232 m_client->dispatchDidFinishDocumentLoad();
1236 if (!m_frame->view())
1237 return; // We are being destroyed by something checkCompleted called.
1239 // Check if the scrollbars are really needed for the content.
1240 // If not, remove them, relayout, and repaint.
1241 m_frame->view()->restoreScrollbar();
1246 void FrameLoader::loadDone()
1251 void FrameLoader::checkCompleted()
1253 if (m_frame->view())
1254 m_frame->view()->checkStopDelayingDeferredRepaints();
1256 // Any frame that hasn't completed yet?
1257 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1258 if (!child->loader()->m_isComplete)
1261 // Have we completed before?
1265 // Are we still parsing?
1266 if (m_frame->document()->parsing())
1269 // Still waiting for images/scripts?
1270 if (numRequests(m_frame->document()))
1274 m_isComplete = true;
1276 RefPtr<Frame> protect(m_frame);
1277 checkCallImplicitClose(); // if we didn't do it before
1279 // Do not start a redirection timer for subframes here.
1280 // That is deferred until the parent is completed.
1281 if (m_scheduledRedirection && !m_frame->tree()->parent())
1282 startRedirectionTimer();
1285 if (m_frame->page())
1286 checkLoadComplete();
1289 void FrameLoader::checkCompletedTimerFired(Timer<FrameLoader>*)
1294 void FrameLoader::scheduleCheckCompleted()
1296 if (!m_checkCompletedTimer.isActive())
1297 m_checkCompletedTimer.startOneShot(0);
1300 void FrameLoader::checkLoadCompleteTimerFired(Timer<FrameLoader>*)
1302 if (!m_frame->page())
1304 checkLoadComplete();
1307 void FrameLoader::scheduleCheckLoadComplete()
1309 if (!m_checkLoadCompleteTimer.isActive())
1310 m_checkLoadCompleteTimer.startOneShot(0);
1313 void FrameLoader::checkCallImplicitClose()
1315 if (m_didCallImplicitClose || m_frame->document()->parsing())
1318 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1319 if (!child->loader()->m_isComplete) // still got a frame running -> too early
1322 m_didCallImplicitClose = true;
1323 m_wasUnloadEventEmitted = false;
1324 m_frame->document()->implicitClose();
1327 KURL FrameLoader::baseURL() const
1329 ASSERT(m_frame->document());
1330 return m_frame->document()->baseURL();
1333 String FrameLoader::baseTarget() const
1335 ASSERT(m_frame->document());
1336 return m_frame->document()->baseTarget();
1339 KURL FrameLoader::completeURL(const String& url)
1341 ASSERT(m_frame->document());
1342 return m_frame->document()->completeURL(url);
1345 void FrameLoader::scheduleHTTPRedirection(double delay, const String& url)
1347 if (delay < 0 || delay > INT_MAX / 1000)
1350 if (!m_frame->page())
1356 // We want a new history item if the refresh timeout is > 1 second.
1357 if (!m_scheduledRedirection || delay <= m_scheduledRedirection->delay)
1358 scheduleRedirection(new ScheduledRedirection(delay, url, true, delay <= 1, false, false));
1361 void FrameLoader::scheduleLocationChange(const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool wasUserGesture)
1363 if (!m_frame->page())
1369 // If the URL we're going to navigate to is the same as the current one, except for the
1370 // fragment part, we don't need to schedule the location change.
1371 KURL parsedURL(url);
1372 if (parsedURL.hasRef() && equalIgnoringRef(m_URL, parsedURL)) {
1373 changeLocation(url, referrer, lockHistory, lockBackForwardList, wasUserGesture);
1377 // Handle a location change of a page with no document as a special case.
1378 // This may happen when a frame changes the location of another frame.
1379 bool duringLoad = !m_committedFirstRealDocumentLoad;
1381 // If a redirect was scheduled during a load, then stop the current load.
1382 // Otherwise when the current load transitions from a provisional to a
1383 // committed state, pending redirects may be cancelled.
1385 if (m_provisionalDocumentLoader)
1386 m_provisionalDocumentLoader->stopLoading();
1390 ScheduledRedirection::Type type = duringLoad
1391 ? ScheduledRedirection::locationChangeDuringLoad : ScheduledRedirection::locationChange;
1392 scheduleRedirection(new ScheduledRedirection(type, url, referrer, lockHistory, lockBackForwardList, wasUserGesture, false));
1395 void FrameLoader::scheduleRefresh(bool wasUserGesture)
1397 if (!m_frame->page())
1400 if (m_URL.isEmpty())
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)
1515 HistoryItem* parentItem = currentHistoryItem();
1516 FrameLoadType loadType = this->loadType();
1517 FrameLoadType childLoadType = FrameLoadTypeRedirectWithLockedBackForwardList;
1519 KURL workingURL = url;
1521 // If we're moving in the back/forward list, we might want to replace the content
1522 // of this child frame with whatever was there at that point.
1523 if (parentItem && parentItem->children().size() && isBackForwardLoadType(loadType)) {
1524 HistoryItem* childItem = parentItem->childItemWithName(childFrame->tree()->name());
1526 // Use the original URL to ensure we get all the side-effects, such as
1527 // onLoad handlers, of any redirects that happened. An example of where
1528 // this is needed is Radar 3213556.
1529 workingURL = KURL(childItem->originalURLString());
1530 childLoadType = loadType;
1531 childFrame->loader()->setProvisionalHistoryItem(childItem);
1535 RefPtr<Archive> subframeArchive = activeDocumentLoader()->popArchiveForSubframe(childFrame->tree()->name());
1537 if (subframeArchive)
1538 childFrame->loader()->loadArchive(subframeArchive.release());
1540 childFrame->loader()->loadURL(workingURL, referer, String(), false, childLoadType, 0, 0);
1543 void FrameLoader::loadArchive(PassRefPtr<Archive> prpArchive)
1545 RefPtr<Archive> archive = prpArchive;
1547 ArchiveResource* mainResource = archive->mainResource();
1548 ASSERT(mainResource);
1552 SubstituteData substituteData(mainResource->data(), mainResource->mimeType(), mainResource->textEncoding(), KURL());
1554 ResourceRequest request(mainResource->url());
1556 request.applyWebArchiveHackForMail();
1559 RefPtr<DocumentLoader> documentLoader = m_client->createDocumentLoader(request, substituteData);
1560 documentLoader->addAllArchiveResources(archive.get());
1561 load(documentLoader.get());
1564 String FrameLoader::encoding() const
1566 if (m_encodingWasChosenByUser && !m_encoding.isEmpty())
1568 if (m_decoder && m_decoder->encoding().isValid())
1569 return m_decoder->encoding().name();
1570 Settings* settings = m_frame->settings();
1571 return settings ? settings->defaultTextEncodingName() : String();
1574 bool FrameLoader::gotoAnchor(const String& name)
1576 ASSERT(m_frame->document());
1578 if (!m_frame->document()->haveStylesheetsLoaded()) {
1579 m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(true);
1583 m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(false);
1585 Element* anchorNode = m_frame->document()->findAnchor(name);
1588 if (m_frame->document()->isSVGDocument()) {
1589 if (name.startsWith("xpointer(")) {
1590 // We need to parse the xpointer reference here
1591 } else if (name.startsWith("svgView(")) {
1592 RefPtr<SVGSVGElement> svg = static_cast<SVGDocument*>(m_frame->document())->rootElement();
1593 if (!svg->currentView()->parseViewSpec(name))
1595 svg->setUseCurrentView(true);
1597 if (anchorNode && anchorNode->hasTagName(SVGNames::viewTag)) {
1598 RefPtr<SVGViewElement> viewElement = anchorNode->hasTagName(SVGNames::viewTag) ? static_cast<SVGViewElement*>(anchorNode) : 0;
1599 if (viewElement.get()) {
1600 RefPtr<SVGSVGElement> svg = static_cast<SVGSVGElement*>(SVGLocatable::nearestViewportElement(viewElement.get()));
1601 svg->inheritViewAttributes(viewElement.get());
1605 // FIXME: need to decide which <svg> to focus on, and zoom to that one
1606 // FIXME: need to actually "highlight" the viewTarget(s)
1610 m_frame->document()->setCSSTarget(anchorNode); // Setting to null will clear the current target.
1612 // Implement the rule that "" and "top" both mean top of page as in other browsers.
1613 if (!anchorNode && !(name.isEmpty() || equalIgnoringCase(name, "top")))
1616 // We need to update the layout before scrolling, otherwise we could
1617 // really mess things up if an anchor scroll comes at a bad moment.
1618 m_frame->document()->updateRendering();
1619 // Only do a layout if changes have occurred that make it necessary.
1620 if (m_frame->view() && m_frame->contentRenderer() && m_frame->contentRenderer()->needsLayout())
1621 m_frame->view()->layout();
1623 // Scroll nested layers and frames to reveal the anchor.
1624 // Align to the top and to the closest side (this matches other browsers).
1625 RenderObject* renderer;
1628 renderer = m_frame->document()->renderer(); // top of document
1630 renderer = anchorNode->renderer();
1631 rect = anchorNode->getRect();
1634 renderer->enclosingLayer()->scrollRectToVisible(rect, true, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
1639 bool FrameLoader::requestObject(RenderPart* renderer, const String& url, const AtomicString& frameName,
1640 const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues)
1642 if (url.isEmpty() && mimeType.isEmpty())
1647 completedURL = completeURL(url);
1650 if (shouldUsePlugin(completedURL, mimeType, renderer->hasFallbackContent(), useFallback)) {
1651 Settings* settings = m_frame->settings();
1652 if (!settings || !settings->arePluginsEnabled() ||
1653 (!settings->isJavaEnabled() && MIMETypeRegistry::isJavaAppletMIMEType(mimeType)))
1655 return loadPlugin(renderer, completedURL, mimeType, paramNames, paramValues, useFallback);
1658 ASSERT(renderer->node()->hasTagName(objectTag) || renderer->node()->hasTagName(embedTag));
1659 HTMLPlugInElement* element = static_cast<HTMLPlugInElement*>(renderer->node());
1661 // FIXME: OK to always make a new frame? When does the old frame get removed?
1662 return loadSubframe(element, completedURL, frameName, m_outgoingReferrer);
1665 bool FrameLoader::shouldUsePlugin(const KURL& url, const String& mimeType, bool hasFallback, bool& useFallback)
1667 if (m_client->shouldUsePluginDocument(mimeType)) {
1668 useFallback = false;
1672 // Allow other plug-ins to win over QuickTime because if the user has installed a plug-in that
1673 // can handle TIFF (which QuickTime can also handle) they probably intended to override QT.
1674 if (m_frame->page() && (mimeType == "image/tiff" || mimeType == "image/tif" || mimeType == "image/x-tiff")) {
1675 const PluginData* pluginData = m_frame->page()->pluginData();
1676 String pluginName = pluginData ? pluginData->pluginNameForMimeType(mimeType) : String();
1677 if (!pluginName.isEmpty() && !pluginName.contains("QuickTime", false))
1681 ObjectContentType objectType = m_client->objectContentType(url, mimeType);
1682 // If an object's content can't be handled and it has no fallback, let
1683 // it be handled as a plugin to show the broken plugin icon.
1684 useFallback = objectType == ObjectContentNone && hasFallback;
1685 return objectType == ObjectContentNone || objectType == ObjectContentNetscapePlugin || objectType == ObjectContentOtherPlugin;
1688 static HTMLPlugInElement* toPlugInElement(Node* node)
1693 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
1694 ASSERT(node->hasTagName(objectTag) || node->hasTagName(embedTag)
1695 || node->hasTagName(videoTag) || node->hasTagName(audioTag)
1696 || node->hasTagName(appletTag));
1698 ASSERT(node->hasTagName(objectTag) || node->hasTagName(embedTag)
1699 || node->hasTagName(appletTag));
1702 return static_cast<HTMLPlugInElement*>(node);
1705 bool FrameLoader::loadPlugin(RenderPart* renderer, const KURL& url, const String& mimeType,
1706 const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback)
1710 if (renderer && !useFallback) {
1711 HTMLPlugInElement* element = toPlugInElement(renderer->node());
1713 if (!canLoad(url, String(), frame()->document())) {
1714 FrameLoader::reportLocalLoadFailed(m_frame, url.string());
1718 widget = m_client->createPlugin(IntSize(renderer->contentWidth(), renderer->contentHeight()),
1719 element, url, paramNames, paramValues, mimeType,
1720 m_frame->document()->isPluginDocument());
1722 renderer->setWidget(widget);
1723 m_containsPlugIns = true;
1730 void FrameLoader::clearRecordedFormValues()
1732 m_formAboutToBeSubmitted = 0;
1733 m_formValuesAboutToBeSubmitted.clear();
1736 void FrameLoader::setFormAboutToBeSubmitted(PassRefPtr<HTMLFormElement> element)
1738 m_formAboutToBeSubmitted = element;
1741 void FrameLoader::recordFormValue(const String& name, const String& value)
1743 m_formValuesAboutToBeSubmitted.set(name, value);
1746 void FrameLoader::parentCompleted()
1748 if (m_scheduledRedirection && !m_redirectionTimer.isActive())
1749 startRedirectionTimer();
1752 String FrameLoader::outgoingReferrer() const
1754 return m_outgoingReferrer;
1757 String FrameLoader::outgoingOrigin() const
1759 return m_frame->document()->securityOrigin()->toString();
1762 Frame* FrameLoader::opener()
1767 void FrameLoader::setOpener(Frame* opener)
1770 m_opener->loader()->m_openedFrames.remove(m_frame);
1772 opener->loader()->m_openedFrames.add(m_frame);
1775 if (m_frame->document()) {
1776 m_frame->document()->initSecurityContext();
1777 m_frame->domWindow()->setSecurityOrigin(m_frame->document()->securityOrigin());
1781 bool FrameLoader::openedByDOM() const
1783 return m_openedByDOM;
1786 void FrameLoader::setOpenedByDOM()
1788 m_openedByDOM = true;
1791 void FrameLoader::handleFallbackContent()
1793 HTMLFrameOwnerElement* owner = m_frame->ownerElement();
1794 if (!owner || !owner->hasTagName(objectTag))
1796 static_cast<HTMLObjectElement*>(owner)->renderFallbackContent();
1799 void FrameLoader::provisionalLoadStarted()
1801 Page* page = m_frame->page();
1803 // this is used to update the current history item
1804 // in the event of a navigation aytime during loading
1805 m_navigationDuringLoad = false;
1807 Document *document = page->mainFrame()->document();
1808 m_navigationDuringLoad = !page->mainFrame()->loader()->isComplete() || (document && document->processingLoadEvent());
1811 m_firstLayoutDone = false;
1812 cancelRedirection(true);
1813 m_client->provisionalLoadStarted();
1816 bool FrameLoader::userGestureHint()
1818 Frame* frame = m_frame->tree()->top();
1819 if (!frame->script()->isEnabled())
1820 return true; // If JavaScript is disabled, a user gesture must have initiated the navigation.
1821 return frame->script()->processingUserGesture(); // FIXME: Use pageIsProcessingUserGesture.
1824 void FrameLoader::didNotOpenURL(const KURL& url)
1826 if (m_submittedFormURL == url)
1827 m_submittedFormURL = KURL();
1830 void FrameLoader::resetMultipleFormSubmissionProtection()
1832 m_submittedFormURL = KURL();
1835 void FrameLoader::setEncoding(const String& name, bool userChosen)
1837 if (!m_workingURL.isEmpty())
1838 receivedFirstData();
1840 m_encodingWasChosenByUser = userChosen;
1843 void FrameLoader::addData(const char* bytes, int length)
1845 ASSERT(m_workingURL.isEmpty());
1846 ASSERT(m_frame->document());
1847 ASSERT(m_frame->document()->parsing());
1848 write(bytes, length);
1851 bool FrameLoader::canCachePageContainingThisFrame()
1853 return m_documentLoader
1854 && m_documentLoader->mainDocumentError().isNull()
1855 && !m_frame->tree()->childCount()
1856 // FIXME: If we ever change this so that frames with plug-ins will be cached,
1857 // we need to make sure that we don't cache frames that have outstanding NPObjects
1858 // (objects created by the plug-in). Since there is no way to pause/resume a Netscape plug-in,
1859 // they would need to be destroyed and then recreated, and there is no way that we can recreate
1860 // the right NPObjects. See <rdar://problem/5197041> for more information.
1861 && !m_containsPlugIns
1862 && !m_URL.protocolIs("https")
1863 && !m_frame->document()->hasWindowEventListener(eventNames().unloadEvent)
1864 #if ENABLE(DATABASE)
1865 && !m_frame->document()->hasOpenDatabases()
1867 && !m_frame->document()->usingGeolocation()
1868 && m_currentHistoryItem
1869 && !isQuickRedirectComing()
1870 && !m_documentLoader->isLoadingInAPISense()
1871 && !m_documentLoader->isStopping()
1872 && m_frame->document()->canSuspendActiveDOMObjects()
1873 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
1874 // FIXME: We should investigating caching frames that have an associated
1875 // application cache. <rdar://problem/5917899> tracks that work.
1876 && !m_documentLoader->applicationCache()
1877 && !m_documentLoader->candidateApplicationCacheGroup()
1879 && m_client->canCachePage()
1883 bool FrameLoader::canCachePage()
1886 logCanCachePageDecision();
1889 // Cache the page, if possible.
1890 // Don't write to the cache if in the middle of a redirect, since we will want to
1891 // store the final page we end up on.
1892 // No point writing to the cache on a reload or loadSame, since we will just write
1893 // over it again when we leave that page.
1894 // FIXME: <rdar://problem/4886592> - We should work out the complexities of caching pages with frames as they
1895 // are the most interesting pages on the web, and often those that would benefit the most from caching!
1896 FrameLoadType loadType = this->loadType();
1898 return !m_frame->tree()->parent()
1899 && canCachePageContainingThisFrame()
1901 && m_frame->page()->backForwardList()->enabled()
1902 && m_frame->page()->backForwardList()->capacity() > 0
1903 && m_frame->page()->settings()->usesPageCache()
1904 && loadType != FrameLoadTypeReload
1905 && loadType != FrameLoadTypeReloadFromOrigin
1906 && loadType != FrameLoadTypeSame
1911 static String& pageCacheLogPrefix(int indentLevel)
1913 static int previousIndent = -1;
1914 DEFINE_STATIC_LOCAL(String, prefix, ());
1916 if (indentLevel != previousIndent) {
1917 previousIndent = indentLevel;
1919 for (int i = 0; i < previousIndent; ++i)
1926 static void pageCacheLog(const String& prefix, const String& message)
1928 LOG(PageCache, "%s%s", prefix.utf8().data(), message.utf8().data());
1931 #define PCLOG(...) pageCacheLog(pageCacheLogPrefix(indentLevel), String::format(__VA_ARGS__))
1933 void FrameLoader::logCanCachePageDecision()
1935 // Only bother logging for main frames that have actually loaded and have content.
1936 if (m_creatingInitialEmptyDocument)
1938 KURL currentURL = m_documentLoader ? m_documentLoader->url() : KURL();
1939 if (currentURL.isEmpty())
1942 int indentLevel = 0;
1943 PCLOG("--------\n Determining if page can be cached:");
1945 bool cannotCache = !logCanCacheFrameDecision(1);
1947 FrameLoadType loadType = this->loadType();
1949 if (m_frame->tree()->parent())
1950 { PCLOG(" -Frame has a parent frame"); cannotCache = true; }
1951 if (!m_frame->page()) {
1952 PCLOG(" -There is no Page object");
1956 if (!m_frame->page()->backForwardList()->enabled())
1957 { PCLOG(" -The back/forward list is disabled"); cannotCache = true; }
1958 if (!(m_frame->page()->backForwardList()->capacity() > 0))
1959 { PCLOG(" -The back/forward list has a 0 capacity"); cannotCache = true; }
1960 if (!m_frame->page()->settings()->usesPageCache())
1961 { PCLOG(" -Page settings says b/f cache disabled"); cannotCache = true; }
1962 if (loadType == FrameLoadTypeReload)
1963 { PCLOG(" -Load type is: Reload"); cannotCache = true; }
1964 if (loadType == FrameLoadTypeReloadFromOrigin)
1965 { PCLOG(" -Load type is: Reload from origin"); cannotCache = true; }
1966 if (loadType == FrameLoadTypeSame)
1967 { PCLOG(" -Load type is: Same"); cannotCache = true; }
1970 PCLOG(cannotCache ? " Page CANNOT be cached\n--------" : " Page CAN be cached\n--------");
1973 bool FrameLoader::logCanCacheFrameDecision(int indentLevel)
1975 // Only bother logging for frames that have actually loaded and have content.
1976 if (m_creatingInitialEmptyDocument)
1978 KURL currentURL = m_documentLoader ? m_documentLoader->url() : KURL();
1979 if (currentURL.isEmpty())
1983 KURL newURL = m_provisionalDocumentLoader ? m_provisionalDocumentLoader->url() : KURL();
1984 if (!newURL.isEmpty())
1985 PCLOG(" Determining if frame can be cached navigating from (%s) to (%s):", currentURL.string().utf8().data(), newURL.string().utf8().data());
1987 PCLOG(" Determining if subframe with URL (%s) can be cached:", currentURL.string().utf8().data());
1989 bool cannotCache = false;
1992 if (!m_documentLoader) {
1993 PCLOG(" -There is no DocumentLoader object");
1997 if (!m_documentLoader->mainDocumentError().isNull())
1998 { PCLOG(" -Main document has an error"); cannotCache = true; }
1999 if (m_frame->tree()->childCount())
2000 { PCLOG(" -Frame has child frames"); cannotCache = true; }
2001 if (m_containsPlugIns)
2002 { PCLOG(" -Frame contains plugins"); cannotCache = true; }
2003 if (m_URL.protocolIs("https"))
2004 { PCLOG(" -Frame is HTTPS"); cannotCache = true; }
2005 if (m_frame->document()->hasWindowEventListener(eventNames().unloadEvent))
2006 { PCLOG(" -Frame has an unload event listener"); cannotCache = true; }
2007 #if ENABLE(DATABASE)
2008 if (m_frame->document()->hasOpenDatabases())
2009 { PCLOG(" -Frame has open database handles"); cannotCache = true; }
2011 if (m_frame->document()->usingGeolocation())
2012 { PCLOG(" -Frame uses Geolocation"); cannotCache = true; }
2013 if (!m_currentHistoryItem)
2014 { PCLOG(" -No current history item"); cannotCache = true; }
2015 if (isQuickRedirectComing())
2016 { PCLOG(" -Quick redirect is coming"); cannotCache = true; }
2017 if (m_documentLoader->isLoadingInAPISense())
2018 { PCLOG(" -DocumentLoader is still loading in API sense"); cannotCache = true; }
2019 if (m_documentLoader->isStopping())
2020 { PCLOG(" -DocumentLoader is in the middle of stopping"); cannotCache = true; }
2021 if (!m_frame->document()->canSuspendActiveDOMObjects())
2022 { PCLOG(" -The document cannot suspect its active DOM Objects"); cannotCache = true; }
2023 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
2024 if (m_documentLoader->applicationCache())
2025 { PCLOG(" -The DocumentLoader has an active application cache"); cannotCache = true; }
2026 if (m_documentLoader->candidateApplicationCacheGroup())
2027 { PCLOG(" -The DocumentLoader has a candidateApplicationCacheGroup"); cannotCache = true; }
2029 if (!m_client->canCachePage())
2030 { PCLOG(" -The client says this frame cannot be cached"); cannotCache = true; }
2033 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2034 if (!child->loader()->logCanCacheFrameDecision(indentLevel + 1))
2037 PCLOG(cannotCache ? " Frame CANNOT be cached" : " Frame CAN be cached");
2040 return !cannotCache;
2044 void FrameLoader::updatePolicyBaseURL()
2046 if (m_frame->tree()->parent())
2047 setPolicyBaseURL(m_frame->tree()->parent()->document()->policyBaseURL());
2049 setPolicyBaseURL(m_URL);
2052 void FrameLoader::setPolicyBaseURL(const KURL& url)
2054 m_frame->document()->setPolicyBaseURL(url);
2055 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2056 child->loader()->setPolicyBaseURL(url);
2059 // This does the same kind of work that didOpenURL does, except it relies on the fact
2060 // that a higher level already checked that the URLs match and the scrolling is the right thing to do.
2061 void FrameLoader::scrollToAnchor(const KURL& url)
2064 updateHistoryForAnchorScroll();
2066 // If we were in the autoscroll/panScroll mode we want to stop it before following the link to the anchor
2067 m_frame->eventHandler()->stopAutoscrollTimer();
2071 // It's important to model this as a load that starts and immediately finishes.
2072 // Otherwise, the parent frame may think we never finished loading.
2073 m_isComplete = false;
2077 bool FrameLoader::isComplete() const
2079 return m_isComplete;
2082 void FrameLoader::scheduleRedirection(ScheduledRedirection* redirection)
2084 ASSERT(m_frame->page());
2086 stopRedirectionTimer();
2087 m_scheduledRedirection.set(redirection);
2088 if (!m_isComplete && redirection->type != ScheduledRedirection::redirection)
2090 if (m_isComplete || redirection->type != ScheduledRedirection::redirection)
2091 startRedirectionTimer();
2094 void FrameLoader::startRedirectionTimer()
2096 ASSERT(m_frame->page());
2097 ASSERT(m_scheduledRedirection);
2099 m_redirectionTimer.stop();
2100 m_redirectionTimer.startOneShot(m_scheduledRedirection->delay);
2102 switch (m_scheduledRedirection->type) {
2103 case ScheduledRedirection::redirection:
2104 case ScheduledRedirection::locationChange:
2105 case ScheduledRedirection::locationChangeDuringLoad:
2106 clientRedirected(KURL(m_scheduledRedirection->url),
2107 m_scheduledRedirection->delay,
2108 currentTime() + m_redirectionTimer.nextFireInterval(),
2109 m_scheduledRedirection->lockBackForwardList,
2110 m_isExecutingJavaScriptFormAction);
2112 case ScheduledRedirection::historyNavigation:
2113 // Don't report history navigations.
2116 ASSERT_NOT_REACHED();
2119 void FrameLoader::stopRedirectionTimer()
2121 if (!m_redirectionTimer.isActive())
2124 m_redirectionTimer.stop();
2126 if (m_scheduledRedirection) {
2127 switch (m_scheduledRedirection->type) {
2128 case ScheduledRedirection::redirection:
2129 case ScheduledRedirection::locationChange:
2130 case ScheduledRedirection::locationChangeDuringLoad:
2131 clientRedirectCancelledOrFinished(m_cancellingWithLoadInProgress);
2133 case ScheduledRedirection::historyNavigation:
2134 // Don't report history navigations.
2137 ASSERT_NOT_REACHED();
2141 void FrameLoader::completed()
2143 RefPtr<Frame> protect(m_frame);
2144 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2145 child->loader()->parentCompleted();
2146 if (Frame* parent = m_frame->tree()->parent())
2147 parent->loader()->checkCompleted();
2151 void FrameLoader::started()
2153 for (Frame* frame = m_frame; frame; frame = frame->tree()->parent())
2154 frame->loader()->m_isComplete = false;
2157 bool FrameLoader::containsPlugins() const
2159 return m_containsPlugIns;
2162 void FrameLoader::prepareForLoadStart()
2164 if (Page* page = m_frame->page())
2165 page->progress()->progressStarted(m_frame);
2166 m_client->dispatchDidStartProvisionalLoad();
2169 void FrameLoader::setupForReplace()
2171 setState(FrameStateProvisional);
2172 m_provisionalDocumentLoader = m_documentLoader;
2173 m_documentLoader = 0;
2177 void FrameLoader::setupForReplaceByMIMEType(const String& newMIMEType)
2179 activeDocumentLoader()->setupForReplaceByMIMEType(newMIMEType);
2182 void FrameLoader::loadFrameRequestWithFormAndValues(const FrameLoadRequest& request, bool lockHistory, bool lockBackForwardList, Event* event,
2183 HTMLFormElement* submitForm, const HashMap<String, String>& formValues)
2185 RefPtr<FormState> formState;
2187 formState = FormState::create(submitForm, formValues, m_frame);
2189 KURL url = request.resourceRequest().url();
2192 String argsReferrer = request.resourceRequest().httpReferrer();
2193 if (!argsReferrer.isEmpty())
2194 referrer = argsReferrer;
2196 referrer = m_outgoingReferrer;
2198 ASSERT(frame()->document());
2199 if (url.protocolIs("file")) {
2200 if (!canLoad(url, String(), frame()->document()) && !canLoad(url, referrer)) {
2201 FrameLoader::reportLocalLoadFailed(m_frame, url.string());
2206 if (shouldHideReferrer(url, referrer))
2207 referrer = String();
2209 FrameLoadType loadType;
2210 if (request.resourceRequest().cachePolicy() == ReloadIgnoringCacheData)
2211 loadType = FrameLoadTypeReload;
2212 else if (lockBackForwardList)
2213 loadType = FrameLoadTypeRedirectWithLockedBackForwardList;
2215 loadType = FrameLoadTypeStandard;
2217 if (request.resourceRequest().httpMethod() == "POST")
2218 loadPostRequest(request.resourceRequest(), referrer, request.frameName(), lockHistory, loadType, event, formState.release());
2220 loadURL(request.resourceRequest().url(), referrer, request.frameName(), lockHistory, loadType, event, formState.release());
2222 Frame* targetFrame = findFrameForNavigation(request.frameName());
2223 if (targetFrame && targetFrame != m_frame)
2224 if (Page* page = targetFrame->page())
2225 page->chrome()->focus();
2228 void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType newLoadType,
2229 Event* event, PassRefPtr<FormState> prpFormState)
2231 RefPtr<FormState> formState = prpFormState;
2232 bool isFormSubmission = formState;
2234 ResourceRequest request(newURL);
2235 if (!referrer.isEmpty()) {
2236 request.setHTTPReferrer(referrer);
2237 RefPtr<SecurityOrigin> referrerOrigin = SecurityOrigin::createFromString(referrer);
2238 addHTTPOriginIfNeeded(request, referrerOrigin->toString());
2240 addExtraFieldsToRequest(request, newLoadType, true, event || isFormSubmission);
2241 if (newLoadType == FrameLoadTypeReload || newLoadType == FrameLoadTypeReloadFromOrigin)
2242 request.setCachePolicy(ReloadIgnoringCacheData);
2244 ASSERT(newLoadType != FrameLoadTypeSame);
2246 NavigationAction action(newURL, newLoadType, isFormSubmission, event);
2248 if (!frameName.isEmpty()) {
2249 if (Frame* targetFrame = findFrameForNavigation(frameName))
2250 targetFrame->loader()->loadURL(newURL, referrer, String(), lockHistory, newLoadType, event, formState);
2252 checkNewWindowPolicy(action, request, formState, frameName);
2256 RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader;
2258 bool sameURL = shouldTreatURLAsSameAsCurrent(newURL);
2260 // Make sure to do scroll to anchor processing even if the URL is
2261 // exactly the same so pages with '#' links and DHTML side effects
2263 if (shouldScrollToAnchor(isFormSubmission, newLoadType, newURL)) {
2264 oldDocumentLoader->setTriggeringAction(action);
2266 checkNavigationPolicy(request, oldDocumentLoader.get(), formState,
2267 callContinueFragmentScrollAfterNavigationPolicy, this);
2269 // must grab this now, since this load may stop the previous load and clear this flag
2270 bool isRedirect = m_quickRedirectComing;
2271 loadWithNavigationAction(request, action, lockHistory, newLoadType, formState);
2273 m_quickRedirectComing = false;
2274 if (m_provisionalDocumentLoader)
2275 m_provisionalDocumentLoader->setIsClientRedirect(true);
2277 // Example of this case are sites that reload the same URL with a different cookie
2278 // driving the generated content, or a master frame with links that drive a target
2279 // frame, where the user has clicked on the same link repeatedly.
2280 m_loadType = FrameLoadTypeSame;
2284 void FrameLoader::load(const ResourceRequest& request, bool lockHistory)
2286 load(request, SubstituteData(), lockHistory);
2289 void FrameLoader::load(const ResourceRequest& request, const SubstituteData& substituteData, bool lockHistory)
2291 if (m_inStopAllLoaders)
2294 // FIXME: is this the right place to reset loadType? Perhaps this should be done after loading is finished or aborted.
2295 m_loadType = FrameLoadTypeStandard;
2296 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, substituteData);
2297 if (lockHistory && m_documentLoader)
2298 loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory() : m_documentLoader->clientRedirectSourceForHistory());
2302 void FrameLoader::load(const ResourceRequest& request, const String& frameName, bool lockHistory)
2304 if (frameName.isEmpty()) {
2305 load(request, lockHistory);
2309 Frame* frame = findFrameForNavigation(frameName);
2311 frame->loader()->load(request, lockHistory);
2315 checkNewWindowPolicy(NavigationAction(request.url(), NavigationTypeOther), request, 0, frameName);
2318 void FrameLoader::loadWithNavigationAction(const ResourceRequest& request, const NavigationAction& action, bool lockHistory, FrameLoadType type, PassRefPtr<FormState> formState)
2320 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, SubstituteData());
2321 if (lockHistory && m_documentLoader)
2322 loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory() : m_documentLoader->clientRedirectSourceForHistory());
2324 loader->setTriggeringAction(action);
2325 if (m_documentLoader)
2326 loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
2328 loadWithDocumentLoader(loader.get(), type, formState);
2331 void FrameLoader::load(DocumentLoader* newDocumentLoader)
2333 ResourceRequest& r = newDocumentLoader->request();
2334 addExtraFieldsToMainResourceRequest(r);
2337 if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->originalRequest().url())) {
2338 r.setCachePolicy(ReloadIgnoringCacheData);
2339 type = FrameLoadTypeSame;
2341 type = FrameLoadTypeStandard;
2343 if (m_documentLoader)
2344 newDocumentLoader->setOverrideEncoding(m_documentLoader->overrideEncoding());
2346 // When we loading alternate content for an unreachable URL that we're
2347 // visiting in the history list, we treat it as a reload so the history list
2348 // is appropriately maintained.
2350 // FIXME: This seems like a dangerous overloading of the meaning of "FrameLoadTypeReload" ...
2351 // shouldn't a more explicit type of reload be defined, that means roughly
2352 // "load without affecting history" ?
2353 if (shouldReloadToHandleUnreachableURL(newDocumentLoader)) {
2354 ASSERT(type == FrameLoadTypeStandard);
2355 type = FrameLoadTypeReload;
2358 loadWithDocumentLoader(newDocumentLoader, type, 0);
2361 void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType type, PassRefPtr<FormState> prpFormState)
2363 ASSERT(m_client->hasWebView());
2365 // Unfortunately the view must be non-nil, this is ultimately due
2366 // to parser requiring a FrameView. We should fix this dependency.
2368 ASSERT(m_frame->view());
2370 m_policyLoadType = type;
2371 RefPtr<FormState> formState = prpFormState;
2372 bool isFormSubmission = formState;
2374 const KURL& newURL = loader->request().url();
2376 if (shouldScrollToAnchor(isFormSubmission, m_policyLoadType, newURL)) {
2377 RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader;
2378 NavigationAction action(newURL, m_policyLoadType, isFormSubmission);
2380 oldDocumentLoader->setTriggeringAction(action);
2382 checkNavigationPolicy(loader->request(), oldDocumentLoader.get(), formState,
2383 callContinueFragmentScrollAfterNavigationPolicy, this);
2385 if (Frame* parent = m_frame->tree()->parent())
2386 loader->setOverrideEncoding(parent->loader()->documentLoader()->overrideEncoding());
2389 setPolicyDocumentLoader(loader);
2391 checkNavigationPolicy(loader->request(), loader, formState,
2392 callContinueLoadAfterNavigationPolicy, this);
2396 bool FrameLoader::canLoad(const KURL& url, const String& referrer, const Document* doc)
2398 // We can always load any URL that isn't considered local (e.g. http URLs)
2399 if (!shouldTreatURLAsLocal(url.string()))
2402 // If we were provided a document, we let its local file policy dictate the result,
2403 // otherwise we allow local loads only if the supplied referrer is also local.
2405 return doc->securityOrigin()->canLoadLocalResources();
2406 else if (!referrer.isEmpty())
2407 return shouldTreatURLAsLocal(referrer);
2412 void FrameLoader::reportLocalLoadFailed(Frame* frame, const String& url)
2414 ASSERT(!url.isEmpty());
2418 frame->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, "Not allowed to load local resource: " + url, 0, String());
2421 bool FrameLoader::shouldHideReferrer(const KURL& url, const String& referrer)
2423 bool referrerIsSecureURL = protocolIs(referrer, "https");
2424 bool referrerIsWebURL = referrerIsSecureURL || protocolIs(referrer, "http");
2426 if (!referrerIsWebURL)
2429 if (!referrerIsSecureURL)
2432 bool URLIsSecureURL = url.protocolIs("https");
2434 return !URLIsSecureURL;
2437 const ResourceRequest& FrameLoader::initialRequest() const
2439 return activeDocumentLoader()->originalRequest();
2442 void FrameLoader::receivedData(const char* data, int length)
2444 activeDocumentLoader()->receivedData(data, length);
2447 void FrameLoader::handleUnimplementablePolicy(const ResourceError& error)
2449 m_delegateIsHandlingUnimplementablePolicy = true;
2450 m_client->dispatchUnableToImplementPolicy(error);
2451 m_delegateIsHandlingUnimplementablePolicy = false;
2454 void FrameLoader::cannotShowMIMEType(const ResourceResponse& response)
2456 handleUnimplementablePolicy(m_client->cannotShowMIMETypeError(response));
2459 ResourceError FrameLoader::interruptionForPolicyChangeError(const ResourceRequest& request)
2461 return m_client->interruptForPolicyChangeError(request);
2464 void FrameLoader::checkNavigationPolicy(const ResourceRequest& newRequest, NavigationPolicyDecisionFunction function, void* argument)
2466 checkNavigationPolicy(newRequest, activeDocumentLoader(), 0, function, argument);
2469 void FrameLoader::checkContentPolicy(const String& MIMEType, ContentPolicyDecisionFunction function, void* argument)
2471 ASSERT(activeDocumentLoader());
2473 // Always show content with valid substitute data.
2474 if (activeDocumentLoader()->substituteData().isValid()) {
2475 function(argument, PolicyUse);
2480 // Respect the hidden FTP Directory Listing pref so it can be tested even if the policy delegate might otherwise disallow it
2481 Settings* settings = m_frame->settings();
2482 if (settings && settings->forceFTPDirectoryListings() && MIMEType == "application/x-ftp-directory") {
2483 function(argument, PolicyUse);
2488 m_policyCheck.set(function, argument);
2489 m_client->dispatchDecidePolicyForMIMEType(&FrameLoader::continueAfterContentPolicy,
2490 MIMEType, activeDocumentLoader()->request());
2493 bool FrameLoader::shouldReloadToHandleUnreachableURL(DocumentLoader* docLoader)
2495 KURL unreachableURL = docLoader->unreachableURL();
2497 if (unreachableURL.isEmpty())
2500 if (!isBackForwardLoadType(m_policyLoadType))
2503 // We only treat unreachableURLs specially during the delegate callbacks
2504 // for provisional load errors and navigation policy decisions. The former
2505 // case handles well-formed URLs that can't be loaded, and the latter
2506 // case handles malformed URLs and unknown schemes. Loading alternate content
2507 // at other times behaves like a standard load.
2508 DocumentLoader* compareDocumentLoader = 0;
2509 if (m_delegateIsDecidingNavigationPolicy || m_delegateIsHandlingUnimplementablePolicy)
2510 compareDocumentLoader = m_policyDocumentLoader.get();
2511 else if (m_delegateIsHandlingProvisionalLoadError)
2512 compareDocumentLoader = m_provisionalDocumentLoader.get();
2514 return compareDocumentLoader && unreachableURL == compareDocumentLoader->request().url();
2517 void FrameLoader::reloadWithOverrideEncoding(const String& encoding)
2519 if (!m_documentLoader)
2522 ResourceRequest request = m_documentLoader->request();
2523 KURL unreachableURL = m_documentLoader->unreachableURL();
2524 if (!unreachableURL.isEmpty())
2525 request.setURL(unreachableURL);
2527 request.setCachePolicy(ReturnCacheDataElseLoad);
2529 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, SubstituteData());
2530 setPolicyDocumentLoader(loader.get());
2532 loader->setOverrideEncoding(encoding);
2534 loadWithDocumentLoader(loader.get(), FrameLoadTypeReload, 0);
2537 void FrameLoader::reload(bool endToEndReload)
2539 if (!m_documentLoader)
2542 // If a window is created by javascript, its main frame can have an empty but non-nil URL.
2543 // Reloading in this case will lose the current contents (see 4151001).
2544 if (m_documentLoader->request().url().isEmpty())
2547 ResourceRequest initialRequest = m_documentLoader->request();
2549 // Replace error-page URL with the URL we were trying to reach.
2550 KURL unreachableURL = m_documentLoader->unreachableURL();
2551 if (!unreachableURL.isEmpty())
2552 initialRequest.setURL(unreachableURL);
2554 // Create a new document loader for the reload, this will become m_documentLoader eventually,
2555 // but first it has to be the "policy" document loader, and then the "provisional" document loader.
2556 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(initialRequest, SubstituteData());
2558 ResourceRequest& request = loader->request();
2560 // FIXME: We don't have a mechanism to revalidate the main resource without reloading at the moment.
2561 request.setCachePolicy(ReloadIgnoringCacheData);
2563 // If we're about to re-post, set up action so the application can warn the user.
2564 if (request.httpMethod() == "POST")
2565 loader->setTriggeringAction(NavigationAction(request.url(), NavigationTypeFormResubmitted));
2567 loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
2569 loadWithDocumentLoader(loader.get(), endToEndReload ? FrameLoadTypeReloadFromOrigin : FrameLoadTypeReload, 0);
2572 static bool canAccessAncestor(const SecurityOrigin* activeSecurityOrigin, Frame* targetFrame)
2574 // targetFrame can be NULL when we're trying to navigate a top-level frame
2575 // that has a NULL opener.
2579 for (Frame* ancestorFrame = targetFrame; ancestorFrame; ancestorFrame = ancestorFrame->tree()->parent()) {
2580 Document* ancestorDocument = ancestorFrame->document();
2581 if (!ancestorDocument)
2584 const SecurityOrigin* ancestorSecurityOrigin = ancestorDocument->securityOrigin();
2585 if (activeSecurityOrigin->canAccess(ancestorSecurityOrigin))
2592 bool FrameLoader::shouldAllowNavigation(Frame* targetFrame) const
2594 // The navigation change is safe if the active frame is:
2595 // - in the same security origin as the target or one of the target's
2598 // Or the target frame is:
2599 // - a top-level frame in the frame hierarchy and the active frame can
2600 // navigate the target frame's opener per above.
2605 // Performance optimization.
2606 if (m_frame == targetFrame)
2609 // Let a frame navigate the top-level window that contains it. This is
2610 // important to allow because it lets a site "frame-bust" (escape from a
2611 // frame created by another web site).
2612 if (targetFrame == m_frame->tree()->top())
2615 Document* activeDocument = m_frame->document();
2616 ASSERT(activeDocument);
2617 const SecurityOrigin* activeSecurityOrigin = activeDocument->securityOrigin();
2619 // For top-level windows, check the opener.
2620 if (!targetFrame->tree()->parent() && canAccessAncestor(activeSecurityOrigin, targetFrame->loader()->opener()))
2623 // In general, check the frame's ancestors.
2624 if (canAccessAncestor(activeSecurityOrigin, targetFrame))
2627 Settings* settings = targetFrame->settings();
2628 if (settings && !settings->privateBrowsingEnabled()) {
2629 Document* targetDocument = targetFrame->document();
2630 // FIXME: this error message should contain more specifics of why the navigation change is not allowed.
2631 String message = String::format("Unsafe JavaScript attempt to initiate a navigation change for frame with URL %s from frame with URL %s.\n",
2632 targetDocument->url().string().utf8().data(), activeDocument->url().string().utf8().data());
2634 // FIXME: should we print to the console of the activeFrame as well?
2635 targetFrame->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, message, 1, String());
2641 void FrameLoader::stopLoadingSubframes()
2643 for (RefPtr<Frame> child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2644 child->loader()->stopAllLoaders();
2647 void FrameLoader::stopAllLoaders()
2649 // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
2650 if (m_inStopAllLoaders)
2653 m_inStopAllLoaders = true;
2657 stopLoadingSubframes();
2658 if (m_provisionalDocumentLoader)
2659 m_provisionalDocumentLoader->stopLoading();
2660 if (m_documentLoader)
2661 m_documentLoader->stopLoading();
2663 setProvisionalDocumentLoader(0);
2665 if (m_documentLoader)
2666 m_documentLoader->clearArchiveResources();
2668 m_inStopAllLoaders = false;
2671 void FrameLoader::stopForUserCancel(bool deferCheckLoadComplete)
2675 if (deferCheckLoadComplete)
2676 scheduleCheckLoadComplete();
2677 else if (m_frame->page())
2678 checkLoadComplete();
2681 DocumentLoader* FrameLoader::activeDocumentLoader() const
2683 if (m_state == FrameStateProvisional)
2684 return m_provisionalDocumentLoader.get();
2685 return m_documentLoader.get();
2688 bool FrameLoader::isLoading() const
2690 DocumentLoader* docLoader = activeDocumentLoader();
2693 return docLoader->isLoadingMainResource() || docLoader->isLoadingSubresources() || docLoader->isLoadingPlugIns();
2696 bool FrameLoader::frameHasLoaded() const
2698 return m_committedFirstRealDocumentLoad || (m_provisionalDocumentLoader && !m_creatingInitialEmptyDocument);
2701 void FrameLoader::setDocumentLoader(DocumentLoader* loader)
2703 if (!loader && !m_documentLoader)
2706 ASSERT(loader != m_documentLoader);
2707 ASSERT(!loader || loader->frameLoader() == this);
2709 m_client->prepareForDataSourceReplacement();
2711 if (m_documentLoader)
2712 m_documentLoader->detachFromFrame();
2714 m_documentLoader = loader;
2717 void FrameLoader::setPolicyDocumentLoader(DocumentLoader* loader)
2719 if (m_policyDocumentLoader == loader)
2724 loader->setFrame(m_frame);
2725 if (m_policyDocumentLoader
2726 && m_policyDocumentLoader != m_provisionalDocumentLoader
2727 && m_policyDocumentLoader != m_documentLoader)
2728 m_policyDocumentLoader->detachFromFrame();
2730 m_policyDocumentLoader = loader;
2733 void FrameLoader::setProvisionalDocumentLoader(DocumentLoader* loader)
2735 ASSERT(!loader || !m_provisionalDocumentLoader);
2736 ASSERT(!loader || loader->frameLoader() == this);
2738 if (m_provisionalDocumentLoader && m_provisionalDocumentLoader != m_documentLoader)
2739 m_provisionalDocumentLoader->detachFromFrame();
2741 m_provisionalDocumentLoader = loader;
2744 double FrameLoader::timeOfLastCompletedLoad()
2746 return storedTimeOfLastCompletedLoad;
2749 void FrameLoader::setState(FrameState newState)
2753 if (newState == FrameStateProvisional)
2754 provisionalLoadStarted();
2755 else if (newState == FrameStateComplete) {
2756 frameLoadCompleted();
2757 storedTimeOfLastCompletedLoad = currentTime();
2758 if (m_documentLoader)
2759 m_documentLoader->stopRecordingResponses();
2763 void FrameLoader::clearProvisionalLoad()
2765 setProvisionalDocumentLoader(0);
2766 if (Page* page = m_frame->page())
2767 page->progress()->progressCompleted(m_frame);
2768 setState(FrameStateComplete);
2771 void FrameLoader::markLoadComplete()
2773 setState(FrameStateComplete);
2776 void FrameLoader::commitProvisionalLoad(PassRefPtr<CachedPage> prpCachedPage)
2778 RefPtr<CachedPage> cachedPage = prpCachedPage;
2779 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
2781 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());
2783 // Check to see if we need to cache the page we are navigating away from into the back/forward cache.
2784 // We are doing this here because we know for sure that a new page is about to be loaded.
2785 cachePageForHistoryItem(m_currentHistoryItem.get());
2787 if (m_loadType != FrameLoadTypeReplace)
2788 closeOldDataSources();
2790 if (!cachedPage && !m_creatingInitialEmptyDocument)
2791 m_client->makeRepresentation(pdl.get());
2793 transitionToCommitted(cachedPage);
2795 // Call clientRedirectCancelledOrFinished() here so that the frame load delegate is notified that the redirect's
2796 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
2797 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are
2798 // just about to commit a new page, there cannot possibly be a pending redirect at this point.
2799 if (m_sentRedirectNotification)
2800 clientRedirectCancelledOrFinished(false);
2802 if (cachedPage && cachedPage->document()) {
2804 cachedPage->clear();
2806 KURL url = pdl->substituteData().responseURL();
2810 url = pdl->responseURL();
2817 LOG(Loading, "WebCoreLoading %s: Finished committing provisional load to URL %s", m_frame->tree()->name().string().utf8().data(), m_URL.string().utf8().data());
2819 if (m_loadType == FrameLoadTypeStandard && m_documentLoader->isClientRedirect())
2820 updateHistoryForClientRedirect();
2822 if (m_documentLoader->isLoadingFromCachedPage()) {
2823 m_frame->document()->documentDidBecomeActive();
2825 // Force a layout to update view size and thereby update scrollbars.
2826 m_client->forceLayout();
2828 const ResponseVector& responses = m_documentLoader->responses();
2829 size_t count = responses.size();
2830 for (size_t i = 0; i < count; i++) {
2831 const ResourceResponse& response = responses[i];
2832 // FIXME: If the WebKit client changes or cancels the request, this is not respected.
2833 ResourceError error;
2834 unsigned long identifier;
2835 ResourceRequest request(response.url());
2836 requestFromDelegate(request, identifier, error);
2837 // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
2838 // However, with today's computers and networking speeds, this won't happen in practice.
2839 // Could be an issue with a giant local file.
2840 sendRemainingDelegateMessages(identifier, response, static_cast<int>(response.expectedContentLength()), error);
2843 pageCache()->remove(m_currentHistoryItem.get());
2845 m_documentLoader->setPrimaryLoadComplete(true);
2847 // FIXME: Why only this frame and not parent frames?
2848 checkLoadCompleteForThisFrame();
2852 void FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage)
2854 ASSERT(m_client->hasWebView());
2855 ASSERT(m_state == FrameStateProvisional);
2857 if (m_state != FrameStateProvisional)
2860 m_client->setCopiesOnScroll();
2861 updateHistoryForCommit();
2863 // The call to closeURL() invokes the unload event handler, which can execute arbitrary
2864 // JavaScript. If the script initiates a new load, we need to abandon the current load,
2865 // or the two will stomp each other.
2866 DocumentLoader* pdl = m_provisionalDocumentLoader.get();
2867 if (m_documentLoader)
2869 if (pdl != m_provisionalDocumentLoader)
2872 // Nothing else can interupt this commit - set the Provisional->Committed transition in stone
2873 if (m_documentLoader)
2874 m_documentLoader->stopLoadingSubresources();
2875 if (m_documentLoader)
2876 m_documentLoader->stopLoadingPlugIns();
2878 setDocumentLoader(m_provisionalDocumentLoader.get());
2879 setProvisionalDocumentLoader(0);
2880 setState(FrameStateCommittedPage);
2882 // Handle adding the URL to the back/forward list.
2883 DocumentLoader* dl = m_documentLoader.get();
2884 String ptitle = dl->title();
2886 switch (m_loadType) {
2887 case FrameLoadTypeForward:
2888 case FrameLoadTypeBack:
2889 case FrameLoadTypeIndexedBackForward:
2890 if (Page* page = m_frame->page())
2891 if (page->backForwardList()) {
2892 updateHistoryForBackForwardNavigation();
2894 // Create a document view for this document, or used the cached view.
2896 DocumentLoader* cachedDocumentLoader = cachedPage->documentLoader();
2897 ASSERT(cachedDocumentLoader);
2898 cachedDocumentLoader->setFrame(m_frame);
2899 m_client->transitionToCommittedFromCachedFrame(cachedPage->cachedMainFrame());
2902 m_client->transitionToCommittedForNewPage();
2906 case FrameLoadTypeReload:
2907 case FrameLoadTypeReloadFromOrigin:
2908 case FrameLoadTypeSame:
2909 case FrameLoadTypeReplace:
2910 updateHistoryForReload();
2911 m_client->transitionToCommittedForNewPage();
2914 case FrameLoadTypeStandard:
2915 updateHistoryForStandardLoad();
2916 #ifndef BUILDING_ON_TIGER
2917 // This code was originally added for a Leopard performance imporvement. We decided to
2918 // ifdef it to fix correctness issues on Tiger documented in <rdar://problem/5441823>.
2919 if (m_frame->view())
2920 m_frame->view()->setScrollbarsSuppressed(true);
2922 m_client->transitionToCommittedForNewPage();
2925 case FrameLoadTypeRedirectWithLockedBackForwardList:
2926 updateHistoryForRedirectWithLockedBackForwardList();
2927 m_client->transitionToCommittedForNewPage();
2930 // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is).
2931 // An exception should be thrown if we're in the FrameLoadTypeUninitialized state.
2933 ASSERT_NOT_REACHED();
2936 m_responseMIMEType = dl->responseMIMEType();
2938 // Tell the client we've committed this URL.
2939 ASSERT(m_frame->view());
2941 if (m_creatingInitialEmptyDocument)
2944 m_committedFirstRealDocumentLoad = true;
2946 // For non-cached HTML pages, these methods are called in FrameLoader::begin.
2947 if (cachedPage || !m_client->hasHTMLView()) {
2948 dispatchDidCommitLoad();
2950 // If we have a title let the WebView know about it.
2951 if (!ptitle.isNull())
2952 m_client->dispatchDidReceiveTitle(ptitle);
2956 void FrameLoader::clientRedirectCancelledOrFinished(bool cancelWithLoadInProgress)
2958 // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
2959 // the redirect succeeded. We should either rename this API, or add a new method, like
2960 // -webView:didFinishClientRedirectForFrame:
2961 m_client->dispatchDidCancelClientRedirect();
2963 if (!cancelWithLoadInProgress)
2964 m_quickRedirectComing = false;
2966 m_sentRedirectNotification = false;
2969 void FrameLoader::clientRedirected(const KURL& url, double seconds, double fireDate, bool lockBackForwardList, bool isJavaScriptFormAction)
2971 m_client->dispatchWillPerformClientRedirect(url, seconds, fireDate);
2973 // Remember that we sent a redirect notification to the frame load delegate so that when we commit
2974 // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
2975 m_sentRedirectNotification = true;
2977 // If a "quick" redirect comes in an, we set a special mode so we treat the next
2978 // load as part of the same navigation. If we don't have a document loader, we have
2979 // no "original" load on which to base a redirect, so we treat the redirect as a normal load.
2980 m_quickRedirectComing = lockBackForwardList && m_documentLoader && !isJavaScriptFormAction;
2984 void FrameLoader::setForceReloadWmlDeck(bool reload)
2986 m_forceReloadWmlDeck = reload;
2990 bool FrameLoader::shouldReload(const KURL& currentURL, const KURL& destinationURL)
2993 // As for WML deck, sometimes it's supposed to be reloaded even if the same URL with fragment
2994 if (m_forceReloadWmlDeck)
2998 // This function implements the rule: "Don't reload if navigating by fragment within
2999 // the same URL, but do reload if going to a new URL or to the same URL with no
3000 // fragment identifier at all."
3001 if (!destinationURL.hasRef())
3003 return !equalIgnoringRef(currentURL, destinationURL);
3006 void FrameLoader::closeOldDataSources()
3008 // FIXME: Is it important for this traversal to be postorder instead of preorder?
3009 // If so, add helpers for postorder traversal, and use them. If not, then lets not
3010 // use a recursive algorithm here.
3011 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
3012 child->loader()->closeOldDataSources();
3014 if (m_documentLoader)
3015 m_client->dispatchWillClose();
3017 m_client->setMainFrameDocumentReady(false); // stop giving out the actual DOMDocument to observers
3020 void FrameLoader::open(CachedPage& cachedPage)
3022 ASSERT(!m_frame->tree()->parent());
3023 ASSERT(m_frame->page());
3024 ASSERT(m_frame->page()->mainFrame() == m_frame);
3026 cancelRedirection();
3028 // We still have to close the previous part page.
3031 // Delete old status bar messages (if it _was_ activated on last URL).
3032 if (m_frame->script()->isEnabled()) {
3033 m_frame->setJSStatusBarText(String());
3034 m_frame->setJSDefaultStatusBarText(String());
3037 open(*cachedPage.cachedMainFrame());
3042 void FrameLoader::open(CachedFrame& cachedFrame)
3044 m_isComplete = false;
3046 // Don't re-emit the load event.
3047 m_didCallImplicitClose = true;
3049 KURL url = cachedFrame.url();
3051 if ((url.protocolIs("http") || url.protocolIs("https")) && !url.host().isEmpty() && url.path().isEmpty())
3061 Document* document = cachedFrame.document();
3063 document->setInPageCache(false);
3065 m_needsClear = true;
3066 m_isComplete = false;
3067 m_didCallImplicitClose = false;
3068 m_outgoingReferrer = url.string();
3070 FrameView* view = cachedFrame.view();
3072 // When navigating to a CachedFrame its FrameView should never be null. If it is we'll crash in creative ways downstream.
3075 view->setWasScrolledByUser(false);
3076 m_frame->setView(view);
3078 m_frame->setDocument(document);
3079 m_frame->setDOMWindow(cachedFrame.domWindow());
3080 m_frame->domWindow()->setURL(document->url());
3081 m_frame->domWindow()->setSecurityOrigin(document->securityOrigin());
3083 m_decoder = document->decoder();
3085 updatePolicyBaseURL();
3087 cachedFrame.restore();
3090 bool FrameLoader::isStopping() const
3092 return activeDocumentLoader()->isStopping();
3095 void FrameLoader::finishedLoading()
3097 // Retain because the stop may release the last reference to it.
3098 RefPtr<Frame> protect(m_frame);
3100 RefPtr<DocumentLoader> dl = activeDocumentLoader();
3101 dl->finishedLoading();
3102 if (!dl->mainDocumentError().isNull() || !dl->frameLoader())
3104 dl->setPrimaryLoadComplete(true);
3105 m_client->dispatchDidLoadMainResource(dl.get());
3106 checkLoadComplete();
3109 bool FrameLoader::isHostedByObjectElement() const
3111 HTMLFrameOwnerElement* owner = m_frame->ownerElement();
3112 return owner && owner->hasTagName(objectTag);
3115 bool FrameLoader::isLoadingMainFrame() const
3117 Page* page = m_frame->page();
3118 return page && m_frame == page->mainFrame();
3121 bool FrameLoader::canShowMIMEType(const String& MIMEType) const
3123 return m_client->canShowMIMEType(MIMEType);
3126 bool FrameLoader::representationExistsForURLScheme(const String& URLScheme)
3128 return m_client->representationExistsForURLScheme(URLScheme);
3131 String FrameLoader::generatedMIMETypeForURLScheme(const String& URLScheme)
3133 return m_client->generatedMIMETypeForURLScheme(URLScheme);
3136 void FrameLoader::cancelContentPolicyCheck()
3138 m_client->cancelPolicyCheck();
3139 m_policyCheck.clear();
3142 void FrameLoader::didReceiveServerRedirectForProvisionalLoadForFrame()
3144 m_client->dispatchDidReceiveServerRedirectForProvisionalLoad();
3147 void FrameLoader::finishedLoadingDocument(DocumentLoader* loader)
3149 // FIXME: Platforms shouldn't differ here!
3150 #if PLATFORM(WIN) || PLATFORM(CHROMIUM)
3151 if (m_creatingInitialEmptyDocument)
3155 // If loading a webarchive, run through webarchive machinery
3156 const String& responseMIMEType = loader->responseMIMEType();
3158 // FIXME: Mac's FrameLoaderClient::finishedLoading() method does work that is required even with Archive loads
3159 // so we still need to call it. Other platforms should only call finishLoading for non-archive loads
3160 // That work should be factored out so this #ifdef can be removed
3162 m_client->finishedLoading(loader);
3163 if (!ArchiveFactory::isArchiveMimeType(responseMIMEType))
3166 if (!ArchiveFactory::isArchiveMimeType(responseMIMEType)) {
3167 m_client->finishedLoading(loader);
3172 RefPtr<Archive> archive(ArchiveFactory::create(loader->mainResourceData().get(), responseMIMEType));
3176 loader->addAllArchiveResources(archive.get());
3178 ArchiveResource* mainResource = archive->mainResource();
3179 loader->setParsedArchiveData(mainResource->data());
3180 continueLoadWithData(mainResource->data(), mainResource->mimeType(), mainResource->textEncoding(), mainResource->url());
3183 bool FrameLoader::isReplacing() const
3185 return m_loadType == FrameLoadTypeReplace;
3188 void FrameLoader::setReplacing()
3190 m_loadType = FrameLoadTypeReplace;
3193 void FrameLoader::revertToProvisional(DocumentLoader* loader)
3195 m_client->revertToProvisionalState(loader);
3198 bool FrameLoader::subframeIsLoading() const
3200 // It's most likely that the last added frame is the last to load so we walk backwards.
3201 for (Frame* child = m_frame->tree()->lastChild(); child; child = child->tree()->previousSibling()) {
3202 FrameLoader* childLoader = child->loader();
3203 DocumentLoader* documentLoader = childLoader->documentLoader();
3204 if (documentLoader && documentLoader->isLoadingInAPISense())
3206 documentLoader = childLoader->provisionalDocumentLoader();
3207 if (documentLoader && documentLoader->isLoadingInAPISense())
3213 void FrameLoader::willChangeTitle(DocumentLoader* loader)
3215 m_client->willChangeTitle(loader);
3218 FrameLoadType FrameLoader::loadType() const
3223 CachePolicy FrameLoader::cachePolicy() const
3226 return CachePolicyVerify;
3228 if (m_loadType == FrameLoadTypeReloadFromOrigin || documentLoader()->request().cachePolicy() == ReloadIgnoringCacheData)
3229 return CachePolicyReload;
3231 if (Frame* parentFrame = m_frame->tree()->parent()) {
3232 CachePolicy parentCachePolicy = parentFrame->loader()->cachePolicy();
3233 if (parentCachePolicy != CachePolicyVerify)
3234 return parentCachePolicy;
3237 if (m_loadType == FrameLoadTypeReload)
3238 return CachePolicyRevalidate;
3240 return CachePolicyVerify;
3243 void FrameLoader::stopPolicyCheck()
3245 m_client->cancelPolicyCheck();
3246 PolicyCheck check = m_policyCheck;
3247 m_policyCheck.clear();
3251 void FrameLoader::checkLoadCompleteForThisFrame()
3253 ASSERT(m_client->hasWebView());
3256 case FrameStateProvisional: {
3257 if (m_delegateIsHandlingProvisionalLoadError)
3260 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
3264 // If we've received any errors we may be stuck in the provisional state and actually complete.
3265 const ResourceError& error = pdl->mainDocumentError();
3269 // Check all children first.
3270 RefPtr<HistoryItem> item;
3271 if (Page* page = m_frame->page())
3272 if (isBackForwardLoadType(loadType()) && m_frame == page->mainFrame())
3273 item = m_currentHistoryItem;
3275 bool shouldReset = true;
3276 if (!pdl->isLoadingInAPISense()) {
3277 m_delegateIsHandlingProvisionalLoadError = true;
3278 m_client->dispatchDidFailProvisionalLoad(error);
3279 m_delegateIsHandlingProvisionalLoadError = false;
3281 // FIXME: can stopping loading here possibly have any effect, if isLoading is false,
3282 // which it must be to be in this branch of the if? And is it OK to just do a full-on
3283 // stopAllLoaders instead of stopLoadingSubframes?
3284 stopLoadingSubframes();
3287 // Finish resetting the load state, but only if another load hasn't been started by the
3288 // delegate callback.
3289 if (pdl == m_provisionalDocumentLoader)
3290 clearProvisionalLoad();
3291 else if (m_provisionalDocumentLoader) {
3292 KURL unreachableURL = m_provisionalDocumentLoader->unreachableURL();
3293 if (!unreachableURL.isEmpty() && unreachableURL == pdl->request().url())
3294 shouldReset = false;
3297 if (shouldReset && item)
3298 if (Page* page = m_frame->page()) {
3299 page->backForwardList()->goToItem(item.get());
3300 Settings* settings = m_frame->settings();
3301 page->setGlobalHistoryItem((!settings || settings->privateBrowsingEnabled()) ? 0 : item.get());
3306 case FrameStateCommittedPage: {
3307 DocumentLoader* dl = m_documentLoader.get();
3308 if (!dl || dl->isLoadingInAPISense())
3313 // FIXME: Is this subsequent work important if we already navigated away?
3314 // Maybe there are bugs because of that, or extra work we can skip because
3315 // the new page is ready.
3317 m_client->forceLayoutForNonHTML();
3319 // If the user had a scroll point, scroll to it, overriding the anchor point if any.
3320 if (Page* page = m_frame->page())
3321 if ((isBackForwardLoadType(m_loadType) || m_loadType == FrameLoadTypeReload || m_loadType == FrameLoadTypeReloadFromOrigin) && page->backForwardList())
3322 restoreScrollPositionAndViewState();
3324 if (m_creatingInitialEmptyDocument || !m_committedFirstRealDocumentLoad)
3327 const ResourceError& error = dl->mainDocumentError();
3329 m_didDispatchDidCommitLoad = false;
3331 if (!error.isNull())
3332 m_client->dispatchDidFailLoad(error);
3334 m_client->dispatchDidFinishLoad();
3336 if (Page* page = m_frame->page())
3337 page->progress()->progressCompleted(m_frame);
3341 case FrameStateComplete:
3342 frameLoadCompleted();
3346 ASSERT_NOT_REACHED();
3349 void FrameLoader::continueAfterContentPolicy(PolicyAction policy)
3351 PolicyCheck check = m_policyCheck;
3352 m_policyCheck.clear();
3356 void FrameLoader::continueLoadAfterWillSubmitForm(PolicyAction)
3358 if (!m_provisionalDocumentLoader)
3361 // DocumentLoader calls back to our prepareForLoadStart
3362 m_provisionalDocumentLoader->prepareForLoadStart();
3364 // The load might be cancelled inside of prepareForLoadStart(), nulling out the m_provisionalDocumentLoader,
3365 // so we need to null check it again.
3366 if (!m_provisionalDocumentLoader)
3369 DocumentLoader* activeDocLoader = activeDocumentLoader();
3370 if (activeDocLoader && activeDocLoader->isLoadingMainResource())
3373 m_provisionalDocumentLoader->setLoadingFromCachedPage(false);
3375 unsigned long identifier = 0;
3377 if (Page* page = m_frame->page()) {
3378 identifier = page->progress()->createUniqueIdentifier();
3379 dispatchAssignIdentifierToInitialRequest(identifier, m_provisionalDocumentLoader.get(), m_provisionalDocumentLoader->originalRequest());
3382 if (!m_provisionalDocumentLoader->startLoadingMainResource(identifier))
3383 m_provisionalDocumentLoader->updateLoading();
3386 void FrameLoader::didFirstLayout()
3388 if (Page* page = m_frame->page())
3389 if (isBackForwardLoadType(m_loadType) && page->backForwardList())
3390 restoreScrollPositionAndViewState();
3392 m_firstLayoutDone = true;
3393 m_client->dispatchDidFirstLayout();
3396 void FrameLoader::didFirstVisuallyNonEmptyLayout()
3398 m_client->dispatchDidFirstVisuallyNonEmptyLayout();
3401 void FrameLoader::frameLoadCompleted()
3403 // Note: Can be called multiple times.
3405 m_client->frameLoadCompleted();
3407 // Even if already complete, we might have set a previous item on a frame that
3408 // didn't do any data loading on the past transaction. Make sure to clear these out.
3409 m_previousHistoryItem = 0;
3411 // After a canceled provisional load, firstLayoutDone is false.
3412 // Reset it to true if we're displaying a page.
3413 if (m_documentLoader)
3414 m_firstLayoutDone = true;
3417 bool FrameLoader::firstLayoutDone() const
3419 return m_firstLayoutDone;
3422 bool FrameLoader::isQuickRedirectComing() const
3424 return m_quickRedirectComing;
3427 void FrameLoader::detachChildren()
3429 // FIXME: Is it really necessary to do this in reverse order?
3431 for (Frame* child = m_frame->tree()->lastChild(); child; child = previous) {
3432 previous = child->tree()->previousSibling();
3433 child->loader()->detachFromParent();
3437 void FrameLoader::closeAndRemoveChild(Frame* child)
3439 child->tree()->detachFromParent();
3442 if (child->ownerElement())
3443 child->page()->decrementFrameCount();
3444 child->pageDestroyed();
3446 m_frame->tree()->removeChild(child);
3449 void FrameLoader::recursiveCheckLoadComplete()
3451 Vector<RefPtr<Frame>, 10> frames;
3453 for (RefPtr<Frame> frame = m_frame->tree()->firstChild(); frame; frame = frame->tree()->nextSibling())
3454 frames.append(frame);
3456 unsigned size = frames.size();
3457 for (unsigned i = 0; i < size; i++)
3458 frames[i]->loader()->recursiveCheckLoadComplete();
3460 checkLoadCompleteForThisFrame();
3463 // Called every time a resource is completely loaded, or an error is received.
3464 void FrameLoader::checkLoadComplete()
3466 ASSERT(m_client->hasWebView());
3468 // FIXME: Always traversing the entire frame tree is a bit inefficient, but
3469 // is currently needed in order to null out the previous history item for all frames.
3470 if (Page* page = m_frame->page())
3471 page->mainFrame()->loader()->recursiveCheckLoadComplete();
3474 int FrameLoader::numPendingOrLoadingRequests(bool recurse) const
3477 return numRequests(m_frame->document());
3480 for (Frame* frame = m_frame; frame; frame = frame->tree()->traverseNext(m_frame))
3481 count += numRequests(frame->document());
3485 void FrameLoader::submitForm(const FrameLoadRequest& request, Event* event, bool lockHistory, bool lockBackForwardList)
3487 // FIXME: We'd like to remove this altogether and fix the multiple form submission issue another way.
3488 // We do not want to submit more than one form from the same page,
3489 // nor do we want to submit a single form more than once.
3490 // This flag prevents these from happening; not sure how other browsers prevent this.
3491 // The flag is reset in each time we start handle a new mouse or key down event, and
3492 // also in setView since this part may get reused for a page from the back/forward cache.
3493 // The form multi-submit logic here is only needed when we are submitting a form that affects this frame.
3494 // FIXME: Frame targeting is only one of the ways the submission could end up doing something other
3495 // than replacing this frame's content, so this check is flawed. On the other hand, the check is hardly
3496 // needed any more now that we reset m_submittedFormURL on each mouse or key down event.
3497 Frame* target = m_frame->tree()->find(request.frameName());
3498 if (m_frame->tree()->isDescendantOf(target)) {
3499 if (m_submittedFormURL == request.resourceRequest().url())
3501 m_submittedFormURL = request.resourceRequest().url();
3504 loadFrameRequestWithFormAndValues(request, lockHistory, lockBackForwardList, event, m_formAboutToBeSubmitted.get(), m_formValuesAboutToBeSubmitted);
3506 clearRecordedFormValues();
3509 String FrameLoader::userAgent(const KURL& url) const
3511 return m_client->userAgent(url);
3514 void FrameLoader::tokenizerProcessedData()
3516 // ASSERT(m_frame->page());
3517 // ASSERT(m_frame->document());
3522 void FrameLoader::handledOnloadEvents()
3524 m_client->dispatchDidHandleOnloadEvents();
3527 void FrameLoader::frameDetached()
3530 m_frame->document()->stopActiveDOMObjects();
3534 void FrameLoader::detachFromParent()
3536 RefPtr<Frame> protect(m_frame);
3540 saveScrollPositionAndViewStateToItem(currentHistoryItem());
3543 if (Page* page = m_frame->page())
3544 page->inspectorController()->frameDetachedFromParent(m_frame);
3546 m_client->detachedFromParent2();
3547 setDocumentLoader(0);
3548 m_client->detachedFromParent3();
3549 if (Frame* parent = m_frame->tree()->parent()) {
3550 parent->loader()->closeAndRemoveChild(m_frame);
3551 parent->loader()->scheduleCheckCompleted();
3553 m_frame->setView(0);
3554 m_frame->pageDestroyed();
3558 void FrameLoader::addExtraFieldsToSubresourceRequest(ResourceRequest& request)
3560 addExtraFieldsToRequest(request, m_loadType, false, false);
3563 void FrameLoader::addExtraFieldsToMainResourceRequest(ResourceRequest& request)
3565 addExtraFieldsToRequest(request, m_loadType, true, false);
3568 void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, FrameLoadType loadType, bool mainResource, bool cookiePolicyURLFromRequest)
3570 // Don't set the cookie policy URL if it's already been set.
3571 // But make sure to set it on all requests, as it has significance beyond the cookie policy for all protocols (<rdar://problem/6616664>).
3572 if (request.mainDocumentURL().isEmpty()) {
3573 if (mainResource && (isLoadingMainFrame() || cookiePolicyURLFromRequest))
3574 request.setMainDocumentURL(request.url());
3575 else if (Page* page = m_frame->page())
3576 request.setMainDocumentURL(page->mainFrame()->loader()->url());
3579 // The remaining modifications are only necessary for HTTP and HTTPS.
3580 if (!request.url().isEmpty() && !request.url().protocolInHTTPFamily())
3583 applyUserAgent(request);
3585 if (loadType == FrameLoadTypeReload) {
3586 request.setCachePolicy(ReloadIgnoringCacheData);
3587 request.setHTTPHeaderField("Cache-Control", "max-age=0");
3588 } else if (loadType == FrameLoadTypeReloadFromOrigin) {
3589 request.setCachePolicy(ReloadIgnoringCacheData);
3590 request.setHTTPHeaderField("Cache-Control", "no-cache");
3591 request.setHTTPHeaderField("Pragma", "no-cache");
3595 request.setHTTPAccept("application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5");
3597 // Make sure we send the Origin header.
3598 addHTTPOriginIfNeeded(request, String());