summaryrefslogtreecommitdiffstats
path: root/content/child
diff options
context:
space:
mode:
Diffstat (limited to 'content/child')
-rw-r--r--content/child/fileapi/OWNERS14
-rw-r--r--content/child/fileapi/webfilesystem_callback_adapters.cc77
-rw-r--r--content/child/fileapi/webfilesystem_callback_adapters.h48
-rw-r--r--content/child/fileapi/webfilesystem_impl.cc144
-rw-r--r--content/child/fileapi/webfilesystem_impl.h69
-rw-r--r--content/child/fileapi/webfilewriter_impl.cc51
-rw-r--r--content/child/fileapi/webfilewriter_impl.h35
-rw-r--r--content/child/indexed_db/OWNERS15
-rw-r--r--content/child/indexed_db/indexed_db_dispatcher.cc713
-rw-r--r--content/child/indexed_db/indexed_db_dispatcher.h241
-rw-r--r--content/child/indexed_db/indexed_db_dispatcher_unittest.cc62
-rw-r--r--content/child/indexed_db/indexed_db_message_filter.cc79
-rw-r--r--content/child/indexed_db/indexed_db_message_filter.h47
-rw-r--r--content/child/indexed_db/proxy_webidbcursor_impl.cc157
-rw-r--r--content/child/indexed_db/proxy_webidbcursor_impl.h71
-rw-r--r--content/child/indexed_db/proxy_webidbcursor_impl_unittest.cc151
-rw-r--r--content/child/indexed_db/proxy_webidbdatabase_impl.cc264
-rw-r--r--content/child/indexed_db/proxy_webidbdatabase_impl.h103
-rw-r--r--content/child/indexed_db/proxy_webidbfactory_impl.cc64
-rw-r--r--content/child/indexed_db/proxy_webidbfactory_impl.h46
-rw-r--r--content/child/np_channel_base.cc305
-rw-r--r--content/child/np_channel_base.h203
-rw-r--r--content/child/npobject_base.h31
-rw-r--r--content/child/npobject_proxy.cc507
-rw-r--r--content/child/npobject_proxy.h127
-rw-r--r--content/child/npobject_stub.cc424
-rw-r--r--content/child/npobject_stub.h99
-rw-r--r--content/child/npobject_util.cc292
-rw-r--r--content/child/npobject_util.h74
-rw-r--r--content/child/plugin_message_generator.cc33
-rw-r--r--content/child/plugin_message_generator.h7
-rw-r--r--content/child/plugin_messages.h380
-rw-r--r--content/child/plugin_param_traits.cc133
-rw-r--r--content/child/plugin_param_traits.h83
-rw-r--r--content/child/web_database_observer_impl.cc169
-rw-r--r--content/child/web_database_observer_impl.h53
-rw-r--r--content/child/webblobregistry_impl.cc127
-rw-r--r--content/child/webblobregistry_impl.h36
38 files changed, 5534 insertions, 0 deletions
diff --git a/content/child/fileapi/OWNERS b/content/child/fileapi/OWNERS
new file mode 100644
index 0000000..9e9046e
--- /dev/null
+++ b/content/child/fileapi/OWNERS
@@ -0,0 +1,14 @@
+ericu@chromium.org
+kinuko@chromium.org
+michaeln@chromium.org
+jianli@chromium.org
+
+# For security review of IPC message files.
+per-file *_messages.h=set noparent
+per-file *_messages.h=cdn@chromium.org
+per-file *_messages.h=cevans@chromium.org
+per-file *_messages.h=inferno@chromium.org
+per-file *_messages.h=jschuh@chromium.org
+per-file *_messages.h=palmer@chromium.org
+per-file *_messages.h=tsepez@chromium.org
+per-file *_messages.h=kenrb@chromium.org
diff --git a/content/child/fileapi/webfilesystem_callback_adapters.cc b/content/child/fileapi/webfilesystem_callback_adapters.cc
new file mode 100644
index 0000000..3935522
--- /dev/null
+++ b/content/child/fileapi/webfilesystem_callback_adapters.cc
@@ -0,0 +1,77 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/fileapi/webfilesystem_callback_adapters.h"
+
+#include <string>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/utf_string_conversions.h"
+#include "googleurl/src/gurl.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebFileSystemCallbacks.h"
+#include "third_party/WebKit/public/platform/WebFileInfo.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "webkit/base/file_path_string_conversions.h"
+#include "webkit/common/fileapi/directory_entry.h"
+#include "webkit/common/fileapi/file_system_util.h"
+#include "webkit/glue/webkit_glue.h"
+
+using WebKit::WebFileInfo;
+using WebKit::WebFileSystemCallbacks;
+using WebKit::WebFileSystemEntry;
+using WebKit::WebString;
+using WebKit::WebVector;
+
+namespace content {
+
+void FileStatusCallbackAdapter(
+ WebKit::WebFileSystemCallbacks* callbacks,
+ base::PlatformFileError error) {
+ if (error == base::PLATFORM_FILE_OK)
+ callbacks->didSucceed();
+ else
+ callbacks->didFail(::fileapi::PlatformFileErrorToWebFileError(error));
+}
+
+void ReadMetadataCallbackAdapter(
+ WebKit::WebFileSystemCallbacks* callbacks,
+ const base::PlatformFileInfo& file_info,
+ const base::FilePath& platform_path) {
+ WebFileInfo web_file_info;
+ webkit_glue::PlatformFileInfoToWebFileInfo(file_info, &web_file_info);
+ web_file_info.platformPath = webkit_base::FilePathToWebString(platform_path);
+ callbacks->didReadMetadata(web_file_info);
+}
+
+void CreateSnapshotFileCallbackAdapter(
+ WebKit::WebFileSystemCallbacks* callbacks,
+ const base::PlatformFileInfo& file_info,
+ const base::FilePath& platform_path) {
+ WebFileInfo web_file_info;
+ webkit_glue::PlatformFileInfoToWebFileInfo(file_info, &web_file_info);
+ web_file_info.platformPath = webkit_base::FilePathToWebString(platform_path);
+ callbacks->didCreateSnapshotFile(web_file_info);
+}
+
+void ReadDirectoryCallbackAdapater(
+ WebKit::WebFileSystemCallbacks* callbacks,
+ const std::vector<fileapi::DirectoryEntry>& entries,
+ bool has_more) {
+ WebVector<WebFileSystemEntry> file_system_entries(entries.size());
+ for (size_t i = 0; i < entries.size(); i++) {
+ file_system_entries[i].name =
+ webkit_base::FilePathStringToWebString(entries[i].name);
+ file_system_entries[i].isDirectory = entries[i].is_directory;
+ }
+ callbacks->didReadDirectory(file_system_entries, has_more);
+}
+
+void OpenFileSystemCallbackAdapter(
+ WebKit::WebFileSystemCallbacks* callbacks,
+ const std::string& name, const GURL& root) {
+ callbacks->didOpenFileSystem(UTF8ToUTF16(name), root);
+}
+
+} // namespace content
diff --git a/content/child/fileapi/webfilesystem_callback_adapters.h b/content/child/fileapi/webfilesystem_callback_adapters.h
new file mode 100644
index 0000000..408d71d
--- /dev/null
+++ b/content/child/fileapi/webfilesystem_callback_adapters.h
@@ -0,0 +1,48 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_CHILD_FILEAPI_WEBFILESYSTEM_CALLBACK_ADAPTERS_H_
+#define CONTENT_CHILD_FILEAPI_WEBFILESYSTEM_CALLBACK_ADAPTERS_H_
+
+#include "base/basictypes.h"
+#include "base/platform_file.h"
+
+class GURL;
+
+namespace fileapi {
+struct DirectoryEntry;
+}
+
+namespace WebKit {
+class WebFileSystemCallbacks;
+}
+
+namespace content {
+
+void FileStatusCallbackAdapter(
+ WebKit::WebFileSystemCallbacks* callbacks,
+ base::PlatformFileError error);
+
+void ReadMetadataCallbackAdapter(
+ WebKit::WebFileSystemCallbacks* callbacks,
+ const base::PlatformFileInfo& file_info,
+ const base::FilePath& platform_path);
+
+void CreateSnapshotFileCallbackAdapter(
+ WebKit::WebFileSystemCallbacks* callbacks,
+ const base::PlatformFileInfo& file_info,
+ const base::FilePath& platform_path);
+
+void ReadDirectoryCallbackAdapater(
+ WebKit::WebFileSystemCallbacks* callbacks,
+ const std::vector<fileapi::DirectoryEntry>& entries,
+ bool has_more);
+
+void OpenFileSystemCallbackAdapter(
+ WebKit::WebFileSystemCallbacks* callbacks,
+ const std::string& name, const GURL& root);
+
+} // namespace content
+
+#endif // CONTENT_CHILD_FILEAPI_WEBFILESYSTEM_CALLBACK_ADAPTERS_H_
diff --git a/content/child/fileapi/webfilesystem_impl.cc b/content/child/fileapi/webfilesystem_impl.cc
new file mode 100644
index 0000000..0e6ed21
--- /dev/null
+++ b/content/child/fileapi/webfilesystem_impl.cc
@@ -0,0 +1,144 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/fileapi/webfilesystem_impl.h"
+
+#include "base/bind.h"
+#include "content/child/fileapi/webfilesystem_callback_adapters.h"
+#include "content/child/fileapi/webfilewriter_impl.h"
+#include "content/common/child_thread.h"
+#include "content/common/fileapi/file_system_dispatcher.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebFileSystemCallbacks.h"
+#include "third_party/WebKit/public/platform/WebFileInfo.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/WebURL.h"
+#include "webkit/glue/webkit_glue.h"
+
+using WebKit::WebFileInfo;
+using WebKit::WebFileSystemCallbacks;
+using WebKit::WebFileSystemEntry;
+using WebKit::WebString;
+using WebKit::WebURL;
+using WebKit::WebVector;
+
+namespace content {
+
+WebFileSystemImpl::WebFileSystemImpl() {
+}
+
+void WebFileSystemImpl::move(const WebURL& src_path,
+ const WebURL& dest_path,
+ WebFileSystemCallbacks* callbacks) {
+ FileSystemDispatcher* dispatcher =
+ ChildThread::current()->file_system_dispatcher();
+ dispatcher->Move(GURL(src_path),
+ GURL(dest_path),
+ base::Bind(&FileStatusCallbackAdapter, callbacks));
+}
+
+void WebFileSystemImpl::copy(const WebURL& src_path,
+ const WebURL& dest_path,
+ WebFileSystemCallbacks* callbacks) {
+ FileSystemDispatcher* dispatcher =
+ ChildThread::current()->file_system_dispatcher();
+ dispatcher->Copy(GURL(src_path),
+ GURL(dest_path),
+ base::Bind(&FileStatusCallbackAdapter, callbacks));
+}
+
+void WebFileSystemImpl::remove(const WebURL& path,
+ WebFileSystemCallbacks* callbacks) {
+ FileSystemDispatcher* dispatcher =
+ ChildThread::current()->file_system_dispatcher();
+ dispatcher->Remove(
+ GURL(path),
+ false /* recursive */,
+ base::Bind(&FileStatusCallbackAdapter, callbacks));
+}
+
+void WebFileSystemImpl::removeRecursively(const WebURL& path,
+ WebFileSystemCallbacks* callbacks) {
+ FileSystemDispatcher* dispatcher =
+ ChildThread::current()->file_system_dispatcher();
+ dispatcher->Remove(
+ GURL(path),
+ true /* recursive */,
+ base::Bind(&FileStatusCallbackAdapter, callbacks));
+}
+
+void WebFileSystemImpl::readMetadata(const WebURL& path,
+ WebFileSystemCallbacks* callbacks) {
+ FileSystemDispatcher* dispatcher =
+ ChildThread::current()->file_system_dispatcher();
+ dispatcher->ReadMetadata(
+ GURL(path),
+ base::Bind(&ReadMetadataCallbackAdapter, callbacks),
+ base::Bind(&FileStatusCallbackAdapter, callbacks));
+}
+
+void WebFileSystemImpl::createFile(const WebURL& path,
+ bool exclusive,
+ WebFileSystemCallbacks* callbacks) {
+ FileSystemDispatcher* dispatcher =
+ ChildThread::current()->file_system_dispatcher();
+ dispatcher->Create(
+ GURL(path), exclusive, false /* directory */, false /* recursive */,
+ base::Bind(&FileStatusCallbackAdapter, callbacks));
+}
+
+void WebFileSystemImpl::createDirectory(const WebURL& path,
+ bool exclusive,
+ WebFileSystemCallbacks* callbacks) {
+ FileSystemDispatcher* dispatcher =
+ ChildThread::current()->file_system_dispatcher();
+ dispatcher->Create(
+ GURL(path), exclusive, true /* directory */, false /* recursive */,
+ base::Bind(&FileStatusCallbackAdapter, callbacks));
+}
+
+void WebFileSystemImpl::fileExists(const WebURL& path,
+ WebFileSystemCallbacks* callbacks) {
+ FileSystemDispatcher* dispatcher =
+ ChildThread::current()->file_system_dispatcher();
+ dispatcher->Exists(
+ GURL(path), false /* directory */,
+ base::Bind(&FileStatusCallbackAdapter, callbacks));
+}
+
+void WebFileSystemImpl::directoryExists(const WebURL& path,
+ WebFileSystemCallbacks* callbacks) {
+ FileSystemDispatcher* dispatcher =
+ ChildThread::current()->file_system_dispatcher();
+ dispatcher->Exists(
+ GURL(path), true /* directory */,
+ base::Bind(&FileStatusCallbackAdapter, callbacks));
+}
+
+void WebFileSystemImpl::readDirectory(const WebURL& path,
+ WebFileSystemCallbacks* callbacks) {
+ FileSystemDispatcher* dispatcher =
+ ChildThread::current()->file_system_dispatcher();
+ dispatcher->ReadDirectory(
+ GURL(path),
+ base::Bind(&ReadDirectoryCallbackAdapater, callbacks),
+ base::Bind(&FileStatusCallbackAdapter, callbacks));
+}
+
+WebKit::WebFileWriter* WebFileSystemImpl::createFileWriter(
+ const WebURL& path, WebKit::WebFileWriterClient* client) {
+ return new WebFileWriterImpl(GURL(path), client);
+}
+
+void WebFileSystemImpl::createSnapshotFileAndReadMetadata(
+ const WebKit::WebURL& path,
+ WebKit::WebFileSystemCallbacks* callbacks) {
+ FileSystemDispatcher* dispatcher =
+ ChildThread::current()->file_system_dispatcher();
+ dispatcher->CreateSnapshotFile(
+ GURL(path),
+ base::Bind(&CreateSnapshotFileCallbackAdapter, callbacks),
+ base::Bind(&FileStatusCallbackAdapter, callbacks));
+}
+
+} // namespace content
diff --git a/content/child/fileapi/webfilesystem_impl.h b/content/child/fileapi/webfilesystem_impl.h
new file mode 100644
index 0000000..2bcf535
--- /dev/null
+++ b/content/child/fileapi/webfilesystem_impl.h
@@ -0,0 +1,69 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_CHILD_FILEAPI_WEBFILESYSTEM_IMPL_H_
+#define CONTENT_CHILD_FILEAPI_WEBFILESYSTEM_IMPL_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "third_party/WebKit/public/platform/WebFileSystem.h"
+
+namespace WebKit {
+class WebURL;
+class WebFileWriter;
+class WebFileWriterClient;
+}
+
+namespace content {
+
+class WebFileSystemImpl : public WebKit::WebFileSystem {
+ public:
+ WebFileSystemImpl();
+ virtual ~WebFileSystemImpl() { }
+
+ // WebFileSystem implementation.
+ virtual void move(
+ const WebKit::WebURL& src_path,
+ const WebKit::WebURL& dest_path,
+ WebKit::WebFileSystemCallbacks*) OVERRIDE;
+ virtual void copy(
+ const WebKit::WebURL& src_path,
+ const WebKit::WebURL& dest_path,
+ WebKit::WebFileSystemCallbacks*) OVERRIDE;
+ virtual void remove(
+ const WebKit::WebURL& path,
+ WebKit::WebFileSystemCallbacks*) OVERRIDE;
+ virtual void removeRecursively(
+ const WebKit::WebURL& path,
+ WebKit::WebFileSystemCallbacks*) OVERRIDE;
+ virtual void readMetadata(
+ const WebKit::WebURL& path,
+ WebKit::WebFileSystemCallbacks*) OVERRIDE;
+ virtual void createFile(
+ const WebKit::WebURL& path,
+ bool exclusive,
+ WebKit::WebFileSystemCallbacks*) OVERRIDE;
+ virtual void createDirectory(
+ const WebKit::WebURL& path,
+ bool exclusive,
+ WebKit::WebFileSystemCallbacks*) OVERRIDE;
+ virtual void fileExists(
+ const WebKit::WebURL& path,
+ WebKit::WebFileSystemCallbacks*) OVERRIDE;
+ virtual void directoryExists(
+ const WebKit::WebURL& path,
+ WebKit::WebFileSystemCallbacks*) OVERRIDE;
+ virtual void readDirectory(
+ const WebKit::WebURL& path,
+ WebKit::WebFileSystemCallbacks*) OVERRIDE;
+ virtual WebKit::WebFileWriter* createFileWriter(
+ const WebKit::WebURL& path, WebKit::WebFileWriterClient*) OVERRIDE;
+ virtual void createSnapshotFileAndReadMetadata(
+ const WebKit::WebURL& path,
+ WebKit::WebFileSystemCallbacks*);
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_FILEAPI_WEBFILESYSTEM_IMPL_H_
diff --git a/content/child/fileapi/webfilewriter_impl.cc b/content/child/fileapi/webfilewriter_impl.cc
new file mode 100644
index 0000000..dc37c99
--- /dev/null
+++ b/content/child/fileapi/webfilewriter_impl.cc
@@ -0,0 +1,51 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/fileapi/webfilewriter_impl.h"
+
+#include "base/bind.h"
+#include "content/common/child_thread.h"
+#include "content/common/fileapi/file_system_dispatcher.h"
+
+namespace content {
+
+namespace {
+
+inline FileSystemDispatcher* GetFileSystemDispatcher() {
+ return ChildThread::current()->file_system_dispatcher();
+}
+
+} // namespace
+
+WebFileWriterImpl::WebFileWriterImpl(
+ const GURL& path, WebKit::WebFileWriterClient* client)
+ : WebFileWriterBase(path, client),
+ request_id_(0) {
+}
+
+WebFileWriterImpl::~WebFileWriterImpl() {
+}
+
+void WebFileWriterImpl::DoTruncate(const GURL& path, int64 offset) {
+ // The FileSystemDispatcher takes ownership of the CallbackDispatcher.
+ GetFileSystemDispatcher()->Truncate(
+ path, offset, &request_id_,
+ base::Bind(&WebFileWriterImpl::DidFinish, AsWeakPtr()));
+}
+
+void WebFileWriterImpl::DoWrite(
+ const GURL& path, const GURL& blob_url, int64 offset) {
+ GetFileSystemDispatcher()->Write(
+ path, blob_url, offset, &request_id_,
+ base::Bind(&WebFileWriterImpl::DidWrite, AsWeakPtr()),
+ base::Bind(&WebFileWriterImpl::DidFinish, AsWeakPtr()));
+}
+
+void WebFileWriterImpl::DoCancel() {
+ GetFileSystemDispatcher()->Cancel(
+ request_id_,
+ base::Bind(&WebFileWriterImpl::DidFinish, AsWeakPtr()));
+}
+
+} // namespace content
diff --git a/content/child/fileapi/webfilewriter_impl.h b/content/child/fileapi/webfilewriter_impl.h
new file mode 100644
index 0000000..718139d
--- /dev/null
+++ b/content/child/fileapi/webfilewriter_impl.h
@@ -0,0 +1,35 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_CHILD_FILEAPI_WEBFILEWRITER_IMPL_H_
+#define CONTENT_CHILD_FILEAPI_WEBFILEWRITER_IMPL_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "webkit/renderer/fileapi/webfilewriter_base.h"
+
+namespace content {
+
+// An implementation of WebFileWriter for use in chrome renderers and workers.
+class WebFileWriterImpl : public fileapi::WebFileWriterBase,
+ public base::SupportsWeakPtr<WebFileWriterImpl> {
+ public:
+ WebFileWriterImpl(const GURL& path, WebKit::WebFileWriterClient* client);
+ virtual ~WebFileWriterImpl();
+
+ protected:
+ // WebFileWriterBase overrides
+ virtual void DoTruncate(const GURL& path, int64 offset) OVERRIDE;
+ virtual void DoWrite(const GURL& path, const GURL& blob_url,
+ int64 offset) OVERRIDE;
+ virtual void DoCancel() OVERRIDE;
+
+ private:
+ class CallbackDispatcher;
+ int request_id_;
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_FILEAPI_WEBFILEWRITER_IMPL_H_
diff --git a/content/child/indexed_db/OWNERS b/content/child/indexed_db/OWNERS
new file mode 100644
index 0000000..ed5258c
--- /dev/null
+++ b/content/child/indexed_db/OWNERS
@@ -0,0 +1,15 @@
+dgrogan@chromium.org
+hans@chromium.org
+michaeln@chromium.org
+jsbell@chromium.org
+alecflett@chromium.org
+
+# For security review of IPC message files.
+per-file *_messages.h=set noparent
+per-file *_messages.h=cdn@chromium.org
+per-file *_messages.h=cevans@chromium.org
+per-file *_messages.h=inferno@chromium.org
+per-file *_messages.h=jschuh@chromium.org
+per-file *_messages.h=palmer@chromium.org
+per-file *_messages.h=tsepez@chromium.org
+per-file *_messages.h=kenrb@chromium.org
diff --git a/content/child/indexed_db/indexed_db_dispatcher.cc b/content/child/indexed_db/indexed_db_dispatcher.cc
new file mode 100644
index 0000000..24c403d
--- /dev/null
+++ b/content/child/indexed_db/indexed_db_dispatcher.cc
@@ -0,0 +1,713 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/indexed_db/indexed_db_dispatcher.h"
+
+#include "base/format_macros.h"
+#include "base/lazy_instance.h"
+#include "base/stringprintf.h"
+#include "base/threading/thread_local.h"
+#include "content/child/indexed_db/proxy_webidbcursor_impl.h"
+#include "content/child/indexed_db/proxy_webidbdatabase_impl.h"
+#include "content/common/child_thread.h"
+#include "content/common/indexed_db/indexed_db_messages.h"
+#include "ipc/ipc_channel.h"
+#include "third_party/WebKit/public/platform/WebIDBDatabaseCallbacks.h"
+#include "third_party/WebKit/public/platform/WebIDBDatabaseError.h"
+#include "third_party/WebKit/public/platform/WebIDBDatabaseException.h"
+#include "third_party/WebKit/public/platform/WebIDBKeyRange.h"
+
+using WebKit::WebData;
+using WebKit::WebIDBCallbacks;
+using WebKit::WebIDBDatabase;
+using WebKit::WebIDBDatabaseCallbacks;
+using WebKit::WebIDBDatabaseError;
+using WebKit::WebIDBKey;
+using WebKit::WebIDBKeyRange;
+using WebKit::WebIDBMetadata;
+using WebKit::WebString;
+using WebKit::WebVector;
+using base::ThreadLocalPointer;
+using webkit_glue::WorkerTaskRunner;
+
+namespace content {
+static base::LazyInstance<ThreadLocalPointer<IndexedDBDispatcher> >::Leaky
+ g_idb_dispatcher_tls = LAZY_INSTANCE_INITIALIZER;
+
+namespace {
+
+IndexedDBDispatcher* const kHasBeenDeleted =
+ reinterpret_cast<IndexedDBDispatcher*>(0x1);
+
+int32 CurrentWorkerId() {
+ return WorkerTaskRunner::Instance()->CurrentWorkerId();
+}
+} // unnamed namespace
+
+const size_t kMaxIDBValueSizeInBytes = 64 * 1024 * 1024;
+
+IndexedDBDispatcher::IndexedDBDispatcher() {
+ g_idb_dispatcher_tls.Pointer()->Set(this);
+}
+
+IndexedDBDispatcher::~IndexedDBDispatcher() {
+ // Clear any pending callbacks - which may result in dispatch requests -
+ // before marking the dispatcher as deleted.
+ pending_callbacks_.Clear();
+ pending_database_callbacks_.Clear();
+
+ DCHECK(pending_callbacks_.IsEmpty());
+ DCHECK(pending_database_callbacks_.IsEmpty());
+
+ g_idb_dispatcher_tls.Pointer()->Set(kHasBeenDeleted);
+}
+
+IndexedDBDispatcher* IndexedDBDispatcher::ThreadSpecificInstance() {
+ if (g_idb_dispatcher_tls.Pointer()->Get() == kHasBeenDeleted) {
+ NOTREACHED() << "Re-instantiating TLS IndexedDBDispatcher.";
+ g_idb_dispatcher_tls.Pointer()->Set(NULL);
+ }
+ if (g_idb_dispatcher_tls.Pointer()->Get())
+ return g_idb_dispatcher_tls.Pointer()->Get();
+
+ IndexedDBDispatcher* dispatcher = new IndexedDBDispatcher;
+ if (WorkerTaskRunner::Instance()->CurrentWorkerId())
+ webkit_glue::WorkerTaskRunner::Instance()->AddStopObserver(dispatcher);
+ return dispatcher;
+}
+
+void IndexedDBDispatcher::OnWorkerRunLoopStopped() { delete this; }
+
+WebIDBMetadata IndexedDBDispatcher::ConvertMetadata(
+ const IndexedDBDatabaseMetadata& idb_metadata) {
+ WebIDBMetadata web_metadata;
+ web_metadata.id = idb_metadata.id;
+ web_metadata.name = idb_metadata.name;
+ web_metadata.version = idb_metadata.version;
+ web_metadata.intVersion = idb_metadata.int_version;
+ web_metadata.maxObjectStoreId = idb_metadata.max_object_store_id;
+ web_metadata.objectStores =
+ WebVector<WebIDBMetadata::ObjectStore>(idb_metadata.object_stores.size());
+
+ for (size_t i = 0; i < idb_metadata.object_stores.size(); ++i) {
+ const IndexedDBObjectStoreMetadata& idb_store_metadata =
+ idb_metadata.object_stores[i];
+ WebIDBMetadata::ObjectStore& web_store_metadata =
+ web_metadata.objectStores[i];
+
+ web_store_metadata.id = idb_store_metadata.id;
+ web_store_metadata.name = idb_store_metadata.name;
+ web_store_metadata.keyPath = idb_store_metadata.keyPath;
+ web_store_metadata.autoIncrement = idb_store_metadata.autoIncrement;
+ web_store_metadata.maxIndexId = idb_store_metadata.max_index_id;
+ web_store_metadata.indexes =
+ WebVector<WebIDBMetadata::Index>(idb_store_metadata.indexes.size());
+
+ for (size_t j = 0; j < idb_store_metadata.indexes.size(); ++j) {
+ const IndexedDBIndexMetadata& idb_index_metadata =
+ idb_store_metadata.indexes[j];
+ WebIDBMetadata::Index& web_index_metadata = web_store_metadata.indexes[j];
+
+ web_index_metadata.id = idb_index_metadata.id;
+ web_index_metadata.name = idb_index_metadata.name;
+ web_index_metadata.keyPath = idb_index_metadata.keyPath;
+ web_index_metadata.unique = idb_index_metadata.unique;
+ web_index_metadata.multiEntry = idb_index_metadata.multiEntry;
+ }
+ }
+
+ return web_metadata;
+}
+
+void IndexedDBDispatcher::OnMessageReceived(const IPC::Message& msg) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(IndexedDBDispatcher, msg)
+ IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessIDBCursor,
+ OnSuccessOpenCursor)
+ IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessCursorAdvance,
+ OnSuccessCursorContinue)
+ IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessCursorContinue,
+ OnSuccessCursorContinue)
+ IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessCursorPrefetch,
+ OnSuccessCursorPrefetch)
+ IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessIDBDatabase,
+ OnSuccessIDBDatabase)
+ IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessIndexedDBKey,
+ OnSuccessIndexedDBKey)
+ IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessStringList,
+ OnSuccessStringList)
+ IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessValue, OnSuccessValue)
+ IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessValueWithKey,
+ OnSuccessValueWithKey)
+ IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessInteger, OnSuccessInteger)
+ IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessUndefined,
+ OnSuccessUndefined)
+ IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksError, OnError)
+ IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksIntBlocked, OnIntBlocked)
+ IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksUpgradeNeeded, OnUpgradeNeeded)
+ IPC_MESSAGE_HANDLER(IndexedDBMsg_DatabaseCallbacksForcedClose,
+ OnForcedClose)
+ IPC_MESSAGE_HANDLER(IndexedDBMsg_DatabaseCallbacksIntVersionChange,
+ OnIntVersionChange)
+ IPC_MESSAGE_HANDLER(IndexedDBMsg_DatabaseCallbacksAbort, OnAbort)
+ IPC_MESSAGE_HANDLER(IndexedDBMsg_DatabaseCallbacksComplete, OnComplete)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ // If a message gets here, IndexedDBMessageFilter already determined that it
+ // is an IndexedDB message.
+ DCHECK(handled) << "Didn't handle a message defined at line "
+ << IPC_MESSAGE_ID_LINE(msg.type());
+}
+
+bool IndexedDBDispatcher::Send(IPC::Message* msg) {
+ if (!ChildThread::current()) {
+ // Unexpected - this may be happening during shutdown.
+ NOTREACHED();
+ return false;
+ }
+ if (CurrentWorkerId()) {
+ scoped_refptr<IPC::SyncMessageFilter> filter(
+ ChildThread::current()->sync_message_filter());
+ return filter->Send(msg);
+ }
+ return ChildThread::current()->Send(msg);
+}
+
+void IndexedDBDispatcher::RequestIDBCursorAdvance(
+ unsigned long count,
+ WebIDBCallbacks* callbacks_ptr,
+ int32 ipc_cursor_id) {
+ // Reset all cursor prefetch caches except for this cursor.
+ ResetCursorPrefetchCaches(ipc_cursor_id);
+
+ scoped_ptr<WebIDBCallbacks> callbacks(callbacks_ptr);
+
+ int32 ipc_callbacks_id = pending_callbacks_.Add(callbacks.release());
+ Send(new IndexedDBHostMsg_CursorAdvance(
+ ipc_cursor_id, CurrentWorkerId(), ipc_callbacks_id, count));
+}
+
+void IndexedDBDispatcher::RequestIDBCursorContinue(
+ const IndexedDBKey& key,
+ WebIDBCallbacks* callbacks_ptr,
+ int32 ipc_cursor_id) {
+ // Reset all cursor prefetch caches except for this cursor.
+ ResetCursorPrefetchCaches(ipc_cursor_id);
+
+ scoped_ptr<WebIDBCallbacks> callbacks(callbacks_ptr);
+
+ int32 ipc_callbacks_id = pending_callbacks_.Add(callbacks.release());
+ Send(new IndexedDBHostMsg_CursorContinue(
+ ipc_cursor_id, CurrentWorkerId(), ipc_callbacks_id, key));
+}
+
+void IndexedDBDispatcher::RequestIDBCursorPrefetch(
+ int n,
+ WebIDBCallbacks* callbacks_ptr,
+ int32 ipc_cursor_id) {
+ scoped_ptr<WebIDBCallbacks> callbacks(callbacks_ptr);
+
+ int32 ipc_callbacks_id = pending_callbacks_.Add(callbacks.release());
+ Send(new IndexedDBHostMsg_CursorPrefetch(
+ ipc_cursor_id, CurrentWorkerId(), ipc_callbacks_id, n));
+}
+
+void IndexedDBDispatcher::RequestIDBCursorPrefetchReset(int used_prefetches,
+ int unused_prefetches,
+ int32 ipc_cursor_id) {
+ Send(new IndexedDBHostMsg_CursorPrefetchReset(
+ ipc_cursor_id, used_prefetches, unused_prefetches));
+}
+
+void IndexedDBDispatcher::RequestIDBFactoryOpen(
+ const string16& name,
+ int64 version,
+ int64 transaction_id,
+ WebIDBCallbacks* callbacks_ptr,
+ WebIDBDatabaseCallbacks* database_callbacks_ptr,
+ const string16& database_identifier) {
+ ResetCursorPrefetchCaches();
+ scoped_ptr<WebIDBCallbacks> callbacks(callbacks_ptr);
+ scoped_ptr<WebIDBDatabaseCallbacks> database_callbacks(
+ database_callbacks_ptr);
+
+ IndexedDBHostMsg_FactoryOpen_Params params;
+ params.ipc_thread_id = CurrentWorkerId();
+ params.ipc_callbacks_id = pending_callbacks_.Add(callbacks.release());
+ params.ipc_database_callbacks_id =
+ pending_database_callbacks_.Add(database_callbacks.release());
+ params.database_identifier = database_identifier;
+ params.name = name;
+ params.transaction_id = transaction_id;
+ params.version = version;
+ Send(new IndexedDBHostMsg_FactoryOpen(params));
+}
+
+void IndexedDBDispatcher::RequestIDBFactoryGetDatabaseNames(
+ WebIDBCallbacks* callbacks_ptr,
+ const string16& database_identifier) {
+ ResetCursorPrefetchCaches();
+ scoped_ptr<WebIDBCallbacks> callbacks(callbacks_ptr);
+
+ IndexedDBHostMsg_FactoryGetDatabaseNames_Params params;
+ params.ipc_thread_id = CurrentWorkerId();
+ params.ipc_callbacks_id = pending_callbacks_.Add(callbacks.release());
+ params.database_identifier = database_identifier;
+ Send(new IndexedDBHostMsg_FactoryGetDatabaseNames(params));
+}
+
+void IndexedDBDispatcher::RequestIDBFactoryDeleteDatabase(
+ const string16& name,
+ WebIDBCallbacks* callbacks_ptr,
+ const string16& database_identifier) {
+ ResetCursorPrefetchCaches();
+ scoped_ptr<WebIDBCallbacks> callbacks(callbacks_ptr);
+
+ IndexedDBHostMsg_FactoryDeleteDatabase_Params params;
+ params.ipc_thread_id = CurrentWorkerId();
+ params.ipc_callbacks_id = pending_callbacks_.Add(callbacks.release());
+ params.database_identifier = database_identifier;
+ params.name = name;
+ Send(new IndexedDBHostMsg_FactoryDeleteDatabase(params));
+}
+
+void IndexedDBDispatcher::RequestIDBDatabaseClose(
+ int32 ipc_database_id,
+ int32 ipc_database_callbacks_id) {
+ ResetCursorPrefetchCaches();
+ Send(new IndexedDBHostMsg_DatabaseClose(ipc_database_id));
+ // There won't be pending database callbacks if the transaction was aborted in
+ // the initial upgradeneeded event handler.
+ if (pending_database_callbacks_.Lookup(ipc_database_callbacks_id))
+ pending_database_callbacks_.Remove(ipc_database_callbacks_id);
+}
+
+void IndexedDBDispatcher::RequestIDBDatabaseCreateTransaction(
+ int32 ipc_database_id,
+ int64 transaction_id,
+ WebIDBDatabaseCallbacks* database_callbacks_ptr,
+ WebKit::WebVector<long long> object_store_ids,
+ unsigned short mode) {
+ scoped_ptr<WebIDBDatabaseCallbacks> database_callbacks(
+ database_callbacks_ptr);
+ IndexedDBHostMsg_DatabaseCreateTransaction_Params params;
+ params.ipc_thread_id = CurrentWorkerId();
+ params.ipc_database_id = ipc_database_id;
+ params.transaction_id = transaction_id;
+ params.ipc_database_callbacks_id =
+ pending_database_callbacks_.Add(database_callbacks.release());
+ params.object_store_ids
+ .assign(object_store_ids.data(),
+ object_store_ids.data() + object_store_ids.size());
+ params.mode = mode;
+
+ Send(new IndexedDBHostMsg_DatabaseCreateTransaction(params));
+}
+
+void IndexedDBDispatcher::RequestIDBDatabaseGet(
+ int32 ipc_database_id,
+ int64 transaction_id,
+ int64 object_store_id,
+ int64 index_id,
+ const IndexedDBKeyRange& key_range,
+ bool key_only,
+ WebIDBCallbacks* callbacks) {
+ ResetCursorPrefetchCaches();
+ IndexedDBHostMsg_DatabaseGet_Params params;
+ init_params(params, callbacks);
+ params.ipc_database_id = ipc_database_id;
+ params.transaction_id = transaction_id;
+ params.object_store_id = object_store_id;
+ params.index_id = index_id;
+ params.key_range = key_range;
+ params.key_only = key_only;
+ Send(new IndexedDBHostMsg_DatabaseGet(params));
+}
+
+void IndexedDBDispatcher::RequestIDBDatabasePut(
+ int32 ipc_database_id,
+ int64 transaction_id,
+ int64 object_store_id,
+ const WebData& value,
+ const IndexedDBKey& key,
+ WebIDBDatabase::PutMode put_mode,
+ WebIDBCallbacks* callbacks,
+ const WebVector<long long>& index_ids,
+ const WebVector<WebKit::WebVector<WebIDBKey> >& index_keys) {
+
+ if (value.size() > kMaxIDBValueSizeInBytes) {
+ callbacks->onError(WebIDBDatabaseError(
+ WebKit::WebIDBDatabaseExceptionUnknownError,
+ WebString::fromUTF8(base::StringPrintf(
+ "The serialized value is too large"
+ " (size=%" PRIuS " bytes, max=%" PRIuS " bytes).",
+ value.size(),
+ kMaxIDBValueSizeInBytes).c_str())));
+ return;
+ }
+
+ ResetCursorPrefetchCaches();
+ IndexedDBHostMsg_DatabasePut_Params params;
+ init_params(params, callbacks);
+ params.ipc_database_id = ipc_database_id;
+ params.transaction_id = transaction_id;
+ params.object_store_id = object_store_id;
+
+ params.value.assign(value.data(), value.data() + value.size());
+ params.key = key;
+ params.put_mode = put_mode;
+
+ COMPILE_ASSERT(sizeof(params.index_ids[0]) == sizeof(index_ids[0]),
+ Cant_copy);
+ params.index_ids
+ .assign(index_ids.data(), index_ids.data() + index_ids.size());
+
+ params.index_keys.resize(index_keys.size());
+ for (size_t i = 0; i < index_keys.size(); ++i) {
+ params.index_keys[i].resize(index_keys[i].size());
+ for (size_t j = 0; j < index_keys[i].size(); ++j) {
+ params.index_keys[i][j] = IndexedDBKey(index_keys[i][j]);
+ }
+ }
+ Send(new IndexedDBHostMsg_DatabasePut(params));
+}
+
+void IndexedDBDispatcher::RequestIDBDatabaseOpenCursor(
+ int32 ipc_database_id,
+ int64 transaction_id,
+ int64 object_store_id,
+ int64 index_id,
+ const IndexedDBKeyRange& key_range,
+ unsigned short direction,
+ bool key_only,
+ WebKit::WebIDBDatabase::TaskType task_type,
+ WebIDBCallbacks* callbacks) {
+ ResetCursorPrefetchCaches();
+ IndexedDBHostMsg_DatabaseOpenCursor_Params params;
+ init_params(params, callbacks);
+ params.ipc_database_id = ipc_database_id;
+ params.transaction_id = transaction_id;
+ params.object_store_id = object_store_id;
+ params.index_id = index_id;
+ params.key_range = IndexedDBKeyRange(key_range);
+ params.direction = direction;
+ params.key_only = key_only;
+ params.task_type = task_type;
+ Send(new IndexedDBHostMsg_DatabaseOpenCursor(params));
+}
+
+void IndexedDBDispatcher::RequestIDBDatabaseCount(
+ int32 ipc_database_id,
+ int64 transaction_id,
+ int64 object_store_id,
+ int64 index_id,
+ const IndexedDBKeyRange& key_range,
+ WebKit::WebIDBCallbacks* callbacks) {
+ ResetCursorPrefetchCaches();
+ IndexedDBHostMsg_DatabaseCount_Params params;
+ init_params(params, callbacks);
+ params.ipc_database_id = ipc_database_id;
+ params.transaction_id = transaction_id;
+ params.object_store_id = object_store_id;
+ params.index_id = index_id;
+ params.key_range = IndexedDBKeyRange(key_range);
+ Send(new IndexedDBHostMsg_DatabaseCount(params));
+}
+
+void IndexedDBDispatcher::RequestIDBDatabaseDeleteRange(
+ int32 ipc_database_id,
+ int64 transaction_id,
+ int64 object_store_id,
+ const IndexedDBKeyRange& key_range,
+ WebKit::WebIDBCallbacks* callbacks) {
+ ResetCursorPrefetchCaches();
+ IndexedDBHostMsg_DatabaseDeleteRange_Params params;
+ init_params(params, callbacks);
+ params.ipc_database_id = ipc_database_id;
+ params.transaction_id = transaction_id;
+ params.object_store_id = object_store_id;
+ params.key_range = key_range;
+ Send(new IndexedDBHostMsg_DatabaseDeleteRange(params));
+}
+
+void IndexedDBDispatcher::RequestIDBDatabaseClear(
+ int32 ipc_database_id,
+ int64 transaction_id,
+ int64 object_store_id,
+ WebKit::WebIDBCallbacks* callbacks_ptr) {
+ scoped_ptr<WebIDBCallbacks> callbacks(callbacks_ptr);
+ int32 ipc_callbacks_id = pending_callbacks_.Add(callbacks.release());
+ Send(new IndexedDBHostMsg_DatabaseClear(CurrentWorkerId(),
+ ipc_callbacks_id,
+ ipc_database_id,
+ transaction_id,
+ object_store_id));
+}
+
+void IndexedDBDispatcher::CursorDestroyed(int32 ipc_cursor_id) {
+ cursors_.erase(ipc_cursor_id);
+}
+
+void IndexedDBDispatcher::DatabaseDestroyed(int32 ipc_database_id) {
+ DCHECK_EQ(databases_.count(ipc_database_id), 1u);
+ databases_.erase(ipc_database_id);
+}
+
+void IndexedDBDispatcher::OnSuccessIDBDatabase(
+ int32 ipc_thread_id,
+ int32 ipc_callbacks_id,
+ int32 ipc_database_callbacks_id,
+ int32 ipc_object_id,
+ const IndexedDBDatabaseMetadata& idb_metadata) {
+ DCHECK_EQ(ipc_thread_id, CurrentWorkerId());
+ WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id);
+ if (!callbacks)
+ return;
+ WebIDBMetadata metadata(ConvertMetadata(idb_metadata));
+ // If an upgrade was performed, count will be non-zero.
+ if (!databases_.count(ipc_object_id))
+ databases_[ipc_object_id] = new RendererWebIDBDatabaseImpl(
+ ipc_object_id, ipc_database_callbacks_id);
+ DCHECK_EQ(databases_.count(ipc_object_id), 1u);
+ callbacks->onSuccess(databases_[ipc_object_id], metadata);
+ pending_callbacks_.Remove(ipc_callbacks_id);
+}
+
+void IndexedDBDispatcher::OnSuccessIndexedDBKey(int32 ipc_thread_id,
+ int32 ipc_callbacks_id,
+ const IndexedDBKey& key) {
+ DCHECK_EQ(ipc_thread_id, CurrentWorkerId());
+ WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id);
+ if (!callbacks)
+ return;
+ callbacks->onSuccess(WebIDBKey(key));
+ pending_callbacks_.Remove(ipc_callbacks_id);
+}
+
+void IndexedDBDispatcher::OnSuccessStringList(
+ int32 ipc_thread_id,
+ int32 ipc_callbacks_id,
+ const std::vector<string16>& value) {
+ DCHECK_EQ(ipc_thread_id, CurrentWorkerId());
+ WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id);
+ if (!callbacks)
+ return;
+ callbacks->onSuccess(WebVector<WebString>(value));
+ pending_callbacks_.Remove(ipc_callbacks_id);
+}
+
+void IndexedDBDispatcher::OnSuccessValue(int32 ipc_thread_id,
+ int32 ipc_callbacks_id,
+ const std::vector<char>& value) {
+ DCHECK_EQ(ipc_thread_id, CurrentWorkerId());
+ WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id);
+ if (!callbacks)
+ return;
+ WebData web_value;
+ if (value.size())
+ web_value.assign(&value.front(), value.size());
+ callbacks->onSuccess(web_value);
+ pending_callbacks_.Remove(ipc_callbacks_id);
+}
+
+void IndexedDBDispatcher::OnSuccessValueWithKey(
+ int32 ipc_thread_id,
+ int32 ipc_callbacks_id,
+ const std::vector<char>& value,
+ const IndexedDBKey& primary_key,
+ const IndexedDBKeyPath& key_path) {
+ DCHECK_EQ(ipc_thread_id, CurrentWorkerId());
+ WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id);
+ if (!callbacks)
+ return;
+ WebData web_value;
+ if (value.size())
+ web_value.assign(&value.front(), value.size());
+ callbacks->onSuccess(web_value, primary_key, key_path);
+ pending_callbacks_.Remove(ipc_callbacks_id);
+}
+
+void IndexedDBDispatcher::OnSuccessInteger(int32 ipc_thread_id,
+ int32 ipc_callbacks_id,
+ int64 value) {
+ DCHECK_EQ(ipc_thread_id, CurrentWorkerId());
+ WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id);
+ if (!callbacks)
+ return;
+ callbacks->onSuccess(value);
+ pending_callbacks_.Remove(ipc_callbacks_id);
+}
+
+void IndexedDBDispatcher::OnSuccessUndefined(int32 ipc_thread_id,
+ int32 ipc_callbacks_id) {
+ DCHECK_EQ(ipc_thread_id, CurrentWorkerId());
+ WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id);
+ if (!callbacks)
+ return;
+ callbacks->onSuccess();
+ pending_callbacks_.Remove(ipc_callbacks_id);
+}
+
+void IndexedDBDispatcher::OnSuccessOpenCursor(
+ const IndexedDBMsg_CallbacksSuccessIDBCursor_Params& p) {
+ DCHECK_EQ(p.ipc_thread_id, CurrentWorkerId());
+ int32 ipc_callbacks_id = p.ipc_callbacks_id;
+ int32 ipc_object_id = p.ipc_cursor_id;
+ const IndexedDBKey& key = p.key;
+ const IndexedDBKey& primary_key = p.primary_key;
+ WebData web_value;
+ if (p.value.size())
+ web_value.assign(&p.value.front(), p.value.size());
+
+ WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id);
+ if (!callbacks)
+ return;
+
+ RendererWebIDBCursorImpl* cursor =
+ new RendererWebIDBCursorImpl(ipc_object_id);
+ cursors_[ipc_object_id] = cursor;
+ callbacks->onSuccess(cursor, key, primary_key, web_value);
+
+ pending_callbacks_.Remove(ipc_callbacks_id);
+}
+
+void IndexedDBDispatcher::OnSuccessCursorContinue(
+ const IndexedDBMsg_CallbacksSuccessCursorContinue_Params& p) {
+ DCHECK_EQ(p.ipc_thread_id, CurrentWorkerId());
+ int32 ipc_callbacks_id = p.ipc_callbacks_id;
+ int32 ipc_cursor_id = p.ipc_cursor_id;
+ const IndexedDBKey& key = p.key;
+ const IndexedDBKey& primary_key = p.primary_key;
+ const std::vector<char>& value = p.value;
+
+ RendererWebIDBCursorImpl* cursor = cursors_[ipc_cursor_id];
+ DCHECK(cursor);
+
+ WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id);
+ if (!callbacks)
+ return;
+
+ WebData web_value;
+ if (value.size())
+ web_value.assign(&value.front(), value.size());
+ callbacks->onSuccess(key, primary_key, web_value);
+
+ pending_callbacks_.Remove(ipc_callbacks_id);
+}
+
+void IndexedDBDispatcher::OnSuccessCursorPrefetch(
+ const IndexedDBMsg_CallbacksSuccessCursorPrefetch_Params& p) {
+ DCHECK_EQ(p.ipc_thread_id, CurrentWorkerId());
+ int32 ipc_callbacks_id = p.ipc_callbacks_id;
+ int32 ipc_cursor_id = p.ipc_cursor_id;
+ const std::vector<IndexedDBKey>& keys = p.keys;
+ const std::vector<IndexedDBKey>& primary_keys = p.primary_keys;
+ std::vector<WebData> values(p.values.size());
+ for (size_t i = 0; i < p.values.size(); ++i) {
+ if (p.values[i].size())
+ values[i].assign(&p.values[i].front(), p.values[i].size());
+ }
+ RendererWebIDBCursorImpl* cursor = cursors_[ipc_cursor_id];
+ DCHECK(cursor);
+ cursor->SetPrefetchData(keys, primary_keys, values);
+
+ WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id);
+ DCHECK(callbacks);
+ cursor->CachedContinue(callbacks);
+ pending_callbacks_.Remove(ipc_callbacks_id);
+}
+
+void IndexedDBDispatcher::OnIntBlocked(int32 ipc_thread_id,
+ int32 ipc_callbacks_id,
+ int64 existing_version) {
+ DCHECK_EQ(ipc_thread_id, CurrentWorkerId());
+ WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id);
+ DCHECK(callbacks);
+ callbacks->onBlocked(existing_version);
+}
+
+void IndexedDBDispatcher::OnUpgradeNeeded(
+ const IndexedDBMsg_CallbacksUpgradeNeeded_Params& p) {
+ DCHECK_EQ(p.ipc_thread_id, CurrentWorkerId());
+ WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(p.ipc_callbacks_id);
+ DCHECK(callbacks);
+ WebIDBMetadata metadata(ConvertMetadata(p.idb_metadata));
+ DCHECK(!databases_.count(p.ipc_database_id));
+ databases_[p.ipc_database_id] = new RendererWebIDBDatabaseImpl(
+ p.ipc_database_id, p.ipc_database_callbacks_id);
+ callbacks->onUpgradeNeeded(
+ p.old_version, databases_[p.ipc_database_id], metadata);
+}
+
+void IndexedDBDispatcher::OnError(int32 ipc_thread_id,
+ int32 ipc_callbacks_id,
+ int code,
+ const string16& message) {
+ DCHECK_EQ(ipc_thread_id, CurrentWorkerId());
+ WebIDBCallbacks* callbacks = pending_callbacks_.Lookup(ipc_callbacks_id);
+ if (!callbacks)
+ return;
+ callbacks->onError(WebIDBDatabaseError(code, message));
+ pending_callbacks_.Remove(ipc_callbacks_id);
+}
+
+void IndexedDBDispatcher::OnAbort(int32 ipc_thread_id,
+ int32 ipc_database_callbacks_id,
+ int64 transaction_id,
+ int code,
+ const string16& message) {
+ DCHECK_EQ(ipc_thread_id, CurrentWorkerId());
+ WebIDBDatabaseCallbacks* callbacks =
+ pending_database_callbacks_.Lookup(ipc_database_callbacks_id);
+ if (!callbacks)
+ return;
+ callbacks->onAbort(transaction_id, WebIDBDatabaseError(code, message));
+}
+
+void IndexedDBDispatcher::OnComplete(int32 ipc_thread_id,
+ int32 ipc_database_callbacks_id,
+ int64 transaction_id) {
+ DCHECK_EQ(ipc_thread_id, CurrentWorkerId());
+ WebIDBDatabaseCallbacks* callbacks =
+ pending_database_callbacks_.Lookup(ipc_database_callbacks_id);
+ if (!callbacks)
+ return;
+ callbacks->onComplete(transaction_id);
+}
+
+void IndexedDBDispatcher::OnForcedClose(int32 ipc_thread_id,
+ int32 ipc_database_callbacks_id) {
+ DCHECK_EQ(ipc_thread_id, CurrentWorkerId());
+ WebIDBDatabaseCallbacks* callbacks =
+ pending_database_callbacks_.Lookup(ipc_database_callbacks_id);
+ if (!callbacks)
+ return;
+ callbacks->onForcedClose();
+}
+
+void IndexedDBDispatcher::OnIntVersionChange(int32 ipc_thread_id,
+ int32 ipc_database_callbacks_id,
+ int64 old_version,
+ int64 new_version) {
+ DCHECK_EQ(ipc_thread_id, CurrentWorkerId());
+ WebIDBDatabaseCallbacks* callbacks =
+ pending_database_callbacks_.Lookup(ipc_database_callbacks_id);
+ // callbacks would be NULL if a versionchange event is received after close
+ // has been called.
+ if (!callbacks)
+ return;
+ callbacks->onVersionChange(old_version, new_version);
+}
+
+void IndexedDBDispatcher::ResetCursorPrefetchCaches(
+ int32 ipc_exception_cursor_id) {
+ typedef std::map<int32, RendererWebIDBCursorImpl*>::iterator Iterator;
+ for (Iterator i = cursors_.begin(); i != cursors_.end(); ++i) {
+ if (i->first == ipc_exception_cursor_id)
+ continue;
+ i->second->ResetPrefetchCache();
+ }
+}
+
+} // namespace content
diff --git a/content/child/indexed_db/indexed_db_dispatcher.h b/content/child/indexed_db/indexed_db_dispatcher.h
new file mode 100644
index 0000000..f8b2102
--- /dev/null
+++ b/content/child/indexed_db/indexed_db_dispatcher.h
@@ -0,0 +1,241 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_CHILD_INDEXED_DB_INDEXED_DB_DISPATCHER_H_
+#define CONTENT_CHILD_INDEXED_DB_INDEXED_DB_DISPATCHER_H_
+
+#include <map>
+#include <vector>
+
+#include "base/gtest_prod_util.h"
+#include "base/id_map.h"
+#include "base/nullable_string16.h"
+#include "content/common/content_export.h"
+#include "ipc/ipc_sync_message_filter.h"
+#include "third_party/WebKit/public/platform/WebIDBCallbacks.h"
+#include "third_party/WebKit/public/platform/WebIDBCursor.h"
+#include "third_party/WebKit/public/platform/WebIDBDatabase.h"
+#include "third_party/WebKit/public/platform/WebIDBDatabaseCallbacks.h"
+#include "webkit/glue/worker_task_runner.h"
+
+struct IndexedDBDatabaseMetadata;
+struct IndexedDBMsg_CallbacksSuccessCursorContinue_Params;
+struct IndexedDBMsg_CallbacksSuccessCursorPrefetch_Params;
+struct IndexedDBMsg_CallbacksSuccessIDBCursor_Params;
+struct IndexedDBMsg_CallbacksUpgradeNeeded_Params;
+
+namespace WebKit {
+class WebData;
+}
+
+namespace content {
+class IndexedDBKey;
+class IndexedDBKeyPath;
+class IndexedDBKeyRange;
+class RendererWebIDBCursorImpl;
+class RendererWebIDBDatabaseImpl;
+
+CONTENT_EXPORT extern const size_t kMaxIDBValueSizeInBytes;
+
+// Handle the indexed db related communication for this context thread - the
+// main thread and each worker thread have their own copies.
+class CONTENT_EXPORT IndexedDBDispatcher
+ : public webkit_glue::WorkerTaskRunner::Observer {
+ public:
+ // Constructor made public to allow RenderThreadImpl to own a copy without
+ // failing a NOTREACHED in ThreadSpecificInstance in tests that instantiate
+ // two copies of RenderThreadImpl on the same thread. Everyone else probably
+ // wants to use ThreadSpecificInstance().
+ IndexedDBDispatcher();
+ virtual ~IndexedDBDispatcher();
+ static IndexedDBDispatcher* ThreadSpecificInstance();
+
+ // webkit_glue::WorkerTaskRunner::Observer implementation.
+ virtual void OnWorkerRunLoopStopped() OVERRIDE;
+
+ static WebKit::WebIDBMetadata ConvertMetadata(
+ const IndexedDBDatabaseMetadata& idb_metadata);
+
+ void OnMessageReceived(const IPC::Message& msg);
+ static bool Send(IPC::Message* msg);
+
+ void RequestIDBFactoryGetDatabaseNames(WebKit::WebIDBCallbacks* callbacks,
+ const string16& database_identifier);
+
+ void RequestIDBFactoryOpen(
+ const string16& name,
+ int64 version,
+ int64 transaction_id,
+ WebKit::WebIDBCallbacks* callbacks,
+ WebKit::WebIDBDatabaseCallbacks* database_callbacks,
+ const string16& database_identifier);
+
+ void RequestIDBFactoryDeleteDatabase(const string16& name,
+ WebKit::WebIDBCallbacks* callbacks,
+ const string16& database_identifier);
+
+ void RequestIDBCursorAdvance(unsigned long count,
+ WebKit::WebIDBCallbacks* callbacks_ptr,
+ int32 ipc_cursor_id);
+
+ virtual void RequestIDBCursorContinue(const IndexedDBKey& key,
+ WebKit::WebIDBCallbacks* callbacks_ptr,
+ int32 ipc_cursor_id);
+
+ virtual void RequestIDBCursorPrefetch(int n,
+ WebKit::WebIDBCallbacks* callbacks_ptr,
+ int32 ipc_cursor_id);
+
+ void RequestIDBCursorPrefetchReset(int used_prefetches,
+ int unused_prefetches,
+ int32 ipc_cursor_id);
+
+ void RequestIDBDatabaseClose(int32 ipc_database_id,
+ int32 ipc_database_callbacks_id);
+
+ void RequestIDBDatabaseCreateTransaction(
+ int32 ipc_database_id,
+ int64 transaction_id,
+ WebKit::WebIDBDatabaseCallbacks* database_callbacks_ptr,
+ WebKit::WebVector<long long> object_store_ids,
+ unsigned short mode);
+
+ void RequestIDBDatabaseGet(int32 ipc_database_id,
+ int64 transaction_id,
+ int64 object_store_id,
+ int64 index_id,
+ const IndexedDBKeyRange& key_range,
+ bool key_only,
+ WebKit::WebIDBCallbacks* callbacks);
+
+ void RequestIDBDatabasePut(
+ int32 ipc_database_id,
+ int64 transaction_id,
+ int64 object_store_id,
+ const WebKit::WebData& value,
+ const IndexedDBKey& key,
+ WebKit::WebIDBDatabase::PutMode put_mode,
+ WebKit::WebIDBCallbacks* callbacks,
+ const WebKit::WebVector<long long>& index_ids,
+ const WebKit::WebVector<WebKit::WebVector<WebKit::WebIDBKey> >&
+ index_keys);
+
+ void RequestIDBDatabaseOpenCursor(int32 ipc_database_id,
+ int64 transaction_id,
+ int64 object_store_id,
+ int64 index_id,
+ const IndexedDBKeyRange& key_range,
+ unsigned short direction,
+ bool key_only,
+ WebKit::WebIDBDatabase::TaskType task_type,
+ WebKit::WebIDBCallbacks* callbacks);
+
+ void RequestIDBDatabaseCount(int32 ipc_database_id,
+ int64 transaction_id,
+ int64 object_store_id,
+ int64 index_id,
+ const IndexedDBKeyRange& key_range,
+ WebKit::WebIDBCallbacks* callbacks);
+
+ void RequestIDBDatabaseDeleteRange(int32 ipc_database_id,
+ int64 transaction_id,
+ int64 object_store_id,
+ const IndexedDBKeyRange& key_range,
+ WebKit::WebIDBCallbacks* callbacks);
+
+ void RequestIDBDatabaseClear(int32 ipc_database_id,
+ int64 transaction_id,
+ int64 object_store_id,
+ WebKit::WebIDBCallbacks* callbacks);
+
+ virtual void CursorDestroyed(int32 ipc_cursor_id);
+ void DatabaseDestroyed(int32 ipc_database_id);
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(IndexedDBDispatcherTest, ValueSizeTest);
+
+ static int32 CurrentWorkerId() {
+ return webkit_glue::WorkerTaskRunner::Instance()->CurrentWorkerId();
+ }
+
+ template <typename T>
+ void init_params(T& params, WebKit::WebIDBCallbacks* callbacks_ptr) {
+ scoped_ptr<WebKit::WebIDBCallbacks> callbacks(callbacks_ptr);
+ params.ipc_thread_id = CurrentWorkerId();
+ params.ipc_callbacks_id = pending_callbacks_.Add(callbacks.release());
+ }
+
+ // IDBCallback message handlers.
+ void OnSuccessIDBDatabase(int32 ipc_thread_id,
+ int32 ipc_callbacks_id,
+ int32 ipc_database_callbacks_id,
+ int32 ipc_object_id,
+ const IndexedDBDatabaseMetadata& idb_metadata);
+ void OnSuccessIndexedDBKey(int32 ipc_thread_id,
+ int32 ipc_callbacks_id,
+ const IndexedDBKey& key);
+
+ void OnSuccessOpenCursor(
+ const IndexedDBMsg_CallbacksSuccessIDBCursor_Params& p);
+ void OnSuccessCursorContinue(
+ const IndexedDBMsg_CallbacksSuccessCursorContinue_Params& p);
+ void OnSuccessCursorPrefetch(
+ const IndexedDBMsg_CallbacksSuccessCursorPrefetch_Params& p);
+ void OnSuccessStringList(int32 ipc_thread_id,
+ int32 ipc_callbacks_id,
+ const std::vector<string16>& value);
+ void OnSuccessValue(int32 ipc_thread_id,
+ int32 ipc_callbacks_id,
+ const std::vector<char>& value);
+ void OnSuccessValueWithKey(int32 ipc_thread_id,
+ int32 ipc_callbacks_id,
+ const std::vector<char>& value,
+ const IndexedDBKey& primary_key,
+ const IndexedDBKeyPath& key_path);
+ void OnSuccessInteger(int32 ipc_thread_id,
+ int32 ipc_callbacks_id,
+ int64 value);
+ void OnSuccessUndefined(int32 ipc_thread_id, int32 ipc_callbacks_id);
+ void OnError(int32 ipc_thread_id,
+ int32 ipc_callbacks_id,
+ int code,
+ const string16& message);
+ void OnIntBlocked(int32 ipc_thread_id,
+ int32 ipc_callbacks_id,
+ int64 existing_version);
+ void OnUpgradeNeeded(const IndexedDBMsg_CallbacksUpgradeNeeded_Params& p);
+ void OnAbort(int32 ipc_thread_id,
+ int32 ipc_database_id,
+ int64 transaction_id,
+ int code,
+ const string16& message);
+ void OnComplete(int32 ipc_thread_id,
+ int32 ipc_database_id,
+ int64 transaction_id);
+ void OnForcedClose(int32 ipc_thread_id, int32 ipc_database_id);
+ void OnIntVersionChange(int32 ipc_thread_id,
+ int32 ipc_database_id,
+ int64 old_version,
+ int64 new_version);
+
+ // Reset cursor prefetch caches for all cursors except exception_cursor_id.
+ void ResetCursorPrefetchCaches(int32 ipc_exception_cursor_id = -1);
+
+ // Careful! WebIDBCallbacks wraps non-threadsafe data types. It must be
+ // destroyed and used on the same thread it was created on.
+ IDMap<WebKit::WebIDBCallbacks, IDMapOwnPointer> pending_callbacks_;
+ IDMap<WebKit::WebIDBDatabaseCallbacks, IDMapOwnPointer>
+ pending_database_callbacks_;
+
+ // Map from cursor id to RendererWebIDBCursorImpl.
+ std::map<int32, RendererWebIDBCursorImpl*> cursors_;
+
+ std::map<int32, RendererWebIDBDatabaseImpl*> databases_;
+
+ DISALLOW_COPY_AND_ASSIGN(IndexedDBDispatcher);
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_INDEXED_DB_INDEXED_DB_DISPATCHER_H_
diff --git a/content/child/indexed_db/indexed_db_dispatcher_unittest.cc b/content/child/indexed_db/indexed_db_dispatcher_unittest.cc
new file mode 100644
index 0000000..155ae7f
--- /dev/null
+++ b/content/child/indexed_db/indexed_db_dispatcher_unittest.cc
@@ -0,0 +1,62 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+#include "content/child/indexed_db/indexed_db_dispatcher.h"
+#include "content/common/indexed_db/indexed_db_key.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebData.h"
+#include "third_party/WebKit/public/platform/WebIDBCallbacks.h"
+
+using WebKit::WebData;
+using WebKit::WebIDBCallbacks;
+using WebKit::WebIDBDatabase;
+using WebKit::WebIDBDatabaseError;
+using WebKit::WebIDBKey;
+using WebKit::WebVector;
+
+namespace content {
+namespace {
+
+class MockCallbacks : public WebIDBCallbacks {
+ public:
+ MockCallbacks() : error_seen_(false) {}
+
+ virtual void onError(const WebIDBDatabaseError&) OVERRIDE {
+ error_seen_ = true;
+ }
+
+ bool error_seen() const { return error_seen_; }
+
+ private:
+ bool error_seen_;
+};
+
+} // namespace
+
+TEST(IndexedDBDispatcherTest, ValueSizeTest) {
+ const std::vector<char> data(kMaxIDBValueSizeInBytes + 1);
+ const WebData value(&data.front(), data.size());
+ const int32 ipc_dummy_id = -1;
+ const int64 transaction_id = 1;
+ const int64 object_store_id = 2;
+
+ MockCallbacks callbacks;
+ IndexedDBDispatcher dispatcher;
+ IndexedDBKey key(0, WebIDBKey::NumberType);
+ dispatcher.RequestIDBDatabasePut(ipc_dummy_id,
+ transaction_id,
+ object_store_id,
+ value,
+ key,
+ WebIDBDatabase::AddOrUpdate,
+ &callbacks,
+ WebVector<long long>(),
+ WebVector<WebVector<WebIDBKey> >());
+
+ EXPECT_TRUE(callbacks.error_seen());
+}
+
+} // namespace content
diff --git a/content/child/indexed_db/indexed_db_message_filter.cc b/content/child/indexed_db/indexed_db_message_filter.cc
new file mode 100644
index 0000000..949c167
--- /dev/null
+++ b/content/child/indexed_db/indexed_db_message_filter.cc
@@ -0,0 +1,79 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/indexed_db/indexed_db_message_filter.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/message_loop_proxy.h"
+#include "base/pickle.h"
+#include "content/child/indexed_db/indexed_db_dispatcher.h"
+#include "content/common/child_thread.h"
+#include "content/common/indexed_db/indexed_db_messages.h"
+#include "webkit/glue/worker_task_runner.h"
+
+using webkit_glue::WorkerTaskRunner;
+
+namespace content {
+
+IndexedDBMessageFilter::IndexedDBMessageFilter() :
+ main_thread_loop_proxy_(base::MessageLoopProxy::current()) {
+}
+
+bool IndexedDBMessageFilter::OnMessageReceived(const IPC::Message& msg) {
+ if (IPC_MESSAGE_CLASS(msg) != IndexedDBMsgStart)
+ return false;
+ int ipc_thread_id = -1;
+ bool result = PickleIterator(msg).ReadInt(&ipc_thread_id);
+ DCHECK(result);
+ base::Closure closure = base::Bind(
+ &IndexedDBMessageFilter::DispatchMessage, this, msg);
+ if (!ipc_thread_id) {
+ main_thread_loop_proxy_->PostTask(FROM_HERE, closure);
+ return true;
+ }
+ if (WorkerTaskRunner::Instance()->PostTask(ipc_thread_id, closure))
+ return true;
+
+ // Message for a terminated worker - perform necessary cleanup
+ OnStaleMessageReceived(msg);
+ return true;
+}
+
+IndexedDBMessageFilter::~IndexedDBMessageFilter() {}
+
+void IndexedDBMessageFilter::DispatchMessage(const IPC::Message& msg) {
+ IndexedDBDispatcher::ThreadSpecificInstance()->OnMessageReceived(msg);
+}
+
+void IndexedDBMessageFilter::OnStaleMessageReceived(const IPC::Message& msg) {
+ IPC_BEGIN_MESSAGE_MAP(IndexedDBMessageFilter, msg)
+ IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksSuccessIDBDatabase,
+ OnStaleSuccessIDBDatabase)
+ IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksUpgradeNeeded,
+ OnStaleUpgradeNeeded)
+ IPC_END_MESSAGE_MAP()
+}
+
+void IndexedDBMessageFilter::OnStaleSuccessIDBDatabase(
+ int32 ipc_thread_id,
+ int32 ipc_callbacks_id,
+ int32 ipc_database_callbacks_id,
+ int32 ipc_database_id,
+ const IndexedDBDatabaseMetadata& idb_metadata) {
+ scoped_refptr<IPC::SyncMessageFilter> filter(
+ ChildThread::current()->sync_message_filter());
+ filter->Send(
+ new IndexedDBHostMsg_DatabaseClose(ipc_database_id));
+}
+
+void IndexedDBMessageFilter::OnStaleUpgradeNeeded(
+ const IndexedDBMsg_CallbacksUpgradeNeeded_Params& p) {
+ scoped_refptr<IPC::SyncMessageFilter> filter(
+ ChildThread::current()->sync_message_filter());
+ filter->Send(
+ new IndexedDBHostMsg_DatabaseClose(p.ipc_database_id));
+}
+
+} // namespace content
diff --git a/content/child/indexed_db/indexed_db_message_filter.h b/content/child/indexed_db/indexed_db_message_filter.h
new file mode 100644
index 0000000..04708d3
--- /dev/null
+++ b/content/child/indexed_db/indexed_db_message_filter.h
@@ -0,0 +1,47 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_CHILD_INDEXED_DB_INDEXED_DB_MESSAGE_FILTER_H_
+#define CONTENT_CHILD_INDEXED_DB_INDEXED_DB_MESSAGE_FILTER_H_
+
+#include "ipc/ipc_channel_proxy.h"
+
+struct IndexedDBDatabaseMetadata;
+struct IndexedDBMsg_CallbacksUpgradeNeeded_Params;
+
+namespace base {
+class MessageLoopProxy;
+} // namespace base
+
+namespace content {
+class IndexedDBDispatcher;
+
+class IndexedDBMessageFilter : public IPC::ChannelProxy::MessageFilter {
+ public:
+ IndexedDBMessageFilter();
+
+ // IPC::Listener implementation.
+ virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
+
+ protected:
+ virtual ~IndexedDBMessageFilter();
+
+ private:
+ void DispatchMessage(const IPC::Message& msg);
+ void OnStaleMessageReceived(const IPC::Message& msg);
+ void OnStaleSuccessIDBDatabase(int32 ipc_thread_id,
+ int32 ipc_callbacks_id,
+ int32 ipc_database_callbacks_id,
+ int32 ipc_object_id,
+ const IndexedDBDatabaseMetadata&);
+ void OnStaleUpgradeNeeded(const IndexedDBMsg_CallbacksUpgradeNeeded_Params&);
+
+ scoped_refptr<base::MessageLoopProxy> main_thread_loop_proxy_;
+
+ DISALLOW_COPY_AND_ASSIGN(IndexedDBMessageFilter);
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_INDEXED_DB_INDEXED_DB_MESSAGE_FILTER_H_
diff --git a/content/child/indexed_db/proxy_webidbcursor_impl.cc b/content/child/indexed_db/proxy_webidbcursor_impl.cc
new file mode 100644
index 0000000..4afd8d9
--- /dev/null
+++ b/content/child/indexed_db/proxy_webidbcursor_impl.cc
@@ -0,0 +1,157 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/indexed_db/proxy_webidbcursor_impl.h"
+
+#include <vector>
+
+#include "content/child/indexed_db/indexed_db_dispatcher.h"
+#include "content/common/child_thread.h"
+#include "content/common/indexed_db/indexed_db_messages.h"
+
+using WebKit::WebData;
+using WebKit::WebIDBCallbacks;
+using WebKit::WebIDBKey;
+
+namespace content {
+
+RendererWebIDBCursorImpl::RendererWebIDBCursorImpl(int32 ipc_cursor_id)
+ : ipc_cursor_id_(ipc_cursor_id),
+ continue_count_(0),
+ used_prefetches_(0),
+ pending_onsuccess_callbacks_(0),
+ prefetch_amount_(kMinPrefetchAmount) {}
+
+RendererWebIDBCursorImpl::~RendererWebIDBCursorImpl() {
+ // It's not possible for there to be pending callbacks that address this
+ // object since inside WebKit, they hold a reference to the object which owns
+ // this object. But, if that ever changed, then we'd need to invalidate
+ // any such pointers.
+
+ if (ipc_cursor_id_ != kInvalidCursorId) {
+ // Invalid ID used in tests to avoid really sending this message.
+ IndexedDBDispatcher::Send(
+ new IndexedDBHostMsg_CursorDestroyed(ipc_cursor_id_));
+ }
+ IndexedDBDispatcher* dispatcher =
+ IndexedDBDispatcher::ThreadSpecificInstance();
+ dispatcher->CursorDestroyed(ipc_cursor_id_);
+}
+
+void RendererWebIDBCursorImpl::advance(unsigned long count,
+ WebIDBCallbacks* callbacks_ptr) {
+ IndexedDBDispatcher* dispatcher =
+ IndexedDBDispatcher::ThreadSpecificInstance();
+ scoped_ptr<WebIDBCallbacks> callbacks(callbacks_ptr);
+ ResetPrefetchCache();
+ dispatcher->RequestIDBCursorAdvance(
+ count, callbacks.release(), ipc_cursor_id_);
+}
+
+void RendererWebIDBCursorImpl::continueFunction(
+ const WebIDBKey& key,
+ WebIDBCallbacks* callbacks_ptr) {
+ IndexedDBDispatcher* dispatcher =
+ IndexedDBDispatcher::ThreadSpecificInstance();
+ scoped_ptr<WebIDBCallbacks> callbacks(callbacks_ptr);
+
+ if (key.type() == WebIDBKey::NullType) {
+ // No key, so this would qualify for a prefetch.
+ ++continue_count_;
+
+ if (!prefetch_keys_.empty()) {
+ // We have a prefetch cache, so serve the result from that.
+ CachedContinue(callbacks.get());
+ return;
+ }
+
+ if (continue_count_ > kPrefetchContinueThreshold) {
+ // Request pre-fetch.
+ ++pending_onsuccess_callbacks_;
+ dispatcher->RequestIDBCursorPrefetch(
+ prefetch_amount_, callbacks.release(), ipc_cursor_id_);
+
+ // Increase prefetch_amount_ exponentially.
+ prefetch_amount_ *= 2;
+ if (prefetch_amount_ > kMaxPrefetchAmount)
+ prefetch_amount_ = kMaxPrefetchAmount;
+
+ return;
+ }
+ } else {
+ // Key argument supplied. We couldn't prefetch this.
+ ResetPrefetchCache();
+ }
+
+ dispatcher->RequestIDBCursorContinue(
+ IndexedDBKey(key), callbacks.release(), ipc_cursor_id_);
+}
+
+void RendererWebIDBCursorImpl::postSuccessHandlerCallback() {
+ pending_onsuccess_callbacks_--;
+
+ // If the onsuccess callback called continue() on the cursor again,
+ // and that continue was served by the prefetch cache, then
+ // pending_onsuccess_callbacks_ would be incremented.
+ // If not, it means the callback did something else, or nothing at all,
+ // in which case we need to reset the cache.
+
+ if (pending_onsuccess_callbacks_ == 0)
+ ResetPrefetchCache();
+}
+
+void RendererWebIDBCursorImpl::SetPrefetchData(
+ const std::vector<IndexedDBKey>& keys,
+ const std::vector<IndexedDBKey>& primary_keys,
+ const std::vector<WebData>& values) {
+ prefetch_keys_.assign(keys.begin(), keys.end());
+ prefetch_primary_keys_.assign(primary_keys.begin(), primary_keys.end());
+ prefetch_values_.assign(values.begin(), values.end());
+
+ used_prefetches_ = 0;
+ pending_onsuccess_callbacks_ = 0;
+}
+
+void RendererWebIDBCursorImpl::CachedContinue(
+ WebKit::WebIDBCallbacks* callbacks) {
+ DCHECK_GT(prefetch_keys_.size(), 0ul);
+ DCHECK(prefetch_primary_keys_.size() == prefetch_keys_.size());
+ DCHECK(prefetch_values_.size() == prefetch_keys_.size());
+
+ IndexedDBKey key = prefetch_keys_.front();
+ IndexedDBKey primary_key = prefetch_primary_keys_.front();
+ // this could be a real problem.. we need 2 CachedContinues
+ WebData value = prefetch_values_.front();
+
+ prefetch_keys_.pop_front();
+ prefetch_primary_keys_.pop_front();
+ prefetch_values_.pop_front();
+ used_prefetches_++;
+
+ pending_onsuccess_callbacks_++;
+
+ callbacks->onSuccess(key, primary_key, value);
+}
+
+void RendererWebIDBCursorImpl::ResetPrefetchCache() {
+ continue_count_ = 0;
+ prefetch_amount_ = kMinPrefetchAmount;
+
+ if (!prefetch_keys_.size()) {
+ // No prefetch cache, so no need to reset the cursor in the back-end.
+ return;
+ }
+
+ IndexedDBDispatcher* dispatcher =
+ IndexedDBDispatcher::ThreadSpecificInstance();
+ dispatcher->RequestIDBCursorPrefetchReset(
+ used_prefetches_, prefetch_keys_.size(), ipc_cursor_id_);
+ prefetch_keys_.clear();
+ prefetch_primary_keys_.clear();
+ prefetch_values_.clear();
+
+ pending_onsuccess_callbacks_ = 0;
+}
+
+} // namespace content
diff --git a/content/child/indexed_db/proxy_webidbcursor_impl.h b/content/child/indexed_db/proxy_webidbcursor_impl.h
new file mode 100644
index 0000000..d3a1c6b
--- /dev/null
+++ b/content/child/indexed_db/proxy_webidbcursor_impl.h
@@ -0,0 +1,71 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_CHILD_INDEXED_DB_PROXY_WEBIDBCURSOR_IMPL_H_
+#define CONTENT_CHILD_INDEXED_DB_PROXY_WEBIDBCURSOR_IMPL_H_
+
+#include <deque>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
+#include "content/common/content_export.h"
+#include "content/common/indexed_db/indexed_db_key.h"
+#include "third_party/WebKit/public/platform/WebData.h"
+#include "third_party/WebKit/public/platform/WebIDBCallbacks.h"
+#include "third_party/WebKit/public/platform/WebIDBCursor.h"
+#include "third_party/WebKit/public/platform/WebIDBKey.h"
+
+namespace content {
+
+class CONTENT_EXPORT RendererWebIDBCursorImpl
+ : NON_EXPORTED_BASE(public WebKit::WebIDBCursor) {
+ public:
+ explicit RendererWebIDBCursorImpl(int32 ipc_cursor_id);
+ virtual ~RendererWebIDBCursorImpl();
+
+ virtual void advance(unsigned long count, WebKit::WebIDBCallbacks* callback);
+ virtual void continueFunction(const WebKit::WebIDBKey& key,
+ WebKit::WebIDBCallbacks* callback);
+ virtual void postSuccessHandlerCallback();
+
+ void SetPrefetchData(const std::vector<IndexedDBKey>& keys,
+ const std::vector<IndexedDBKey>& primary_keys,
+ const std::vector<WebKit::WebData>& values);
+
+ void CachedContinue(WebKit::WebIDBCallbacks* callbacks);
+ void ResetPrefetchCache();
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(RendererWebIDBCursorImplTest, PrefetchTest);
+
+ int32 ipc_cursor_id_;
+
+ // Prefetch cache.
+ std::deque<IndexedDBKey> prefetch_keys_;
+ std::deque<IndexedDBKey> prefetch_primary_keys_;
+ std::deque<WebKit::WebData> prefetch_values_;
+
+ // Number of continue calls that would qualify for a pre-fetch.
+ int continue_count_;
+
+ // Number of items used from the last prefetch.
+ int used_prefetches_;
+
+ // Number of onsuccess handlers we are waiting for.
+ int pending_onsuccess_callbacks_;
+
+ // Number of items to request in next prefetch.
+ int prefetch_amount_;
+
+ enum { kInvalidCursorId = -1 };
+ enum { kPrefetchContinueThreshold = 2 };
+ enum { kMinPrefetchAmount = 5 };
+ enum { kMaxPrefetchAmount = 100 };
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_INDEXED_DB_PROXY_WEBIDBCURSOR_IMPL_H_
diff --git a/content/child/indexed_db/proxy_webidbcursor_impl_unittest.cc b/content/child/indexed_db/proxy_webidbcursor_impl_unittest.cc
new file mode 100644
index 0000000..a9c6e24
--- /dev/null
+++ b/content/child/indexed_db/proxy_webidbcursor_impl_unittest.cc
@@ -0,0 +1,151 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+#include "content/child/indexed_db/indexed_db_dispatcher.h"
+#include "content/child/indexed_db/proxy_webidbcursor_impl.h"
+#include "content/common/indexed_db/indexed_db_key.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebData.h"
+#include "third_party/WebKit/public/platform/WebIDBCallbacks.h"
+
+using WebKit::WebData;
+using WebKit::WebIDBCallbacks;
+using WebKit::WebIDBDatabase;
+using WebKit::WebIDBDatabaseError;
+using WebKit::WebIDBKey;
+
+namespace content {
+
+namespace {
+
+class MockDispatcher : public IndexedDBDispatcher {
+ public:
+ MockDispatcher()
+ : prefetch_calls_(0),
+ last_prefetch_count_(0),
+ continue_calls_(0),
+ destroyed_cursor_id_(0) {}
+
+ virtual void RequestIDBCursorPrefetch(int n,
+ WebIDBCallbacks* callbacks,
+ int32 ipc_cursor_id) OVERRIDE {
+ ++prefetch_calls_;
+ last_prefetch_count_ = n;
+ callbacks_.reset(callbacks);
+ }
+
+ virtual void RequestIDBCursorContinue(const IndexedDBKey&,
+ WebIDBCallbacks* callbacks,
+ int32 ipc_cursor_id) OVERRIDE {
+ ++continue_calls_;
+ callbacks_.reset(callbacks);
+ }
+
+ virtual void CursorDestroyed(int32 ipc_cursor_id) OVERRIDE {
+ destroyed_cursor_id_ = ipc_cursor_id;
+ }
+
+ int prefetch_calls() { return prefetch_calls_; }
+ int continue_calls() { return continue_calls_; }
+ int last_prefetch_count() { return last_prefetch_count_; }
+ int32 destroyed_cursor_id() { return destroyed_cursor_id_; }
+
+ private:
+ int prefetch_calls_;
+ int last_prefetch_count_;
+ int continue_calls_;
+ int32 destroyed_cursor_id_;
+ scoped_ptr<WebIDBCallbacks> callbacks_;
+};
+
+class MockContinueCallbacks : public WebIDBCallbacks {
+ public:
+ MockContinueCallbacks(IndexedDBKey* key = 0) : key_(key) {}
+
+ virtual void onSuccess(const WebIDBKey& key,
+ const WebIDBKey& primaryKey,
+ const WebData& value) {
+
+ if (key_)
+ *key_ = IndexedDBKey(key);
+ }
+
+ private:
+ IndexedDBKey* key_;
+};
+
+} // namespace
+
+TEST(RendererWebIDBCursorImplTest, PrefetchTest) {
+
+ WebIDBKey null_key;
+ null_key.assignNull();
+
+ MockDispatcher dispatcher;
+
+ {
+ RendererWebIDBCursorImpl cursor(RendererWebIDBCursorImpl::kInvalidCursorId);
+
+ // Call continue() until prefetching should kick in.
+ int continue_calls = 0;
+ EXPECT_EQ(dispatcher.continue_calls(), 0);
+ for (int i = 0; i < RendererWebIDBCursorImpl::kPrefetchContinueThreshold;
+ ++i) {
+ cursor.continueFunction(null_key, new MockContinueCallbacks());
+ EXPECT_EQ(++continue_calls, dispatcher.continue_calls());
+ EXPECT_EQ(0, dispatcher.prefetch_calls());
+ }
+
+ // Do enough repetitions to verify that the count grows each time,
+ // but not so many that the maximum limit is hit.
+ const int kPrefetchRepetitions = 5;
+
+ int expected_key = 0;
+ int last_prefetch_count = 0;
+ for (int repetitions = 0; repetitions < kPrefetchRepetitions;
+ ++repetitions) {
+
+ // Initiate the prefetch
+ cursor.continueFunction(null_key, new MockContinueCallbacks());
+ EXPECT_EQ(continue_calls, dispatcher.continue_calls());
+ EXPECT_EQ(repetitions + 1, dispatcher.prefetch_calls());
+
+ // Verify that the requested count has increased since last time.
+ int prefetch_count = dispatcher.last_prefetch_count();
+ EXPECT_GT(prefetch_count, last_prefetch_count);
+ last_prefetch_count = prefetch_count;
+
+ // Fill the prefetch cache as requested.
+ std::vector<IndexedDBKey> keys;
+ std::vector<IndexedDBKey> primary_keys(prefetch_count);
+ std::vector<WebData> values(prefetch_count);
+ for (int i = 0; i < prefetch_count; ++i) {
+ keys.push_back(IndexedDBKey(expected_key + i, WebIDBKey::NumberType));
+ }
+ cursor.SetPrefetchData(keys, primary_keys, values);
+
+ // Note that the real dispatcher would call cursor->CachedContinue()
+ // immediately after cursor->SetPrefetchData() to service the request
+ // that initiated the prefetch.
+
+ // Verify that the cache is used for subsequent continue() calls.
+ for (int i = 0; i < prefetch_count; ++i) {
+ IndexedDBKey key;
+ cursor.continueFunction(null_key, new MockContinueCallbacks(&key));
+ EXPECT_EQ(continue_calls, dispatcher.continue_calls());
+ EXPECT_EQ(repetitions + 1, dispatcher.prefetch_calls());
+
+ EXPECT_EQ(WebIDBKey::NumberType, key.type());
+ EXPECT_EQ(expected_key++, key.number());
+ }
+ }
+ }
+
+ EXPECT_EQ(dispatcher.destroyed_cursor_id(),
+ RendererWebIDBCursorImpl::kInvalidCursorId);
+}
+
+} // namespace content
diff --git a/content/child/indexed_db/proxy_webidbdatabase_impl.cc b/content/child/indexed_db/proxy_webidbdatabase_impl.cc
new file mode 100644
index 0000000..d120a85
--- /dev/null
+++ b/content/child/indexed_db/proxy_webidbdatabase_impl.cc
@@ -0,0 +1,264 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/indexed_db/proxy_webidbdatabase_impl.h"
+
+#include <vector>
+
+#include "content/child/indexed_db/indexed_db_dispatcher.h"
+#include "content/common/child_thread.h"
+#include "content/common/indexed_db/indexed_db_messages.h"
+#include "third_party/WebKit/public/platform/WebIDBKeyPath.h"
+#include "third_party/WebKit/public/platform/WebIDBMetadata.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/WebVector.h"
+#include "webkit/glue/worker_task_runner.h"
+
+using WebKit::WebIDBCallbacks;
+using WebKit::WebIDBDatabaseCallbacks;
+using WebKit::WebIDBMetadata;
+using WebKit::WebIDBKeyPath;
+using WebKit::WebString;
+using WebKit::WebVector;
+using webkit_glue::WorkerTaskRunner;
+
+namespace content {
+
+RendererWebIDBDatabaseImpl::RendererWebIDBDatabaseImpl(
+ int32 ipc_database_id, int32 ipc_database_callbacks_id)
+ : ipc_database_id_(ipc_database_id),
+ ipc_database_callbacks_id_(ipc_database_callbacks_id) {
+}
+
+RendererWebIDBDatabaseImpl::~RendererWebIDBDatabaseImpl() {
+ // It's not possible for there to be pending callbacks that address this
+ // object since inside WebKit, they hold a reference to the object which owns
+ // this object. But, if that ever changed, then we'd need to invalidate
+ // any such pointers.
+ IndexedDBDispatcher::Send(new IndexedDBHostMsg_DatabaseDestroyed(
+ ipc_database_id_));
+ IndexedDBDispatcher* dispatcher =
+ IndexedDBDispatcher::ThreadSpecificInstance();
+ dispatcher->DatabaseDestroyed(ipc_database_id_);
+}
+
+void RendererWebIDBDatabaseImpl::createObjectStore(
+ long long transaction_id,
+ long long object_store_id,
+ const WebKit::WebString& name,
+ const WebKit::WebIDBKeyPath& key_path,
+ bool auto_increment) {
+ IndexedDBHostMsg_DatabaseCreateObjectStore_Params params;
+ params.ipc_database_id = ipc_database_id_;
+ params.transaction_id = transaction_id;
+ params.object_store_id = object_store_id;
+ params.name = name;
+ params.key_path = IndexedDBKeyPath(key_path);
+ params.auto_increment = auto_increment;
+
+ IndexedDBDispatcher::Send(
+ new IndexedDBHostMsg_DatabaseCreateObjectStore(params));
+}
+
+void RendererWebIDBDatabaseImpl::deleteObjectStore(
+ long long transaction_id,
+ long long object_store_id) {
+ IndexedDBDispatcher::Send(
+ new IndexedDBHostMsg_DatabaseDeleteObjectStore(
+ ipc_database_id_,
+ transaction_id,
+ object_store_id));
+}
+
+void RendererWebIDBDatabaseImpl::createTransaction(
+ long long transaction_id,
+ WebKit::WebIDBDatabaseCallbacks* callbacks,
+ const WebVector<long long>& object_store_ids,
+ unsigned short mode)
+{
+ IndexedDBDispatcher* dispatcher =
+ IndexedDBDispatcher::ThreadSpecificInstance();
+ dispatcher->RequestIDBDatabaseCreateTransaction(ipc_database_id_,
+ transaction_id,
+ callbacks,
+ object_store_ids,
+ mode);
+}
+
+void RendererWebIDBDatabaseImpl::close() {
+ IndexedDBDispatcher* dispatcher =
+ IndexedDBDispatcher::ThreadSpecificInstance();
+ dispatcher->RequestIDBDatabaseClose(ipc_database_id_,
+ ipc_database_callbacks_id_);
+}
+
+void RendererWebIDBDatabaseImpl::get(
+ long long transaction_id,
+ long long object_store_id,
+ long long index_id,
+ const WebKit::WebIDBKeyRange& key_range,
+ bool key_only,
+ WebIDBCallbacks* callbacks) {
+ IndexedDBDispatcher* dispatcher =
+ IndexedDBDispatcher::ThreadSpecificInstance();
+ dispatcher->RequestIDBDatabaseGet(
+ ipc_database_id_, transaction_id, object_store_id, index_id,
+ IndexedDBKeyRange(key_range), key_only, callbacks);
+}
+
+void RendererWebIDBDatabaseImpl::put(
+ long long transaction_id,
+ long long object_store_id,
+ const WebKit::WebData& value,
+ const WebKit::WebIDBKey& key,
+ PutMode put_mode,
+ WebIDBCallbacks* callbacks,
+ const WebVector<long long>& web_index_ids,
+ const WebVector<WebIndexKeys>& web_index_keys) {
+ IndexedDBDispatcher* dispatcher =
+ IndexedDBDispatcher::ThreadSpecificInstance();
+ dispatcher->RequestIDBDatabasePut(
+ ipc_database_id_, transaction_id, object_store_id,
+ value, IndexedDBKey(key), put_mode, callbacks,
+ web_index_ids, web_index_keys);
+}
+
+void RendererWebIDBDatabaseImpl::setIndexKeys(
+ long long transaction_id,
+ long long object_store_id,
+ const WebKit::WebIDBKey& primary_key,
+ const WebVector<long long>& index_ids,
+ const WebVector<WebIndexKeys>& index_keys) {
+ IndexedDBHostMsg_DatabaseSetIndexKeys_Params params;
+ params.ipc_database_id = ipc_database_id_;
+ params.transaction_id = transaction_id;
+ params.object_store_id = object_store_id;
+ params.primary_key = IndexedDBKey(primary_key);
+ COMPILE_ASSERT(sizeof(params.index_ids[0]) ==
+ sizeof(index_ids[0]), Cant_copy);
+ params.index_ids.assign(index_ids.data(),
+ index_ids.data() + index_ids.size());
+
+ params.index_keys.resize(index_keys.size());
+ for (size_t i = 0; i < index_keys.size(); ++i) {
+ params.index_keys[i].resize(index_keys[i].size());
+ for (size_t j = 0; j < index_keys[i].size(); ++j) {
+ params.index_keys[i][j] = content::IndexedDBKey(index_keys[i][j]);
+ }
+ }
+ IndexedDBDispatcher::Send(new IndexedDBHostMsg_DatabaseSetIndexKeys(
+ params));
+}
+
+void RendererWebIDBDatabaseImpl::setIndexesReady(
+ long long transaction_id,
+ long long object_store_id,
+ const WebVector<long long>& web_index_ids) {
+ std::vector<int64> index_ids(web_index_ids.data(),
+ web_index_ids.data() + web_index_ids.size());
+ IndexedDBDispatcher::Send(new IndexedDBHostMsg_DatabaseSetIndexesReady(
+ ipc_database_id_, transaction_id, object_store_id, index_ids));
+}
+
+void RendererWebIDBDatabaseImpl::openCursor(
+ long long transaction_id,
+ long long object_store_id,
+ long long index_id,
+ const WebKit::WebIDBKeyRange& key_range,
+ unsigned short direction,
+ bool key_only,
+ TaskType task_type,
+ WebIDBCallbacks* callbacks) {
+ IndexedDBDispatcher* dispatcher =
+ IndexedDBDispatcher::ThreadSpecificInstance();
+ dispatcher->RequestIDBDatabaseOpenCursor(
+ ipc_database_id_,
+ transaction_id, object_store_id, index_id,
+ IndexedDBKeyRange(key_range), direction, key_only, task_type, callbacks);
+}
+
+void RendererWebIDBDatabaseImpl::count(
+ long long transaction_id,
+ long long object_store_id,
+ long long index_id,
+ const WebKit::WebIDBKeyRange& key_range,
+ WebIDBCallbacks* callbacks) {
+ IndexedDBDispatcher* dispatcher =
+ IndexedDBDispatcher::ThreadSpecificInstance();
+ dispatcher->RequestIDBDatabaseCount(
+ ipc_database_id_,
+ transaction_id, object_store_id, index_id,
+ IndexedDBKeyRange(key_range), callbacks);
+}
+
+void RendererWebIDBDatabaseImpl::deleteRange(
+ long long transaction_id,
+ long long object_store_id,
+ const WebKit::WebIDBKeyRange& key_range,
+ WebIDBCallbacks* callbacks) {
+ IndexedDBDispatcher* dispatcher =
+ IndexedDBDispatcher::ThreadSpecificInstance();
+ dispatcher->RequestIDBDatabaseDeleteRange(
+ ipc_database_id_,
+ transaction_id, object_store_id,
+ IndexedDBKeyRange(key_range), callbacks);
+}
+
+void RendererWebIDBDatabaseImpl::clear(
+ long long transaction_id,
+ long long object_store_id,
+ WebIDBCallbacks* callbacks) {
+ IndexedDBDispatcher* dispatcher =
+ IndexedDBDispatcher::ThreadSpecificInstance();
+ dispatcher->RequestIDBDatabaseClear(
+ ipc_database_id_,
+ transaction_id, object_store_id, callbacks);
+}
+
+void RendererWebIDBDatabaseImpl::createIndex(
+ long long transaction_id,
+ long long object_store_id,
+ long long index_id,
+ const WebString& name,
+ const WebIDBKeyPath& key_path,
+ bool unique,
+ bool multi_entry)
+{
+ IndexedDBHostMsg_DatabaseCreateIndex_Params params;
+ params.ipc_database_id = ipc_database_id_;
+ params.transaction_id = transaction_id;
+ params.object_store_id = object_store_id;
+ params.index_id = index_id;
+ params.name = name;
+ params.key_path = IndexedDBKeyPath(key_path);
+ params.unique = unique;
+ params.multi_entry = multi_entry;
+
+ IndexedDBDispatcher::Send(
+ new IndexedDBHostMsg_DatabaseCreateIndex(params));
+}
+
+void RendererWebIDBDatabaseImpl::deleteIndex(
+ long long transaction_id,
+ long long object_store_id,
+ long long index_id)
+{
+ IndexedDBDispatcher::Send(
+ new IndexedDBHostMsg_DatabaseDeleteIndex(
+ ipc_database_id_,
+ transaction_id,
+ object_store_id, index_id));
+}
+
+void RendererWebIDBDatabaseImpl::abort(long long transaction_id) {
+ IndexedDBDispatcher::Send(new IndexedDBHostMsg_DatabaseAbort(
+ ipc_database_id_, transaction_id));
+}
+
+void RendererWebIDBDatabaseImpl::commit(long long transaction_id) {
+ IndexedDBDispatcher::Send(new IndexedDBHostMsg_DatabaseCommit(
+ ipc_database_id_, transaction_id));
+}
+
+} // namespace content
diff --git a/content/child/indexed_db/proxy_webidbdatabase_impl.h b/content/child/indexed_db/proxy_webidbdatabase_impl.h
new file mode 100644
index 0000000..7a1b31a
--- /dev/null
+++ b/content/child/indexed_db/proxy_webidbdatabase_impl.h
@@ -0,0 +1,103 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_CHILD_INDEXED_DB_PROXY_WEBIDBDATABASE_IMPL_H_
+#define CONTENT_CHILD_INDEXED_DB_PROXY_WEBIDBDATABASE_IMPL_H_
+
+#include "base/basictypes.h"
+#include "third_party/WebKit/public/platform/WebIDBDatabase.h"
+
+namespace WebKit {
+class WebIDBCallbacks;
+class WebIDBDatabaseCallbacks;
+class WebString;
+}
+
+namespace content {
+
+class RendererWebIDBDatabaseImpl : public WebKit::WebIDBDatabase {
+ public:
+ explicit RendererWebIDBDatabaseImpl(int32 ipc_database_id,
+ int32 ipc_database_callbacks_id);
+ virtual ~RendererWebIDBDatabaseImpl();
+
+ // WebKit::WebIDBDatabase
+ virtual void createObjectStore(
+ long long transaction_id,
+ long long objectstore_id,
+ const WebKit::WebString& name,
+ const WebKit::WebIDBKeyPath& key_path,
+ bool auto_increment);
+ virtual void deleteObjectStore(
+ long long transaction_id,
+ long long object_store_id);
+ virtual void createTransaction(
+ long long transaction_id,
+ WebKit::WebIDBDatabaseCallbacks* callbacks,
+ const WebKit::WebVector<long long>& scope,
+ unsigned short mode);
+ virtual void close();
+ virtual void get(long long transactionId,
+ long long objectStoreId,
+ long long indexId,
+ const WebKit::WebIDBKeyRange&,
+ bool keyOnly,
+ WebKit::WebIDBCallbacks*);
+ virtual void put(long long transactionId,
+ long long objectStoreId,
+ const WebKit::WebData& value,
+ const WebKit::WebIDBKey&,
+ PutMode,
+ WebKit::WebIDBCallbacks*,
+ const WebKit::WebVector<long long>& indexIds,
+ const WebKit::WebVector<WebIndexKeys>&);
+ virtual void setIndexKeys(long long transactionId,
+ long long objectStoreId,
+ const WebKit::WebIDBKey&,
+ const WebKit::WebVector<long long>& indexIds,
+ const WebKit::WebVector<WebIndexKeys>&);
+ virtual void setIndexesReady(long long transactionId,
+ long long objectStoreId,
+ const WebKit::WebVector<long long>& indexIds);
+ virtual void openCursor(long long transactionId,
+ long long objectStoreId,
+ long long indexId,
+ const WebKit::WebIDBKeyRange&,
+ unsigned short direction,
+ bool keyOnly,
+ TaskType,
+ WebKit::WebIDBCallbacks*);
+ virtual void count(long long transactionId,
+ long long objectStoreId,
+ long long indexId,
+ const WebKit::WebIDBKeyRange&,
+ WebKit::WebIDBCallbacks*);
+ virtual void deleteRange(long long transactionId,
+ long long objectStoreId,
+ const WebKit::WebIDBKeyRange&,
+ WebKit::WebIDBCallbacks*);
+ virtual void clear(long long transactionId,
+ long long objectStoreId,
+ WebKit::WebIDBCallbacks*);
+ virtual void createIndex(long long transactionId,
+ long long objectStoreId,
+ long long indexId,
+ const WebKit::WebString& name,
+ const WebKit::WebIDBKeyPath&,
+ bool unique,
+ bool multiEntry);
+ virtual void deleteIndex(long long transactionId, long
+ long objectStoreId,
+ long long indexId);
+ virtual void abort(long long transaction_id);
+ virtual void commit(long long transaction_id);
+
+ private:
+ int32 ipc_database_id_;
+ int32 ipc_database_callbacks_id_;
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_INDEXED_DB_PROXY_WEBIDBDATABASE_IMPL_H_
diff --git a/content/child/indexed_db/proxy_webidbfactory_impl.cc b/content/child/indexed_db/proxy_webidbfactory_impl.cc
new file mode 100644
index 0000000..42a561d
--- /dev/null
+++ b/content/child/indexed_db/proxy_webidbfactory_impl.cc
@@ -0,0 +1,64 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/indexed_db/proxy_webidbfactory_impl.h"
+
+#include "content/child/indexed_db/indexed_db_dispatcher.h"
+#include "content/common/child_thread.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+
+using WebKit::WebIDBCallbacks;
+using WebKit::WebIDBDatabase;
+using WebKit::WebIDBDatabaseCallbacks;
+using WebKit::WebString;
+
+namespace content {
+
+RendererWebIDBFactoryImpl::RendererWebIDBFactoryImpl() {
+}
+
+RendererWebIDBFactoryImpl::~RendererWebIDBFactoryImpl() {
+}
+
+void RendererWebIDBFactoryImpl::getDatabaseNames(
+ WebIDBCallbacks* callbacks,
+ const WebString& database_identifier,
+ const WebString& data_dir_unused) {
+ IndexedDBDispatcher* dispatcher =
+ IndexedDBDispatcher::ThreadSpecificInstance();
+ dispatcher->RequestIDBFactoryGetDatabaseNames(
+ callbacks, database_identifier);
+}
+
+void RendererWebIDBFactoryImpl::open(
+ const WebString& name,
+ long long version,
+ long long transaction_id,
+ WebIDBCallbacks* callbacks,
+ WebIDBDatabaseCallbacks* database_callbacks,
+ const WebString& database_identifier,
+ const WebString& data_dir) {
+ // Don't send the data_dir. We know what we want on the Browser side of
+ // things.
+ IndexedDBDispatcher* dispatcher =
+ IndexedDBDispatcher::ThreadSpecificInstance();
+ dispatcher->RequestIDBFactoryOpen(
+ name, version, transaction_id, callbacks, database_callbacks,
+ database_identifier);
+}
+
+void RendererWebIDBFactoryImpl::deleteDatabase(
+ const WebString& name,
+ WebIDBCallbacks* callbacks,
+ const WebString& database_identifier,
+ const WebString& data_dir) {
+ // Don't send the data_dir. We know what we want on the Browser side of
+ // things.
+ IndexedDBDispatcher* dispatcher =
+ IndexedDBDispatcher::ThreadSpecificInstance();
+ dispatcher->RequestIDBFactoryDeleteDatabase(
+ name, callbacks, database_identifier);
+}
+
+} // namespace content
diff --git a/content/child/indexed_db/proxy_webidbfactory_impl.h b/content/child/indexed_db/proxy_webidbfactory_impl.h
new file mode 100644
index 0000000..778838b
--- /dev/null
+++ b/content/child/indexed_db/proxy_webidbfactory_impl.h
@@ -0,0 +1,46 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_CHILD_INDEXED_DB_PROXY_WEBIDBFACTORY_IMPL_H_
+#define CONTENT_CHILD_INDEXED_DB_PROXY_WEBIDBFACTORY_IMPL_H_
+
+#include "third_party/WebKit/public/platform/WebIDBCallbacks.h"
+#include "third_party/WebKit/public/platform/WebIDBDatabaseCallbacks.h"
+#include "third_party/WebKit/public/platform/WebIDBFactory.h"
+#include "third_party/WebKit/public/platform/WebVector.h"
+
+namespace WebKit {
+class WebString;
+}
+
+namespace content {
+
+class RendererWebIDBFactoryImpl : public WebKit::WebIDBFactory {
+ public:
+ RendererWebIDBFactoryImpl();
+ virtual ~RendererWebIDBFactoryImpl();
+
+ // See WebIDBFactory.h for documentation on these functions.
+ virtual void getDatabaseNames(
+ WebKit::WebIDBCallbacks* callbacks,
+ const WebKit::WebString& database_identifier,
+ const WebKit::WebString& data_dir);
+ virtual void open(
+ const WebKit::WebString& name,
+ long long version,
+ long long transaction_id,
+ WebKit::WebIDBCallbacks* callbacks,
+ WebKit::WebIDBDatabaseCallbacks* databaseCallbacks,
+ const WebKit::WebString& database_identifier,
+ const WebKit::WebString& data_dir);
+ virtual void deleteDatabase(
+ const WebKit::WebString& name,
+ WebKit::WebIDBCallbacks* callbacks,
+ const WebKit::WebString& database_identifier,
+ const WebKit::WebString& data_dir);
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_INDEXED_DB_PROXY_WEBIDBFACTORY_IMPL_H_
diff --git a/content/child/np_channel_base.cc b/content/child/np_channel_base.cc
new file mode 100644
index 0000000..34aa22b
--- /dev/null
+++ b/content/child/np_channel_base.cc
@@ -0,0 +1,305 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/np_channel_base.h"
+
+#include <stack>
+
+#include "base/auto_reset.h"
+#include "base/hash_tables.h"
+#include "base/lazy_instance.h"
+#include "base/string_number_conversions.h"
+#include "ipc/ipc_sync_message.h"
+
+#if defined(OS_POSIX)
+#include "ipc/ipc_channel_posix.h"
+#endif
+
+namespace content {
+
+typedef base::hash_map<std::string, scoped_refptr<NPChannelBase> > ChannelMap;
+static base::LazyInstance<ChannelMap>::Leaky
+ g_channels = LAZY_INSTANCE_INITIALIZER;
+
+typedef std::stack<scoped_refptr<NPChannelBase> > NPChannelRefStack;
+static base::LazyInstance<NPChannelRefStack>::Leaky
+ g_lazy_channel_stack = LAZY_INSTANCE_INITIALIZER;
+
+NPChannelBase* NPChannelBase::GetChannel(
+ const IPC::ChannelHandle& channel_handle, IPC::Channel::Mode mode,
+ ChannelFactory factory, base::MessageLoopProxy* ipc_message_loop,
+ bool create_pipe_now, base::WaitableEvent* shutdown_event) {
+ scoped_refptr<NPChannelBase> channel;
+ std::string channel_key = channel_handle.name;
+ ChannelMap::const_iterator iter = g_channels.Get().find(channel_key);
+ if (iter == g_channels.Get().end()) {
+ channel = factory();
+ } else {
+ channel = iter->second;
+ }
+
+ DCHECK(channel.get() != NULL);
+
+ if (!channel->channel_valid()) {
+ channel->channel_handle_ = channel_handle;
+ if (mode & IPC::Channel::MODE_SERVER_FLAG) {
+ channel->channel_handle_.name =
+ IPC::Channel::GenerateVerifiedChannelID(channel_key);
+ }
+ channel->mode_ = mode;
+ if (channel->Init(ipc_message_loop, create_pipe_now, shutdown_event)) {
+ g_channels.Get()[channel_key] = channel;
+ } else {
+ channel = NULL;
+ }
+ }
+
+ return channel.get();
+}
+
+void NPChannelBase::Broadcast(IPC::Message* message) {
+ for (ChannelMap::iterator iter = g_channels.Get().begin();
+ iter != g_channels.Get().end();
+ ++iter) {
+ iter->second->Send(new IPC::Message(*message));
+ }
+ delete message;
+}
+
+NPChannelBase::NPChannelBase()
+ : mode_(IPC::Channel::MODE_NONE),
+ non_npobject_count_(0),
+ peer_pid_(0),
+ in_remove_route_(false),
+ channel_valid_(false),
+ in_unblock_dispatch_(0),
+ send_unblocking_only_during_unblock_dispatch_(false) {
+}
+
+NPChannelBase::~NPChannelBase() {
+}
+
+NPChannelBase* NPChannelBase::GetCurrentChannel() {
+ return g_lazy_channel_stack.Pointer()->top().get();
+}
+
+void NPChannelBase::CleanupChannels() {
+ // Make a copy of the references as we can't iterate the map since items will
+ // be removed from it as we clean them up.
+ std::vector<scoped_refptr<NPChannelBase> > channels;
+ for (ChannelMap::const_iterator iter = g_channels.Get().begin();
+ iter != g_channels.Get().end();
+ ++iter) {
+ channels.push_back(iter->second);
+ }
+
+ for (size_t i = 0; i < channels.size(); ++i)
+ channels[i]->CleanUp();
+
+ // This will clean up channels added to the map for which subsequent
+ // AddRoute wasn't called
+ g_channels.Get().clear();
+}
+
+NPObjectBase* NPChannelBase::GetNPObjectListenerForRoute(int route_id) {
+ ListenerMap::iterator iter = npobject_listeners_.find(route_id);
+ if (iter == npobject_listeners_.end()) {
+ DLOG(WARNING) << "Invalid route id passed in:" << route_id;
+ return NULL;
+ }
+ return iter->second;
+}
+
+base::WaitableEvent* NPChannelBase::GetModalDialogEvent(int render_view_id) {
+ return NULL;
+}
+
+bool NPChannelBase::Init(base::MessageLoopProxy* ipc_message_loop,
+ bool create_pipe_now,
+ base::WaitableEvent* shutdown_event) {
+#if defined(OS_POSIX)
+ // Attempting to initialize with an invalid channel handle.
+ // See http://crbug.com/97285 for details.
+ if (mode_ == IPC::Channel::MODE_CLIENT && -1 == channel_handle_.socket.fd)
+ return false;
+#endif
+
+ channel_.reset(new IPC::SyncChannel(
+ channel_handle_, mode_, this, ipc_message_loop, create_pipe_now,
+ shutdown_event));
+
+#if defined(OS_POSIX)
+ // Check the validity of fd for bug investigation. Remove after fixed.
+ // See crbug.com/97285 for details.
+ if (mode_ == IPC::Channel::MODE_SERVER)
+ CHECK_NE(-1, channel_->GetClientFileDescriptor());
+#endif
+
+ channel_valid_ = true;
+ return true;
+}
+
+bool NPChannelBase::Send(IPC::Message* message) {
+ if (!channel_) {
+ VLOG(1) << "Channel is NULL; dropping message";
+ delete message;
+ return false;
+ }
+
+ if (send_unblocking_only_during_unblock_dispatch_ &&
+ in_unblock_dispatch_ == 0 &&
+ message->is_sync()) {
+ message->set_unblock(false);
+ }
+
+ return channel_->Send(message);
+}
+
+int NPChannelBase::Count() {
+ return static_cast<int>(g_channels.Get().size());
+}
+
+bool NPChannelBase::OnMessageReceived(const IPC::Message& message) {
+ // This call might cause us to be deleted, so keep an extra reference to
+ // ourself so that we can send the reply and decrement back in_dispatch_.
+ g_lazy_channel_stack.Pointer()->push(
+ scoped_refptr<NPChannelBase>(this));
+
+ bool handled;
+ if (message.should_unblock())
+ in_unblock_dispatch_++;
+ if (message.routing_id() == MSG_ROUTING_CONTROL) {
+ handled = OnControlMessageReceived(message);
+ } else {
+ handled = router_.RouteMessage(message);
+ if (!handled && message.is_sync()) {
+ // The listener has gone away, so we must respond or else the caller will
+ // hang waiting for a reply.
+ IPC::Message* reply = IPC::SyncMessage::GenerateReply(&message);
+ reply->set_reply_error();
+ Send(reply);
+ }
+ }
+ if (message.should_unblock())
+ in_unblock_dispatch_--;
+
+ g_lazy_channel_stack.Pointer()->pop();
+ return handled;
+}
+
+void NPChannelBase::OnChannelConnected(int32 peer_pid) {
+ peer_pid_ = peer_pid;
+}
+
+void NPChannelBase::AddRoute(int route_id,
+ IPC::Listener* listener,
+ NPObjectBase* npobject) {
+ if (npobject) {
+ npobject_listeners_[route_id] = npobject;
+ } else {
+ non_npobject_count_++;
+ }
+
+ router_.AddRoute(route_id, listener);
+}
+
+void NPChannelBase::RemoveRoute(int route_id) {
+ router_.RemoveRoute(route_id);
+
+ ListenerMap::iterator iter = npobject_listeners_.find(route_id);
+ if (iter != npobject_listeners_.end()) {
+ // This was an NPObject proxy or stub, it's not involved in the refcounting.
+
+ // If this RemoveRoute call from the NPObject is a result of us calling
+ // OnChannelError below, don't call erase() here because that'll corrupt
+ // the iterator below.
+ if (in_remove_route_) {
+ iter->second = NULL;
+ } else {
+ npobject_listeners_.erase(iter);
+ }
+
+ return;
+ }
+
+ non_npobject_count_--;
+ DCHECK(non_npobject_count_ >= 0);
+
+ if (!non_npobject_count_) {
+ base::AutoReset<bool> auto_reset_in_remove_route(&in_remove_route_, true);
+ for (ListenerMap::iterator npobj_iter = npobject_listeners_.begin();
+ npobj_iter != npobject_listeners_.end(); ++npobj_iter) {
+ if (npobj_iter->second) {
+ npobj_iter->second->GetChannelListener()->OnChannelError();
+ }
+ }
+
+ for (ChannelMap::iterator iter = g_channels.Get().begin();
+ iter != g_channels.Get().end(); ++iter) {
+ if (iter->second.get() == this) {
+ g_channels.Get().erase(iter);
+ return;
+ }
+ }
+
+ NOTREACHED();
+ }
+}
+
+bool NPChannelBase::OnControlMessageReceived(const IPC::Message& msg) {
+ NOTREACHED() <<
+ "should override in subclass if you care about control messages";
+ return false;
+}
+
+void NPChannelBase::OnChannelError() {
+ channel_valid_ = false;
+
+ // TODO(shess): http://crbug.com/97285
+ // Once an error is seen on a channel, remap the channel to prevent
+ // it from being vended again. Keep the channel in the map so
+ // RemoveRoute() can clean things up correctly.
+ for (ChannelMap::iterator iter = g_channels.Get().begin();
+ iter != g_channels.Get().end(); ++iter) {
+ if (iter->second.get() == this) {
+ // Insert new element before invalidating |iter|.
+ g_channels.Get()[iter->first + "-error"] = iter->second;
+ g_channels.Get().erase(iter);
+ break;
+ }
+ }
+}
+
+NPObject* NPChannelBase::GetExistingNPObjectProxy(int route_id) {
+ ProxyMap::iterator iter = proxy_map_.find(route_id);
+ return iter != proxy_map_.end() ? iter->second : NULL;
+}
+
+int NPChannelBase::GetExistingRouteForNPObjectStub(NPObject* npobject) {
+ StubMap::iterator iter = stub_map_.find(npobject);
+ return iter != stub_map_.end() ? iter->second : MSG_ROUTING_NONE;
+}
+
+void NPChannelBase::AddMappingForNPObjectProxy(int route_id,
+ NPObject* object) {
+ proxy_map_[route_id] = object;
+}
+
+void NPChannelBase::AddMappingForNPObjectStub(int route_id,
+ NPObject* object) {
+ DCHECK(object != NULL);
+ stub_map_[object] = route_id;
+}
+
+void NPChannelBase::RemoveMappingForNPObjectStub(int route_id,
+ NPObject* object) {
+ DCHECK(object != NULL);
+ stub_map_.erase(object);
+}
+
+void NPChannelBase::RemoveMappingForNPObjectProxy(int route_id) {
+ proxy_map_.erase(route_id);
+}
+
+} // namespace content
diff --git a/content/child/np_channel_base.h b/content/child/np_channel_base.h
new file mode 100644
index 0000000..02ada3e
--- /dev/null
+++ b/content/child/np_channel_base.h
@@ -0,0 +1,203 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_CHILD_NP_CHANNEL_BASE_H_
+#define CONTENT_CHILD_NP_CHANNEL_BASE_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/hash_tables.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/process.h"
+#include "content/child/npobject_base.h"
+#include "content/common/message_router.h"
+#include "ipc/ipc_channel_handle.h"
+#include "ipc/ipc_sync_channel.h"
+
+namespace base {
+class MessageLoopProxy;
+}
+
+#if defined(COMPILER_GCC)
+namespace BASE_HASH_NAMESPACE {
+
+template<>
+struct hash<NPObject*> {
+ std::size_t operator()(NPObject* const& ptr) const {
+ return hash<size_t>()(reinterpret_cast<size_t>(ptr));
+ }
+};
+
+} // namespace __gnu_cxx
+#elif defined(COMPILER_MSVC)
+namespace stdext {
+
+template<>
+inline size_t hash_value(NPObject* const& ptr) {
+ return hash_value(reinterpret_cast<size_t>(ptr));
+}
+
+} // namespace stdext
+#endif // COMPILER
+
+namespace content {
+
+// Encapsulates an IPC channel between a renderer and another process. Used to
+// proxy access to NP objects.
+class NPChannelBase : public IPC::Listener,
+ public IPC::Sender,
+ public base::RefCountedThreadSafe<NPChannelBase> {
+ public:
+
+ // WebPlugin[Delegate] call these on construction and destruction to setup
+ // the routing and manage lifetime of this object (they pass NULL for
+ // npobject). These are also called by NPObjectProxy and NPObjectStub (which
+ // pass themselves for npobject). However the latter don't control the
+ // lifetime of this object because we don't want a leak of an NPObject to
+ // keep the channel around longer than necessary.
+ void AddRoute(int route_id, IPC::Listener* listener, NPObjectBase* npobject);
+ void RemoveRoute(int route_id);
+
+
+ void AddMappingForNPObjectProxy(int route_id, NPObject* object);
+ void RemoveMappingForNPObjectProxy(int route_id);
+
+ void AddMappingForNPObjectStub(int route_id, NPObject* object);
+ void RemoveMappingForNPObjectStub(int route_id, NPObject* object);
+
+ NPObject* GetExistingNPObjectProxy(int route_id);
+ int GetExistingRouteForNPObjectStub(NPObject* npobject);
+
+
+ // IPC::Sender implementation:
+ virtual bool Send(IPC::Message* msg) OVERRIDE;
+
+ base::ProcessId peer_pid() { return channel_->peer_pid(); }
+ IPC::ChannelHandle channel_handle() const { return channel_handle_; }
+
+ // Returns the number of open NPObject channels in this process.
+ static int Count();
+
+ // Returns a new route id.
+ virtual int GenerateRouteID() = 0;
+
+ // Returns whether the channel is valid or not. A channel is invalid
+ // if it is disconnected due to a channel error.
+ bool channel_valid() {
+ return channel_valid_;
+ }
+
+ // Returns the most recent NPChannelBase to have received a message
+ // in this process.
+ static NPChannelBase* GetCurrentChannel();
+
+ static void CleanupChannels();
+
+ // Returns the NPObjectBase object for the route id passed in.
+ // Returns NULL on failure.
+ NPObjectBase* GetNPObjectListenerForRoute(int route_id);
+
+ // Returns the event that's set when a call to the renderer causes a modal
+ // dialog to come up. The default implementation returns NULL. Derived
+ // classes should override this method if this functionality is required.
+ virtual base::WaitableEvent* GetModalDialogEvent(int render_view_id);
+
+ protected:
+ typedef NPChannelBase* (*ChannelFactory)();
+
+ friend class base::RefCountedThreadSafe<NPChannelBase>;
+
+ virtual ~NPChannelBase();
+
+ // Returns a NPChannelBase derived object for the given channel name.
+ // If an existing channel exists returns that object, otherwise creates a
+ // new one. Even though on creation the object is refcounted, each caller
+ // must still ref count the returned value. When there are no more routes
+ // on the channel and its ref count is 0, the object deletes itself.
+ static NPChannelBase* GetChannel(
+ const IPC::ChannelHandle& channel_handle, IPC::Channel::Mode mode,
+ ChannelFactory factory, base::MessageLoopProxy* ipc_message_loop,
+ bool create_pipe_now, base::WaitableEvent* shutdown_event);
+
+ // Sends a message to all instances.
+ static void Broadcast(IPC::Message* message);
+
+ // Called on the worker thread
+ NPChannelBase();
+
+ virtual void CleanUp() { }
+
+ // Implemented by derived classes to handle control messages
+ virtual bool OnControlMessageReceived(const IPC::Message& msg);
+
+ // IPC::Listener implementation:
+ virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
+ virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
+ virtual void OnChannelError() OVERRIDE;
+
+ void set_send_unblocking_only_during_unblock_dispatch() {
+ send_unblocking_only_during_unblock_dispatch_ = true;
+ }
+
+ virtual bool Init(base::MessageLoopProxy* ipc_message_loop,
+ bool create_pipe_now,
+ base::WaitableEvent* shutdown_event);
+
+ scoped_ptr<IPC::SyncChannel> channel_;
+ IPC::ChannelHandle channel_handle_;
+
+ private:
+ IPC::Channel::Mode mode_;
+ // This tracks the number of routes registered without an NPObject. It's used
+ // to manage the lifetime of this object. See comment for AddRoute() and
+ // RemoveRoute().
+ int non_npobject_count_;
+ int peer_pid_;
+
+ // true when in the middle of a RemoveRoute call
+ bool in_remove_route_;
+
+ // Keep track of all the registered NPObjects proxies/stubs so that when the
+ // channel is closed we can inform them.
+ typedef base::hash_map<int, NPObjectBase*> ListenerMap;
+ ListenerMap npobject_listeners_;
+
+ typedef base::hash_map<int, NPObject*> ProxyMap;
+ ProxyMap proxy_map_;
+
+ typedef base::hash_map<NPObject*, int> StubMap;
+ StubMap stub_map_;
+
+ // Used to implement message routing functionality to WebPlugin[Delegate]
+ // objects
+ MessageRouter router_;
+
+ // A channel is invalid if it is disconnected as a result of a channel
+ // error. This flag is used to indicate the same.
+ bool channel_valid_;
+
+ // Track whether we're dispatching a message with the unblock flag; works like
+ // a refcount, 0 when we're not.
+ int in_unblock_dispatch_;
+
+ // If true, sync messages will only be marked as unblocking if the channel is
+ // in the middle of dispatching an unblocking message. The non-renderer
+ // process wants to avoid setting the unblock flag on its sync messages
+ // unless necessary, since it can potentially introduce reentrancy into
+ // WebKit in ways that it doesn't expect (i.e. causing layout during paint).
+ // However to avoid deadlock, we must ensure that any message that's sent as
+ // a result of a sync call from the renderer must unblock the renderer. We
+ // additionally have to do this for async messages from the renderer that
+ // have the unblock flag set, since they could be followed by a sync message
+ // that won't get dispatched until the call to the renderer is complete.
+ bool send_unblocking_only_during_unblock_dispatch_;
+
+ DISALLOW_COPY_AND_ASSIGN(NPChannelBase);
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_NP_CHANNEL_BASE_H_
diff --git a/content/child/npobject_base.h b/content/child/npobject_base.h
new file mode 100644
index 0000000..042daf7
--- /dev/null
+++ b/content/child/npobject_base.h
@@ -0,0 +1,31 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Base interface used by NPChannelBase and implemented by NPObjectProxy and
+// NPObjectStub.
+
+#ifndef CONTENT_CHILD_NPOBJECT_BASE_H_
+#define CONTENT_CHILD_NPOBJECT_BASE_H_
+
+#include "ipc/ipc_listener.h"
+#include "third_party/npapi/bindings/npruntime.h"
+
+struct NPObject;
+
+namespace content {
+
+class NPObjectBase {
+ public:
+ virtual ~NPObjectBase() {}
+
+ // Returns the underlying NPObject handled by this NPObjectBase instance.
+ virtual NPObject* GetUnderlyingNPObject() = 0;
+
+ // Returns the channel listener for this NPObjectBase instance.
+ virtual IPC::Listener* GetChannelListener() = 0;
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_NPOBJECT_BASE_H_
diff --git a/content/child/npobject_proxy.cc b/content/child/npobject_proxy.cc
new file mode 100644
index 0000000..0d0b84d
--- /dev/null
+++ b/content/child/npobject_proxy.cc
@@ -0,0 +1,507 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/npobject_proxy.h"
+
+#include "content/child/np_channel_base.h"
+#include "content/child/npobject_util.h"
+#include "content/child/plugin_messages.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/plugins/npapi/plugin_host.h"
+#include "webkit/plugins/npapi/plugin_instance.h"
+
+using WebKit::WebBindings;
+
+namespace content {
+
+struct NPObjectWrapper {
+ NPObject object;
+ NPObjectProxy* proxy;
+};
+
+NPClass NPObjectProxy::npclass_proxy_ = {
+ NP_CLASS_STRUCT_VERSION,
+ NPObjectProxy::NPAllocate,
+ NPObjectProxy::NPDeallocate,
+ NPObjectProxy::NPPInvalidate,
+ NPObjectProxy::NPHasMethod,
+ NPObjectProxy::NPInvoke,
+ NPObjectProxy::NPInvokeDefault,
+ NPObjectProxy::NPHasProperty,
+ NPObjectProxy::NPGetProperty,
+ NPObjectProxy::NPSetProperty,
+ NPObjectProxy::NPRemoveProperty,
+ NPObjectProxy::NPNEnumerate,
+ NPObjectProxy::NPNConstruct
+};
+
+NPObjectProxy* NPObjectProxy::GetProxy(NPObject* object) {
+ NPObjectProxy* proxy = NULL;
+
+ // Wrapper exists only for NPObjects that we had created.
+ if (&npclass_proxy_ == object->_class) {
+ NPObjectWrapper* wrapper = reinterpret_cast<NPObjectWrapper*>(object);
+ proxy = wrapper->proxy;
+ }
+
+ return proxy;
+}
+
+NPObject* NPObjectProxy::GetUnderlyingNPObject() {
+ return NULL;
+}
+
+IPC::Listener* NPObjectProxy::GetChannelListener() {
+ return static_cast<IPC::Listener*>(this);
+}
+
+NPObjectProxy::NPObjectProxy(
+ NPChannelBase* channel,
+ int route_id,
+ int render_view_id,
+ const GURL& page_url)
+ : channel_(channel),
+ route_id_(route_id),
+ render_view_id_(render_view_id),
+ page_url_(page_url) {
+ channel_->AddRoute(route_id, this, this);
+}
+
+NPObjectProxy::~NPObjectProxy() {
+ if (channel_.get()) {
+ // This NPObjectProxy instance is now invalid and should not be reused for
+ // requests initiated by plugins. We may receive requests for the
+ // same NPObject in the context of the outgoing NPObjectMsg_Release call.
+ // We should be creating new NPObjectProxy instances to wrap these
+ // NPObjects.
+ channel_->RemoveMappingForNPObjectProxy(route_id_);
+ channel_->RemoveRoute(route_id_);
+ Send(new NPObjectMsg_Release(route_id_));
+ }
+}
+
+NPObject* NPObjectProxy::Create(NPChannelBase* channel,
+ int route_id,
+ int render_view_id,
+ const GURL& page_url) {
+ NPObjectWrapper* obj = reinterpret_cast<NPObjectWrapper*>(
+ WebBindings::createObject(0, &npclass_proxy_));
+ obj->proxy = new NPObjectProxy(channel, route_id, render_view_id, page_url);
+ channel->AddMappingForNPObjectProxy(route_id, &obj->object);
+ return reinterpret_cast<NPObject*>(obj);
+}
+
+bool NPObjectProxy::Send(IPC::Message* msg) {
+ if (channel_.get())
+ return channel_->Send(msg);
+
+ delete msg;
+ return false;
+}
+
+NPObject* NPObjectProxy::NPAllocate(NPP, NPClass*) {
+ return reinterpret_cast<NPObject*>(new NPObjectWrapper);
+}
+
+void NPObjectProxy::NPDeallocate(NPObject* npObj) {
+ NPObjectWrapper* obj = reinterpret_cast<NPObjectWrapper*>(npObj);
+ delete obj->proxy;
+ delete obj;
+}
+
+bool NPObjectProxy::OnMessageReceived(const IPC::Message& msg) {
+ NOTREACHED();
+ return false;
+}
+
+void NPObjectProxy::OnChannelError() {
+ // Release our ref count of the plugin channel object, as it addrefs the
+ // process.
+ channel_ = NULL;
+}
+
+bool NPObjectProxy::NPHasMethod(NPObject *obj,
+ NPIdentifier name) {
+ if (obj == NULL)
+ return false;
+
+ bool result = false;
+ NPObjectProxy* proxy = GetProxy(obj);
+
+ if (!proxy) {
+ return obj->_class->hasMethod(obj, name);
+ }
+
+ NPIdentifier_Param name_param;
+ CreateNPIdentifierParam(name, &name_param);
+
+ proxy->Send(new NPObjectMsg_HasMethod(proxy->route_id(), name_param,
+ &result));
+ return result;
+}
+
+bool NPObjectProxy::NPInvoke(NPObject *obj,
+ NPIdentifier name,
+ const NPVariant *args,
+ uint32_t arg_count,
+ NPVariant *result) {
+ return NPInvokePrivate(0, obj, false, name, args, arg_count, result);
+}
+
+bool NPObjectProxy::NPInvokeDefault(NPObject *npobj,
+ const NPVariant *args,
+ uint32_t arg_count,
+ NPVariant *result) {
+ return NPInvokePrivate(0, npobj, true, 0, args, arg_count, result);
+}
+
+bool NPObjectProxy::NPInvokePrivate(NPP npp,
+ NPObject *obj,
+ bool is_default,
+ NPIdentifier name,
+ const NPVariant *args,
+ uint32_t arg_count,
+ NPVariant *np_result) {
+ if (obj == NULL)
+ return false;
+
+ NPObjectProxy* proxy = GetProxy(obj);
+ if (!proxy) {
+ if (is_default) {
+ return obj->_class->invokeDefault(obj, args, arg_count, np_result);
+ } else {
+ return obj->_class->invoke(obj, name, args, arg_count, np_result);
+ }
+ }
+
+ bool result = false;
+ int render_view_id = proxy->render_view_id_;
+ NPIdentifier_Param name_param;
+ if (is_default) {
+ // The data won't actually get used, but set it so we don't send random
+ // data.
+ name_param.identifier = NULL;
+ } else {
+ CreateNPIdentifierParam(name, &name_param);
+ }
+
+ // Note: This instance can get destroyed in the context of
+ // Send so addref the channel in this scope.
+ scoped_refptr<NPChannelBase> channel_copy = proxy->channel_;
+ std::vector<NPVariant_Param> args_param;
+ for (unsigned int i = 0; i < arg_count; ++i) {
+ NPVariant_Param param;
+ CreateNPVariantParam(args[i],
+ channel_copy.get(),
+ &param,
+ false,
+ render_view_id,
+ proxy->page_url_);
+ args_param.push_back(param);
+ }
+
+ NPVariant_Param param_result;
+ NPObjectMsg_Invoke* msg = new NPObjectMsg_Invoke(
+ proxy->route_id_, is_default, name_param, args_param, &param_result,
+ &result);
+
+ // If we're in the plugin process and this invoke leads to a dialog box, the
+ // plugin will hang the window hierarchy unless we pump the window message
+ // queue while waiting for a reply. We need to do this to simulate what
+ // happens when everything runs in-process (while calling MessageBox window
+ // messages are pumped).
+ if (IsPluginProcess() && proxy->channel()) {
+ msg->set_pump_messages_event(
+ proxy->channel()->GetModalDialogEvent(render_view_id));
+ }
+
+ GURL page_url = proxy->page_url_;
+ proxy->Send(msg);
+
+ // Send may delete proxy.
+ proxy = NULL;
+
+ if (!result)
+ return false;
+
+ CreateNPVariant(
+ param_result, channel_copy.get(), np_result, render_view_id, page_url);
+ return true;
+}
+
+bool NPObjectProxy::NPHasProperty(NPObject *obj,
+ NPIdentifier name) {
+ if (obj == NULL)
+ return false;
+
+ bool result = false;
+ NPObjectProxy* proxy = GetProxy(obj);
+ if (!proxy) {
+ return obj->_class->hasProperty(obj, name);
+ }
+
+ NPIdentifier_Param name_param;
+ CreateNPIdentifierParam(name, &name_param);
+
+ NPVariant_Param param;
+ proxy->Send(new NPObjectMsg_HasProperty(
+ proxy->route_id(), name_param, &result));
+
+ // Send may delete proxy.
+ proxy = NULL;
+
+ return result;
+}
+
+bool NPObjectProxy::NPGetProperty(NPObject *obj,
+ NPIdentifier name,
+ NPVariant *np_result) {
+ // Please refer to http://code.google.com/p/chromium/issues/detail?id=2556,
+ // which was a crash in the XStandard plugin during plugin shutdown. The
+ // crash occured because the plugin requests the plugin script object,
+ // which fails. The plugin does not check the result of the operation and
+ // invokes NPN_GetProperty on a NULL object which lead to the crash. If
+ // we observe similar crashes in other methods in the future, these null
+ // checks may have to be replicated in the other methods in this class.
+ if (obj == NULL)
+ return false;
+
+ NPObjectProxy* proxy = GetProxy(obj);
+ if (!proxy) {
+ return obj->_class->getProperty(obj, name, np_result);
+ }
+
+ bool result = false;
+ int render_view_id = proxy->render_view_id_;
+ NPIdentifier_Param name_param;
+ CreateNPIdentifierParam(name, &name_param);
+
+ NPVariant_Param param;
+ scoped_refptr<NPChannelBase> channel(proxy->channel_);
+
+ GURL page_url = proxy->page_url_;
+ proxy->Send(new NPObjectMsg_GetProperty(
+ proxy->route_id(), name_param, &param, &result));
+ // Send may delete proxy.
+ proxy = NULL;
+ if (!result)
+ return false;
+
+ CreateNPVariant(
+ param, channel.get(), np_result, render_view_id, page_url);
+
+ return true;
+}
+
+bool NPObjectProxy::NPSetProperty(NPObject *obj,
+ NPIdentifier name,
+ const NPVariant *value) {
+ if (obj == NULL)
+ return false;
+
+ NPObjectProxy* proxy = GetProxy(obj);
+ if (!proxy) {
+ return obj->_class->setProperty(obj, name, value);
+ }
+
+ bool result = false;
+ int render_view_id = proxy->render_view_id_;
+ NPIdentifier_Param name_param;
+ CreateNPIdentifierParam(name, &name_param);
+
+ NPVariant_Param value_param;
+ CreateNPVariantParam(
+ *value, proxy->channel(), &value_param, false, render_view_id,
+ proxy->page_url_);
+
+ proxy->Send(new NPObjectMsg_SetProperty(
+ proxy->route_id(), name_param, value_param, &result));
+ // Send may delete proxy.
+ proxy = NULL;
+
+ return result;
+}
+
+bool NPObjectProxy::NPRemoveProperty(NPObject *obj,
+ NPIdentifier name) {
+ if (obj == NULL)
+ return false;
+
+ bool result = false;
+ NPObjectProxy* proxy = GetProxy(obj);
+ if (!proxy) {
+ return obj->_class->removeProperty(obj, name);
+ }
+
+ NPIdentifier_Param name_param;
+ CreateNPIdentifierParam(name, &name_param);
+
+ NPVariant_Param param;
+ proxy->Send(new NPObjectMsg_RemoveProperty(
+ proxy->route_id(), name_param, &result));
+ // Send may delete proxy.
+ proxy = NULL;
+
+ return result;
+}
+
+void NPObjectProxy::NPPInvalidate(NPObject *obj) {
+ if (obj == NULL)
+ return;
+
+ NPObjectProxy* proxy = GetProxy(obj);
+ if (!proxy) {
+ obj->_class->invalidate(obj);
+ return;
+ }
+
+ proxy->Send(new NPObjectMsg_Invalidate(proxy->route_id()));
+ // Send may delete proxy.
+ proxy = NULL;
+}
+
+bool NPObjectProxy::NPNEnumerate(NPObject *obj,
+ NPIdentifier **value,
+ uint32_t *count) {
+ if (obj == NULL)
+ return false;
+
+ bool result = false;
+ NPObjectProxy* proxy = GetProxy(obj);
+ if (!proxy) {
+ if (obj->_class->structVersion >= NP_CLASS_STRUCT_VERSION_ENUM) {
+ return obj->_class->enumerate(obj, value, count);
+ } else {
+ return false;
+ }
+ }
+
+ std::vector<NPIdentifier_Param> value_param;
+ proxy->Send(new NPObjectMsg_Enumeration(
+ proxy->route_id(), &value_param, &result));
+ // Send may delete proxy.
+ proxy = NULL;
+
+ if (!result)
+ return false;
+
+ *count = static_cast<unsigned int>(value_param.size());
+ *value = static_cast<NPIdentifier *>(
+ webkit::npapi::PluginHost::Singleton()->host_functions()->memalloc(
+ sizeof(NPIdentifier) * *count));
+ for (unsigned int i = 0; i < *count; ++i)
+ (*value)[i] = CreateNPIdentifier(value_param[i]);
+
+ return true;
+}
+
+bool NPObjectProxy::NPNConstruct(NPObject *obj,
+ const NPVariant *args,
+ uint32_t arg_count,
+ NPVariant *np_result) {
+ if (obj == NULL)
+ return false;
+
+ NPObjectProxy* proxy = GetProxy(obj);
+ if (!proxy) {
+ if (obj->_class->structVersion >= NP_CLASS_STRUCT_VERSION_CTOR) {
+ return obj->_class->construct(obj, args, arg_count, np_result);
+ } else {
+ return false;
+ }
+ }
+
+ bool result = false;
+ int render_view_id = proxy->render_view_id_;
+
+ // Note: This instance can get destroyed in the context of
+ // Send so addref the channel in this scope.
+ scoped_refptr<NPChannelBase> channel_copy = proxy->channel_;
+ std::vector<NPVariant_Param> args_param;
+ for (unsigned int i = 0; i < arg_count; ++i) {
+ NPVariant_Param param;
+ CreateNPVariantParam(args[i],
+ channel_copy.get(),
+ &param,
+ false,
+ render_view_id,
+ proxy->page_url_);
+ args_param.push_back(param);
+ }
+
+ NPVariant_Param param_result;
+ NPObjectMsg_Construct* msg = new NPObjectMsg_Construct(
+ proxy->route_id_, args_param, &param_result, &result);
+
+ // See comment in NPObjectProxy::NPInvokePrivate.
+ if (IsPluginProcess() && proxy->channel()) {
+ msg->set_pump_messages_event(
+ proxy->channel()->GetModalDialogEvent(proxy->render_view_id_));
+ }
+
+ GURL page_url = proxy->page_url_;
+ proxy->Send(msg);
+
+ // Send may delete proxy.
+ proxy = NULL;
+
+ if (!result)
+ return false;
+
+ CreateNPVariant(
+ param_result, channel_copy.get(), np_result, render_view_id, page_url);
+ return true;
+}
+
+bool NPObjectProxy::NPNEvaluate(NPP npp,
+ NPObject *obj,
+ NPString *script,
+ NPVariant *result_var) {
+ NPObjectProxy* proxy = GetProxy(obj);
+ if (!proxy) {
+ return false;
+ }
+
+ bool result = false;
+ int render_view_id = proxy->render_view_id_;
+ bool popups_allowed = false;
+
+ if (npp) {
+ webkit::npapi::PluginInstance* plugin_instance =
+ reinterpret_cast<webkit::npapi::PluginInstance*>(npp->ndata);
+ if (plugin_instance)
+ popups_allowed = plugin_instance->popups_allowed();
+ }
+
+ NPVariant_Param result_param;
+ std::string script_str = std::string(
+ script->UTF8Characters, script->UTF8Length);
+
+ NPObjectMsg_Evaluate* msg = new NPObjectMsg_Evaluate(proxy->route_id(),
+ script_str,
+ popups_allowed,
+ &result_param,
+ &result);
+
+ // See comment in NPObjectProxy::NPInvokePrivate.
+ if (IsPluginProcess() && proxy->channel()) {
+ msg->set_pump_messages_event(
+ proxy->channel()->GetModalDialogEvent(render_view_id));
+ }
+ scoped_refptr<NPChannelBase> channel(proxy->channel_);
+
+ GURL page_url = proxy->page_url_;
+ proxy->Send(msg);
+ // Send may delete proxy.
+ proxy = NULL;
+ if (!result)
+ return false;
+
+ CreateNPVariant(
+ result_param, channel.get(), result_var, render_view_id, page_url);
+ return true;
+}
+
+} // namespace content
diff --git a/content/child/npobject_proxy.h b/content/child/npobject_proxy.h
new file mode 100644
index 0000000..ab7815c
--- /dev/null
+++ b/content/child/npobject_proxy.h
@@ -0,0 +1,127 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// A proxy for NPObject that sends all calls to the object to an NPObjectStub
+// running in a different process.
+
+#ifndef CONTENT_CHILD_NPOBJECT_PROXY_H_
+#define CONTENT_CHILD_NPOBJECT_PROXY_H_
+
+#include "base/memory/ref_counted.h"
+#include "content/child/npobject_base.h"
+#include "googleurl/src/gurl.h"
+#include "ipc/ipc_listener.h"
+#include "ipc/ipc_sender.h"
+#include "third_party/npapi/bindings/npruntime.h"
+#include "ui/gfx/native_widget_types.h"
+
+struct NPObject;
+
+namespace content {
+class NPChannelBase;
+
+// When running a plugin in a different process from the renderer, we need to
+// proxy calls to NPObjects across process boundaries. This happens both ways,
+// as a plugin can get an NPObject for the window, and a page can get an
+// NPObject for the plugin. In the process that interacts with the NPobject we
+// give it an NPObjectProxy instead. All calls to it are sent across an IPC
+// channel (specifically, a NPChannelBase). The NPObjectStub on the other
+// side translates the IPC messages into calls to the actual NPObject, and
+// returns the marshalled result.
+class NPObjectProxy : public IPC::Listener,
+ public IPC::Sender,
+ public NPObjectBase {
+ public:
+ virtual ~NPObjectProxy();
+
+ static NPObject* Create(NPChannelBase* channel,
+ int route_id,
+ int render_view_id,
+ const GURL& page_url);
+
+ // IPC::Sender implementation:
+ virtual bool Send(IPC::Message* msg) OVERRIDE;
+ int route_id() { return route_id_; }
+ NPChannelBase* channel() { return channel_.get(); }
+
+ // The next 9 functions are called on NPObjects from the plugin and browser.
+ static bool NPHasMethod(NPObject *obj,
+ NPIdentifier name);
+ static bool NPInvoke(NPObject *obj,
+ NPIdentifier name,
+ const NPVariant *args,
+ uint32_t arg_count,
+ NPVariant *result);
+ static bool NPInvokeDefault(NPObject *npobj,
+ const NPVariant *args,
+ uint32_t arg_count,
+ NPVariant *result);
+ static bool NPHasProperty(NPObject *obj,
+ NPIdentifier name);
+ static bool NPGetProperty(NPObject *obj,
+ NPIdentifier name,
+ NPVariant *result);
+ static bool NPSetProperty(NPObject *obj,
+ NPIdentifier name,
+ const NPVariant *value);
+ static bool NPRemoveProperty(NPObject *obj,
+ NPIdentifier name);
+ static bool NPNEnumerate(NPObject *obj,
+ NPIdentifier **value,
+ uint32_t *count);
+ static bool NPNConstruct(NPObject *npobj,
+ const NPVariant *args,
+ uint32_t arg_count,
+ NPVariant *result);
+
+ // The next two functions are only called on NPObjects from the browser.
+ static bool NPNEvaluate(NPP npp,
+ NPObject *obj,
+ NPString *script,
+ NPVariant *result);
+
+ static bool NPInvokePrivate(NPP npp,
+ NPObject *obj,
+ bool is_default,
+ NPIdentifier name,
+ const NPVariant *args,
+ uint32_t arg_count,
+ NPVariant *result);
+
+ static NPObjectProxy* GetProxy(NPObject* object);
+ static const NPClass* npclass() { return &npclass_proxy_; }
+
+ // NPObjectBase implementation.
+ virtual NPObject* GetUnderlyingNPObject() OVERRIDE;
+
+ virtual IPC::Listener* GetChannelListener() OVERRIDE;
+
+ private:
+ NPObjectProxy(NPChannelBase* channel,
+ int route_id,
+ int render_view_id,
+ const GURL& page_url);
+
+ // IPC::Listener implementation:
+ virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
+ virtual void OnChannelError() OVERRIDE;
+
+ static NPObject* NPAllocate(NPP, NPClass*);
+ static void NPDeallocate(NPObject* npObj);
+
+ // This function is only caled on NPObjects from the plugin.
+ static void NPPInvalidate(NPObject *obj);
+ static NPClass npclass_proxy_;
+
+ scoped_refptr<NPChannelBase> channel_;
+ int route_id_;
+ int render_view_id_;
+
+ // The url of the main frame hosting the plugin.
+ GURL page_url_;
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_NPOBJECT_PROXY_H_
diff --git a/content/child/npobject_stub.cc b/content/child/npobject_stub.cc
new file mode 100644
index 0000000..d3ef7a2
--- /dev/null
+++ b/content/child/npobject_stub.cc
@@ -0,0 +1,424 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/npobject_stub.h"
+
+#include "content/child/np_channel_base.h"
+#include "content/child/npobject_util.h"
+#include "content/child/plugin_messages.h"
+#include "content/public/common/content_client.h"
+#include "content/public/common/content_switches.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h"
+#include "third_party/npapi/bindings/npapi.h"
+#include "third_party/npapi/bindings/npruntime.h"
+#include "webkit/plugins/npapi/plugin_host.h"
+
+#if defined(OS_WIN)
+#include "base/command_line.h"
+#include "webkit/plugins/npapi/plugin_constants_win.h"
+#endif
+
+using WebKit::WebBindings;
+
+namespace content {
+
+NPObjectStub::NPObjectStub(
+ NPObject* npobject,
+ NPChannelBase* channel,
+ int route_id,
+ int render_view_id,
+ const GURL& page_url)
+ : npobject_(npobject),
+ channel_(channel),
+ route_id_(route_id),
+ render_view_id_(render_view_id),
+ page_url_(page_url) {
+ channel_->AddMappingForNPObjectStub(route_id, npobject);
+ channel_->AddRoute(route_id, this, this);
+
+ // We retain the object just as PluginHost does if everything was in-process.
+ WebBindings::retainObject(npobject_);
+}
+
+NPObjectStub::~NPObjectStub() {
+ channel_->RemoveRoute(route_id_);
+ DCHECK(!npobject_);
+}
+
+void NPObjectStub::DeleteSoon() {
+ if (npobject_) {
+ channel_->RemoveMappingForNPObjectStub(route_id_, npobject_);
+
+ // We need to NULL npobject_ prior to calling releaseObject() to avoid
+ // problems with re-entrancy. See http://crbug.com/94179#c17 for more
+ // details on how this can happen.
+ NPObject* npobject = npobject_;
+ npobject_ = NULL;
+
+ WebBindings::releaseObject(npobject);
+
+ base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+ }
+}
+
+bool NPObjectStub::Send(IPC::Message* msg) {
+ return channel_->Send(msg);
+}
+
+NPObject* NPObjectStub::GetUnderlyingNPObject() {
+ return npobject_;
+}
+
+IPC::Listener* NPObjectStub::GetChannelListener() {
+ return static_cast<IPC::Listener*>(this);
+}
+
+bool NPObjectStub::OnMessageReceived(const IPC::Message& msg) {
+ GetContentClient()->SetActiveURL(page_url_);
+ if (!npobject_) {
+ if (msg.is_sync()) {
+ // The object could be garbage because the frame has gone away, so
+ // just send an error reply to the caller.
+ IPC::Message* reply = IPC::SyncMessage::GenerateReply(&msg);
+ reply->set_reply_error();
+ Send(reply);
+ }
+
+ return true;
+ }
+
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(NPObjectStub, msg)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_Release, OnRelease);
+ IPC_MESSAGE_HANDLER(NPObjectMsg_HasMethod, OnHasMethod);
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_Invoke, OnInvoke);
+ IPC_MESSAGE_HANDLER(NPObjectMsg_HasProperty, OnHasProperty);
+ IPC_MESSAGE_HANDLER(NPObjectMsg_GetProperty, OnGetProperty);
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_SetProperty, OnSetProperty);
+ IPC_MESSAGE_HANDLER(NPObjectMsg_RemoveProperty, OnRemoveProperty);
+ IPC_MESSAGE_HANDLER(NPObjectMsg_Invalidate, OnInvalidate);
+ IPC_MESSAGE_HANDLER(NPObjectMsg_Enumeration, OnEnumeration);
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_Construct, OnConstruct);
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_Evaluate, OnEvaluate);
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ DCHECK(handled);
+ return handled;
+}
+
+void NPObjectStub::OnChannelError() {
+ DeleteSoon();
+}
+
+void NPObjectStub::OnRelease(IPC::Message* reply_msg) {
+ Send(reply_msg);
+ DeleteSoon();
+}
+
+void NPObjectStub::OnHasMethod(const NPIdentifier_Param& name,
+ bool* result) {
+ NPIdentifier id = CreateNPIdentifier(name);
+ // If we're in the plugin process, then the stub is holding onto an NPObject
+ // from the plugin, so all function calls on it need to go through the
+ // functions in NPClass. If we're in the renderer process, then we just call
+ // the NPN_ functions.
+ if (IsPluginProcess()) {
+ if (npobject_->_class->hasMethod) {
+ *result = npobject_->_class->hasMethod(npobject_, id);
+ } else {
+ *result = false;
+ }
+ } else {
+ *result = WebBindings::hasMethod(0, npobject_, id);
+ }
+}
+
+void NPObjectStub::OnInvoke(bool is_default,
+ const NPIdentifier_Param& method,
+ const std::vector<NPVariant_Param>& args,
+ IPC::Message* reply_msg) {
+ bool return_value = false;
+ NPVariant_Param result_param;
+ NPVariant result_var;
+
+ VOID_TO_NPVARIANT(result_var);
+ result_param.type = NPVARIANT_PARAM_VOID;
+
+ int arg_count = static_cast<int>(args.size());
+ NPVariant* args_var = new NPVariant[arg_count];
+ for (int i = 0; i < arg_count; ++i) {
+ if (!CreateNPVariant(args[i],
+ channel_.get(),
+ &(args_var[i]),
+ render_view_id_,
+ page_url_)) {
+ NPObjectMsg_Invoke::WriteReplyParams(
+ reply_msg, result_param, return_value);
+ channel_->Send(reply_msg);
+ delete[] args_var;
+ return;
+ }
+ }
+
+ if (is_default) {
+ if (IsPluginProcess()) {
+ if (npobject_->_class->invokeDefault) {
+ return_value = npobject_->_class->invokeDefault(
+ npobject_, args_var, arg_count, &result_var);
+ } else {
+ return_value = false;
+ }
+ } else {
+ return_value = WebBindings::invokeDefault(
+ 0, npobject_, args_var, arg_count, &result_var);
+ }
+ } else {
+ NPIdentifier id = CreateNPIdentifier(method);
+ if (IsPluginProcess()) {
+ if (npobject_->_class->invoke) {
+ return_value = npobject_->_class->invoke(
+ npobject_, id, args_var, arg_count, &result_var);
+ } else {
+ return_value = false;
+ }
+ } else {
+ return_value = WebBindings::invoke(
+ 0, npobject_, id, args_var, arg_count, &result_var);
+ }
+ }
+
+ for (int i = 0; i < arg_count; ++i)
+ WebBindings::releaseVariantValue(&(args_var[i]));
+
+ delete[] args_var;
+
+ CreateNPVariantParam(result_var,
+ channel_.get(),
+ &result_param,
+ true,
+ render_view_id_,
+ page_url_);
+ NPObjectMsg_Invoke::WriteReplyParams(reply_msg, result_param, return_value);
+ channel_->Send(reply_msg);
+}
+
+void NPObjectStub::OnHasProperty(const NPIdentifier_Param& name,
+ bool* result) {
+ NPIdentifier id = CreateNPIdentifier(name);
+ if (IsPluginProcess()) {
+ if (npobject_->_class->hasProperty) {
+ *result = npobject_->_class->hasProperty(npobject_, id);
+ } else {
+ *result = false;
+ }
+ } else {
+ *result = WebBindings::hasProperty(0, npobject_, id);
+ }
+}
+
+void NPObjectStub::OnGetProperty(const NPIdentifier_Param& name,
+ NPVariant_Param* property,
+ bool* result) {
+ NPVariant result_var;
+ VOID_TO_NPVARIANT(result_var);
+ NPIdentifier id = CreateNPIdentifier(name);
+
+ if (IsPluginProcess()) {
+ if (npobject_->_class->getProperty) {
+ *result = npobject_->_class->getProperty(npobject_, id, &result_var);
+ } else {
+ *result = false;
+ }
+ } else {
+ *result = WebBindings::getProperty(0, npobject_, id, &result_var);
+ }
+
+ CreateNPVariantParam(
+ result_var, channel_.get(), property, true, render_view_id_, page_url_);
+}
+
+void NPObjectStub::OnSetProperty(const NPIdentifier_Param& name,
+ const NPVariant_Param& property,
+ IPC::Message* reply_msg) {
+ bool result = false;
+ NPIdentifier id = CreateNPIdentifier(name);
+ NPVariant property_var;
+ if (!CreateNPVariant(property,
+ channel_.get(),
+ &property_var,
+ render_view_id_,
+ page_url_)) {
+ NPObjectMsg_SetProperty::WriteReplyParams(reply_msg, result);
+ channel_->Send(reply_msg);
+ return;
+ }
+
+ if (IsPluginProcess()) {
+ if (npobject_->_class->setProperty) {
+#if defined(OS_WIN)
+ static base::FilePath plugin_path =
+ CommandLine::ForCurrentProcess()->GetSwitchValuePath(
+ switches::kPluginPath);
+ static std::wstring filename = StringToLowerASCII(
+ plugin_path.BaseName().value());
+ static NPIdentifier fullscreen =
+ WebBindings::getStringIdentifier("fullScreen");
+ if (filename == webkit::npapi::kNewWMPPlugin && id == fullscreen) {
+ // Workaround for bug 15985, which is if Flash causes WMP to go
+ // full screen a deadlock can occur when WMP calls SetFocus.
+ NPObjectMsg_SetProperty::WriteReplyParams(reply_msg, true);
+ Send(reply_msg);
+ reply_msg = NULL;
+ }
+#endif
+ result = npobject_->_class->setProperty(npobject_, id, &property_var);
+ } else {
+ result = false;
+ }
+ } else {
+ result = WebBindings::setProperty(0, npobject_, id, &property_var);
+ }
+
+ WebBindings::releaseVariantValue(&property_var);
+
+ if (reply_msg) {
+ NPObjectMsg_SetProperty::WriteReplyParams(reply_msg, result);
+ Send(reply_msg);
+ }
+}
+
+void NPObjectStub::OnRemoveProperty(const NPIdentifier_Param& name,
+ bool* result) {
+ NPIdentifier id = CreateNPIdentifier(name);
+ if (IsPluginProcess()) {
+ if (npobject_->_class->removeProperty) {
+ *result = npobject_->_class->removeProperty(npobject_, id);
+ } else {
+ *result = false;
+ }
+ } else {
+ *result = WebBindings::removeProperty(0, npobject_, id);
+ }
+}
+
+void NPObjectStub::OnInvalidate() {
+ if (!IsPluginProcess()) {
+ NOTREACHED() << "Should only be called on NPObjects in the plugin";
+ return;
+ }
+
+ if (!npobject_->_class->invalidate)
+ return;
+
+ npobject_->_class->invalidate(npobject_);
+}
+
+void NPObjectStub::OnEnumeration(std::vector<NPIdentifier_Param>* value,
+ bool* result) {
+ NPIdentifier* value_np = NULL;
+ unsigned int count = 0;
+ if (!IsPluginProcess()) {
+ *result = WebBindings::enumerate(0, npobject_, &value_np, &count);
+ } else {
+ if (npobject_->_class->structVersion < NP_CLASS_STRUCT_VERSION_ENUM ||
+ !npobject_->_class->enumerate) {
+ *result = false;
+ return;
+ }
+
+ *result = npobject_->_class->enumerate(npobject_, &value_np, &count);
+ }
+
+ if (!*result)
+ return;
+
+ for (unsigned int i = 0; i < count; ++i) {
+ NPIdentifier_Param param;
+ CreateNPIdentifierParam(value_np[i], &param);
+ value->push_back(param);
+ }
+
+ webkit::npapi::PluginHost::Singleton()->host_functions()->memfree(value_np);
+}
+
+void NPObjectStub::OnConstruct(const std::vector<NPVariant_Param>& args,
+ IPC::Message* reply_msg) {
+ bool return_value = false;
+ NPVariant_Param result_param;
+ NPVariant result_var;
+
+ VOID_TO_NPVARIANT(result_var);
+
+ int arg_count = static_cast<int>(args.size());
+ NPVariant* args_var = new NPVariant[arg_count];
+ for (int i = 0; i < arg_count; ++i) {
+ if (!CreateNPVariant(args[i],
+ channel_.get(),
+ &(args_var[i]),
+ render_view_id_,
+ page_url_)) {
+ NPObjectMsg_Invoke::WriteReplyParams(
+ reply_msg, result_param, return_value);
+ channel_->Send(reply_msg);
+ delete[] args_var;
+ return;
+ }
+ }
+
+ if (IsPluginProcess()) {
+ if (npobject_->_class->structVersion >= NP_CLASS_STRUCT_VERSION_CTOR &&
+ npobject_->_class->construct) {
+ return_value = npobject_->_class->construct(
+ npobject_, args_var, arg_count, &result_var);
+ } else {
+ return_value = false;
+ }
+ } else {
+ return_value = WebBindings::construct(
+ 0, npobject_, args_var, arg_count, &result_var);
+ }
+
+ for (int i = 0; i < arg_count; ++i)
+ WebBindings::releaseVariantValue(&(args_var[i]));
+
+ delete[] args_var;
+
+ CreateNPVariantParam(result_var,
+ channel_.get(),
+ &result_param,
+ true,
+ render_view_id_,
+ page_url_);
+ NPObjectMsg_Invoke::WriteReplyParams(reply_msg, result_param, return_value);
+ channel_->Send(reply_msg);
+}
+
+void NPObjectStub::OnEvaluate(const std::string& script,
+ bool popups_allowed,
+ IPC::Message* reply_msg) {
+ if (IsPluginProcess()) {
+ NOTREACHED() << "Should only be called on NPObjects in the renderer";
+ return;
+ }
+
+ NPVariant result_var;
+ NPString script_string;
+ script_string.UTF8Characters = script.c_str();
+ script_string.UTF8Length = static_cast<unsigned int>(script.length());
+
+ bool return_value = WebBindings::evaluateHelper(0, popups_allowed, npobject_,
+ &script_string, &result_var);
+
+ NPVariant_Param result_param;
+ CreateNPVariantParam(result_var,
+ channel_.get(),
+ &result_param,
+ true,
+ render_view_id_,
+ page_url_);
+ NPObjectMsg_Evaluate::WriteReplyParams(reply_msg, result_param, return_value);
+ channel_->Send(reply_msg);
+}
+
+} // namespace content
diff --git a/content/child/npobject_stub.h b/content/child/npobject_stub.h
new file mode 100644
index 0000000..76b19b4
--- /dev/null
+++ b/content/child/npobject_stub.h
@@ -0,0 +1,99 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// A class that receives IPC messages from an NPObjectProxy and calls the real
+// NPObject.
+
+#ifndef CONTENT_CHILD_NPOBJECT_STUB_H_
+#define CONTENT_CHILD_NPOBJECT_STUB_H_
+
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "content/child/npobject_base.h"
+#include "googleurl/src/gurl.h"
+#include "ipc/ipc_listener.h"
+#include "ipc/ipc_sender.h"
+
+struct NPObject;
+
+namespace content {
+class NPChannelBase;
+struct NPIdentifier_Param;
+struct NPVariant_Param;
+
+// This wraps an NPObject and converts IPC messages from NPObjectProxy to calls
+// to the object. The results are marshalled back. See npobject_proxy.h for
+// more information.
+class NPObjectStub : public IPC::Listener,
+ public IPC::Sender,
+ public base::SupportsWeakPtr<NPObjectStub>,
+ public NPObjectBase {
+ public:
+ NPObjectStub(NPObject* npobject,
+ NPChannelBase* channel,
+ int route_id,
+ int render_view_id,
+ const GURL& page_url);
+ virtual ~NPObjectStub();
+
+ // Schedules tear-down of this stub. The underlying NPObject reference is
+ // released, and further invokations form the IPC channel will fail once this
+ // call has returned. Deletion of the stub is deferred to the main loop, in
+ // case it is touched as the stack unwinds. DeleteSoon() is safe to call
+ // more than once, until control returns to the main loop.
+ void DeleteSoon();
+
+ // IPC::Sender implementation:
+ virtual bool Send(IPC::Message* msg) OVERRIDE;
+
+ // NPObjectBase implementation.
+ virtual NPObject* GetUnderlyingNPObject() OVERRIDE;
+ virtual IPC::Listener* GetChannelListener() OVERRIDE;
+
+ private:
+ // IPC::Listener implementation:
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ virtual void OnChannelError() OVERRIDE;
+
+ // message handlers
+ void OnRelease(IPC::Message* reply_msg);
+ void OnHasMethod(const NPIdentifier_Param& name,
+ bool* result);
+ void OnInvoke(bool is_default,
+ const NPIdentifier_Param& method,
+ const std::vector<NPVariant_Param>& args,
+ IPC::Message* reply_msg);
+ void OnHasProperty(const NPIdentifier_Param& name,
+ bool* result);
+ void OnGetProperty(const NPIdentifier_Param& name,
+ NPVariant_Param* property,
+ bool* result);
+ void OnSetProperty(const NPIdentifier_Param& name,
+ const NPVariant_Param& property,
+ IPC::Message* reply_msg);
+ void OnRemoveProperty(const NPIdentifier_Param& name,
+ bool* result);
+ void OnInvalidate();
+ void OnEnumeration(std::vector<NPIdentifier_Param>* value,
+ bool* result);
+ void OnConstruct(const std::vector<NPVariant_Param>& args,
+ IPC::Message* reply_msg);
+ void OnEvaluate(const std::string& script, bool popups_allowed,
+ IPC::Message* reply_msg);
+
+ private:
+ NPObject* npobject_;
+ scoped_refptr<NPChannelBase> channel_;
+ int route_id_;
+ int render_view_id_;
+
+ // The url of the main frame hosting the plugin.
+ GURL page_url_;
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_NPOBJECT_STUB_H_
diff --git a/content/child/npobject_util.cc b/content/child/npobject_util.cc
new file mode 100644
index 0000000..c86ce91
--- /dev/null
+++ b/content/child/npobject_util.cc
@@ -0,0 +1,292 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/npobject_util.h"
+
+#include "base/string_util.h"
+#include "content/child/np_channel_base.h"
+#include "content/child/npobject_proxy.h"
+#include "content/child/plugin_messages.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h"
+#include "third_party/npapi/bindings/nphostapi.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/plugins/npapi/plugin_host.h"
+
+using WebKit::WebBindings;
+
+namespace content {
+
+// true if the current process is a plugin process, false otherwise.
+static bool g_plugin_process;
+
+namespace {
+// The next 7 functions are called by the plugin code when it's using the
+// NPObject. Plugins always ignore the functions in NPClass (except allocate
+// and deallocate), and instead just use the function pointers that were
+// passed in NPInitialize.
+// When the renderer interacts with an NPObject from the plugin, it of course
+// uses the function pointers in its NPClass structure.
+static bool NPN_HasMethodPatch(NPP npp,
+ NPObject *npobj,
+ NPIdentifier methodName) {
+ return NPObjectProxy::NPHasMethod(npobj, methodName);
+}
+
+static bool NPN_InvokePatch(NPP npp, NPObject *npobj,
+ NPIdentifier methodName,
+ const NPVariant *args,
+ uint32_t argCount,
+ NPVariant *result) {
+ return NPObjectProxy::NPInvokePrivate(npp, npobj, false, methodName, args,
+ argCount, result);
+}
+
+static bool NPN_InvokeDefaultPatch(NPP npp,
+ NPObject *npobj,
+ const NPVariant *args,
+ uint32_t argCount,
+ NPVariant *result) {
+ return NPObjectProxy::NPInvokePrivate(npp, npobj, true, 0, args, argCount,
+ result);
+}
+
+static bool NPN_HasPropertyPatch(NPP npp,
+ NPObject *npobj,
+ NPIdentifier propertyName) {
+ return NPObjectProxy::NPHasProperty(npobj, propertyName);
+}
+
+static bool NPN_GetPropertyPatch(NPP npp,
+ NPObject *npobj,
+ NPIdentifier propertyName,
+ NPVariant *result) {
+ return NPObjectProxy::NPGetProperty(npobj, propertyName, result);
+}
+
+static bool NPN_SetPropertyPatch(NPP npp,
+ NPObject *npobj,
+ NPIdentifier propertyName,
+ const NPVariant *value) {
+ return NPObjectProxy::NPSetProperty(npobj, propertyName, value);
+}
+
+static bool NPN_RemovePropertyPatch(NPP npp,
+ NPObject *npobj,
+ NPIdentifier propertyName) {
+ return NPObjectProxy::NPRemoveProperty(npobj, propertyName);
+}
+
+static bool NPN_EvaluatePatch(NPP npp,
+ NPObject *npobj,
+ NPString *script,
+ NPVariant *result) {
+ return NPObjectProxy::NPNEvaluate(npp, npobj, script, result);
+}
+
+
+static void NPN_SetExceptionPatch(NPObject *obj, const NPUTF8 *message) {
+ std::string message_str(message);
+ if (IsPluginProcess()) {
+ NPChannelBase* renderer_channel = NPChannelBase::GetCurrentChannel();
+ if (renderer_channel)
+ renderer_channel->Send(new PluginHostMsg_SetException(message_str));
+ } else {
+ WebBindings::setException(obj, message_str.c_str());
+ }
+}
+
+static bool NPN_EnumeratePatch(NPP npp, NPObject *obj,
+ NPIdentifier **identifier, uint32_t *count) {
+ return NPObjectProxy::NPNEnumerate(obj, identifier, count);
+}
+
+// The overrided table of functions provided to the plugin.
+NPNetscapeFuncs *GetHostFunctions() {
+ static bool init = false;
+ static NPNetscapeFuncs host_funcs;
+ if (init)
+ return &host_funcs;
+
+ memset(&host_funcs, 0, sizeof(host_funcs));
+ host_funcs.invoke = NPN_InvokePatch;
+ host_funcs.invokeDefault = NPN_InvokeDefaultPatch;
+ host_funcs.evaluate = NPN_EvaluatePatch;
+ host_funcs.getproperty = NPN_GetPropertyPatch;
+ host_funcs.setproperty = NPN_SetPropertyPatch;
+ host_funcs.removeproperty = NPN_RemovePropertyPatch;
+ host_funcs.hasproperty = NPN_HasPropertyPatch;
+ host_funcs.hasmethod = NPN_HasMethodPatch;
+ host_funcs.setexception = NPN_SetExceptionPatch;
+ host_funcs.enumerate = NPN_EnumeratePatch;
+
+ init = true;
+ return &host_funcs;
+}
+
+}
+
+void PatchNPNFunctions() {
+ g_plugin_process = true;
+ NPNetscapeFuncs* funcs = GetHostFunctions();
+ webkit::npapi::PluginHost::Singleton()->PatchNPNetscapeFuncs(funcs);
+}
+
+bool IsPluginProcess() {
+ return g_plugin_process;
+}
+
+void CreateNPIdentifierParam(NPIdentifier id, NPIdentifier_Param* param) {
+ param->identifier = id;
+}
+
+NPIdentifier CreateNPIdentifier(const NPIdentifier_Param& param) {
+ return param.identifier;
+}
+
+void CreateNPVariantParam(const NPVariant& variant,
+ NPChannelBase* channel,
+ NPVariant_Param* param,
+ bool release,
+ int render_view_id,
+ const GURL& page_url) {
+ switch (variant.type) {
+ case NPVariantType_Void:
+ param->type = NPVARIANT_PARAM_VOID;
+ break;
+ case NPVariantType_Null:
+ param->type = NPVARIANT_PARAM_NULL;
+ break;
+ case NPVariantType_Bool:
+ param->type = NPVARIANT_PARAM_BOOL;
+ param->bool_value = variant.value.boolValue;
+ break;
+ case NPVariantType_Int32:
+ param->type = NPVARIANT_PARAM_INT;
+ param->int_value = variant.value.intValue;
+ break;
+ case NPVariantType_Double:
+ param->type = NPVARIANT_PARAM_DOUBLE;
+ param->double_value = variant.value.doubleValue;
+ break;
+ case NPVariantType_String:
+ param->type = NPVARIANT_PARAM_STRING;
+ if (variant.value.stringValue.UTF8Length) {
+ param->string_value.assign(variant.value.stringValue.UTF8Characters,
+ variant.value.stringValue.UTF8Length);
+ }
+ break;
+ case NPVariantType_Object: {
+ if (variant.value.objectValue->_class == NPObjectProxy::npclass()) {
+ param->type = NPVARIANT_PARAM_RECEIVER_OBJECT_ROUTING_ID;
+ NPObjectProxy* proxy =
+ NPObjectProxy::GetProxy(variant.value.objectValue);
+ DCHECK(proxy);
+ param->npobject_routing_id = proxy->route_id();
+ // Don't release, because our original variant is the same as our proxy.
+ release = false;
+ } else {
+ // The channel could be NULL if there was a channel error. The caller's
+ // Send call will fail anyways.
+ if (channel) {
+ // NPObjectStub adds its own reference to the NPObject it owns, so if
+ // we were supposed to release the corresponding variant
+ // (release==true), we should still do that.
+ param->type = NPVARIANT_PARAM_SENDER_OBJECT_ROUTING_ID;
+ int route_id = channel->GetExistingRouteForNPObjectStub(
+ variant.value.objectValue);
+ if (route_id != MSG_ROUTING_NONE) {
+ param->npobject_routing_id = route_id;
+ } else {
+ route_id = channel->GenerateRouteID();
+ new NPObjectStub(
+ variant.value.objectValue, channel, route_id, render_view_id,
+ page_url);
+ param->npobject_routing_id = route_id;
+ }
+ } else {
+ param->type = NPVARIANT_PARAM_VOID;
+ }
+ }
+ break;
+ }
+ default:
+ NOTREACHED();
+ }
+
+ if (release)
+ WebBindings::releaseVariantValue(const_cast<NPVariant*>(&variant));
+}
+
+bool CreateNPVariant(const NPVariant_Param& param,
+ NPChannelBase* channel,
+ NPVariant* result,
+ int render_view_id,
+ const GURL& page_url) {
+ switch (param.type) {
+ case NPVARIANT_PARAM_VOID:
+ result->type = NPVariantType_Void;
+ break;
+ case NPVARIANT_PARAM_NULL:
+ result->type = NPVariantType_Null;
+ break;
+ case NPVARIANT_PARAM_BOOL:
+ result->type = NPVariantType_Bool;
+ result->value.boolValue = param.bool_value;
+ break;
+ case NPVARIANT_PARAM_INT:
+ result->type = NPVariantType_Int32;
+ result->value.intValue = param.int_value;
+ break;
+ case NPVARIANT_PARAM_DOUBLE:
+ result->type = NPVariantType_Double;
+ result->value.doubleValue = param.double_value;
+ break;
+ case NPVARIANT_PARAM_STRING: {
+ result->type = NPVariantType_String;
+ void* buffer = malloc(param.string_value.size());
+ size_t size = param.string_value.size();
+ result->value.stringValue.UTF8Characters = static_cast<NPUTF8*>(buffer);
+ memcpy(buffer, param.string_value.c_str(), size);
+ result->value.stringValue.UTF8Length = static_cast<int>(size);
+ break;
+ }
+ case NPVARIANT_PARAM_SENDER_OBJECT_ROUTING_ID: {
+ result->type = NPVariantType_Object;
+ NPObject* object =
+ channel->GetExistingNPObjectProxy(param.npobject_routing_id);
+ if (object) {
+ WebBindings::retainObject(object);
+ result->value.objectValue = object;
+ } else {
+ result->value.objectValue =
+ NPObjectProxy::Create(channel,
+ param.npobject_routing_id,
+ render_view_id,
+ page_url);
+ }
+ break;
+ }
+ case NPVARIANT_PARAM_RECEIVER_OBJECT_ROUTING_ID: {
+ NPObjectBase* npobject_base =
+ channel->GetNPObjectListenerForRoute(param.npobject_routing_id);
+ if (!npobject_base) {
+ DLOG(WARNING) << "Invalid routing id passed in"
+ << param.npobject_routing_id;
+ return false;
+ }
+
+ DCHECK(npobject_base->GetUnderlyingNPObject() != NULL);
+
+ result->type = NPVariantType_Object;
+ result->value.objectValue = npobject_base->GetUnderlyingNPObject();
+ WebBindings::retainObject(result->value.objectValue);
+ break;
+ }
+ default:
+ NOTREACHED();
+ }
+ return true;
+}
+
+} // namespace content
diff --git a/content/child/npobject_util.h b/content/child/npobject_util.h
new file mode 100644
index 0000000..bbf52e8
--- /dev/null
+++ b/content/child/npobject_util.h
@@ -0,0 +1,74 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Helper functions that are used by the NPObject proxy and stub.
+
+#ifndef CONTENT_CHILD_NPOBJECT_UTIL_H_
+#define CONTENT_CHILD_NPOBJECT_UTIL_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+#include "content/child/npobject_stub.h"
+
+class GURL;
+
+struct _NPVariant;
+
+typedef _NPVariant NPVariant;
+typedef void *NPIdentifier;
+
+namespace content {
+class NPChannelBase;
+struct NPIdentifier_Param;
+struct NPVariant_Param;
+
+// Needs to be called early in the plugin process lifetime, before any
+// plugin instances are initialized.
+void PatchNPNFunctions();
+
+// Returns true if the current process is a plugin process, or false otherwise.
+bool IsPluginProcess();
+
+// Creates an object similar to NPIdentifier that can be marshalled.
+void CreateNPIdentifierParam(NPIdentifier id, NPIdentifier_Param* param);
+
+// Creates an NPIdentifier from the marshalled object.
+NPIdentifier CreateNPIdentifier(const NPIdentifier_Param& param);
+
+// Creates an object similar to NPVariant that can be marshalled.
+// If the containing NPObject happens to be an NPObject, then a stub
+// is created around it and param holds the routing id for it.
+// If release is true, the NPVariant object is released (except if
+// it contains an NPObject, since the stub will manage its lifetime).
+void CreateNPVariantParam(const NPVariant& variant,
+ NPChannelBase* channel,
+ NPVariant_Param* param,
+ bool release,
+ int render_view_id,
+ const GURL& page_url);
+
+// Creates an NPVariant from the marshalled object.
+// Returns true on success.
+bool CreateNPVariant(const NPVariant_Param& param,
+ NPChannelBase* channel,
+ NPVariant* result,
+ int render_view_id,
+ const GURL& page_url);
+
+#if defined(OS_WIN)
+// Given a plugin's HWND, returns an event associated with the WebContentsImpl
+// that's set when inside a messagebox. This tells the plugin process that
+// the message queue should be pumped (as what would happen if everything was
+// in-process). This avoids deadlocks when a plugin invokes javascript that
+// causes a message box to come up.
+HANDLE GetMessageBoxEvent(HWND hwnd);
+#endif // defined(OS_WIN)
+
+} // namespace content
+
+#endif // CONTENT_CHILD_NPOBJECT_UTIL_H_
diff --git a/content/child/plugin_message_generator.cc b/content/child/plugin_message_generator.cc
new file mode 100644
index 0000000..d490345
--- /dev/null
+++ b/content/child/plugin_message_generator.cc
@@ -0,0 +1,33 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Get basic type definitions.
+#define IPC_MESSAGE_IMPL
+#include "content/child/plugin_message_generator.h"
+
+// Generate constructors.
+#include "ipc/struct_constructor_macros.h"
+#include "content/child/plugin_message_generator.h"
+
+// Generate destructors.
+#include "ipc/struct_destructor_macros.h"
+#include "content/child/plugin_message_generator.h"
+
+// Generate param traits write methods.
+#include "ipc/param_traits_write_macros.h"
+namespace IPC {
+#include "content/child/plugin_message_generator.h"
+} // namespace IPC
+
+// Generate param traits read methods.
+#include "ipc/param_traits_read_macros.h"
+namespace IPC {
+#include "content/child/plugin_message_generator.h"
+} // namespace IPC
+
+// Generate param traits log methods.
+#include "ipc/param_traits_log_macros.h"
+namespace IPC {
+#include "content/child/plugin_message_generator.h"
+} // namespace IPC
diff --git a/content/child/plugin_message_generator.h b/content/child/plugin_message_generator.h
new file mode 100644
index 0000000..9eddea2
--- /dev/null
+++ b/content/child/plugin_message_generator.h
@@ -0,0 +1,7 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Multiply-included file, hence no include guard.
+
+#include "content/child/plugin_messages.h"
diff --git a/content/child/plugin_messages.h b/content/child/plugin_messages.h
new file mode 100644
index 0000000..7c0d825
--- /dev/null
+++ b/content/child/plugin_messages.h
@@ -0,0 +1,380 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Multiply-included message file, hence no include guard.
+
+#include "build/build_config.h"
+#include "content/child/plugin_param_traits.h"
+#include "content/common/content_export.h"
+#include "content/common/content_param_traits.h"
+#include "content/public/common/common_param_traits.h"
+#include "ipc/ipc_channel_handle.h"
+#include "ipc/ipc_message_macros.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/rect.h"
+#include "webkit/common/cursors/webcursor.h"
+
+#if defined(OS_POSIX)
+#include "base/file_descriptor_posix.h"
+#endif
+
+#undef IPC_MESSAGE_EXPORT
+#define IPC_MESSAGE_EXPORT CONTENT_EXPORT
+
+#define IPC_MESSAGE_START PluginMsgStart
+
+IPC_STRUCT_BEGIN(PluginMsg_Init_Params)
+ IPC_STRUCT_MEMBER(GURL, url)
+ IPC_STRUCT_MEMBER(GURL, page_url)
+ IPC_STRUCT_MEMBER(std::vector<std::string>, arg_names)
+ IPC_STRUCT_MEMBER(std::vector<std::string>, arg_values)
+ IPC_STRUCT_MEMBER(bool, load_manually)
+ IPC_STRUCT_MEMBER(int, host_render_view_routing_id)
+IPC_STRUCT_END()
+
+IPC_STRUCT_BEGIN(PluginHostMsg_URLRequest_Params)
+ IPC_STRUCT_MEMBER(std::string, url)
+ IPC_STRUCT_MEMBER(std::string, method)
+ IPC_STRUCT_MEMBER(std::string, target)
+ IPC_STRUCT_MEMBER(std::vector<char>, buffer)
+ IPC_STRUCT_MEMBER(int, notify_id)
+ IPC_STRUCT_MEMBER(bool, popups_allowed)
+ IPC_STRUCT_MEMBER(bool, notify_redirects)
+IPC_STRUCT_END()
+
+IPC_STRUCT_BEGIN(PluginMsg_DidReceiveResponseParams)
+ IPC_STRUCT_MEMBER(unsigned long, id)
+ IPC_STRUCT_MEMBER(std::string, mime_type)
+ IPC_STRUCT_MEMBER(std::string, headers)
+ IPC_STRUCT_MEMBER(uint32, expected_length)
+ IPC_STRUCT_MEMBER(uint32, last_modified)
+ IPC_STRUCT_MEMBER(bool, request_is_seekable)
+IPC_STRUCT_END()
+
+IPC_STRUCT_BEGIN(PluginMsg_UpdateGeometry_Param)
+ IPC_STRUCT_MEMBER(gfx::Rect, window_rect)
+ IPC_STRUCT_MEMBER(gfx::Rect, clip_rect)
+ IPC_STRUCT_MEMBER(TransportDIB::Handle, windowless_buffer0)
+ IPC_STRUCT_MEMBER(TransportDIB::Handle, windowless_buffer1)
+ IPC_STRUCT_MEMBER(int, windowless_buffer_index)
+IPC_STRUCT_END()
+
+//-----------------------------------------------------------------------------
+// Plugin messages
+// These are messages sent from the renderer process to the plugin process.
+// Tells the plugin process to create a new plugin instance with the given
+// id. A corresponding WebPluginDelegateStub is created which hosts the
+// WebPluginDelegateImpl.
+IPC_SYNC_MESSAGE_CONTROL1_1(PluginMsg_CreateInstance,
+ std::string /* mime_type */,
+ int /* instance_id */)
+
+// The WebPluginDelegateProxy sends this to the WebPluginDelegateStub in its
+// destructor, so that the stub deletes the actual WebPluginDelegateImpl
+// object that it's hosting.
+IPC_SYNC_MESSAGE_CONTROL1_0(PluginMsg_DestroyInstance,
+ int /* instance_id */)
+
+IPC_SYNC_MESSAGE_CONTROL0_1(PluginMsg_GenerateRouteID,
+ int /* id */)
+
+// The messages below all map to WebPluginDelegate methods.
+IPC_SYNC_MESSAGE_ROUTED1_2(PluginMsg_Init,
+ PluginMsg_Init_Params,
+ bool /* transparent */,
+ bool /* result */)
+
+// Used to synchronously request a paint for windowless plugins.
+IPC_SYNC_MESSAGE_ROUTED1_0(PluginMsg_Paint,
+ gfx::Rect /* damaged_rect */)
+
+// Sent by the renderer after it paints from its backing store so that the
+// plugin knows it can send more invalidates.
+IPC_MESSAGE_ROUTED0(PluginMsg_DidPaint)
+
+IPC_SYNC_MESSAGE_ROUTED0_1(PluginMsg_GetPluginScriptableObject,
+ int /* route_id */)
+
+// Gets the form value of the plugin instance synchronously.
+IPC_SYNC_MESSAGE_ROUTED0_2(PluginMsg_GetFormValue,
+ string16 /* value */,
+ bool /* success */)
+
+IPC_MESSAGE_ROUTED3(PluginMsg_DidFinishLoadWithReason,
+ GURL /* url */,
+ int /* reason */,
+ int /* notify_id */)
+
+// Updates the plugin location.
+IPC_MESSAGE_ROUTED1(PluginMsg_UpdateGeometry,
+ PluginMsg_UpdateGeometry_Param)
+
+// A synchronous version of above.
+IPC_SYNC_MESSAGE_ROUTED1_0(PluginMsg_UpdateGeometrySync,
+ PluginMsg_UpdateGeometry_Param)
+
+IPC_SYNC_MESSAGE_ROUTED1_0(PluginMsg_SetFocus,
+ bool /* focused */)
+
+IPC_SYNC_MESSAGE_ROUTED1_2(PluginMsg_HandleInputEvent,
+ IPC::WebInputEventPointer /* event */,
+ bool /* handled */,
+ WebCursor /* cursor type*/)
+
+IPC_MESSAGE_ROUTED1(PluginMsg_SetContentAreaFocus,
+ bool /* has_focus */)
+
+#if defined(OS_WIN)
+IPC_MESSAGE_ROUTED4(PluginMsg_ImeCompositionUpdated,
+ string16 /* text */,
+ std::vector<int> /* clauses */,
+ std::vector<int>, /* target */
+ int /* cursor_position */)
+
+IPC_MESSAGE_ROUTED1(PluginMsg_ImeCompositionCompleted,
+ string16 /* text */)
+#endif
+
+#if defined(OS_MACOSX)
+IPC_MESSAGE_ROUTED1(PluginMsg_SetWindowFocus,
+ bool /* has_focus */)
+
+IPC_MESSAGE_ROUTED0(PluginMsg_ContainerHidden)
+
+IPC_MESSAGE_ROUTED3(PluginMsg_ContainerShown,
+ gfx::Rect /* window_frame */,
+ gfx::Rect /* view_frame */,
+ bool /* has_focus */)
+
+IPC_MESSAGE_ROUTED2(PluginMsg_WindowFrameChanged,
+ gfx::Rect /* window_frame */,
+ gfx::Rect /* view_frame */)
+
+IPC_MESSAGE_ROUTED1(PluginMsg_ImeCompositionCompleted,
+ string16 /* text */)
+#endif
+
+IPC_SYNC_MESSAGE_ROUTED3_0(PluginMsg_WillSendRequest,
+ unsigned long /* id */,
+ GURL /* url */,
+ int /* http_status_code */)
+
+IPC_MESSAGE_ROUTED1(PluginMsg_DidReceiveResponse,
+ PluginMsg_DidReceiveResponseParams)
+
+IPC_MESSAGE_ROUTED3(PluginMsg_DidReceiveData,
+ unsigned long /* id */,
+ std::vector<char> /* buffer */,
+ int /* data_offset */)
+
+IPC_MESSAGE_ROUTED1(PluginMsg_DidFinishLoading,
+ unsigned long /* id */)
+
+IPC_MESSAGE_ROUTED1(PluginMsg_DidFail,
+ unsigned long /* id */)
+
+IPC_MESSAGE_ROUTED4(PluginMsg_SendJavaScriptStream,
+ GURL /* url */,
+ std::string /* result */,
+ bool /* success */,
+ int /* notify_id */)
+
+IPC_MESSAGE_ROUTED2(PluginMsg_DidReceiveManualResponse,
+ GURL /* url */,
+ PluginMsg_DidReceiveResponseParams)
+
+IPC_MESSAGE_ROUTED1(PluginMsg_DidReceiveManualData,
+ std::vector<char> /* buffer */)
+
+IPC_MESSAGE_ROUTED0(PluginMsg_DidFinishManualLoading)
+
+IPC_MESSAGE_ROUTED0(PluginMsg_DidManualLoadFail)
+
+IPC_MESSAGE_ROUTED3(PluginMsg_HandleURLRequestReply,
+ unsigned long /* resource_id */,
+ GURL /* url */,
+ int /* notify_id */)
+
+IPC_MESSAGE_ROUTED2(PluginMsg_HTTPRangeRequestReply,
+ unsigned long /* resource_id */,
+ int /* range_request_id */)
+
+IPC_MESSAGE_CONTROL1(PluginMsg_SignalModalDialogEvent,
+ int /* render_view_id */)
+
+IPC_MESSAGE_CONTROL1(PluginMsg_ResetModalDialogEvent,
+ int /* render_view_id */)
+
+#if defined(OS_MACOSX)
+// This message, used only on 10.6 and later, transmits the "fake"
+// window handle allocated by the browser on behalf of the renderer
+// to the GPU plugin.
+IPC_MESSAGE_ROUTED1(PluginMsg_SetFakeAcceleratedSurfaceWindowHandle,
+ gfx::PluginWindowHandle /* window */)
+#endif
+
+//-----------------------------------------------------------------------------
+// PluginHost messages
+// These are messages sent from the plugin process to the renderer process.
+// They all map to the corresponding WebPlugin methods.
+// Sends the plugin window information to the renderer.
+// The window parameter is a handle to the window if the plugin is a windowed
+// plugin. It is NULL for windowless plugins.
+IPC_SYNC_MESSAGE_ROUTED1_0(PluginHostMsg_SetWindow,
+ gfx::PluginWindowHandle /* window */)
+
+#if defined(OS_WIN)
+// The modal_loop_pump_messages_event parameter is an event handle which is
+// passed in for windowless plugins and is used to indicate if messages
+// are to be pumped in sync calls to the plugin process. Currently used
+// in HandleEvent calls.
+IPC_SYNC_MESSAGE_ROUTED2_0(PluginHostMsg_SetWindowlessData,
+ HANDLE /* modal_loop_pump_messages_event */,
+ gfx::NativeViewId /* dummy_activation_window*/)
+
+// Send the IME status retrieved from a windowless plug-in. A windowless plug-in
+// uses the IME attached to a browser process as a renderer does. A plug-in
+// sends this message to control the IME status of a browser process. I would
+// note that a plug-in sends this message to a renderer process that hosts this
+// plug-in (not directly to a browser process) so the renderer process can
+// update its IME status.
+IPC_MESSAGE_ROUTED2(PluginHostMsg_NotifyIMEStatus,
+ int /* input_type */,
+ gfx::Rect /* caret_rect */)
+#endif
+
+IPC_MESSAGE_ROUTED1(PluginHostMsg_URLRequest,
+ PluginHostMsg_URLRequest_Params)
+
+IPC_MESSAGE_ROUTED1(PluginHostMsg_CancelResource,
+ int /* id */)
+
+IPC_MESSAGE_ROUTED1(PluginHostMsg_InvalidateRect,
+ gfx::Rect /* rect */)
+
+IPC_SYNC_MESSAGE_ROUTED1_1(PluginHostMsg_GetWindowScriptNPObject,
+ int /* route id */,
+ bool /* success */)
+
+IPC_SYNC_MESSAGE_ROUTED1_1(PluginHostMsg_GetPluginElement,
+ int /* route id */,
+ bool /* success */)
+
+IPC_SYNC_MESSAGE_ROUTED1_2(PluginHostMsg_ResolveProxy,
+ GURL /* url */,
+ bool /* result */,
+ std::string /* proxy list */)
+
+IPC_MESSAGE_ROUTED3(PluginHostMsg_SetCookie,
+ GURL /* url */,
+ GURL /* first_party_for_cookies */,
+ std::string /* cookie */)
+
+IPC_SYNC_MESSAGE_ROUTED2_1(PluginHostMsg_GetCookies,
+ GURL /* url */,
+ GURL /* first_party_for_cookies */,
+ std::string /* cookies */)
+
+IPC_MESSAGE_ROUTED0(PluginHostMsg_CancelDocumentLoad)
+
+IPC_MESSAGE_ROUTED3(PluginHostMsg_InitiateHTTPRangeRequest,
+ std::string /* url */,
+ std::string /* range_info */,
+ int /* range_request_id */)
+
+IPC_MESSAGE_ROUTED2(PluginHostMsg_DeferResourceLoading,
+ unsigned long /* resource_id */,
+ bool /* defer */)
+
+IPC_SYNC_MESSAGE_CONTROL1_0(PluginHostMsg_SetException,
+ std::string /* message */)
+
+IPC_MESSAGE_CONTROL0(PluginHostMsg_PluginShuttingDown)
+
+#if defined(OS_MACOSX)
+IPC_MESSAGE_ROUTED1(PluginHostMsg_FocusChanged,
+ bool /* focused */)
+
+IPC_MESSAGE_ROUTED0(PluginHostMsg_StartIme)
+
+//----------------------------------------------------------------------
+// Core Animation plugin implementation rendering via compositor.
+
+// Notifies the renderer process that this plugin will be using the
+// accelerated rendering path.
+IPC_MESSAGE_ROUTED0(PluginHostMsg_AcceleratedPluginEnabledRendering)
+
+// Notifies the renderer process that the plugin allocated a new
+// IOSurface into which it is rendering. The renderer process forwards
+// this IOSurface to the GPU process, causing it to be bound to a
+// texture from which the compositor can render. Any previous
+// IOSurface allocated by this plugin must be implicitly released by
+// the receipt of this message.
+IPC_MESSAGE_ROUTED3(PluginHostMsg_AcceleratedPluginAllocatedIOSurface,
+ int32 /* width */,
+ int32 /* height */,
+ uint32 /* surface_id */)
+
+// Notifies the renderer process that the plugin produced a new frame
+// of content into its IOSurface, and therefore that the compositor
+// needs to redraw.
+IPC_MESSAGE_ROUTED0(PluginHostMsg_AcceleratedPluginSwappedIOSurface)
+#endif
+
+IPC_MESSAGE_ROUTED2(PluginHostMsg_URLRedirectResponse,
+ bool /* allow */,
+ int /* resource_id */)
+
+
+//-----------------------------------------------------------------------------
+// NPObject messages
+// These are messages used to marshall NPObjects. They are sent both from the
+// plugin to the renderer and from the renderer to the plugin.
+IPC_SYNC_MESSAGE_ROUTED0_0(NPObjectMsg_Release)
+
+IPC_SYNC_MESSAGE_ROUTED1_1(NPObjectMsg_HasMethod,
+ content::NPIdentifier_Param /* name */,
+ bool /* result */)
+
+IPC_SYNC_MESSAGE_ROUTED3_2(NPObjectMsg_Invoke,
+ bool /* is_default */,
+ content::NPIdentifier_Param /* method */,
+ std::vector<content::NPVariant_Param> /* args */,
+ content::NPVariant_Param /* result_param */,
+ bool /* result */)
+
+IPC_SYNC_MESSAGE_ROUTED1_1(NPObjectMsg_HasProperty,
+ content::NPIdentifier_Param /* name */,
+ bool /* result */)
+
+IPC_SYNC_MESSAGE_ROUTED1_2(NPObjectMsg_GetProperty,
+ content::NPIdentifier_Param /* name */,
+ content::NPVariant_Param /* property */,
+ bool /* result */)
+
+IPC_SYNC_MESSAGE_ROUTED2_1(NPObjectMsg_SetProperty,
+ content::NPIdentifier_Param /* name */,
+ content::NPVariant_Param /* property */,
+ bool /* result */)
+
+IPC_SYNC_MESSAGE_ROUTED1_1(NPObjectMsg_RemoveProperty,
+ content::NPIdentifier_Param /* name */,
+ bool /* result */)
+
+IPC_SYNC_MESSAGE_ROUTED0_0(NPObjectMsg_Invalidate)
+
+IPC_SYNC_MESSAGE_ROUTED0_2(NPObjectMsg_Enumeration,
+ std::vector<content::NPIdentifier_Param> /* value */,
+ bool /* result */)
+
+IPC_SYNC_MESSAGE_ROUTED1_2(NPObjectMsg_Construct,
+ std::vector<content::NPVariant_Param> /* args */,
+ content::NPVariant_Param /* result_param */,
+ bool /* result */)
+
+IPC_SYNC_MESSAGE_ROUTED2_2(NPObjectMsg_Evaluate,
+ std::string /* script */,
+ bool /* popups_allowed */,
+ content::NPVariant_Param /* result_param */,
+ bool /* result */)
diff --git a/content/child/plugin_param_traits.cc b/content/child/plugin_param_traits.cc
new file mode 100644
index 0000000..53e75a4
--- /dev/null
+++ b/content/child/plugin_param_traits.cc
@@ -0,0 +1,133 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/plugin_param_traits.h"
+
+#include "base/strings/string_number_conversions.h"
+#include "ipc/ipc_message_utils.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h"
+#include "webkit/glue/npruntime_util.h"
+#include "webkit/plugins/npapi/plugin_host.h"
+
+namespace content {
+
+NPIdentifier_Param::NPIdentifier_Param()
+ : identifier() {
+}
+
+NPIdentifier_Param::~NPIdentifier_Param() {
+}
+
+NPVariant_Param::NPVariant_Param()
+ : type(NPVARIANT_PARAM_VOID),
+ bool_value(false),
+ int_value(0),
+ double_value(0),
+ npobject_routing_id(-1) {
+}
+
+NPVariant_Param::~NPVariant_Param() {
+}
+
+} // namespace content
+
+using content::NPIdentifier_Param;
+using content::NPVariant_Param;
+
+namespace IPC {
+
+void ParamTraits<NPVariant_Param>::Write(Message* m, const param_type& p) {
+ WriteParam(m, static_cast<int>(p.type));
+ if (p.type == content::NPVARIANT_PARAM_BOOL) {
+ WriteParam(m, p.bool_value);
+ } else if (p.type == content::NPVARIANT_PARAM_INT) {
+ WriteParam(m, p.int_value);
+ } else if (p.type == content::NPVARIANT_PARAM_DOUBLE) {
+ WriteParam(m, p.double_value);
+ } else if (p.type == content::NPVARIANT_PARAM_STRING) {
+ WriteParam(m, p.string_value);
+ } else if (p.type == content::NPVARIANT_PARAM_SENDER_OBJECT_ROUTING_ID ||
+ p.type == content::NPVARIANT_PARAM_RECEIVER_OBJECT_ROUTING_ID) {
+ // This is the routing id used to connect NPObjectProxy in the other
+ // process with NPObjectStub in this process or to identify the raw
+ // npobject pointer to be used in the callee process.
+ WriteParam(m, p.npobject_routing_id);
+ } else {
+ DCHECK(p.type == content::NPVARIANT_PARAM_VOID ||
+ p.type == content::NPVARIANT_PARAM_NULL);
+ }
+}
+
+bool ParamTraits<NPVariant_Param>::Read(const Message* m,
+ PickleIterator* iter,
+ param_type* r) {
+ int type;
+ if (!ReadParam(m, iter, &type))
+ return false;
+
+ bool result = false;
+ r->type = static_cast<content::NPVariant_ParamEnum>(type);
+ if (r->type == content::NPVARIANT_PARAM_BOOL) {
+ result = ReadParam(m, iter, &r->bool_value);
+ } else if (r->type == content::NPVARIANT_PARAM_INT) {
+ result = ReadParam(m, iter, &r->int_value);
+ } else if (r->type == content::NPVARIANT_PARAM_DOUBLE) {
+ result = ReadParam(m, iter, &r->double_value);
+ } else if (r->type == content::NPVARIANT_PARAM_STRING) {
+ result = ReadParam(m, iter, &r->string_value);
+ } else if (r->type == content::NPVARIANT_PARAM_SENDER_OBJECT_ROUTING_ID ||
+ r->type == content::NPVARIANT_PARAM_RECEIVER_OBJECT_ROUTING_ID) {
+ result = ReadParam(m, iter, &r->npobject_routing_id);
+ } else if ((r->type == content::NPVARIANT_PARAM_VOID) ||
+ (r->type == content::NPVARIANT_PARAM_NULL)) {
+ result = true;
+ } else {
+ NOTREACHED();
+ }
+
+ return result;
+}
+
+void ParamTraits<NPVariant_Param>::Log(const param_type& p, std::string* l) {
+ l->append(
+ base::StringPrintf("NPVariant_Param(%d, ", static_cast<int>(p.type)));
+ if (p.type == content::NPVARIANT_PARAM_BOOL) {
+ LogParam(p.bool_value, l);
+ } else if (p.type == content::NPVARIANT_PARAM_INT) {
+ LogParam(p.int_value, l);
+ } else if (p.type == content::NPVARIANT_PARAM_DOUBLE) {
+ LogParam(p.double_value, l);
+ } else if (p.type == content::NPVARIANT_PARAM_STRING) {
+ LogParam(p.string_value, l);
+ } else if (p.type == content::NPVARIANT_PARAM_SENDER_OBJECT_ROUTING_ID ||
+ p.type == content::NPVARIANT_PARAM_RECEIVER_OBJECT_ROUTING_ID) {
+ LogParam(p.npobject_routing_id, l);
+ } else {
+ l->append("<none>");
+ }
+ l->append(")");
+}
+
+void ParamTraits<NPIdentifier_Param>::Write(Message* m, const param_type& p) {
+ webkit_glue::SerializeNPIdentifier(p.identifier, m);
+}
+
+bool ParamTraits<NPIdentifier_Param>::Read(const Message* m,
+ PickleIterator* iter,
+ param_type* r) {
+ return webkit_glue::DeserializeNPIdentifier(iter, &r->identifier);
+}
+
+void ParamTraits<NPIdentifier_Param>::Log(const param_type& p, std::string* l) {
+ if (WebKit::WebBindings::identifierIsString(p.identifier)) {
+ NPUTF8* str = WebKit::WebBindings::utf8FromIdentifier(p.identifier);
+ l->append(str);
+ webkit::npapi::PluginHost::Singleton()->host_functions()->memfree(str);
+ } else {
+ l->append(base::IntToString(
+ WebKit::WebBindings::intFromIdentifier(p.identifier)));
+ }
+}
+
+} // namespace IPC
diff --git a/content/child/plugin_param_traits.h b/content/child/plugin_param_traits.h
new file mode 100644
index 0000000..b8495c6
--- /dev/null
+++ b/content/child/plugin_param_traits.h
@@ -0,0 +1,83 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is used to define IPC::ParamTraits<> specializations for a number
+// of types so that they can be serialized over IPC. IPC::ParamTraits<>
+// specializations for basic types (like int and std::string) and types in the
+// 'base' project can be found in ipc/ipc_message_utils.h. This file contains
+// specializations for types that are used by the content code, and which need
+// manual serialization code. This is usually because they're not structs with
+// public members, or because the same type is being used in multiple
+// *_messages.h headers.
+
+#ifndef CONTENT_CHILD_PLUGIN_PARAM_TRAITS_H_
+#define CONTENT_CHILD_PLUGIN_PARAM_TRAITS_H_
+
+#include <string>
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_param_traits.h"
+#include "webkit/glue/npruntime_util.h"
+
+namespace content {
+
+// Define the NPVariant_Param struct and its enum here since it needs manual
+// serialization code.
+enum NPVariant_ParamEnum {
+ NPVARIANT_PARAM_VOID,
+ NPVARIANT_PARAM_NULL,
+ NPVARIANT_PARAM_BOOL,
+ NPVARIANT_PARAM_INT,
+ NPVARIANT_PARAM_DOUBLE,
+ NPVARIANT_PARAM_STRING,
+ // Used when when the NPObject is running in the caller's process, so we
+ // create an NPObjectProxy in the other process.
+ NPVARIANT_PARAM_SENDER_OBJECT_ROUTING_ID,
+ // Used when the NPObject we're sending is running in the callee's process
+ // (i.e. we have an NPObjectProxy for it). In that case we want the callee
+ // to just use the raw pointer.
+ NPVARIANT_PARAM_RECEIVER_OBJECT_ROUTING_ID,
+};
+
+struct NPVariant_Param {
+ NPVariant_Param();
+ ~NPVariant_Param();
+
+ NPVariant_ParamEnum type;
+ bool bool_value;
+ int int_value;
+ double double_value;
+ std::string string_value;
+ int npobject_routing_id;
+};
+
+struct NPIdentifier_Param {
+ NPIdentifier_Param();
+ ~NPIdentifier_Param();
+
+ NPIdentifier identifier;
+};
+
+} // namespace content
+
+namespace IPC {
+
+template <>
+struct ParamTraits<content::NPVariant_Param> {
+ typedef content::NPVariant_Param param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct ParamTraits<content::NPIdentifier_Param> {
+ typedef content::NPIdentifier_Param param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+} // namespace IPC
+
+#endif // CONTENT_CHILD_PLUGIN_PARAM_TRAITS_H_
diff --git a/content/child/web_database_observer_impl.cc b/content/child/web_database_observer_impl.cc
new file mode 100644
index 0000000..00002aa
--- /dev/null
+++ b/content/child/web_database_observer_impl.cc
@@ -0,0 +1,169 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/web_database_observer_impl.h"
+
+#include "base/metrics/histogram.h"
+#include "base/string16.h"
+#include "content/common/database_messages.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebDatabase.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/sqlite/sqlite3.h"
+
+using WebKit::WebDatabase;
+
+namespace content {
+namespace {
+
+const int kResultHistogramSize = 50;
+const int kCallsiteHistogramSize = 10;
+
+int DetermineHistogramResult(int websql_error, int sqlite_error) {
+ // If we have a sqlite error, log it after trimming the extended bits.
+ // There are 26 possible values, but we leave room for some new ones.
+ if (sqlite_error)
+ return std::min(sqlite_error & 0xff, 30);
+
+ // Otherwise, websql_error may be an SQLExceptionCode, SQLErrorCode
+ // or a DOMExceptionCode, or -1 for success.
+ if (websql_error == -1)
+ return 0; // no error
+
+ // SQLExceptionCode starts at 1000
+ if (websql_error >= 1000)
+ websql_error -= 1000;
+
+ return std::min(websql_error + 30, kResultHistogramSize - 1);
+}
+
+#define HISTOGRAM_WEBSQL_RESULT(name, database, callsite, \
+ websql_error, sqlite_error) \
+ do { \
+ DCHECK(callsite < kCallsiteHistogramSize); \
+ int result = DetermineHistogramResult(websql_error, sqlite_error); \
+ if (database.isSyncDatabase()) { \
+ UMA_HISTOGRAM_ENUMERATION("websql.Sync." name, \
+ result, kResultHistogramSize); \
+ if (result) { \
+ UMA_HISTOGRAM_ENUMERATION("websql.Sync." name ".ErrorSite", \
+ callsite, kCallsiteHistogramSize); \
+ } \
+ } else { \
+ UMA_HISTOGRAM_ENUMERATION("websql.Async." name, \
+ result, kResultHistogramSize); \
+ if (result) { \
+ UMA_HISTOGRAM_ENUMERATION("websql.Async." name ".ErrorSite", \
+ callsite, kCallsiteHistogramSize); \
+ } \
+ } \
+ } while (0)
+
+} // namespace
+
+WebDatabaseObserverImpl::WebDatabaseObserverImpl(
+ IPC::SyncMessageFilter* sender)
+ : sender_(sender),
+ open_connections_(new webkit_database::DatabaseConnectionsWrapper) {
+ DCHECK(sender);
+}
+
+WebDatabaseObserverImpl::~WebDatabaseObserverImpl() {
+}
+
+void WebDatabaseObserverImpl::databaseOpened(
+ const WebDatabase& database) {
+ string16 origin_identifier = database.securityOrigin().databaseIdentifier();
+ string16 database_name = database.name();
+ open_connections_->AddOpenConnection(origin_identifier, database_name);
+ sender_->Send(new DatabaseHostMsg_Opened(
+ origin_identifier, database_name,
+ database.displayName(), database.estimatedSize()));
+}
+
+void WebDatabaseObserverImpl::databaseModified(
+ const WebDatabase& database) {
+ sender_->Send(new DatabaseHostMsg_Modified(
+ database.securityOrigin().databaseIdentifier(), database.name()));
+}
+
+void WebDatabaseObserverImpl::databaseClosed(
+ const WebDatabase& database) {
+ string16 origin_identifier = database.securityOrigin().databaseIdentifier();
+ string16 database_name = database.name();
+ sender_->Send(new DatabaseHostMsg_Closed(
+ origin_identifier, database_name));
+ open_connections_->RemoveOpenConnection(origin_identifier, database_name);
+}
+
+void WebDatabaseObserverImpl::reportOpenDatabaseResult(
+ const WebDatabase& database, int callsite, int websql_error,
+ int sqlite_error) {
+ HISTOGRAM_WEBSQL_RESULT("OpenResult", database, callsite,
+ websql_error, sqlite_error);
+ HandleSqliteError(database, sqlite_error);
+}
+
+void WebDatabaseObserverImpl::reportChangeVersionResult(
+ const WebDatabase& database, int callsite, int websql_error,
+ int sqlite_error) {
+ HISTOGRAM_WEBSQL_RESULT("ChangeVersionResult", database, callsite,
+ websql_error, sqlite_error);
+ HandleSqliteError(database, sqlite_error);
+}
+
+void WebDatabaseObserverImpl::reportStartTransactionResult(
+ const WebDatabase& database, int callsite, int websql_error,
+ int sqlite_error) {
+ HISTOGRAM_WEBSQL_RESULT("BeginResult", database, callsite,
+ websql_error, sqlite_error);
+ HandleSqliteError(database, sqlite_error);
+}
+
+void WebDatabaseObserverImpl::reportCommitTransactionResult(
+ const WebDatabase& database, int callsite, int websql_error,
+ int sqlite_error) {
+ HISTOGRAM_WEBSQL_RESULT("CommitResult", database, callsite,
+ websql_error, sqlite_error);
+ HandleSqliteError(database, sqlite_error);
+}
+
+void WebDatabaseObserverImpl::reportExecuteStatementResult(
+ const WebDatabase& database, int callsite, int websql_error,
+ int sqlite_error) {
+ HISTOGRAM_WEBSQL_RESULT("StatementResult", database, callsite,
+ websql_error, sqlite_error);
+ HandleSqliteError(database, sqlite_error);
+}
+
+void WebDatabaseObserverImpl::reportVacuumDatabaseResult(
+ const WebDatabase& database, int sqlite_error) {
+ int result = DetermineHistogramResult(-1, sqlite_error);
+ if (database.isSyncDatabase()) {
+ UMA_HISTOGRAM_ENUMERATION("websql.Sync.VacuumResult",
+ result, kResultHistogramSize);
+ } else {
+ UMA_HISTOGRAM_ENUMERATION("websql.Async.VacuumResult",
+ result, kResultHistogramSize);
+ }
+ HandleSqliteError(database, sqlite_error);
+}
+
+void WebDatabaseObserverImpl::WaitForAllDatabasesToClose() {
+ open_connections_->WaitForAllDatabasesToClose();
+}
+
+void WebDatabaseObserverImpl::HandleSqliteError(
+ const WebDatabase& database, int error) {
+ // We filter out errors which the backend doesn't act on to avoid
+ // a unnecessary ipc traffic, this method can get called at a fairly
+ // high frequency (per-sqlstatement).
+ if (error == SQLITE_CORRUPT || error == SQLITE_NOTADB) {
+ sender_->Send(new DatabaseHostMsg_HandleSqliteError(
+ database.securityOrigin().databaseIdentifier(),
+ database.name(),
+ error));
+ }
+}
+
+} // namespace content
diff --git a/content/child/web_database_observer_impl.h b/content/child/web_database_observer_impl.h
new file mode 100644
index 0000000..a5b7da3
--- /dev/null
+++ b/content/child/web_database_observer_impl.h
@@ -0,0 +1,53 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_CHILD_WEB_DATABASE_OBSERVER_IMPL_H_
+#define CONTENT_CHILD_WEB_DATABASE_OBSERVER_IMPL_H_
+
+#include "base/memory/ref_counted.h"
+#include "ipc/ipc_sync_message_filter.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebDatabaseObserver.h"
+#include "webkit/common/database/database_connections.h"
+
+namespace content {
+
+class WebDatabaseObserverImpl : public WebKit::WebDatabaseObserver {
+ public:
+ explicit WebDatabaseObserverImpl(IPC::SyncMessageFilter* sender);
+ virtual ~WebDatabaseObserverImpl();
+
+ virtual void databaseOpened(const WebKit::WebDatabase& database) OVERRIDE;
+ virtual void databaseModified(const WebKit::WebDatabase& database) OVERRIDE;
+ virtual void databaseClosed(const WebKit::WebDatabase& database) OVERRIDE;
+
+ virtual void reportOpenDatabaseResult(
+ const WebKit::WebDatabase& database, int callsite,
+ int websql_error, int sqlite_error) OVERRIDE;
+ virtual void reportChangeVersionResult(
+ const WebKit::WebDatabase& database, int callsite,
+ int websql_error, int sqlite_error) OVERRIDE;
+ virtual void reportStartTransactionResult(
+ const WebKit::WebDatabase& database, int callsite,
+ int websql_error, int sqlite_error) OVERRIDE;
+ virtual void reportCommitTransactionResult(
+ const WebKit::WebDatabase& database, int callsite,
+ int websql_error, int sqlite_error) OVERRIDE;
+ virtual void reportExecuteStatementResult(
+ const WebKit::WebDatabase& database, int callsite,
+ int websql_error, int sqlite_error) OVERRIDE;
+ virtual void reportVacuumDatabaseResult(
+ const WebKit::WebDatabase& database, int sqlite_error) OVERRIDE;
+
+ void WaitForAllDatabasesToClose();
+
+ private:
+ void HandleSqliteError(const WebKit::WebDatabase& database, int error);
+
+ scoped_refptr<IPC::SyncMessageFilter> sender_;
+ scoped_refptr<webkit_database::DatabaseConnectionsWrapper> open_connections_;
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_WEB_DATABASE_OBSERVER_IMPL_H_
diff --git a/content/child/webblobregistry_impl.cc b/content/child/webblobregistry_impl.cc
new file mode 100644
index 0000000..b70b883
--- /dev/null
+++ b/content/child/webblobregistry_impl.cc
@@ -0,0 +1,127 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/webblobregistry_impl.h"
+
+#include "base/memory/ref_counted.h"
+#include "base/message_loop.h"
+#include "base/shared_memory.h"
+#include "content/common/child_thread.h"
+#include "content/common/fileapi/webblob_messages.h"
+#include "content/common/thread_safe_sender.h"
+#include "third_party/WebKit/public/platform/WebBlobData.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/WebURL.h"
+#include "webkit/base/file_path_string_conversions.h"
+#include "webkit/common/blob/blob_data.h"
+
+using WebKit::WebBlobData;
+using WebKit::WebString;
+using WebKit::WebURL;
+
+namespace content {
+
+WebBlobRegistryImpl::WebBlobRegistryImpl(ThreadSafeSender* sender)
+ : sender_(sender) {
+}
+
+WebBlobRegistryImpl::~WebBlobRegistryImpl() {
+}
+
+void WebBlobRegistryImpl::registerBlobURL(
+ const WebURL& url, WebBlobData& data) {
+ DCHECK(ChildThread::current()->message_loop() ==
+ base::MessageLoop::current());
+ const size_t kLargeThresholdBytes = 250 * 1024;
+ const size_t kMaxSharedMemoryBytes = 10 * 1024 * 1024;
+
+ sender_->Send(new BlobHostMsg_StartBuildingBlob(url));
+ size_t i = 0;
+ WebBlobData::Item data_item;
+ while (data.itemAt(i++, data_item)) {
+ webkit_blob::BlobData::Item item;
+ switch (data_item.type) {
+ case WebBlobData::Item::TypeData: {
+ // WebBlobData does not allow partial data items.
+ DCHECK(!data_item.offset && data_item.length == -1);
+ if (data_item.data.size() == 0)
+ break;
+ if (data_item.data.size() < kLargeThresholdBytes) {
+ item.SetToBytes(data_item.data.data(), data_item.data.size());
+ sender_->Send(new BlobHostMsg_AppendBlobDataItem(url, item));
+ } else {
+ // We handle larger amounts of data via SharedMemory instead of
+ // writing it directly to the IPC channel.
+ size_t data_size = data_item.data.size();
+ const char* data_ptr = data_item.data.data();
+ size_t shared_memory_size = std::min(
+ data_size, kMaxSharedMemoryBytes);
+ scoped_ptr<base::SharedMemory> shared_memory(
+ ChildThread::AllocateSharedMemory(shared_memory_size,
+ sender_.get()));
+ CHECK(shared_memory.get());
+ while (data_size) {
+ size_t chunk_size = std::min(data_size, shared_memory_size);
+ memcpy(shared_memory->memory(), data_ptr, chunk_size);
+ sender_->Send(new BlobHostMsg_SyncAppendSharedMemory(
+ url, shared_memory->handle(), chunk_size));
+ data_size -= chunk_size;
+ data_ptr += chunk_size;
+ }
+ }
+ break;
+ }
+ case WebBlobData::Item::TypeFile:
+ if (data_item.length) {
+ item.SetToFilePathRange(
+ webkit_base::WebStringToFilePath(data_item.filePath),
+ static_cast<uint64>(data_item.offset),
+ static_cast<uint64>(data_item.length),
+ base::Time::FromDoubleT(data_item.expectedModificationTime));
+ sender_->Send(new BlobHostMsg_AppendBlobDataItem(url, item));
+ }
+ break;
+ case WebBlobData::Item::TypeBlob:
+ if (data_item.length) {
+ item.SetToBlobUrlRange(
+ data_item.blobURL,
+ static_cast<uint64>(data_item.offset),
+ static_cast<uint64>(data_item.length));
+ sender_->Send(new BlobHostMsg_AppendBlobDataItem(url, item));
+ }
+ break;
+ case WebBlobData::Item::TypeURL:
+ if (data_item.length) {
+ // We only support filesystem URL as of now.
+ DCHECK(GURL(data_item.url).SchemeIsFileSystem());
+ item.SetToFileSystemUrlRange(
+ data_item.url,
+ static_cast<uint64>(data_item.offset),
+ static_cast<uint64>(data_item.length),
+ base::Time::FromDoubleT(data_item.expectedModificationTime));
+ sender_->Send(new BlobHostMsg_AppendBlobDataItem(url, item));
+ }
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+ sender_->Send(new BlobHostMsg_FinishBuildingBlob(
+ url, data.contentType().utf8().data()));
+}
+
+void WebBlobRegistryImpl::registerBlobURL(
+ const WebURL& url, const WebURL& src_url) {
+ DCHECK(ChildThread::current()->message_loop() ==
+ base::MessageLoop::current());
+ sender_->Send(new BlobHostMsg_CloneBlob(url, src_url));
+}
+
+void WebBlobRegistryImpl::unregisterBlobURL(const WebURL& url) {
+ DCHECK(ChildThread::current()->message_loop() ==
+ base::MessageLoop::current());
+ sender_->Send(new BlobHostMsg_RemoveBlob(url));
+}
+
+} // namespace content
diff --git a/content/child/webblobregistry_impl.h b/content/child/webblobregistry_impl.h
new file mode 100644
index 0000000..a624cfc
--- /dev/null
+++ b/content/child/webblobregistry_impl.h
@@ -0,0 +1,36 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_CHILD_FILEAPI_WEBBLOBREGISTRY_IMPL_H_
+#define CONTENT_CHILD_FILEAPI_WEBBLOBREGISTRY_IMPL_H_
+
+#include "base/memory/ref_counted.h"
+#include "third_party/WebKit/public/platform/WebBlobRegistry.h"
+
+namespace WebKit {
+class WebBlobData;
+class WebURL;
+}
+
+namespace content {
+class ThreadSafeSender;
+
+class WebBlobRegistryImpl : public WebKit::WebBlobRegistry {
+ public:
+ explicit WebBlobRegistryImpl(ThreadSafeSender* sender);
+ virtual ~WebBlobRegistryImpl();
+
+ virtual void registerBlobURL(const WebKit::WebURL& url,
+ WebKit::WebBlobData& data);
+ virtual void registerBlobURL(const WebKit::WebURL& url,
+ const WebKit::WebURL& src_url);
+ virtual void unregisterBlobURL(const WebKit::WebURL& url);
+
+ private:
+ scoped_refptr<ThreadSafeSender> sender_;
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_FILEAPI_WEBBLOBREGISTRY_IMPL_H_