FrameLoader.cpp 181 KB
Newer Older
mjs's avatar
mjs committed
1
/*
darin@apple.com's avatar
darin@apple.com committed
2
 * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3
 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
4
 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
mjs's avatar
mjs committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
 *
 * 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
31 32
#include "config.h"
#include "FrameLoader.h"
mjs's avatar
mjs committed
33

34
#include "ApplicationCacheHost.h"
beidson@apple.com's avatar
beidson@apple.com committed
35 36
#include "Archive.h"
#include "ArchiveFactory.h"
weinig's avatar
weinig committed
37
#include "CString.h"
darin's avatar
darin committed
38
#include "Cache.h"
beidson's avatar
beidson committed
39
#include "CachedPage.h"
ggaren's avatar
ggaren committed
40
#include "Chrome.h"
darin's avatar
darin committed
41
#include "DOMImplementation.h"
42
#include "DOMWindow.h"
darin's avatar
darin committed
43 44
#include "DocLoader.h"
#include "Document.h"
ggaren's avatar
ggaren committed
45
#include "DocumentLoader.h"
darin's avatar
darin committed
46
#include "Editor.h"
andersca's avatar
andersca committed
47
#include "EditorClient.h"
darin's avatar
darin committed
48
#include "Element.h"
darin's avatar
darin committed
49
#include "Event.h"
darin's avatar
darin committed
50
#include "EventNames.h"
ggaren's avatar
ggaren committed
51 52
#include "FloatRect.h"
#include "FormState.h"
darin's avatar
darin committed
53
#include "Frame.h"
ggaren's avatar
ggaren committed
54
#include "FrameLoadRequest.h"
darin's avatar
darin committed
55
#include "FrameLoaderClient.h"
ggaren's avatar
ggaren committed
56
#include "FrameTree.h"
darin's avatar
darin committed
57
#include "FrameView.h"
58
#include "HTMLAppletElement.h"
darin's avatar
darin committed
59
#include "HTMLFormElement.h"
lars's avatar
lars committed
60
#include "HTMLFrameElement.h"
darin's avatar
darin committed
61 62
#include "HTMLNames.h"
#include "HTMLObjectElement.h"
ap's avatar
ap committed
63
#include "HTTPParsers.h"
weinig's avatar
weinig committed
64
#include "HistoryItem.h"
darin's avatar
darin committed
65 66
#include "IconDatabase.h"
#include "IconLoader.h"
aroben's avatar
aroben committed
67
#include "InspectorController.h"
beidson's avatar
beidson committed
68
#include "Logging.h"
weinig's avatar
weinig committed
69
#include "MIMETypeRegistry.h"
weinig's avatar
weinig committed
70
#include "MainResourceLoader.h"
ggaren's avatar
ggaren committed
71
#include "Page.h"
ggaren's avatar
ggaren committed
72
#include "PageCache.h"
darin@apple.com's avatar
darin@apple.com committed
73
#include "PageGroup.h"
74
#include "PageTransitionEvent.h"
mitz@apple.com's avatar
mitz@apple.com committed
75
#include "PlaceholderDocument.h"
76
#include "PluginData.h"
77
#include "PluginDocument.h"
andersca's avatar
andersca committed
78
#include "ProgressTracker.h"
darin's avatar
darin committed
79
#include "RenderPart.h"
eric@webkit.org's avatar
eric@webkit.org committed
80
#include "RenderView.h"
81
#include "RenderWidget.h"
beidson's avatar
beidson committed
82
#include "ResourceHandle.h"
darin's avatar
darin committed
83
#include "ResourceRequest.h"
84
#include "ScriptController.h"
85
#include "ScriptSourceCode.h"
dglazkov@chromium.org's avatar
dglazkov@chromium.org committed
86
#include "ScriptString.h"
87
#include "ScriptValue.h"
weinig's avatar
weinig committed
88
#include "SecurityOrigin.h"
darin's avatar
darin committed
89 90
#include "SegmentedString.h"
#include "Settings.h"
kov@webkit.org's avatar
kov@webkit.org committed
91 92

#if ENABLE(SHARED_WORKERS)
93
#include "SharedWorkerRepository.h"
kov@webkit.org's avatar
kov@webkit.org committed
94 95
#endif

darin's avatar
darin committed
96
#include "TextResourceDecoder.h"
ggaren's avatar
ggaren committed
97
#include "WindowFeatures.h"
weinig's avatar
weinig committed
98
#include "XMLHttpRequest.h"
darin's avatar
darin committed
99
#include "XMLTokenizer.h"
abarth@webkit.org's avatar
abarth@webkit.org committed
100
#include "XSSAuditor.h"
ap@webkit.org's avatar
ap@webkit.org committed
101
#include <wtf/CurrentTime.h>
102
#include <wtf/StdLibExtras.h>
darin's avatar
darin committed
103

darin@apple.com's avatar
darin@apple.com committed
104

oliver's avatar
oliver committed
105 106 107 108 109 110 111 112 113 114
#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

115 116 117 118
#if PLATFORM(MAC) || PLATFORM(WIN)
#define PAGE_CACHE_ACCEPTS_UNLOAD_HANDLERS
#endif

darin's avatar
darin committed
119 120
namespace WebCore {

121
#if ENABLE(SVG)
oliver's avatar
oliver committed
122
using namespace SVGNames;
123
#endif
darin's avatar
darin committed
124 125
using namespace HTMLNames;

126 127 128 129 130
#if ENABLE(XHTMLMP)
static const char defaultAcceptHeader[] = "application/xml,application/vnd.wap.xhtml+xml,application/xhtml+xml;profile='http://www.wapforum.org/xhtml',text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5";
#else
static const char defaultAcceptHeader[] = "application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5";
#endif
darin's avatar
darin committed
131
static double storedTimeOfLastCompletedLoad;
abarth@webkit.org's avatar
abarth@webkit.org committed
132
static FrameLoader::LocalLoadPolicy localLoadPolicy = FrameLoader::AllowLocalLoadsForLocalOnly;
darin's avatar
darin committed
133 134 135 136 137 138

bool isBackForwardLoadType(FrameLoadType type)
{
    switch (type) {
        case FrameLoadTypeStandard:
        case FrameLoadTypeReload:
139
        case FrameLoadTypeReloadFromOrigin:
darin's avatar
darin committed
140
        case FrameLoadTypeSame:
ggaren@apple.com's avatar
ggaren@apple.com committed
141
        case FrameLoadTypeRedirectWithLockedBackForwardList:
darin's avatar
darin committed
142 143 144
        case FrameLoadTypeReplace:
            return false;
        case FrameLoadTypeBack:
145
        case FrameLoadTypeBackWMLDeckNotAccessible:
darin's avatar
darin committed
146 147 148 149 150 151 152 153 154 155
        case FrameLoadTypeForward:
        case FrameLoadTypeIndexedBackForward:
            return true;
    }
    ASSERT_NOT_REACHED();
    return false;
}

static int numRequests(Document* document)
{
beidson's avatar
beidson committed
156 157 158 159
    if (!document)
        return 0;
    
    return document->docLoader()->requestCount();
darin's avatar
darin committed
160 161
}

162 163 164 165 166
static inline bool canReferToParentFrameEncoding(const Frame* frame, const Frame* parentFrame) 
{
    return parentFrame && parentFrame->document()->securityOrigin()->canAccess(frame->document()->securityOrigin());
}

ggaren's avatar
ggaren committed
167
FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client)
darin's avatar
darin committed
168
    : m_frame(frame)
ggaren's avatar
ggaren committed
169
    , m_client(client)
darin's avatar
darin committed
170 171
    , m_state(FrameStateCommittedPage)
    , m_loadType(FrameLoadTypeStandard)
darin's avatar
darin committed
172
    , m_policyLoadType(FrameLoadTypeStandard)
darin's avatar
darin committed
173 174 175 176 177 178
    , m_delegateIsHandlingProvisionalLoadError(false)
    , m_delegateIsDecidingNavigationPolicy(false)
    , m_delegateIsHandlingUnimplementablePolicy(false)
    , m_firstLayoutDone(false)
    , m_quickRedirectComing(false)
    , m_sentRedirectNotification(false)
darin's avatar
darin committed
179 180 181
    , m_inStopAllLoaders(false)
    , m_isExecutingJavaScriptFormAction(false)
    , m_isRunningScript(false)
ggaren's avatar
ggaren committed
182
    , m_didCallImplicitClose(false)
darin's avatar
darin committed
183
    , m_wasUnloadEventEmitted(false)
weinig@apple.com's avatar
weinig@apple.com committed
184
    , m_unloadEventBeingDispatched(false)
darin's avatar
darin committed
185 186 187 188 189 190
    , m_isComplete(false)
    , m_isLoadingMainResource(false)
    , m_needsClear(false)
    , m_receivedData(false)
    , m_encodingWasChosenByUser(false)
    , m_containsPlugIns(false)
191 192 193
    , m_checkTimer(this, &FrameLoader::checkTimerFired)
    , m_shouldCallCheckCompleted(false)
    , m_shouldCallCheckLoadComplete(false)
darin's avatar
darin committed
194
    , m_opener(0)
kmccullo's avatar
kmccullo committed
195
    , m_openedByDOM(false)
mjs's avatar
mjs committed
196
    , m_creatingInitialEmptyDocument(false)
antti's avatar
antti committed
197
    , m_isDisplayingInitialEmptyDocument(false)
mjs's avatar
mjs committed
198
    , m_committedFirstRealDocumentLoad(false)
ggaren's avatar
gtk:  
ggaren committed
199
    , m_didPerformFirstNavigation(false)
200
    , m_loadingFromCachedPage(false)
darin@apple.com's avatar
darin@apple.com committed
201 202 203
#ifndef NDEBUG
    , m_didDispatchDidCommitLoad(false)
#endif
darin's avatar
darin committed
204 205 206 207 208
{
}

FrameLoader::~FrameLoader()
{
darin's avatar
darin committed
209 210 211 212 213
    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;
ggaren's avatar
ggaren committed
214 215
        
    m_client->frameLoaderDestroyed();
darin's avatar
darin committed
216 217
}

218
void FrameLoader::init()
mjs's avatar
mjs committed
219 220
{
    // this somewhat odd set of steps is needed to give the frame an initial empty document
antti's avatar
antti committed
221
    m_isDisplayingInitialEmptyDocument = false;
mjs's avatar
mjs committed
222
    m_creatingInitialEmptyDocument = true;
ap@apple.com's avatar
ap@apple.com committed
223
    setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(KURL(ParsedURLString, "")), SubstituteData()).get());
mjs's avatar
mjs committed
224 225
    setProvisionalDocumentLoader(m_policyDocumentLoader.get());
    setState(FrameStateProvisional);
andersca's avatar
andersca committed
226
    m_provisionalDocumentLoader->setResponse(ResourceResponse(KURL(), "text/html", 0, String(), String()));
mjs's avatar
mjs committed
227
    m_provisionalDocumentLoader->finishedLoading();
228 229
    begin(KURL(), false);
    end();
mjs's avatar
mjs committed
230 231
    m_frame->document()->cancelParsing();
    m_creatingInitialEmptyDocument = false;
ggaren's avatar
ggaren committed
232
    m_didCallImplicitClose = true;
mjs's avatar
mjs committed
233 234
}

darin's avatar
darin committed
235
void FrameLoader::setDefersLoading(bool defers)
mjs's avatar
mjs committed
236
{
darin's avatar
darin committed
237 238 239 240 241 242
    if (m_documentLoader)
        m_documentLoader->setDefersLoading(defers);
    if (m_provisionalDocumentLoader)
        m_provisionalDocumentLoader->setDefersLoading(defers);
    if (m_policyDocumentLoader)
        m_policyDocumentLoader->setDefersLoading(defers);
243 244

    if (!defers) {
245
        m_frame->redirectScheduler()->startTimer();
246 247
        startCheckCompleteTimer();
    }
mjs's avatar
mjs committed
248 249
}

andersca@apple.com's avatar
andersca@apple.com committed
250
Frame* FrameLoader::createWindow(FrameLoader* frameLoaderForFrameLookup, const FrameLoadRequest& request, const WindowFeatures& features, bool& created)
ggaren's avatar
ggaren committed
251 252 253
{ 
    ASSERT(!features.dialog || request.frameName().isEmpty());

andersca@apple.com's avatar
andersca@apple.com committed
254 255 256
    if (!request.frameName().isEmpty() && request.frameName() != "_blank") {
        Frame* frame = frameLoaderForFrameLookup->frame()->tree()->find(request.frameName());
        if (frame && shouldAllowNavigation(frame)) {
darin's avatar
darin committed
257
            if (!request.resourceRequest().url().isEmpty())
darin@apple.com's avatar
darin@apple.com committed
258
                frame->loader()->loadFrameRequest(request, false, false, 0, 0);
darin's avatar
darin committed
259 260
            if (Page* page = frame->page())
                page->chrome()->focus();
mjs's avatar
mjs committed
261
            created = false;
ggaren's avatar
ggaren committed
262 263
            return frame;
        }
andersca@apple.com's avatar
andersca@apple.com committed
264 265
    }
    
ggaren's avatar
ggaren committed
266 267
    // FIXME: Setting the referrer should be the caller's responsibility.
    FrameLoadRequest requestWithReferrer = request;
darin's avatar
darin committed
268
    requestWithReferrer.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
abarth@webkit.org's avatar
abarth@webkit.org committed
269
    addHTTPOriginIfNeeded(requestWithReferrer.resourceRequest(), outgoingOrigin());
beidson@apple.com's avatar
beidson@apple.com committed
270 271 272 273 274 275

    Page* oldPage = m_frame->page();
    if (!oldPage)
        return 0;
        
    Page* page = oldPage->chrome()->createWindow(m_frame, requestWithReferrer, features);
ggaren's avatar
ggaren committed
276 277 278 279
    if (!page)
        return 0;

    Frame* frame = page->mainFrame();
mjs's avatar
mjs committed
280 281
    if (request.frameName() != "_blank")
        frame->tree()->setName(request.frameName());
ggaren's avatar
ggaren committed
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306

    page->chrome()->setToolbarsVisible(features.toolBarVisible || features.locationBarVisible);
    page->chrome()->setStatusbarVisible(features.statusBarVisible);
    page->chrome()->setScrollbarsVisible(features.scrollbarsVisible);
    page->chrome()->setMenubarVisible(features.menuBarVisible);
    page->chrome()->setResizable(features.resizable);

    // 'x' and 'y' specify the location of the window, while 'width' and 'height' 
    // specify the size of the page. We can only resize the window, so 
    // adjust for the difference between the window size and the page size.

    FloatRect windowRect = page->chrome()->windowRect();
    FloatSize pageSize = page->chrome()->pageRect().size();
    if (features.xSet)
        windowRect.setX(features.x);
    if (features.ySet)
        windowRect.setY(features.y);
    if (features.widthSet)
        windowRect.setWidth(features.width + (windowRect.width() - pageSize.width()));
    if (features.heightSet)
        windowRect.setHeight(features.height + (windowRect.height() - pageSize.height()));
    page->chrome()->setWindowRect(windowRect);

    page->chrome()->show();

mjs's avatar
mjs committed
307
    created = true;
ggaren's avatar
ggaren committed
308 309
    return frame;
}
darin's avatar
darin committed
310

bdakin's avatar
bdakin committed
311 312 313 314 315
bool FrameLoader::canHandleRequest(const ResourceRequest& request)
{
    return m_client->canHandleRequest(request);
}

ggaren@apple.com's avatar
ggaren@apple.com committed
316
void FrameLoader::changeLocation(const KURL& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool userGesture, bool refresh)
mjs's avatar
mjs committed
317
{
318 319
    RefPtr<Frame> protect(m_frame);

320
    ResourceRequest request(url, referrer, refresh ? ReloadIgnoringCacheData : UseProtocolCachePolicy);
darin's avatar
darin committed
321
    
322 323 324
    if (executeIfJavaScriptURL(request.url(), userGesture))
        return;

ggaren@apple.com's avatar
ggaren@apple.com committed
325
    urlSelected(request, "_self", 0, lockHistory, lockBackForwardList, userGesture);
darin's avatar
darin committed
326 327
}

328
void FrameLoader::urlSelected(const ResourceRequest& request, const String& passedTarget, PassRefPtr<Event> triggeringEvent, bool lockHistory, bool lockBackForwardList, bool userGesture)
darin's avatar
darin committed
329
{
330
    if (executeIfJavaScriptURL(request.url(), userGesture, false))
weinig@apple.com's avatar
weinig@apple.com committed
331 332
        return;

333
    String target = passedTarget;
ap@webkit.org's avatar
ap@webkit.org committed
334
    if (target.isEmpty())
darin's avatar
darin committed
335 336 337 338
        target = m_frame->document()->baseTarget();

    FrameLoadRequest frameRequest(request, target);

339 340 341 342
    if (frameRequest.resourceRequest().httpReferrer().isEmpty())
        frameRequest.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
    addHTTPOriginIfNeeded(frameRequest.resourceRequest(), outgoingOrigin());

darin@apple.com's avatar
darin@apple.com committed
343
    loadFrameRequest(frameRequest, lockHistory, lockBackForwardList, triggeringEvent, 0);
darin's avatar
darin committed
344 345
}

darin's avatar
darin committed
346
bool FrameLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String& urlString, const AtomicString& frameName)
darin's avatar
darin committed
347 348 349 350
{
    // Support for <frame src="javascript:string">
    KURL scriptURL;
    KURL url;
beidson@apple.com's avatar
beidson@apple.com committed
351
    if (protocolIsJavaScript(urlString)) {
ap@webkit.org's avatar
ap@webkit.org committed
352
        scriptURL = completeURL(urlString); // completeURL() encodes the URL.
darin@apple.com's avatar
darin@apple.com committed
353
        url = blankURL();
darin's avatar
darin committed
354 355 356
    } else
        url = completeURL(urlString);

ggaren's avatar
ggaren committed
357
    Frame* frame = ownerElement->contentFrame();
andersca's avatar
andersca committed
358
    if (frame)
359
        frame->redirectScheduler()->scheduleLocationChange(url.string(), m_outgoingReferrer, true, true, isProcessingUserGesture());
andersca's avatar
andersca committed
360
    else
darin's avatar
darin committed
361 362 363 364 365 366
        frame = loadSubframe(ownerElement, url, frameName, m_outgoingReferrer);
    
    if (!frame)
        return false;

    if (!scriptURL.isEmpty())
weinig@apple.com's avatar
weinig@apple.com committed
367
        frame->loader()->executeIfJavaScriptURL(scriptURL);
darin's avatar
darin committed
368 369 370 371

    return true;
}

darin's avatar
darin committed
372
Frame* FrameLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const String& name, const String& referrer)
darin's avatar
darin committed
373
{
lars's avatar
lars committed
374 375 376 377 378 379 380 381 382 383
    bool allowsScrolling = true;
    int marginWidth = -1;
    int marginHeight = -1;
    if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag)) {
        HTMLFrameElementBase* o = static_cast<HTMLFrameElementBase*>(ownerElement);
        allowsScrolling = o->scrollingMode() != ScrollbarAlwaysOff;
        marginWidth = o->getMarginWidth();
        marginHeight = o->getMarginHeight();
    }

kmccullo's avatar
kmccullo committed
384
    if (!canLoad(url, referrer)) {
385
        FrameLoader::reportLocalLoadFailed(m_frame, url.string());
lars's avatar
lars committed
386
        return 0;
kmccullo's avatar
kmccullo committed
387
    }
lars's avatar
lars committed
388

kmccullo's avatar
kmccullo committed
389
    bool hideReferrer = shouldHideReferrer(url, referrer);
darin@apple.com's avatar
darin@apple.com committed
390
    RefPtr<Frame> frame = m_client->createFrame(url, name, ownerElement, hideReferrer ? String() : referrer, allowsScrolling, marginWidth, marginHeight);
lars's avatar
lars committed
391

darin's avatar
darin committed
392
    if (!frame)  {
ggaren's avatar
ggaren committed
393
        checkCallImplicitClose();
darin's avatar
darin committed
394 395 396 397
        return 0;
    }
    
    frame->loader()->m_isComplete = false;
398 399 400 401
   
    RenderObject* renderer = ownerElement->renderer();
    FrameView* view = frame->view();
    if (renderer && renderer->isWidget() && view)
402
        toRenderWidget(renderer)->setWidget(view);
darin's avatar
darin committed
403
    
ggaren's avatar
ggaren committed
404
    checkCallImplicitClose();
darin's avatar
darin committed
405 406 407 408 409 410 411
    
    // In these cases, the synchronous load would have finished
    // before we could connect the signals, so make sure to send the 
    // completed() signal for the child by hand
    // FIXME: In this case the Frame will have finished loading before 
    // it's being added to the child list. It would be a good idea to
    // create the child first, then invoke the loader separately.
darin@apple.com's avatar
darin@apple.com committed
412
    if (url.isEmpty() || url == blankURL()) {
darin's avatar
darin committed
413 414 415 416
        frame->loader()->completed();
        frame->loader()->checkCompleted();
    }

aliceli1's avatar
gtk:  
aliceli1 committed
417
    return frame.get();
darin's avatar
darin committed
418 419
}

beidson's avatar
beidson committed
420
void FrameLoader::submitForm(const char* action, const String& url, PassRefPtr<FormData> formData,
darin@apple.com's avatar
darin@apple.com committed
421
    const String& target, const String& contentType, const String& boundary,
422
    bool lockHistory, PassRefPtr<Event> event, PassRefPtr<FormState> formState)
darin's avatar
darin committed
423
{
darin@apple.com's avatar
darin@apple.com committed
424 425
    ASSERT(action);
    ASSERT(strcmp(action, "GET") == 0 || strcmp(action, "POST") == 0);
darin@apple.com's avatar
darin@apple.com committed
426
    ASSERT(formData);
darin@apple.com's avatar
darin@apple.com committed
427 428
    ASSERT(formState);
    ASSERT(formState->sourceFrame() == m_frame);
beidson's avatar
beidson committed
429
    
adele@apple.com's avatar
adele@apple.com committed
430 431 432
    if (!m_frame->page())
        return;
    
433
    KURL u = completeURL(url.isNull() ? "" : url);
darin's avatar
darin committed
434
    if (u.isEmpty())
darin's avatar
darin committed
435 436
        return;

beidson@apple.com's avatar
beidson@apple.com committed
437
    if (protocolIsJavaScript(u)) {
darin's avatar
darin committed
438
        m_isExecutingJavaScriptFormAction = true;
439
        executeIfJavaScriptURL(u, false, false);
darin's avatar
darin committed
440 441 442 443
        m_isExecutingJavaScriptFormAction = false;
        return;
    }

darin@apple.com's avatar
darin@apple.com committed
444 445 446 447 448 449 450 451 452
    FrameLoadRequest frameRequest;

    String targetOrBaseTarget = target.isEmpty() ? m_frame->document()->baseTarget() : target;
    Frame* targetFrame = findFrameForNavigation(targetOrBaseTarget);
    if (!targetFrame) {
        targetFrame = m_frame;
        frameRequest.setFrameName(targetOrBaseTarget);
    }
    if (!targetFrame->page())
darin's avatar
darin committed
453
        return;
darin@apple.com's avatar
darin@apple.com committed
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470

    // 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)) {
        if (m_submittedFormURL == u)
            return;
        m_submittedFormURL = u;
darin's avatar
darin committed
471 472
    }

adele@apple.com's avatar
adele@apple.com committed
473 474
    formData->generateFiles(m_frame->page()->chrome()->client());
    
darin's avatar
darin committed
475 476 477
    if (!m_outgoingReferrer.isEmpty())
        frameRequest.resourceRequest().setHTTPReferrer(m_outgoingReferrer);

478
    if (strcmp(action, "GET") == 0)
darin@apple.com's avatar
darin@apple.com committed
479
        u.setQuery(formData->flattenToString());
480
    else {
darin's avatar
darin committed
481
        frameRequest.resourceRequest().setHTTPMethod("POST");
darin@apple.com's avatar
darin@apple.com committed
482
        frameRequest.resourceRequest().setHTTPBody(formData);
darin's avatar
darin committed
483 484 485 486 487 488 489 490 491

        // construct some user headers if necessary
        if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
            frameRequest.resourceRequest().setHTTPContentType(contentType);
        else // contentType must be "multipart/form-data"
            frameRequest.resourceRequest().setHTTPContentType(contentType + "; boundary=" + boundary);
    }

    frameRequest.resourceRequest().setURL(u);
abarth@webkit.org's avatar
abarth@webkit.org committed
492
    addHTTPOriginIfNeeded(frameRequest.resourceRequest(), outgoingOrigin());
darin's avatar
darin committed
493

494
    targetFrame->redirectScheduler()->scheduleFormSubmission(frameRequest, lockHistory, event, formState);
darin's avatar
darin committed
495 496
}

497
void FrameLoader::stopLoading(UnloadEventPolicy unloadEventPolicy, DatabasePolicy databasePolicy)
darin's avatar
darin committed
498 499 500
{
    if (m_frame->document() && m_frame->document()->tokenizer())
        m_frame->document()->tokenizer()->stopParsing();
mjs's avatar
mjs committed
501

502
    if (unloadEventPolicy != UnloadEventPolicyNone) {
darin's avatar
darin committed
503
        if (m_frame->document()) {
ggaren's avatar
ggaren committed
504
            if (m_didCallImplicitClose && !m_wasUnloadEventEmitted) {
ggaren's avatar
ggaren committed
505 506 507
                Node* currentFocusedNode = m_frame->document()->focusedNode();
                if (currentFocusedNode)
                    currentFocusedNode->aboutToUnload();
weinig@apple.com's avatar
weinig@apple.com committed
508
                m_unloadEventBeingDispatched = true;
ap@apple.com's avatar
ap@apple.com committed
509
                if (m_frame->domWindow()) {
510
                    if (unloadEventPolicy == UnloadEventPolicyUnloadAndPageHide)
511
                        m_frame->domWindow()->dispatchEvent(PageTransitionEvent::create(EventNames().pagehideEvent, m_frame->document()->inPageCache()), m_frame->document());
512
                    if (!m_frame->document()->inPageCache())
513
                        m_frame->domWindow()->dispatchEvent(Event::create(eventNames().unloadEvent, false, false), m_frame->domWindow()->document());
ap@apple.com's avatar
ap@apple.com committed
514
                }
weinig@apple.com's avatar
weinig@apple.com committed
515
                m_unloadEventBeingDispatched = false;
darin's avatar
darin committed
516
                if (m_frame->document())
517
                    m_frame->document()->updateStyleIfNeeded();
darin's avatar
darin committed
518 519 520
                m_wasUnloadEventEmitted = true;
            }
        }
521 522

        // Dispatching the unload event could have made m_frame->document() null.
darin's avatar
darin committed
523
        if (m_frame->document() && !m_frame->document()->inPageCache())
524
            m_frame->document()->removeAllEventListeners();
darin's avatar
darin committed
525 526
    }

527
    m_isComplete = true; // to avoid calling completed() in finishedParsing()
darin's avatar
darin committed
528
    m_isLoadingMainResource = false;
ggaren's avatar
ggaren committed
529
    m_didCallImplicitClose = true; // don't want that one either
darin's avatar
darin committed
530 531 532 533 534 535 536 537 538 539 540

    if (m_frame->document() && m_frame->document()->parsing()) {
        finishedParsing();
        m_frame->document()->setParsing(false);
    }
  
    m_workingURL = KURL();

    if (Document* doc = m_frame->document()) {
        if (DocLoader* docLoader = doc->docLoader())
            cache()->loader()->cancelRequests(docLoader);
ap@webkit.org's avatar
ap@webkit.org committed
541

542
#if ENABLE(DATABASE)
543 544
        if (databasePolicy == DatabasePolicyStop)
            doc->stopDatabases();
545
#endif
darin's avatar
darin committed
546 547 548 549
    }

    // tell all subframes to stop as well
    for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
550
        child->loader()->stopLoading(unloadEventPolicy);
darin's avatar
darin committed
551

552
    m_frame->redirectScheduler()->cancel();
darin's avatar
darin committed
553 554 555 556 557 558 559 560
}

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);
    
ap@webkit.org's avatar
ap@webkit.org committed
561 562 563 564
    if (m_frame->document()->tokenizer())
        m_frame->document()->tokenizer()->stopParsing();
    m_frame->document()->finishParsing();

darin's avatar
darin committed
565 566 567 568 569 570 571
    if (m_iconLoader)
        m_iconLoader->stopLoading();
}

bool FrameLoader::closeURL()
{
    saveDocumentState();
572 573 574 575 576
    
    // 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
577
    m_frame->editor()->clearUndoRedoOperations();
darin's avatar
darin committed
578 579 580 581 582 583 584
    return true;
}

KURL FrameLoader::iconURL()
{
    // If this isn't a top level frame, return nothing
    if (m_frame->tree() && m_frame->tree()->parent())
darin@apple.com's avatar
darin@apple.com committed
585 586
        return KURL();

darin's avatar
darin committed
587
    // If we have an iconURL from a Link element, return that
ap@webkit.org's avatar
ap@webkit.org committed
588
    if (!m_frame->document()->iconURL().isEmpty())
ap@apple.com's avatar
ap@apple.com committed
589
        return KURL(ParsedURLString, m_frame->document()->iconURL());
darin@apple.com's avatar
darin@apple.com committed
590

darin's avatar
darin committed
591
    // Don't return a favicon iconURL unless we're http or https
592
    if (!m_URL.protocolInHTTPFamily())
darin@apple.com's avatar
darin@apple.com committed
593 594
        return KURL();

darin's avatar
darin committed
595 596 597
    KURL url;
    url.setProtocol(m_URL.protocol());
    url.setHost(m_URL.host());
beidson's avatar
beidson committed
598 599
    if (int port = m_URL.port())
        url.setPort(port);
darin's avatar
darin committed
600 601 602 603 604 605
    url.setPath("/favicon.ico");
    return url;
}

bool FrameLoader::didOpenURL(const KURL& url)
{
606
    if (m_frame->redirectScheduler()->redirectScheduledDuringLoad()) {
darin's avatar
darin committed
607 608 609
        // 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
610
    }
darin's avatar
darin committed
611

612
    m_frame->redirectScheduler()->cancel();
darin@apple.com's avatar
darin@apple.com committed
613
    m_frame->editor()->clearLastEditCommand();
darin's avatar
darin committed
614 615 616 617
    closeURL();

    m_isComplete = false;
    m_isLoadingMainResource = true;
ggaren's avatar
ggaren committed
618
    m_didCallImplicitClose = false;
darin's avatar
darin committed
619

620 621 622 623 624 625 626
    // 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.
    if (!m_creatingInitialEmptyDocument) {
        m_frame->setJSStatusBarText(String());
        m_frame->setJSDefaultStatusBarText(String());
    }
darin's avatar
darin committed
627
    m_URL = url;
628
    if (m_URL.protocolInHTTPFamily() && !m_URL.host().isEmpty() && m_URL.path().isEmpty())
darin's avatar
darin committed
629 630 631 632 633 634 635 636
        m_URL.setPath("/");
    m_workingURL = m_URL;

    started();

    return true;
}

637
void FrameLoader::didExplicitOpen()
darin's avatar
darin committed
638 639
{
    m_isComplete = false;
ggaren's avatar
ggaren committed
640
    m_didCallImplicitClose = false;
darin's avatar
darin committed
641

andersca@apple.com's avatar
andersca@apple.com committed
642 643 644
    // Calling document.open counts as committing the first real document load.
    m_committedFirstRealDocumentLoad = true;
    
darin's avatar
darin committed
645 646 647 648
    // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
    // from a subsequent window.document.open / window.document.write call. 
    // Cancelling redirection here works for all cases because document.open 
    // implicitly precedes document.write.
649
    m_frame->redirectScheduler()->cancel(); 
darin@apple.com's avatar
darin@apple.com committed
650
    if (m_frame->document()->url() != blankURL())
weinig@apple.com's avatar
weinig@apple.com committed
651
        m_URL = m_frame->document()->url();
darin's avatar
darin committed
652 653
}

654
bool FrameLoader::executeIfJavaScriptURL(const KURL& url, bool userGesture, bool replaceDocument)
darin's avatar
darin committed
655
{
beidson@apple.com's avatar
beidson@apple.com committed
656
    if (!protocolIsJavaScript(url))
weinig@apple.com's avatar
weinig@apple.com committed
657 658
        return false;

weinig@apple.com's avatar
weinig@apple.com committed
659 660 661
    if (m_frame->page() && !m_frame->page()->javaScriptURLsAreAllowed())
        return true;

662 663
    const int javascriptSchemeLength = sizeof("javascript:") - 1;

664 665 666 667
    String script = url.string().substring(javascriptSchemeLength);
    ScriptValue result;
    if (m_frame->script()->xssAuditor()->canEvaluateJavaScriptURL(script))
        result = executeScript(decodeURLEscapeSequences(script), userGesture);
weinig@apple.com's avatar
weinig@apple.com committed
668

darin's avatar
darin committed
669
    String scriptResult;
670
    if (!result.getString(scriptResult))
weinig@apple.com's avatar
weinig@apple.com committed
671 672
        return true;

673
    SecurityOrigin* currentSecurityOrigin = m_frame->document()->securityOrigin();
weinig@apple.com's avatar
weinig@apple.com committed
674

675 676 677 678
    // FIXME: We should always replace the document, but doing so
    //        synchronously can cause crashes:
    //        http://bugs.webkit.org/show_bug.cgi?id=16782
    if (replaceDocument) {
679
        stopAllLoaders();
680 681 682 683
        begin(m_URL, true, currentSecurityOrigin);
        write(scriptResult);
        end();
    }
weinig@apple.com's avatar
weinig@apple.com committed
684 685

    return true;
darin's avatar
darin committed
686 687
}

688
ScriptValue FrameLoader::executeScript(const String& script, bool forceUserGesture)
darin's avatar
darin committed
689
{
690
    return executeScript(ScriptSourceCode(script, forceUserGesture ? KURL() : m_URL));
darin's avatar
darin committed
691 692
}

693
ScriptValue FrameLoader::executeScript(const ScriptSourceCode& sourceCode)
darin's avatar
darin committed
694
{
darin@apple.com's avatar
darin@apple.com committed
695
    if (!m_frame->script()->isEnabled() || m_frame->script()->isPaused())
696
        return ScriptValue();
darin's avatar
darin committed
697 698 699 700

    bool wasRunningScript = m_isRunningScript;
    m_isRunningScript = true;

701
    ScriptValue result = m_frame->script()->evaluate(sourceCode);
darin's avatar
darin committed
702 703 704

    if (!wasRunningScript) {
        m_isRunningScript = false;
705
        Document::updateStyleForAllDocuments();
darin's avatar
darin committed
706 707 708 709 710 711 712
    }

    return result;
}

void FrameLoader::cancelAndClear()
{
713
    m_frame->redirectScheduler()->cancel();
darin's avatar
darin committed
714 715 716 717 718

    if (!m_isComplete)
        closeURL();

    clear(false);
719
    m_frame->script()->updatePlatformScriptObjects();
darin's avatar
darin committed
720 721
}

722
void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects, bool clearFrameView)
darin's avatar
darin committed
723
{
darin's avatar
darin committed
724
    m_frame->editor()->clear();
darin's avatar
darin committed
725 726 727 728

    if (!m_needsClear)
        return;
    m_needsClear = false;
lars's avatar
lars committed
729
    
ap@webkit.org's avatar
ap@webkit.org committed
730
    if (!m_frame->document()->inPageCache()) {
darin's avatar
darin committed
731
        m_frame->document()->cancelParsing();
ap@webkit.org's avatar
ap@webkit.org committed
732
        m_frame->document()->stopActiveDOMObjects();
darin's avatar
darin committed
733 734
        if (m_frame->document()->attached()) {
            m_frame->document()->willRemove();
darin's avatar
darin committed
735
            m_frame->document()->detach();
alice.liu@apple.com's avatar
alice.liu@apple.com committed
736 737
            
            m_frame->document()->removeFocusedNodeOfSubtree(m_frame->document());
darin's avatar
darin committed
738
        }
darin's avatar
darin committed
739 740 741
    }

    // Do this after detaching the document so that the unload event works.
thatcher's avatar
thatcher committed
742
    if (clearWindowProperties) {
weinig's avatar
weinig committed
743
        m_frame->clearDOMWindow();
744
        m_frame->script()->clearWindowShell();
weinig's avatar
weinig committed
745
    }
darin's avatar
darin committed
746

darin@apple.com's avatar
darin@apple.com committed
747
    m_frame->selection()->clear();
darin's avatar
darin committed
748
    m_frame->eventHandler()->clear();
749
    if (clearFrameView && m_frame->view())
darin's avatar
darin committed
750
        m_frame->view()->clear();
751

justin.garcia@apple.com's avatar
justin.garcia@apple.com committed
752
    m_frame->setSelectionGranularity(CharacterGranularity);
darin's avatar
darin committed
753

754 755
    // 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
756
    m_frame->setDocument(0);
darin's avatar
darin committed
757 758 759
    m_decoder = 0;

    m_containsPlugIns = false;
760

antti's avatar
antti committed
761
    if (clearScriptObjects)
762 763
        m_frame->script()->clearScriptObjects();

764
    m_frame->redirectScheduler()->clear();
darin's avatar
darin committed
765

766 767 768
    m_checkTimer.stop();
    m_shouldCallCheckCompleted = false;
    m_shouldCallCheckLoadComplete = false;
weinig's avatar
weinig committed
769

darin's avatar
darin committed
770
    m_receivedData = false;
antti's avatar
antti committed
771
    m_isDisplayingInitialEmptyDocument = false;
darin's avatar
darin committed
772 773 774 775 776 777 778

    if (!m_encodingWasChosenByUser)
        m_encoding = String();
}

void FrameLoader::receivedFirstData()
{
mjs's avatar
mjs committed
779 780 781 782 783
    begin(m_workingURL, false);

    dispatchDidCommitLoad();
    dispatchWindowObjectAvailable();
    
784 785 786 787 788 789
    if (m_documentLoader) {
        String ptitle = m_documentLoader->title();
        // If we have a title let the WebView know about it.
        if (!ptitle.isNull())
            m_client->dispatchDidReceiveTitle(ptitle);
    }
darin's avatar
darin committed
790 791 792

    m_workingURL = KURL();

darin's avatar
darin committed
793
    double delay;
weinig@apple.com's avatar
weinig@apple.com committed
794
    String url;
darin's avatar
darin committed
795 796
    if (!m_documentLoader)
        return;
weinig@apple.com's avatar
weinig@apple.com committed
797
    if (!parseHTTPRefresh(m_documentLoader->response().httpHeaderField("Refresh"), false, delay, url))
ap's avatar
ap committed
798 799
        return;

weinig@apple.com's avatar
weinig@apple.com committed
800 801
    if (url.isEmpty())
        url = m_URL.string();
ap's avatar
ap committed
802
    else
darin@apple.com's avatar
darin@apple.com committed
803
        url = m_frame->document()->completeURL(url).string();
darin's avatar
darin committed
804

805
    m_frame->redirectScheduler()->scheduleRedirect(delay, url);
darin's avatar
darin committed
806 807 808 809 810 811 812 813 814 815 816
}

const String& FrameLoader::responseMIMEType() const
{
    return m_responseMIMEType;
}

void FrameLoader::setResponseMIMEType(const String& type)
{
    m_responseMIMEType = type;
}
antti's avatar
antti committed
817
    
darin's avatar
darin committed
818 819 820 821 822
void FrameLoader::begin()
{
    begin(KURL());
}

weinig@apple.com's avatar
weinig@apple.com committed
823
void FrameLoader::begin(const KURL& url, bool dispatch, SecurityOrigin* origin)
darin's avatar
darin committed
824
{
weinig@apple.com's avatar
weinig@apple.com committed
825 826 827 828
    // We need to take a reference to the security origin because |clear|
    // might destroy the document that owns it.
    RefPtr<SecurityOrigin> forcedSecurityOrigin = origin;

ap@webkit.org's avatar
ap@webkit.org committed
829 830 831 832 833
    RefPtr<Document> document;

    // Create a new document before clearing the frame, because it may need to inherit an aliased security context.
    if (!m_isDisplayingInitialEmptyDocument && m_client->shouldUsePluginDocument(m_responseMIMEType))
        document = PluginDocument::create(m_frame);
mitz@apple.com's avatar
mitz@apple.com committed
834 835
    else if (!m_client->hasHTMLView())
        document = PlaceholderDocument::create(m_frame);
ap@webkit.org's avatar
ap@webkit.org committed
836 837 838
    else
        document = DOMImplementation::createDocument(m_responseMIMEType, m_frame, m_frame->inViewSourceMode());

ap@webkit.org's avatar
ap@webkit.org committed
839
    bool resetScripting = !(m_isDisplayingInitialEmptyDocument && m_frame->document()->securityOrigin()->isSecureTransitionTo(url));
antti's avatar
antti committed
840
    clear(resetScripting, resetScripting);
841 842
    if (resetScripting)
        m_frame->script()->updatePlatformScriptObjects();
darin's avatar
darin committed
843 844 845

    m_needsClear = true;
    m_isComplete = false;
ggaren's avatar
ggaren committed
846
    m_didCallImplicitClose = false;
darin's avatar
darin committed
847
    m_isLoadingMainResource = true;
antti's avatar
antti committed
848
    m_isDisplayingInitialEmptyDocument = m_creatingInitialEmptyDocument;
darin's avatar
darin committed
849 850

    KURL ref(url);
darin@apple.com's avatar
darin@apple.com committed
851 852
    ref.setUser(String());
    ref.setPass(String());
853
    ref.removeFragmentIdentifier();
weinig@apple.com's avatar
weinig@apple.com committed
854
    m_outgoingReferrer = ref.string();
darin's avatar
darin committed
855 856
    m_URL = url;

857
    document->setURL(m_URL);
858
    m_frame->setDocument(document);
darin's avatar
darin committed
859 860 861

    if (m_decoder)
        document->setDecoder(m_decoder.get());
weinig@apple.com's avatar
weinig@apple.com committed
862 863
    if (forcedSecurityOrigin)
        document->setSecurityOrigin(forcedSecurityOrigin.get());