create helper class to read blob data

This commit is contained in:
deepak1556 2016-08-31 05:38:32 +05:30
parent 5cbc8d5c71
commit 7b85ca0301
12 changed files with 251 additions and 153 deletions

View file

@ -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<void(T...)>& callback, T... result) {
BrowserThread::UI, FROM_HERE, base::Bind(callback, result...));
}
void RunBlobDataCallback(
const Session::BlobDataCallback& completion_callback,
std::unique_ptr<base::BinaryValue> 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<net::IOBuffer>& blob_data,
const Session::BlobDataCallback& completion_callback,
int bytes_read) {
std::unique_ptr<base::BinaryValue> 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<storage::BlobReader> blob_reader,
const Session::BlobDataCallback& completion_callback,
int result) {
if (result != net::OK) {
std::unique_ptr<base::BinaryValue> 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<net::IOBuffer> blob_data =
new net::IOBuffer(static_cast<size_t>(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<storage::BlobDataHandle> 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<base::BinaryValue> 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<storage::BlobReader>
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));
}

View file

@ -8,6 +8,7 @@
#include <string>
#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<Session>,
public content::DownloadManager::Observer {
public:
using ResolveProxyCallback = base::Callback<void(std::string)>;
using BlobDataCallback = base::Callback<void(const base::BinaryValue&)>;
enum class CacheAction {
CLEAR,
STATS,
};
enum class BlobIdType {
PUBLIC_URL,
UUID,
};
// Gets or creates Session from the |browser_context|.
static mate::Handle<Session> CreateFrom(
v8::Isolate* isolate, AtomBrowserContext* browser_context);
@ -82,7 +77,8 @@ class Session: public mate::TrackableObject<Session>,
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<v8::Value> Cookies(v8::Isolate* isolate);
v8::Local<v8::Value> Protocol(v8::Isolate* isolate);
v8::Local<v8::Value> WebRequest(v8::Isolate* isolate);

View file

@ -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<v8::Value> buffer = node::Buffer::New(isolate,
blob_data, static_cast<size_t>(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<storage::BlobReader> 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<net::IOBuffer> blob_data =
new net::IOBuffer(static_cast<size_t>(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<net::IOBuffer>& 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

View file

@ -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 <string>
#include "base/callback.h"
namespace content {
class ChromeBlobStorageContext;
}
namespace net {
class IOBuffer;
}
namespace storage {
class BlobDataHandle;
class BlobReader;
class FileSystemContext;
}
namespace v8 {
template <class T>
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<void(v8::Local<v8::Value>)>;
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<void(char*, int)>;
BlobReadHelper(std::unique_ptr<storage::BlobReader> blob_reader,
const BlobReadHelper::CompletionCallback& callback);
~BlobReadHelper();
void Read();
private:
void DidCalculateSize(int result);
void DidReadBlobData(const scoped_refptr<net::IOBuffer>& blob_data,
int bytes_read);
std::unique_ptr<storage::BlobReader> blob_reader_;
BlobReadHelper::CompletionCallback completion_callback_;
DISALLOW_COPY_AND_ASSIGN(BlobReadHelper);
};
scoped_refptr<content::ChromeBlobStorageContext> blob_context_;
scoped_refptr<storage::FileSystemContext> file_system_context_;
DISALLOW_COPY_AND_ASSIGN(AtomBlobReader);
};
} // namespace atom
#endif // ATOM_BROWSER_ATOM_BLOB_READER_H_

View file

@ -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> AtomBrowserContext::From(
const std::string& partition, bool in_memory,

View file

@ -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<AtomDownloadManagerDelegate> download_manager_delegate_;
std::unique_ptr<WebViewManager> guest_manager_;
std::unique_ptr<AtomPermissionManager> permission_manager_;
std::unique_ptr<AtomBlobReader> blob_reader_;
std::string user_agent_;
bool use_cache_;

View file

@ -51,11 +51,4 @@ v8::Local<v8::Value> Converter<base::ListValue>::ToV8(
return converter->ToV8Value(&val, isolate->GetCurrentContext());
}
v8::Local<v8::Value> Converter<base::BinaryValue>::ToV8(
v8::Isolate* isolate,
const base::BinaryValue& val) {
std::unique_ptr<atom::V8ValueConverter> converter(new atom::V8ValueConverter);
return converter->ToV8Value(&val, isolate->GetCurrentContext());
}
} // namespace mate

View file

@ -8,7 +8,6 @@
#include "native_mate/converter.h"
namespace base {
class BinaryValue;
class DictionaryValue;
class ListValue;
}
@ -33,12 +32,6 @@ struct Converter<base::ListValue> {
const base::ListValue& val);
};
template<>
struct Converter<base::BinaryValue> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
const base::BinaryValue& val);
};
} // namespace mate
#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_VALUE_CONVERTER_H_

View file

@ -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

View file

@ -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:

View file

@ -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',

View file

@ -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