From 7b85ca0301b7fbe1452b857e15c966c17743e7ce Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Wed, 31 Aug 2016 05:38:32 +0530 Subject: [PATCH] create helper class to read blob data --- atom/browser/api/atom_api_session.cc | 125 ++-------------- atom/browser/api/atom_api_session.h | 10 +- atom/browser/atom_blob_reader.cc | 133 ++++++++++++++++++ atom/browser/atom_blob_reader.h | 80 +++++++++++ atom/browser/atom_browser_context.cc | 16 +++ atom/browser/atom_browser_context.h | 3 + .../native_mate_converters/value_converter.cc | 7 - .../native_mate_converters/value_converter.h | 7 - docs/api/protocol.md | 3 +- docs/api/session.md | 5 +- filenames.gypi | 2 + spec/api-session-spec.js | 13 -- 12 files changed, 251 insertions(+), 153 deletions(-) create mode 100644 atom/browser/atom_blob_reader.cc create mode 100644 atom/browser/atom_blob_reader.h diff --git a/atom/browser/api/atom_api_session.cc b/atom/browser/api/atom_api_session.cc index 019ac27bf164..45405099ddef 100644 --- a/atom/browser/api/atom_api_session.cc +++ b/atom/browser/api/atom_api_session.cc @@ -33,13 +33,11 @@ #include "brightray/browser/net/devtools_network_controller_handle.h" #include "chrome/common/pref_names.h" #include "components/prefs/pref_service.h" -#include "content/browser/blob_storage/chrome_blob_storage_context.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/storage_partition.h" #include "native_mate/dictionary.h" #include "native_mate/object_template_builder.h" #include "net/base/load_flags.h" -#include "net/base/io_buffer.h" #include "net/disk_cache/disk_cache.h" #include "net/dns/host_cache.h" #include "net/http/http_auth_handler_factory.h" @@ -49,9 +47,6 @@ #include "net/url_request/static_http_user_agent_settings.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_getter.h" -#include "storage/browser/blob/blob_reader.h" -#include "storage/browser/blob/blob_storage_context.h" -#include "storage/browser/fileapi/file_system_context.h" #include "ui/base/l10n/l10n_util.h" using content::BrowserThread; @@ -238,12 +233,6 @@ void RunCallbackInUI(const base::Callback& callback, T... result) { BrowserThread::UI, FROM_HERE, base::Bind(callback, result...)); } -void RunBlobDataCallback( - const Session::BlobDataCallback& completion_callback, - std::unique_ptr result) { - completion_callback.Run(*(result.get())); -} - // Callback of HttpCache::GetBackend. void OnGetBackend(disk_cache::Backend** backend_ptr, Session::CacheAction action, @@ -341,85 +330,6 @@ void OnClearStorageDataDone(const base::Closure& callback) { callback.Run(); } -void DidReadBlobData(const scoped_refptr& blob_data, - const Session::BlobDataCallback& completion_callback, - int bytes_read) { - std::unique_ptr result( - base::BinaryValue::CreateWithCopiedBuffer(blob_data->data(), - bytes_read)); - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - base::Bind(&RunBlobDataCallback, - completion_callback, - base::Passed(&result))); -} - -void DidCalculateBlobSize( - std::shared_ptr blob_reader, - const Session::BlobDataCallback& completion_callback, - int result) { - if (result != net::OK) { - std::unique_ptr dummy(new base::BinaryValue()); - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - base::Bind(&RunBlobDataCallback, - completion_callback, - base::Passed(&dummy))); - return; - } - - uint64_t total_size = blob_reader->total_size(); - int bytes_read = 0; - scoped_refptr blob_data = - new net::IOBuffer(static_cast(total_size)); - net::CompletionCallback callback = base::Bind(&DidReadBlobData, - base::RetainedRef(blob_data), - completion_callback); - storage::BlobReader::Status read_status = blob_reader->Read( - blob_data.get(), - total_size, - &bytes_read, - callback); - if (read_status != storage::BlobReader::Status::IO_PENDING) - callback.Run(bytes_read); -} - -void GetBlobDataInIO( - const std::string& identifier, - Session::BlobIdType type, - content::ChromeBlobStorageContext* blob_context, - storage::FileSystemContext* file_system_context, - const Session::BlobDataCallback& completion_callback) { - std::unique_ptr blob_data_handle; - if (type == Session::BlobIdType::PUBLIC_URL) { - blob_data_handle = - blob_context->context()->GetBlobDataFromPublicURL(GURL(identifier)); - } else if (type == Session::BlobIdType::UUID) { - blob_data_handle = - blob_context->context()->GetBlobDataFromUUID(identifier); - } - - if (!blob_data_handle) { - std::unique_ptr dummy(new base::BinaryValue()); - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - base::Bind(&RunBlobDataCallback, - completion_callback, - base::Passed(&dummy))); - return; - } - - auto blob_reader = blob_data_handle->CreateReader( - file_system_context, - BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE).get()); - std::shared_ptr - shared_blob_reader(blob_reader.release()); - auto callback = base::Bind(&DidCalculateBlobSize, - shared_blob_reader, - completion_callback); - storage::BlobReader::Status size_status = - shared_blob_reader->CalculateSize(callback); - if (size_status != storage::BlobReader::Status::IO_PENDING) - callback.Run(net::OK); -} - } // namespace Session::Session(v8::Isolate* isolate, AtomBrowserContext* browser_context) @@ -594,35 +504,18 @@ std::string Session::GetUserAgent() { return browser_context_->GetUserAgent(); } -void Session::GetBlobData(mate::Arguments* args) { - std::string identifier; - BlobDataCallback callback; - BlobIdType type = BlobIdType::UUID; - if (!args->GetNext(&identifier)) { - args->ThrowError("Must pass uuid or public url"); +void Session::GetBlobData( + const std::string& uuid, + const AtomBlobReader::CompletionCallback& callback) { + if (callback.is_null()) return; - } - GURL public_url(identifier); - if (public_url.is_valid()) - type = BlobIdType::PUBLIC_URL; - - if (!args->GetNext(&callback)) { - args->ThrowError("Must pass Function"); - return; - } - - content::ChromeBlobStorageContext* blob_context = - content::ChromeBlobStorageContext::GetFor(browser_context()); - storage::FileSystemContext* file_system_context = - content::BrowserContext::GetStoragePartition( - browser_context(), nullptr)->GetFileSystemContext(); + AtomBlobReader* blob_reader = + browser_context()->GetBlobReader(); BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, - base::Bind(&GetBlobDataInIO, - identifier, - type, - blob_context, - file_system_context, + base::Bind(&AtomBlobReader::StartReading, + base::Unretained(blob_reader), + uuid, callback)); } diff --git a/atom/browser/api/atom_api_session.h b/atom/browser/api/atom_api_session.h index d32d1ed53d56..8fbdb75fd6ff 100644 --- a/atom/browser/api/atom_api_session.h +++ b/atom/browser/api/atom_api_session.h @@ -8,6 +8,7 @@ #include #include "atom/browser/api/trackable_object.h" +#include "atom/browser/atom_blob_reader.h" #include "base/values.h" #include "content/public/browser/download_manager.h" #include "native_mate/handle.h" @@ -38,18 +39,12 @@ class Session: public mate::TrackableObject, public content::DownloadManager::Observer { public: using ResolveProxyCallback = base::Callback; - using BlobDataCallback = base::Callback; enum class CacheAction { CLEAR, STATS, }; - enum class BlobIdType { - PUBLIC_URL, - UUID, - }; - // Gets or creates Session from the |browser_context|. static mate::Handle CreateFrom( v8::Isolate* isolate, AtomBrowserContext* browser_context); @@ -82,7 +77,8 @@ class Session: public mate::TrackableObject, void AllowNTLMCredentialsForDomains(const std::string& domains); void SetUserAgent(const std::string& user_agent, mate::Arguments* args); std::string GetUserAgent(); - void GetBlobData(mate::Arguments* args); + void GetBlobData(const std::string& uuid, + const AtomBlobReader::CompletionCallback& callback); v8::Local Cookies(v8::Isolate* isolate); v8::Local Protocol(v8::Isolate* isolate); v8::Local WebRequest(v8::Isolate* isolate); diff --git a/atom/browser/atom_blob_reader.cc b/atom/browser/atom_blob_reader.cc new file mode 100644 index 000000000000..360024a0743f --- /dev/null +++ b/atom/browser/atom_blob_reader.cc @@ -0,0 +1,133 @@ +// Copyright (c) 2016 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/atom_blob_reader.h" + +#include "content/browser/blob_storage/chrome_blob_storage_context.h" +#include "content/public/browser/browser_thread.h" +#include "net/base/io_buffer.h" +#include "net/base/net_errors.h" +#include "storage/browser/blob/blob_data_handle.h" +#include "storage/browser/blob/blob_reader.h" +#include "storage/browser/blob/blob_storage_context.h" +#include "storage/browser/fileapi/file_system_context.h" + +#include "atom/common/node_includes.h" + +using content::BrowserThread; + +namespace atom { + +namespace { + +void RunCallbackInUI( + const AtomBlobReader::CompletionCallback& callback, + char* blob_data, + int size) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::Locker locker(isolate); + v8::HandleScope handle_scope(isolate); + if (blob_data) { + v8::Local buffer = node::Buffer::New(isolate, + blob_data, static_cast(size)).ToLocalChecked(); + callback.Run(buffer); + } else { + callback.Run(v8::Null(isolate)); + } +} + +} // namespace + +AtomBlobReader::AtomBlobReader( + content::ChromeBlobStorageContext* blob_context, + storage::FileSystemContext* file_system_context) + : blob_context_(blob_context), + file_system_context_(file_system_context) { +} + +AtomBlobReader::~AtomBlobReader() { +} + +void AtomBlobReader::StartReading( + const std::string& uuid, + const AtomBlobReader::CompletionCallback& completion_callback) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + auto blob_data_handle = + blob_context_->context()->GetBlobDataFromUUID(uuid); + auto callback = base::Bind(&RunCallbackInUI, + completion_callback); + if (!blob_data_handle) { + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + base::Bind(callback, nullptr, 0)); + return; + } + + auto blob_reader = blob_data_handle->CreateReader( + file_system_context_.get(), + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE).get()); + BlobReadHelper* blob_read_helper = + new BlobReadHelper(std::move(blob_reader), callback); + blob_read_helper->Read(); +} + +AtomBlobReader::BlobReadHelper::BlobReadHelper( + std::unique_ptr blob_reader, + const BlobReadHelper::CompletionCallback& callback) + : blob_reader_(std::move(blob_reader)), + completion_callback_(callback) { +} + +AtomBlobReader::BlobReadHelper::~BlobReadHelper() { +} + +void AtomBlobReader::BlobReadHelper::Read() { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + storage::BlobReader::Status size_status = blob_reader_->CalculateSize( + base::Bind(&AtomBlobReader::BlobReadHelper::DidCalculateSize, + base::Unretained(this))); + if (size_status != storage::BlobReader::Status::IO_PENDING) + DidCalculateSize(net::OK); +} + +void AtomBlobReader::BlobReadHelper::DidCalculateSize(int result) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + if (result != net::OK) { + DidReadBlobData(nullptr, 0); + return; + } + + uint64_t total_size = blob_reader_->total_size(); + int bytes_read = 0; + scoped_refptr blob_data = + new net::IOBuffer(static_cast(total_size)); + auto callback = base::Bind(&AtomBlobReader::BlobReadHelper::DidReadBlobData, + base::Unretained(this), + base::RetainedRef(blob_data)); + storage::BlobReader::Status read_status = blob_reader_->Read( + blob_data.get(), + total_size, + &bytes_read, + callback); + if (read_status != storage::BlobReader::Status::IO_PENDING) + callback.Run(bytes_read); +} + +void AtomBlobReader::BlobReadHelper::DidReadBlobData( + const scoped_refptr& blob_data, + int size) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + char* data = new char[size]; + memcpy(data, blob_data->data(), size); + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + base::Bind(completion_callback_, data, size)); + delete this; +} + +} // namespace atom diff --git a/atom/browser/atom_blob_reader.h b/atom/browser/atom_blob_reader.h new file mode 100644 index 000000000000..41d9cf9194df --- /dev/null +++ b/atom/browser/atom_blob_reader.h @@ -0,0 +1,80 @@ +// Copyright (c) 2016 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_ATOM_BLOB_READER_H_ +#define ATOM_BROWSER_ATOM_BLOB_READER_H_ + +#include + +#include "base/callback.h" + +namespace content { +class ChromeBlobStorageContext; +} + +namespace net { +class IOBuffer; +} + +namespace storage { +class BlobDataHandle; +class BlobReader; +class FileSystemContext; +} + +namespace v8 { +template +class Local; +class Value; +} + +namespace atom { + +// A class to keep track of the blob context. All methods, +// except Ctor are expected to be called on IO thread. +class AtomBlobReader { + public: + using CompletionCallback = base::Callback)>; + + AtomBlobReader(content::ChromeBlobStorageContext* blob_context, + storage::FileSystemContext* file_system_context); + ~AtomBlobReader(); + + void StartReading( + const std::string& uuid, + const AtomBlobReader::CompletionCallback& callback); + + private: + // A self-destroyed helper class to read the blob data. + // Must be accessed on IO thread. + class BlobReadHelper { + public: + using CompletionCallback = base::Callback; + + BlobReadHelper(std::unique_ptr blob_reader, + const BlobReadHelper::CompletionCallback& callback); + ~BlobReadHelper(); + + void Read(); + + private: + void DidCalculateSize(int result); + void DidReadBlobData(const scoped_refptr& blob_data, + int bytes_read); + + std::unique_ptr blob_reader_; + BlobReadHelper::CompletionCallback completion_callback_; + + DISALLOW_COPY_AND_ASSIGN(BlobReadHelper); + }; + + scoped_refptr blob_context_; + scoped_refptr file_system_context_; + + DISALLOW_COPY_AND_ASSIGN(AtomBlobReader); +}; + +} // namespace atom + +#endif // ATOM_BROWSER_ATOM_BLOB_READER_H_ diff --git a/atom/browser/atom_browser_context.cc b/atom/browser/atom_browser_context.cc index c3945e48adce..0b8146995d08 100644 --- a/atom/browser/atom_browser_context.cc +++ b/atom/browser/atom_browser_context.cc @@ -5,6 +5,7 @@ #include "atom/browser/atom_browser_context.h" #include "atom/browser/api/atom_api_protocol.h" +#include "atom/browser/atom_blob_reader.h" #include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/atom_download_manager_delegate.h" #include "atom/browser/atom_permission_manager.h" @@ -30,7 +31,9 @@ #include "chrome/common/chrome_paths.h" #include "chrome/common/pref_names.h" #include "components/prefs/pref_registry_simple.h" +#include "content/browser/blob_storage/chrome_blob_storage_context.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/storage_partition.h" #include "content/public/common/url_constants.h" #include "content/public/common/user_agent.h" #include "net/ftp/ftp_network_layer.h" @@ -207,6 +210,19 @@ void AtomBrowserContext::RegisterPrefs(PrefRegistrySimple* pref_registry) { pref_registry->RegisterDictionaryPref(prefs::kDevToolsFileSystemPaths); } +AtomBlobReader* AtomBrowserContext::GetBlobReader() { + if (!blob_reader_.get()) { + content::ChromeBlobStorageContext* blob_context = + content::ChromeBlobStorageContext::GetFor(this); + storage::FileSystemContext* file_system_context = + content::BrowserContext::GetStoragePartition( + this, nullptr)->GetFileSystemContext(); + blob_reader_.reset(new AtomBlobReader(blob_context, + file_system_context)); + } + return blob_reader_.get(); +} + // static scoped_refptr AtomBrowserContext::From( const std::string& partition, bool in_memory, diff --git a/atom/browser/atom_browser_context.h b/atom/browser/atom_browser_context.h index fa3186396ca0..23d8c64b62c9 100644 --- a/atom/browser/atom_browser_context.h +++ b/atom/browser/atom_browser_context.h @@ -12,6 +12,7 @@ namespace atom { +class AtomBlobReader; class AtomDownloadManagerDelegate; class AtomNetworkDelegate; class AtomPermissionManager; @@ -47,6 +48,7 @@ class AtomBrowserContext : public brightray::BrowserContext { // brightray::BrowserContext: void RegisterPrefs(PrefRegistrySimple* pref_registry) override; + AtomBlobReader* GetBlobReader(); AtomNetworkDelegate* network_delegate() const { return network_delegate_; } protected: @@ -58,6 +60,7 @@ class AtomBrowserContext : public brightray::BrowserContext { std::unique_ptr download_manager_delegate_; std::unique_ptr guest_manager_; std::unique_ptr permission_manager_; + std::unique_ptr blob_reader_; std::string user_agent_; bool use_cache_; diff --git a/atom/common/native_mate_converters/value_converter.cc b/atom/common/native_mate_converters/value_converter.cc index 56e550efc13b..c3c7ae0383c5 100644 --- a/atom/common/native_mate_converters/value_converter.cc +++ b/atom/common/native_mate_converters/value_converter.cc @@ -51,11 +51,4 @@ v8::Local Converter::ToV8( return converter->ToV8Value(&val, isolate->GetCurrentContext()); } -v8::Local Converter::ToV8( - v8::Isolate* isolate, - const base::BinaryValue& val) { - std::unique_ptr converter(new atom::V8ValueConverter); - return converter->ToV8Value(&val, isolate->GetCurrentContext()); -} - } // namespace mate diff --git a/atom/common/native_mate_converters/value_converter.h b/atom/common/native_mate_converters/value_converter.h index 723ea6b74ef1..013dd99cc798 100644 --- a/atom/common/native_mate_converters/value_converter.h +++ b/atom/common/native_mate_converters/value_converter.h @@ -8,7 +8,6 @@ #include "native_mate/converter.h" namespace base { -class BinaryValue; class DictionaryValue; class ListValue; } @@ -33,12 +32,6 @@ struct Converter { const base::ListValue& val); }; -template<> -struct Converter { - static v8::Local ToV8(v8::Isolate* isolate, - const base::BinaryValue& val); -}; - } // namespace mate #endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_VALUE_CONVERTER_H_ diff --git a/docs/api/protocol.md b/docs/api/protocol.md index 0f79f0afc44b..5864cf173fbe 100644 --- a/docs/api/protocol.md +++ b/docs/api/protocol.md @@ -93,7 +93,8 @@ The `uploadData` is an array of `data` objects: * `data` Object * `bytes` Buffer - Content being sent. * `file` String - Path of file being uploaded. - * `blobUUID` String - UUID of blob data. + * `blobUUID` String - UUID of blob data. Use [ses.getBlobData](session.md#sesgetblobdataidentifier-callback) method + to retrieve the data. To handle the `request`, the `callback` should be called with either the file's path or an object that has a `path` property, e.g. `callback(filePath)` or diff --git a/docs/api/session.md b/docs/api/session.md index a691cb4a080f..22b07afa497f 100644 --- a/docs/api/session.md +++ b/docs/api/session.md @@ -328,7 +328,7 @@ Returns a `String` representing the user agent for this session. #### `ses.getBlobData(identifier, callback)` -* `identifier` String - Valid UUID or public blob URL. +* `identifier` String - Valid UUID. * `callback` Function * `result` Buffer - Blob data. @@ -521,7 +521,8 @@ The `uploadData` is an array of `data` objects: * `data` Object * `bytes` Buffer - Content being sent. * `file` String - Path of file being uploaded. - * `blobUUID` String - UUID of blob data. + * `blobUUID` String - UUID of blob data. Use [ses.getBlobData](session.md#sesgetblobdataidentifier-callback) method + to retrieve the data. The `callback` has to be called with an `response` object: diff --git a/filenames.gypi b/filenames.gypi index 7335ae9acc07..d3c71cc918a1 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -152,6 +152,8 @@ 'atom/browser/auto_updater_mac.mm', 'atom/browser/atom_access_token_store.cc', 'atom/browser/atom_access_token_store.h', + 'atom/browser/atom_blob_reader.cc', + 'atom/browser/atom_blob_reader.h', 'atom/browser/atom_browser_client.cc', 'atom/browser/atom_browser_client.h', 'atom/browser/atom_browser_context.cc', diff --git a/spec/api-session-spec.js b/spec/api-session-spec.js index 91f97775dc1b..2eb696ea7e8c 100644 --- a/spec/api-session-spec.js +++ b/spec/api-session-spec.js @@ -404,19 +404,6 @@ describe('session module', function () { }) describe('ses.getblobData(identifier, callback)', function () { - it('returns blob data for public url', function (done) { - let data = JSON.stringify({ - type: 'blob', - value: 'hello' - }) - let blob = new Blob([data], {type: 'application/json'}) - let blobURL = URL.createObjectURL(blob) - session.defaultSession.getBlobData(blobURL, function (result) { - assert.equal(result.toString(), data) - done() - }) - }) - it('returns blob data for uuid', function (done) { const scheme = 'temp' const protocol = session.defaultSession.protocol