Skip to content

Commit a8a7a71

Browse files
[Attachment Support] Add a way to write blob data to a file URL from the UI process
https://bugs.webkit.org/show_bug.cgi?id=181236 Reviewed by Brady Eidson. Source/WebCore: Add support for writing a blob to a designated file path. See comments below for more detail. No new tests, as there change in behavior yet. See part 2: https://bugs.webkit.org/show_bug.cgi?id=181199. * page/DragController.cpp: (WebCore::DragController::dragAttachmentElement): * platform/PromisedBlobInfo.h: Remove PromisedBlobData entirely. This was added with the premise of having the web process deliver blob data to the UI process. However, the new approach I'm taking just has the UI process tell the network process to write a blob to a given location, so a data structure to deliver blob data over IPC is no longer necessary. (WebCore::PromisedBlobData::hasData const): Deleted. (WebCore::PromisedBlobData::hasFile const): Deleted. (WebCore::PromisedBlobData::operator bool const): Deleted. (WebCore::PromisedBlobData::fulfills const): Deleted. * platform/network/BlobRegistryImpl.cpp: (WebCore::BlobRegistryImpl::populateBlobsForFileWriting): Introduce a new helper to build a list of blob data for file writing. (WebCore::writeFilePathsOrDataBuffersToFile): Introduce a new static helper to write blob data (a list of file paths and data buffers) to a given file handle. Automatically closes the given file handle upon exit. (WebCore::BlobRegistryImpl::writeBlobsToTemporaryFiles): (WebCore::BlobRegistryImpl::writeBlobToFilePath): Pull out common logic in writeBlobsToTemporaryFiles and writeBlobToFilePath into helper methods (see above), and refactor both methods to use the helpers. * platform/network/BlobRegistryImpl.h: Source/WebKit: Add support for writing a blob to a designated file path. In WebKit, this is mainly plumbing writeBlobToFilePath through WebPageProxy to the network process. * NetworkProcess/FileAPI/NetworkBlobRegistry.cpp: (WebKit::NetworkBlobRegistry::writeBlobToFilePath): Call out to the BlobRegistryImpl to write blobs to the file path. Additionally grant sandbox extensions for any file-backed blob parts corresponding to the given blob URL. (WebKit::NetworkBlobRegistry::filesInBlob): Introduce a version of filesInBlob that doesn't check against the NetworkConnectionToWebProcess. This is used when the UI process is the driver for writing a blob. * NetworkProcess/FileAPI/NetworkBlobRegistry.h: * NetworkProcess/NetworkProcess.cpp: (WebKit::NetworkProcess::writeBlobToFilePath): Temporarily grant sandbox access to the given file path. * NetworkProcess/NetworkProcess.h: * NetworkProcess/NetworkProcess.messages.in: * Shared/WebCoreArgumentCoders.cpp: (IPC::ArgumentCoder<PromisedBlobInfo>::encode): (IPC::ArgumentCoder<PromisedBlobInfo>::decode): (IPC::ArgumentCoder<PromisedBlobData>::encode): Deleted. (IPC::ArgumentCoder<PromisedBlobData>::decode): Deleted. Remove PromisedBlobData (see WebCore/ChangeLog for more information). * Shared/WebCoreArgumentCoders.h: * UIProcess/Network/NetworkProcessProxy.cpp: (WebKit::NetworkProcessProxy::didClose): If the network process is terminated, flush any pending callbacks in m_writeBlobToFilePathCallbackMap, passing in a failure result (success := false) and clearing the callback map. (WebKit::NetworkProcessProxy::writeBlobToFilePath): (WebKit::NetworkProcessProxy::didWriteBlobToFilePath): * UIProcess/Network/NetworkProcessProxy.h: * UIProcess/Network/NetworkProcessProxy.messages.in: * UIProcess/WebPageProxy.cpp: (WebKit::WebPageProxy::writeBlobToFilePath): * UIProcess/WebPageProxy.h: git-svn-id: http://svn.webkit.org/repository/webkit/trunk@226470 268f45cc-cd09-0410-ab3c-d52691b4dbfc
1 parent eb0f458 commit a8a7a71

18 files changed

+266
-115
lines changed

Source/WebCore/ChangeLog

+40
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,43 @@
1+
2018-01-05 Wenson Hsieh <[email protected]>
2+
3+
[Attachment Support] Add a way to write blob data to a file URL from the UI process
4+
https://bugs.webkit.org/show_bug.cgi?id=181236
5+
6+
Reviewed by Brady Eidson.
7+
8+
Add support for writing a blob to a designated file path. See comments below for more detail. No new tests, as
9+
there change in behavior yet. See part 2: https://bugs.webkit.org/show_bug.cgi?id=181199.
10+
11+
* page/DragController.cpp:
12+
(WebCore::DragController::dragAttachmentElement):
13+
* platform/PromisedBlobInfo.h:
14+
15+
Remove PromisedBlobData entirely. This was added with the premise of having the web process deliver blob data to
16+
the UI process. However, the new approach I'm taking just has the UI process tell the network process to write
17+
a blob to a given location, so a data structure to deliver blob data over IPC is no longer necessary.
18+
19+
(WebCore::PromisedBlobData::hasData const): Deleted.
20+
(WebCore::PromisedBlobData::hasFile const): Deleted.
21+
(WebCore::PromisedBlobData::operator bool const): Deleted.
22+
(WebCore::PromisedBlobData::fulfills const): Deleted.
23+
* platform/network/BlobRegistryImpl.cpp:
24+
(WebCore::BlobRegistryImpl::populateBlobsForFileWriting):
25+
26+
Introduce a new helper to build a list of blob data for file writing.
27+
28+
(WebCore::writeFilePathsOrDataBuffersToFile):
29+
30+
Introduce a new static helper to write blob data (a list of file paths and data buffers) to a given file handle.
31+
Automatically closes the given file handle upon exit.
32+
33+
(WebCore::BlobRegistryImpl::writeBlobsToTemporaryFiles):
34+
(WebCore::BlobRegistryImpl::writeBlobToFilePath):
35+
36+
Pull out common logic in writeBlobsToTemporaryFiles and writeBlobToFilePath into helper methods (see above), and
37+
refactor both methods to use the helpers.
38+
39+
* platform/network/BlobRegistryImpl.h:
40+
141
2018-01-05 Alex Christensen <[email protected]>
242

343
Forbid < and > in URL hosts

Source/WebCore/page/DragController.cpp

+1-4
Original file line numberDiff line numberDiff line change
@@ -1289,10 +1289,7 @@ bool DragController::dragAttachmentElement(Frame& frame, HTMLAttachmentElement&
12891289
#endif
12901290

12911291
auto& file = *attachment.file();
1292-
auto blobURL = file.url().string();
1293-
bool isFileBacked = !file.path().isEmpty();
1294-
auto blobType = isFileBacked ? PromisedBlobType::FileBacked : PromisedBlobType::DataBacked;
1295-
m_client.prepareToDragPromisedBlob({ blobURL, file.type(), file.name(), blobType, additionalTypes, additionalData });
1292+
m_client.prepareToDragPromisedBlob({ file.url(), file.type(), file.name(), additionalTypes, additionalData });
12961293

12971294
return true;
12981295
}

Source/WebCore/platform/PromisedBlobInfo.h

+3-29
Original file line numberDiff line numberDiff line change
@@ -25,47 +25,21 @@
2525

2626
#pragma once
2727

28-
#include "SharedBuffer.h"
29-
3028
namespace WebCore {
3129

32-
enum class PromisedBlobType { DataBacked, FileBacked };
30+
class SharedBuffer;
31+
class URL;
3332

3433
struct PromisedBlobInfo {
35-
String blobURL;
34+
URL blobURL;
3635
String contentType;
3736
String filename;
38-
PromisedBlobType blobType;
3937

4038
Vector<String> additionalTypes;
4139
Vector<RefPtr<SharedBuffer>> additionalData;
4240

4341
operator bool() const { return !blobURL.isEmpty(); }
4442
};
4543

46-
struct PromisedBlobData {
47-
String blobURL;
48-
String filePath;
49-
RefPtr<SharedBuffer> data;
50-
51-
bool hasData() const { return data; }
52-
bool hasFile() const { return !filePath.isEmpty(); }
53-
operator bool() const { return !blobURL.isEmpty(); }
54-
bool fulfills(const PromisedBlobInfo& info) const { return *this && blobURL == info.blobURL; }
55-
};
56-
5744
} // namespace WebCore
5845

59-
namespace WTF {
60-
61-
template<typename> struct EnumTraits;
62-
template<typename E, E...> struct EnumValues;
63-
64-
template<> struct EnumTraits<WebCore::PromisedBlobType> {
65-
using values = EnumValues<WebCore::PromisedBlobType,
66-
WebCore::PromisedBlobType::DataBacked,
67-
WebCore::PromisedBlobType::FileBacked
68-
>;
69-
};
70-
71-
} // namespace WTF

Source/WebCore/platform/network/BlobRegistryImpl.cpp

+65-49
Original file line numberDiff line numberDiff line change
@@ -245,24 +245,15 @@ static WorkQueue& blobUtilityQueue()
245245
return queue;
246246
}
247247

248-
struct BlobForFileWriting {
249-
String blobURL;
250-
Vector<std::pair<String, ThreadSafeDataBuffer>> filePathsOrDataBuffers;
251-
};
252-
253-
void BlobRegistryImpl::writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, Function<void (const Vector<String>& filePaths)>&& completionHandler)
248+
bool BlobRegistryImpl::populateBlobsForFileWriting(const Vector<String>& blobURLs, Vector<BlobForFileWriting>& blobsForWriting)
254249
{
255-
Vector<BlobForFileWriting> blobsForWriting;
256250
for (auto& url : blobURLs) {
257251
blobsForWriting.append({ });
258252
blobsForWriting.last().blobURL = url.isolatedCopy();
259253

260254
auto* blobData = getBlobDataFromURL({ ParsedURLString, url });
261-
if (!blobData) {
262-
Vector<String> filePaths;
263-
completionHandler(filePaths);
264-
return;
265-
}
255+
if (!blobData)
256+
return false;
266257

267258
for (auto& item : blobData->items()) {
268259
switch (item.type()) {
@@ -277,53 +268,78 @@ void BlobRegistryImpl::writeBlobsToTemporaryFiles(const Vector<String>& blobURLs
277268
}
278269
}
279270
}
271+
return true;
272+
}
280273

281-
blobUtilityQueue().dispatch([blobsForWriting = WTFMove(blobsForWriting), completionHandler = WTFMove(completionHandler)]() mutable {
282-
Vector<String> filePaths;
274+
static bool writeFilePathsOrDataBuffersToFile(const Vector<std::pair<String, ThreadSafeDataBuffer>>& filePathsOrDataBuffers, FileSystem::PlatformFileHandle file, const String& path)
275+
{
276+
auto fileCloser = WTF::makeScopeExit([file]() mutable {
277+
FileSystem::closeFile(file);
278+
});
283279

284-
auto performWriting = [blobsForWriting = WTFMove(blobsForWriting), &filePaths]() {
285-
for (auto& blob : blobsForWriting) {
286-
FileSystem::PlatformFileHandle file;
287-
String tempFilePath = FileSystem::openTemporaryFile(ASCIILiteral("Blob"), file);
288-
289-
auto fileCloser = WTF::makeScopeExit([file]() mutable {
290-
FileSystem::closeFile(file);
291-
});
292-
293-
if (tempFilePath.isEmpty() || !FileSystem::isHandleValid(file)) {
294-
LOG_ERROR("Failed to open temporary file for writing a Blob to IndexedDB");
295-
return false;
296-
}
297-
298-
for (auto& part : blob.filePathsOrDataBuffers) {
299-
if (part.second.data()) {
300-
int length = part.second.data()->size();
301-
if (FileSystem::writeToFile(file, reinterpret_cast<const char*>(part.second.data()->data()), length) != length) {
302-
LOG_ERROR("Failed writing a Blob to temporary file for storage in IndexedDB");
303-
return false;
304-
}
305-
} else {
306-
ASSERT(!part.first.isEmpty());
307-
if (!FileSystem::appendFileContentsToFileHandle(part.first, file)) {
308-
LOG_ERROR("Failed copying File contents to a Blob temporary file for storage in IndexedDB (%s to %s)", part.first.utf8().data(), tempFilePath.utf8().data());
309-
return false;
310-
}
311-
}
312-
}
313-
314-
filePaths.append(tempFilePath.isolatedCopy());
280+
if (path.isEmpty() || !FileSystem::isHandleValid(file)) {
281+
LOG_ERROR("Failed to open temporary file for writing a Blob");
282+
return false;
283+
}
284+
285+
for (auto& part : filePathsOrDataBuffers) {
286+
if (part.second.data()) {
287+
int length = part.second.data()->size();
288+
if (FileSystem::writeToFile(file, reinterpret_cast<const char*>(part.second.data()->data()), length) != length) {
289+
LOG_ERROR("Failed writing a Blob to temporary file");
290+
return false;
315291
}
292+
} else {
293+
ASSERT(!part.first.isEmpty());
294+
if (!FileSystem::appendFileContentsToFileHandle(part.first, file)) {
295+
LOG_ERROR("Failed copying File contents to a Blob temporary file (%s to %s)", part.first.utf8().data(), path.utf8().data());
296+
return false;
297+
}
298+
}
299+
}
300+
return true;
301+
}
316302

317-
return true;
318-
};
303+
void BlobRegistryImpl::writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, Function<void(const Vector<String>& filePaths)>&& completionHandler)
304+
{
305+
Vector<BlobForFileWriting> blobsForWriting;
306+
if (!populateBlobsForFileWriting(blobURLs, blobsForWriting)) {
307+
completionHandler({ });
308+
return;
309+
}
319310

320-
if (!performWriting())
321-
filePaths.clear();
311+
blobUtilityQueue().dispatch([blobsForWriting = WTFMove(blobsForWriting), completionHandler = WTFMove(completionHandler)]() mutable {
312+
Vector<String> filePaths;
313+
for (auto& blob : blobsForWriting) {
314+
FileSystem::PlatformFileHandle file;
315+
String tempFilePath = FileSystem::openTemporaryFile(ASCIILiteral("Blob"), file);
316+
if (!writeFilePathsOrDataBuffersToFile(blob.filePathsOrDataBuffers, file, tempFilePath)) {
317+
filePaths.clear();
318+
break;
319+
}
320+
filePaths.append(tempFilePath.isolatedCopy());
321+
}
322322

323323
callOnMainThread([completionHandler = WTFMove(completionHandler), filePaths = WTFMove(filePaths)]() {
324324
completionHandler(filePaths);
325325
});
326326
});
327327
}
328328

329+
void BlobRegistryImpl::writeBlobToFilePath(const URL& blobURL, const String& path, Function<void(bool success)>&& completionHandler)
330+
{
331+
Vector<BlobForFileWriting> blobsForWriting;
332+
if (!populateBlobsForFileWriting({ blobURL }, blobsForWriting) || blobsForWriting.size() != 1) {
333+
completionHandler(false);
334+
return;
335+
}
336+
337+
blobUtilityQueue().dispatch([path, blobsForWriting = WTFMove(blobsForWriting), completionHandler = WTFMove(completionHandler)]() mutable {
338+
bool success = writeFilePathsOrDataBuffersToFile(blobsForWriting.first().filePathsOrDataBuffers, FileSystem::openFile(path, FileSystem::FileOpenMode::Write), path);
339+
callOnMainThread([success, completionHandler = WTFMove(completionHandler)]() {
340+
completionHandler(success);
341+
});
342+
});
343+
}
344+
329345
} // namespace WebCore

Source/WebCore/platform/network/BlobRegistryImpl.h

+9
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class URL;
4444
class ResourceHandle;
4545
class ResourceHandleClient;
4646
class ResourceRequest;
47+
class ThreadSafeDataBuffer;
4748

4849
// BlobRegistryImpl is not thread-safe. It should only be called from main thread.
4950
class WEBCORE_EXPORT BlobRegistryImpl final : public BlobRegistry {
@@ -54,6 +55,7 @@ class WEBCORE_EXPORT BlobRegistryImpl final : public BlobRegistry {
5455
BlobData* getBlobDataFromURL(const URL&) const;
5556

5657
Ref<ResourceHandle> createResourceHandle(const ResourceRequest&, ResourceHandleClient*);
58+
void writeBlobToFilePath(const URL& blobURL, const String& path, Function<void(bool success)>&& completionHandler);
5759

5860
private:
5961
void appendStorageItems(BlobData*, const BlobDataItemList&, long long offset, long long length);
@@ -70,6 +72,13 @@ class WEBCORE_EXPORT BlobRegistryImpl final : public BlobRegistry {
7072

7173
void writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, Function<void (const Vector<String>& filePaths)>&& completionHandler) override;
7274

75+
struct BlobForFileWriting {
76+
String blobURL;
77+
Vector<std::pair<String, ThreadSafeDataBuffer>> filePathsOrDataBuffers;
78+
};
79+
80+
bool populateBlobsForFileWriting(const Vector<String>& blobURLs, Vector<BlobForFileWriting>&);
81+
7382
HashMap<String, RefPtr<BlobData>> m_blobs;
7483
};
7584

Source/WebKit/ChangeLog

+52
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,55 @@
1+
2018-01-05 Wenson Hsieh <[email protected]>
2+
3+
[Attachment Support] Add a way to write blob data to a file URL from the UI process
4+
https://bugs.webkit.org/show_bug.cgi?id=181236
5+
6+
Reviewed by Brady Eidson.
7+
8+
Add support for writing a blob to a designated file path. In WebKit, this is mainly plumbing writeBlobToFilePath
9+
through WebPageProxy to the network process.
10+
11+
* NetworkProcess/FileAPI/NetworkBlobRegistry.cpp:
12+
(WebKit::NetworkBlobRegistry::writeBlobToFilePath):
13+
14+
Call out to the BlobRegistryImpl to write blobs to the file path. Additionally grant sandbox extensions for any
15+
file-backed blob parts corresponding to the given blob URL.
16+
17+
(WebKit::NetworkBlobRegistry::filesInBlob):
18+
19+
Introduce a version of filesInBlob that doesn't check against the NetworkConnectionToWebProcess. This is used
20+
when the UI process is the driver for writing a blob.
21+
22+
* NetworkProcess/FileAPI/NetworkBlobRegistry.h:
23+
* NetworkProcess/NetworkProcess.cpp:
24+
(WebKit::NetworkProcess::writeBlobToFilePath):
25+
26+
Temporarily grant sandbox access to the given file path.
27+
28+
* NetworkProcess/NetworkProcess.h:
29+
* NetworkProcess/NetworkProcess.messages.in:
30+
* Shared/WebCoreArgumentCoders.cpp:
31+
(IPC::ArgumentCoder<PromisedBlobInfo>::encode):
32+
(IPC::ArgumentCoder<PromisedBlobInfo>::decode):
33+
(IPC::ArgumentCoder<PromisedBlobData>::encode): Deleted.
34+
(IPC::ArgumentCoder<PromisedBlobData>::decode): Deleted.
35+
36+
Remove PromisedBlobData (see WebCore/ChangeLog for more information).
37+
38+
* Shared/WebCoreArgumentCoders.h:
39+
* UIProcess/Network/NetworkProcessProxy.cpp:
40+
(WebKit::NetworkProcessProxy::didClose):
41+
42+
If the network process is terminated, flush any pending callbacks in m_writeBlobToFilePathCallbackMap, passing
43+
in a failure result (success := false) and clearing the callback map.
44+
45+
(WebKit::NetworkProcessProxy::writeBlobToFilePath):
46+
(WebKit::NetworkProcessProxy::didWriteBlobToFilePath):
47+
* UIProcess/Network/NetworkProcessProxy.h:
48+
* UIProcess/Network/NetworkProcessProxy.messages.in:
49+
* UIProcess/WebPageProxy.cpp:
50+
(WebKit::WebPageProxy::writeBlobToFilePath):
51+
* UIProcess/WebPageProxy.h:
52+
153
2018-01-05 Dan Bernstein <[email protected]>
254

355
Add injected bundle equivalents of DOMHTMLDocument (DOMHTMLDocumentExtensions)

Source/WebKit/NetworkProcess/FileAPI/NetworkBlobRegistry.cpp

+26-2
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,25 @@ void NetworkBlobRegistry::writeBlobsToTemporaryFiles(const Vector<String>& blobU
140140
blobRegistry().writeBlobsToTemporaryFiles(blobURLs, WTFMove(completionHandler));
141141
}
142142

143+
void NetworkBlobRegistry::writeBlobToFilePath(const URL& blobURL, const String& path, Function<void(bool success)>&& completionHandler)
144+
{
145+
if (!blobRegistry().isBlobRegistryImpl()) {
146+
completionHandler(false);
147+
ASSERT_NOT_REACHED();
148+
return;
149+
}
150+
151+
auto blobFiles = filesInBlob({ ParsedURLString, blobURL });
152+
for (auto& file : blobFiles)
153+
file->prepareForFileAccess();
154+
155+
static_cast<BlobRegistryImpl&>(blobRegistry()).writeBlobToFilePath(blobURL, path, [blobFiles = WTFMove(blobFiles), completionHandler = WTFMove(completionHandler)] (bool success) {
156+
for (auto& file : blobFiles)
157+
file->revokeFileAccess();
158+
completionHandler(success);
159+
});
160+
}
161+
143162
void NetworkBlobRegistry::connectionToWebProcessDidClose(NetworkConnectionToWebProcess* connection)
144163
{
145164
if (!m_blobsForConnection.contains(connection))
@@ -155,12 +174,17 @@ void NetworkBlobRegistry::connectionToWebProcessDidClose(NetworkConnectionToWebP
155174
Vector<RefPtr<BlobDataFileReference>> NetworkBlobRegistry::filesInBlob(NetworkConnectionToWebProcess& connection, const WebCore::URL& url)
156175
{
157176
if (!m_blobsForConnection.contains(&connection) || !m_blobsForConnection.find(&connection)->value.contains(url))
158-
return Vector<RefPtr<BlobDataFileReference>>();
177+
return { };
159178

179+
return filesInBlob(url);
180+
}
181+
182+
Vector<RefPtr<BlobDataFileReference>> NetworkBlobRegistry::filesInBlob(const URL& url)
183+
{
160184
ASSERT(blobRegistry().isBlobRegistryImpl());
161185
BlobData* blobData = static_cast<BlobRegistryImpl&>(blobRegistry()).getBlobDataFromURL(url);
162186
if (!blobData)
163-
return Vector<RefPtr<BlobDataFileReference>>();
187+
return { };
164188

165189
Vector<RefPtr<BlobDataFileReference>> result;
166190
for (const BlobDataItem& item : blobData->items()) {

Source/WebKit/NetworkProcess/FileAPI/NetworkBlobRegistry.h

+2
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,12 @@ WTF_MAKE_NONCOPYABLE(NetworkBlobRegistry);
5454
void unregisterBlobURL(NetworkConnectionToWebProcess*, const WebCore::URL&);
5555
uint64_t blobSize(NetworkConnectionToWebProcess*, const WebCore::URL&);
5656
void writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, Function<void (const Vector<String>&)>&& completionHandler);
57+
void writeBlobToFilePath(const WebCore::URL& blobURL, const String& path, Function<void(bool success)>&& completionHandler);
5758

5859
void connectionToWebProcessDidClose(NetworkConnectionToWebProcess*);
5960

6061
Vector<RefPtr<WebCore::BlobDataFileReference>> filesInBlob(NetworkConnectionToWebProcess&, const WebCore::URL&);
62+
Vector<RefPtr<WebCore::BlobDataFileReference>> filesInBlob(const WebCore::URL&);
6163

6264
private:
6365
~NetworkBlobRegistry();

0 commit comments

Comments
 (0)