1/*
2 * Copyright (C) 2013 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#import "config.h"
27#import "DiskCacheMonitor.h"
28
29#import "NetworkConnectionToWebProcess.h"
30#import "NetworkProcessConnectionMessages.h"
31#import "NetworkResourceLoader.h"
32#import "WebCoreArgumentCoders.h"
33#import <wtf/PassOwnPtr.h>
34
35#ifdef __has_include
36#if __has_include(<CFNetwork/CFURLCachePriv.h>)
37#include <CFNetwork/CFURLCachePriv.h>
38#endif
39#endif
40
41#if (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 80000) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090)
42
43typedef void (^CFCachedURLResponseCallBackBlock)(CFCachedURLResponseRef);
44extern "C" void _CFCachedURLResponseSetBecameFileBackedCallBackBlock(CFCachedURLResponseRef, CFCachedURLResponseCallBackBlock, dispatch_queue_t);
45
46using namespace WebCore;
47
48namespace WebKit {
49
50// The maximum number of seconds we'll try to wait for a resource to be disk cached before we forget the request.
51static const double diskCacheMonitorTimeout = 20;
52
53void DiskCacheMonitor::monitorFileBackingStoreCreation(CFCachedURLResponseRef cachedResponse, NetworkResourceLoader* loader)
54{
55    if (!cachedResponse)
56        return;
57
58    ASSERT(loader);
59
60    new DiskCacheMonitor(cachedResponse, loader); // Balanced by adoptPtr in the blocks setup in the constructor, one of which is guaranteed to run.
61}
62
63DiskCacheMonitor::DiskCacheMonitor(CFCachedURLResponseRef cachedResponse, NetworkResourceLoader* loader)
64    : m_connectionToWebProcess(loader->connectionToWebProcess())
65    , m_resourceRequest(loader->request())
66    , m_sessionID(loader->sessionID())
67{
68    ASSERT(RunLoop::isMain());
69
70    // Set up a delayed callback to cancel this monitor if the resource hasn't been cached yet.
71    __block DiskCacheMonitor* rawMonitor = this;
72
73    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * diskCacheMonitorTimeout), dispatch_get_main_queue(), ^{
74        adoptPtr(rawMonitor); // Balanced by `new DiskCacheMonitor` in monitorFileBackingStoreCreation.
75        rawMonitor = 0;
76    });
77
78    // Set up the disk caching callback to create the ShareableResource and send it to the WebProcess.
79    CFCachedURLResponseCallBackBlock block = ^(CFCachedURLResponseRef cachedResponse)
80    {
81        // If the monitor isn't there then it timed out before this resource was cached to disk.
82        if (!rawMonitor)
83            return;
84
85        OwnPtr<DiskCacheMonitor> monitor = adoptPtr(rawMonitor); // Balanced by `new DiskCacheMonitor` in monitorFileBackingStoreCreation.
86        rawMonitor = 0;
87
88        ShareableResource::Handle handle;
89        NetworkResourceLoader::tryGetShareableHandleFromCFURLCachedResponse(handle, cachedResponse);
90        if (handle.isNull())
91            return;
92
93        monitor->send(Messages::NetworkProcessConnection::DidCacheResource(monitor->resourceRequest(), handle, m_sessionID));
94    };
95
96    _CFCachedURLResponseSetBecameFileBackedCallBackBlock(cachedResponse, block, dispatch_get_main_queue());
97}
98
99IPC::Connection* DiskCacheMonitor::messageSenderConnection()
100{
101    return m_connectionToWebProcess->connection();
102}
103
104uint64_t DiskCacheMonitor::messageSenderDestinationID()
105{
106    return 0;
107}
108
109} // namespace WebKit
110
111#endif
112