Unreviewed, rolling out r215608.
[WebKit-https.git] / Source / WebCore / loader / cocoa / DiskCacheMonitorCocoa.mm
1 /*
2  * Copyright (C) 2014 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 "DiskCacheMonitorCocoa.h"
28
29 #import "CFNetworkSPI.h"
30 #import "CachedResource.h"
31 #import "MemoryCache.h"
32 #import "SharedBuffer.h"
33 #import <wtf/MainThread.h>
34 #import <wtf/RefPtr.h>
35
36 #if USE(WEB_THREAD)
37 #include "WebCoreThreadRun.h"
38 #endif
39
40 namespace WebCore {
41
42 // The maximum number of seconds we'll try to wait for a resource to be disk cached before we forget the request.
43 static const double diskCacheMonitorTimeout = 20;
44
45 RefPtr<SharedBuffer> DiskCacheMonitor::tryGetFileBackedSharedBufferFromCFURLCachedResponse(CFCachedURLResponseRef cachedResponse)
46 {
47     auto data = _CFCachedURLResponseGetMemMappedData(cachedResponse);
48     if (!data)
49         return nullptr;
50
51     return SharedBuffer::wrapCFData(data);
52 }
53
54 void DiskCacheMonitor::monitorFileBackingStoreCreation(const ResourceRequest& request, SessionID sessionID, CFCachedURLResponseRef cachedResponse)
55 {
56     if (!cachedResponse)
57         return;
58
59     // FIXME: It's not good to have the new here, but the delete inside the constructor. Reconsider this design.
60     new DiskCacheMonitor(request, sessionID, cachedResponse); // Balanced by delete and unique_ptr in the blocks set up in the constructor, one of which is guaranteed to run.
61 }
62
63 DiskCacheMonitor::DiskCacheMonitor(const ResourceRequest& request, SessionID sessionID, CFCachedURLResponseRef cachedResponse)
64     : m_resourceRequest(request)
65     , m_sessionID(sessionID)
66 {
67     ASSERT(isMainThread());
68
69     // Set up a delayed callback to cancel this monitor if the resource hasn't been cached yet.
70     __block DiskCacheMonitor* rawMonitor = this;
71     auto cancelMonitorBlock = ^{
72         delete rawMonitor; // Balanced by "new DiskCacheMonitor" in monitorFileBackingStoreCreation.
73         rawMonitor = nullptr;
74     };
75
76 #if USE(WEB_THREAD)
77     auto cancelMonitorBlockToRun = ^{
78         WebThreadRun(cancelMonitorBlock);
79     };
80 #else
81     auto cancelMonitorBlockToRun = cancelMonitorBlock;
82 #endif
83
84     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * diskCacheMonitorTimeout), dispatch_get_main_queue(), cancelMonitorBlockToRun);
85
86     // Set up the disk caching callback to create the ShareableResource and send it to the WebProcess.
87     auto block = ^(CFCachedURLResponseRef cachedResponse) {
88         ASSERT(isMainThread());
89         // If the monitor isn't there then it timed out before this resource was cached to disk.
90         if (!rawMonitor)
91             return;
92
93         auto monitor = std::unique_ptr<DiskCacheMonitor>(rawMonitor); // Balanced by "new DiskCacheMonitor" in monitorFileBackingStoreCreation.
94         rawMonitor = nullptr;
95
96         auto fileBackedBuffer = DiskCacheMonitor::tryGetFileBackedSharedBufferFromCFURLCachedResponse(cachedResponse);
97         if (!fileBackedBuffer)
98             return;
99
100         monitor->resourceBecameFileBacked(*fileBackedBuffer);
101     };
102
103 #if USE(WEB_THREAD)
104     auto blockToRun = ^(CFCachedURLResponseRef response) {
105         CFRetain(response);
106         WebThreadRun(^{
107             block(response);
108             CFRelease(response);
109         });
110     };
111 #else
112     auto blockToRun = block;
113 #endif
114     _CFCachedURLResponseSetBecameFileBackedCallBackBlock(cachedResponse, blockToRun, dispatch_get_main_queue());
115 }
116
117 void DiskCacheMonitor::resourceBecameFileBacked(SharedBuffer& fileBackedBuffer)
118 {
119     auto* resource = MemoryCache::singleton().resourceForRequest(m_resourceRequest, m_sessionID);
120     if (!resource)
121         return;
122
123     resource->tryReplaceEncodedData(fileBackedBuffer);
124 }
125
126
127 } // namespace WebCore