1/*
2 * Copyright (C) 2013-2016 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#include "config.h"
27#include "NetworkBlobRegistry.h"
28
29#include "BlobDataFileReferenceWithSandboxExtension.h"
30#include "NetworkConnectionToWebProcess.h"
31#include "SandboxExtension.h"
32#include <WebCore/BlobPart.h>
33#include <WebCore/BlobRegistryImpl.h>
34#include <wtf/NeverDestroyed.h>
35#include <wtf/RunLoop.h>
36
37namespace WebKit {
38using namespace WebCore;
39
40NetworkBlobRegistry::NetworkBlobRegistry() = default;
41NetworkBlobRegistry::~NetworkBlobRegistry() = default;
42
43void NetworkBlobRegistry::registerFileBlobURL(NetworkConnectionToWebProcess& connection, const URL& url, const String& path, RefPtr<SandboxExtension>&& sandboxExtension, const String& contentType)
44{
45 m_blobRegistry.registerFileBlobURL(url, BlobDataFileReferenceWithSandboxExtension::create(path, WTFMove(sandboxExtension)), contentType);
46
47 ASSERT(!m_blobsForConnection.get(&connection).contains(url));
48 BlobForConnectionMap::iterator mapIterator = m_blobsForConnection.find(&connection);
49 if (mapIterator == m_blobsForConnection.end())
50 mapIterator = m_blobsForConnection.add(&connection, HashSet<URL>()).iterator;
51 mapIterator->value.add(url);
52}
53
54void NetworkBlobRegistry::registerBlobURL(NetworkConnectionToWebProcess& connection, const URL& url, Vector<WebCore::BlobPart>&& blobParts, const String& contentType)
55{
56 m_blobRegistry.registerBlobURL(url, WTFMove(blobParts), contentType);
57
58 ASSERT(!m_blobsForConnection.get(&connection).contains(url));
59 BlobForConnectionMap::iterator mapIterator = m_blobsForConnection.find(&connection);
60 if (mapIterator == m_blobsForConnection.end())
61 mapIterator = m_blobsForConnection.add(&connection, HashSet<URL>()).iterator;
62 mapIterator->value.add(url);
63}
64
65void NetworkBlobRegistry::registerBlobURL(NetworkConnectionToWebProcess& connection, const URL& url, const URL& srcURL, bool shouldBypassConnectionCheck)
66{
67 // The connection may not be registered if NetworkProcess prevously crashed for any reason.
68 BlobForConnectionMap::iterator mapIterator = m_blobsForConnection.find(&connection);
69 if (mapIterator == m_blobsForConnection.end()) {
70 if (!shouldBypassConnectionCheck)
71 return;
72 mapIterator = m_blobsForConnection.add(&connection, HashSet<URL>()).iterator;
73 }
74
75 m_blobRegistry.registerBlobURL(url, srcURL);
76
77 ASSERT(shouldBypassConnectionCheck || mapIterator->value.contains(srcURL));
78 mapIterator->value.add(url);
79}
80
81void NetworkBlobRegistry::registerBlobURLOptionallyFileBacked(NetworkConnectionToWebProcess& connection, const URL& url, const URL& srcURL, const String& fileBackedPath, const String& contentType)
82{
83 m_blobRegistry.registerBlobURLOptionallyFileBacked(url, srcURL, BlobDataFileReferenceWithSandboxExtension::create(fileBackedPath, nullptr), contentType);
84
85 ASSERT(!m_blobsForConnection.get(&connection).contains(url));
86 BlobForConnectionMap::iterator mapIterator = m_blobsForConnection.find(&connection);
87 if (mapIterator == m_blobsForConnection.end())
88 mapIterator = m_blobsForConnection.add(&connection, HashSet<URL>()).iterator;
89 mapIterator->value.add(url);
90}
91
92void NetworkBlobRegistry::registerBlobURLForSlice(NetworkConnectionToWebProcess& connection, const URL& url, const URL& srcURL, int64_t start, int64_t end)
93{
94 // The connection may not be registered if NetworkProcess prevously crashed for any reason.
95 BlobForConnectionMap::iterator mapIterator = m_blobsForConnection.find(&connection);
96 if (mapIterator == m_blobsForConnection.end())
97 return;
98
99 m_blobRegistry.registerBlobURLForSlice(url, srcURL, start, end);
100
101 ASSERT(mapIterator->value.contains(srcURL));
102 mapIterator->value.add(url);
103}
104
105void NetworkBlobRegistry::unregisterBlobURL(NetworkConnectionToWebProcess& connection, const URL& url)
106{
107 // The connection may not be registered if NetworkProcess prevously crashed for any reason.
108 BlobForConnectionMap::iterator mapIterator = m_blobsForConnection.find(&connection);
109 if (mapIterator == m_blobsForConnection.end())
110 return;
111
112 m_blobRegistry.unregisterBlobURL(url);
113
114 mapIterator->value.remove(url);
115}
116
117uint64_t NetworkBlobRegistry::blobSize(NetworkConnectionToWebProcess& connection, const URL& url)
118{
119 if (!m_blobsForConnection.contains(&connection) || !m_blobsForConnection.find(&connection)->value.contains(url))
120 return 0;
121
122 return m_blobRegistry.blobSize(url);
123}
124
125void NetworkBlobRegistry::writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, CompletionHandler<void(Vector<String>&&)>&& completionHandler)
126{
127 m_blobRegistry.writeBlobsToTemporaryFiles(blobURLs, WTFMove(completionHandler));
128}
129
130void NetworkBlobRegistry::writeBlobToFilePath(const URL& blobURL, const String& path, CompletionHandler<void(bool success)>&& completionHandler)
131{
132 if (!m_blobRegistry.isBlobRegistryImpl()) {
133 completionHandler(false);
134 ASSERT_NOT_REACHED();
135 return;
136 }
137
138 auto blobFiles = filesInBlob({ { }, blobURL });
139 for (auto& file : blobFiles)
140 file->prepareForFileAccess();
141
142 m_blobRegistry.writeBlobToFilePath(blobURL, path, [blobFiles = WTFMove(blobFiles), completionHandler = WTFMove(completionHandler)] (bool success) mutable {
143 for (auto& file : blobFiles)
144 file->revokeFileAccess();
145 completionHandler(success);
146 });
147}
148
149void NetworkBlobRegistry::connectionToWebProcessDidClose(NetworkConnectionToWebProcess& connection)
150{
151 if (!m_blobsForConnection.contains(&connection))
152 return;
153
154 HashSet<URL>& blobsForConnection = m_blobsForConnection.find(&connection)->value;
155 for (HashSet<URL>::iterator iter = blobsForConnection.begin(), end = blobsForConnection.end(); iter != end; ++iter)
156 m_blobRegistry.unregisterBlobURL(*iter);
157
158 m_blobsForConnection.remove(&connection);
159}
160
161Vector<RefPtr<BlobDataFileReference>> NetworkBlobRegistry::filesInBlob(NetworkConnectionToWebProcess& connection, const URL& url)
162{
163 if (!m_blobsForConnection.contains(&connection) || !m_blobsForConnection.find(&connection)->value.contains(url))
164 return { };
165
166 return filesInBlob(url);
167}
168
169Vector<RefPtr<BlobDataFileReference>> NetworkBlobRegistry::filesInBlob(const URL& url)
170{
171 ASSERT(m_blobRegistry.isBlobRegistryImpl());
172 BlobData* blobData = m_blobRegistry.getBlobDataFromURL(url);
173 if (!blobData)
174 return { };
175
176 Vector<RefPtr<BlobDataFileReference>> result;
177 for (const BlobDataItem& item : blobData->items()) {
178 if (item.type() == BlobDataItem::Type::File)
179 result.append(item.file());
180 }
181
182 return result;
183}
184
185}
186