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