Browse Source

create helper class to read blob data

deepak1556 8 years ago
parent
commit
7b85ca0301

+ 9 - 116
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<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));
 }
 

+ 3 - 7
atom/browser/api/atom_api_session.h

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

+ 133 - 0
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<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

+ 80 - 0
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 <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_

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

+ 3 - 0
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<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_;
 

+ 0 - 7
atom/common/native_mate_converters/value_converter.cc

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

+ 0 - 7
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<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_

+ 2 - 1
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

+ 3 - 2
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:
 

+ 2 - 0
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',

+ 0 - 13
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