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 FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client)
259 , m_state(FrameStateCommittedPage)
260 , m_loadType(FrameLoadTypeStandard)
261 , m_policyLoadType(FrameLoadTypeStandard)
262 , m_delegateIsHandlingProvisionalLoadError(false)
263 , m_delegateIsDecidingNavigationPolicy(false)
264 , m_delegateIsHandlingUnimplementablePolicy(false)
265 , m_firstLayoutDone(false)
266 , m_quickRedirectComing(false)
267 , m_sentRedirectNotification(false)
268 , m_inStopAllLoaders(false)
269 , m_navigationDuringLoad(false)
270 , m_isExecutingJavaScriptFormAction(false)
271 , m_isRunningScript(false)
272 , m_didCallImplicitClose(false)
273 , m_wasUnloadEventEmitted(false)
274 , m_isComplete(false)
275 , m_isLoadingMainResource(false)
276 , m_cancellingWithLoadInProgress(false)
277 , m_needsClear(false)
278 , m_receivedData(false)
279 , m_encodingWasChosenByUser(false)
280 , m_containsPlugIns(false)
281 , m_redirectionTimer(this, &FrameLoader::redirectionTimerFired)
282 , m_checkCompletedTimer(this, &FrameLoader::checkCompletedTimerFired)
283 , m_checkLoadCompleteTimer(this, &FrameLoader::checkLoadCompleteTimerFired)
285 , m_openedByDOM(false)
286 , m_creatingInitialEmptyDocument(false)
287 , m_isDisplayingInitialEmptyDocument(false)
288 , m_committedFirstRealDocumentLoad(false)
289 , m_didPerformFirstNavigation(false)
291 , m_didDispatchDidCommitLoad(false)
294 , m_forceReloadWmlDeck(false)
299 FrameLoader::~FrameLoader()
303 HashSet<Frame*>::iterator end = m_openedFrames.end();
304 for (HashSet<Frame*>::iterator it = m_openedFrames.begin(); it != end; ++it)
305 (*it)->loader()->m_opener = 0;
307 m_client->frameLoaderDestroyed();
310 void FrameLoader::init()
312 // this somewhat odd set of steps is needed to give the frame an initial empty document
313 m_isDisplayingInitialEmptyDocument = false;
314 m_creatingInitialEmptyDocument = true;
315 setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(KURL("")), SubstituteData()).get());
316 setProvisionalDocumentLoader(m_policyDocumentLoader.get());
317 setState(FrameStateProvisional);
318 m_provisionalDocumentLoader->setResponse(ResourceResponse(KURL(), "text/html", 0, String(), String()));
319 m_provisionalDocumentLoader->finishedLoading();
320 begin(KURL(), false);
322 m_frame->document()->cancelParsing();
323 m_creatingInitialEmptyDocument = false;
324 m_didCallImplicitClose = true;
327 void FrameLoader::setDefersLoading(bool defers)
329 if (m_documentLoader)
330 m_documentLoader->setDefersLoading(defers);
331 if (m_provisionalDocumentLoader)
332 m_provisionalDocumentLoader->setDefersLoading(defers);
333 if (m_policyDocumentLoader)
334 m_policyDocumentLoader->setDefersLoading(defers);
337 Frame* FrameLoader::createWindow(FrameLoader* frameLoaderForFrameLookup, const FrameLoadRequest& request, const WindowFeatures& features, bool& created)
339 ASSERT(!features.dialog || request.frameName().isEmpty());
341 if (!request.frameName().isEmpty() && request.frameName() != "_blank") {
342 Frame* frame = frameLoaderForFrameLookup->frame()->tree()->find(request.frameName());
343 if (frame && shouldAllowNavigation(frame)) {
344 if (!request.resourceRequest().url().isEmpty())
345 frame->loader()->loadFrameRequestWithFormAndValues(request, false, false, 0, 0, HashMap<String, String>());
346 if (Page* page = frame->page())
347 page->chrome()->focus();
353 // FIXME: Setting the referrer should be the caller's responsibility.
354 FrameLoadRequest requestWithReferrer = request;
355 requestWithReferrer.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
356 addHTTPOriginIfNeeded(requestWithReferrer.resourceRequest(), outgoingOrigin());
358 Page* oldPage = m_frame->page();
362 Page* page = oldPage->chrome()->createWindow(m_frame, requestWithReferrer, features);
366 Frame* frame = page->mainFrame();
367 if (request.frameName() != "_blank")
368 frame->tree()->setName(request.frameName());
370 page->chrome()->setToolbarsVisible(features.toolBarVisible || features.locationBarVisible);
371 page->chrome()->setStatusbarVisible(features.statusBarVisible);
372 page->chrome()->setScrollbarsVisible(features.scrollbarsVisible);
373 page->chrome()->setMenubarVisible(features.menuBarVisible);
374 page->chrome()->setResizable(features.resizable);
376 // 'x' and 'y' specify the location of the window, while 'width' and 'height'
377 // specify the size of the page. We can only resize the window, so
378 // adjust for the difference between the window size and the page size.
380 FloatRect windowRect = page->chrome()->windowRect();
381 FloatSize pageSize = page->chrome()->pageRect().size();
383 windowRect.setX(features.x);
385 windowRect.setY(features.y);
386 if (features.widthSet)
387 windowRect.setWidth(features.width + (windowRect.width() - pageSize.width()));
388 if (features.heightSet)
389 windowRect.setHeight(features.height + (windowRect.height() - pageSize.height()));
390 page->chrome()->setWindowRect(windowRect);
392 page->chrome()->show();
398 bool FrameLoader::canHandleRequest(const ResourceRequest& request)
400 return m_client->canHandleRequest(request);
403 void FrameLoader::changeLocation(const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool userGesture, bool refresh)
405 changeLocation(completeURL(url), referrer, lockHistory, lockBackForwardList, userGesture, refresh);
408 void FrameLoader::changeLocation(const KURL& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool userGesture, bool refresh)
410 RefPtr<Frame> protect(m_frame);
412 ResourceRequest request(url, referrer, refresh ? ReloadIgnoringCacheData : UseProtocolCachePolicy);
414 if (executeIfJavaScriptURL(request.url(), userGesture))
417 urlSelected(request, "_self", 0, lockHistory, lockBackForwardList, userGesture);
420 void FrameLoader::urlSelected(const FrameLoadRequest& request, Event* event, bool lockHistory, bool lockBackForwardList)
422 FrameLoadRequest copy = request;
423 if (copy.resourceRequest().httpReferrer().isEmpty())
424 copy.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
425 addHTTPOriginIfNeeded(copy.resourceRequest(), outgoingOrigin());
427 loadFrameRequestWithFormAndValues(copy, lockHistory, lockBackForwardList, event, 0, HashMap<String, String>());
430 void FrameLoader::urlSelected(const ResourceRequest& request, const String& _target, Event* triggeringEvent, bool lockHistory, bool lockBackForwardList, bool userGesture)
432 if (executeIfJavaScriptURL(request.url(), userGesture, false))
435 String target = _target;
436 if (target.isEmpty())
437 target = m_frame->document()->baseTarget();
439 FrameLoadRequest frameRequest(request, target);
441 urlSelected(frameRequest, triggeringEvent, lockHistory, lockBackForwardList);
444 bool FrameLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String& urlString, const AtomicString& frameName)
446 // Support for <frame src="javascript:string">
449 if (protocolIs(urlString, "javascript")) {
450 scriptURL = completeURL(urlString); // completeURL() encodes the URL.
453 url = completeURL(urlString);
455 Frame* frame = ownerElement->contentFrame();
457 frame->loader()->scheduleLocationChange(url.string(), m_outgoingReferrer, true, true, userGestureHint());
459 frame = loadSubframe(ownerElement, url, frameName, m_outgoingReferrer);
464 if (!scriptURL.isEmpty())
465 frame->loader()->executeIfJavaScriptURL(scriptURL);
470 Frame* FrameLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const String& name, const String& referrer)
472 bool allowsScrolling = true;
473 int marginWidth = -1;
474 int marginHeight = -1;
475 if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag)) {
476 HTMLFrameElementBase* o = static_cast<HTMLFrameElementBase*>(ownerElement);
477 allowsScrolling = o->scrollingMode() != ScrollbarAlwaysOff;
478 marginWidth = o->getMarginWidth();
479 marginHeight = o->getMarginHeight();
482 if (!canLoad(url, referrer)) {
483 FrameLoader::reportLocalLoadFailed(m_frame, url.string());
487 bool hideReferrer = shouldHideReferrer(url, referrer);
488 RefPtr<Frame> frame = m_client->createFrame(url, name, ownerElement, hideReferrer ? String() : referrer,
489 allowsScrolling, marginWidth, marginHeight);
492 checkCallImplicitClose();
496 frame->loader()->m_isComplete = false;
498 RenderObject* renderer = ownerElement->renderer();
499 FrameView* view = frame->view();
500 if (renderer && renderer->isWidget() && view)
501 static_cast<RenderWidget*>(renderer)->setWidget(view);
503 checkCallImplicitClose();
505 // In these cases, the synchronous load would have finished
506 // before we could connect the signals, so make sure to send the
507 // completed() signal for the child by hand
508 // FIXME: In this case the Frame will have finished loading before
509 // it's being added to the child list. It would be a good idea to
510 // create the child first, then invoke the loader separately.
511 if (url.isEmpty() || url == blankURL()) {
512 frame->loader()->completed();
513 frame->loader()->checkCompleted();
519 void FrameLoader::submitFormAgain()
521 if (m_isRunningScript)
523 OwnPtr<FormSubmission> form(m_deferredFormSubmission.release());
526 submitForm(form->action, form->url, form->formData, form->target, form->contentType, form->boundary, form->event.get(), form->lockHistory, form->lockBackForwardList);
529 void FrameLoader::submitForm(const char* action, const String& url, PassRefPtr<FormData> formData,
530 const String& target, const String& contentType, const String& boundary, Event* event, bool lockHistory, bool lockBackForwardList)
534 if (!m_frame->page())
537 KURL u = completeURL(url.isNull() ? "" : url);
538 // FIXME: Do we really need to special-case an empty URL?
539 // Would it be better to just go on with the form submisson and let the I/O fail?
543 if (u.protocolIs("javascript")) {
544 m_isExecutingJavaScriptFormAction = true;
545 executeIfJavaScriptURL(u, false, false);
546 m_isExecutingJavaScriptFormAction = false;
550 if (m_isRunningScript) {
551 if (m_deferredFormSubmission)
553 m_deferredFormSubmission.set(new FormSubmission(action, url, formData, target, contentType, boundary, event, lockHistory, lockBackForwardList));
557 formData->generateFiles(m_frame->page()->chrome()->client());
559 FrameLoadRequest frameRequest;
561 if (!m_outgoingReferrer.isEmpty())
562 frameRequest.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
564 frameRequest.setFrameName(target.isEmpty() ? m_frame->document()->baseTarget() : target);
566 // Handle mailto: forms
567 bool isMailtoForm = equalIgnoringCase(u.protocol(), "mailto");
568 if (isMailtoForm && strcmp(action, "GET") != 0) {
569 // Append body= for POST mailto, replace the whole query string for GET one.
570 String body = formData->flattenToString();
571 String query = u.query();
572 if (!query.isEmpty())
574 u.setQuery(query + body);
577 if (strcmp(action, "GET") == 0) {
578 u.setQuery(formData->flattenToString());
581 frameRequest.resourceRequest().setHTTPBody(formData.get());
582 frameRequest.resourceRequest().setHTTPMethod("POST");
584 // construct some user headers if necessary
585 if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
586 frameRequest.resourceRequest().setHTTPContentType(contentType);
587 else // contentType must be "multipart/form-data"
588 frameRequest.resourceRequest().setHTTPContentType(contentType + "; boundary=" + boundary);
591 frameRequest.resourceRequest().setURL(u);
592 addHTTPOriginIfNeeded(frameRequest.resourceRequest(), outgoingOrigin());
594 submitForm(frameRequest, event, lockHistory, lockBackForwardList);
597 void FrameLoader::stopLoading(bool sendUnload)
599 if (m_frame->document() && m_frame->document()->tokenizer())
600 m_frame->document()->tokenizer()->stopParsing();
603 if (m_frame->document()) {
604 if (m_didCallImplicitClose && !m_wasUnloadEventEmitted) {
605 Node* currentFocusedNode = m_frame->document()->focusedNode();
606 if (currentFocusedNode)
607 currentFocusedNode->aboutToUnload();
608 m_frame->document()->dispatchWindowEvent(eventNames().unloadEvent, false, false);
609 if (m_frame->document())
610 m_frame->document()->updateRendering();
611 m_wasUnloadEventEmitted = true;
612 if (m_frame->eventHandler()->pendingFrameUnloadEventCount())
613 m_frame->eventHandler()->clearPendingFrameUnloadEventCount();
614 if (m_frame->eventHandler()->pendingFrameBeforeUnloadEventCount())
615 m_frame->eventHandler()->clearPendingFrameBeforeUnloadEventCount();
618 if (m_frame->document() && !m_frame->document()->inPageCache())
619 m_frame->document()->removeAllEventListenersFromAllNodes();
622 m_isComplete = true; // to avoid calling completed() in finishedParsing() (David)
623 m_isLoadingMainResource = false;
624 m_didCallImplicitClose = true; // don't want that one either
626 if (m_frame->document() && m_frame->document()->parsing()) {
628 m_frame->document()->setParsing(false);
631 m_workingURL = KURL();
633 if (Document* doc = m_frame->document()) {
634 if (DocLoader* docLoader = doc->docLoader())
635 cache()->loader()->cancelRequests(docLoader);
638 doc->stopDatabases();
642 // tell all subframes to stop as well
643 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
644 child->loader()->stopLoading(sendUnload);
649 void FrameLoader::stop()
651 // http://bugs.webkit.org/show_bug.cgi?id=10854
652 // The frame's last ref may be removed and it will be deleted by checkCompleted().
653 RefPtr<Frame> protector(m_frame);
655 if (m_frame->document()->tokenizer())
656 m_frame->document()->tokenizer()->stopParsing();
657 m_frame->document()->finishParsing();
660 m_iconLoader->stopLoading();
663 bool FrameLoader::closeURL()
667 m_frame->editor()->clearUndoRedoOperations();
671 void FrameLoader::cancelRedirection(bool cancelWithLoadInProgress)
673 m_cancellingWithLoadInProgress = cancelWithLoadInProgress;
675 stopRedirectionTimer();
677 m_scheduledRedirection.clear();
680 KURL FrameLoader::iconURL()
682 // If this isn't a top level frame, return nothing
683 if (m_frame->tree() && m_frame->tree()->parent())
686 // If we have an iconURL from a Link element, return that
687 if (!m_frame->document()->iconURL().isEmpty())
688 return KURL(m_frame->document()->iconURL());
690 // Don't return a favicon iconURL unless we're http or https
691 if (!m_URL.protocolIs("http") && !m_URL.protocolIs("https"))
695 url.setProtocol(m_URL.protocol());
696 url.setHost(m_URL.host());
697 if (int port = m_URL.port())
699 url.setPath("/favicon.ico");
703 bool FrameLoader::didOpenURL(const KURL& url)
705 if (m_scheduledRedirection && m_scheduledRedirection->type == ScheduledRedirection::locationChangeDuringLoad)
706 // A redirect was scheduled before the document was created.
707 // This can happen when one frame changes another frame's location.
711 m_frame->editor()->clearLastEditCommand();
714 m_isComplete = false;
715 m_isLoadingMainResource = true;
716 m_didCallImplicitClose = false;
718 m_frame->setJSStatusBarText(String());
719 m_frame->setJSDefaultStatusBarText(String());
722 if ((m_URL.protocolIs("http") || m_URL.protocolIs("https")) && !m_URL.host().isEmpty() && m_URL.path().isEmpty())
724 m_workingURL = m_URL;
731 void FrameLoader::didExplicitOpen()
733 m_isComplete = false;
734 m_didCallImplicitClose = false;
736 // Calling document.open counts as committing the first real document load.
737 m_committedFirstRealDocumentLoad = true;
739 // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
740 // from a subsequent window.document.open / window.document.write call.
741 // Cancelling redirection here works for all cases because document.open
742 // implicitly precedes document.write.
744 if (m_frame->document()->url() != blankURL())
745 m_URL = m_frame->document()->url();
748 bool FrameLoader::executeIfJavaScriptURL(const KURL& url, bool userGesture, bool replaceDocument)
750 if (!url.protocolIs("javascript"))
753 if (m_frame->page() && !m_frame->page()->javaScriptURLsAreAllowed())
756 String script = decodeURLEscapeSequences(url.string().substring(strlen("javascript:")));
757 ScriptValue result = executeScript(script, userGesture);
760 if (!result.getString(scriptResult))
763 SecurityOrigin* currentSecurityOrigin = 0;
764 currentSecurityOrigin = m_frame->document()->securityOrigin();
766 // FIXME: We should always replace the document, but doing so
767 // synchronously can cause crashes:
768 // http://bugs.webkit.org/show_bug.cgi?id=16782
769 if (replaceDocument) {
771 begin(m_URL, true, currentSecurityOrigin);
779 ScriptValue FrameLoader::executeScript(const String& script, bool forceUserGesture)
781 return executeScript(ScriptSourceCode(script, forceUserGesture ? KURL() : m_URL));
784 ScriptValue FrameLoader::executeScript(const ScriptSourceCode& sourceCode)
786 if (!m_frame->script()->isEnabled() || m_frame->script()->isPaused())
787 return ScriptValue();
789 bool wasRunningScript = m_isRunningScript;
790 m_isRunningScript = true;
792 ScriptValue result = m_frame->script()->evaluate(sourceCode);
794 if (!wasRunningScript) {
795 m_isRunningScript = false;
797 Document::updateDocumentsRendering();
803 void FrameLoader::cancelAndClear()
811 m_frame->script()->updatePlatformScriptObjects();
814 void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects)
816 m_frame->editor()->clear();
820 m_needsClear = false;
822 if (!m_frame->document()->inPageCache()) {
823 m_frame->document()->cancelParsing();
824 m_frame->document()->stopActiveDOMObjects();
825 if (m_frame->document()->attached()) {
826 m_frame->document()->willRemove();
827 m_frame->document()->detach();
829 m_frame->document()->removeFocusedNodeOfSubtree(m_frame->document());
833 // Do this after detaching the document so that the unload event works.
834 if (clearWindowProperties) {
835 m_frame->clearDOMWindow();
836 m_frame->script()->clearWindowShell();
839 m_frame->selection()->clear();
840 m_frame->eventHandler()->clear();
842 m_frame->view()->clear();
844 m_frame->setSelectionGranularity(CharacterGranularity);
846 // Do not drop the document before the ScriptController and view are cleared
847 // as some destructors might still try to access the document.
848 m_frame->setDocument(0);
851 m_containsPlugIns = false;
853 if (clearScriptObjects)
854 m_frame->script()->clearScriptObjects();
856 m_redirectionTimer.stop();
857 m_scheduledRedirection.clear();
859 m_checkCompletedTimer.stop();
860 m_checkLoadCompleteTimer.stop();
862 m_receivedData = false;
863 m_isDisplayingInitialEmptyDocument = false;
865 if (!m_encodingWasChosenByUser)
866 m_encoding = String();
869 void FrameLoader::receivedFirstData()
871 begin(m_workingURL, false);
873 dispatchDidCommitLoad();
874 dispatchWindowObjectAvailable();
876 String ptitle = m_documentLoader->title();
877 // If we have a title let the WebView know about it.
878 if (!ptitle.isNull())
879 m_client->dispatchDidReceiveTitle(ptitle);
881 m_workingURL = KURL();
885 if (!m_documentLoader)
887 if (!parseHTTPRefresh(m_documentLoader->response().httpHeaderField("Refresh"), false, delay, url))
891 url = m_URL.string();
893 url = m_frame->document()->completeURL(url).string();
895 scheduleHTTPRedirection(delay, url);
898 const String& FrameLoader::responseMIMEType() const
900 return m_responseMIMEType;
903 void FrameLoader::setResponseMIMEType(const String& type)
905 m_responseMIMEType = type;
908 void FrameLoader::begin()
913 void FrameLoader::begin(const KURL& url, bool dispatch, SecurityOrigin* origin)
915 // We need to take a reference to the security origin because |clear|
916 // might destroy the document that owns it.
917 RefPtr<SecurityOrigin> forcedSecurityOrigin = origin;
919 RefPtr<Document> document;
921 // Create a new document before clearing the frame, because it may need to inherit an aliased security context.
922 if (!m_isDisplayingInitialEmptyDocument && m_client->shouldUsePluginDocument(m_responseMIMEType))
923 document = PluginDocument::create(m_frame);
925 document = DOMImplementation::createDocument(m_responseMIMEType, m_frame, m_frame->inViewSourceMode());
927 bool resetScripting = !(m_isDisplayingInitialEmptyDocument && m_frame->document()->securityOrigin()->isSecureTransitionTo(url));
928 clear(resetScripting, resetScripting);
930 m_frame->script()->updatePlatformScriptObjects();
933 m_isComplete = false;
934 m_didCallImplicitClose = false;
935 m_isLoadingMainResource = true;
936 m_isDisplayingInitialEmptyDocument = m_creatingInitialEmptyDocument;
939 ref.setUser(String());
940 ref.setPass(String());
941 ref.setRef(String());
942 m_outgoingReferrer = ref.string();
945 m_frame->setDocument(document);
948 dispatchWindowObjectAvailable();
950 document->setURL(m_URL);
952 document->setDecoder(m_decoder.get());
953 if (forcedSecurityOrigin)
954 document->setSecurityOrigin(forcedSecurityOrigin.get());
956 m_frame->domWindow()->setURL(document->url());
957 m_frame->domWindow()->setSecurityOrigin(document->securityOrigin());
959 updatePolicyBaseURL();
961 Settings* settings = document->settings();
962 document->docLoader()->setAutoLoadImages(settings && settings->loadsImagesAutomatically());
964 if (m_documentLoader) {
965 String dnsPrefetchControl = m_documentLoader->response().httpHeaderField("X-DNS-Prefetch-Control");
966 if (!dnsPrefetchControl.isEmpty())
967 document->parseDNSPrefetchControlHeader(dnsPrefetchControl);
970 #if FRAME_LOADS_USER_STYLESHEET
971 KURL userStyleSheet = settings ? settings->userStyleSheetLocation() : KURL();
972 if (!userStyleSheet.isEmpty())
973 m_frame->setUserStyleSheetLocation(userStyleSheet);
976 restoreDocumentState();
978 document->implicitOpen();
981 m_frame->view()->setContentsSize(IntSize());
984 void FrameLoader::write(const char* str, int len, bool flush)
986 if (len == 0 && !flush)
992 Tokenizer* tokenizer = m_frame->document()->tokenizer();
993 if (tokenizer && tokenizer->wantsRawData()) {
995 tokenizer->writeRawData(str, len);
1000 Settings* settings = m_frame->settings();
1001 m_decoder = TextResourceDecoder::create(m_responseMIMEType, settings ? settings->defaultTextEncodingName() : String());
1002 if (m_encoding.isEmpty()) {
1003 Frame* parentFrame = m_frame->tree()->parent();
1004 if (parentFrame && parentFrame->document()->securityOrigin()->canAccess(m_frame->document()->securityOrigin()))
1005 m_decoder->setEncoding(parentFrame->document()->inputEncoding(), TextResourceDecoder::DefaultEncoding);
1007 m_decoder->setEncoding(m_encoding,
1008 m_encodingWasChosenByUser ? TextResourceDecoder::UserChosenEncoding : TextResourceDecoder::EncodingFromHTTPHeader);
1010 m_frame->document()->setDecoder(m_decoder.get());
1013 String decoded = m_decoder->decode(str, len);
1015 decoded += m_decoder->flush();
1016 if (decoded.isEmpty())
1019 if (!m_receivedData) {
1020 m_receivedData = true;
1021 if (m_decoder->encoding().usesVisualOrdering())
1022 m_frame->document()->setVisuallyOrdered();
1023 m_frame->document()->recalcStyle(Node::Force);
1027 ASSERT(!tokenizer->wantsRawData());
1028 tokenizer->write(decoded, true);
1032 void FrameLoader::write(const String& str)
1037 if (!m_receivedData) {
1038 m_receivedData = true;
1039 m_frame->document()->setParseMode(Document::Strict);
1042 if (Tokenizer* tokenizer = m_frame->document()->tokenizer())
1043 tokenizer->write(str, true);
1046 void FrameLoader::end()
1048 m_isLoadingMainResource = false;
1049 endIfNotLoadingMainResource();
1052 void FrameLoader::endIfNotLoadingMainResource()
1054 if (m_isLoadingMainResource || !m_frame->page() || !m_frame->document())
1057 // http://bugs.webkit.org/show_bug.cgi?id=10854
1058 // The frame's last ref may be removed and it can be deleted by checkCompleted(),
1059 // so we'll add a protective refcount
1060 RefPtr<Frame> protector(m_frame);
1062 // make sure nothing's left in there
1064 m_frame->document()->finishParsing();
1067 void FrameLoader::iconLoadDecisionAvailable()
1069 if (!m_mayLoadIconLater)
1071 LOG(IconDatabase, "FrameLoader %p was told a load decision is available for its icon", this);
1073 m_mayLoadIconLater = false;
1076 void FrameLoader::startIconLoader()
1078 // FIXME: We kick off the icon loader when the frame is done receiving its main resource.
1079 // But we should instead do it when we're done parsing the head element.
1080 if (!isLoadingMainFrame())
1083 if (!iconDatabase() || !iconDatabase()->isEnabled())
1086 KURL url(iconURL());
1087 String urlString(url.string());
1088 if (urlString.isEmpty())
1091 // If we're not reloading and the icon database doesn't say to load now then bail before we actually start the load
1092 if (loadType() != FrameLoadTypeReload && loadType() != FrameLoadTypeReloadFromOrigin) {
1093 IconLoadDecision decision = iconDatabase()->loadDecisionForIconURL(urlString, m_documentLoader.get());
1094 if (decision == IconLoadNo) {
1095 LOG(IconDatabase, "FrameLoader::startIconLoader() - Told not to load this icon, committing iconURL %s to database for pageURL mapping", urlString.ascii().data());
1096 commitIconURLToIconDatabase(url);
1098 // We were told not to load this icon - that means this icon is already known by the database
1099 // 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
1100 // has done it. This is after registering for the notification so the WebView can call the appropriate delegate method.
1101 // Otherwise if the icon data *is* available, notify the delegate
1102 if (!iconDatabase()->iconDataKnownForIconURL(urlString)) {
1103 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());
1104 m_client->registerForIconNotification();
1105 iconDatabase()->iconForPageURL(m_URL.string(), IntSize(0, 0));
1106 iconDatabase()->iconForPageURL(originalRequestURL().string(), IntSize(0, 0));
1108 m_client->dispatchDidReceiveIcon();
1113 if (decision == IconLoadUnknown) {
1114 // In this case, we may end up loading the icon later, but we still want to commit the icon url mapping to the database
1115 // 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
1116 // We also tell the client to register for the notification that the icon is received now so it isn't missed in case the
1117 // icon is later read in from disk
1118 LOG(IconDatabase, "FrameLoader %p might load icon %s later", this, urlString.ascii().data());
1119 m_mayLoadIconLater = true;
1120 m_client->registerForIconNotification();
1121 commitIconURLToIconDatabase(url);
1126 // This is either a reload or the icon database said "yes, load the icon", so kick off the load!
1128 m_iconLoader.set(IconLoader::create(m_frame).release());
1130 m_iconLoader->startLoading();
1133 void FrameLoader::setLocalLoadPolicy(LocalLoadPolicy policy)
1135 localLoadPolicy = policy;
1138 bool FrameLoader::restrictAccessToLocal()
1140 return localLoadPolicy != FrameLoader::AllowLocalLoadsForAll;
1143 bool FrameLoader::allowSubstituteDataAccessToLocal()
1145 return localLoadPolicy != FrameLoader::AllowLocalLoadsForLocalOnly;
1148 void FrameLoader::commitIconURLToIconDatabase(const KURL& icon)
1150 ASSERT(iconDatabase());
1151 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());
1152 iconDatabase()->setIconURLForPageURL(icon.string(), m_URL.string());
1153 iconDatabase()->setIconURLForPageURL(icon.string(), originalRequestURL().string());
1156 void FrameLoader::restoreDocumentState()
1158 Document* doc = m_frame->document();
1160 HistoryItem* itemToRestore = 0;
1162 switch (loadType()) {
1163 case FrameLoadTypeReload:
1164 case FrameLoadTypeReloadFromOrigin:
1165 case FrameLoadTypeSame:
1166 case FrameLoadTypeReplace:
1168 case FrameLoadTypeBack:
1169 case FrameLoadTypeForward:
1170 case FrameLoadTypeIndexedBackForward:
1171 case FrameLoadTypeRedirectWithLockedBackForwardList:
1172 case FrameLoadTypeStandard:
1173 itemToRestore = m_currentHistoryItem.get();
1179 LOG(Loading, "WebCoreLoading %s: restoring form state from %p", m_frame->tree()->name().string().utf8().data(), itemToRestore);
1180 doc->setStateForNewFormElements(itemToRestore->documentState());
1183 void FrameLoader::gotoAnchor()
1185 // If our URL has no ref, then we have no place we need to jump to.
1186 // OTOH If CSS target was set previously, we want to set it to 0, recalc
1187 // and possibly repaint because :target pseudo class may have been
1188 // set (see bug 11321).
1189 if (!m_URL.hasRef() && !m_frame->document()->cssTarget())
1192 String ref = m_URL.ref();
1193 if (gotoAnchor(ref))
1196 // Try again after decoding the ref, based on the document's encoding.
1198 gotoAnchor(decodeURLEscapeSequences(ref, m_decoder->encoding()));
1201 void FrameLoader::finishedParsing()
1203 if (m_creatingInitialEmptyDocument)
1206 // This can be called from the Frame's destructor, in which case we shouldn't protect ourselves
1207 // because doing so will cause us to re-enter the destructor when protector goes out of scope.
1208 // Null-checking the FrameView indicates whether or not we're in the destructor.
1209 RefPtr<Frame> protector = m_frame->view() ? m_frame : 0;
1211 m_client->dispatchDidFinishDocumentLoad();
1215 if (!m_frame->view())
1216 return; // We are being destroyed by something checkCompleted called.
1218 // Check if the scrollbars are really needed for the content.
1219 // If not, remove them, relayout, and repaint.
1220 m_frame->view()->restoreScrollbar();
1225 void FrameLoader::loadDone()
1230 void FrameLoader::checkCompleted()
1232 if (m_frame->view())
1233 m_frame->view()->checkStopDelayingDeferredRepaints();
1235 // Any frame that hasn't completed yet?
1236 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1237 if (!child->loader()->m_isComplete)
1240 // Have we completed before?
1244 // Are we still parsing?
1245 if (m_frame->document()->parsing())
1248 // Still waiting for images/scripts?
1249 if (numRequests(m_frame->document()))
1253 m_isComplete = true;
1255 RefPtr<Frame> protect(m_frame);
1256 checkCallImplicitClose(); // if we didn't do it before
1258 // Do not start a redirection timer for subframes here.
1259 // That is deferred until the parent is completed.
1260 if (m_scheduledRedirection && !m_frame->tree()->parent())
1261 startRedirectionTimer();
1264 if (m_frame->page())
1265 checkLoadComplete();
1268 void FrameLoader::checkCompletedTimerFired(Timer<FrameLoader>*)
1273 void FrameLoader::scheduleCheckCompleted()
1275 if (!m_checkCompletedTimer.isActive())
1276 m_checkCompletedTimer.startOneShot(0);
1279 void FrameLoader::checkLoadCompleteTimerFired(Timer<FrameLoader>*)
1281 if (!m_frame->page())
1283 checkLoadComplete();
1286 void FrameLoader::scheduleCheckLoadComplete()
1288 if (!m_checkLoadCompleteTimer.isActive())
1289 m_checkLoadCompleteTimer.startOneShot(0);
1292 void FrameLoader::checkCallImplicitClose()
1294 if (m_didCallImplicitClose || m_frame->document()->parsing())
1297 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1298 if (!child->loader()->m_isComplete) // still got a frame running -> too early
1301 m_didCallImplicitClose = true;
1302 m_wasUnloadEventEmitted = false;
1303 m_frame->document()->implicitClose();
1306 KURL FrameLoader::baseURL() const
1308 ASSERT(m_frame->document());
1309 return m_frame->document()->baseURL();
1312 String FrameLoader::baseTarget() const
1314 ASSERT(m_frame->document());
1315 return m_frame->document()->baseTarget();
1318 KURL FrameLoader::completeURL(const String& url)
1320 ASSERT(m_frame->document());
1321 return m_frame->document()->completeURL(url);
1324 void FrameLoader::scheduleHTTPRedirection(double delay, const String& url)
1326 if (delay < 0 || delay > INT_MAX / 1000)
1329 if (!m_frame->page())
1335 // We want a new history item if the refresh timeout is > 1 second.
1336 if (!m_scheduledRedirection || delay <= m_scheduledRedirection->delay)
1337 scheduleRedirection(new ScheduledRedirection(delay, url, true, delay <= 1, false, false));
1340 void FrameLoader::scheduleLocationChange(const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool wasUserGesture)
1342 if (!m_frame->page())
1348 // If the URL we're going to navigate to is the same as the current one, except for the
1349 // fragment part, we don't need to schedule the location change.
1350 KURL parsedURL(url);
1351 if (parsedURL.hasRef() && equalIgnoringRef(m_URL, parsedURL)) {
1352 changeLocation(url, referrer, lockHistory, lockBackForwardList, wasUserGesture);
1356 // Handle a location change of a page with no document as a special case.
1357 // This may happen when a frame changes the location of another frame.
1358 bool duringLoad = !m_committedFirstRealDocumentLoad;
1360 // If a redirect was scheduled during a load, then stop the current load.
1361 // Otherwise when the current load transitions from a provisional to a
1362 // committed state, pending redirects may be cancelled.
1364 if (m_provisionalDocumentLoader)
1365 m_provisionalDocumentLoader->stopLoading();
1369 ScheduledRedirection::Type type = duringLoad
1370 ? ScheduledRedirection::locationChangeDuringLoad : ScheduledRedirection::locationChange;
1371 scheduleRedirection(new ScheduledRedirection(type, url, referrer, lockHistory, lockBackForwardList, wasUserGesture, false));
1374 void FrameLoader::scheduleRefresh(bool wasUserGesture)
1376 if (!m_frame->page())
1379 if (m_URL.isEmpty())
1382 ScheduledRedirection::Type type = ScheduledRedirection::locationChange;
1383 scheduleRedirection(new ScheduledRedirection(type, m_URL.string(), m_outgoingReferrer, true, true, wasUserGesture, true));
1386 bool FrameLoader::isLocationChange(const ScheduledRedirection& redirection)
1388 switch (redirection.type) {
1389 case ScheduledRedirection::redirection:
1391 case ScheduledRedirection::historyNavigation:
1392 case ScheduledRedirection::locationChange:
1393 case ScheduledRedirection::locationChangeDuringLoad:
1396 ASSERT_NOT_REACHED();
1400 void FrameLoader::scheduleHistoryNavigation(int steps)
1402 if (!m_frame->page())
1405 // navigation will always be allowed in the 0 steps case, which is OK because that's supposed to force a reload.
1406 if (!canGoBackOrForward(steps)) {
1407 cancelRedirection();
1411 // 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
1412 // (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),
1413 // then we don't need to schedule the navigation.
1415 KURL destination = historyURL(steps);
1416 // FIXME: This doesn't seem like a reliable way to tell whether or not the load will be a fragment load.
1417 if (equalIgnoringRef(m_URL, destination) && m_URL != destination) {
1418 goBackOrForward(steps);
1423 scheduleRedirection(new ScheduledRedirection(steps));
1426 void FrameLoader::goBackOrForward(int distance)
1431 Page* page = m_frame->page();
1434 BackForwardList* list = page->backForwardList();
1438 HistoryItem* item = list->itemAtIndex(distance);
1441 int forwardListCount = list->forwardListCount();
1442 if (forwardListCount > 0)
1443 item = list->itemAtIndex(forwardListCount);
1445 int backListCount = list->backListCount();
1446 if (backListCount > 0)
1447 item = list->itemAtIndex(-backListCount);
1451 ASSERT(item); // we should not reach this line with an empty back/forward list
1453 page->goToItem(item, FrameLoadTypeIndexedBackForward);
1456 void FrameLoader::redirectionTimerFired(Timer<FrameLoader>*)
1458 ASSERT(m_frame->page());
1460 OwnPtr<ScheduledRedirection> redirection(m_scheduledRedirection.release());
1462 switch (redirection->type) {
1463 case ScheduledRedirection::redirection:
1464 case ScheduledRedirection::locationChange:
1465 case ScheduledRedirection::locationChangeDuringLoad:
1466 changeLocation(redirection->url, redirection->referrer,
1467 redirection->lockHistory, redirection->lockBackForwardList, redirection->wasUserGesture, redirection->wasRefresh);
1469 case ScheduledRedirection::historyNavigation:
1470 if (redirection->historySteps == 0) {
1471 // Special case for go(0) from a frame -> reload only the frame
1472 urlSelected(m_URL, "", 0, redirection->lockHistory, redirection->lockBackForwardList, redirection->wasUserGesture);
1475 // go(i!=0) from a frame navigates into the history of the frame only,
1476 // in both IE and NS (but not in Mozilla). We can't easily do that.
1477 goBackOrForward(redirection->historySteps);
1481 ASSERT_NOT_REACHED();
1485 In the case of saving state about a page with frames, we store a tree of items that mirrors the frame tree.
1486 The item that was the target of the user's navigation is designated as the "targetItem".
1487 When this method is called with doClip=YES we're able to create the whole tree except for the target's children,
1488 which will be loaded in the future. That part of the tree will be filled out as the child loads are committed.
1490 void FrameLoader::loadURLIntoChildFrame(const KURL& url, const String& referer, Frame* childFrame)
1494 HistoryItem* parentItem = currentHistoryItem();
1495 FrameLoadType loadType = this->loadType();
1496 FrameLoadType childLoadType = FrameLoadTypeRedirectWithLockedBackForwardList;
1498 KURL workingURL = url;
1500 // If we're moving in the back/forward list, we might want to replace the content
1501 // of this child frame with whatever was there at that point.
1502 if (parentItem && parentItem->children().size() && isBackForwardLoadType(loadType)) {
1503 HistoryItem* childItem = parentItem->childItemWithName(childFrame->tree()->name());
1505 // Use the original URL to ensure we get all the side-effects, such as
1506 // onLoad handlers, of any redirects that happened. An example of where
1507 // this is needed is Radar 3213556.
1508 workingURL = KURL(childItem->originalURLString());
1509 childLoadType = loadType;
1510 childFrame->loader()->setProvisionalHistoryItem(childItem);
1514 RefPtr<Archive> subframeArchive = activeDocumentLoader()->popArchiveForSubframe(childFrame->tree()->name());
1516 if (subframeArchive)
1517 childFrame->loader()->loadArchive(subframeArchive.release());
1519 childFrame->loader()->loadURL(workingURL, referer, String(), false, childLoadType, 0, 0);
1522 void FrameLoader::loadArchive(PassRefPtr<Archive> prpArchive)
1524 RefPtr<Archive> archive = prpArchive;
1526 ArchiveResource* mainResource = archive->mainResource();
1527 ASSERT(mainResource);
1531 SubstituteData substituteData(mainResource->data(), mainResource->mimeType(), mainResource->textEncoding(), KURL());
1533 ResourceRequest request(mainResource->url());
1535 request.applyWebArchiveHackForMail();
1538 RefPtr<DocumentLoader> documentLoader = m_client->createDocumentLoader(request, substituteData);
1539 documentLoader->addAllArchiveResources(archive.get());
1540 load(documentLoader.get());
1543 String FrameLoader::encoding() const
1545 if (m_encodingWasChosenByUser && !m_encoding.isEmpty())
1547 if (m_decoder && m_decoder->encoding().isValid())
1548 return m_decoder->encoding().name();
1549 Settings* settings = m_frame->settings();
1550 return settings ? settings->defaultTextEncodingName() : String();
1553 bool FrameLoader::gotoAnchor(const String& name)
1555 ASSERT(m_frame->document());
1557 if (!m_frame->document()->haveStylesheetsLoaded()) {
1558 m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(true);
1562 m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(false);
1564 Element* anchorNode = m_frame->document()->findAnchor(name);
1567 if (m_frame->document()->isSVGDocument()) {
1568 if (name.startsWith("xpointer(")) {
1569 // We need to parse the xpointer reference here
1570 } else if (name.startsWith("svgView(")) {
1571 RefPtr<SVGSVGElement> svg = static_cast<SVGDocument*>(m_frame->document())->rootElement();
1572 if (!svg->currentView()->parseViewSpec(name))
1574 svg->setUseCurrentView(true);
1576 if (anchorNode && anchorNode->hasTagName(SVGNames::viewTag)) {
1577 RefPtr<SVGViewElement> viewElement = anchorNode->hasTagName(SVGNames::viewTag) ? static_cast<SVGViewElement*>(anchorNode) : 0;
1578 if (viewElement.get()) {
1579 RefPtr<SVGSVGElement> svg = static_cast<SVGSVGElement*>(SVGLocatable::nearestViewportElement(viewElement.get()));
1580 svg->inheritViewAttributes(viewElement.get());
1584 // FIXME: need to decide which <svg> to focus on, and zoom to that one
1585 // FIXME: need to actually "highlight" the viewTarget(s)
1589 m_frame->document()->setCSSTarget(anchorNode); // Setting to null will clear the current target.
1591 // Implement the rule that "" and "top" both mean top of page as in other browsers.
1592 if (!anchorNode && !(name.isEmpty() || equalIgnoringCase(name, "top")))
1595 // We need to update the layout before scrolling, otherwise we could
1596 // really mess things up if an anchor scroll comes at a bad moment.
1597 m_frame->document()->updateRendering();
1598 // Only do a layout if changes have occurred that make it necessary.
1599 if (m_frame->view() && m_frame->contentRenderer() && m_frame->contentRenderer()->needsLayout())
1600 m_frame->view()->layout();
1602 // Scroll nested layers and frames to reveal the anchor.
1603 // Align to the top and to the closest side (this matches other browsers).
1604 RenderObject* renderer;
1607 renderer = m_frame->document()->renderer(); // top of document
1609 renderer = anchorNode->renderer();
1610 rect = anchorNode->getRect();
1613 renderer->enclosingLayer()->scrollRectToVisible(rect, true, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
1618 bool FrameLoader::requestObject(RenderPart* renderer, const String& url, const AtomicString& frameName,
1619 const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues)
1621 if (url.isEmpty() && mimeType.isEmpty())
1626 completedURL = completeURL(url);
1629 if (shouldUsePlugin(completedURL, mimeType, renderer->hasFallbackContent(), useFallback)) {
1630 Settings* settings = m_frame->settings();
1631 if (!settings || !settings->arePluginsEnabled() ||
1632 (!settings->isJavaEnabled() && MIMETypeRegistry::isJavaAppletMIMEType(mimeType)))
1634 return loadPlugin(renderer, completedURL, mimeType, paramNames, paramValues, useFallback);
1637 ASSERT(renderer->node()->hasTagName(objectTag) || renderer->node()->hasTagName(embedTag));
1638 HTMLPlugInElement* element = static_cast<HTMLPlugInElement*>(renderer->node());
1640 // FIXME: OK to always make a new frame? When does the old frame get removed?
1641 return loadSubframe(element, completedURL, frameName, m_outgoingReferrer);
1644 bool FrameLoader::shouldUsePlugin(const KURL& url, const String& mimeType, bool hasFallback, bool& useFallback)
1646 if (m_client->shouldUsePluginDocument(mimeType)) {
1647 useFallback = false;
1651 // Allow other plug-ins to win over QuickTime because if the user has installed a plug-in that
1652 // can handle TIFF (which QuickTime can also handle) they probably intended to override QT.
1653 if (m_frame->page() && (mimeType == "image/tiff" || mimeType == "image/tif" || mimeType == "image/x-tiff")) {
1654 const PluginData* pluginData = m_frame->page()->pluginData();
1655 String pluginName = pluginData ? pluginData->pluginNameForMimeType(mimeType) : String();
1656 if (!pluginName.isEmpty() && !pluginName.contains("QuickTime", false))
1660 ObjectContentType objectType = m_client->objectContentType(url, mimeType);
1661 // If an object's content can't be handled and it has no fallback, let
1662 // it be handled as a plugin to show the broken plugin icon.
1663 useFallback = objectType == ObjectContentNone && hasFallback;
1664 return objectType == ObjectContentNone || objectType == ObjectContentNetscapePlugin || objectType == ObjectContentOtherPlugin;
1667 static HTMLPlugInElement* toPlugInElement(Node* node)
1672 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
1673 ASSERT(node->hasTagName(objectTag) || node->hasTagName(embedTag)
1674 || node->hasTagName(videoTag) || node->hasTagName(audioTag)
1675 || node->hasTagName(appletTag));
1677 ASSERT(node->hasTagName(objectTag) || node->hasTagName(embedTag)
1678 || node->hasTagName(appletTag));
1681 return static_cast<HTMLPlugInElement*>(node);
1684 bool FrameLoader::loadPlugin(RenderPart* renderer, const KURL& url, const String& mimeType,
1685 const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback)
1689 if (renderer && !useFallback) {
1690 HTMLPlugInElement* element = toPlugInElement(renderer->node());
1692 if (!canLoad(url, String(), frame()->document())) {
1693 FrameLoader::reportLocalLoadFailed(m_frame, url.string());
1697 widget = m_client->createPlugin(IntSize(renderer->contentWidth(), renderer->contentHeight()),
1698 element, url, paramNames, paramValues, mimeType,
1699 m_frame->document()->isPluginDocument());
1701 renderer->setWidget(widget);
1702 m_containsPlugIns = true;
1709 void FrameLoader::clearRecordedFormValues()
1711 m_formAboutToBeSubmitted = 0;
1712 m_formValuesAboutToBeSubmitted.clear();
1715 void FrameLoader::setFormAboutToBeSubmitted(PassRefPtr<HTMLFormElement> element)
1717 m_formAboutToBeSubmitted = element;
1720 void FrameLoader::recordFormValue(const String& name, const String& value)
1722 m_formValuesAboutToBeSubmitted.set(name, value);
1725 void FrameLoader::parentCompleted()
1727 if (m_scheduledRedirection && !m_redirectionTimer.isActive())
1728 startRedirectionTimer();
1731 String FrameLoader::outgoingReferrer() const
1733 return m_outgoingReferrer;
1736 String FrameLoader::outgoingOrigin() const
1738 return m_frame->document()->securityOrigin()->toString();
1741 Frame* FrameLoader::opener()
1746 void FrameLoader::setOpener(Frame* opener)
1749 m_opener->loader()->m_openedFrames.remove(m_frame);
1751 opener->loader()->m_openedFrames.add(m_frame);
1754 if (m_frame->document()) {
1755 m_frame->document()->initSecurityContext();
1756 m_frame->domWindow()->setSecurityOrigin(m_frame->document()->securityOrigin());
1760 bool FrameLoader::openedByDOM() const
1762 return m_openedByDOM;
1765 void FrameLoader::setOpenedByDOM()
1767 m_openedByDOM = true;
1770 void FrameLoader::handleFallbackContent()
1772 HTMLFrameOwnerElement* owner = m_frame->ownerElement();
1773 if (!owner || !owner->hasTagName(objectTag))
1775 static_cast<HTMLObjectElement*>(owner)->renderFallbackContent();
1778 void FrameLoader::provisionalLoadStarted()
1780 Page* page = m_frame->page();
1782 // this is used to update the current history item
1783 // in the event of a navigation aytime during loading
1784 m_navigationDuringLoad = false;
1786 Document *document = page->mainFrame()->document();
1787 m_navigationDuringLoad = !page->mainFrame()->loader()->isComplete() || (document && document->processingLoadEvent());
1790 m_firstLayoutDone = false;
1791 cancelRedirection(true);
1792 m_client->provisionalLoadStarted();
1795 bool FrameLoader::userGestureHint()
1797 Frame* frame = m_frame->tree()->top();
1798 if (!frame->script()->isEnabled())
1799 return true; // If JavaScript is disabled, a user gesture must have initiated the navigation.
1800 return frame->script()->processingUserGesture(); // FIXME: Use pageIsProcessingUserGesture.
1803 void FrameLoader::didNotOpenURL(const KURL& url)
1805 if (m_submittedFormURL == url)
1806 m_submittedFormURL = KURL();
1809 void FrameLoader::resetMultipleFormSubmissionProtection()
1811 m_submittedFormURL = KURL();
1814 void FrameLoader::setEncoding(const String& name, bool userChosen)
1816 if (!m_workingURL.isEmpty())
1817 receivedFirstData();
1819 m_encodingWasChosenByUser = userChosen;
1822 void FrameLoader::addData(const char* bytes, int length)
1824 ASSERT(m_workingURL.isEmpty());
1825 ASSERT(m_frame->document());
1826 ASSERT(m_frame->document()->parsing());
1827 write(bytes, length);
1830 bool FrameLoader::canCachePageContainingThisFrame()
1832 return m_documentLoader
1833 && m_documentLoader->mainDocumentError().isNull()
1834 && !m_frame->tree()->childCount()
1835 // FIXME: If we ever change this so that frames with plug-ins will be cached,
1836 // we need to make sure that we don't cache frames that have outstanding NPObjects
1837 // (objects created by the plug-in). Since there is no way to pause/resume a Netscape plug-in,
1838 // they would need to be destroyed and then recreated, and there is no way that we can recreate
1839 // the right NPObjects. See <rdar://problem/5197041> for more information.
1840 && !m_containsPlugIns
1841 && !m_URL.protocolIs("https")
1842 && !m_frame->document()->hasWindowEventListener(eventNames().unloadEvent)
1843 #if ENABLE(DATABASE)
1844 && !m_frame->document()->hasOpenDatabases()
1846 && !m_frame->document()->usingGeolocation()
1847 && m_currentHistoryItem
1848 && !isQuickRedirectComing()
1849 && !m_documentLoader->isLoadingInAPISense()
1850 && !m_documentLoader->isStopping()
1851 && m_frame->document()->canSuspendActiveDOMObjects()
1852 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
1853 // FIXME: We should investigating caching frames that have an associated
1854 // application cache. <rdar://problem/5917899> tracks that work.
1855 && !m_documentLoader->applicationCache()
1856 && !m_documentLoader->candidateApplicationCacheGroup()
1858 && m_client->canCachePage()
1862 bool FrameLoader::canCachePage()
1865 logCanCachePageDecision();
1868 // Cache the page, if possible.
1869 // Don't write to the cache if in the middle of a redirect, since we will want to
1870 // store the final page we end up on.
1871 // No point writing to the cache on a reload or loadSame, since we will just write
1872 // over it again when we leave that page.
1873 // FIXME: <rdar://problem/4886592> - We should work out the complexities of caching pages with frames as they
1874 // are the most interesting pages on the web, and often those that would benefit the most from caching!
1875 FrameLoadType loadType = this->loadType();
1877 return !m_frame->tree()->parent()
1878 && canCachePageContainingThisFrame()
1880 && m_frame->page()->backForwardList()->enabled()
1881 && m_frame->page()->backForwardList()->capacity() > 0
1882 && m_frame->page()->settings()->usesPageCache()
1883 && loadType != FrameLoadTypeReload
1884 && loadType != FrameLoadTypeReloadFromOrigin
1885 && loadType != FrameLoadTypeSame
1890 static String& pageCacheLogPrefix(int indentLevel)
1892 static int previousIndent = -1;
1893 DEFINE_STATIC_LOCAL(String, prefix, ());
1895 if (indentLevel != previousIndent) {
1896 previousIndent = indentLevel;
1898 for (int i = 0; i < previousIndent; ++i)
1905 static void pageCacheLog(const String& prefix, const String& message)
1907 LOG(PageCache, "%s%s", prefix.utf8().data(), message.utf8().data());
1910 #define PCLOG(...) pageCacheLog(pageCacheLogPrefix(indentLevel), String::format(__VA_ARGS__))
1912 void FrameLoader::logCanCachePageDecision()
1914 // Only bother logging for main frames that have actually loaded and have content.
1915 if (m_creatingInitialEmptyDocument)
1917 KURL currentURL = m_documentLoader ? m_documentLoader->url() : KURL();
1918 if (currentURL.isEmpty())
1921 int indentLevel = 0;
1922 PCLOG("--------\n Determining if page can be cached:");
1924 bool cannotCache = !logCanCacheFrameDecision(1);
1926 FrameLoadType loadType = this->loadType();
1928 if (m_frame->tree()->parent())
1929 { PCLOG(" -Frame has a parent frame"); cannotCache = true; }
1930 if (!m_frame->page()) {
1931 PCLOG(" -There is no Page object");
1935 if (!m_frame->page()->backForwardList()->enabled())
1936 { PCLOG(" -The back/forward list is disabled"); cannotCache = true; }
1937 if (!(m_frame->page()->backForwardList()->capacity() > 0))
1938 { PCLOG(" -The back/forward list has a 0 capacity"); cannotCache = true; }
1939 if (!m_frame->page()->settings()->usesPageCache())
1940 { PCLOG(" -Page settings says b/f cache disabled"); cannotCache = true; }
1941 if (loadType == FrameLoadTypeReload)
1942 { PCLOG(" -Load type is: Reload"); cannotCache = true; }
1943 if (loadType == FrameLoadTypeReloadFromOrigin)
1944 { PCLOG(" -Load type is: Reload from origin"); cannotCache = true; }
1945 if (loadType == FrameLoadTypeSame)
1946 { PCLOG(" -Load type is: Same"); cannotCache = true; }
1949 PCLOG(cannotCache ? " Page CANNOT be cached\n--------" : " Page CAN be cached\n--------");
1952 bool FrameLoader::logCanCacheFrameDecision(int indentLevel)
1954 // Only bother logging for frames that have actually loaded and have content.
1955 if (m_creatingInitialEmptyDocument)
1957 KURL currentURL = m_documentLoader ? m_documentLoader->url() : KURL();
1958 if (currentURL.isEmpty())
1962 KURL newURL = m_provisionalDocumentLoader ? m_provisionalDocumentLoader->url() : KURL();
1963 if (!newURL.isEmpty())
1964 PCLOG(" Determining if frame can be cached navigating from (%s) to (%s):", currentURL.string().utf8().data(), newURL.string().utf8().data());
1966 PCLOG(" Determining if subframe with URL (%s) can be cached:", currentURL.string().utf8().data());
1968 bool cannotCache = false;
1971 if (!m_documentLoader) {
1972 PCLOG(" -There is no DocumentLoader object");
1976 if (!m_documentLoader->mainDocumentError().isNull())
1977 { PCLOG(" -Main document has an error"); cannotCache = true; }
1978 if (m_frame->tree()->childCount())
1979 { PCLOG(" -Frame has child frames"); cannotCache = true; }
1980 if (m_containsPlugIns)
1981 { PCLOG(" -Frame contains plugins"); cannotCache = true; }
1982 if (m_URL.protocolIs("https"))
1983 { PCLOG(" -Frame is HTTPS"); cannotCache = true; }
1984 if (m_frame->document()->hasWindowEventListener(eventNames().unloadEvent))
1985 { PCLOG(" -Frame has an unload event listener"); cannotCache = true; }
1986 #if ENABLE(DATABASE)
1987 if (m_frame->document()->hasOpenDatabases())
1988 { PCLOG(" -Frame has open database handles"); cannotCache = true; }
1990 if (m_frame->document()->usingGeolocation())
1991 { PCLOG(" -Frame uses Geolocation"); cannotCache = true; }
1992 if (!m_currentHistoryItem)
1993 { PCLOG(" -No current history item"); cannotCache = true; }
1994 if (isQuickRedirectComing())
1995 { PCLOG(" -Quick redirect is coming"); cannotCache = true; }
1996 if (m_documentLoader->isLoadingInAPISense())
1997 { PCLOG(" -DocumentLoader is still loading in API sense"); cannotCache = true; }
1998 if (m_documentLoader->isStopping())
1999 { PCLOG(" -DocumentLoader is in the middle of stopping"); cannotCache = true; }
2000 if (!m_frame->document()->canSuspendActiveDOMObjects())
2001 { PCLOG(" -The document cannot suspect its active DOM Objects"); cannotCache = true; }
2002 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
2003 if (m_documentLoader->applicationCache())
2004 { PCLOG(" -The DocumentLoader has an active application cache"); cannotCache = true; }
2005 if (m_documentLoader->candidateApplicationCacheGroup())
2006 { PCLOG(" -The DocumentLoader has a candidateApplicationCacheGroup"); cannotCache = true; }
2008 if (!m_client->canCachePage())
2009 { PCLOG(" -The client says this frame cannot be cached"); cannotCache = true; }
2012 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2013 if (!child->loader()->logCanCacheFrameDecision(indentLevel + 1))
2016 PCLOG(cannotCache ? " Frame CANNOT be cached" : " Frame CAN be cached");
2019 return !cannotCache;
2023 void FrameLoader::updatePolicyBaseURL()
2025 if (m_frame->tree()->parent())
2026 setPolicyBaseURL(m_frame->tree()->parent()->document()->policyBaseURL());
2028 setPolicyBaseURL(m_URL);
2031 void FrameLoader::setPolicyBaseURL(const KURL& url)
2033 m_frame->document()->setPolicyBaseURL(url);
2034 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2035 child->loader()->setPolicyBaseURL(url);
2038 // This does the same kind of work that didOpenURL does, except it relies on the fact
2039 // that a higher level already checked that the URLs match and the scrolling is the right thing to do.
2040 void FrameLoader::scrollToAnchor(const KURL& url)
2043 updateHistoryForAnchorScroll();
2045 // If we were in the autoscroll/panScroll mode we want to stop it before following the link to the anchor
2046 m_frame->eventHandler()->stopAutoscrollTimer();
2050 // It's important to model this as a load that starts and immediately finishes.
2051 // Otherwise, the parent frame may think we never finished loading.
2052 m_isComplete = false;
2056 bool FrameLoader::isComplete() const
2058 return m_isComplete;
2061 void FrameLoader::scheduleRedirection(ScheduledRedirection* redirection)
2063 ASSERT(m_frame->page());
2065 stopRedirectionTimer();
2066 m_scheduledRedirection.set(redirection);
2067 if (!m_isComplete && redirection->type != ScheduledRedirection::redirection)
2069 if (m_isComplete || redirection->type != ScheduledRedirection::redirection)
2070 startRedirectionTimer();
2073 void FrameLoader::startRedirectionTimer()
2075 ASSERT(m_frame->page());
2076 ASSERT(m_scheduledRedirection);
2078 m_redirectionTimer.stop();
2079 m_redirectionTimer.startOneShot(m_scheduledRedirection->delay);
2081 switch (m_scheduledRedirection->type) {
2082 case ScheduledRedirection::redirection:
2083 case ScheduledRedirection::locationChange:
2084 case ScheduledRedirection::locationChangeDuringLoad:
2085 clientRedirected(KURL(m_scheduledRedirection->url),
2086 m_scheduledRedirection->delay,
2087 currentTime() + m_redirectionTimer.nextFireInterval(),
2088 m_scheduledRedirection->lockBackForwardList,
2089 m_isExecutingJavaScriptFormAction);
2091 case ScheduledRedirection::historyNavigation:
2092 // Don't report history navigations.
2095 ASSERT_NOT_REACHED();
2098 void FrameLoader::stopRedirectionTimer()
2100 if (!m_redirectionTimer.isActive())
2103 m_redirectionTimer.stop();
2105 if (m_scheduledRedirection) {
2106 switch (m_scheduledRedirection->type) {
2107 case ScheduledRedirection::redirection:
2108 case ScheduledRedirection::locationChange:
2109 case ScheduledRedirection::locationChangeDuringLoad:
2110 clientRedirectCancelledOrFinished(m_cancellingWithLoadInProgress);
2112 case ScheduledRedirection::historyNavigation:
2113 // Don't report history navigations.
2116 ASSERT_NOT_REACHED();
2120 void FrameLoader::completed()
2122 RefPtr<Frame> protect(m_frame);
2123 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2124 child->loader()->parentCompleted();
2125 if (Frame* parent = m_frame->tree()->parent())
2126 parent->loader()->checkCompleted();
2130 void FrameLoader::started()
2132 for (Frame* frame = m_frame; frame; frame = frame->tree()->parent())
2133 frame->loader()->m_isComplete = false;
2136 bool FrameLoader::containsPlugins() const
2138 return m_containsPlugIns;
2141 void FrameLoader::prepareForLoadStart()
2143 if (Page* page = m_frame->page())
2144 page->progress()->progressStarted(m_frame);
2145 m_client->dispatchDidStartProvisionalLoad();
2148 void FrameLoader::setupForReplace()
2150 setState(FrameStateProvisional);
2151 m_provisionalDocumentLoader = m_documentLoader;
2152 m_documentLoader = 0;
2156 void FrameLoader::setupForReplaceByMIMEType(const String& newMIMEType)
2158 activeDocumentLoader()->setupForReplaceByMIMEType(newMIMEType);
2161 void FrameLoader::loadFrameRequestWithFormAndValues(const FrameLoadRequest& request, bool lockHistory, bool lockBackForwardList, Event* event,
2162 HTMLFormElement* submitForm, const HashMap<String, String>& formValues)
2164 RefPtr<FormState> formState;
2166 formState = FormState::create(submitForm, formValues, m_frame);
2168 KURL url = request.resourceRequest().url();
2171 String argsReferrer = request.resourceRequest().httpReferrer();
2172 if (!argsReferrer.isEmpty())
2173 referrer = argsReferrer;
2175 referrer = m_outgoingReferrer;
2177 ASSERT(frame()->document());
2178 if (url.protocolIs("file")) {
2179 if (!canLoad(url, String(), frame()->document()) && !canLoad(url, referrer)) {
2180 FrameLoader::reportLocalLoadFailed(m_frame, url.string());
2185 if (shouldHideReferrer(url, referrer))
2186 referrer = String();
2188 FrameLoadType loadType;
2189 if (request.resourceRequest().cachePolicy() == ReloadIgnoringCacheData)
2190 loadType = FrameLoadTypeReload;
2191 else if (lockBackForwardList)
2192 loadType = FrameLoadTypeRedirectWithLockedBackForwardList;
2194 loadType = FrameLoadTypeStandard;
2196 if (request.resourceRequest().httpMethod() == "POST")
2197 loadPostRequest(request.resourceRequest(), referrer, request.frameName(), lockHistory, loadType, event, formState.release());
2199 loadURL(request.resourceRequest().url(), referrer, request.frameName(), lockHistory, loadType, event, formState.release());
2201 Frame* targetFrame = findFrameForNavigation(request.frameName());
2202 if (targetFrame && targetFrame != m_frame)
2203 if (Page* page = targetFrame->page())
2204 page->chrome()->focus();
2207 void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType newLoadType,
2208 Event* event, PassRefPtr<FormState> prpFormState)
2210 RefPtr<FormState> formState = prpFormState;
2211 bool isFormSubmission = formState;
2213 ResourceRequest request(newURL);
2214 if (!referrer.isEmpty()) {
2215 request.setHTTPReferrer(referrer);
2216 RefPtr<SecurityOrigin> referrerOrigin = SecurityOrigin::createFromString(referrer);
2217 addHTTPOriginIfNeeded(request, referrerOrigin->toString());
2219 addExtraFieldsToRequest(request, newLoadType, true, event || isFormSubmission);
2220 if (newLoadType == FrameLoadTypeReload || newLoadType == FrameLoadTypeReloadFromOrigin)
2221 request.setCachePolicy(ReloadIgnoringCacheData);
2223 ASSERT(newLoadType != FrameLoadTypeSame);
2225 NavigationAction action(newURL, newLoadType, isFormSubmission, event);
2227 if (!frameName.isEmpty()) {
2228 if (Frame* targetFrame = findFrameForNavigation(frameName))
2229 targetFrame->loader()->loadURL(newURL, referrer, String(), lockHistory, newLoadType, event, formState);
2231 checkNewWindowPolicy(action, request, formState, frameName);
2235 RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader;
2237 bool sameURL = shouldTreatURLAsSameAsCurrent(newURL);
2239 // Make sure to do scroll to anchor processing even if the URL is
2240 // exactly the same so pages with '#' links and DHTML side effects
2242 if (shouldScrollToAnchor(isFormSubmission, newLoadType, newURL)) {
2243 oldDocumentLoader->setTriggeringAction(action);
2245 checkNavigationPolicy(request, oldDocumentLoader.get(), formState,
2246 callContinueFragmentScrollAfterNavigationPolicy, this);
2248 // must grab this now, since this load may stop the previous load and clear this flag
2249 bool isRedirect = m_quickRedirectComing;
2250 loadWithNavigationAction(request, action, lockHistory, newLoadType, formState);
2252 m_quickRedirectComing = false;
2253 if (m_provisionalDocumentLoader)
2254 m_provisionalDocumentLoader->setIsClientRedirect(true);
2256 // Example of this case are sites that reload the same URL with a different cookie
2257 // driving the generated content, or a master frame with links that drive a target
2258 // frame, where the user has clicked on the same link repeatedly.
2259 m_loadType = FrameLoadTypeSame;
2263 void FrameLoader::load(const ResourceRequest& request, bool lockHistory)
2265 load(request, SubstituteData(), lockHistory);
2268 void FrameLoader::load(const ResourceRequest& request, const SubstituteData& substituteData, bool lockHistory)
2270 if (m_inStopAllLoaders)
2273 // FIXME: is this the right place to reset loadType? Perhaps this should be done after loading is finished or aborted.
2274 m_loadType = FrameLoadTypeStandard;
2275 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, substituteData);
2276 if (lockHistory && m_documentLoader)
2277 loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory() : m_documentLoader->clientRedirectSourceForHistory());
2281 void FrameLoader::load(const ResourceRequest& request, const String& frameName, bool lockHistory)
2283 if (frameName.isEmpty()) {
2284 load(request, lockHistory);
2288 Frame* frame = findFrameForNavigation(frameName);
2290 frame->loader()->load(request, lockHistory);
2294 checkNewWindowPolicy(NavigationAction(request.url(), NavigationTypeOther), request, 0, frameName);
2297 void FrameLoader::loadWithNavigationAction(const ResourceRequest& request, const NavigationAction& action, bool lockHistory, FrameLoadType type, PassRefPtr<FormState> formState)
2299 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, SubstituteData());
2300 if (lockHistory && m_documentLoader)
2301 loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory() : m_documentLoader->clientRedirectSourceForHistory());
2303 loader->setTriggeringAction(action);
2304 if (m_documentLoader)
2305 loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
2307 loadWithDocumentLoader(loader.get(), type, formState);
2310 void FrameLoader::load(DocumentLoader* newDocumentLoader)
2312 ResourceRequest& r = newDocumentLoader->request();
2313 addExtraFieldsToMainResourceRequest(r);
2316 if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->originalRequest().url())) {
2317 r.setCachePolicy(ReloadIgnoringCacheData);
2318 type = FrameLoadTypeSame;
2320 type = FrameLoadTypeStandard;
2322 if (m_documentLoader)
2323 newDocumentLoader->setOverrideEncoding(m_documentLoader->overrideEncoding());
2325 // When we loading alternate content for an unreachable URL that we're
2326 // visiting in the history list, we treat it as a reload so the history list
2327 // is appropriately maintained.
2329 // FIXME: This seems like a dangerous overloading of the meaning of "FrameLoadTypeReload" ...
2330 // shouldn't a more explicit type of reload be defined, that means roughly
2331 // "load without affecting history" ?
2332 if (shouldReloadToHandleUnreachableURL(newDocumentLoader)) {
2333 ASSERT(type == FrameLoadTypeStandard);
2334 type = FrameLoadTypeReload;
2337 loadWithDocumentLoader(newDocumentLoader, type, 0);
2340 void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType type, PassRefPtr<FormState> prpFormState)
2342 ASSERT(m_client->hasWebView());
2344 // Unfortunately the view must be non-nil, this is ultimately due
2345 // to parser requiring a FrameView. We should fix this dependency.
2347 ASSERT(m_frame->view());
2349 m_policyLoadType = type;
2350 RefPtr<FormState> formState = prpFormState;
2351 bool isFormSubmission = formState;
2353 const KURL& newURL = loader->request().url();
2355 if (shouldScrollToAnchor(isFormSubmission, m_policyLoadType, newURL)) {
2356 RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader;
2357 NavigationAction action(newURL, m_policyLoadType, isFormSubmission);
2359 oldDocumentLoader->setTriggeringAction(action);
2361 checkNavigationPolicy(loader->request(), oldDocumentLoader.get(), formState,
2362 callContinueFragmentScrollAfterNavigationPolicy, this);
2364 if (Frame* parent = m_frame->tree()->parent())
2365 loader->setOverrideEncoding(parent->loader()->documentLoader()->overrideEncoding());
2368 setPolicyDocumentLoader(loader);
2370 checkNavigationPolicy(loader->request(), loader, formState,
2371 callContinueLoadAfterNavigationPolicy, this);
2375 bool FrameLoader::canLoad(const KURL& url, const String& referrer, const Document* doc)
2377 // We can always load any URL that isn't considered local (e.g. http URLs)
2378 if (!shouldTreatURLAsLocal(url.string()))
2381 // If we were provided a document, we let its local file policy dictate the result,
2382 // otherwise we allow local loads only if the supplied referrer is also local.
2384 return doc->securityOrigin()->canLoadLocalResources();
2385 else if (!referrer.isEmpty())
2386 return shouldTreatURLAsLocal(referrer);
2391 void FrameLoader::reportLocalLoadFailed(Frame* frame, const String& url)
2393 ASSERT(!url.isEmpty());
2397 frame->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, "Not allowed to load local resource: " + url, 0, String());
2400 bool FrameLoader::shouldHideReferrer(const KURL& url, const String& referrer)
2402 bool referrerIsSecureURL = protocolIs(referrer, "https");
2403 bool referrerIsWebURL = referrerIsSecureURL || protocolIs(referrer, "http");
2405 if (!referrerIsWebURL)
2408 if (!referrerIsSecureURL)
2411 bool URLIsSecureURL = url.protocolIs("https");
2413 return !URLIsSecureURL;
2416 const ResourceRequest& FrameLoader::initialRequest() const
2418 return activeDocumentLoader()->originalRequest();
2421 void FrameLoader::receivedData(const char* data, int length)
2423 activeDocumentLoader()->receivedData(data, length);
2426 void FrameLoader::handleUnimplementablePolicy(const ResourceError& error)
2428 m_delegateIsHandlingUnimplementablePolicy = true;
2429 m_client->dispatchUnableToImplementPolicy(error);
2430 m_delegateIsHandlingUnimplementablePolicy = false;
2433 void FrameLoader::cannotShowMIMEType(const ResourceResponse& response)
2435 handleUnimplementablePolicy(m_client->cannotShowMIMETypeError(response));
2438 ResourceError FrameLoader::interruptionForPolicyChangeError(const ResourceRequest& request)
2440 return m_client->interruptForPolicyChangeError(request);
2443 void FrameLoader::checkNavigationPolicy(const ResourceRequest& newRequest, NavigationPolicyDecisionFunction function, void* argument)
2445 checkNavigationPolicy(newRequest, activeDocumentLoader(), 0, function, argument);
2448 void FrameLoader::checkContentPolicy(const String& MIMEType, ContentPolicyDecisionFunction function, void* argument)
2450 ASSERT(activeDocumentLoader());
2452 // Always show content with valid substitute data.
2453 if (activeDocumentLoader()->substituteData().isValid()) {
2454 function(argument, PolicyUse);
2459 // Respect the hidden FTP Directory Listing pref so it can be tested even if the policy delegate might otherwise disallow it
2460 Settings* settings = m_frame->settings();
2461 if (settings && settings->forceFTPDirectoryListings() && MIMEType == "application/x-ftp-directory") {
2462 function(argument, PolicyUse);
2467 m_policyCheck.set(function, argument);
2468 m_client->dispatchDecidePolicyForMIMEType(&FrameLoader::continueAfterContentPolicy,
2469 MIMEType, activeDocumentLoader()->request());
2472 bool FrameLoader::shouldReloadToHandleUnreachableURL(DocumentLoader* docLoader)
2474 KURL unreachableURL = docLoader->unreachableURL();
2476 if (unreachableURL.isEmpty())
2479 if (!isBackForwardLoadType(m_policyLoadType))
2482 // We only treat unreachableURLs specially during the delegate callbacks
2483 // for provisional load errors and navigation policy decisions. The former
2484 // case handles well-formed URLs that can't be loaded, and the latter
2485 // case handles malformed URLs and unknown schemes. Loading alternate content
2486 // at other times behaves like a standard load.
2487 DocumentLoader* compareDocumentLoader = 0;
2488 if (m_delegateIsDecidingNavigationPolicy || m_delegateIsHandlingUnimplementablePolicy)
2489 compareDocumentLoader = m_policyDocumentLoader.get();
2490 else if (m_delegateIsHandlingProvisionalLoadError)
2491 compareDocumentLoader = m_provisionalDocumentLoader.get();
2493 return compareDocumentLoader && unreachableURL == compareDocumentLoader->request().url();
2496 void FrameLoader::reloadWithOverrideEncoding(const String& encoding)
2498 if (!m_documentLoader)
2501 ResourceRequest request = m_documentLoader->request();
2502 KURL unreachableURL = m_documentLoader->unreachableURL();
2503 if (!unreachableURL.isEmpty())
2504 request.setURL(unreachableURL);
2506 request.setCachePolicy(ReturnCacheDataElseLoad);
2508 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, SubstituteData());
2509 setPolicyDocumentLoader(loader.get());
2511 loader->setOverrideEncoding(encoding);
2513 loadWithDocumentLoader(loader.get(), FrameLoadTypeReload, 0);
2516 void FrameLoader::reload(bool endToEndReload)
2518 if (!m_documentLoader)
2521 // If a window is created by javascript, its main frame can have an empty but non-nil URL.
2522 // Reloading in this case will lose the current contents (see 4151001).
2523 if (m_documentLoader->request().url().isEmpty())
2526 ResourceRequest initialRequest = m_documentLoader->request();
2528 // Replace error-page URL with the URL we were trying to reach.
2529 KURL unreachableURL = m_documentLoader->unreachableURL();
2530 if (!unreachableURL.isEmpty())
2531 initialRequest.setURL(unreachableURL);
2533 // Create a new document loader for the reload, this will become m_documentLoader eventually,
2534 // but first it has to be the "policy" document loader, and then the "provisional" document loader.
2535 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(initialRequest, SubstituteData());
2537 ResourceRequest& request = loader->request();
2539 // FIXME: We don't have a mechanism to revalidate the main resource without reloading at the moment.
2540 request.setCachePolicy(ReloadIgnoringCacheData);
2542 // If we're about to re-post, set up action so the application can warn the user.
2543 if (request.httpMethod() == "POST")
2544 loader->setTriggeringAction(NavigationAction(request.url(), NavigationTypeFormResubmitted));
2546 loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
2548 loadWithDocumentLoader(loader.get(), endToEndReload ? FrameLoadTypeReloadFromOrigin : FrameLoadTypeReload, 0);
2551 static bool canAccessAncestor(const SecurityOrigin* activeSecurityOrigin, Frame* targetFrame)
2553 // targetFrame can be NULL when we're trying to navigate a top-level frame
2554 // that has a NULL opener.
2558 for (Frame* ancestorFrame = targetFrame; ancestorFrame; ancestorFrame = ancestorFrame->tree()->parent()) {
2559 Document* ancestorDocument = ancestorFrame->document();
2560 if (!ancestorDocument)
2563 const SecurityOrigin* ancestorSecurityOrigin = ancestorDocument->securityOrigin();
2564 if (activeSecurityOrigin->canAccess(ancestorSecurityOrigin))
2571 bool FrameLoader::shouldAllowNavigation(Frame* targetFrame) const
2573 // The navigation change is safe if the active frame is:
2574 // - in the same security origin as the target or one of the target's
2577 // Or the target frame is:
2578 // - a top-level frame in the frame hierarchy and the active frame can
2579 // navigate the target frame's opener per above.
2584 // Performance optimization.
2585 if (m_frame == targetFrame)
2588 // Let a frame navigate the top-level window that contains it. This is
2589 // important to allow because it lets a site "frame-bust" (escape from a
2590 // frame created by another web site).
2591 if (targetFrame == m_frame->tree()->top())
2594 Document* activeDocument = m_frame->document();
2595 ASSERT(activeDocument);
2596 const SecurityOrigin* activeSecurityOrigin = activeDocument->securityOrigin();
2598 // For top-level windows, check the opener.
2599 if (!targetFrame->tree()->parent() && canAccessAncestor(activeSecurityOrigin, targetFrame->loader()->opener()))
2602 // In general, check the frame's ancestors.
2603 if (canAccessAncestor(activeSecurityOrigin, targetFrame))
2606 Settings* settings = targetFrame->settings();
2607 if (settings && !settings->privateBrowsingEnabled()) {
2608 Document* targetDocument = targetFrame->document();
2609 // FIXME: this error message should contain more specifics of why the navigation change is not allowed.
2610 String message = String::format("Unsafe JavaScript attempt to initiate a navigation change for frame with URL %s from frame with URL %s.\n",
2611 targetDocument->url().string().utf8().data(), activeDocument->url().string().utf8().data());
2613 // FIXME: should we print to the console of the activeFrame as well?
2614 targetFrame->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, message, 1, String());
2620 void FrameLoader::stopLoadingSubframes()
2622 for (RefPtr<Frame> child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2623 child->loader()->stopAllLoaders();
2626 void FrameLoader::stopAllLoaders()
2628 // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
2629 if (m_inStopAllLoaders)
2632 m_inStopAllLoaders = true;
2636 stopLoadingSubframes();
2637 if (m_provisionalDocumentLoader)
2638 m_provisionalDocumentLoader->stopLoading();
2639 if (m_documentLoader)
2640 m_documentLoader->stopLoading();
2642 setProvisionalDocumentLoader(0);
2644 if (m_documentLoader)
2645 m_documentLoader->clearArchiveResources();
2647 m_inStopAllLoaders = false;
2650 void FrameLoader::stopForUserCancel(bool deferCheckLoadComplete)
2654 if (deferCheckLoadComplete)
2655 scheduleCheckLoadComplete();
2656 else if (m_frame->page())
2657 checkLoadComplete();
2660 DocumentLoader* FrameLoader::activeDocumentLoader() const
2662 if (m_state == FrameStateProvisional)
2663 return m_provisionalDocumentLoader.get();
2664 return m_documentLoader.get();
2667 bool FrameLoader::isLoading() const
2669 DocumentLoader* docLoader = activeDocumentLoader();
2672 return docLoader->isLoadingMainResource() || docLoader->isLoadingSubresources() || docLoader->isLoadingPlugIns();
2675 bool FrameLoader::frameHasLoaded() const
2677 return m_committedFirstRealDocumentLoad || (m_provisionalDocumentLoader && !m_creatingInitialEmptyDocument);
2680 void FrameLoader::setDocumentLoader(DocumentLoader* loader)
2682 if (!loader && !m_documentLoader)
2685 ASSERT(loader != m_documentLoader);
2686 ASSERT(!loader || loader->frameLoader() == this);
2688 m_client->prepareForDataSourceReplacement();
2690 if (m_documentLoader)
2691 m_documentLoader->detachFromFrame();
2693 m_documentLoader = loader;
2696 void FrameLoader::setPolicyDocumentLoader(DocumentLoader* loader)
2698 if (m_policyDocumentLoader == loader)
2703 loader->setFrame(m_frame);
2704 if (m_policyDocumentLoader
2705 && m_policyDocumentLoader != m_provisionalDocumentLoader
2706 && m_policyDocumentLoader != m_documentLoader)
2707 m_policyDocumentLoader->detachFromFrame();
2709 m_policyDocumentLoader = loader;
2712 void FrameLoader::setProvisionalDocumentLoader(DocumentLoader* loader)
2714 ASSERT(!loader || !m_provisionalDocumentLoader);
2715 ASSERT(!loader || loader->frameLoader() == this);
2717 if (m_provisionalDocumentLoader && m_provisionalDocumentLoader != m_documentLoader)
2718 m_provisionalDocumentLoader->detachFromFrame();
2720 m_provisionalDocumentLoader = loader;
2723 double FrameLoader::timeOfLastCompletedLoad()
2725 return storedTimeOfLastCompletedLoad;
2728 void FrameLoader::setState(FrameState newState)
2732 if (newState == FrameStateProvisional)
2733 provisionalLoadStarted();
2734 else if (newState == FrameStateComplete) {
2735 frameLoadCompleted();
2736 storedTimeOfLastCompletedLoad = currentTime();
2737 if (m_documentLoader)
2738 m_documentLoader->stopRecordingResponses();
2742 void FrameLoader::clearProvisionalLoad()
2744 setProvisionalDocumentLoader(0);
2745 if (Page* page = m_frame->page())
2746 page->progress()->progressCompleted(m_frame);
2747 setState(FrameStateComplete);
2750 void FrameLoader::markLoadComplete()
2752 setState(FrameStateComplete);
2755 void FrameLoader::commitProvisionalLoad(PassRefPtr<CachedPage> prpCachedPage)
2757 RefPtr<CachedPage> cachedPage = prpCachedPage;
2758 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
2760 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());
2762 // Check to see if we need to cache the page we are navigating away from into the back/forward cache.
2763 // We are doing this here because we know for sure that a new page is about to be loaded.
2764 cachePageForHistoryItem(m_currentHistoryItem.get());
2766 if (m_loadType != FrameLoadTypeReplace)
2767 closeOldDataSources();
2769 if (!cachedPage && !m_creatingInitialEmptyDocument)
2770 m_client->makeRepresentation(pdl.get());
2772 transitionToCommitted(cachedPage);
2774 // Call clientRedirectCancelledOrFinished() here so that the frame load delegate is notified that the redirect's
2775 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
2776 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are
2777 // just about to commit a new page, there cannot possibly be a pending redirect at this point.
2778 if (m_sentRedirectNotification)
2779 clientRedirectCancelledOrFinished(false);
2781 if (cachedPage && cachedPage->document()) {
2783 cachedPage->clear();
2785 KURL url = pdl->substituteData().responseURL();
2789 url = pdl->responseURL();
2796 LOG(Loading, "WebCoreLoading %s: Finished committing provisional load to URL %s", m_frame->tree()->name().string().utf8().data(), m_URL.string().utf8().data());
2798 if (m_loadType == FrameLoadTypeStandard && m_documentLoader->isClientRedirect())
2799 updateHistoryForClientRedirect();
2801 if (m_documentLoader->isLoadingFromCachedPage()) {
2802 m_frame->document()->documentDidBecomeActive();
2804 // Force a layout to update view size and thereby update scrollbars.
2805 m_client->forceLayout();
2807 const ResponseVector& responses = m_documentLoader->responses();
2808 size_t count = responses.size();
2809 for (size_t i = 0; i < count; i++) {
2810 const ResourceResponse& response = responses[i];
2811 // FIXME: If the WebKit client changes or cancels the request, this is not respected.
2812 ResourceError error;
2813 unsigned long identifier;
2814 ResourceRequest request(response.url());
2815 requestFromDelegate(request, identifier, error);
2816 // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
2817 // However, with today's computers and networking speeds, this won't happen in practice.
2818 // Could be an issue with a giant local file.
2819 sendRemainingDelegateMessages(identifier, response, static_cast<int>(response.expectedContentLength()), error);
2822 pageCache()->remove(m_currentHistoryItem.get());
2824 m_documentLoader->setPrimaryLoadComplete(true);
2826 // FIXME: Why only this frame and not parent frames?
2827 checkLoadCompleteForThisFrame();
2831 void FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage)
2833 ASSERT(m_client->hasWebView());
2834 ASSERT(m_state == FrameStateProvisional);
2836 if (m_state != FrameStateProvisional)
2839 m_client->setCopiesOnScroll();
2840 updateHistoryForCommit();
2842 // The call to closeURL() invokes the unload event handler, which can execute arbitrary
2843 // JavaScript. If the script initiates a new load, we need to abandon the current load,
2844 // or the two will stomp each other.
2845 DocumentLoader* pdl = m_provisionalDocumentLoader.get();
2846 if (m_documentLoader)
2848 if (pdl != m_provisionalDocumentLoader)
2851 // Nothing else can interupt this commit - set the Provisional->Committed transition in stone
2852 if (m_documentLoader)
2853 m_documentLoader->stopLoadingSubresources();
2854 if (m_documentLoader)
2855 m_documentLoader->stopLoadingPlugIns();
2857 setDocumentLoader(m_provisionalDocumentLoader.get());
2858 setProvisionalDocumentLoader(0);
2859 setState(FrameStateCommittedPage);
2861 // Handle adding the URL to the back/forward list.
2862 DocumentLoader* dl = m_documentLoader.get();
2863 String ptitle = dl->title();
2865 switch (m_loadType) {
2866 case FrameLoadTypeForward:
2867 case FrameLoadTypeBack:
2868 case FrameLoadTypeIndexedBackForward:
2869 if (Page* page = m_frame->page())
2870 if (page->backForwardList()) {
2871 updateHistoryForBackForwardNavigation();
2873 // Create a document view for this document, or used the cached view.
2875 DocumentLoader* cachedDocumentLoader = cachedPage->documentLoader();
2876 ASSERT(cachedDocumentLoader);
2877 cachedDocumentLoader->setFrame(m_frame);
2878 m_client->transitionToCommittedFromCachedFrame(cachedPage->cachedMainFrame());
2881 m_client->transitionToCommittedForNewPage();
2885 case FrameLoadTypeReload:
2886 case FrameLoadTypeReloadFromOrigin:
2887 case FrameLoadTypeSame:
2888 case FrameLoadTypeReplace:
2889 updateHistoryForReload();
2890 m_client->transitionToCommittedForNewPage();
2893 case FrameLoadTypeStandard:
2894 updateHistoryForStandardLoad();
2895 #ifndef BUILDING_ON_TIGER
2896 // This code was originally added for a Leopard performance imporvement. We decided to
2897 // ifdef it to fix correctness issues on Tiger documented in <rdar://problem/5441823>.
2898 if (m_frame->view())
2899 m_frame->view()->setScrollbarsSuppressed(true);
2901 m_client->transitionToCommittedForNewPage();
2904 case FrameLoadTypeRedirectWithLockedBackForwardList:
2905 updateHistoryForRedirectWithLockedBackForwardList();
2906 m_client->transitionToCommittedForNewPage();
2909 // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is).
2910 // An exception should be thrown if we're in the FrameLoadTypeUninitialized state.
2912 ASSERT_NOT_REACHED();
2915 m_responseMIMEType = dl->responseMIMEType();
2917 // Tell the client we've committed this URL.
2918 ASSERT(m_frame->view());
2920 if (m_creatingInitialEmptyDocument)
2923 m_committedFirstRealDocumentLoad = true;
2925 // For non-cached HTML pages, these methods are called in FrameLoader::begin.
2926 if (cachedPage || !m_client->hasHTMLView()) {
2927 dispatchDidCommitLoad();
2929 // If we have a title let the WebView know about it.
2930 if (!ptitle.isNull())
2931 m_client->dispatchDidReceiveTitle(ptitle);
2935 void FrameLoader::clientRedirectCancelledOrFinished(bool cancelWithLoadInProgress)
2937 // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
2938 // the redirect succeeded. We should either rename this API, or add a new method, like
2939 // -webView:didFinishClientRedirectForFrame:
2940 m_client->dispatchDidCancelClientRedirect();
2942 if (!cancelWithLoadInProgress)
2943 m_quickRedirectComing = false;
2945 m_sentRedirectNotification = false;
2948 void FrameLoader::clientRedirected(const KURL& url, double seconds, double fireDate, bool lockBackForwardList, bool isJavaScriptFormAction)
2950 m_client->dispatchWillPerformClientRedirect(url, seconds, fireDate);
2952 // Remember that we sent a redirect notification to the frame load delegate so that when we commit
2953 // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
2954 m_sentRedirectNotification = true;
2956 // If a "quick" redirect comes in an, we set a special mode so we treat the next
2957 // load as part of the same navigation. If we don't have a document loader, we have
2958 // no "original" load on which to base a redirect, so we treat the redirect as a normal load.
2959 m_quickRedirectComing = lockBackForwardList && m_documentLoader && !isJavaScriptFormAction;
2963 void FrameLoader::setForceReloadWmlDeck(bool reload)
2965 m_forceReloadWmlDeck = reload;
2969 bool FrameLoader::shouldReload(const KURL& currentURL, const KURL& destinationURL)
2972 // As for WML deck, sometimes it's supposed to be reloaded even if the same URL with fragment
2973 if (m_forceReloadWmlDeck)
2977 // This function implements the rule: "Don't reload if navigating by fragment within
2978 // the same URL, but do reload if going to a new URL or to the same URL with no
2979 // fragment identifier at all."
2980 if (!destinationURL.hasRef())
2982 return !equalIgnoringRef(currentURL, destinationURL);
2985 void FrameLoader::closeOldDataSources()
2987 // FIXME: Is it important for this traversal to be postorder instead of preorder?
2988 // If so, add helpers for postorder traversal, and use them. If not, then lets not
2989 // use a recursive algorithm here.
2990 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2991 child->loader()->closeOldDataSources();
2993 if (m_documentLoader)
2994 m_client->dispatchWillClose();
2996 m_client->setMainFrameDocumentReady(false); // stop giving out the actual DOMDocument to observers
2999 void FrameLoader::open(CachedPage& cachedPage)
3001 ASSERT(!m_frame->tree()->parent());
3002 ASSERT(m_frame->page());
3003 ASSERT(m_frame->page()->mainFrame() == m_frame);
3005 cancelRedirection();
3007 // We still have to close the previous part page.
3010 // Delete old status bar messages (if it _was_ activated on last URL).
3011 if (m_frame->script()->isEnabled()) {
3012 m_frame->setJSStatusBarText(String());
3013 m_frame->setJSDefaultStatusBarText(String());
3016 open(*cachedPage.cachedMainFrame());
3021 void FrameLoader::open(CachedFrame& cachedFrame)
3023 m_isComplete = false;
3025 // Don't re-emit the load event.
3026 m_didCallImplicitClose = true;
3028 KURL url = cachedFrame.url();
3030 if ((url.protocolIs("http") || url.protocolIs("https")) && !url.host().isEmpty() && url.path().isEmpty())
3040 Document* document = cachedFrame.document();
3042 document->setInPageCache(false);
3044 m_needsClear = true;
3045 m_isComplete = false;
3046 m_didCallImplicitClose = false;
3047 m_outgoingReferrer = url.string();
3049 FrameView* view = cachedFrame.view();
3051 // When navigating to a CachedFrame its FrameView should never be null. If it is we'll crash in creative ways downstream.
3054 view->setWasScrolledByUser(false);
3055 m_frame->setView(view);
3057 m_frame->setDocument(document);
3058 m_frame->setDOMWindow(cachedFrame.domWindow());
3059 m_frame->domWindow()->setURL(document->url());
3060 m_frame->domWindow()->setSecurityOrigin(document->securityOrigin());
3062 m_decoder = document->decoder();
3064 updatePolicyBaseURL();
3066 cachedFrame.restore();
3069 bool FrameLoader::isStopping() const
3071 return activeDocumentLoader()->isStopping();
3074 void FrameLoader::finishedLoading()
3076 // Retain because the stop may release the last reference to it.
3077 RefPtr<Frame> protect(m_frame);
3079 RefPtr<DocumentLoader> dl = activeDocumentLoader();
3080 dl->finishedLoading();
3081 if (!dl->mainDocumentError().isNull() || !dl->frameLoader())
3083 dl->setPrimaryLoadComplete(true);
3084 m_client->dispatchDidLoadMainResource(dl.get());
3085 checkLoadComplete();
3088 bool FrameLoader::isHostedByObjectElement() const
3090 HTMLFrameOwnerElement* owner = m_frame->ownerElement();
3091 return owner && owner->hasTagName(objectTag);
3094 bool FrameLoader::isLoadingMainFrame() const
3096 Page* page = m_frame->page();
3097 return page && m_frame == page->mainFrame();
3100 bool FrameLoader::canShowMIMEType(const String& MIMEType) const
3102 return m_client->canShowMIMEType(MIMEType);
3105 bool FrameLoader::representationExistsForURLScheme(const String& URLScheme)
3107 return m_client->representationExistsForURLScheme(URLScheme);
3110 String FrameLoader::generatedMIMETypeForURLScheme(const String& URLScheme)
3112 return m_client->generatedMIMETypeForURLScheme(URLScheme);
3115 void FrameLoader::cancelContentPolicyCheck()
3117 m_client->cancelPolicyCheck();
3118 m_policyCheck.clear();
3121 void FrameLoader::didReceiveServerRedirectForProvisionalLoadForFrame()
3123 m_client->dispatchDidReceiveServerRedirectForProvisionalLoad();
3126 void FrameLoader::finishedLoadingDocument(DocumentLoader* loader)
3128 // FIXME: Platforms shouldn't differ here!
3129 #if PLATFORM(WIN) || PLATFORM(CHROMIUM)
3130 if (m_creatingInitialEmptyDocument)
3134 // If loading a webarchive, run through webarchive machinery
3135 const String& responseMIMEType = loader->responseMIMEType();
3137 // FIXME: Mac's FrameLoaderClient::finishedLoading() method does work that is required even with Archive loads
3138 // so we still need to call it. Other platforms should only call finishLoading for non-archive loads
3139 // That work should be factored out so this #ifdef can be removed
3141 m_client->finishedLoading(loader);
3142 if (!ArchiveFactory::isArchiveMimeType(responseMIMEType))
3145 if (!ArchiveFactory::isArchiveMimeType(responseMIMEType)) {
3146 m_client->finishedLoading(loader);
3151 RefPtr<Archive> archive(ArchiveFactory::create(loader->mainResourceData().get(), responseMIMEType));
3155 loader->addAllArchiveResources(archive.get());
3157 ArchiveResource* mainResource = archive->mainResource();
3158 loader->setParsedArchiveData(mainResource->data());
3159 continueLoadWithData(mainResource->data(), mainResource->mimeType(), mainResource->textEncoding(), mainResource->url());
3162 bool FrameLoader::isReplacing() const
3164 return m_loadType == FrameLoadTypeReplace;
3167 void FrameLoader::setReplacing()
3169 m_loadType = FrameLoadTypeReplace;
3172 void FrameLoader::revertToProvisional(DocumentLoader* loader)
3174 m_client->revertToProvisionalState(loader);
3177 bool FrameLoader::subframeIsLoading() const
3179 // It's most likely that the last added frame is the last to load so we walk backwards.
3180 for (Frame* child = m_frame->tree()->lastChild(); child; child = child->tree()->previousSibling()) {
3181 FrameLoader* childLoader = child->loader();
3182 DocumentLoader* documentLoader = childLoader->documentLoader();
3183 if (documentLoader && documentLoader->isLoadingInAPISense())
3185 documentLoader = childLoader->provisionalDocumentLoader();
3186 if (documentLoader && documentLoader->isLoadingInAPISense())
3192 void FrameLoader::willChangeTitle(DocumentLoader* loader)
3194 m_client->willChangeTitle(loader);
3197 FrameLoadType FrameLoader::loadType() const
3202 CachePolicy FrameLoader::cachePolicy() const
3205 return CachePolicyVerify;
3207 if (m_loadType == FrameLoadTypeReloadFromOrigin || documentLoader()->request().cachePolicy() == ReloadIgnoringCacheData)
3208 return CachePolicyReload;
3210 if (Frame* parentFrame = m_frame->tree()->parent()) {
3211 CachePolicy parentCachePolicy = parentFrame->loader()->cachePolicy();
3212 if (parentCachePolicy != CachePolicyVerify)
3213 return parentCachePolicy;
3216 if (m_loadType == FrameLoadTypeReload)
3217 return CachePolicyRevalidate;
3219 return CachePolicyVerify;
3222 void FrameLoader::stopPolicyCheck()
3224 m_client->cancelPolicyCheck();
3225 PolicyCheck check = m_policyCheck;
3226 m_policyCheck.clear();
3230 void FrameLoader::checkLoadCompleteForThisFrame()
3232 ASSERT(m_client->hasWebView());
3235 case FrameStateProvisional: {
3236 if (m_delegateIsHandlingProvisionalLoadError)
3239 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
3243 // If we've received any errors we may be stuck in the provisional state and actually complete.
3244 const ResourceError& error = pdl->mainDocumentError();
3248 // Check all children first.
3249 RefPtr<HistoryItem> item;
3250 if (Page* page = m_frame->page())
3251 if (isBackForwardLoadType(loadType()) && m_frame == page->mainFrame())
3252 item = m_currentHistoryItem;
3254 bool shouldReset = true;
3255 if (!pdl->isLoadingInAPISense()) {
3256 m_delegateIsHandlingProvisionalLoadError = true;
3257 m_client->dispatchDidFailProvisionalLoad(error);
3258 m_delegateIsHandlingProvisionalLoadError = false;
3260 // FIXME: can stopping loading here possibly have any effect, if isLoading is false,
3261 // which it must be to be in this branch of the if? And is it OK to just do a full-on
3262 // stopAllLoaders instead of stopLoadingSubframes?
3263 stopLoadingSubframes();
3266 // Finish resetting the load state, but only if another load hasn't been started by the
3267 // delegate callback.
3268 if (pdl == m_provisionalDocumentLoader)
3269 clearProvisionalLoad();
3270 else if (m_provisionalDocumentLoader) {
3271 KURL unreachableURL = m_provisionalDocumentLoader->unreachableURL();
3272 if (!unreachableURL.isEmpty() && unreachableURL == pdl->request().url())
3273 shouldReset = false;
3276 if (shouldReset && item)
3277 if (Page* page = m_frame->page()) {
3278 page->backForwardList()->goToItem(item.get());
3279 Settings* settings = m_frame->settings();
3280 page->setGlobalHistoryItem((!settings || settings->privateBrowsingEnabled()) ? 0 : item.get());
3285 case FrameStateCommittedPage: {
3286 DocumentLoader* dl = m_documentLoader.get();
3287 if (!dl || dl->isLoadingInAPISense())
3292 // FIXME: Is this subsequent work important if we already navigated away?
3293 // Maybe there are bugs because of that, or extra work we can skip because
3294 // the new page is ready.
3296 m_client->forceLayoutForNonHTML();
3298 // If the user had a scroll point, scroll to it, overriding the anchor point if any.
3299 if (Page* page = m_frame->page())
3300 if ((isBackForwardLoadType(m_loadType) || m_loadType == FrameLoadTypeReload || m_loadType == FrameLoadTypeReloadFromOrigin) && page->backForwardList())
3301 restoreScrollPositionAndViewState();
3303 if (m_creatingInitialEmptyDocument || !m_committedFirstRealDocumentLoad)
3306 const ResourceError& error = dl->mainDocumentError();
3308 m_didDispatchDidCommitLoad = false;
3310 if (!error.isNull())
3311 m_client->dispatchDidFailLoad(error);
3313 m_client->dispatchDidFinishLoad();
3315 if (Page* page = m_frame->page())
3316 page->progress()->progressCompleted(m_frame);
3320 case FrameStateComplete:
3321 frameLoadCompleted();
3325 ASSERT_NOT_REACHED();
3328 void FrameLoader::continueAfterContentPolicy(PolicyAction policy)
3330 PolicyCheck check = m_policyCheck;
3331 m_policyCheck.clear();
3335 void FrameLoader::continueLoadAfterWillSubmitForm(PolicyAction)
3337 if (!m_provisionalDocumentLoader)
3340 // DocumentLoader calls back to our prepareForLoadStart
3341 m_provisionalDocumentLoader->prepareForLoadStart();
3343 // The load might be cancelled inside of prepareForLoadStart(), nulling out the m_provisionalDocumentLoader,
3344 // so we need to null check it again.
3345 if (!m_provisionalDocumentLoader)
3348 DocumentLoader* activeDocLoader = activeDocumentLoader();
3349 if (activeDocLoader && activeDocLoader->isLoadingMainResource())
3352 m_provisionalDocumentLoader->setLoadingFromCachedPage(false);
3354 unsigned long identifier = 0;
3356 if (Page* page = m_frame->page()) {
3357 identifier = page->progress()->createUniqueIdentifier();
3358 dispatchAssignIdentifierToInitialRequest(identifier, m_provisionalDocumentLoader.get(), m_provisionalDocumentLoader->originalRequest());
3361 if (!m_provisionalDocumentLoader->startLoadingMainResource(identifier))
3362 m_provisionalDocumentLoader->updateLoading();
3365 void FrameLoader::didFirstLayout()
3367 if (Page* page = m_frame->page())
3368 if (isBackForwardLoadType(m_loadType) && page->backForwardList())
3369 restoreScrollPositionAndViewState();
3371 m_firstLayoutDone = true;
3372 m_client->dispatchDidFirstLayout();
3375 void FrameLoader::didFirstVisuallyNonEmptyLayout()
3377 m_client->dispatchDidFirstVisuallyNonEmptyLayout();
3380 void FrameLoader::frameLoadCompleted()
3382 // Note: Can be called multiple times.
3384 m_client->frameLoadCompleted();
3386 // Even if already complete, we might have set a previous item on a frame that
3387 // didn't do any data loading on the past transaction. Make sure to clear these out.
3388 m_previousHistoryItem = 0;
3390 // After a canceled provisional load, firstLayoutDone is false.
3391 // Reset it to true if we're displaying a page.
3392 if (m_documentLoader)
3393 m_firstLayoutDone = true;
3396 bool FrameLoader::firstLayoutDone() const
3398 return m_firstLayoutDone;
3401 bool FrameLoader::isQuickRedirectComing() const
3403 return m_quickRedirectComing;
3406 void FrameLoader::detachChildren()
3408 // FIXME: Is it really necessary to do this in reverse order?
3410 for (Frame* child = m_frame->tree()->lastChild(); child; child = previous) {
3411 previous = child->tree()->previousSibling();
3412 child->loader()->detachFromParent();
3416 void FrameLoader::closeAndRemoveChild(Frame* child)
3418 child->tree()->detachFromParent();
3421 if (child->ownerElement())
3422 child->page()->decrementFrameCount();
3423 child->pageDestroyed();
3425 m_frame->tree()->removeChild(child);
3428 void FrameLoader::recursiveCheckLoadComplete()
3430 Vector<RefPtr<Frame>, 10> frames;
3432 for (RefPtr<Frame> frame = m_frame->tree()->firstChild(); frame; frame = frame->tree()->nextSibling())
3433 frames.append(frame);
3435 unsigned size = frames.size();
3436 for (unsigned i = 0; i < size; i++)
3437 frames[i]->loader()->recursiveCheckLoadComplete();
3439 checkLoadCompleteForThisFrame();
3442 // Called every time a resource is completely loaded, or an error is received.
3443 void FrameLoader::checkLoadComplete()
3445 ASSERT(m_client->hasWebView());
3447 // FIXME: Always traversing the entire frame tree is a bit inefficient, but
3448 // is currently needed in order to null out the previous history item for all frames.
3449 if (Page* page = m_frame->page())
3450 page->mainFrame()->loader()->recursiveCheckLoadComplete();
3453 int FrameLoader::numPendingOrLoadingRequests(bool recurse) const
3456 return numRequests(m_frame->document());
3459 for (Frame* frame = m_frame; frame; frame = frame->tree()->traverseNext(m_frame))
3460 count += numRequests(frame->document());
3464 void FrameLoader::submitForm(const FrameLoadRequest& request, Event* event, bool lockHistory, bool lockBackForwardList)
3466 // FIXME: We'd like to remove this altogether and fix the multiple form submission issue another way.
3467 // We do not want to submit more than one form from the same page,
3468 // nor do we want to submit a single form more than once.
3469 // This flag prevents these from happening; not sure how other browsers prevent this.
3470 // The flag is reset in each time we start handle a new mouse or key down event, and
3471 // also in setView since this part may get reused for a page from the back/forward cache.
3472 // The form multi-submit logic here is only needed when we are submitting a form that affects this frame.
3473 // FIXME: Frame targeting is only one of the ways the submission could end up doing something other
3474 // than replacing this frame's content, so this check is flawed. On the other hand, the check is hardly
3475 // needed any more now that we reset m_submittedFormURL on each mouse or key down event.
3476 Frame* target = m_frame->tree()->find(request.frameName());
3477 if (m_frame->tree()->isDescendantOf(target)) {
3478 if (m_submittedFormURL == request.resourceRequest().url())
3480 m_submittedFormURL = request.resourceRequest().url();
3483 loadFrameRequestWithFormAndValues(request, lockHistory, lockBackForwardList, event, m_formAboutToBeSubmitted.get(), m_formValuesAboutToBeSubmitted);
3485 clearRecordedFormValues();
3488 String FrameLoader::userAgent(const KURL& url) const
3490 return m_client->userAgent(url);
3493 void FrameLoader::tokenizerProcessedData()
3495 // ASSERT(m_frame->page());
3496 // ASSERT(m_frame->document());
3501 void FrameLoader::handledOnloadEvents()
3503 m_client->dispatchDidHandleOnloadEvents();
3506 void FrameLoader::frameDetached()
3509 m_frame->document()->stopActiveDOMObjects();
3513 void FrameLoader::detachFromParent()
3515 RefPtr<Frame> protect(m_frame);
3519 saveScrollPositionAndViewStateToItem(currentHistoryItem());
3522 if (Page* page = m_frame->page())
3523 page->inspectorController()->frameDetachedFromParent(m_frame);
3525 m_client->detachedFromParent2();
3526 setDocumentLoader(0);
3527 m_client->detachedFromParent3();
3528 if (Frame* parent = m_frame->tree()->parent()) {
3529 parent->loader()->closeAndRemoveChild(m_frame);
3530 parent->loader()->scheduleCheckCompleted();
3532 m_frame->setView(0);
3533 m_frame->pageDestroyed();
3537 void FrameLoader::addExtraFieldsToSubresourceRequest(ResourceRequest& request)
3539 addExtraFieldsToRequest(request, m_loadType, false, false);
3542 void FrameLoader::addExtraFieldsToMainResourceRequest(ResourceRequest& request)
3544 addExtraFieldsToRequest(request, m_loadType, true, false);
3547 void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, FrameLoadType loadType, bool mainResource, bool cookiePolicyURLFromRequest)
3549 // Don't set the cookie policy URL if it's already been set.
3550 // But make sure to set it on all requests, as it has significance beyond the cookie policy for all protocols (<rdar://problem/6616664>).
3551 if (request.mainDocumentURL().isEmpty()) {
3552 if (mainResource && (isLoadingMainFrame() || cookiePolicyURLFromRequest))
3553 request.setMainDocumentURL(request.url());
3554 else if (Page* page = m_frame->page())
3555 request.setMainDocumentURL(page->mainFrame()->loader()->url());
3558 // The remaining modifications are only necessary for HTTP and HTTPS.
3559 if (!request.url().isEmpty() && !request.url().protocolInHTTPFamily())
3562 applyUserAgent(request);
3564 if (loadType == FrameLoadTypeReload) {
3565 request.setCachePolicy(ReloadIgnoringCacheData);
3566 request.setHTTPHeaderField("Cache-Control", "max-age=0");
3567 } else if (loadType == FrameLoadTypeReloadFromOrigin) {
3568 request.setCachePolicy(ReloadIgnoringCacheData);
3569 request.setHTTPHeaderField("Cache-Control", "no-cache");
3570 request.setHTTPHeaderField("Pragma", "no-cache");
3574 request.setHTTPAccept("application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5");
3576 // Make sure we send the Origin header.
3577 addHTTPOriginIfNeeded(request, String());
3579 // Always try UTF-8. If that fails, try frame encoding (if any) and then the default.
3580 // For a newly opened frame with an empty URL, encoding() should not be used, because this methods asks decoder, which uses ISO-8859-1.
3581 Settings* settings = m_frame->settings();
3582 request.setResponseContentDispositionEncodingFallbackArray("UTF-8", m_URL.isEmpty() ? m_encoding : encoding(), settings ? settings->defaultTextEncodingName() : String());
3585 void FrameLoader::addHTTPOriginIfNeeded(ResourceRequest& request, String origin)
3587 if (!request.httpOrigin().isEmpty())
3588 return; // Request already has an Origin header.
3590 // Don't send an Origin header for GET or HEAD to avoid privacy issues.
3591 // For example, if an intranet page has a hyperlink to an external web
3592 // site, we don't want to include the Origin of the request because it
3593 // will leak the internal host name. Similar privacy concerns have lead
3594 // to the widespread suppression of the Referer header at the network
3596 if (request.httpMethod() == "GET" || request.httpMethod() == "HEAD")
3599 // For non-GET and non-HEAD methods, always send an Origin header so the
3600 // server knows we support this feature.
3602 if (origin.isEmpty()) {
3603 // If we don't know what origin header to attach, we attach the value
3604 // for an empty origin.
3605 origin = SecurityOrigin::createEmpty()->toString();
3608 request.setHTTPOrigin(origin);
3611 void FrameLoader::committedLoad(DocumentLoader* loader, const char* data, int length)
3613 if (ArchiveFactory::isArchiveMimeType(loader->response().mimeType()))
3615 m_client->committedLoad(loader, data, length);
3618 void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType loadType, Event* event, PassRefPtr<FormState> prpFormState)
3620 RefPtr<FormState> formState = prpFormState;
3622 // When posting, use the NSURLRequestReloadIgnoringCacheData load flag.
3623 // This prevents a potential bug which may cause a page with a form that uses itself
3624 // as an action to be returned from the cache without submitting.
3626 // FIXME: Where's the code that implements what the comment above says?
3628 // Previously when this method was reached, the original FrameLoadRequest had been deconstructed to build a
3629 // bunch of parameters that would come in here and then be built back up to a ResourceRequest. In case
3630 // any caller depends on the immutability of the original ResourceRequest, I'm rebuilding a ResourceRequest
3631 // from scratch as it did all along.
3632 const KURL& url = inRequest.url();
3633 RefPtr<FormData> formData = inRequest.httpBody();
3634 const String& contentType = inRequest.httpContentType();
3635 String origin = inRequest.httpOrigin();
3637 ResourceRequest workingResourceRequest(url);
3639 if (!referrer.isEmpty())
3640 workingResourceRequest.setHTTPReferrer(referrer);
3641 workingResourceRequest.setHTTPOrigin(origin);
3642 workingResourceRequest.setHTTPMethod("POST");
3643 workingResourceRequest.setHTTPBody(formData);
3644 workingResourceRequest.setHTTPContentType(contentType);
3645 addExtraFieldsToRequest(workingResourceRequest, loadType, true, true);
3647 NavigationAction action(url, loadType, true, event);
3649 if (!frameName.isEmpty()) {
3650 if (Frame* targetFrame = findFrameForNavigation(frameName))
3651 targetFrame->loader()->loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, formState.release());
3653 checkNewWindowPolicy(action, workingResourceRequest, formState.release(), frameName);
3655 loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, formState.release());
3658 void FrameLoader::loadEmptyDocumentSynchronously()
3660 ResourceRequest request(KURL(""));
3661 load(request, false);
3664 unsigned long FrameLoader::loadResourceSynchronously(const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data)
3666 // Since this is a subresource, we can load any URL (we ignore the return value).
3667 // But we still want to know whether we should hide the referrer or not, so we call the canLoad method.
3668 String referrer = m_outgoingReferrer;
3669 if (shouldHideReferrer(request.url(), referrer))
3670 referrer = String();
3672 ResourceRequest initialRequest = request;
3673 initialRequest.setTimeoutInterval(10);
3675 if (initialRequest.isConditional())
3676 initialRequest.setCachePolicy(ReloadIgnoringCacheData);
3678 initialRequest.setCachePolicy(documentLoader()->request().cachePolicy());
3680 if (!referrer.isEmpty())
3681 initialRequest.setHTTPReferrer(referrer);
3682 addHTTPOriginIfNeeded(initialRequest, outgoingOrigin());
3684 if (Page* page = m_frame->page())
3685 initialRequest.setMainDocumentURL(page->mainFrame()->loader()->documentLoader()->request().url());
3686 initialRequest.setHTTPUserAgent(client()->userAgent(request.url()));
3688 unsigned long identifier = 0;
3689 ResourceRequest newRequest(initialRequest);
3690 requestFromDelegate(newRequest, identifier, error);
3692 if (error.isNull()) {
3693 ASSERT(!newRequest.isNull());
3695 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
3696 ApplicationCacheResource* resource;
3697 if (documentLoader()->shouldLoadResourceFromApplicationCache(newRequest, resource)) {
3699 response = resource->response();
3700 data.append(resource->data()->data(), resource->data()->size());
3702 error = cannotShowURLError(newRequest);
3705 ResourceHandle::loadResourceSynchronously(newRequest, error, response, data, m_frame);
3707 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
3708 // If normal loading results in a redirect to a resource with another origin (indicative of a captive portal), or a 4xx or 5xx status code or equivalent,
3709 // or if there were network errors (but not if the user canceled the download), then instead get, from the cache, the resource of the fallback entry
3710 // corresponding to the matched namespace.
3711 if ((!error.isNull() && !error.isCancellation())
3712 || response.httpStatusCode() / 100 == 4 || response.httpStatusCode() / 100 == 5
3713 || !protocolHostAndPortAreEqual(newRequest.url(), response.url())) {
3714 if (documentLoader()->getApplicationCacheFallbackResource(newRequest, resource)) {
3715 response = resource->response();
3717 data.append(resource->data()->data(), resource->data()->size());
3724 sendRemainingDelegateMessages(identifier, response, data.size(), error);
3728 void FrameLoader::assignIdentifierToInitialRequest(unsigned long identifier, const ResourceRequest& clientRequest)
3730 return dispatchAssignIdentifierToInitialRequest(identifier, activeDocumentLoader(), clientRequest);
3733 void FrameLoader::willSendRequest(ResourceLoader* loader, ResourceRequest& clientRequest, const ResourceResponse& redirectResponse)
3735 applyUserAgent(clientRequest);
3736 dispatchWillSendRequest(loader->documentLoader(), loader->identifier(), clientRequest, redirectResponse);
3739 void FrameLoader::didReceiveResponse(ResourceLoader* loader, const ResourceResponse& r)
3741 activeDocumentLoader()->addResponse(r);
3743 if (Page* page = m_frame->page())
3744 page->progress()->incrementProgress(loader->identifier(), r);
3745 dispatchDidReceiveResponse(loader->documentLoader(), loader->identifier(), r);
3748 void FrameLoader::didReceiveData(ResourceLoader* loader, const char* data, int length, int lengthReceived)
3750 if (Page* page = m_frame->page())
3751 page->progress()->incrementProgress(loader->identifier(), data, length);
3752 dispatchDidReceiveContentLength(loader->documentLoader(), loader->identifier(), lengthReceived);
3755 void FrameLoader::didFailToLoad(ResourceLoader* loader, const ResourceError& error)
3757 if (Page* page = m_frame->page())
3758 page->progress()->completeProgress(loader->identifier());
3759 if (!error.isNull())
3760 m_client->dispatchDidFailLoading(loader->documentLoader(), loader->identifier(), error);
3763 const ResourceRequest& FrameLoader::originalRequest() const
3765 return activeDocumentLoader()->originalRequestCopy();
3768 void FrameLoader::receivedMainResourceError(const ResourceError& error, bool isComplete)
3770 // Retain because the stop may release the last reference to it.
3771 RefPtr<Frame> protect(m_frame);
3773 RefPtr<DocumentLoader> loader = activeDocumentLoader();
3776 // FIXME: Don't want to do this if an entirely new load is going, so should check
3777 // that both data sources on the frame are either this or nil.
3779 if (m_client->shouldFallBack(error))
3780 handleFallbackContent();
3783 if (m_state == FrameStateProvisional && m_provisionalDocumentLoader) {
3784 KURL failedURL = m_provisionalDocumentLoader->originalRequestCopy().url();
3785 didNotOpenURL(failedURL);
3787 // We might have made a page cache item, but now we're bailing out due to an error before we ever
3788 // transitioned to the new page (before WebFrameState == commit). The goal here is to restore any state
3789 // so that the existing view (that wenever got far enough to replace) can continue being used.
3790 invalidateCurrentItemCachedPage();
3792 // Call clientRedirectCancelledOrFinished here so that the frame load delegate is notified that the redirect's
3793 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
3794 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are definitely
3795 // not going to use this provisional resource, as it was cancelled, notify the frame load delegate that the redirect
3797 if (m_sentRedirectNotification)
3798 clientRedirectCancelledOrFinished(false);
3802 loader->mainReceivedError(error, isComplete);
3805 void FrameLoader::callContinueFragmentScrollAfterNavigationPolicy(void* argument,
3806 const ResourceRequest& request, PassRefPtr<FormState>, bool shouldContinue)
3808 FrameLoader* loader = static_cast<FrameLoader*>(argument);
3809 loader->continueFragmentScrollAfterNavigationPolicy(request, shouldContinue);
3812 void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequest& request, bool shouldContinue)
3814 bool isRedirect = m_quickRedirectComing || m_policyLoadType == FrameLoadTypeRedirectWithLockedBackForwardList;
3815 m_quickRedirectComing = false;
3817 if (!shouldContinue)
3820 KURL url = request.url();
3822 m_documentLoader->replaceRequestURLForAnchorScroll(url);
3823 if (!isRedirect && !shouldTreatURLAsSameAsCurrent(url)) {
3824 // NB: must happen after _setURL, since we add based on the current request.
3825 // Must also happen before we openURL and displace the scroll position, since
3826 // adding the BF item will save away scroll state.
3828 // NB2: If we were loading a long, slow doc, and the user anchor nav'ed before
3829 // it was done, currItem is now set the that slow doc, and prevItem is whatever was
3830 // before it. Adding the b/f item will bump the slow doc down to prevItem, even
3831 // though its load is not yet done. I think this all works out OK, for one because
3832 // we have already saved away the scroll and doc state for the long slow load,
3833 // but it's not an obvious case.
3835 addHistoryItemForFragmentScroll();
3838 scrollToAnchor(url);
3841 // This will clear previousItem from the rest of the frame tree that didn't
3842 // doing any loading. We need to make a pass on this now, since for anchor nav
3843 // we'll not go through a real load and reach Completed state.
3844 checkLoadComplete();
3846 m_client->dispatchDidChangeLocationWithinPage();
3847 m_client->didFinishLoad();
3850 bool FrameLoader::shouldScrollToAnchor(bool isFormSubmission, FrameLoadType loadType, const KURL& url)
3852 // Should we do anchor navigation within the existing content?
3854 // We don't do this if we are submitting a form, explicitly reloading,
3855 // currently displaying a frameset, or if the URL does not have a fragment.
3856 // These rules were originally based on what KHTML was doing in KHTMLPart::openURL.
3858 // FIXME: What about load types other than Standard and Reload?
3860 return !isFormSubmission
3861 && loadType != FrameLoadTypeReload
3862 && loadType != FrameLoadTypeReloadFromOrigin
3863 && loadType != FrameLoadTypeSame
3864 && !shouldReload(this->url(), url)
3865 // We don't want to just scroll if a link from within a
3866 // frameset is trying to reload the frameset into _top.
3867 && !m_frame->document()->isFrameSet();
3870 void FrameLoader::checkNewWindowPolicy(const NavigationAction& action, const ResourceRequest& request,
3871 PassRefPtr<FormState> formState, const String& frameName)
3873 m_policyCheck.set(request, formState, frameName,
3874 callContinueLoadAfterNewWindowPolicy, this);
3875 m_client->dispatchDecidePolicyForNewWindowAction(&FrameLoader::continueAfterNewWindowPolicy,
3876 action, request, formState, frameName);
3879 void FrameLoader::continueAfterNewWindowPolicy(PolicyAction policy)
3881 PolicyCheck check = m_policyCheck;
3882 m_policyCheck.clear();
3886 check.clearRequest();
3888 case PolicyDownload:
3889 m_client->startDownload(check.request());
3890 check.clearRequest();
3896 check.call(policy == PolicyUse);
3899 void FrameLoader::checkNavigationPolicy(const ResourceRequest& request, DocumentLoader* loader,
3900 PassRefPtr<FormState> formState, NavigationPolicyDecisionFunction function, void* argument)
3902 NavigationAction action = loader->triggeringAction();
3903 if (action.isEmpty()) {
3904 action = NavigationAction(request.url(), NavigationTypeOther);
3905 loader->setTriggeringAction(action);
3908 // Don't ask more than once for the same request or if we are loading an empty URL.
3909 // This avoids confusion on the part of the client.
3910 if (equalIgnoringHeaderFields(request, loader->lastCheckedRequest()) || (!request.isNull() && request.url().isEmpty())) {
3911 function(argument, request, 0, true);
3912 loader->setLastCheckedRequest(request);
3916 // We are always willing to show alternate content for unreachable URLs;
3917 // treat it like a reload so it maintains the right state for b/f list.
3918 if (loader->substituteData().isValid() && !loader->substituteData().failingURL().isEmpty()) {
3919 if (isBackForwardLoadType(m_policyLoadType))
3920 m_policyLoadType = FrameLoadTypeReload;
3921 function(argument, request, 0, true);
3925 loader->setLastCheckedRequest(request);
3927 m_policyCheck.set(request, formState.get(), function, argument);
3929 m_delegateIsDecidingNavigationPolicy = true;
3930 m_client->dispatchDecidePolicyForNavigationAction(&FrameLoader::continueAfterNavigationPolicy,
3931 action, request, formState);
3932 m_delegateIsDecidingNavigationPolicy = false;
3935 void FrameLoader::continueAfterNavigationPolicy(PolicyAction policy)
3937 PolicyCheck check = m_policyCheck;
3938 m_policyCheck.clear();
3940 bool shouldContinue = policy == PolicyUse;
3944 check.clearRequest();
3946 case PolicyDownload:
3947 m_client->startDownload(check.request());
3948 check.clearRequest();
3951 ResourceRequest request(check.request());
3953 if (!m_client->canHandleRequest(request)) {
3954 handleUnimplementablePolicy(m_client->cannotShowURLError(check.request()));
3955 check.clearRequest();
3956 shouldContinue = false;
3962 check.call(shouldContinue);
3965 void FrameLoader::callContinueLoadAfterNavigationPolicy(void* argument,
3966 const ResourceRequest& request, PassRefPtr<FormState> formState, bool shouldContinue)
3968 FrameLoader* loader = static_cast<FrameLoader*>(argument);
3969 loader->continueLoadAfterNavigationPolicy(request, formState, shouldContinue);
3972 void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, PassRefPtr<FormState> formState, bool shouldContinue)
3974 // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
3975 // nil policyDataSource because loading the alternate page will have passed
3976 // through this method already, nested; otherwise, policyDataSource should still be set.
3977 ASSERT(m_policyDocumentLoader || !m_provisionalDocumentLoader->unreachableURL().isEmpty());
3979 bool isTargetItem = m_provisionalHistoryItem ? m_provisionalHistoryItem->isTargetItem() : false;
3981 // Two reasons we can't continue:
3982 // 1) Navigation policy delegate said we can't so request is nil. A primary case of this
3983 // is the user responding Cancel to the form repost nag sheet.
3984 // 2) User responded Cancel to an alert popped up by the before unload event handler.
3985 // The "before unload" event handler runs only for the main frame.
3986 bool canContinue = shouldContinue && (!isLoadingMainFrame() || m_frame->shouldClose());
3989 // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we
3990 // need to report that the client redirect was cancelled.
3991 if (m_quickRedirectComing)
3992 clientRedirectCancelledOrFinished(false);
3994 setPolicyDocumentLoader(0);
3996 // If the navigation request came from the back/forward menu, and we punt on it, we have the
3997 // problem that we have optimistically moved the b/f cursor already, so move it back. For sanity,
3998 // we only do this when punting a navigation for the target frame or top-level frame.
3999 if ((isTargetItem || isLoadingMainFrame()) && isBackForwardLoadType(m_policyLoadType))
4000 if (Page* page = m_frame->page()) {
4001 Frame* mainFrame = page->mainFrame();
4002 if (HistoryItem* resetItem = mainFrame->loader()->m_currentHistoryItem.get()) {
4003 page->backForwardList()->goToItem(resetItem);
4004 Settings* settings = m_frame->settings();
4005 page->setGlobalHistoryItem((!settings || settings->privateBrowsingEnabled()) ? 0 : resetItem);
4011 FrameLoadType type = m_policyLoadType;
4014 // <rdar://problem/6250856> - In certain circumstances on pages with multiple frames, stopAllLoaders()
4015 // might detach the current FrameLoader, in which case we should bail on this newly defunct load.
4016 if (!m_frame->page())
4019 setProvisionalDocumentLoader(m_policyDocumentLoader.get());
4021 setState(FrameStateProvisional);
4023 setPolicyDocumentLoader(0);
4025 if (isBackForwardLoadType(type) && loadProvisionalItemFromCachedPage())
4029 m_client->dispatchWillSubmitForm(&FrameLoader::continueLoadAfterWillSubmitForm, formState);
4031 continueLoadAfterWillSubmitForm();
4035 void FrameLoader::callContinueLoadAfterNewWindowPolicy(void* argument,
4036 const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, bool shouldContinue)
4038 FrameLoader* loader = static_cast<FrameLoader*>(argument);
4039 loader->continueLoadAfterNewWindowPolicy(request, formState, frameName, shouldContinue);
4042 void FrameLoader::continueLoadAfterNewWindowPolicy(const ResourceRequest& request,
4043 PassRefPtr<FormState> formState, const String& frameName, bool shouldContinue)
4045 if (!shouldContinue)
4048 RefPtr<Frame> frame = m_frame;
4049 RefPtr<Frame> mainFrame = m_client->dispatchCreatePage();
4053 if (frameName != "_blank")
4054 mainFrame->tree()->setName(frameName);
4056 mainFrame->loader()->setOpenedByDOM();
4057 mainFrame->loader()->m_client->dispatchShow();
4058 mainFrame->loader()->setOpener(frame.get());
4059 mainFrame->loader()->loadWithNavigationAction(request, NavigationAction(), false, FrameLoadTypeStandard, formState);
4062 void FrameLoader::sendRemainingDelegateMessages(unsigned long identifier, const ResourceResponse& response, int length, const ResourceError& error)
4064 if (!response.isNull())
4065 dispatchDidReceiveResponse(m_documentLoader.get(), identifier, response);
4068 dispatchDidReceiveContentLength(m_documentLoader.get(), identifier, length);
4071 dispatchDidFinishLoading(m_documentLoader.get(), identifier);
4073 m_client->dispatchDidFailLoading(m_documentLoader.get(), identifier, error);
4076 void FrameLoader::requestFromDelegate(ResourceRequest& request, unsigned long& identifier, ResourceError& error)
4078 ASSERT(!request.isNull());
4081 if (Page* page = m_frame->page()) {
4082 identifier = page->progress()->createUniqueIdentifier();
4083 dispatchAssignIdentifierToInitialRequest(identifier, m_documentLoader.get(), request);
4086 ResourceRequest newRequest(request);
4087 dispatchWillSendRequest(m_documentLoader.get(), identifier, newRequest, ResourceResponse());
4089 if (newRequest.isNull())
4090 error = cancelledError(request);
4092 error = ResourceError();
4094 request = newRequest;
4097 void FrameLoader::loadedResourceFromMemoryCache(const CachedResource* resource)
4099 Page* page = m_frame->page();
4103 page->inspectorController()->didLoadResourceFromMemoryCache(m_documentLoader.get(), resource);
4105 if (!resource->sendResourceLoadCallbacks() || m_documentLoader->haveToldClientAboutLoad(resource->url()))
4108 if (!page->areMemoryCacheClientCallsEnabled()) {
4109 m_documentLoader->recordMemoryCacheLoadForFutureClientNotification(resource->url());
4110 m_documentLoader->didTellClientAboutLoad(resource->url());
4114 ResourceRequest request(resource->url());
4115 if (m_client->dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(), request, resource->response(), resource->encodedSize())) {
4116 m_documentLoader->didTellClientAboutLoad(resource->url());
4120 unsigned long identifier;
4121 ResourceError error;
4122 requestFromDelegate(request, identifier, error);
4123 sendRemainingDelegateMessages(identifier, resource->response(), resource->encodedSize(), error);
4126 void FrameLoader::applyUserAgent(ResourceRequest& request)
4128 String userAgent = client()->userAgent(request.url());
4129 ASSERT(!userAgent.isNull());
4130 request.setHTTPUserAgent(userAgent);
4133 bool FrameLoader::canGoBackOrForward(int distance) const
4135 if (Page* page = m_frame->page()) {
4138 if (distance > 0 && distance <= page->backForwardList()->forwardListCount())
4140 if (distance < 0 && -distance <= page->backForwardList()->backListCount())
4146 int FrameLoader::getHistoryLength()
4148 if (Page* page = m_frame->page())
4149 return page->backForwardList()->backListCount() + 1;
4153 KURL FrameLoader::historyURL(int distance)
4155 if (Page* page = m_frame->page()) {
4156 BackForwardList* list = page->backForwardList();
4157 HistoryItem* item = list->itemAtIndex(distance);
4160 int forwardListCount = list->forwardListCount();
4161 if (forwardListCount > 0)
4162 item = list->itemAtIndex(forwardListCount);
4164 int backListCount = list->backListCount();
4165 if (backListCount > 0)
4166 item = list->itemAtIndex(-backListCount);
4175 void FrameLoader::addHistoryItemForFragmentScroll()
4177 addBackForwardItemClippedAtTarget(false);
4180 bool FrameLoader::loadProvisionalItemFromCachedPage()
4182 RefPtr<CachedPage> cachedPage = pageCache()->get(m_provisionalHistoryItem.get());
4183 if (!cachedPage || !cachedPage->document())
4185 provisionalDocumentLoader()->loadFromCachedPage(cachedPage.release());
4189 void FrameLoader::cachePageForHistoryItem(HistoryItem* item)
4191 if (!canCachePage() || item->isInPageCache())
4194 if (Page* page = m_frame->page()) {
4195 RefPtr<CachedPage> cachedPage = CachedPage::create(page);
4196 pageCache()->add(item, cachedPage.release());
4200 bool FrameLoader::shouldTreatURLAsSameAsCurrent(const KURL& url) const
4202 if (!m_currentHistoryItem)
4204 return url == m_currentHistoryItem->url() || url == m_currentHistoryItem->originalURL();
4207 PassRefPtr<HistoryItem> FrameLoader::createHistoryItem(bool useOriginal)
4209 DocumentLoader* docLoader = documentLoader();
4211 KURL unreachableURL = docLoader ? docLoader->unreachableURL() : KURL();
4216 if (!unreachableURL.isEmpty()) {
4217 url = unreachableURL;
4218 originalURL = unreachableURL;
4220 originalURL = docLoader ? docLoader->originalURL() : KURL();
4224 url = docLoader->requestURL();