2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
3 * Copyright (C) 2007 Trolltech ASA
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "FrameLoader.h"
35 #include "CachedPage.h"
37 #include "DOMImplementation.h"
38 #include "DocLoader.h"
40 #include "DocumentLoader.h"
41 #include "EditCommand.h"
43 #include "EditorClient.h"
46 #include "EventNames.h"
47 #include "FloatRect.h"
48 #include "FormState.h"
50 #include "FrameLoadRequest.h"
51 #include "FrameLoaderClient.h"
52 #include "FramePrivate.h"
53 #include "FrameTree.h"
54 #include "FrameView.h"
55 #include "HTMLFormElement.h"
56 #include "HTMLFrameElement.h"
57 #include "HTMLNames.h"
58 #include "HTMLObjectElement.h"
59 #include "HTTPParsers.h"
60 #include "HistoryItem.h"
61 #include "IconDatabase.h"
62 #include "IconLoader.h"
63 #include "InspectorController.h"
65 #include "MainResourceLoader.h"
66 #include "MIMETypeRegistry.h"
68 #include "PageCache.h"
69 #include "ProgressTracker.h"
70 #include "RenderPart.h"
71 #include "RenderWidget.h"
72 #include "ResourceHandle.h"
73 #include "ResourceRequest.h"
74 #include "SegmentedString.h"
76 #include "SystemTime.h"
77 #include "TextResourceDecoder.h"
78 #include "WindowFeatures.h"
79 #include "XMLHttpRequest.h"
80 #include "XMLTokenizer.h"
81 #include "kjs_binding.h"
82 #include "kjs_proxy.h"
83 #include "kjs_window.h"
84 #include <kjs/JSLock.h>
85 #include <kjs/object.h>
93 using namespace HTMLNames;
94 using namespace EventNames;
96 #if USE(LOW_BANDWIDTH_DISPLAY)
97 const unsigned int cMaxPendingSourceLengthInLowBandwidthDisplay = 128 * 1024;
100 struct FormSubmission {
103 RefPtr<FormData> data;
109 FormSubmission(const char* a, const String& u, PassRefPtr<FormData> d, const String& t,
110 const String& ct, const String& b, PassRefPtr<Event> e)
122 struct ScheduledRedirection {
123 enum Type { redirection, locationChange, historyNavigation, locationChangeDuringLoad };
132 ScheduledRedirection(double redirectDelay, const String& redirectURL, bool redirectLockHistory, bool userGesture)
134 , delay(redirectDelay)
137 , lockHistory(redirectLockHistory)
138 , wasUserGesture(userGesture)
142 ScheduledRedirection(Type locationChangeType,
143 const String& locationChangeURL, const String& locationChangeReferrer,
144 bool locationChangeLockHistory, bool locationChangeWasUserGesture)
145 : type(locationChangeType)
147 , URL(locationChangeURL)
148 , referrer(locationChangeReferrer)
150 , lockHistory(locationChangeLockHistory)
151 , wasUserGesture(locationChangeWasUserGesture)
155 explicit ScheduledRedirection(int historyNavigationSteps)
156 : type(historyNavigation)
158 , historySteps(historyNavigationSteps)
160 , wasUserGesture(false)
165 static double storedTimeOfLastCompletedLoad;
166 static bool m_restrictAccessToLocal = false;
168 static bool getString(JSValue* result, String& string)
174 if (!result->getString(ustring))
180 bool isBackForwardLoadType(FrameLoadType type)
183 case FrameLoadTypeStandard:
184 case FrameLoadTypeReload:
185 case FrameLoadTypeReloadAllowingStaleData:
186 case FrameLoadTypeSame:
187 case FrameLoadTypeRedirectWithLockedHistory:
188 case FrameLoadTypeReplace:
190 case FrameLoadTypeBack:
191 case FrameLoadTypeForward:
192 case FrameLoadTypeIndexedBackForward:
195 ASSERT_NOT_REACHED();
199 static int numRequests(Document* document)
204 return document->docLoader()->requestCount();
207 FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client)
210 , m_state(FrameStateCommittedPage)
211 , m_loadType(FrameLoadTypeStandard)
212 , m_policyLoadType(FrameLoadTypeStandard)
213 , m_delegateIsHandlingProvisionalLoadError(false)
214 , m_delegateIsDecidingNavigationPolicy(false)
215 , m_delegateIsHandlingUnimplementablePolicy(false)
216 , m_firstLayoutDone(false)
217 , m_quickRedirectComing(false)
218 , m_sentRedirectNotification(false)
219 , m_inStopAllLoaders(false)
220 , m_cachePolicy(CachePolicyVerify)
221 , m_isExecutingJavaScriptFormAction(false)
222 , m_isRunningScript(false)
223 , m_didCallImplicitClose(false)
224 , m_wasUnloadEventEmitted(false)
225 , m_isComplete(false)
226 , m_isLoadingMainResource(false)
227 , m_cancellingWithLoadInProgress(false)
228 , m_needsClear(false)
229 , m_shouldClearWindowProperties(true)
230 , m_receivedData(false)
231 , m_encodingWasChosenByUser(false)
232 , m_containsPlugIns(false)
233 , m_redirectionTimer(this, &FrameLoader::redirectionTimerFired)
234 , m_checkCompletedTimer(this, &FrameLoader::checkCompletedTimerFired)
236 , m_openedByDOM(false)
237 , m_creatingInitialEmptyDocument(false)
238 , m_committedFirstRealDocumentLoad(false)
239 #if USE(LOW_BANDWIDTH_DISPLAY)
240 , m_useLowBandwidthDisplay(true)
241 , m_finishedParsingDuringLowBandwidthDisplay(false)
242 , m_needToSwitchOutLowBandwidthDisplay(false)
247 FrameLoader::~FrameLoader()
251 HashSet<Frame*>::iterator end = m_openedFrames.end();
252 for (HashSet<Frame*>::iterator it = m_openedFrames.begin(); it != end; ++it)
253 (*it)->loader()->m_opener = 0;
255 m_client->frameLoaderDestroyed();
258 void FrameLoader::init()
260 // this somewhat odd set of steps is needed to give the frame an initial empty document
261 m_creatingInitialEmptyDocument = true;
262 setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(String("")), SubstituteData()).get());
263 setProvisionalDocumentLoader(m_policyDocumentLoader.get());
264 setState(FrameStateProvisional);
265 m_provisionalDocumentLoader->setResponse(ResourceResponse(KURL(), "text/html", 0, String(), String()));
266 m_provisionalDocumentLoader->finishedLoading();
268 write("<html><body>");
270 m_frame->document()->cancelParsing();
271 m_creatingInitialEmptyDocument = false;
272 m_didCallImplicitClose = true;
275 void FrameLoader::setDefersLoading(bool defers)
277 if (m_documentLoader)
278 m_documentLoader->setDefersLoading(defers);
279 if (m_provisionalDocumentLoader)
280 m_provisionalDocumentLoader->setDefersLoading(defers);
281 if (m_policyDocumentLoader)
282 m_policyDocumentLoader->setDefersLoading(defers);
283 m_client->setDefersLoading(defers);
286 Frame* FrameLoader::createWindow(const FrameLoadRequest& request, const WindowFeatures& features, bool& created)
288 ASSERT(!features.dialog || request.frameName().isEmpty());
290 if (!request.frameName().isEmpty() && request.frameName() != "_blank")
291 if (Frame* frame = m_frame->tree()->find(request.frameName())) {
292 if (!request.resourceRequest().url().isEmpty())
293 frame->loader()->load(request, false, true, 0, 0, HashMap<String, String>());
294 if (Page* page = frame->page())
295 page->chrome()->focus();
300 // FIXME: Setting the referrer should be the caller's responsibility.
301 FrameLoadRequest requestWithReferrer = request;
302 requestWithReferrer.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
304 Page* page = m_frame->page();
307 page = page->chrome()->createModalDialog(m_frame, requestWithReferrer);
309 page = page->chrome()->createWindow(m_frame, requestWithReferrer);
314 Frame* frame = page->mainFrame();
315 if (request.frameName() != "_blank")
316 frame->tree()->setName(request.frameName());
318 frame->loader()->setShouldClearWindowProperties(false);
320 page->chrome()->setToolbarsVisible(features.toolBarVisible || features.locationBarVisible);
321 page->chrome()->setStatusbarVisible(features.statusBarVisible);
322 page->chrome()->setScrollbarsVisible(features.scrollbarsVisible);
323 page->chrome()->setMenubarVisible(features.menuBarVisible);
324 page->chrome()->setResizable(features.resizable);
326 // 'x' and 'y' specify the location of the window, while 'width' and 'height'
327 // specify the size of the page. We can only resize the window, so
328 // adjust for the difference between the window size and the page size.
330 FloatRect windowRect = page->chrome()->windowRect();
331 FloatSize pageSize = page->chrome()->pageRect().size();
333 windowRect.setX(features.x);
335 windowRect.setY(features.y);
336 if (features.widthSet)
337 windowRect.setWidth(features.width + (windowRect.width() - pageSize.width()));
338 if (features.heightSet)
339 windowRect.setHeight(features.height + (windowRect.height() - pageSize.height()));
340 page->chrome()->setWindowRect(windowRect);
342 page->chrome()->show();
348 bool FrameLoader::canHandleRequest(const ResourceRequest& request)
350 return m_client->canHandleRequest(request);
353 void FrameLoader::changeLocation(const String& URL, const String& referrer, bool lockHistory, bool userGesture)
355 changeLocation(completeURL(URL), referrer, lockHistory, userGesture);
358 void FrameLoader::changeLocation(const KURL& URL, const String& referrer, bool lockHistory, bool userGesture)
360 if (URL.url().find("javascript:", 0, false) == 0) {
361 String script = KURL::decode_string(URL.url().mid(strlen("javascript:")));
362 JSValue* result = executeScript(script, userGesture);
364 if (getString(result, scriptResult)) {
372 ResourceRequestCachePolicy policy = (m_cachePolicy == CachePolicyReload) || (m_cachePolicy == CachePolicyRefresh)
373 ? ReloadIgnoringCacheData : UseProtocolCachePolicy;
374 ResourceRequest request(URL, referrer, policy);
376 urlSelected(request, "_self", 0, lockHistory, userGesture);
379 void FrameLoader::urlSelected(const ResourceRequest& request, const String& _target, Event* triggeringEvent, bool lockHistory, bool userGesture)
381 String target = _target;
382 if (target.isEmpty() && m_frame->document())
383 target = m_frame->document()->baseTarget();
385 const KURL& url = request.url();
386 if (url.url().startsWith("javascript:", false)) {
387 executeScript(KURL::decode_string(url.url().mid(strlen("javascript:"))), true);
391 if (!url.isValid() && !url.isEmpty())
394 FrameLoadRequest frameRequest(request, target);
396 if (frameRequest.resourceRequest().httpReferrer().isEmpty())
397 frameRequest.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
399 urlSelected(frameRequest, triggeringEvent, lockHistory, userGesture);
402 bool FrameLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String& urlString, const AtomicString& frameName)
404 #if USE(LOW_BANDWIDTH_DISPLAY)
405 // don't create sub-frame during low bandwidth display
406 if (frame()->document()->inLowBandwidthDisplay()) {
407 m_needToSwitchOutLowBandwidthDisplay = true;
412 // Support for <frame src="javascript:string">
415 if (urlString.startsWith("javascript:", false)) {
416 scriptURL = urlString.deprecatedString();
419 url = completeURL(urlString);
421 Frame* frame = m_frame->tree()->child(frameName);
423 frame->loader()->scheduleLocationChange(url.url(), m_outgoingReferrer, true, userGestureHint());
425 frame = loadSubframe(ownerElement, url, frameName, m_outgoingReferrer);
430 if (!scriptURL.isEmpty())
431 frame->loader()->replaceContentsWithScriptResult(scriptURL);
436 Frame* FrameLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const String& name, const String& referrer)
438 bool allowsScrolling = true;
439 int marginWidth = -1;
440 int marginHeight = -1;
441 if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag)) {
442 HTMLFrameElementBase* o = static_cast<HTMLFrameElementBase*>(ownerElement);
443 allowsScrolling = o->scrollingMode() != ScrollbarAlwaysOff;
444 marginWidth = o->getMarginWidth();
445 marginHeight = o->getMarginHeight();
448 if (!canLoad(url, referrer)) {
449 FrameLoader::reportLocalLoadFailed(m_frame->page(), url.url());
453 bool hideReferrer = shouldHideReferrer(url, referrer);
454 Frame* frame = m_client->createFrame(url, name, ownerElement, hideReferrer ? String() : referrer,
455 allowsScrolling, marginWidth, marginHeight);
458 checkCallImplicitClose();
462 frame->loader()->m_isComplete = false;
464 if (ownerElement->renderer() && frame->view())
465 static_cast<RenderWidget*>(ownerElement->renderer())->setWidget(frame->view());
467 checkCallImplicitClose();
469 // In these cases, the synchronous load would have finished
470 // before we could connect the signals, so make sure to send the
471 // completed() signal for the child by hand
472 // FIXME: In this case the Frame will have finished loading before
473 // it's being added to the child list. It would be a good idea to
474 // create the child first, then invoke the loader separately.
475 if (url.isEmpty() || url == "about:blank") {
476 frame->loader()->completed();
477 frame->loader()->checkCompleted();
483 void FrameLoader::submitFormAgain()
485 if (m_isRunningScript)
487 OwnPtr<FormSubmission> form(m_deferredFormSubmission.release());
489 submitForm(form->action, form->URL, form->data, form->target,
490 form->contentType, form->boundary, form->event.get());
493 void FrameLoader::submitForm(const char* action, const String& url, PassRefPtr<FormData> formData,
494 const String& target, const String& contentType, const String& boundary, Event* event)
496 ASSERT(formData.get());
498 KURL u = completeURL(url.isNull() ? "" : url);
502 DeprecatedString urlString = u.url();
503 if (urlString.startsWith("javascript:", false)) {
504 m_isExecutingJavaScriptFormAction = true;
505 executeScript(KURL::decode_string(urlString.mid(strlen("javascript:"))));
506 m_isExecutingJavaScriptFormAction = false;
510 if (m_isRunningScript) {
511 if (m_deferredFormSubmission)
513 m_deferredFormSubmission.set(new FormSubmission(action, url, formData, target,
514 contentType, boundary, event));
518 FrameLoadRequest frameRequest;
520 if (!m_outgoingReferrer.isEmpty())
521 frameRequest.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
523 frameRequest.setFrameName(target.isEmpty() ? m_frame->document()->baseTarget() : target);
525 // Handle mailto: forms
526 bool mailtoForm = u.protocol() == "mailto";
530 if (equalIgnoringCase(contentType, "multipart/form-data"))
531 // FIXME: is this correct? I suspect not, but what site can we test this on?
532 body = formData->flattenToString();
533 else if (equalIgnoringCase(contentType, "text/plain"))
534 // Convention seems to be to decode, and s/&/\n/
535 body = KURL::decode_string(
536 formData->flattenToString().replace('&', '\n')
537 .replace('+', ' ').deprecatedString()); // Recode for the URL
539 body = formData->flattenToString();
541 String query = u.query();
542 if (!query.isEmpty())
544 u.setQuery((query + "body=" + KURL::encode_string(body.deprecatedString())).deprecatedString());
547 if (strcmp(action, "GET") == 0) {
549 u.setQuery(formData->flattenToString().deprecatedString());
551 frameRequest.resourceRequest().setHTTPBody(formData.get());
552 frameRequest.resourceRequest().setHTTPMethod("POST");
554 // construct some user headers if necessary
555 if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
556 frameRequest.resourceRequest().setHTTPContentType(contentType);
557 else // contentType must be "multipart/form-data"
558 frameRequest.resourceRequest().setHTTPContentType(contentType + "; boundary=" + boundary);
561 frameRequest.resourceRequest().setURL(u);
563 submitForm(frameRequest, event);
566 void FrameLoader::stopLoading(bool sendUnload)
568 if (m_frame->document() && m_frame->document()->tokenizer())
569 m_frame->document()->tokenizer()->stopParsing();
572 if (m_frame->document()) {
573 if (m_didCallImplicitClose && !m_wasUnloadEventEmitted) {
574 Node* currentFocusedNode = m_frame->document()->focusedNode();
575 if (currentFocusedNode)
576 currentFocusedNode->aboutToUnload();
577 m_frame->document()->dispatchWindowEvent(unloadEvent, false, false);
578 if (m_frame->document())
579 m_frame->document()->updateRendering();
580 m_wasUnloadEventEmitted = true;
583 if (m_frame->document() && !m_frame->document()->inPageCache())
584 m_frame->document()->removeAllEventListenersFromAllNodes();
587 m_isComplete = true; // to avoid calling completed() in finishedParsing() (David)
588 m_isLoadingMainResource = false;
589 m_didCallImplicitClose = true; // don't want that one either
590 m_cachePolicy = CachePolicyVerify; // Why here?
592 if (m_frame->document() && m_frame->document()->parsing()) {
594 m_frame->document()->setParsing(false);
597 m_workingURL = KURL();
599 if (Document* doc = m_frame->document()) {
600 if (DocLoader* docLoader = doc->docLoader())
601 cache()->loader()->cancelRequests(docLoader);
602 XMLHttpRequest::cancelRequests(doc);
605 // tell all subframes to stop as well
606 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
607 child->loader()->stopLoading(sendUnload);
611 #if USE(LOW_BANDWIDTH_DISPLAY)
612 if (m_frame->document() && m_frame->document()->inLowBandwidthDisplay()) {
613 // Since loading is forced to stop, reset the state without really switching.
614 m_needToSwitchOutLowBandwidthDisplay = false;
615 switchOutLowBandwidthDisplayIfReady();
620 void FrameLoader::stop()
622 // http://bugs.webkit.org/show_bug.cgi?id=10854
623 // The frame's last ref may be removed and it will be deleted by checkCompleted().
624 RefPtr<Frame> protector(m_frame);
626 if (m_frame->document()) {
627 if (m_frame->document()->tokenizer())
628 m_frame->document()->tokenizer()->stopParsing();
629 m_frame->document()->finishParsing();
631 // WebKit partially uses WebCore when loading non-HTML docs. In these cases doc==nil, but
632 // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to
633 // become true. An example is when a subframe is a pure text doc, and that subframe is the
634 // last one to complete.
637 m_iconLoader->stopLoading();
640 bool FrameLoader::closeURL()
644 m_frame->editor()->clearUndoRedoOperations();
648 void FrameLoader::cancelRedirection(bool cancelWithLoadInProgress)
650 m_cancellingWithLoadInProgress = cancelWithLoadInProgress;
652 stopRedirectionTimer();
654 m_scheduledRedirection.clear();
657 KURL FrameLoader::iconURL()
659 // If this isn't a top level frame, return nothing
660 if (m_frame->tree() && m_frame->tree()->parent())
663 // If we have an iconURL from a Link element, return that
664 if (m_frame->document() && !m_frame->document()->iconURL().isEmpty())
665 return m_frame->document()->iconURL().deprecatedString();
667 // Don't return a favicon iconURL unless we're http or https
668 if (m_URL.protocol() != "http" && m_URL.protocol() != "https")
672 url.setProtocol(m_URL.protocol());
673 url.setHost(m_URL.host());
674 if (int port = m_URL.port())
676 url.setPath("/favicon.ico");
680 bool FrameLoader::didOpenURL(const KURL& url)
682 if (m_scheduledRedirection && m_scheduledRedirection->type == ScheduledRedirection::locationChangeDuringLoad)
683 // A redirect was scheduled before the document was created.
684 // This can happen when one frame changes another frame's location.
688 m_frame->editor()->setLastEditCommand(0);
691 m_isComplete = false;
692 m_isLoadingMainResource = true;
693 m_didCallImplicitClose = false;
695 m_frame->setJSStatusBarText(String());
696 m_frame->setJSDefaultStatusBarText(String());
699 if (m_URL.protocol().startsWith("http") && !m_URL.host().isEmpty() && m_URL.path().isEmpty())
701 m_workingURL = m_URL;
708 void FrameLoader::didExplicitOpen()
710 m_isComplete = false;
711 m_didCallImplicitClose = false;
713 // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
714 // from a subsequent window.document.open / window.document.write call.
715 // Cancelling redirection here works for all cases because document.open
716 // implicitly precedes document.write.
718 if (m_frame->document()->URL() != "about:blank")
719 m_URL = m_frame->document()->URL();
722 void FrameLoader::replaceContentsWithScriptResult(const KURL& url)
724 JSValue* result = executeScript(KURL::decode_string(url.url().mid(strlen("javascript:"))));
726 if (!getString(result, scriptResult))
733 JSValue* FrameLoader::executeScript(const String& script, bool forceUserGesture)
735 return executeScript(forceUserGesture ? String() : String(m_URL.url()), 0, script);
738 JSValue* FrameLoader::executeScript(const String& URL, int baseLine, const String& script)
740 KJSProxy* proxy = m_frame->scriptProxy();
744 bool wasRunningScript = m_isRunningScript;
745 m_isRunningScript = true;
747 JSValue* result = proxy->evaluate(URL, baseLine, script);
749 if (!wasRunningScript) {
750 m_isRunningScript = false;
752 Document::updateDocumentsRendering();
758 void FrameLoader::cancelAndClear()
768 void FrameLoader::clear(bool clearWindowProperties)
770 // FIXME: Commenting out the below line causes <http://bugs.webkit.org/show_bug.cgi?id=11212>, but putting it
771 // back causes a measurable performance regression which we will need to fix to restore the correct behavior
772 // urlsBridgeKnowsAbout.clear();
775 m_frame->setMarkedTextRange(0, nil, nil);
780 m_needsClear = false;
782 if (m_frame->document()) {
783 m_frame->document()->cancelParsing();
784 m_frame->document()->willRemove();
785 m_frame->document()->detach();
788 // Do this after detaching the document so that the unload event works.
789 if (clearWindowProperties && m_shouldClearWindowProperties) {
790 m_frame->clearScriptProxy();
791 m_frame->clearDOMWindow();
794 m_frame->selectionController()->clear();
795 m_frame->eventHandler()->clear();
797 m_frame->view()->clear();
799 // Do not drop the document before the script proxy and view are cleared, as some destructors
800 // might still try to access the document.
801 m_frame->setDocument(0);
804 m_containsPlugIns = false;
805 m_frame->cleanupScriptObjects();
807 m_redirectionTimer.stop();
808 m_scheduledRedirection.clear();
810 m_checkCompletedTimer.stop();
812 m_receivedData = false;
814 if (!m_encodingWasChosenByUser)
815 m_encoding = String();
818 void FrameLoader::receivedFirstData()
820 begin(m_workingURL, false);
822 dispatchDidCommitLoad();
823 dispatchWindowObjectAvailable();
825 String ptitle = m_documentLoader->title();
826 // If we have a title let the WebView know about it.
827 if (!ptitle.isNull())
828 m_client->dispatchDidReceiveTitle(ptitle);
830 m_frame->document()->docLoader()->setCachePolicy(m_cachePolicy);
831 m_workingURL = KURL();
835 if (!m_documentLoader)
837 if (!parseHTTPRefresh(m_documentLoader->response().httpHeaderField("Refresh"), false, delay, URL))
843 URL = m_frame->document()->completeURL(URL);
845 scheduleHTTPRedirection(delay, URL);
848 const String& FrameLoader::responseMIMEType() const
850 return m_responseMIMEType;
853 void FrameLoader::setResponseMIMEType(const String& type)
855 m_responseMIMEType = type;
858 void FrameLoader::begin()
863 void FrameLoader::begin(const KURL& url, bool dispatch)
867 dispatchWindowObjectAvailable();
870 m_shouldClearWindowProperties = true;
871 m_isComplete = false;
872 m_didCallImplicitClose = false;
873 m_isLoadingMainResource = true;
876 ref.setUser(DeprecatedString());
877 ref.setPass(DeprecatedString());
878 ref.setRef(DeprecatedString());
879 m_outgoingReferrer = ref.url();
883 if (!m_URL.isEmpty())
886 RefPtr<Document> document = DOMImplementation::instance()->createDocument(m_responseMIMEType, m_frame, m_frame->inViewSourceMode());
887 m_frame->setDocument(document);
889 document->setURL(m_URL.url());
890 // We prefer m_baseURL over m_URL because m_URL changes when we are
891 // about to load a new page.
892 document->setBaseURL(baseurl.url());
894 document->setDecoder(m_decoder.get());
896 updatePolicyBaseURL();
898 Settings* settings = document->settings();
899 document->docLoader()->setAutoLoadImages(settings && settings->loadsImagesAutomatically());
900 KURL userStyleSheet = settings ? settings->userStyleSheetLocation() : KURL();
901 if (!userStyleSheet.isEmpty())
902 m_frame->setUserStyleSheetLocation(userStyleSheet);
904 restoreDocumentState();
906 document->implicitOpen();
909 m_frame->view()->resizeContents(0, 0);
911 #if USE(LOW_BANDWIDTH_DISPLAY)
912 // Low bandwidth display is a first pass display without external resources
913 // used to give an instant visual feedback. We currently only enable it for
914 // HTML documents in the top frame.
915 if (document->isHTMLDocument() && !m_frame->tree()->parent() && m_useLowBandwidthDisplay) {
916 m_pendingSourceInLowBandwidthDisplay = String();
917 m_finishedParsingDuringLowBandwidthDisplay = false;
918 m_needToSwitchOutLowBandwidthDisplay = false;
919 document->setLowBandwidthDisplay(true);
924 void FrameLoader::write(const char* str, int len, bool flush)
926 if (len == 0 && !flush)
932 Tokenizer* tokenizer = m_frame->document()->tokenizer();
933 if (tokenizer && tokenizer->wantsRawData()) {
935 tokenizer->writeRawData(str, len);
940 Settings* settings = m_frame->settings();
941 m_decoder = new TextResourceDecoder(m_responseMIMEType, settings ? settings->defaultTextEncodingName() : String());
942 if (!m_encoding.isNull())
943 m_decoder->setEncoding(m_encoding,
944 m_encodingWasChosenByUser ? TextResourceDecoder::UserChosenEncoding : TextResourceDecoder::EncodingFromHTTPHeader);
945 if (m_frame->document())
946 m_frame->document()->setDecoder(m_decoder.get());
949 String decoded = m_decoder->decode(str, len);
951 decoded += m_decoder->flush();
952 if (decoded.isEmpty())
955 #if USE(LOW_BANDWIDTH_DISPLAY)
956 if (m_frame->document()->inLowBandwidthDisplay())
957 m_pendingSourceInLowBandwidthDisplay.append(decoded);
958 else // reset policy which is changed in switchOutLowBandwidthDisplayIfReady()
959 m_frame->document()->docLoader()->setCachePolicy(m_cachePolicy);
962 if (!m_receivedData) {
963 m_receivedData = true;
964 m_frame->document()->determineParseMode(decoded);
965 if (m_decoder->encoding().usesVisualOrdering())
966 m_frame->document()->setVisuallyOrdered();
967 m_frame->document()->recalcStyle(Node::Force);
971 ASSERT(!tokenizer->wantsRawData());
972 tokenizer->write(decoded, true);
976 void FrameLoader::write(const String& str)
981 if (!m_receivedData) {
982 m_receivedData = true;
983 m_frame->document()->setParseMode(Document::Strict);
986 if (Tokenizer* tokenizer = m_frame->document()->tokenizer())
987 tokenizer->write(str, true);
990 void FrameLoader::end()
992 m_isLoadingMainResource = false;
993 endIfNotLoadingMainResource();
996 void FrameLoader::endIfNotLoadingMainResource()
998 if (m_isLoadingMainResource)
1001 // http://bugs.webkit.org/show_bug.cgi?id=10854
1002 // The frame's last ref may be removed and it can be deleted by checkCompleted(),
1003 // so we'll add a protective refcount
1004 RefPtr<Frame> protector(m_frame);
1006 // make sure nothing's left in there
1007 if (m_frame->document()) {
1009 m_frame->document()->finishParsing();
1010 #if USE(LOW_BANDWIDTH_DISPLAY)
1011 if (m_frame->document()->inLowBandwidthDisplay()) {
1012 m_finishedParsingDuringLowBandwidthDisplay = true;
1013 switchOutLowBandwidthDisplayIfReady();
1017 // WebKit partially uses WebCore when loading non-HTML docs. In these cases doc==nil, but
1018 // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to
1019 // become true. An example is when a subframe is a pure text doc, and that subframe is the
1020 // last one to complete.
1023 if (m_documentLoader && !m_documentLoader->isLoadingFromCachedPage())
1027 void FrameLoader::startIconLoader()
1029 // FIXME: We kick off the icon loader when the frame is done receiving its main resource.
1030 // But we should instead do it when we're done parsing the head element.
1031 if (!isLoadingMainFrame())
1034 if (!iconDatabase() || !iconDatabase()->enabled())
1037 KURL url(iconURL());
1038 String urlString(url.url());
1039 if (urlString.isEmpty())
1042 // If we already have an unexpired icon, we won't kick off a load but we *will* map the appropriate URLs to it
1043 if (iconDatabase()->hasEntryForIconURL(urlString) && loadType() != FrameLoadTypeReload && !iconDatabase()->isIconExpiredForIconURL(urlString)) {
1044 LOG(IconDatabase, "FrameLoader::startIconLoader() - Committing iconURL %s to database", urlString.ascii().data());
1045 commitIconURLToIconDatabase(url);
1050 m_iconLoader.set(IconLoader::create(m_frame).release());
1051 m_iconLoader->startLoading();
1054 bool FrameLoader::restrictAccessToLocal()
1056 return m_restrictAccessToLocal;
1059 void FrameLoader::setRestrictAccessToLocal(bool access)
1061 m_restrictAccessToLocal = access;
1064 static HashSet<String, CaseInsensitiveHash<String> >& localSchemes()
1066 static HashSet<String, CaseInsensitiveHash<String> > localSchemes;
1068 if (localSchemes.isEmpty()) {
1069 localSchemes.add("file");
1070 localSchemes.add("applewebdata");
1073 return localSchemes;
1076 void FrameLoader::commitIconURLToIconDatabase(const KURL& icon)
1078 ASSERT(iconDatabase());
1079 LOG(IconDatabase, "Committing iconURL %s to database for pageURLs %s and %s", icon.url().ascii(), m_URL.url().ascii(), originalRequestURL().url().ascii());
1080 iconDatabase()->setIconURLForPageURL(icon.url(), m_URL.url());
1081 iconDatabase()->setIconURLForPageURL(icon.url(), originalRequestURL().url());
1084 void FrameLoader::restoreDocumentState()
1086 Document* doc = m_frame->document();
1090 HistoryItem* itemToRestore = 0;
1092 switch (loadType()) {
1093 case FrameLoadTypeReload:
1094 case FrameLoadTypeReloadAllowingStaleData:
1095 case FrameLoadTypeSame:
1096 case FrameLoadTypeReplace:
1098 case FrameLoadTypeBack:
1099 case FrameLoadTypeForward:
1100 case FrameLoadTypeIndexedBackForward:
1101 case FrameLoadTypeRedirectWithLockedHistory:
1102 case FrameLoadTypeStandard:
1103 itemToRestore = m_currentHistoryItem.get();
1109 doc->setStateForNewFormElements(itemToRestore->documentState());
1112 void FrameLoader::gotoAnchor()
1114 // If our URL has no ref, then we have no place we need to jump to.
1115 // OTOH if css target was set previously, we want to set it to 0, recalc
1116 // and possibly repaint because :target pseudo class may have been
1117 // set(See bug 11321)
1118 if (!m_URL.hasRef() &&
1119 !(m_frame->document() && m_frame->document()->getCSSTarget()))
1122 DeprecatedString ref = m_URL.encodedHtmlRef();
1123 if (!gotoAnchor(ref)) {
1124 // Can't use htmlRef() here because it doesn't know which encoding to use to decode.
1125 // Decoding here has to match encoding in completeURL, which means it has to use the
1126 // page's encoding rather than UTF-8.
1128 gotoAnchor(KURL::decode_string(ref, m_decoder->encoding()));
1132 void FrameLoader::finishedParsing()
1134 if (m_creatingInitialEmptyDocument)
1137 // This can be called from the Frame's destructor, in which case we shouldn't protect ourselves
1138 // because doing so will cause us to re-enter the destructor when protector goes out of scope.
1139 RefPtr<Frame> protector = m_frame->refCount() > 0 ? m_frame : 0;
1143 if (!m_frame->view())
1144 return; // We are being destroyed by something checkCompleted called.
1146 // Check if the scrollbars are really needed for the content.
1147 // If not, remove them, relayout, and repaint.
1148 m_frame->view()->restoreScrollbar();
1150 m_client->dispatchDidFinishDocumentLoad();
1155 void FrameLoader::loadDone()
1157 if (m_frame->document())
1161 void FrameLoader::checkCompleted()
1163 // Any frame that hasn't completed yet?
1164 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1165 if (!child->loader()->m_isComplete)
1168 // Have we completed before?
1172 // Are we still parsing?
1173 if (m_frame->document() && m_frame->document()->parsing())
1176 // Still waiting for images/scripts?
1177 if (m_frame->document())
1178 if (numRequests(m_frame->document()))
1181 #if USE(LOW_BANDWIDTH_DISPLAY)
1182 // as switch will be called, don't complete yet
1183 if (m_frame->document() && m_frame->document()->inLowBandwidthDisplay() && m_needToSwitchOutLowBandwidthDisplay)
1188 m_isComplete = true;
1190 RefPtr<Frame> protect(m_frame);
1191 checkCallImplicitClose(); // if we didn't do it before
1193 // Do not start a redirection timer for subframes here.
1194 // That is deferred until the parent is completed.
1195 if (m_scheduledRedirection && !m_frame->tree()->parent())
1196 startRedirectionTimer();
1199 if (m_frame->page())
1200 checkLoadComplete();
1203 void FrameLoader::checkCompletedTimerFired(Timer<FrameLoader>*)
1208 void FrameLoader::scheduleCheckCompleted()
1210 if (!m_checkCompletedTimer.isActive())
1211 m_checkCompletedTimer.startOneShot(0);
1214 void FrameLoader::checkCallImplicitClose()
1216 if (m_didCallImplicitClose || !m_frame->document() || m_frame->document()->parsing())
1219 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1220 if (!child->loader()->m_isComplete) // still got a frame running -> too early
1223 // All frames completed -> set their domain to the frameset's domain
1224 // This must only be done when loading the frameset initially (#22039),
1225 // not when following a link in a frame (#44162).
1226 if (m_frame->document()) {
1227 String domain = m_frame->document()->domain();
1228 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1229 if (child->document())
1230 child->document()->setDomain(domain);
1233 m_didCallImplicitClose = true;
1234 m_wasUnloadEventEmitted = false;
1235 if (m_frame->document())
1236 m_frame->document()->implicitClose();
1239 KURL FrameLoader::baseURL() const
1241 ASSERT(m_frame->document());
1242 return m_frame->document()->baseURL();
1245 String FrameLoader::baseTarget() const
1247 ASSERT(m_frame->document());
1248 return m_frame->document()->baseTarget();
1251 KURL FrameLoader::completeURL(const String& url)
1253 ASSERT(m_frame->document());
1254 return m_frame->document()->completeURL(url).deprecatedString();
1257 void FrameLoader::scheduleHTTPRedirection(double delay, const String& url)
1259 if (delay < 0 || delay > INT_MAX / 1000)
1262 // We want a new history item if the refresh timeout is > 1 second.
1263 if (!m_scheduledRedirection || delay <= m_scheduledRedirection->delay)
1264 scheduleRedirection(new ScheduledRedirection(delay, url, delay <= 1, false));
1267 void FrameLoader::scheduleLocationChange(const String& url, const String& referrer, bool lockHistory, bool wasUserGesture)
1269 // If the URL we're going to navigate to is the same as the current one, except for the
1270 // fragment part, we don't need to schedule the location change.
1271 KURL u(url.deprecatedString());
1272 if (u.hasRef() && equalIgnoringRef(m_URL, u)) {
1273 changeLocation(url, referrer, lockHistory, wasUserGesture);
1277 // Handle a location change of a page with no document as a special case.
1278 // This may happen when a frame changes the location of another frame.
1279 bool duringLoad = !m_committedFirstRealDocumentLoad;
1281 // If a redirect was scheduled during a load, then stop the current load.
1282 // Otherwise when the current load transitions from a provisional to a
1283 // committed state, pending redirects may be cancelled.
1285 if (m_provisionalDocumentLoader)
1286 m_provisionalDocumentLoader->stopLoading();
1290 ScheduledRedirection::Type type = duringLoad
1291 ? ScheduledRedirection::locationChangeDuringLoad : ScheduledRedirection::locationChange;
1292 scheduleRedirection(new ScheduledRedirection(type, url, referrer, lockHistory, wasUserGesture));
1295 void FrameLoader::scheduleRefresh(bool wasUserGesture)
1297 // Handle a location change of a page with no document as a special case.
1298 // This may happen when a frame requests a refresh of another frame.
1299 bool duringLoad = !m_frame->document();
1301 // If a refresh was scheduled during a load, then stop the current load.
1302 // Otherwise when the current load transitions from a provisional to a
1303 // committed state, pending redirects may be cancelled.
1307 ScheduledRedirection::Type type = duringLoad
1308 ? ScheduledRedirection::locationChangeDuringLoad : ScheduledRedirection::locationChange;
1309 scheduleRedirection(new ScheduledRedirection(type, m_URL.url(), m_outgoingReferrer, true, wasUserGesture));
1310 m_cachePolicy = CachePolicyRefresh;
1313 bool FrameLoader::isScheduledLocationChangePending() const
1315 if (!m_scheduledRedirection)
1317 switch (m_scheduledRedirection->type) {
1318 case ScheduledRedirection::redirection:
1320 case ScheduledRedirection::historyNavigation:
1321 case ScheduledRedirection::locationChange:
1322 case ScheduledRedirection::locationChangeDuringLoad:
1325 ASSERT_NOT_REACHED();
1329 void FrameLoader::scheduleHistoryNavigation(int steps)
1331 // navigation will always be allowed in the 0 steps case, which is OK because
1332 // that's supposed to force a reload.
1333 if (!canGoBackOrForward(steps)) {
1334 cancelRedirection();
1338 // If the steps to navigate is not zero (which needs to force a reload), and if the URL we're going to navigate
1339 // to is the same as the current one, except for the fragment part, we don't need to schedule the navigation.
1340 if (steps != 0 && equalIgnoringRef(m_URL, historyURL(steps))) {
1341 goBackOrForward(steps);
1345 scheduleRedirection(new ScheduledRedirection(steps));
1348 void FrameLoader::goBackOrForward(int distance)
1353 Page* page = m_frame->page();
1356 BackForwardList* list = page->backForwardList();
1360 HistoryItem* item = list->itemAtIndex(distance);
1363 int forwardListCount = list->forwardListCount();
1364 if (forwardListCount > 0)
1365 item = list->itemAtIndex(forwardListCount);
1367 int backListCount = list->forwardListCount();
1368 if (backListCount > 0)
1369 item = list->itemAtIndex(-backListCount);
1373 page->goToItem(item, FrameLoadTypeIndexedBackForward);
1376 void FrameLoader::redirectionTimerFired(Timer<FrameLoader>*)
1378 OwnPtr<ScheduledRedirection> redirection(m_scheduledRedirection.release());
1380 switch (redirection->type) {
1381 case ScheduledRedirection::redirection:
1382 case ScheduledRedirection::locationChange:
1383 case ScheduledRedirection::locationChangeDuringLoad:
1384 changeLocation(redirection->URL, redirection->referrer,
1385 redirection->lockHistory, redirection->wasUserGesture);
1387 case ScheduledRedirection::historyNavigation:
1388 if (redirection->historySteps == 0) {
1389 // Special case for go(0) from a frame -> reload only the frame
1390 urlSelected(m_URL, "", 0, redirection->lockHistory, redirection->wasUserGesture);
1393 // go(i!=0) from a frame navigates into the history of the frame only,
1394 // in both IE and NS (but not in Mozilla). We can't easily do that.
1395 goBackOrForward(redirection->historySteps);
1398 ASSERT_NOT_REACHED();
1401 String FrameLoader::encoding() const
1403 if (m_encodingWasChosenByUser && !m_encoding.isEmpty())
1405 if (m_decoder && m_decoder->encoding().isValid())
1406 return m_decoder->encoding().name();
1407 Settings* settings = m_frame->settings();
1408 return settings ? settings->defaultTextEncodingName() : String();
1411 bool FrameLoader::gotoAnchor(const String& name)
1413 ASSERT(m_frame->document());
1415 if (!m_frame->document()->haveStylesheetsLoaded()) {
1416 m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(true);
1420 m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(false);
1422 Node* anchorNode = m_frame->document()->getElementById(AtomicString(name));
1424 anchorNode = m_frame->document()->anchors()->namedItem(name, !m_frame->document()->inCompatMode());
1426 m_frame->document()->setCSSTarget(anchorNode); // Setting to null will clear the current target.
1428 // Implement the rule that "" and "top" both mean top of page as in other browsers.
1429 if (!anchorNode && !(name.isEmpty() || equalIgnoringCase(name, "top")))
1432 // We need to update the layout before scrolling, otherwise we could
1433 // really mess things up if an anchor scroll comes at a bad moment.
1434 if (m_frame->document()) {
1435 m_frame->document()->updateRendering();
1436 // Only do a layout if changes have occurred that make it necessary.
1437 if (m_frame->view() && m_frame->document()->renderer() && m_frame->document()->renderer()->needsLayout())
1438 m_frame->view()->layout();
1441 // Scroll nested layers and frames to reveal the anchor.
1442 // Align to the top and to the closest side (this matches other browsers).
1443 RenderObject* renderer;
1446 renderer = m_frame->document()->renderer(); // top of document
1448 renderer = anchorNode->renderer();
1449 rect = anchorNode->getRect();
1452 renderer->enclosingLayer()->scrollRectToVisible(rect, RenderLayer::gAlignToEdgeIfNeeded, RenderLayer::gAlignTopAlways);
1457 bool FrameLoader::requestObject(RenderPart* renderer, const String& url, const AtomicString& frameName,
1458 const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues)
1460 if (url.isEmpty() && mimeType.isEmpty())
1463 #if USE(LOW_BANDWIDTH_DISPLAY)
1464 // don't care object during low bandwidth display
1465 if (frame()->document()->inLowBandwidthDisplay()) {
1466 m_needToSwitchOutLowBandwidthDisplay = true;
1473 completedURL = completeURL(url);
1476 if (shouldUsePlugin(completedURL, mimeType, renderer->hasFallbackContent(), useFallback)) {
1477 Settings* settings = m_frame->settings();
1478 if (!settings || !settings->arePluginsEnabled() ||
1479 (!settings->isJavaEnabled() && MIMETypeRegistry::isJavaAppletMIMEType(mimeType)))
1481 return loadPlugin(renderer, completedURL, mimeType, paramNames, paramValues, useFallback);
1484 ASSERT(renderer->node()->hasTagName(objectTag) || renderer->node()->hasTagName(embedTag));
1485 HTMLPlugInElement* element = static_cast<HTMLPlugInElement*>(renderer->node());
1487 AtomicString uniqueFrameName = m_frame->tree()->uniqueChildName(frameName);
1488 element->setFrameName(uniqueFrameName);
1490 // FIXME: OK to always make a new frame? When does the old frame get removed?
1491 return loadSubframe(element, completedURL, uniqueFrameName, m_outgoingReferrer);
1494 bool FrameLoader::shouldUsePlugin(const KURL& url, const String& mimeType, bool hasFallback, bool& useFallback)
1496 ObjectContentType objectType = m_client->objectContentType(url, mimeType);
1497 // If an object's content can't be handled and it has no fallback, let
1498 // it be handled as a plugin to show the broken plugin icon.
1499 useFallback = objectType == ObjectContentNone && hasFallback;
1500 return objectType == ObjectContentNone || objectType == ObjectContentPlugin;
1503 bool FrameLoader::loadPlugin(RenderPart* renderer, const KURL& url, const String& mimeType,
1504 const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback)
1508 if (renderer && !useFallback) {
1509 Element* pluginElement = 0;
1510 if (renderer->node() && renderer->node()->isElementNode())
1511 pluginElement = static_cast<Element*>(renderer->node());
1513 if (!canLoad(url, frame()->document())) {
1514 FrameLoader::reportLocalLoadFailed(m_frame->page(), url.url());
1518 widget = m_client->createPlugin(pluginElement, url, paramNames, paramValues, mimeType,
1519 m_frame->document()->isPluginDocument());
1521 renderer->setWidget(widget);
1522 m_containsPlugIns = true;
1526 checkCallImplicitClose();
1530 void FrameLoader::clearRecordedFormValues()
1532 m_formAboutToBeSubmitted = 0;
1533 m_formValuesAboutToBeSubmitted.clear();
1536 void FrameLoader::recordFormValue(const String& name, const String& value, PassRefPtr<HTMLFormElement> element)
1538 m_formAboutToBeSubmitted = element;
1539 m_formValuesAboutToBeSubmitted.set(name, value);
1542 void FrameLoader::parentCompleted()
1544 if (m_scheduledRedirection && !m_redirectionTimer.isActive())
1545 startRedirectionTimer();
1548 String FrameLoader::outgoingReferrer() const
1550 return m_outgoingReferrer;
1553 Frame* FrameLoader::opener()
1558 void FrameLoader::setOpener(Frame* opener)
1561 m_opener->loader()->m_openedFrames.remove(m_frame);
1563 opener->loader()->m_openedFrames.add(m_frame);
1567 bool FrameLoader::openedByDOM() const
1569 return m_openedByDOM;
1572 void FrameLoader::setOpenedByDOM()
1574 m_openedByDOM = true;
1577 void FrameLoader::handleFallbackContent()
1579 HTMLFrameOwnerElement* owner = m_frame->ownerElement();
1580 if (!owner || !owner->hasTagName(objectTag))
1582 static_cast<HTMLObjectElement*>(owner)->renderFallbackContent();
1585 void FrameLoader::provisionalLoadStarted()
1587 m_firstLayoutDone = false;
1588 cancelRedirection(true);
1589 m_client->provisionalLoadStarted();
1591 if (canCachePage() && m_client->canCachePage() && !m_currentHistoryItem->isInPageCache())
1592 cachePageForHistoryItem(m_currentHistoryItem.get());
1595 bool FrameLoader::userGestureHint()
1597 Frame* rootFrame = m_frame;
1598 while (rootFrame->tree()->parent())
1599 rootFrame = rootFrame->tree()->parent();
1601 if (rootFrame->scriptProxy())
1602 return rootFrame->scriptProxy()->interpreter()->wasRunByUserGesture();
1604 return true; // If JavaScript is disabled, a user gesture must have initiated the navigation
1607 void FrameLoader::didNotOpenURL(const KURL& URL)
1609 if (m_submittedFormURL == URL)
1610 m_submittedFormURL = KURL();
1613 void FrameLoader::resetMultipleFormSubmissionProtection()
1615 m_submittedFormURL = KURL();
1618 void FrameLoader::setEncoding(const String& name, bool userChosen)
1620 if (!m_workingURL.isEmpty())
1621 receivedFirstData();
1623 m_encodingWasChosenByUser = userChosen;
1626 void FrameLoader::addData(const char* bytes, int length)
1628 ASSERT(m_workingURL.isEmpty());
1629 ASSERT(m_frame->document());
1630 ASSERT(m_frame->document()->parsing());
1631 write(bytes, length);
1634 bool FrameLoader::canCachePage()
1636 // Cache the page, if possible.
1637 // Don't write to the cache if in the middle of a redirect, since we will want to
1638 // store the final page we end up on.
1639 // No point writing to the cache on a reload or loadSame, since we will just write
1640 // over it again when we leave that page.
1641 // FIXME: <rdar://problem/4886592> - We should work out the complexities of caching pages with frames as they
1642 // are the most interesting pages on the web, and often those that would benefit the most from caching!
1643 FrameLoadType loadType = this->loadType();
1645 return m_documentLoader
1646 && m_documentLoader->mainDocumentError().isNull()
1647 && !m_frame->tree()->childCount()
1648 && !m_frame->tree()->parent()
1649 && !m_containsPlugIns
1650 && !m_URL.protocol().startsWith("https")
1651 && m_frame->document()
1652 && !m_frame->document()->applets()->length()
1653 && !m_frame->document()->hasWindowEventListener(unloadEvent)
1655 && m_frame->page()->backForwardList()->enabled()
1656 && m_frame->page()->backForwardList()->capacity() > 0
1657 && m_frame->page()->settings()->usesPageCache()
1658 && m_currentHistoryItem
1659 && !isQuickRedirectComing()
1660 && loadType != FrameLoadTypeReload
1661 && loadType != FrameLoadTypeReloadAllowingStaleData
1662 && loadType != FrameLoadTypeSame
1663 && !m_documentLoader->isLoadingInAPISense()
1664 && !m_documentLoader->isStopping();
1667 void FrameLoader::updatePolicyBaseURL()
1669 if (m_frame->tree()->parent() && m_frame->tree()->parent()->document())
1670 setPolicyBaseURL(m_frame->tree()->parent()->document()->policyBaseURL());
1672 setPolicyBaseURL(m_URL.url());
1675 void FrameLoader::setPolicyBaseURL(const String& s)
1677 if (m_frame->document())
1678 m_frame->document()->setPolicyBaseURL(s);
1679 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1680 child->loader()->setPolicyBaseURL(s);
1683 // This does the same kind of work that FrameLoader::openURL does, except it relies on the fact
1684 // that a higher level already checked that the URLs match and the scrolling is the right thing to do.
1685 void FrameLoader::scrollToAnchor(const KURL& URL)
1692 // It's important to model this as a load that starts and immediately finishes.
1693 // Otherwise, the parent frame may think we never finished loading.
1694 m_isComplete = false;
1698 bool FrameLoader::isComplete() const
1700 return m_isComplete;
1703 void FrameLoader::scheduleRedirection(ScheduledRedirection* redirection)
1705 stopRedirectionTimer();
1706 m_scheduledRedirection.set(redirection);
1708 startRedirectionTimer();
1711 void FrameLoader::startRedirectionTimer()
1713 ASSERT(m_scheduledRedirection);
1715 m_redirectionTimer.stop();
1716 m_redirectionTimer.startOneShot(m_scheduledRedirection->delay);
1718 switch (m_scheduledRedirection->type) {
1719 case ScheduledRedirection::redirection:
1720 case ScheduledRedirection::locationChange:
1721 case ScheduledRedirection::locationChangeDuringLoad:
1722 clientRedirected(m_scheduledRedirection->URL.deprecatedString(),
1723 m_scheduledRedirection->delay,
1724 currentTime() + m_redirectionTimer.nextFireInterval(),
1725 m_scheduledRedirection->lockHistory,
1726 m_isExecutingJavaScriptFormAction);
1728 case ScheduledRedirection::historyNavigation:
1729 // Don't report history navigations.
1732 ASSERT_NOT_REACHED();
1735 void FrameLoader::stopRedirectionTimer()
1737 if (!m_redirectionTimer.isActive())
1740 m_redirectionTimer.stop();
1742 if (m_scheduledRedirection) {
1743 switch (m_scheduledRedirection->type) {
1744 case ScheduledRedirection::redirection:
1745 case ScheduledRedirection::locationChange:
1746 case ScheduledRedirection::locationChangeDuringLoad:
1747 clientRedirectCancelledOrFinished(m_cancellingWithLoadInProgress);
1749 case ScheduledRedirection::historyNavigation:
1750 // Don't report history navigations.
1753 ASSERT_NOT_REACHED();
1757 void FrameLoader::completed()
1759 RefPtr<Frame> protect(m_frame);
1760 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1761 child->loader()->parentCompleted();
1762 if (Frame* parent = m_frame->tree()->parent())
1763 parent->loader()->checkCompleted();
1767 void FrameLoader::started()
1769 for (Frame* frame = m_frame; frame; frame = frame->tree()->parent())
1770 frame->loader()->m_isComplete = false;
1773 bool FrameLoader::containsPlugins() const
1775 return m_containsPlugIns;
1778 void FrameLoader::prepareForLoadStart()
1780 if (Page* page = m_frame->page())
1781 page->progress()->progressStarted(m_frame);
1782 m_client->dispatchDidStartProvisionalLoad();
1785 void FrameLoader::setupForReplace()
1787 setState(FrameStateProvisional);
1788 m_provisionalDocumentLoader = m_documentLoader;
1789 m_documentLoader = 0;
1793 void FrameLoader::setupForReplaceByMIMEType(const String& newMIMEType)
1795 activeDocumentLoader()->setupForReplaceByMIMEType(newMIMEType);
1798 void FrameLoader::finalSetupForReplace(DocumentLoader* loader)
1800 m_client->clearUnarchivingState(loader);
1803 void FrameLoader::load(const KURL& URL, Event* event)
1805 load(ResourceRequest(URL), false, true, event, 0, HashMap<String, String>());
1808 void FrameLoader::load(const FrameLoadRequest& request, bool lockHistory, bool userGesture, Event* event,
1809 HTMLFormElement* submitForm, const HashMap<String, String>& formValues)
1811 KURL url = request.resourceRequest().url();
1814 String argsReferrer = request.resourceRequest().httpReferrer();
1815 if (!argsReferrer.isEmpty())
1816 referrer = argsReferrer;
1818 referrer = m_outgoingReferrer;
1820 ASSERT(frame()->document());
1821 if (!canLoad(url, frame()->document()) &&
1822 !canLoad(url, referrer)) {
1823 FrameLoader::reportLocalLoadFailed(m_frame->page(), url.url());
1827 if (shouldHideReferrer(url, referrer))
1828 referrer = String();
1830 Frame* targetFrame = m_frame->tree()->find(request.frameName());
1831 if (!canTarget(targetFrame))
1834 if (request.resourceRequest().httpMethod() != "POST") {
1835 FrameLoadType loadType;
1836 if (request.resourceRequest().cachePolicy() == ReloadIgnoringCacheData)
1837 loadType = FrameLoadTypeReload;
1838 else if (lockHistory)
1839 loadType = FrameLoadTypeRedirectWithLockedHistory;
1841 loadType = FrameLoadTypeStandard;
1843 RefPtr<FormState> formState;
1844 if (submitForm && !formValues.isEmpty())
1845 formState = FormState::create(submitForm, formValues, m_frame);
1847 load(request.resourceRequest().url(), referrer, loadType,
1848 request.frameName(), event, formState.release());
1850 post(request.resourceRequest().url(), referrer, request.frameName(),
1851 request.resourceRequest().httpBody(), request.resourceRequest().httpContentType(), event, submitForm, formValues);
1853 if (targetFrame && targetFrame != m_frame)
1854 if (Page* page = targetFrame->page())
1855 page->chrome()->focus();
1858 void FrameLoader::load(const KURL& URL, const String& referrer, FrameLoadType newLoadType,
1859 const String& frameName, Event* event, PassRefPtr<FormState> formState)
1861 bool isFormSubmission = formState;
1863 ResourceRequest request(URL);
1864 if (!referrer.isEmpty())
1865 request.setHTTPReferrer(referrer);
1866 addExtraFieldsToRequest(request, true, event || isFormSubmission);
1867 if (newLoadType == FrameLoadTypeReload)
1868 request.setCachePolicy(ReloadIgnoringCacheData);
1870 ASSERT(newLoadType != FrameLoadTypeSame);
1872 NavigationAction action(URL, newLoadType, isFormSubmission, event);
1874 if (!frameName.isEmpty()) {
1875 if (Frame* targetFrame = m_frame->tree()->find(frameName))
1876 targetFrame->loader()->load(URL, referrer, newLoadType, String(), event, formState);
1878 checkNewWindowPolicy(action, request, formState, frameName);
1882 RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader;
1884 bool sameURL = shouldTreatURLAsSameAsCurrent(URL);
1886 // Make sure to do scroll to anchor processing even if the URL is
1887 // exactly the same so pages with '#' links and DHTML side effects
1889 if (!isFormSubmission
1890 && newLoadType != FrameLoadTypeReload
1891 && newLoadType != FrameLoadTypeSame
1892 && !shouldReload(URL, url())
1893 // We don't want to just scroll if a link from within a
1894 // frameset is trying to reload the frameset into _top.
1895 && !m_frame->isFrameSet()) {
1897 // Just do anchor navigation within the existing content.
1899 // We don't do this if we are submitting a form, explicitly reloading,
1900 // currently displaying a frameset, or if the new URL does not have a fragment.
1901 // These rules are based on what KHTML was doing in KHTMLPart::openURL.
1903 // FIXME: What about load types other than Standard and Reload?
1905 oldDocumentLoader->setTriggeringAction(action);
1907 checkNavigationPolicy(request, oldDocumentLoader.get(), formState,
1908 callContinueFragmentScrollAfterNavigationPolicy, this);
1910 // must grab this now, since this load may stop the previous load and clear this flag
1911 bool isRedirect = m_quickRedirectComing;
1912 load(request, action, newLoadType, formState);
1914 m_quickRedirectComing = false;
1915 if (m_provisionalDocumentLoader)
1916 m_provisionalDocumentLoader->setIsClientRedirect(true);
1918 // Example of this case are sites that reload the same URL with a different cookie
1919 // driving the generated content, or a master frame with links that drive a target
1920 // frame, where the user has clicked on the same link repeatedly.
1921 m_loadType = FrameLoadTypeSame;
1925 void FrameLoader::load(const ResourceRequest& request)
1927 load(request, SubstituteData());
1930 void FrameLoader::load(const ResourceRequest& request, const SubstituteData& substituteData)
1932 if (m_inStopAllLoaders)
1935 // FIXME: is this the right place to reset loadType? Perhaps this should be done after loading is finished or aborted.
1936 m_loadType = FrameLoadTypeStandard;
1937 load(m_client->createDocumentLoader(request, substituteData).get());
1940 void FrameLoader::load(const ResourceRequest& request, const String& frameName)
1942 if (frameName.isEmpty()) {
1947 Frame* frame = m_frame->tree()->find(frameName);
1949 frame->loader()->load(request);
1953 checkNewWindowPolicy(NavigationAction(request.url(), NavigationTypeOther), request, 0, frameName);
1956 void FrameLoader::load(const ResourceRequest& request, const NavigationAction& action, FrameLoadType type, PassRefPtr<FormState> formState)
1958 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, SubstituteData());
1960 loader->setTriggeringAction(action);
1961 if (m_documentLoader)
1962 loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
1964 load(loader.get(), type, formState);
1967 void FrameLoader::load(DocumentLoader* newDocumentLoader)
1969 ResourceRequest& r = newDocumentLoader->request();
1970 addExtraFieldsToRequest(r, true, false);
1973 if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->originalRequest().url())) {
1974 r.setCachePolicy(ReloadIgnoringCacheData);
1975 type = FrameLoadTypeSame;
1977 type = FrameLoadTypeStandard;
1979 if (m_documentLoader)
1980 newDocumentLoader->setOverrideEncoding(m_documentLoader->overrideEncoding());
1982 // When we loading alternate content for an unreachable URL that we're
1983 // visiting in the b/f list, we treat it as a reload so the b/f list
1984 // is appropriately maintained.
1985 if (shouldReloadToHandleUnreachableURL(newDocumentLoader)) {
1986 ASSERT(type == FrameLoadTypeStandard);
1987 type = FrameLoadTypeReload;
1990 load(newDocumentLoader, type, 0);
1993 void FrameLoader::load(DocumentLoader* loader, FrameLoadType type, PassRefPtr<FormState> formState)
1995 ASSERT(m_client->hasWebView());
1997 // Unfortunately the view must be non-nil, this is ultimately due
1998 // to parser requiring a FrameView. We should fix this dependency.
2000 ASSERT(m_client->hasFrameView());
2002 m_policyLoadType = type;
2004 if (Frame* parent = m_frame->tree()->parent())
2005 loader->setOverrideEncoding(parent->loader()->documentLoader()->overrideEncoding());
2008 setPolicyDocumentLoader(loader);
2010 checkNavigationPolicy(loader->request(), loader, formState,
2011 callContinueLoadAfterNavigationPolicy, this);
2014 // FIXME: It would be nice if we could collapse these into one or two functions.
2015 bool FrameLoader::canLoad(const KURL& url, const String& referrer)
2017 if (!shouldTreatURLAsLocal(url.url()))
2020 return shouldTreatURLAsLocal(referrer);
2023 bool FrameLoader::canLoad(const KURL& url, const Document* doc)
2025 if (!shouldTreatURLAsLocal(url.url()))
2028 return doc && doc->isAllowedToLoadLocalResources();
2031 bool FrameLoader::canLoad(const CachedResource& resource, const Document* doc)
2033 if (!resource.treatAsLocal())
2036 return doc && doc->isAllowedToLoadLocalResources();
2039 void FrameLoader::reportLocalLoadFailed(const Page* page, const String& url)
2041 ASSERT(!url.isEmpty());
2043 page->chrome()->addMessageToConsole(JSMessageSource, ErrorMessageLevel, "Not allowed to load local resource: " + url, 0, String());
2046 bool FrameLoader::shouldHideReferrer(const KURL& url, const String& referrer)
2048 bool referrerIsSecureURL = referrer.startsWith("https:", false);
2049 bool referrerIsWebURL = referrerIsSecureURL || referrer.startsWith("http:", false);
2051 if (!referrerIsWebURL)
2054 if (!referrerIsSecureURL)
2057 bool URLIsSecureURL = url.url().startsWith("https:", false);
2059 return !URLIsSecureURL;
2062 const ResourceRequest& FrameLoader::initialRequest() const
2064 return activeDocumentLoader()->initialRequest();
2067 void FrameLoader::receivedData(const char* data, int length)
2069 activeDocumentLoader()->receivedData(data, length);
2072 bool FrameLoader::willUseArchive(ResourceLoader* loader, const ResourceRequest& request, const KURL& originalURL) const
2074 return m_client->willUseArchive(loader, request, originalURL);
2077 void FrameLoader::handleUnimplementablePolicy(const ResourceError& error)
2079 m_delegateIsHandlingUnimplementablePolicy = true;
2080 m_client->dispatchUnableToImplementPolicy(error);
2081 m_delegateIsHandlingUnimplementablePolicy = false;
2084 void FrameLoader::cannotShowMIMEType(const ResourceResponse& response)
2086 handleUnimplementablePolicy(m_client->cannotShowMIMETypeError(response));
2089 ResourceError FrameLoader::interruptionForPolicyChangeError(const ResourceRequest& request)
2091 return m_client->interruptForPolicyChangeError(request);
2094 void FrameLoader::checkNavigationPolicy(const ResourceRequest& newRequest, NavigationPolicyDecisionFunction function, void* argument)
2096 checkNavigationPolicy(newRequest, activeDocumentLoader(), 0, function, argument);
2099 void FrameLoader::checkContentPolicy(const String& MIMEType, ContentPolicyDecisionFunction function, void* argument)
2101 ASSERT(activeDocumentLoader());
2103 // Always show content with valid substitute data.
2104 if (activeDocumentLoader()->substituteData().isValid()) {
2105 function(argument, PolicyUse);
2110 // Respect the hidden FTP Directory Listing pref so it can be tested even if the policy delegate might otherwise disallow it
2111 Settings* settings = m_frame->settings();
2112 if (settings && settings->forceFTPDirectoryListings() && MIMEType == "application/x-ftp-directory") {
2113 function(argument, PolicyUse);
2118 m_policyCheck.set(function, argument);
2119 m_client->dispatchDecidePolicyForMIMEType(&FrameLoader::continueAfterContentPolicy,
2120 MIMEType, activeDocumentLoader()->request());
2123 bool FrameLoader::shouldReloadToHandleUnreachableURL(DocumentLoader* docLoader)
2125 KURL unreachableURL = docLoader->unreachableURL();
2127 if (unreachableURL.isEmpty())
2130 if (!isBackForwardLoadType(m_policyLoadType))
2133 // We only treat unreachableURLs specially during the delegate callbacks
2134 // for provisional load errors and navigation policy decisions. The former
2135 // case handles well-formed URLs that can't be loaded, and the latter
2136 // case handles malformed URLs and unknown schemes. Loading alternate content
2137 // at other times behaves like a standard load.
2138 DocumentLoader* compareDocumentLoader = 0;
2139 if (m_delegateIsDecidingNavigationPolicy || m_delegateIsHandlingUnimplementablePolicy)
2140 compareDocumentLoader = m_policyDocumentLoader.get();
2141 else if (m_delegateIsHandlingProvisionalLoadError)
2142 compareDocumentLoader = m_provisionalDocumentLoader.get();
2144 return compareDocumentLoader && unreachableURL == compareDocumentLoader->request().url();
2147 void FrameLoader::reloadAllowingStaleData(const String& encoding)
2149 if (!m_documentLoader)
2152 ResourceRequest request = m_documentLoader->request();
2153 KURL unreachableURL = m_documentLoader->unreachableURL();
2154 if (!unreachableURL.isEmpty())
2155 request.setURL(unreachableURL);
2157 request.setCachePolicy(ReturnCacheDataElseLoad);
2159 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, SubstituteData());
2160 setPolicyDocumentLoader(loader.get());
2162 loader->setOverrideEncoding(encoding);
2164 load(loader.get(), FrameLoadTypeReloadAllowingStaleData, 0);
2167 void FrameLoader::reload()
2169 if (!m_documentLoader)
2172 ResourceRequest& initialRequest = m_documentLoader->request();
2174 // If a window is created by javascript, its main frame can have an empty but non-nil URL.
2175 // Reloading in this case will lose the current contents (see 4151001).
2176 if (initialRequest.url().isEmpty())
2179 // Replace error-page URL with the URL we were trying to reach.
2180 KURL unreachableURL = m_documentLoader->unreachableURL();
2181 if (!unreachableURL.isEmpty())
2182 initialRequest = ResourceRequest(unreachableURL);
2184 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(initialRequest, SubstituteData());
2186 ResourceRequest& request = loader->request();
2188 request.setCachePolicy(ReloadIgnoringCacheData);
2189 request.setHTTPHeaderField("Cache-Control", "max-age=0");
2191 // If we're about to re-post, set up action so the application can warn the user.
2192 if (request.httpMethod() == "POST")
2193 loader->setTriggeringAction(NavigationAction(request.url(), NavigationTypeFormResubmitted));
2195 loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
2197 load(loader.get(), FrameLoadTypeReload, 0);
2200 bool FrameLoader::canTarget(Frame* target) const
2202 // This function prevents this exploit:
2203 // <rdar://problem/3715785> multiple frame injection vulnerability reported by Secunia, affects almost all browsers
2205 // Allow if there is no specific target.
2209 // Allow navigation within the same page/frameset.
2210 if (m_frame->page() == target->page())
2213 // Allow if the request is made from a local file.
2214 ASSERT(m_frame->document());
2215 String domain = m_frame->document()->domain();
2216 if (domain.isEmpty())
2219 // Allow if target is an entire window (top level frame of a window).
2220 Frame* parent = target->tree()->parent();
2224 // Allow if the domain of the parent of the targeted frame equals this domain.
2225 String parentDomain;
2226 if (Document* parentDocument = parent->document())
2227 domain = parentDocument->domain();
2228 return equalIgnoringCase(parentDomain, domain);
2231 void FrameLoader::stopLoadingSubframes()
2233 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2234 child->loader()->stopAllLoaders();
2237 void FrameLoader::stopAllLoaders()
2239 // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
2240 if (m_inStopAllLoaders)
2243 m_inStopAllLoaders = true;
2247 stopLoadingSubframes();
2248 if (m_provisionalDocumentLoader)
2249 m_provisionalDocumentLoader->stopLoading();
2250 if (m_documentLoader)
2251 m_documentLoader->stopLoading();
2252 setProvisionalDocumentLoader(0);
2253 m_client->clearArchivedResources();
2255 m_inStopAllLoaders = false;
2258 void FrameLoader::stopForUserCancel()
2261 if (m_frame->page())
2262 checkLoadComplete();
2265 void FrameLoader::cancelPendingArchiveLoad(ResourceLoader* loader)
2267 m_client->cancelPendingArchiveLoad(loader);
2270 DocumentLoader* FrameLoader::activeDocumentLoader() const
2272 if (m_state == FrameStateProvisional)
2273 return m_provisionalDocumentLoader.get();
2274 return m_documentLoader.get();
2277 bool FrameLoader::isLoading() const
2279 DocumentLoader* docLoader = activeDocumentLoader();
2282 return docLoader->isLoadingMainResource() || docLoader->isLoadingSubresources() || docLoader->isLoadingPlugIns();
2285 bool FrameLoader::frameHasLoaded() const
2287 return m_committedFirstRealDocumentLoad || (m_provisionalDocumentLoader && !m_creatingInitialEmptyDocument);
2290 void FrameLoader::setDocumentLoader(DocumentLoader* loader)
2292 if (!loader && !m_documentLoader)
2295 ASSERT(loader != m_documentLoader);
2296 ASSERT(!loader || loader->frameLoader() == this);
2298 m_client->prepareForDataSourceReplacement();
2300 if (m_documentLoader)
2301 m_documentLoader->detachFromFrame();
2303 m_documentLoader = loader;
2306 DocumentLoader* FrameLoader::documentLoader() const
2308 return m_documentLoader.get();
2311 void FrameLoader::setPolicyDocumentLoader(DocumentLoader* loader)
2313 if (m_policyDocumentLoader == loader)
2318 loader->setFrame(m_frame);
2319 if (m_policyDocumentLoader
2320 && m_policyDocumentLoader != m_provisionalDocumentLoader
2321 && m_policyDocumentLoader != m_documentLoader)
2322 m_policyDocumentLoader->detachFromFrame();
2324 m_policyDocumentLoader = loader;
2327 DocumentLoader* FrameLoader::provisionalDocumentLoader()
2329 return m_provisionalDocumentLoader.get();
2332 void FrameLoader::setProvisionalDocumentLoader(DocumentLoader* loader)
2334 ASSERT(!loader || !m_provisionalDocumentLoader);
2335 ASSERT(!loader || loader->frameLoader() == this);
2337 if (m_provisionalDocumentLoader && m_provisionalDocumentLoader != m_documentLoader)
2338 m_provisionalDocumentLoader->detachFromFrame();
2340 m_provisionalDocumentLoader = loader;
2343 FrameState FrameLoader::state() const
2348 double FrameLoader::timeOfLastCompletedLoad()
2350 return storedTimeOfLastCompletedLoad;
2353 void FrameLoader::setState(FrameState newState)
2357 if (newState == FrameStateProvisional)
2358 provisionalLoadStarted();
2359 else if (newState == FrameStateComplete) {
2360 frameLoadCompleted();
2361 storedTimeOfLastCompletedLoad = currentTime();
2362 if (m_documentLoader)
2363 m_documentLoader->stopRecordingResponses();
2367 void FrameLoader::clearProvisionalLoad()
2369 setProvisionalDocumentLoader(0);
2370 if (Page* page = m_frame->page())
2371 page->progress()->progressCompleted(m_frame);
2372 setState(FrameStateComplete);
2375 void FrameLoader::markLoadComplete()
2377 setState(FrameStateComplete);
2380 void FrameLoader::commitProvisionalLoad(PassRefPtr<CachedPage> prpCachedPage)
2382 RefPtr<CachedPage> cachedPage = prpCachedPage;
2383 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
2385 if (m_loadType != FrameLoadTypeReplace)
2386 closeOldDataSources();
2388 if (!cachedPage && !m_creatingInitialEmptyDocument)
2389 m_client->makeRepresentation(pdl.get());
2391 transitionToCommitted(cachedPage);
2393 // Call clientRedirectCancelledOrFinished() here so that the frame load delegate is notified that the redirect's
2394 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
2395 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are
2396 // just about to commit a new page, there cannot possibly be a pending redirect at this point.
2397 if (m_sentRedirectNotification)
2398 clientRedirectCancelledOrFinished(false);
2400 if (cachedPage && cachedPage->document()) {
2402 cachedPage->clear();
2404 KURL url = pdl->substituteData().responseURL();
2408 url = pdl->responseURL();
2410 url = "about:blank";
2417 void FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage)
2419 ASSERT(m_client->hasWebView());
2420 ASSERT(m_state == FrameStateProvisional);
2422 if (m_state != FrameStateProvisional)
2425 m_client->setCopiesOnScroll();
2426 updateHistoryForCommit();
2428 // The call to closeURL() invokes the unload event handler, which can execute arbitrary
2429 // JavaScript. If the script initiates a new load, we need to abandon the current load,
2430 // or the two will stomp each other.
2431 DocumentLoader* pdl = m_provisionalDocumentLoader.get();
2432 if (m_documentLoader)
2434 if (pdl != m_provisionalDocumentLoader)
2437 // Nothing else can interupt this commit - set the Provisional->Committed transition in stone
2438 if (m_documentLoader)
2439 m_documentLoader->stopLoadingSubresources();
2440 if (m_documentLoader)
2441 m_documentLoader->stopLoadingPlugIns();
2443 setDocumentLoader(m_provisionalDocumentLoader.get());
2444 setProvisionalDocumentLoader(0);
2445 setState(FrameStateCommittedPage);
2447 // Handle adding the URL to the back/forward list.
2448 DocumentLoader* dl = m_documentLoader.get();
2450 switch (m_loadType) {
2451 case FrameLoadTypeForward:
2452 case FrameLoadTypeBack:
2453 case FrameLoadTypeIndexedBackForward:
2454 if (Page* page = m_frame->page())
2455 if (page->backForwardList()) {
2456 updateHistoryForBackForwardNavigation();
2458 // Create a document view for this document, or used the cached view.
2460 m_client->setDocumentViewFromCachedPage(cachedPage.get());
2462 m_client->makeDocumentView();
2466 case FrameLoadTypeReload:
2467 case FrameLoadTypeSame:
2468 case FrameLoadTypeReplace:
2469 updateHistoryForReload();
2470 m_client->makeDocumentView();
2473 // FIXME - just get rid of this case, and merge FrameLoadTypeReloadAllowingStaleData with the above case
2474 case FrameLoadTypeReloadAllowingStaleData:
2475 m_client->makeDocumentView();
2478 case FrameLoadTypeStandard:
2479 updateHistoryForStandardLoad();
2480 m_client->makeDocumentView();
2483 case FrameLoadTypeRedirectWithLockedHistory:
2484 updateHistoryForRedirectWithLockedHistory();
2485 m_client->makeDocumentView();
2488 // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is).
2489 // An exception should be thrown if we're in the FrameLoadTypeUninitialized state.
2491 ASSERT_NOT_REACHED();
2494 m_responseMIMEType = dl->responseMIMEType();
2496 // Tell the client we've committed this URL.
2497 ASSERT(m_client->hasFrameView());
2499 if (m_creatingInitialEmptyDocument)
2502 m_committedFirstRealDocumentLoad = true;
2505 bool FrameLoader::privateBrowsingEnabled() const
2507 return m_client->privateBrowsingEnabled();
2510 void FrameLoader::clientRedirectCancelledOrFinished(bool cancelWithLoadInProgress)
2512 // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
2513 // the redirect succeeded. We should either rename this API, or add a new method, like
2514 // -webView:didFinishClientRedirectForFrame:
2515 m_client->dispatchDidCancelClientRedirect();
2517 if (!cancelWithLoadInProgress)
2518 m_quickRedirectComing = false;
2520 m_sentRedirectNotification = false;
2523 void FrameLoader::clientRedirected(const KURL& URL, double seconds, double fireDate, bool lockHistory, bool isJavaScriptFormAction)
2525 m_client->dispatchWillPerformClientRedirect(URL, seconds, fireDate);
2527 // Remember that we sent a redirect notification to the frame load delegate so that when we commit
2528 // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
2529 m_sentRedirectNotification = true;
2531 // If a "quick" redirect comes in an, we set a special mode so we treat the next
2532 // load as part of the same navigation. If we don't have a document loader, we have
2533 // no "original" load on which to base a redirect, so we treat the redirect as a normal load.
2534 m_quickRedirectComing = lockHistory && m_documentLoader && !isJavaScriptFormAction;
2537 bool FrameLoader::shouldReload(const KURL& currentURL, const KURL& destinationURL)
2539 // This function implements the rule: "Don't reload if navigating by fragment within
2540 // the same URL, but do reload if going to a new URL or to the same URL with no
2541 // fragment identifier at all."
2542 if (!currentURL.hasRef() && !destinationURL.hasRef())
2544 return !equalIgnoringRef(currentURL, destinationURL);
2547 void FrameLoader::closeOldDataSources()
2549 // FIXME: Is it important for this traversal to be postorder instead of preorder?
2550 // If so, add helpers for postorder traversal, and use them. If not, then lets not
2551 // use a recursive algorithm here.
2552 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2553 child->loader()->closeOldDataSources();
2555 if (m_documentLoader)
2556 m_client->dispatchWillClose();
2558 m_client->setMainFrameDocumentReady(false); // stop giving out the actual DOMDocument to observers
2561 void FrameLoader::open(CachedPage& cachedPage)
2563 ASSERT(m_frame->page());
2564 ASSERT(m_frame->page()->mainFrame() == m_frame);
2566 cancelRedirection();
2568 // We still have to close the previous part page.
2571 m_isComplete = false;
2573 // Don't re-emit the load event.
2574 m_didCallImplicitClose = true;
2576 // Delete old status bar messages (if it _was_ activated on last URL).
2577 Settings* settings = m_frame->settings();
2578 if (settings && settings->isJavaScriptEnabled()) {
2579 m_frame->setJSStatusBarText(String());
2580 m_frame->setJSDefaultStatusBarText(String());
2583 KURL URL = cachedPage.URL();
2585 if (URL.protocol().startsWith("http") && !URL.host().isEmpty() && URL.path().isEmpty())
2595 Document* document = cachedPage.document();
2597 document->setInPageCache(false);
2599 m_needsClear = true;
2600 m_shouldClearWindowProperties = true;
2601 m_isComplete = false;
2602 m_didCallImplicitClose = false;
2603 m_outgoingReferrer = URL.url();
2605 FrameView* view = cachedPage.view();
2607 view->setWasScrolledByUser(false);
2608 m_frame->setView(view);
2610 m_frame->setDocument(document);
2611 m_decoder = document->decoder();
2613 updatePolicyBaseURL();
2615 cachedPage.restore(m_frame->page());
2620 bool FrameLoader::isStopping() const
2622 return activeDocumentLoader()->isStopping();
2625 void FrameLoader::finishedLoading()
2627 // Retain because the stop may release the last reference to it.
2628 RefPtr<Frame> protect(m_frame);
2630 RefPtr<DocumentLoader> dl = activeDocumentLoader();
2631 dl->finishedLoading();
2632 if (!dl->mainDocumentError().isNull() || !dl->frameLoader())
2634 dl->setPrimaryLoadComplete(true);
2635 m_client->dispatchDidLoadMainResource(dl.get());
2636 checkLoadComplete();
2639 // FIXME: Which one of these URL methods is right?
2641 KURL FrameLoader::url() const
2646 KURL FrameLoader::URL() const
2648 return activeDocumentLoader()->URL();
2651 bool FrameLoader::isArchiveLoadPending(ResourceLoader* loader) const
2653 return m_client->isArchiveLoadPending(loader);
2656 bool FrameLoader::isHostedByObjectElement() const
2658 HTMLFrameOwnerElement* owner = m_frame->ownerElement();
2659 return owner && owner->hasTagName(objectTag);
2662 bool FrameLoader::isLoadingMainFrame() const
2664 Page* page = m_frame->page();
2665 return page && m_frame == page->mainFrame();
2668 bool FrameLoader::canShowMIMEType(const String& MIMEType) const
2670 return m_client->canShowMIMEType(MIMEType);
2673 bool FrameLoader::representationExistsForURLScheme(const String& URLScheme)
2675 return m_client->representationExistsForURLScheme(URLScheme);
2678 String FrameLoader::generatedMIMETypeForURLScheme(const String& URLScheme)
2680 return m_client->generatedMIMETypeForURLScheme(URLScheme);
2683 void FrameLoader::cancelContentPolicyCheck()
2685 m_client->cancelPolicyCheck();
2686 m_policyCheck.clear();
2689 void FrameLoader::didReceiveServerRedirectForProvisionalLoadForFrame()
2691 m_client->dispatchDidReceiveServerRedirectForProvisionalLoad();
2694 void FrameLoader::finishedLoadingDocument(DocumentLoader* loader)
2696 m_client->finishedLoading(loader);
2699 bool FrameLoader::isReplacing() const
2701 return m_loadType == FrameLoadTypeReplace;
2704 void FrameLoader::setReplacing()
2706 m_loadType = FrameLoadTypeReplace;
2709 void FrameLoader::revertToProvisional(DocumentLoader* loader)
2711 m_client->revertToProvisionalState(loader);
2714 bool FrameLoader::subframeIsLoading() const
2716 // It's most likely that the last added frame is the last to load so we walk backwards.
2717 for (Frame* child = m_frame->tree()->lastChild(); child; child = child->tree()->previousSibling()) {
2718 FrameLoader* childLoader = child->loader();
2719 DocumentLoader* documentLoader = childLoader->documentLoader();
2720 if (documentLoader && documentLoader->isLoadingInAPISense())
2722 documentLoader = childLoader->provisionalDocumentLoader();
2723 if (documentLoader && documentLoader->isLoadingInAPISense())
2729 void FrameLoader::willChangeTitle(DocumentLoader* loader)
2731 m_client->willChangeTitle(loader);
2734 FrameLoadType FrameLoader::loadType() const
2739 void FrameLoader::stopPolicyCheck()
2741 m_client->cancelPolicyCheck();
2742 PolicyCheck check = m_policyCheck;
2743 m_policyCheck.clear();
2747 void FrameLoader::checkLoadCompleteForThisFrame()
2749 ASSERT(m_client->hasWebView());
2752 case FrameStateProvisional: {
2753 if (m_delegateIsHandlingProvisionalLoadError)
2756 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
2760 // If we've received any errors we may be stuck in the provisional state and actually complete.
2761 const ResourceError& error = pdl->mainDocumentError();
2765 // Check all children first.
2766 RefPtr<HistoryItem> item;
2767 if (Page* page = m_frame->page())
2768 if (isBackForwardLoadType(loadType()) && m_frame == page->mainFrame())
2769 item = m_currentHistoryItem;
2771 bool shouldReset = true;
2772 if (!pdl->isLoadingInAPISense()) {
2773 m_delegateIsHandlingProvisionalLoadError = true;
2774 m_client->dispatchDidFailProvisionalLoad(error);
2775 m_delegateIsHandlingProvisionalLoadError = false;
2777 // FIXME: can stopping loading here possibly have any effect, if isLoading is false,
2778 // which it must be to be in this branch of the if? And is it OK to just do a full-on
2779 // stopAllLoaders instead of stopLoadingSubframes?
2780 stopLoadingSubframes();
2783 // Finish resetting the load state, but only if another load hasn't been started by the
2784 // delegate callback.
2785 if (pdl == m_provisionalDocumentLoader)
2786 clearProvisionalLoad();
2787 else if (m_provisionalDocumentLoader) {
2788 KURL unreachableURL = m_provisionalDocumentLoader->unreachableURL();
2789 if (!unreachableURL.isEmpty() && unreachableURL == pdl->request().url())
2790 shouldReset = false;
2793 if (shouldReset && item)
2794 if (Page* page = m_frame->page())
2795 page->backForwardList()->goToItem(item.get());
2799 case FrameStateCommittedPage: {
2800 DocumentLoader* dl = m_documentLoader.get();
2801 if (!dl || dl->isLoadingInAPISense())
2806 // FIXME: Is this subsequent work important if we already navigated away?
2807 // Maybe there are bugs because of that, or extra work we can skip because
2808 // the new page is ready.
2810 m_client->forceLayoutForNonHTML();
2812 // If the user had a scroll point, scroll to it, overriding the anchor point if any.
2813 if (Page* page = m_frame->page())
2814 if ((isBackForwardLoadType(m_loadType) || m_loadType == FrameLoadTypeReload) && page->backForwardList())
2815 restoreScrollPositionAndViewState();
2817 if (m_creatingInitialEmptyDocument || !m_committedFirstRealDocumentLoad)
2820 const ResourceError& error = dl->mainDocumentError();
2821 if (!error.isNull())
2822 m_client->dispatchDidFailLoad(error);
2824 m_client->dispatchDidFinishLoad();
2826 if (Page* page = m_frame->page())
2827 page->progress()->progressCompleted(m_frame);
2831 case FrameStateComplete:
2832 // Even if already complete, we might have set a previous item on a frame that
2833 // didn't do any data loading on the past transaction. Make sure to clear these out.
2834 m_client->frameLoadCompleted();
2838 ASSERT_NOT_REACHED();
2841 void FrameLoader::continueAfterContentPolicy(PolicyAction policy)
2843 PolicyCheck check = m_policyCheck;
2844 m_policyCheck.clear();
2848 void FrameLoader::continueLoadAfterWillSubmitForm(PolicyAction)
2850 if (!m_provisionalDocumentLoader)
2853 m_provisionalDocumentLoader->prepareForLoadStart();
2855 DocumentLoader* activeDocLoader = activeDocumentLoader();
2856 if (activeDocLoader && activeDocLoader->isLoadingMainResource())
2859 m_provisionalDocumentLoader->setLoadingFromCachedPage(false);
2861 unsigned long identifier = 0;
2863 if (Page* page = m_frame->page()) {
2864 identifier = page->progress()->createUniqueIdentifier();
2865 dispatchAssignIdentifierToInitialRequest(identifier, m_provisionalDocumentLoader.get(), m_provisionalDocumentLoader->originalRequest());
2868 if (!m_provisionalDocumentLoader->startLoadingMainResource(identifier))
2869 m_provisionalDocumentLoader->updateLoading();
2872 void FrameLoader::didFirstLayout()
2874 if (Page* page = m_frame->page())
2875 if (isBackForwardLoadType(m_loadType) && page->backForwardList())
2876 restoreScrollPositionAndViewState();
2878 m_firstLayoutDone = true;
2879 m_client->dispatchDidFirstLayout();
2882 void FrameLoader::frameLoadCompleted()
2884 m_client->frameLoadCompleted();
2886 // After a canceled provisional load, firstLayoutDone is false.
2887 // Reset it to true if we're displaying a page.
2888 if (m_documentLoader)
2889 m_firstLayoutDone = true;
2892 bool FrameLoader::firstLayoutDone() const
2894 return m_firstLayoutDone;
2897 bool FrameLoader::isQuickRedirectComing() const
2899 return m_quickRedirectComing;
2902 void FrameLoader::detachChildren()
2904 // FIXME: Is it really necessary to do this in reverse order?
2906 for (Frame* child = m_frame->tree()->lastChild(); child; child = previous) {
2907 previous = child->tree()->previousSibling();
2908 child->loader()->detachFromParent();
2912 void FrameLoader::recursiveCheckLoadComplete()
2914 Vector<RefPtr<Frame>, 10> frames;
2916 for (RefPtr<Frame> frame = m_frame->tree()->firstChild(); frame; frame = frame->tree()->nextSibling())
2917 frames.append(frame);
2919 unsigned size = frames.size();
2920 for (unsigned i = 0; i < size; i++)
2921 frames[i]->loader()->recursiveCheckLoadComplete();
2923 checkLoadCompleteForThisFrame();
2926 // Called every time a resource is completely loaded, or an error is received.
2927 void FrameLoader::checkLoadComplete()
2929 ASSERT(m_client->hasWebView());
2931 // FIXME: Always traversing the entire frame tree is a bit inefficient, but
2932 // is currently needed in order to null out the previous history item for all frames.
2933 if (Page* page = m_frame->page())
2934 page->mainFrame()->loader()->recursiveCheckLoadComplete();
2937 int FrameLoader::numPendingOrLoadingRequests(bool recurse) const
2940 return numRequests(m_frame->document());
2943 for (Frame* frame = m_frame; frame; frame = frame->tree()->traverseNext(m_frame))
2944 count += numRequests(frame->document());
2948 FrameLoaderClient* FrameLoader::client() const
2953 void FrameLoader::submitForm(const FrameLoadRequest& request, Event* event)
2955 // FIXME: We'd like to remove this altogether and fix the multiple form submission issue another way.
2956 // We do not want to submit more than one form from the same page,
2957 // nor do we want to submit a single form more than once.
2958 // This flag prevents these from happening; not sure how other browsers prevent this.
2959 // The flag is reset in each time we start handle a new mouse or key down event, and
2960 // also in setView since this part may get reused for a page from the back/forward cache.
2961 // The form multi-submit logic here is only needed when we are submitting a form that affects this frame.
2962 // FIXME: Frame targeting is only one of the ways the submission could end up doing something other
2963 // than replacing this frame's content, so this check is flawed. On the other hand, the check is hardly
2964 // needed any more now that we reset m_submittedFormURL on each mouse or key down event.
2965 Frame* target = m_frame->tree()->find(request.frameName());
2966 if (m_frame->tree()->isDescendantOf(target)) {
2967 if (m_submittedFormURL == request.resourceRequest().url())
2969 m_submittedFormURL = request.resourceRequest().url();
2972 // FIXME: We should probably call userGestureHint() to tell whether this form submission was the result of a user gesture.
2973 load(request, false, true, event, m_formAboutToBeSubmitted.get(), m_formValuesAboutToBeSubmitted);
2975 clearRecordedFormValues();
2978 void FrameLoader::urlSelected(const FrameLoadRequest& request, Event* event, bool lockHistory, bool userGesture)
2980 FrameLoadRequest copy = request;
2981 if (copy.resourceRequest().httpReferrer().isEmpty())
2982 copy.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
2984 load(copy, lockHistory, userGesture, event, 0, HashMap<String, String>());
2987 String FrameLoader::userAgent(const KURL& url) const
2989 return m_client->userAgent(url);
2992 void FrameLoader::tokenizerProcessedData()
2994 ASSERT(m_frame->page());
2995 ASSERT(m_frame->document());
3000 void FrameLoader::didTellBridgeAboutLoad(const String& URL)
3002 m_urlsBridgeKnowsAbout.add(URL);
3005 bool FrameLoader::haveToldBridgeAboutLoad(const String& URL)
3007 return m_urlsBridgeKnowsAbout.contains(URL);
3010 void FrameLoader::handledOnloadEvents()
3012 m_client->dispatchDidHandleOnloadEvents();
3015 void FrameLoader::frameDetached()
3021 void FrameLoader::detachFromParent()
3023 RefPtr<Frame> protect(m_frame);
3027 saveScrollPositionAndViewStateToItem(currentHistoryItem());
3030 if (Page* page = m_frame->page())
3031 page->inspectorController()->frameDetachedFromParent(m_frame);
3033 m_client->detachedFromParent2();
3034 setDocumentLoader(0);
3035 m_client->detachedFromParent3();
3036 if (Frame* parent = m_frame->tree()->parent()) {
3037 parent->tree()->removeChild(m_frame);
3038 parent->loader()->scheduleCheckCompleted();
3040 m_frame->setView(0);
3041 m_frame->pageDestroyed();
3044 [m_frame->bridge() close];
3046 m_client->detachedFromParent4();
3049 void FrameLoader::dispatchDidChangeLocationWithinPage()
3051 m_client->dispatchDidChangeLocationWithinPage();
3054 void FrameLoader::dispatchDidFinishLoadToClient()
3056 m_client->didFinishLoad();
3059 void FrameLoader::updateGlobalHistoryForStandardLoad(const KURL& url)
3061 m_client->updateGlobalHistoryForStandardLoad(url);
3064 void FrameLoader::updateGlobalHistoryForReload(const KURL& url)
3066 m_client->updateGlobalHistoryForReload(url);
3069 bool FrameLoader::shouldGoToHistoryItem(HistoryItem* item) const
3071 return m_client->shouldGoToHistoryItem(item);
3074 void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, bool mainResource, bool alwaysFromRequest)
3076 applyUserAgent(request);
3078 if (m_loadType == FrameLoadTypeReload)
3079 request.setHTTPHeaderField("Cache-Control", "max-age=0");
3081 // Don't set the cookie policy URL if it's already been set.
3082 if (request.mainDocumentURL().isEmpty()) {
3083 if (mainResource && (isLoadingMainFrame() || alwaysFromRequest))
3084 request.setMainDocumentURL(request.url());
3085 else if (Page* page = m_frame->page())
3086 request.setMainDocumentURL(page->mainFrame()->loader()->url());
3090 request.setHTTPAccept("text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5");
3093 void FrameLoader::committedLoad(DocumentLoader* loader, const char* data, int length)
3095 m_client->committedLoad(loader, data, length);
3098 void FrameLoader::post(const KURL& URL, const String& referrer, const String& frameName, PassRefPtr<FormData> formData,
3099 const String& contentType, Event* event, HTMLFormElement* form, const HashMap<String, String>& formValues)
3101 // When posting, use the NSURLRequestReloadIgnoringCacheData load flag.
3102 // This prevents a potential bug which may cause a page with a form that uses itself
3103 // as an action to be returned from the cache without submitting.
3105 // FIXME: Where's the code that implements what the comment above says?
3107 ResourceRequest request(URL);
3108 addExtraFieldsToRequest(request, true, true);
3110 if (!referrer.isEmpty())
3111 request.setHTTPReferrer(referrer);
3112 request.setHTTPMethod("POST");
3113 request.setHTTPBody(formData);
3114 request.setHTTPContentType(contentType);
3116 NavigationAction action(URL, FrameLoadTypeStandard, true, event);
3118 RefPtr<FormState> formState;
3119 if (form && !formValues.isEmpty())
3120 formState = FormState::create(form, formValues, m_frame);
3122 if (!frameName.isEmpty()) {
3123 if (Frame* targetFrame = m_frame->tree()->find(frameName))
3124 targetFrame->loader()->load(request, action, FrameLoadTypeStandard, formState.release());
3126 checkNewWindowPolicy(action, request, formState.release(), frameName);
3128 load(request, action, FrameLoadTypeStandard, formState.release());
3131 bool FrameLoader::isReloading() const
3133 return documentLoader()->request().cachePolicy() == ReloadIgnoringCacheData;
3136 void FrameLoader::loadEmptyDocumentSynchronously()
3138 ResourceRequest request(KURL(""));
3142 void FrameLoader::loadResourceSynchronously(const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data)
3144 // Since this is a subresource, we can load any URL (we ignore the return value).
3145 // But we still want to know whether we should hide the referrer or not, so we call the canLoad method.
3146 String referrer = m_outgoingReferrer;
3147 if (shouldHideReferrer(request.url(), referrer))
3148 referrer = String();
3150 ResourceRequest initialRequest = request;
3151 initialRequest.setTimeoutInterval(10);
3153 if (initialRequest.isConditional())
3154 initialRequest.setCachePolicy(ReloadIgnoringCacheData);
3156 initialRequest.setCachePolicy(documentLoader()->request().cachePolicy());
3158 if (!referrer.isEmpty())
3159 initialRequest.setHTTPReferrer(referrer);
3161 if (Page* page = m_frame->page())
3162 initialRequest.setMainDocumentURL(page->mainFrame()->loader()->documentLoader()->request().url());
3163 initialRequest.setHTTPUserAgent(client()->userAgent(request.url()));
3165 unsigned long identifier = 0;
3166 ResourceRequest newRequest(initialRequest);
3167 requestFromDelegate(newRequest, identifier, error);
3169 if (error.isNull()) {
3170 ASSERT(!newRequest.isNull());
3171 didTellBridgeAboutLoad(newRequest.url().url());
3172 ResourceHandle::loadResourceSynchronously(newRequest, error, response, data);
3175 sendRemainingDelegateMessages(identifier, response, data.size(), error);
3178 void FrameLoader::assignIdentifierToInitialRequest(unsigned long identifier, const ResourceRequest& clientRequest)
3180 return dispatchAssignIdentifierToInitialRequest(identifier, activeDocumentLoader(), clientRequest);
3183 void FrameLoader::willSendRequest(ResourceLoader* loader, ResourceRequest& clientRequest, const ResourceResponse& redirectResponse)
3185 applyUserAgent(clientRequest);
3186 dispatchWillSendRequest(loader->documentLoader(), loader->identifier(), clientRequest, redirectResponse);
3189 void FrameLoader::didReceiveResponse(ResourceLoader* loader, const ResourceResponse& r)
3191 activeDocumentLoader()->addResponse(r);
3193 if (Page* page = m_frame->page())
3194 page->progress()->incrementProgress(loader->identifier(), r);
3195 dispatchDidReceiveResponse(loader->documentLoader(), loader->identifier(), r);
3198 void FrameLoader::didReceiveData(ResourceLoader* loader, const char* data, int length, int lengthReceived)
3200 if (Page* page = m_frame->page())
3201 page->progress()->incrementProgress(loader->identifier(), data, length);
3202 dispatchDidReceiveContentLength(loader->documentLoader(), loader->identifier(), lengthReceived);
3205 void FrameLoader::didFailToLoad(ResourceLoader* loader, const ResourceError& error)
3207 if (Page* page = m_frame->page())
3208 page->progress()->completeProgress(loader->identifier());
3209 if (!error.isNull())
3210 m_client->dispatchDidFailLoading(loader->documentLoader(), loader->identifier(), error);
3213 const ResourceRequest& FrameLoader::originalRequest() const
3215 return activeDocumentLoader()->originalRequestCopy();
3218 void FrameLoader::receivedMainResourceError(const ResourceError& error, bool isComplete)
3220 // Retain because the stop may release the last reference to it.
3221 RefPtr<Frame> protect(m_frame);
3223 RefPtr<DocumentLoader> loader = activeDocumentLoader();
3226 // FIXME: Don't want to do this if an entirely new load is going, so should check
3227 // that both data sources on the frame are either this or nil.
3229 if (m_client->shouldFallBack(error))
3230 handleFallbackContent();
3233 if (m_state == FrameStateProvisional) {
3234 KURL failedURL = m_provisionalDocumentLoader->originalRequestCopy().url();
3235 didNotOpenURL(failedURL);
3237 // We might have made a page cache item, but now we're bailing out due to an error before we ever
3238 // transitioned to the new page (before WebFrameState == commit). The goal here is to restore any state
3239 // so that the existing view (that wenever got far enough to replace) can continue being used.
3240 m_frame->document()->setInPageCache(false);
3241 invalidateCurrentItemCachedPage();
3243 // Call clientRedirectCancelledOrFinished here so that the frame load delegate is notified that the redirect's
3244 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
3245 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are definitely
3246 // not going to use this provisional resource, as it was cancelled, notify the frame load delegate that the redirect
3248 if (m_sentRedirectNotification)
3249 clientRedirectCancelledOrFinished(false);
3253 loader->mainReceivedError(error, isComplete);
3256 void FrameLoader::callContinueFragmentScrollAfterNavigationPolicy(void* argument,
3257 const ResourceRequest& request, PassRefPtr<FormState>, bool shouldContinue)
3259 FrameLoader* loader = static_cast<FrameLoader*>(argument);
3260 loader->continueFragmentScrollAfterNavigationPolicy(request, shouldContinue);
3263 void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequest& request, bool shouldContinue)
3265 bool isRedirect = m_quickRedirectComing;
3266 m_quickRedirectComing = false;
3268 if (!shouldContinue)
3271 KURL URL = request.url();
3273 m_documentLoader->replaceRequestURLForAnchorScroll(URL);
3274 if (!isRedirect && !shouldTreatURLAsSameAsCurrent(URL)) {
3275 // NB: must happen after _setURL, since we add based on the current request.
3276 // Must also happen before we openURL and displace the scroll position, since
3277 // adding the BF item will save away scroll state.
3279 // NB2: If we were loading a long, slow doc, and the user anchor nav'ed before
3280 // it was done, currItem is now set the that slow doc, and prevItem is whatever was
3281 // before it. Adding the b/f item will bump the slow doc down to prevItem, even
3282 // though its load is not yet done. I think this all works out OK, for one because
3283 // we have already saved away the scroll and doc state for the long slow load,
3284 // but it's not an obvious case.
3286 addHistoryItemForFragmentScroll();
3289 scrollToAnchor(URL);
3292 // This will clear previousItem from the rest of the frame tree that didn't
3293 // doing any loading. We need to make a pass on this now, since for anchor nav
3294 // we'll not go through a real load and reach Completed state.
3295 checkLoadComplete();
3297 dispatchDidChangeLocationWithinPage();
3298 m_client->didFinishLoad();
3301 void FrameLoader::opened()
3303 if (m_loadType == FrameLoadTypeStandard && m_documentLoader->isClientRedirect())
3304 updateHistoryForClientRedirect();
3306 if (m_documentLoader->isLoadingFromCachedPage()) {
3307 m_frame->document()->didRestoreFromCache();
3309 // Force a layout to update view size and thereby update scrollbars.
3310 m_client->forceLayout();
3312 const ResponseVector& responses = m_documentLoader->responses();
3313 size_t count = responses.size();
3314 for (size_t i = 0; i < count; i++) {
3315 const ResourceResponse& response = responses[i];
3316 // FIXME: If the WebKit client changes or cancels the request, this is not respected.
3317 ResourceError error;
3318 unsigned long identifier;
3319 ResourceRequest request(response.url());
3320 requestFromDelegate(request, identifier, error);
3321 // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
3322 // However, with today's computers and networking speeds, this won't happen in practice.
3323 // Could be an issue with a giant local file.
3324 sendRemainingDelegateMessages(identifier, response, static_cast<int>(response.expectedContentLength()), error);
3327 pageCache()->remove(m_currentHistoryItem.get());
3329 m_documentLoader->setPrimaryLoadComplete(true);
3331 // FIXME: Why only this frame and not parent frames?
3332 checkLoadCompleteForThisFrame();
3336 void FrameLoader::checkNewWindowPolicy(const NavigationAction& action, const ResourceRequest& request,
3337 PassRefPtr<FormState> formState, const String& frameName)
3339 m_policyCheck.set(request, formState, frameName,
3340 callContinueLoadAfterNewWindowPolicy, this);
3341 m_client->dispatchDecidePolicyForNewWindowAction(&FrameLoader::continueAfterNewWindowPolicy,
3342 action, request, frameName);
3345 void FrameLoader::continueAfterNewWindowPolicy(PolicyAction policy)
3347 PolicyCheck check = m_policyCheck;
3348 m_policyCheck.clear();
3352 check.clearRequest();
3354 case PolicyDownload:
3355 m_client->startDownload(check.request());
3356 check.clearRequest();
3362 check.call(policy == PolicyUse);
3365 void FrameLoader::checkNavigationPolicy(const ResourceRequest& request, DocumentLoader* loader,
3366 PassRefPtr<FormState> formState, NavigationPolicyDecisionFunction function, void* argument)
3368 NavigationAction action = loader->triggeringAction();
3369 if (action.isEmpty()) {
3370 action = NavigationAction(request.url(), NavigationTypeOther);
3371 loader->setTriggeringAction(action);
3374 // Don't ask more than once for the same request or if we are loading an empty URL.
3375 // This avoids confusion on the part of the client.
3376 if (equalIgnoringHeaderFields(request, loader->lastCheckedRequest()) || (!request.isNull() && request.url().isEmpty())) {
3377 function(argument, request, 0, true);
3378 loader->setLastCheckedRequest(request);
3382 // We are always willing to show alternate content for unreachable URLs;
3383 // treat it like a reload so it maintains the right state for b/f list.
3384 if (loader->substituteData().isValid() && !loader->substituteData().failingURL().isEmpty()) {
3385 if (isBackForwardLoadType(m_policyLoadType))
3386 m_policyLoadType = FrameLoadTypeReload;
3387 function(argument, request, 0, true);
3391 loader->setLastCheckedRequest(request);
3393 m_policyCheck.set(request, formState, function, argument);
3395 m_delegateIsDecidingNavigationPolicy = true;
3396 m_client->dispatchDecidePolicyForNavigationAction(&FrameLoader::continueAfterNavigationPolicy,
3398 m_delegateIsDecidingNavigationPolicy = false;
3401 void FrameLoader::continueAfterNavigationPolicy(PolicyAction policy)
3403 PolicyCheck check = m_policyCheck;
3404 m_policyCheck.clear();
3406 bool shouldContinue = policy == PolicyUse;
3410 check.clearRequest();
3412 case PolicyDownload:
3413 m_client->startDownload(check.request());
3414 check.clearRequest();
3417 ResourceRequest request(check.request());
3419 if (!m_client->canHandleRequest(request)) {
3420 handleUnimplementablePolicy(m_client->cannotShowURLError(check.request()));
3421 check.clearRequest();
3422 shouldContinue = false;
3428 check.call(shouldContinue);
3431 void FrameLoader::callContinueLoadAfterNavigationPolicy(void* argument,
3432 const ResourceRequest& request, PassRefPtr<FormState> formState, bool shouldContinue)
3434 FrameLoader* loader = static_cast<FrameLoader*>(argument);
3435 loader->continueLoadAfterNavigationPolicy(request, formState, shouldContinue);
3438 void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest& request, PassRefPtr<FormState> formState, bool shouldContinue)
3440 // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
3441 // nil policyDataSource because loading the alternate page will have passed
3442 // through this method already, nested; otherwise, policyDataSource should still be set.
3443 ASSERT(m_policyDocumentLoader || !m_provisionalDocumentLoader->unreachableURL().isEmpty());
3445 bool isTargetItem = m_provisionalHistoryItem ? m_provisionalHistoryItem->isTargetItem() : false;
3447 // Two reasons we can't continue:
3448 // 1) Navigation policy delegate said we can't so request is nil. A primary case of this
3449 // is the user responding Cancel to the form repost nag sheet.
3450 // 2) User responded Cancel to an alert popped up by the before unload event handler.
3451 // The "before unload" event handler runs only for the main frame.
3452 bool canContinue = shouldContinue && (!isLoadingMainFrame() || m_frame->shouldClose());
3455 // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we
3456 // need to report that the client redirect was cancelled.
3457 if (m_quickRedirectComing)
3458 clientRedirectCancelledOrFinished(false);
3460 setPolicyDocumentLoader(0);
3462 // If the navigation request came from the back/forward menu, and we punt on it, we have the
3463 // problem that we have optimistically moved the b/f cursor already, so move it back. For sanity,
3464 // we only do this when punting a navigation for the target frame or top-level frame.
3465 if ((isTargetItem || isLoadingMainFrame()) && isBackForwardLoadType(m_policyLoadType))
3466 if (Page* page = m_frame->page()) {
3467 Frame* mainFrame = page->mainFrame();
3468 if (HistoryItem* resetItem = mainFrame->loader()->m_currentHistoryItem.get())
3469 page->backForwardList()->goToItem(resetItem);
3474 FrameLoadType type = m_policyLoadType;
3476 setProvisionalDocumentLoader(m_policyDocumentLoader.get());
3478 setState(FrameStateProvisional);
3480 setPolicyDocumentLoader(0);
3482 if (isBackForwardLoadType(type) && loadProvisionalItemFromCachedPage())
3486 m_client->dispatchWillSubmitForm(&FrameLoader::continueLoadAfterWillSubmitForm, formState);
3488 continueLoadAfterWillSubmitForm();
3492 void FrameLoader::callContinueLoadAfterNewWindowPolicy(void* argument,
3493 const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, bool shouldContinue)
3495 FrameLoader* loader = static_cast<FrameLoader*>(argument);
3496 loader->continueLoadAfterNewWindowPolicy(request, formState, frameName, shouldContinue);
3499 void FrameLoader::continueLoadAfterNewWindowPolicy(const ResourceRequest& request,
3500 PassRefPtr<FormState> formState, const String& frameName, bool shouldContinue)
3502 if (!shouldContinue)
3505 RefPtr<Frame> frame = m_frame;
3506 RefPtr<Frame> mainFrame = m_client->dispatchCreatePage();
3510 if (frameName != "_blank")
3511 mainFrame->tree()->setName(frameName);
3513 mainFrame->loader()->setOpenedByDOM();
3514 mainFrame->loader()->m_client->dispatchShow();
3515 mainFrame->loader()->setOpener(frame.get());
3516 mainFrame->loader()->load(request, NavigationAction(), FrameLoadTypeStandard, formState);
3519 void FrameLoader::sendRemainingDelegateMessages(unsigned long identifier, const ResourceResponse& response, int length, const ResourceError& error)
3521 if (!response.isNull())
3522 dispatchDidReceiveResponse(m_documentLoader.get(), identifier, response);
3525 dispatchDidReceiveContentLength(m_documentLoader.get(), identifier, length);
3528 dispatchDidFinishLoading(m_documentLoader.get(), identifier);
3530 m_client->dispatchDidFailLoading(m_documentLoader.get(), identifier, error);
3533 void FrameLoader::requestFromDelegate(ResourceRequest& request, unsigned long& identifier, ResourceError& error)
3535 ASSERT(!request.isNull());
3538 if (Page* page = m_frame->page()) {
3539 identifier = page->progress()->createUniqueIdentifier();
3540 dispatchAssignIdentifierToInitialRequest(identifier, m_documentLoader.get(), request);
3543 ResourceRequest newRequest(request);
3544 dispatchWillSendRequest(m_documentLoader.get(), identifier, newRequest, ResourceResponse());
3546 if (newRequest.isNull())
3547 error = m_client->cancelledError(request);
3549 error = ResourceError();
3551 request = newRequest;
3554 void FrameLoader::loadedResourceFromMemoryCache(const ResourceRequest& request, const ResourceResponse& response, int length)
3556 if (dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(), request, response, length))
3559 unsigned long identifier;
3560 ResourceError error;
3561 ResourceRequest r(request);
3562 requestFromDelegate(r, identifier, error);
3563 sendRemainingDelegateMessages(identifier, response, length, error);
3566 void FrameLoader::applyUserAgent(ResourceRequest& request)
3568 String userAgent = client()->userAgent(request.url());
3569 ASSERT(!userAgent.isNull());
3570 request.setHTTPUserAgent(userAgent);
3573 bool FrameLoader::canGoBackOrForward(int distance) const
3575 if (Page* page = m_frame->page()) {
3578 if (distance > 0 && distance <= page->backForwardList()->forwardListCount())
3580 if (distance < 0 && -distance <= page->backForwardList()->backListCount())
3586 int FrameLoader::getHistoryLength()
3588 if (Page* page = m_frame->page())
3589 return page->backForwardList()->backListCount() + 1;
3593 KURL FrameLoader::historyURL(int distance)
3595 if (Page* page = m_frame->page()) {
3596 BackForwardList* list = page->backForwardList();
3597 HistoryItem* item = list->itemAtIndex(distance);
3600 int forwardListCount = list->forwardListCount();
3601 if (forwardListCount > 0)
3602 item = list->itemAtIndex(forwardListCount);
3604 int backListCount = list->backListCount();
3605 if (backListCount > 0)
3606 item = list->itemAtIndex(-backListCount);
3615 void FrameLoader::addHistoryItemForFragmentScroll()
3617 addBackForwardItemClippedAtTarget(false);
3620 bool FrameLoader::loadProvisionalItemFromCachedPage()
3622 RefPtr<CachedPage> cachedPage = pageCache()->get(m_provisionalHistoryItem.get());
3623 if (!cachedPage || !cachedPage->document())
3625 provisionalDocumentLoader()->loadFromCachedPage(cachedPage.release());
3629 void FrameLoader::cachePageForHistoryItem(HistoryItem* item)
3631 if (Page* page = m_frame->page()) {
3632 RefPtr<CachedPage> cachedPage = CachedPage::create(page);
3633 cachedPage->setTimeStampToNow();
3634 cachedPage->setDocumentLoader(documentLoader());
3635 m_client->saveDocumentViewToCachedPage(cachedPage.get());
3637 pageCache()->add(item, cachedPage.release());
3641 bool FrameLoader::shouldTreatURLAsSameAsCurrent(const KURL& URL) const