~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/loader/FrameLoader.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

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