FrameLoader.cpp 132 KB
Newer Older
mjs's avatar
mjs committed
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 6
 * Copyright (C) 2008 Alp Toker <alp@atoker.com>
 * Copyright (C) Research In Motion Limited 2009. All rights reserved.
7
 * Copyright (C) 2011 Kris Jordan <krisjordan@gmail.com>
8
 * Copyright (C) 2011 Google Inc. All rights reserved.
mjs's avatar
mjs committed
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer. 
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution. 
 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
 *     its contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission. 
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

darin's avatar
darin committed
35 36
#include "config.h"
#include "FrameLoader.h"
mjs's avatar
mjs committed
37

38
#include "AXObjectCache.h"
39
#include "ApplicationCacheHost.h"
40
#include "BackForwardController.h"
41
#include "BeforeUnloadEvent.h"
42
#include "MemoryCache.h"
beidson's avatar
beidson committed
43
#include "CachedPage.h"
44
#include "CachedResourceLoader.h"
ggaren's avatar
ggaren committed
45
#include "Chrome.h"
46
#include "ChromeClient.h"
47
#include "Console.h"
48
#include "ContentSecurityPolicy.h"
darin's avatar
darin committed
49
#include "DOMImplementation.h"
50
#include "DOMWindow.h"
51
#include "DatabaseManager.h"
darin's avatar
darin committed
52
#include "Document.h"
53
#include "DocumentLoadTiming.h"
ggaren's avatar
ggaren committed
54
#include "DocumentLoader.h"
darin's avatar
darin committed
55
#include "Editor.h"
andersca's avatar
andersca committed
56
#include "EditorClient.h"
darin's avatar
darin committed
57
#include "Element.h"
darin's avatar
darin committed
58
#include "Event.h"
darin's avatar
darin committed
59
#include "EventNames.h"
ggaren's avatar
ggaren committed
60 61
#include "FloatRect.h"
#include "FormState.h"
62
#include "FormSubmission.h"
darin's avatar
darin committed
63
#include "Frame.h"
ggaren's avatar
ggaren committed
64
#include "FrameLoadRequest.h"
darin's avatar
darin committed
65
#include "FrameLoaderClient.h"
66
#include "FrameNetworkingContext.h"
ggaren's avatar
ggaren committed
67
#include "FrameTree.h"
darin's avatar
darin committed
68
#include "FrameView.h"
69
#include "HTMLAnchorElement.h"
darin's avatar
darin committed
70
#include "HTMLFormElement.h"
71
#include "HTMLInputElement.h"
darin's avatar
darin committed
72 73
#include "HTMLNames.h"
#include "HTMLObjectElement.h"
74
#include "HTMLParserIdioms.h"
ap's avatar
ap committed
75
#include "HTTPParsers.h"
weinig's avatar
weinig committed
76
#include "HistoryItem.h"
77
#include "InspectorController.h"
78
#include "InspectorInstrumentation.h"
79
#include "LoaderStrategy.h"
beidson's avatar
beidson committed
80
#include "Logging.h"
weinig's avatar
weinig committed
81
#include "MIMETypeRegistry.h"
ggaren's avatar
ggaren committed
82
#include "Page.h"
ggaren's avatar
ggaren committed
83
#include "PageCache.h"
84
#include "PageTransitionEvent.h"
85
#include "PlatformStrategies.h"
86
#include "PluginData.h"
87
#include "PluginDatabase.h"
88
#include "PluginDocument.h"
89
#include "PolicyChecker.h"
andersca's avatar
andersca committed
90
#include "ProgressTracker.h"
beidson's avatar
beidson committed
91
#include "ResourceHandle.h"
darin's avatar
darin committed
92
#include "ResourceRequest.h"
93
#include "SchemeRegistry.h"
94
#include "ScriptCallStack.h"
95
#include "ScriptController.h"
96
#include "ScriptSourceCode.h"
97
#include "ScrollAnimator.h"
weinig's avatar
weinig committed
98
#include "SecurityOrigin.h"
99
#include "SecurityPolicy.h"
darin's avatar
darin committed
100
#include "SegmentedString.h"
101
#include "SerializedScriptValue.h"
darin's avatar
darin committed
102 103
#include "Settings.h"
#include "TextResourceDecoder.h"
104
#include "WebCoreMemoryInstrumentation.h"
ggaren's avatar
ggaren committed
105
#include "WindowFeatures.h"
106
#include "XMLDocumentParser.h"
ap@webkit.org's avatar
ap@webkit.org committed
107
#include <wtf/CurrentTime.h>
108
#include <wtf/MemoryInstrumentationHashSet.h>
109
#include <wtf/StdLibExtras.h>
110
#include <wtf/text/CString.h>
111
#include <wtf/text/WTFString.h>
darin's avatar
darin committed
112

113 114 115
#if ENABLE(SHARED_WORKERS)
#include "SharedWorkerRepository.h"
#endif
darin@apple.com's avatar
darin@apple.com committed
116

oliver's avatar
oliver committed
117 118 119 120 121 122 123 124 125 126
#if ENABLE(SVG)
#include "SVGDocument.h"
#include "SVGLocatable.h"
#include "SVGNames.h"
#include "SVGPreserveAspectRatio.h"
#include "SVGSVGElement.h"
#include "SVGViewElement.h"
#include "SVGViewSpec.h"
#endif

127
#if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
128 129 130
#include "Archive.h"
#endif

131

darin's avatar
darin committed
132 133
namespace WebCore {

134 135
using namespace HTMLNames;

136
#if ENABLE(SVG)
oliver's avatar
oliver committed
137
using namespace SVGNames;
138
#endif
darin's avatar
darin committed
139

140
static const char defaultAcceptHeader[] = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
darin's avatar
darin committed
141 142 143 144 145 146 147
static double storedTimeOfLastCompletedLoad;

bool isBackForwardLoadType(FrameLoadType type)
{
    switch (type) {
        case FrameLoadTypeStandard:
        case FrameLoadTypeReload:
148
        case FrameLoadTypeReloadFromOrigin:
darin's avatar
darin committed
149
        case FrameLoadTypeSame:
ggaren@apple.com's avatar
ggaren@apple.com committed
150
        case FrameLoadTypeRedirectWithLockedBackForwardList:
darin's avatar
darin committed
151 152 153 154 155 156 157 158 159 160 161
        case FrameLoadTypeReplace:
            return false;
        case FrameLoadTypeBack:
        case FrameLoadTypeForward:
        case FrameLoadTypeIndexedBackForward:
            return true;
    }
    ASSERT_NOT_REACHED();
    return false;
}

162 163 164 165 166 167 168 169
// This is not in the FrameLoader class to emphasize that it does not depend on
// private FrameLoader data, and to avoid increasing the number of public functions
// with access to private data.  Since only this .cpp file needs it, making it
// non-member lets us exclude it from the header file, thus keeping FrameLoader.h's
// API simpler.
//
static bool isDocumentSandboxed(Frame* frame, SandboxFlags mask)
{
170
    return frame->document() && frame->document()->isSandboxed(mask);
171 172
}

173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
class FrameLoader::FrameProgressTracker {
public:
    static PassOwnPtr<FrameProgressTracker> create(Frame* frame) { return adoptPtr(new FrameProgressTracker(frame)); }
    ~FrameProgressTracker()
    {
        ASSERT(!m_inProgress || m_frame->page());
        if (m_inProgress)
            m_frame->page()->progress()->progressCompleted(m_frame);
    }

    void progressStarted()
    {
        ASSERT(m_frame->page());
        if (!m_inProgress)
            m_frame->page()->progress()->progressStarted(m_frame);
        m_inProgress = true;
    }

    void progressCompleted()
    {
        ASSERT(m_inProgress);
        ASSERT(m_frame->page());
        m_inProgress = false;
        m_frame->page()->progress()->progressCompleted(m_frame);
    }

private:
    FrameProgressTracker(Frame* frame)
        : m_frame(frame)
        , m_inProgress(false)
    {
    }

    Frame* m_frame;
    bool m_inProgress;
};

ggaren's avatar
ggaren committed
210
FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client)
darin's avatar
darin committed
211
    : m_frame(frame)
ggaren's avatar
ggaren committed
212
    , m_client(client)
213
    , m_policyChecker(frame)
214
    , m_history(frame)
215
    , m_notifer(frame)
216
    , m_subframeLoader(frame)
217
    , m_icon(frame)
218
    , m_mixedContentChecker(frame)
219
    , m_state(FrameStateProvisional)
darin's avatar
darin committed
220 221 222 223
    , m_loadType(FrameLoadTypeStandard)
    , m_delegateIsHandlingProvisionalLoadError(false)
    , m_quickRedirectComing(false)
    , m_sentRedirectNotification(false)
darin's avatar
darin committed
224 225
    , m_inStopAllLoaders(false)
    , m_isExecutingJavaScriptFormAction(false)
226
    , m_didCallImplicitClose(true)
darin's avatar
darin committed
227
    , m_wasUnloadEventEmitted(false)
228
    , m_pageDismissalEventBeingDispatched(NoDismissal)
darin's avatar
darin committed
229 230
    , m_isComplete(false)
    , m_needsClear(false)
231 232 233
    , m_checkTimer(this, &FrameLoader::checkTimerFired)
    , m_shouldCallCheckCompleted(false)
    , m_shouldCallCheckLoadComplete(false)
darin's avatar
darin committed
234
    , m_opener(0)
ggaren's avatar
gtk:  
ggaren committed
235
    , m_didPerformFirstNavigation(false)
236
    , m_loadingFromCachedPage(false)
237
    , m_suppressOpenerInNewFrame(false)
238
    , m_forcedSandboxFlags(SandboxNone)
darin's avatar
darin committed
239 240 241 242 243
{
}

FrameLoader::~FrameLoader()
{
darin's avatar
darin committed
244 245 246 247 248
    setOpener(0);

    HashSet<Frame*>::iterator end = m_openedFrames.end();
    for (HashSet<Frame*>::iterator it = m_openedFrames.begin(); it != end; ++it)
        (*it)->loader()->m_opener = 0;
249

ggaren's avatar
ggaren committed
250
    m_client->frameLoaderDestroyed();
251 252 253

    if (m_networkingContext)
        m_networkingContext->invalidate();
darin's avatar
darin committed
254 255
}

256
void FrameLoader::init()
mjs's avatar
mjs committed
257
{
258
    // This somewhat odd set of steps gives the frame an initial empty document.
259
    setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(KURL(ParsedURLString, emptyString())), SubstituteData()).get());
mjs's avatar
mjs committed
260
    setProvisionalDocumentLoader(m_policyDocumentLoader.get());
261
    m_provisionalDocumentLoader->startLoadingMainResource();
mjs's avatar
mjs committed
262
    m_frame->document()->cancelParsing();
263
    m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocument);
264 265

    m_networkingContext = m_client->createNetworkingContext();
266
    m_progressTracker = FrameProgressTracker::create(m_frame);
mjs's avatar
mjs committed
267 268
}

darin's avatar
darin committed
269
void FrameLoader::setDefersLoading(bool defers)
mjs's avatar
mjs committed
270
{
darin's avatar
darin committed
271 272 273 274 275 276
    if (m_documentLoader)
        m_documentLoader->setDefersLoading(defers);
    if (m_provisionalDocumentLoader)
        m_provisionalDocumentLoader->setDefersLoading(defers);
    if (m_policyDocumentLoader)
        m_policyDocumentLoader->setDefersLoading(defers);
277
    history()->setDefersLoading(defers);
278 279

    if (!defers) {
280
        m_frame->navigationScheduler()->startTimer();
281 282
        startCheckCompleteTimer();
    }
mjs's avatar
mjs committed
283 284
}

285
void FrameLoader::changeLocation(SecurityOrigin* securityOrigin, const KURL& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool refresh)
mjs's avatar
mjs committed
286
{
287
    urlSelected(FrameLoadRequest(securityOrigin, ResourceRequest(url, referrer, refresh ? ReloadIgnoringCacheData : UseProtocolCachePolicy), "_self"),
288
        0, lockHistory, lockBackForwardList, MaybeSendReferrer, ReplaceDocumentIfJavaScriptURL);
darin's avatar
darin committed
289 290
}

291
void FrameLoader::urlSelected(const KURL& url, const String& passedTarget, PassRefPtr<Event> triggeringEvent, bool lockHistory, bool lockBackForwardList, ShouldSendReferrer shouldSendReferrer)
292
{
293
    urlSelected(FrameLoadRequest(m_frame->document()->securityOrigin(), ResourceRequest(url), passedTarget),
294
        triggeringEvent, lockHistory, lockBackForwardList, shouldSendReferrer, DoNotReplaceDocumentIfJavaScriptURL);
295 296
}

297 298
// The shouldReplaceDocumentIfJavaScriptURL parameter will go away when the FIXME to eliminate the
// corresponding parameter from ScriptController::executeIfJavaScriptURL() is addressed.
299
void FrameLoader::urlSelected(const FrameLoadRequest& passedRequest, PassRefPtr<Event> triggeringEvent, bool lockHistory, bool lockBackForwardList, ShouldSendReferrer shouldSendReferrer, ShouldReplaceDocumentIfJavaScriptURL shouldReplaceDocumentIfJavaScriptURL)
darin's avatar
darin committed
300
{
301 302
    ASSERT(!m_suppressOpenerInNewFrame);

303
    RefPtr<Frame> protect(m_frame);
304
    FrameLoadRequest frameRequest(passedRequest);
weinig@apple.com's avatar
weinig@apple.com committed
305

306 307
    if (m_frame->script()->executeIfJavaScriptURL(frameRequest.resourceRequest().url(), shouldReplaceDocumentIfJavaScriptURL))
        return;
darin's avatar
darin committed
308

309 310
    if (frameRequest.frameName().isEmpty())
        frameRequest.setFrameName(m_frame->document()->baseTarget());
darin's avatar
darin committed
311

312
    if (shouldSendReferrer == NeverSendReferrer)
313
        m_suppressOpenerInNewFrame = true;
314 315
    addHTTPOriginIfNeeded(frameRequest.resourceRequest(), outgoingOrigin());

316
    loadFrameRequest(frameRequest, lockHistory, lockBackForwardList, triggeringEvent, 0, shouldSendReferrer);
317 318

    m_suppressOpenerInNewFrame = false;
darin's avatar
darin committed
319 320
}

321
void FrameLoader::submitForm(PassRefPtr<FormSubmission> submission)
darin's avatar
darin committed
322
{
323 324 325 326 327
    ASSERT(submission->method() == FormSubmission::PostMethod || submission->method() == FormSubmission::GetMethod);

    // FIXME: Find a good spot for these.
    ASSERT(submission->data());
    ASSERT(submission->state());
328
    ASSERT(!submission->state()->sourceDocument()->frame() || submission->state()->sourceDocument()->frame() == m_frame);
beidson's avatar
beidson committed
329
    
adele@apple.com's avatar
adele@apple.com committed
330 331 332
    if (!m_frame->page())
        return;
    
333
    if (submission->action().isEmpty())
darin's avatar
darin committed
334 335
        return;

336 337
    if (isDocumentSandboxed(m_frame, SandboxForms)) {
        // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists.
338
        m_frame->document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Blocked form submission to '" + submission->action().elidedString() + "' because the form's frame is sandboxed and the 'allow-forms' permission is not set.");
339
        return;
340
    }
341

342
    if (protocolIsJavaScript(submission->action())) {
343 344
        if (!m_frame->document()->contentSecurityPolicy()->allowFormAction(KURL(submission->action())))
            return;
darin's avatar
darin committed
345
        m_isExecutingJavaScriptFormAction = true;
346
        m_frame->script()->executeIfJavaScriptURL(submission->action(), DoNotReplaceDocumentIfJavaScriptURL);
darin's avatar
darin committed
347 348 349 350
        m_isExecutingJavaScriptFormAction = false;
        return;
    }

351
    Frame* targetFrame = findFrameForNavigation(submission->target(), submission->state()->sourceDocument());
darin@apple.com's avatar
darin@apple.com committed
352
    if (!targetFrame) {
353
        if (!DOMWindow::allowPopUp(m_frame) && !ScriptController::processingUserGesture())
354 355
            return;

darin@apple.com's avatar
darin@apple.com committed
356
        targetFrame = m_frame;
357 358 359
    } else
        submission->clearTarget();

darin@apple.com's avatar
darin@apple.com committed
360
    if (!targetFrame->page())
darin's avatar
darin committed
361
        return;
darin@apple.com's avatar
darin@apple.com committed
362 363 364 365 366 367 368 369 370 371 372 373 374 375

    // FIXME: We'd like to remove this altogether and fix the multiple form submission issue another way.

    // We do not want to submit more than one form from the same page, nor do we want to submit a single
    // form more than once. This flag prevents these from happening; not sure how other browsers prevent this.
    // The flag is reset in each time we start handle a new mouse or key down event, and
    // also in setView since this part may get reused for a page from the back/forward cache.
    // The form multi-submit logic here is only needed when we are submitting a form that affects this frame.

    // FIXME: Frame targeting is only one of the ways the submission could end up doing something other
    // than replacing this frame's content, so this check is flawed. On the other hand, the check is hardly
    // needed any more now that we reset m_submittedFormURL on each mouse or key down event.

    if (m_frame->tree()->isDescendantOf(targetFrame)) {
376
        if (m_submittedFormURL == submission->requestURL())
darin@apple.com's avatar
darin@apple.com committed
377
            return;
378
        m_submittedFormURL = submission->requestURL();
darin's avatar
darin committed
379 380
    }

381
    submission->data()->generateFiles(m_frame->document());
abarth@webkit.org's avatar
abarth@webkit.org committed
382
    submission->setReferrer(outgoingReferrer());
383
    submission->setOrigin(outgoingOrigin());
darin's avatar
darin committed
384

385
    targetFrame->navigationScheduler()->scheduleFormSubmission(submission);
darin's avatar
darin committed
386 387
}

388
void FrameLoader::stopLoading(UnloadEventPolicy unloadEventPolicy)
darin's avatar
darin committed
389
{
390 391
    if (m_frame->document() && m_frame->document()->parser())
        m_frame->document()->parser()->stopParsing();
mjs's avatar
mjs committed
392

393
    if (unloadEventPolicy != UnloadEventPolicyNone) {
darin's avatar
darin committed
394
        if (m_frame->document()) {
ggaren's avatar
ggaren committed
395
            if (m_didCallImplicitClose && !m_wasUnloadEventEmitted) {
ggaren's avatar
ggaren committed
396
                Node* currentFocusedNode = m_frame->document()->focusedNode();
397 398
                if (currentFocusedNode && currentFocusedNode->toInputElement())
                    currentFocusedNode->toInputElement()->endEditing();
399
                if (m_pageDismissalEventBeingDispatched == NoDismissal) {
400 401
                    if (unloadEventPolicy == UnloadEventPolicyUnloadAndPageHide) {
                        m_pageDismissalEventBeingDispatched = PageHideDismissal;
402
                        m_frame->document()->domWindow()->dispatchEvent(PageTransitionEvent::create(eventNames().pagehideEvent, m_frame->document()->inPageCache()), m_frame->document());
403
                    }
404
                    if (!m_frame->document()->inPageCache()) {
405
                        RefPtr<Event> unloadEvent(Event::create(eventNames().unloadEvent, false, false));
406 407 408
                        // The DocumentLoader (and thus its DocumentLoadTiming) might get destroyed
                        // while dispatching the event, so protect it to prevent writing the end
                        // time into freed memory.
409
                        RefPtr<DocumentLoader> documentLoader = m_provisionalDocumentLoader;
410
                        m_pageDismissalEventBeingDispatched = UnloadDismissal;
411
                        if (documentLoader && !documentLoader->timing()->unloadEventStart() && !documentLoader->timing()->unloadEventEnd()) {
412
                            DocumentLoadTiming* timing = documentLoader->timing();
413 414
                            ASSERT(timing->navigationStart());
                            timing->markUnloadEventStart();
415
                            m_frame->document()->domWindow()->dispatchEvent(unloadEvent, m_frame->document());
416
                            timing->markUnloadEventEnd();
417
                        } else
418
                            m_frame->document()->domWindow()->dispatchEvent(unloadEvent, m_frame->document());
419
                    }
ap@apple.com's avatar
ap@apple.com committed
420
                }
421
                m_pageDismissalEventBeingDispatched = NoDismissal;
darin's avatar
darin committed
422
                if (m_frame->document())
423
                    m_frame->document()->updateStyleIfNeeded();
darin's avatar
darin committed
424 425 426
                m_wasUnloadEventEmitted = true;
            }
        }
427 428

        // Dispatching the unload event could have made m_frame->document() null.
429 430
        if (m_frame->document() && !m_frame->document()->inPageCache()) {
            // Don't remove event listeners from a transitional empty document (see bug 28716 for more information).
431
            bool keepEventListeners = m_stateMachine.isDisplayingInitialEmptyDocument() && m_provisionalDocumentLoader
432
                && m_frame->document()->isSecureTransitionTo(m_provisionalDocumentLoader->url());
433 434 435 436

            if (!keepEventListeners)
                m_frame->document()->removeAllEventListeners();
        }
darin's avatar
darin committed
437 438
    }

439
    m_isComplete = true; // to avoid calling completed() in finishedParsing()
ggaren's avatar
ggaren committed
440
    m_didCallImplicitClose = true; // don't want that one either
darin's avatar
darin committed
441 442 443 444 445

    if (m_frame->document() && m_frame->document()->parsing()) {
        finishedParsing();
        m_frame->document()->setParsing(false);
    }
446

darin's avatar
darin committed
447
    if (Document* doc = m_frame->document()) {
448 449 450 451
        // FIXME: HTML5 doesn't tell us to set the state to complete when aborting, but we do anyway to match legacy behavior.
        // http://www.w3.org/Bugs/Public/show_bug.cgi?id=10537
        doc->setReadyState(Document::Complete);

452
#if ENABLE(SQL_DATABASE)
453 454
        // FIXME: Should the DatabaseManager watch for something like ActiveDOMObject::stop() rather than being special-cased here?
        DatabaseManager::manager().stopDatabases(doc, 0);
455
#endif
darin's avatar
darin committed
456 457
    }

ap@apple.com's avatar
ap@apple.com committed
458
    // FIXME: This will cancel redirection timer, which really needs to be restarted when restoring the frame from b/f cache.
459
    m_frame->navigationScheduler()->cancel();
darin's avatar
darin committed
460 461 462 463 464 465 466
}

void FrameLoader::stop()
{
    // http://bugs.webkit.org/show_bug.cgi?id=10854
    // The frame's last ref may be removed and it will be deleted by checkCompleted().
    RefPtr<Frame> protector(m_frame);
467 468 469 470 471

    if (DocumentParser* parser = m_frame->document()->parser()) {
        parser->stopParsing();
        parser->finish();
    }
472 473
    
    icon()->stopLoader();
darin's avatar
darin committed
474 475 476 477
}

bool FrameLoader::closeURL()
{
478
    history()->saveDocumentState();
479 480 481 482 483
    
    // Should only send the pagehide event here if the current document exists and has not been placed in the page cache.    
    Document* currentDocument = m_frame->document();
    stopLoading(currentDocument && !currentDocument->inPageCache() ? UnloadEventPolicyUnloadAndPageHide : UnloadEventPolicyUnloadOnly);
    
ggaren's avatar
ggaren committed
484
    m_frame->editor()->clearUndoRedoOperations();
darin's avatar
darin committed
485 486 487
    return true;
}

488
bool FrameLoader::didOpenURL()
darin's avatar
darin committed
489
{
490
    if (m_frame->navigationScheduler()->redirectScheduledDuringLoad()) {
darin's avatar
darin committed
491 492 493
        // A redirect was scheduled before the document was created.
        // This can happen when one frame changes another frame's location.
        return false;
darin@apple.com's avatar
darin@apple.com committed
494
    }
darin's avatar
darin committed
495

496
    m_frame->navigationScheduler()->cancel();
darin@apple.com's avatar
darin@apple.com committed
497
    m_frame->editor()->clearLastEditCommand();
darin's avatar
darin committed
498 499

    m_isComplete = false;
ggaren's avatar
ggaren committed
500
    m_didCallImplicitClose = false;
darin's avatar
darin committed
501

502 503 504
    // If we are still in the process of initializing an empty document then
    // its frame is not in a consistent state for rendering, so avoid setJSStatusBarText
    // since it may cause clients to attempt to render the frame.
505
    if (!m_stateMachine.creatingInitialEmptyDocument()) {
506 507 508
        DOMWindow* window = m_frame->document()->domWindow();
        window->setStatus(String());
        window->setDefaultStatus(String());
509
    }
darin's avatar
darin committed
510 511 512 513 514 515

    started();

    return true;
}

516
void FrameLoader::didExplicitOpen()
darin's avatar
darin committed
517 518
{
    m_isComplete = false;
ggaren's avatar
ggaren committed
519
    m_didCallImplicitClose = false;
darin's avatar
darin committed
520

andersca@apple.com's avatar
andersca@apple.com committed
521
    // Calling document.open counts as committing the first real document load.
522 523
    if (!m_stateMachine.committedFirstRealDocumentLoad())
        m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit);
andersca@apple.com's avatar
andersca@apple.com committed
524
    
darin's avatar
darin committed
525 526
    // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
    // from a subsequent window.document.open / window.document.write call. 
527
    // Canceling redirection here works for all cases because document.open 
darin's avatar
darin committed
528
    // implicitly precedes document.write.
529
    m_frame->navigationScheduler()->cancel();
darin's avatar
darin committed
530 531 532 533 534
}


void FrameLoader::cancelAndClear()
{
535
    m_frame->navigationScheduler()->cancel();
darin's avatar
darin committed
536 537 538 539

    if (!m_isComplete)
        closeURL();

540
    clear(m_frame->document(), false);
541
    m_frame->script()->updatePlatformScriptObjects();
darin's avatar
darin committed
542 543
}

544
void FrameLoader::clear(Document* newDocument, bool clearWindowProperties, bool clearScriptObjects, bool clearFrameView)
darin's avatar
darin committed
545
{
darin's avatar
darin committed
546
    m_frame->editor()->clear();
darin's avatar
darin committed
547 548 549 550

    if (!m_needsClear)
        return;
    m_needsClear = false;
lars's avatar
lars committed
551
    
ap@webkit.org's avatar
ap@webkit.org committed
552
    if (!m_frame->document()->inPageCache()) {
darin's avatar
darin committed
553
        m_frame->document()->cancelParsing();
ap@webkit.org's avatar
ap@webkit.org committed
554
        m_frame->document()->stopActiveDOMObjects();
darin's avatar
darin committed
555
        if (m_frame->document()->attached()) {
556
            m_frame->document()->prepareForDestruction();
alice.liu@apple.com's avatar
alice.liu@apple.com committed
557
            m_frame->document()->removeFocusedNodeOfSubtree(m_frame->document());
darin's avatar
darin committed
558
        }
darin's avatar
darin committed
559 560 561
    }

    // Do this after detaching the document so that the unload event works.
thatcher's avatar
thatcher committed
562
    if (clearWindowProperties) {
563
        InspectorInstrumentation::frameWindowDiscarded(m_frame, m_frame->document()->domWindow());
564
        m_frame->document()->domWindow()->resetUnlessSuspendedForPageCache();
565
        m_frame->script()->clearWindowShell(newDocument->domWindow(), m_frame->document()->inPageCache());
weinig's avatar
weinig committed
566
    }
darin's avatar
darin committed
567

568
    m_frame->selection()->prepareForDestruction();
darin's avatar
darin committed
569
    m_frame->eventHandler()->clear();
570
    if (clearFrameView && m_frame->view())
darin's avatar
darin committed
571
        m_frame->view()->clear();
572 573 574

    // Do not drop the document before the ScriptController and view are cleared
    // as some destructors might still try to access the document.
darin's avatar
darin committed
575
    m_frame->setDocument(0);
darin's avatar
darin committed
576

577
    m_subframeLoader.clear();
578

antti's avatar
antti committed
579
    if (clearScriptObjects)
580 581
        m_frame->script()->clearScriptObjects();

582 583
    m_frame->script()->enableEval();

584
    m_frame->navigationScheduler()->clear();
darin's avatar
darin committed
585

586 587 588
    m_checkTimer.stop();
    m_shouldCallCheckCompleted = false;
    m_shouldCallCheckLoadComplete = false;
589

590 591
    if (m_stateMachine.isDisplayingInitialEmptyDocument() && m_stateMachine.committedFirstRealDocumentLoad())
        m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
darin's avatar
darin committed
592 593 594 595
}

void FrameLoader::receivedFirstData()
{
596 597
    dispatchDidCommitLoad();
    dispatchDidClearWindowObjectsInAllWorlds();
598
    dispatchGlobalObjectAvailableInAllWorlds();
599

600
    if (m_documentLoader) {
601
        StringWithDirection ptitle = m_documentLoader->title();
602 603 604 605
        // If we have a title let the WebView know about it.
        if (!ptitle.isNull())
            m_client->dispatchDidReceiveTitle(ptitle);
    }
darin's avatar
darin committed
606

darin's avatar
darin committed
607 608
    if (!m_documentLoader)
        return;
609
    if (m_frame->document()->isViewSource())
610
        return;
611 612 613

    double delay;
    String url;
weinig@apple.com's avatar
weinig@apple.com committed
614
    if (!parseHTTPRefresh(m_documentLoader->response().httpHeaderField("Refresh"), false, delay, url))
ap's avatar
ap committed
615
        return;
weinig@apple.com's avatar
weinig@apple.com committed
616
    if (url.isEmpty())
617
        url = m_frame->document()->url().string();
ap's avatar
ap committed
618
    else
darin@apple.com's avatar
darin@apple.com committed
619
        url = m_frame->document()->completeURL(url).string();
darin's avatar
darin committed
620

621
    m_frame->navigationScheduler()->scheduleRedirect(delay, url);
darin's avatar
darin committed
622 623
}

624
void FrameLoader::setOutgoingReferrer(const KURL& url)
darin's avatar
darin committed
625
{
626
    m_outgoingReferrer = url.strippedForUseAsReferrer();
627 628
}

629
void FrameLoader::didBeginDocument(bool dispatch)
630 631 632 633
{
    m_needsClear = true;
    m_isComplete = false;
    m_didCallImplicitClose = false;
634
    m_frame->document()->setReadyState(Document::Loading);
635

636
    if (m_pendingStateObject) {
637
        m_frame->document()->statePopped(m_pendingStateObject.get());
638 639
        m_pendingStateObject.clear();
    }
weinig@apple.com's avatar
weinig@apple.com committed
640

andersca@apple.com's avatar
andersca@apple.com committed
641
    if (dispatch)
642
        dispatchDidClearWindowObjectsInAllWorlds();
643

644
    updateFirstPartyForCookies();
645
    m_frame->document()->initContentSecurityPolicy();
darin's avatar
darin committed
646

647
    Settings* settings = m_frame->document()->settings();
648 649 650 651
    if (settings) {
        m_frame->document()->cachedResourceLoader()->setImagesEnabled(settings->areImagesEnabled());
        m_frame->document()->cachedResourceLoader()->setAutoLoadImages(settings->loadsImagesAutomatically());
    }
652

collinj@webkit.org's avatar
 
collinj@webkit.org committed
653 654 655
    if (m_documentLoader) {
        String dnsPrefetchControl = m_documentLoader->response().httpHeaderField("X-DNS-Prefetch-Control");
        if (!dnsPrefetchControl.isEmpty())
656
            m_frame->document()->parseDNSPrefetchControlHeader(dnsPrefetchControl);
657

658 659
        String policyValue = m_documentLoader->response().httpHeaderField("Content-Security-Policy");
        if (!policyValue.isEmpty())
660
            m_frame->document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::Enforce);
661

662 663
        policyValue = m_documentLoader->response().httpHeaderField("Content-Security-Policy-Report-Only");
        if (!policyValue.isEmpty())
664
            m_frame->document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::Report);
665 666 667

        policyValue = m_documentLoader->response().httpHeaderField("X-WebKit-CSP");
        if (!policyValue.isEmpty())
668
            m_frame->document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::PrefixedEnforce);
669 670 671

        policyValue = m_documentLoader->response().httpHeaderField("X-WebKit-CSP-Report-Only");
        if (!policyValue.isEmpty())
672
            m_frame->document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::PrefixedReport);
673 674 675 676 677 678 679 680 681

        String headerContentLanguage = m_documentLoader->response().httpHeaderField("Content-Language");
        if (!headerContentLanguage.isEmpty()) {
            size_t commaIndex = headerContentLanguage.find(',');
            headerContentLanguage.truncate(commaIndex); // notFound == -1 == don't truncate
            headerContentLanguage = headerContentLanguage.stripWhiteSpace(isHTMLSpace);
            if (!headerContentLanguage.isEmpty())
                m_frame->document()->setContentLanguage(headerContentLanguage);
        }
collinj@webkit.org's avatar
 
collinj@webkit.org committed
682 683
    }

684
    history()->restoreDocumentState();
685 686
}

darin's avatar
darin committed
687 688
void FrameLoader::finishedParsing()
{
689 690
    m_frame->injectUserScripts(InjectAtDocumentEnd);

691
    if (m_stateMachine.creatingInitialEmptyDocument())
mjs's avatar
mjs committed
692 693
        return;

darin's avatar
darin committed
694 695
    // This can be called from the Frame's destructor, in which case we shouldn't protect ourselves
    // because doing so will cause us to re-enter the destructor when protector goes out of scope.
beidson@apple.com's avatar
beidson@apple.com committed
696 697
    // Null-checking the FrameView indicates whether or not we're in the destructor.
    RefPtr<Frame> protector = m_frame->view() ? m_frame : 0;
darin's avatar
darin committed
698

699 700
    m_client->dispatchDidFinishDocumentLoad();

darin's avatar
darin committed
701 702 703 704 705 706 707 708
    checkCompleted();

    if (!m_frame->view())
        return; // We are being destroyed by something checkCompleted called.

    // Check if the scrollbars are really needed for the content.
    // If not, remove them, relayout, and repaint.
    m_frame->view()->restoreScrollbar();
709
    scrollToFragmentWithParentBoundary(m_frame->document()->url());
darin's avatar
darin committed
710 711 712 713
}

void FrameLoader::loadDone()
{
ap@webkit.org's avatar
ap@webkit.org committed
714
    checkCompleted();
darin's avatar
darin committed
715 716
}

717 718 719 720 721 722 723 724 725
bool FrameLoader::allChildrenAreComplete() const
{
    for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) {
        if (!child->loader()->m_isComplete)
            return false;
    }
    return true;
}

726 727 728 729 730 731 732 733 734
bool FrameLoader::allAncestorsAreComplete() const
{
    for (Frame* ancestor = m_frame; ancestor; ancestor = ancestor->tree()->parent()) {
        if (!ancestor->loader()->m_isComplete)
            return false;
    }
    return true;
}

darin's avatar
darin committed
735 736
void FrameLoader::checkCompleted()
{
737
    RefPtr<Frame> protect(m_frame);
738 739
    m_shouldCallCheckCompleted = false;

antti@apple.com's avatar
antti@apple.com committed
740
    if (m_frame->view())
741
        m_frame->view()->handleLoadCompleted();
antti@apple.com's avatar
antti@apple.com committed
742

darin's avatar
darin committed
743 744 745 746 747
    // Have we completed before?
    if (m_isComplete)
        return;

    // Are we still parsing?
ap@webkit.org's avatar
ap@webkit.org committed
748
    if (m_frame->document()->parsing())
darin's avatar
darin committed
749 750 751
        return;

    // Still waiting for images/scripts?
752
    if (m_frame->document()->cachedResourceLoader()->requestCount())
ap@webkit.org's avatar
ap@webkit.org committed
753
        return;
darin's avatar
darin committed
754

755 756 757 758
    // Still waiting for elements that don't go through a FrameLoader?
    if (m_frame->document()->isDelayingLoadEvent())
        return;

759 760 761 762
    // Any frame that hasn't completed yet?
    if (!allChildrenAreComplete())
        return;

darin's avatar
darin committed
763 764
    // OK, completed.
    m_isComplete = true;
765
    m_requestedHistoryItem = 0;
766
    m_frame->document()->setReadyState(Document::Complete);
darin's avatar
darin committed
767

ggaren's avatar
ggaren committed
768
    checkCallImplicitClose(); // if we didn't do it before
darin's avatar
darin committed
769

770
    m_frame->navigationScheduler()->startTimer();
darin's avatar
darin committed
771 772