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

« back to all changes in this revision

Viewing changes to Source/WebCore/loader/MainResourceLoader.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 Apple Inc. All rights reserved.
 
3
 * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions
 
7
 * are met:
 
8
 *
 
9
 * 1.  Redistributions of source code must retain the above copyright
 
10
 *     notice, this list of conditions and the following disclaimer. 
 
11
 * 2.  Redistributions in binary form must reproduce the above copyright
 
12
 *     notice, this list of conditions and the following disclaimer in the
 
13
 *     documentation and/or other materials provided with the distribution. 
 
14
 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
 
15
 *     its contributors may be used to endorse or promote products derived
 
16
 *     from this software without specific prior written permission. 
 
17
 *
 
18
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 
19
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 
20
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 
21
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 
22
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 
23
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 
24
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 
25
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
26
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 
27
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
28
 */
 
29
 
 
30
#include "config.h"
 
31
#include "MainResourceLoader.h"
 
32
 
 
33
#include "ApplicationCacheHost.h"
 
34
#include "BackForwardController.h"
 
35
#include "Console.h"
 
36
#include "DOMWindow.h"
 
37
#include "Document.h"
 
38
#include "DocumentLoadTiming.h"
 
39
#include "DocumentLoader.h"
 
40
#include "FormState.h"
 
41
#include "Frame.h"
 
42
#include "FrameLoader.h"
 
43
#include "FrameLoaderClient.h"
 
44
#include "HTMLFormElement.h"
 
45
#include "HistoryItem.h"
 
46
#include "InspectorInstrumentation.h"
 
47
#include "LoaderStrategy.h"
 
48
#include "Page.h"
 
49
#include "PlatformStrategies.h"
 
50
#include "ResourceError.h"
 
51
#include "ResourceHandle.h"
 
52
#include "ResourceLoadScheduler.h"
 
53
#include "SchemeRegistry.h"
 
54
#include "SecurityOrigin.h"
 
55
#include "Settings.h"
 
56
#include <wtf/CurrentTime.h>
 
57
 
 
58
#if PLATFORM(QT)
 
59
#include "PluginDatabase.h"
 
60
#endif
 
61
 
 
62
#if PLATFORM(MAC) && !PLATFORM(IOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
 
63
#include "WebCoreSystemInterface.h"
 
64
#endif
 
65
 
 
66
// FIXME: More that is in common with SubresourceLoader should move up into ResourceLoader.
 
67
 
 
68
namespace WebCore {
 
69
 
 
70
MainResourceLoader::MainResourceLoader(Frame* frame)
 
71
    : ResourceLoader(frame, ResourceLoaderOptions(SendCallbacks, SniffContent, BufferData, AllowStoredCredentials, AskClientForCrossOriginCredentials, SkipSecurityCheck))
 
72
    , m_dataLoadTimer(this, &MainResourceLoader::handleSubstituteDataLoadNow)
 
73
    , m_loadingMultipartContent(false)
 
74
    , m_waitingForContentPolicy(false)
 
75
    , m_timeOfLastDataReceived(0.0)
 
76
#if PLATFORM(MAC) && !PLATFORM(IOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
 
77
    , m_filter(0)
 
78
#endif
 
79
{
 
80
}
 
81
 
 
82
MainResourceLoader::~MainResourceLoader()
 
83
{
 
84
#if PLATFORM(MAC) && !PLATFORM(IOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
 
85
    ASSERT(!m_filter);
 
86
#endif
 
87
}
 
88
 
 
89
PassRefPtr<MainResourceLoader> MainResourceLoader::create(Frame* frame)
 
90
{
 
91
    return adoptRef(new MainResourceLoader(frame));
 
92
}
 
93
 
 
94
void MainResourceLoader::receivedError(const ResourceError& error)
 
95
{
 
96
    // Calling receivedMainResourceError will likely result in the last reference to this object to go away.
 
97
    RefPtr<MainResourceLoader> protect(this);
 
98
    RefPtr<Frame> protectFrame(m_frame);
 
99
 
 
100
    // It is important that we call DocumentLoader::mainReceivedError before calling 
 
101
    // ResourceLoadNotifier::didFailToLoad because mainReceivedError clears out the relevant
 
102
    // document loaders. Also, mainReceivedError ends up calling a FrameLoadDelegate method
 
103
    // and didFailToLoad calls a ResourceLoadDelegate method and they need to be in the correct order.
 
104
    documentLoader()->mainReceivedError(error);
 
105
 
 
106
    if (!cancelled()) {
 
107
        ASSERT(!reachedTerminalState());
 
108
        frameLoader()->notifier()->didFailToLoad(this, error);
 
109
        
 
110
        releaseResources();
 
111
    }
 
112
 
 
113
    ASSERT(reachedTerminalState());
 
114
}
 
115
 
 
116
void MainResourceLoader::willCancel(const ResourceError&)
 
117
{
 
118
    m_dataLoadTimer.stop();
 
119
 
 
120
    if (m_waitingForContentPolicy) {
 
121
        frameLoader()->policyChecker()->cancelCheck();
 
122
        ASSERT(m_waitingForContentPolicy);
 
123
        m_waitingForContentPolicy = false;
 
124
        deref(); // balances ref in didReceiveResponse
 
125
    }
 
126
}
 
127
 
 
128
void MainResourceLoader::didCancel(const ResourceError& error)
 
129
{
 
130
    // We should notify the frame loader after fully canceling the load, because it can do complicated work
 
131
    // like calling DOMWindow::print(), during which a half-canceled load could try to finish.
 
132
    documentLoader()->mainReceivedError(error);
 
133
 
 
134
#if PLATFORM(MAC) && !PLATFORM(IOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
 
135
    if (m_filter) {
 
136
        wkFilterRelease(m_filter);
 
137
        m_filter = 0;
 
138
    }
 
139
#endif
 
140
}
 
141
 
 
142
ResourceError MainResourceLoader::interruptedForPolicyChangeError() const
 
143
{
 
144
    return frameLoader()->client()->interruptedForPolicyChangeError(request());
 
145
}
 
146
 
 
147
void MainResourceLoader::stopLoadingForPolicyChange()
 
148
{
 
149
    ResourceError error = interruptedForPolicyChangeError();
 
150
    error.setIsCancellation(true);
 
151
    cancel(error);
 
152
}
 
153
 
 
154
void MainResourceLoader::callContinueAfterNavigationPolicy(void* argument, const ResourceRequest& request, PassRefPtr<FormState>, bool shouldContinue)
 
155
{
 
156
    static_cast<MainResourceLoader*>(argument)->continueAfterNavigationPolicy(request, shouldContinue);
 
157
}
 
158
 
 
159
void MainResourceLoader::continueAfterNavigationPolicy(const ResourceRequest& request, bool shouldContinue)
 
160
{
 
161
    if (!shouldContinue)
 
162
        stopLoadingForPolicyChange();
 
163
    else if (m_substituteData.isValid()) {
 
164
        // A redirect resulted in loading substitute data.
 
165
        ASSERT(documentLoader()->timing()->redirectCount());
 
166
        handle()->cancel();
 
167
        handleSubstituteDataLoadSoon(request);
 
168
    }
 
169
 
 
170
    deref(); // balances ref in willSendRequest
 
171
}
 
172
 
 
173
bool MainResourceLoader::isPostOrRedirectAfterPost(const ResourceRequest& newRequest, const ResourceResponse& redirectResponse)
 
174
{
 
175
    if (newRequest.httpMethod() == "POST")
 
176
        return true;
 
177
 
 
178
    int status = redirectResponse.httpStatusCode();
 
179
    if (((status >= 301 && status <= 303) || status == 307)
 
180
        && frameLoader()->initialRequest().httpMethod() == "POST")
 
181
        return true;
 
182
    
 
183
    return false;
 
184
}
 
185
 
 
186
void MainResourceLoader::addData(const char* data, int length, bool allAtOnce)
 
187
{
 
188
    ResourceLoader::addData(data, length, allAtOnce);
 
189
    documentLoader()->receivedData(data, length);
 
190
}
 
191
 
 
192
void MainResourceLoader::willSendRequest(ResourceRequest& newRequest, const ResourceResponse& redirectResponse)
 
193
{
 
194
    // Note that there are no asserts here as there are for the other callbacks. This is due to the
 
195
    // fact that this "callback" is sent when starting every load, and the state of callback
 
196
    // deferrals plays less of a part in this function in preventing the bad behavior deferring 
 
197
    // callbacks is meant to prevent.
 
198
    ASSERT(!newRequest.isNull());
 
199
 
 
200
    // The additional processing can do anything including possibly removing the last
 
201
    // reference to this object; one example of this is 3266216.
 
202
    RefPtr<MainResourceLoader> protect(this);
 
203
 
 
204
    if (!frameLoader()->checkIfFormActionAllowedByCSP(newRequest.url())) {
 
205
        cancel();
 
206
        return;
 
207
    }
 
208
 
 
209
    ASSERT(documentLoader()->timing()->fetchStart());
 
210
    if (!redirectResponse.isNull()) {
 
211
        // If the redirecting url is not allowed to display content from the target origin,
 
212
        // then block the redirect.
 
213
        RefPtr<SecurityOrigin> redirectingOrigin = SecurityOrigin::create(redirectResponse.url());
 
214
        if (!redirectingOrigin->canDisplay(newRequest.url())) {
 
215
            FrameLoader::reportLocalLoadFailed(m_frame.get(), newRequest.url().string());
 
216
            cancel();
 
217
            return;
 
218
        }
 
219
        documentLoader()->timing()->addRedirect(redirectResponse.url(), newRequest.url());
 
220
    }
 
221
 
 
222
    // Update cookie policy base URL as URL changes, except for subframes, which use the
 
223
    // URL of the main frame which doesn't change when we redirect.
 
224
    if (frameLoader()->isLoadingMainFrame())
 
225
        newRequest.setFirstPartyForCookies(newRequest.url());
 
226
 
 
227
    // If we're fielding a redirect in response to a POST, force a load from origin, since
 
228
    // this is a common site technique to return to a page viewing some data that the POST
 
229
    // just modified.
 
230
    // Also, POST requests always load from origin, but this does not affect subresources.
 
231
    if (newRequest.cachePolicy() == UseProtocolCachePolicy && isPostOrRedirectAfterPost(newRequest, redirectResponse))
 
232
        newRequest.setCachePolicy(ReloadIgnoringCacheData);
 
233
 
 
234
    Frame* top = m_frame->tree()->top();
 
235
    if (top != m_frame) {
 
236
        if (!frameLoader()->mixedContentChecker()->canDisplayInsecureContent(top->document()->securityOrigin(), newRequest.url())) {
 
237
            cancel();
 
238
            return;
 
239
        }
 
240
    }
 
241
 
 
242
    ResourceLoader::willSendRequest(newRequest, redirectResponse);
 
243
 
 
244
    // Don't set this on the first request. It is set when the main load was started.
 
245
    m_documentLoader->setRequest(newRequest);
 
246
 
 
247
    if (!redirectResponse.isNull()) {
 
248
        // We checked application cache for initial URL, now we need to check it for redirected one.
 
249
        ASSERT(!m_substituteData.isValid());
 
250
        documentLoader()->applicationCacheHost()->maybeLoadMainResourceForRedirect(newRequest, m_substituteData);
 
251
    }
 
252
 
 
253
    // FIXME: Ideally we'd stop the I/O until we hear back from the navigation policy delegate
 
254
    // listener. But there's no way to do that in practice. So instead we cancel later if the
 
255
    // listener tells us to. In practice that means the navigation policy needs to be decided
 
256
    // synchronously for these redirect cases.
 
257
    if (!redirectResponse.isNull()) {
 
258
        ref(); // balanced by deref in continueAfterNavigationPolicy
 
259
        frameLoader()->policyChecker()->checkNavigationPolicy(newRequest, callContinueAfterNavigationPolicy, this);
 
260
    }
 
261
}
 
262
 
 
263
void MainResourceLoader::continueAfterContentPolicy(PolicyAction contentPolicy, const ResourceResponse& r)
 
264
{
 
265
    KURL url = request().url();
 
266
    const String& mimeType = r.mimeType();
 
267
    
 
268
    switch (contentPolicy) {
 
269
    case PolicyUse: {
 
270
        // Prevent remote web archives from loading because they can claim to be from any domain and thus avoid cross-domain security checks (4120255).
 
271
        bool isRemoteWebArchive = (equalIgnoringCase("application/x-webarchive", mimeType)
 
272
#if PLATFORM(GTK)
 
273
                                   || equalIgnoringCase("message/rfc822", mimeType)
 
274
#endif
 
275
                                   || equalIgnoringCase("multipart/related", mimeType))
 
276
            && !m_substituteData.isValid() && !SchemeRegistry::shouldTreatURLSchemeAsLocal(url.protocol());
 
277
        if (!frameLoader()->client()->canShowMIMEType(mimeType) || isRemoteWebArchive) {
 
278
            frameLoader()->policyChecker()->cannotShowMIMEType(r);
 
279
            // Check reachedTerminalState since the load may have already been canceled inside of _handleUnimplementablePolicyWithErrorCode::.
 
280
            if (!reachedTerminalState())
 
281
                stopLoadingForPolicyChange();
 
282
            return;
 
283
        }
 
284
        break;
 
285
    }
 
286
 
 
287
    case PolicyDownload: {
 
288
        // m_handle can be null, e.g. when loading a substitute resource from application cache.
 
289
        if (!m_handle) {
 
290
            receivedError(cannotShowURLError());
 
291
            return;
 
292
        }
 
293
        InspectorInstrumentation::continueWithPolicyDownload(m_frame.get(), documentLoader(), identifier(), r);
 
294
 
 
295
        // When starting the request, we didn't know that it would result in download and not navigation. Now we know that main document URL didn't change.
 
296
        // Download may use this knowledge for purposes unrelated to cookies, notably for setting file quarantine data.
 
297
        ResourceRequest request = this->request();
 
298
        frameLoader()->setOriginalURLForDownloadRequest(request);
 
299
 
 
300
        frameLoader()->client()->download(m_handle.get(), request, r);
 
301
 
 
302
        // It might have gone missing
 
303
        if (frameLoader())
 
304
            receivedError(interruptedForPolicyChangeError());
 
305
        return;
 
306
    }
 
307
    case PolicyIgnore:
 
308
        InspectorInstrumentation::continueWithPolicyIgnore(m_frame.get(), documentLoader(), identifier(), r);
 
309
        stopLoadingForPolicyChange();
 
310
        return;
 
311
    
 
312
    default:
 
313
        ASSERT_NOT_REACHED();
 
314
    }
 
315
 
 
316
    RefPtr<MainResourceLoader> protect(this);
 
317
 
 
318
    if (r.isHTTP()) {
 
319
        int status = r.httpStatusCode();
 
320
        if (status < 200 || status >= 300) {
 
321
            bool hostedByObject = frameLoader()->isHostedByObjectElement();
 
322
 
 
323
            frameLoader()->handleFallbackContent();
 
324
            // object elements are no longer rendered after we fallback, so don't
 
325
            // keep trying to process data from their load
 
326
 
 
327
            if (hostedByObject)
 
328
                cancel();
 
329
        }
 
330
    }
 
331
 
 
332
    // we may have cancelled this load as part of switching to fallback content
 
333
    if (!reachedTerminalState())
 
334
        ResourceLoader::didReceiveResponse(r);
 
335
 
 
336
    if (frameLoader() && !frameLoader()->activeDocumentLoader()->isStopping() && m_substituteData.isValid()) {
 
337
        if (m_substituteData.content()->size())
 
338
            didReceiveData(m_substituteData.content()->data(), m_substituteData.content()->size(), m_substituteData.content()->size(), true);
 
339
        if (frameLoader() && !frameLoader()->activeDocumentLoader()->isStopping()) 
 
340
            didFinishLoading(0);
 
341
    }
 
342
}
 
343
 
 
344
void MainResourceLoader::callContinueAfterContentPolicy(void* argument, PolicyAction policy)
 
345
{
 
346
    static_cast<MainResourceLoader*>(argument)->continueAfterContentPolicy(policy);
 
347
}
 
348
 
 
349
void MainResourceLoader::continueAfterContentPolicy(PolicyAction policy)
 
350
{
 
351
    ASSERT(m_waitingForContentPolicy);
 
352
    m_waitingForContentPolicy = false;
 
353
    if (frameLoader() && !frameLoader()->activeDocumentLoader()->isStopping())
 
354
        continueAfterContentPolicy(policy, m_response);
 
355
    deref(); // balances ref in didReceiveResponse
 
356
}
 
357
 
 
358
void MainResourceLoader::didReceiveResponse(const ResourceResponse& r)
 
359
{
 
360
    if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForMainResponse(request(), r))
 
361
        return;
 
362
 
 
363
    DEFINE_STATIC_LOCAL(AtomicString, xFrameOptionHeader, ("x-frame-options", AtomicString::ConstructFromLiteral));
 
364
    HTTPHeaderMap::const_iterator it = r.httpHeaderFields().find(xFrameOptionHeader);
 
365
    if (it != r.httpHeaderFields().end()) {
 
366
        String content = it->value;
 
367
        if (m_frame->loader()->shouldInterruptLoadForXFrameOptions(content, r.url(), identifier())) {
 
368
            InspectorInstrumentation::continueAfterXFrameOptionsDenied(m_frame.get(), documentLoader(), identifier(), r);
 
369
            String message = "Refused to display '" + r.url().string() + "' in a frame because it set 'X-Frame-Options' to '" + content + "'.";
 
370
            m_frame->document()->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message, r.url().string(), 0, 0, identifier());
 
371
 
 
372
            cancel();
 
373
            return;
 
374
        }
 
375
    }
 
376
 
 
377
    // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred.
 
378
    // See <rdar://problem/6304600> for more details.
 
379
#if !USE(CF)
 
380
    ASSERT(!defersLoading());
 
381
#endif
 
382
 
 
383
    if (m_loadingMultipartContent) {
 
384
        m_documentLoader->setupForReplace();
 
385
        clearResourceData();
 
386
    }
 
387
    
 
388
    if (r.isMultipart())
 
389
        m_loadingMultipartContent = true;
 
390
        
 
391
    // The additional processing can do anything including possibly removing the last
 
392
    // reference to this object; one example of this is 3266216.
 
393
    RefPtr<MainResourceLoader> protect(this);
 
394
 
 
395
    m_documentLoader->setResponse(r);
 
396
 
 
397
    m_response = r;
 
398
 
 
399
    ASSERT(!m_waitingForContentPolicy);
 
400
    m_waitingForContentPolicy = true;
 
401
    ref(); // balanced by deref in continueAfterContentPolicy and didCancel
 
402
 
 
403
    ASSERT(frameLoader()->activeDocumentLoader());
 
404
 
 
405
    // Always show content with valid substitute data.
 
406
    if (frameLoader()->activeDocumentLoader()->substituteData().isValid()) {
 
407
        callContinueAfterContentPolicy(this, PolicyUse);
 
408
        return;
 
409
    }
 
410
 
 
411
#if ENABLE(FTPDIR)
 
412
    // Respect the hidden FTP Directory Listing pref so it can be tested even if the policy delegate might otherwise disallow it
 
413
    Settings* settings = m_frame->settings();
 
414
    if (settings && settings->forceFTPDirectoryListings() && m_response.mimeType() == "application/x-ftp-directory") {
 
415
        callContinueAfterContentPolicy(this, PolicyUse);
 
416
        return;
 
417
    }
 
418
#endif
 
419
 
 
420
#if PLATFORM(MAC) && !PLATFORM(IOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
 
421
    if (r.url().protocolIs("https") && wkFilterIsManagedSession())
 
422
        m_filter = wkFilterCreateInstance(r.nsURLResponse());
 
423
#endif
 
424
 
 
425
    frameLoader()->policyChecker()->checkContentPolicy(m_response, callContinueAfterContentPolicy, this);
 
426
}
 
427
 
 
428
void MainResourceLoader::didReceiveData(const char* data, int length, long long encodedDataLength, bool allAtOnce)
 
429
{
 
430
    ASSERT(data);
 
431
    ASSERT(length != 0);
 
432
 
 
433
    ASSERT(!m_response.isNull());
 
434
 
 
435
#if USE(CFNETWORK) || PLATFORM(MAC)
 
436
    // Workaround for <rdar://problem/6060782>
 
437
    if (m_response.isNull()) {
 
438
        m_response = ResourceResponse(KURL(), "text/html", 0, String(), String());
 
439
        if (DocumentLoader* documentLoader = frameLoader()->activeDocumentLoader())
 
440
            documentLoader->setResponse(m_response);
 
441
    }
 
442
#endif
 
443
 
 
444
    // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred.
 
445
    // See <rdar://problem/6304600> for more details.
 
446
#if !USE(CF)
 
447
    ASSERT(!defersLoading());
 
448
#endif
 
449
 
 
450
#if PLATFORM(MAC) && !PLATFORM(IOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
 
451
    if (m_filter) {
 
452
        ASSERT(!wkFilterWasBlocked(m_filter));
 
453
        const char* blockedData = wkFilterAddData(m_filter, data, &length);
 
454
        // If we don't have blockedData, that means we're still accumulating data
 
455
        if (!blockedData) {
 
456
            // Transition to committed state.
 
457
            ResourceLoader::didReceiveData("", 0, 0, false);
 
458
            return;
 
459
        }
 
460
 
 
461
        data = blockedData;
 
462
        encodedDataLength = -1;
 
463
    }
 
464
#endif
 
465
 
 
466
    documentLoader()->applicationCacheHost()->mainResourceDataReceived(data, length, encodedDataLength, allAtOnce);
 
467
 
 
468
    // The additional processing can do anything including possibly removing the last
 
469
    // reference to this object; one example of this is 3266216.
 
470
    RefPtr<MainResourceLoader> protect(this);
 
471
 
 
472
    m_timeOfLastDataReceived = monotonicallyIncreasingTime();
 
473
 
 
474
    ResourceLoader::didReceiveData(data, length, encodedDataLength, allAtOnce);
 
475
 
 
476
#if PLATFORM(MAC) && !PLATFORM(IOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
 
477
    if (WebFilterEvaluator *filter = m_filter) {
 
478
        // If we got here, it means we know if we were blocked or not. If we were blocked, we're
 
479
        // done loading the page altogether. Either way, we don't need the filter anymore.
 
480
 
 
481
        // Remove this->m_filter early so didFinishLoading doesn't see it.
 
482
        m_filter = 0;
 
483
        if (wkFilterWasBlocked(filter))
 
484
            cancel();
 
485
        wkFilterRelease(filter);
 
486
    }
 
487
#endif
 
488
}
 
489
 
 
490
void MainResourceLoader::didFinishLoading(double finishTime)
 
491
{
 
492
    // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred.
 
493
    // See <rdar://problem/6304600> for more details.
 
494
#if !USE(CF)
 
495
    ASSERT(!defersLoading() || InspectorInstrumentation::isDebuggerPaused(m_frame.get()));
 
496
#endif
 
497
 
 
498
    // The additional processing can do anything including possibly removing the last
 
499
    // reference to this object.
 
500
    RefPtr<MainResourceLoader> protect(this);
 
501
    RefPtr<DocumentLoader> dl = documentLoader();
 
502
 
 
503
#if PLATFORM(MAC) && !PLATFORM(IOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
 
504
    if (m_filter) {
 
505
        int length;
 
506
        const char* data = wkFilterDataComplete(m_filter, &length);
 
507
        WebFilterEvaluator *filter = m_filter;
 
508
        // Remove this->m_filter early so didReceiveData doesn't see it.
 
509
        m_filter = 0;
 
510
        if (data)
 
511
            didReceiveData(data, length, -1, false);
 
512
        wkFilterRelease(filter);
 
513
    }
 
514
#endif
 
515
 
 
516
    if (m_loadingMultipartContent)
 
517
        dl->maybeFinishLoadingMultipartContent();
 
518
 
 
519
    documentLoader()->timing()->setResponseEnd(finishTime ? finishTime : (m_timeOfLastDataReceived ? m_timeOfLastDataReceived : monotonicallyIncreasingTime()));
 
520
    documentLoader()->finishedLoading();
 
521
    ResourceLoader::didFinishLoading(finishTime);
 
522
 
 
523
    dl->applicationCacheHost()->finishedLoadingMainResource();
 
524
}
 
525
 
 
526
void MainResourceLoader::didFail(const ResourceError& error)
 
527
{
 
528
#if PLATFORM(MAC) && !PLATFORM(IOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
 
529
    if (m_filter) {
 
530
        wkFilterRelease(m_filter);
 
531
        m_filter = 0;
 
532
    }
 
533
#endif
 
534
 
 
535
    if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForMainError(request(), error))
 
536
        return;
 
537
 
 
538
    // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred.
 
539
    // See <rdar://problem/6304600> for more details.
 
540
#if !USE(CF)
 
541
    ASSERT(!defersLoading());
 
542
#endif
 
543
    
 
544
    receivedError(error);
 
545
}
 
546
 
 
547
void MainResourceLoader::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
 
548
{
 
549
    MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::Loader);
 
550
    ResourceLoader::reportMemoryUsage(memoryObjectInfo);
 
551
    info.addMember(m_initialRequest);
 
552
    info.addMember(m_substituteData);
 
553
    info.addMember(m_dataLoadTimer);
 
554
}
 
555
 
 
556
void MainResourceLoader::handleSubstituteDataLoadNow(MainResourceLoaderTimer*)
 
557
{
 
558
    RefPtr<MainResourceLoader> protect(this);
 
559
 
 
560
    KURL url = m_substituteData.responseURL();
 
561
    if (url.isEmpty())
 
562
        url = m_initialRequest.url();
 
563
 
 
564
    // Clear the initial request here so that subsequent entries into the
 
565
    // loader will not think there's still a deferred load left to do.
 
566
    m_initialRequest = ResourceRequest();
 
567
        
 
568
    ResourceResponse response(url, m_substituteData.mimeType(), m_substituteData.content()->size(), m_substituteData.textEncoding(), "");
 
569
    didReceiveResponse(response);
 
570
}
 
571
 
 
572
void MainResourceLoader::startDataLoadTimer()
 
573
{
 
574
    m_dataLoadTimer.startOneShot(0);
 
575
 
 
576
#if HAVE(RUNLOOP_TIMER)
 
577
    if (SchedulePairHashSet* scheduledPairs = m_frame->page()->scheduledRunLoopPairs())
 
578
        m_dataLoadTimer.schedule(*scheduledPairs);
 
579
#endif
 
580
}
 
581
 
 
582
void MainResourceLoader::handleSubstituteDataLoadSoon(const ResourceRequest& r)
 
583
{
 
584
    m_initialRequest = r;
 
585
    
 
586
    if (m_documentLoader->deferMainResourceDataLoad())
 
587
        startDataLoadTimer();
 
588
    else
 
589
        handleSubstituteDataLoadNow(0);
 
590
}
 
591
 
 
592
void MainResourceLoader::loadNow(ResourceRequest& r)
 
593
{
 
594
    ASSERT(!m_handle);
 
595
    ASSERT(!defersLoading());
 
596
 
 
597
#if USE(PLATFORM_STRATEGIES)
 
598
    platformStrategies()->loaderStrategy()->resourceLoadScheduler()->addMainResourceLoad(this);
 
599
#else
 
600
    resourceLoadScheduler()->addMainResourceLoad(this);
 
601
#endif
 
602
 
 
603
    if (m_substituteData.isValid())
 
604
        handleSubstituteDataLoadSoon(r);
 
605
    else
 
606
        m_handle = ResourceHandle::create(m_frame->loader()->networkingContext(), r, this, false, true);
 
607
 
 
608
    return;
 
609
}
 
610
 
 
611
void MainResourceLoader::load(const ResourceRequest& r, const SubstituteData& substituteData)
 
612
{
 
613
    ASSERT(!m_handle);
 
614
 
 
615
    // It appears that it is possible for this load to be cancelled and derefenced by the DocumentLoader
 
616
    // in willSendRequest() if loadNow() is called.
 
617
    RefPtr<MainResourceLoader> protect(this);
 
618
 
 
619
    m_substituteData = substituteData;
 
620
 
 
621
    ASSERT(documentLoader()->timing()->navigationStart());
 
622
    ASSERT(!documentLoader()->timing()->fetchStart());
 
623
    documentLoader()->timing()->markFetchStart();
 
624
    ResourceRequest request(r);
 
625
 
 
626
    // Send this synthetic delegate callback since clients expect it, and
 
627
    // we no longer send the callback from within NSURLConnection for
 
628
    // initial requests.
 
629
    willSendRequest(request, ResourceResponse());
 
630
    ASSERT(!deletionHasBegun());
 
631
 
 
632
    // <rdar://problem/4801066>
 
633
    // willSendRequest() is liable to make the call to frameLoader() return null, so we need to check that here
 
634
    if (!frameLoader() || request.isNull()) {
 
635
        if (!reachedTerminalState())
 
636
            releaseResources();
 
637
        return;
 
638
    }
 
639
 
 
640
    documentLoader()->applicationCacheHost()->maybeLoadMainResource(request, m_substituteData);
 
641
 
 
642
    if (defersLoading())
 
643
        m_initialRequest = request;
 
644
    else
 
645
        loadNow(request);
 
646
}
 
647
 
 
648
void MainResourceLoader::setDefersLoading(bool defers)
 
649
{
 
650
    ResourceLoader::setDefersLoading(defers);
 
651
 
 
652
    if (defers) {
 
653
        if (m_dataLoadTimer.isActive())
 
654
            m_dataLoadTimer.stop();
 
655
    } else {
 
656
        if (m_initialRequest.isNull())
 
657
            return;
 
658
 
 
659
        ResourceRequest initialRequest(m_initialRequest);
 
660
        m_initialRequest = ResourceRequest();
 
661
        loadNow(initialRequest);
 
662
    }
 
663
}
 
664
 
 
665
}