diff options
author | Ben Murdoch <benm@google.com> | 2010-08-06 12:13:06 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2010-08-18 15:49:13 +0100 |
commit | 06741cbc25cd4227a9fba40dfd0273bfcc1a587a (patch) | |
tree | ca6f21dec86a8c4f6d3c50e78628c0cf31da0353 /chrome/common | |
parent | aa0bf16ed53445f227734aee4274c7aef056f032 (diff) | |
download | external_chromium-06741cbc25cd4227a9fba40dfd0273bfcc1a587a.zip external_chromium-06741cbc25cd4227a9fba40dfd0273bfcc1a587a.tar.gz external_chromium-06741cbc25cd4227a9fba40dfd0273bfcc1a587a.tar.bz2 |
Add chrome/common @ 52593
Needed by autofill
Change-Id: Ibfea9ab92382af0bd0cfc6e94d21e4baa4b9d896
Diffstat (limited to 'chrome/common')
277 files changed, 39486 insertions, 0 deletions
diff --git a/chrome/common/DEPS b/chrome/common/DEPS new file mode 100644 index 0000000..2f3b9b0 --- /dev/null +++ b/chrome/common/DEPS @@ -0,0 +1,22 @@ +include_rules = [ + "+chrome/plugin", # For checking whether we're a plugin process. + "+chrome/default_plugin", + "+grit", # For generated headers + "+libxml", + "+media/audio", + "+remoting/client/plugin", + "+sandbox/src", + "+skia/include", + "+webkit/glue", + + # Other libraries. + "+chrome/third_party/xdg_user_dirs", + "+third_party/bzip2", + "+third_party/npapi", + "+third_party/sqlite", + "+third_party/zlib", + + # FIXME - refactor code and remove these dependencies + "+chrome/app", + "+chrome/installer", +] diff --git a/chrome/common/about_handler.cc b/chrome/common/about_handler.cc new file mode 100644 index 0000000..84658a0 --- /dev/null +++ b/chrome/common/about_handler.cc @@ -0,0 +1,34 @@ +// Copyright (c) 2010 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 "chrome/common/about_handler.h" + +namespace chrome_about_handler { + +// This needs to match up with about_urls_handlers in +// chrome/renderer/about_handler.cc. +const char* const about_urls[] = { + chrome::kAboutCrashURL, + chrome::kAboutHangURL, + chrome::kAboutShorthangURL, + NULL, +}; +const size_t about_urls_size = arraysize(about_urls); + +const char* const kAboutScheme = "about"; + +bool WillHandle(const GURL& url) { + if (url.scheme() != kAboutScheme) + return false; + + const char* const* url_handler = about_urls; + while (*url_handler) { + if (GURL(*url_handler) == url) + return true; + url_handler++; + } + return false; +} + +} // namespace chrome_about_handler diff --git a/chrome/common/about_handler.h b/chrome/common/about_handler.h new file mode 100644 index 0000000..f5d0818 --- /dev/null +++ b/chrome/common/about_handler.h @@ -0,0 +1,23 @@ +// Copyright (c) 2010 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 CHROME_COMMON_ABOUT_HANDLER_H__ +#define CHROME_COMMON_ABOUT_HANDLER_H__ + +#include "chrome/common/url_constants.h" +#include "googleurl/src/gurl.h" + +namespace chrome_about_handler { + +extern const char* const about_urls[]; +extern const size_t about_urls_size; // Only used for testing +extern const char* const kAboutScheme; + +// Returns true if the URL is one that AboutHandler will handle when +// AboutHandler::MaybeHandle is called. +bool WillHandle(const GURL& url); + +} // namespace chrome_about_handler + +#endif // CHROME_COMMON_ABOUT_HANDLER_H__ diff --git a/chrome/common/app_mode_common_mac.h b/chrome/common/app_mode_common_mac.h new file mode 100644 index 0000000..046324a --- /dev/null +++ b/chrome/common/app_mode_common_mac.h @@ -0,0 +1,66 @@ +// Copyright (c) 2010 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 CHROME_COMMON_APP_MODE_COMMON_MAC_H_ +#define CHROME_COMMON_APP_MODE_COMMON_MAC_H_ + +#include <CoreFoundation/CoreFoundation.h> + +// This file contains constants, interfaces, etc. which are common to the +// browser application and the app mode loader (a.k.a. shim). + +namespace app_mode { + +// The ID under which app mode preferences will be recorded +// ("org.chromium.Chromium" or "com.google.Chrome"). +extern const CFStringRef kAppPrefsID; + +// The key under which to record the path to the (user-visible) application +// bundle; this key is recorded under the ID given by |kAppPrefsID|. +extern const CFStringRef kLastRunAppBundlePathPrefsKey; + +// Current major/minor version numbers of |ChromeAppModeInfo| (defined below). +const unsigned kCurrentChromeAppModeInfoMajorVersion = 1; +const unsigned kCurrentChromeAppModeInfoMinorVersion = 0; + +// The structure used to pass information from the app mode loader to the +// (browser) framework. This is versioned using major and minor version numbers, +// written below as v<major>.<minor>. Version-number checking is done by the +// framework, and the framework must accept all structures with the same major +// version number. It may refuse to load if the major version of the structure +// is different from the one it accepts. +struct ChromeAppModeInfo { + // Major and minor version number of this structure. + unsigned major_version; // Required: all versions + unsigned minor_version; // Required: all versions + + // Original |argc| and |argv|. + int argc; // Required: v1.0 + char** argv; // Required: v1.0 + + // Versioned path to the browser which is being loaded. + char* chrome_versioned_path; // Required: v1.0 + + // Information about the App Mode shortcut: + + // Path to the App Mode Loader application bundle originally run. + char* app_mode_bundle_path; // Optional: v1.0 + + // Short ID string, preferably derived from |app_mode_short_name|. Should be + // safe for the file system. + char* app_mode_id; // Required: v1.0 + + // Short (e.g., one-word) UTF8-encoded name for the shortcut. + char* app_mode_short_name; // Optional: v1.0 + + // Unrestricted (e.g., several-word) UTF8-encoded name for the shortcut. + char* app_mode_name; // Optional: v1.0 + + // URL for the shortcut. Must be a valid URL. + char* app_mode_url; // Required: v1.0 +}; + +} // namespace app_mode + +#endif // CHROME_COMMON_APP_MODE_COMMON_MAC_H_ diff --git a/chrome/common/app_mode_common_mac.mm b/chrome/common/app_mode_common_mac.mm new file mode 100644 index 0000000..3705c34 --- /dev/null +++ b/chrome/common/app_mode_common_mac.mm @@ -0,0 +1,17 @@ +// Copyright (c) 2010 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 "chrome/common/app_mode_common_mac.h" + +namespace app_mode { + +#if defined(GOOGLE_CHROME_BUILD) +const CFStringRef kAppPrefsID = CFSTR("com.google.Chrome"); +#else +const CFStringRef kAppPrefsID = CFSTR("org.chromium.Chromium"); +#endif + +const CFStringRef kLastRunAppBundlePathPrefsKey = CFSTR("LastRunAppBundlePath"); + +} // namespace app_mode diff --git a/chrome/common/appcache/appcache_backend_proxy.cc b/chrome/common/appcache/appcache_backend_proxy.cc new file mode 100644 index 0000000..e1776db --- /dev/null +++ b/chrome/common/appcache/appcache_backend_proxy.cc @@ -0,0 +1,65 @@ +// Copyright (c) 2009 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 "chrome/common/appcache/appcache_backend_proxy.h" + +#include "chrome/common/render_messages.h" + +void AppCacheBackendProxy::RegisterHost(int host_id) { + sender_->Send(new AppCacheMsg_RegisterHost(host_id)); +} + +void AppCacheBackendProxy::UnregisterHost(int host_id) { + sender_->Send(new AppCacheMsg_UnregisterHost(host_id)); +} + +void AppCacheBackendProxy::SelectCache( + int host_id, + const GURL& document_url, + const int64 cache_document_was_loaded_from, + const GURL& manifest_url) { + sender_->Send(new AppCacheMsg_SelectCache( + host_id, document_url, + cache_document_was_loaded_from, + manifest_url)); +} + +void AppCacheBackendProxy::SelectCacheForWorker( + int host_id, int parent_process_id, int parent_host_id) { + sender_->Send(new AppCacheMsg_SelectCacheForWorker( + host_id, parent_process_id, + parent_host_id)); +} + +void AppCacheBackendProxy::SelectCacheForSharedWorker( + int host_id, int64 appcache_id) { + sender_->Send(new AppCacheMsg_SelectCacheForSharedWorker( + host_id, appcache_id)); +} + +void AppCacheBackendProxy::MarkAsForeignEntry( + int host_id, const GURL& document_url, + int64 cache_document_was_loaded_from) { + sender_->Send(new AppCacheMsg_MarkAsForeignEntry( + host_id, document_url, + cache_document_was_loaded_from)); +} + +appcache::Status AppCacheBackendProxy::GetStatus(int host_id) { + appcache::Status status = appcache::UNCACHED; + sender_->Send(new AppCacheMsg_GetStatus(host_id, &status)); + return status; +} + +bool AppCacheBackendProxy::StartUpdate(int host_id) { + bool result = false; + sender_->Send(new AppCacheMsg_StartUpdate(host_id, &result)); + return result; +} + +bool AppCacheBackendProxy::SwapCache(int host_id) { + bool result = false; + sender_->Send(new AppCacheMsg_SwapCache(host_id, &result)); + return result; +} diff --git a/chrome/common/appcache/appcache_backend_proxy.h b/chrome/common/appcache/appcache_backend_proxy.h new file mode 100644 index 0000000..2ef2660 --- /dev/null +++ b/chrome/common/appcache/appcache_backend_proxy.h @@ -0,0 +1,43 @@ +// Copyright (c) 2009 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 CHROME_COMMON_APPCACHE_APPCACHE_BACKEND_PROXY_H_ +#define CHROME_COMMON_APPCACHE_APPCACHE_BACKEND_PROXY_H_ + +#include "ipc/ipc_message.h" +#include "webkit/appcache/appcache_interfaces.h" + +// Sends appcache related messages to the main process. +class AppCacheBackendProxy : public appcache::AppCacheBackend { + public: + explicit AppCacheBackendProxy(IPC::Message::Sender* sender) + : sender_(sender) {} + + IPC::Message::Sender* sender() const { return sender_; } + + // AppCacheBackend methods + virtual void RegisterHost(int host_id); + virtual void UnregisterHost(int host_id); + virtual void SelectCache(int host_id, + const GURL& document_url, + const int64 cache_document_was_loaded_from, + const GURL& manifest_url); + virtual void SelectCacheForWorker( + int host_id, + int parent_process_id, + int parent_host_id); + virtual void SelectCacheForSharedWorker( + int host_id, + int64 appcache_id); + virtual void MarkAsForeignEntry(int host_id, const GURL& document_url, + int64 cache_document_was_loaded_from); + virtual appcache::Status GetStatus(int host_id); + virtual bool StartUpdate(int host_id); + virtual bool SwapCache(int host_id); + + private: + IPC::Message::Sender* sender_; +}; + +#endif // CHROME_COMMON_APPCACHE_APPCACHE_BACKEND_PROXY_H_ diff --git a/chrome/common/appcache/appcache_dispatcher.cc b/chrome/common/appcache/appcache_dispatcher.cc new file mode 100644 index 0000000..6cf40cc --- /dev/null +++ b/chrome/common/appcache/appcache_dispatcher.cc @@ -0,0 +1,61 @@ +// Copyright (c) 2010 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 "chrome/common/appcache/appcache_dispatcher.h" + +#include "chrome/common/render_messages.h" +#include "webkit/appcache/web_application_cache_host_impl.h" + +bool AppCacheDispatcher::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(AppCacheDispatcher, msg) + IPC_MESSAGE_HANDLER(AppCacheMsg_CacheSelected, OnCacheSelected) + IPC_MESSAGE_HANDLER(AppCacheMsg_StatusChanged, OnStatusChanged) + IPC_MESSAGE_HANDLER(AppCacheMsg_EventRaised, OnEventRaised) + IPC_MESSAGE_HANDLER(AppCacheMsg_ProgressEventRaised, OnProgressEventRaised) + IPC_MESSAGE_HANDLER(AppCacheMsg_ErrorEventRaised, OnErrorEventRaised) + IPC_MESSAGE_HANDLER(AppCacheMsg_LogMessage, OnLogMessage) + IPC_MESSAGE_HANDLER(AppCacheMsg_ContentBlocked, OnContentBlocked) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void AppCacheDispatcher::OnCacheSelected(int host_id, int64 cache_id, + appcache::Status status) { + frontend_impl_.OnCacheSelected(host_id, cache_id, status); +} + +void AppCacheDispatcher::OnStatusChanged(const std::vector<int>& host_ids, + appcache::Status status) { + frontend_impl_.OnStatusChanged(host_ids, status); +} + +void AppCacheDispatcher::OnEventRaised(const std::vector<int>& host_ids, + appcache::EventID event_id) { + frontend_impl_.OnEventRaised(host_ids, event_id); +} + +void AppCacheDispatcher::OnProgressEventRaised( + const std::vector<int>& host_ids, + const GURL& url, int num_total, int num_complete) { + frontend_impl_.OnProgressEventRaised(host_ids, url, num_total, num_complete); +} + +void AppCacheDispatcher::OnErrorEventRaised( + const std::vector<int>& host_ids, + const std::string& message) { + frontend_impl_.OnErrorEventRaised(host_ids, message); +} + +void AppCacheDispatcher::OnLogMessage( + int host_id, int log_level, const std::string& message) { + frontend_impl_.OnLogMessage( + host_id, static_cast<appcache::LogLevel>(log_level), message); +} + +void AppCacheDispatcher::OnContentBlocked(int host_id, + const GURL& manifest_url) { + frontend_impl_.OnContentBlocked(host_id, manifest_url); +} diff --git a/chrome/common/appcache/appcache_dispatcher.h b/chrome/common/appcache/appcache_dispatcher.h new file mode 100644 index 0000000..d21be54 --- /dev/null +++ b/chrome/common/appcache/appcache_dispatcher.h @@ -0,0 +1,46 @@ +// Copyright (c) 2010 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 CHROME_COMMON_APPCACHE_APPCACHE_DISPATCHER_H_ +#define CHROME_COMMON_APPCACHE_APPCACHE_DISPATCHER_H_ + +#include <vector> +#include "chrome/common/appcache/appcache_backend_proxy.h" +#include "ipc/ipc_message.h" +#include "webkit/appcache/appcache_frontend_impl.h" + +// Dispatches appcache related messages sent to a child process from the +// main browser process. There is one instance per child process. Messages +// are dispatched on the main child thread. The ChildThread base class +// creates an instance and delegates calls to it. +class AppCacheDispatcher { + public: + explicit AppCacheDispatcher(IPC::Message::Sender* sender) + : backend_proxy_(sender) {} + + AppCacheBackendProxy* backend_proxy() { return &backend_proxy_; } + + bool OnMessageReceived(const IPC::Message& msg); + + private: + // Ipc message handlers + void OnCacheSelected(int host_id, int64 cache_id, + appcache::Status status); + void OnStatusChanged(const std::vector<int>& host_ids, + appcache::Status status); + void OnEventRaised(const std::vector<int>& host_ids, + appcache::EventID event_id); + void OnProgressEventRaised(const std::vector<int>& host_ids, + const GURL& url, int num_total, int num_complete); + void OnErrorEventRaised(const std::vector<int>& host_ids, + const std::string& message); + void OnLogMessage(int host_id, int log_level, const std::string& message); + void OnContentBlocked(int host_id, + const GURL& manifest_url); + + AppCacheBackendProxy backend_proxy_; + appcache::AppCacheFrontendImpl frontend_impl_; +}; + +#endif // CHROME_COMMON_APPCACHE_APPCACHE_DISPATCHER_H_ diff --git a/chrome/common/automation_constants.cc b/chrome/common/automation_constants.cc new file mode 100644 index 0000000..185d57b --- /dev/null +++ b/chrome/common/automation_constants.cc @@ -0,0 +1,15 @@ +// Copyright (c) 2006-2009 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 "chrome/common/automation_constants.h" + +namespace automation { +// JSON value labels for proxy settings that are passed in via +// AutomationMsg_SetProxyConfig. +const wchar_t kJSONProxyAutoconfig[] = L"proxy.autoconfig"; +const wchar_t kJSONProxyNoProxy[] = L"proxy.no_proxy"; +const wchar_t kJSONProxyPacUrl[] = L"proxy.pac_url"; +const wchar_t kJSONProxyBypassList[] = L"proxy.bypass_list"; +const wchar_t kJSONProxyServer[] = L"proxy.server"; +} diff --git a/chrome/common/automation_constants.h b/chrome/common/automation_constants.h new file mode 100644 index 0000000..9c31bd1 --- /dev/null +++ b/chrome/common/automation_constants.h @@ -0,0 +1,19 @@ +// Copyright (c) 2006-2009 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 CHROME_COMMON_AUTOMATION_CONSTANTS_H__ +#define CHROME_COMMON_AUTOMATION_CONSTANTS_H__ + +namespace automation { +// JSON value labels for proxy settings that are passed in via +// AutomationMsg_SetProxyConfig. These are here since they are used by both +// AutomationProvider and AutomationProxy. +extern const wchar_t kJSONProxyAutoconfig[]; +extern const wchar_t kJSONProxyNoProxy[]; +extern const wchar_t kJSONProxyPacUrl[]; +extern const wchar_t kJSONProxyBypassList[]; +extern const wchar_t kJSONProxyServer[]; +} + +#endif // CHROME_COMMON_AUTOMATION_CONSTANTS_H__ diff --git a/chrome/common/bindings_policy.h b/chrome/common/bindings_policy.h new file mode 100644 index 0000000..eccce17 --- /dev/null +++ b/chrome/common/bindings_policy.h @@ -0,0 +1,42 @@ +// Copyright (c) 2006-2009 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 CHROME_COMMON_BINDINGS_POLICY_H__ +#define CHROME_COMMON_BINDINGS_POLICY_H__ + +// This is a utility class that specifies flag values for the types of +// JavaScript bindings exposed to renderers. +class BindingsPolicy { + public: + enum { + // HTML-based UI bindings that allows he js content to send JSON-encoded + // data back to the browser process. + DOM_UI = 1 << 0, + // DOM automation bindings that allows the js content to send JSON-encoded + // data back to automation in the parent process. (By default this isn't + // allowed unless the app has been started up with the --dom-automation + // switch.) + DOM_AUTOMATION = 1 << 1, + // Bindings that allow access to the external host (through automation). + EXTERNAL_HOST = 1 << 2, + // Special bindings with privileged APIs for code running in the extension + // process. + EXTENSION = 1 << 3, + }; + + static bool is_dom_ui_enabled(int flags) { + return (flags & DOM_UI) != 0; + } + static bool is_dom_automation_enabled(int flags) { + return (flags & DOM_AUTOMATION) != 0; + } + static bool is_external_host_enabled(int flags) { + return (flags & EXTERNAL_HOST) != 0; + } + static bool is_extension_enabled(int flags) { + return (flags & EXTENSION) != 0; + } +}; + +#endif // CHROME_COMMON_BINDINGS_POLICY_H__ diff --git a/chrome/common/bzip2_unittest.cc b/chrome/common/bzip2_unittest.cc new file mode 100644 index 0000000..0f14205 --- /dev/null +++ b/chrome/common/bzip2_unittest.cc @@ -0,0 +1,72 @@ +// Copyright (c) 2006-2008 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. + +#if defined(USE_SYSTEM_LIBBZ2) +#include <bzlib.h> +#else +#include "third_party/bzip2/bzlib.h" +#endif + +#include "base/basictypes.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + class Bzip2Test : public testing::Test { + }; +}; + +// This test does a simple round trip to test that the bzip2 library is +// present and working. +TEST(Bzip2Test, Roundtrip) { + char input[] = "Test Data, More Test Data, Even More Data of Test"; + char output[256]; + + memset(output, 0, arraysize(output)); + + bz_stream stream; + stream.bzalloc = NULL; + stream.bzfree = NULL; + stream.opaque = NULL; + int result = BZ2_bzCompressInit(&stream, + 9, // 900k block size + 0, // quiet + 0); // default work factor + ASSERT_EQ(BZ_OK, result); + + stream.next_in = input; + stream.avail_in = arraysize(input) - 1; + stream.next_out = output; + stream.avail_out = arraysize(output); + do { + result = BZ2_bzCompress(&stream, BZ_FINISH); + } while (result == BZ_FINISH_OK); + ASSERT_EQ(BZ_STREAM_END, result); + result = BZ2_bzCompressEnd(&stream); + ASSERT_EQ(BZ_OK, result); + int written = stream.total_out_lo32; + + // Make sure we wrote something; otherwise not sure what to expect + ASSERT_GT(written, 0); + + // Now decompress and check that we got the same thing. + result = BZ2_bzDecompressInit(&stream, 0, 0); + ASSERT_EQ(BZ_OK, result); + char output2[256]; + memset(output2, 0, arraysize(output2)); + + stream.next_in = output; + stream.avail_in = written; + stream.next_out = output2; + stream.avail_out = arraysize(output2); + + do { + result = BZ2_bzDecompress(&stream); + } while (result == BZ_OK); + ASSERT_EQ(result, BZ_STREAM_END); + result = BZ2_bzDecompressEnd(&stream); + ASSERT_EQ(result, BZ_OK); + + EXPECT_EQ(arraysize(input) - 1, stream.total_out_lo32); + EXPECT_STREQ(input, output2); +} diff --git a/chrome/common/child_process.cc b/chrome/common/child_process.cc new file mode 100644 index 0000000..328ca14 --- /dev/null +++ b/chrome/common/child_process.cc @@ -0,0 +1,97 @@ +// Copyright (c) 2006-2008 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 "chrome/common/child_process.h" + +#include "app/l10n_util.h" +#include "base/message_loop.h" +#include "base/process_util.h" +#include "base/string_util.h" +#include "chrome/common/child_thread.h" +#include "grit/chromium_strings.h" + +#if defined(OS_POSIX) +#include <signal.h> + +static void SigUSR1Handler(int signal) { } +#endif + +ChildProcess* ChildProcess::child_process_; + +ChildProcess::ChildProcess() + : ref_count_(0), + shutdown_event_(true, false), + io_thread_("Chrome_ChildIOThread") { + DCHECK(!child_process_); + child_process_ = this; + + io_thread_.StartWithOptions(base::Thread::Options(MessageLoop::TYPE_IO, 0)); +} + +ChildProcess::~ChildProcess() { + DCHECK(child_process_ == this); + + // Signal this event before destroying the child process. That way all + // background threads can cleanup. + // For example, in the renderer the RenderThread instances will be able to + // notice shutdown before the render process begins waiting for them to exit. + shutdown_event_.Signal(); + + // Kill the main thread object before nulling child_process_, since + // destruction code might depend on it. + main_thread_.reset(); + + child_process_ = NULL; +} + +void ChildProcess::AddRefProcess() { + DCHECK(!main_thread_.get() || // null in unittests. + MessageLoop::current() == main_thread_->message_loop()); + ref_count_++; +} + +void ChildProcess::ReleaseProcess() { + DCHECK(!main_thread_.get() || // null in unittests. + MessageLoop::current() == main_thread_->message_loop()); + DCHECK(ref_count_); + DCHECK(child_process_); + if (--ref_count_) + return; + + if (main_thread_.get()) // null in unittests. + main_thread_->OnProcessFinalRelease(); +} + +base::WaitableEvent* ChildProcess::GetShutDownEvent() { + DCHECK(child_process_); + return &child_process_->shutdown_event_; +} + +void ChildProcess::WaitForDebugger(const std::wstring& label) { +#if defined(OS_WIN) + std::wstring title = l10n_util::GetString(IDS_PRODUCT_NAME); + std::wstring message = label; + message += L" starting with pid: "; + message += IntToWString(base::GetCurrentProcId()); + title += L" "; + title += label; // makes attaching to process easier + ::MessageBox(NULL, message.c_str(), title.c_str(), + MB_OK | MB_SETFOREGROUND); +#elif defined(OS_POSIX) + // TODO(playmobil): In the long term, overriding this flag doesn't seem + // right, either use our own flag or open a dialog we can use. + // This is just to ease debugging in the interim. + LOG(WARNING) << label + << " (" + << getpid() + << ") paused waiting for debugger to attach @ pid"; + // Install a signal handler so that pause can be woken. + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SigUSR1Handler; + sigaction(SIGUSR1, &sa, NULL); + + pause(); +#endif // defined(OS_POSIX) +} diff --git a/chrome/common/child_process.h b/chrome/common/child_process.h new file mode 100644 index 0000000..fb2c660 --- /dev/null +++ b/chrome/common/child_process.h @@ -0,0 +1,70 @@ +// Copyright (c) 2006-2008 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 CHROME_COMMON_CHILD_PROCESS_H__ +#define CHROME_COMMON_CHILD_PROCESS_H__ + +#include "base/basictypes.h" +#include "base/scoped_ptr.h" +#include "base/thread.h" +#include "base/waitable_event.h" +#include "chrome/common/child_thread.h" + +// Base class for child processes of the browser process (i.e. renderer and +// plugin host). This is a singleton object for each child process. +class ChildProcess { + public: + // Child processes should have an object that derives from this class. + ChildProcess(); + virtual ~ChildProcess(); + + // Getter for the child process' main thread. + ChildThread* main_thread() { return main_thread_.get(); } + void set_main_thread(ChildThread* thread) { main_thread_.reset(thread); } + + MessageLoop* io_message_loop() { return io_thread_.message_loop(); } + + // A global event object that is signalled when the main thread's message + // loop exits. This gives background threads a way to observe the main + // thread shutting down. This can be useful when a background thread is + // waiting for some information from the browser process. If the browser + // process goes away prematurely, the background thread can at least notice + // the child processes's main thread exiting to determine that it should give + // up waiting. + // For example, see the renderer code used to implement + // webkit_glue::GetCookies. + base::WaitableEvent* GetShutDownEvent(); + + // These are used for ref-counting the child process. The process shuts + // itself down when the ref count reaches 0. + // For example, in the renderer process, generally each tab managed by this + // process will hold a reference to the process, and release when closed. + void AddRefProcess(); + void ReleaseProcess(); + + // Getter for the one ChildProcess object for this process. + static ChildProcess* current() { return child_process_; } + + static void WaitForDebugger(const std::wstring& label); + private: + int ref_count_; + + // An event that will be signalled when we shutdown. + base::WaitableEvent shutdown_event_; + + // The thread that handles IO events. + base::Thread io_thread_; + + // NOTE: make sure that main_thread_ is listed after shutdown_event_, since + // it depends on it (indirectly through IPC::SyncChannel). Same for + // io_thread_. + scoped_ptr<ChildThread> main_thread_; + + // The singleton instance for this process. + static ChildProcess* child_process_; + + DISALLOW_COPY_AND_ASSIGN(ChildProcess); +}; + +#endif // CHROME_COMMON_CHILD_PROCESS_H__ diff --git a/chrome/common/child_process_host.cc b/chrome/common/child_process_host.cc new file mode 100644 index 0000000..bcd0c3d --- /dev/null +++ b/chrome/common/child_process_host.cc @@ -0,0 +1,190 @@ +// Copyright (c) 2010 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 "chrome/common/child_process_host.h" + +#include "base/command_line.h" +#include "base/histogram.h" +#include "base/path_service.h" +#include "chrome/common/child_process_info.h" +#include "chrome/common/chrome_constants.h" +#include "chrome/common/chrome_paths_internal.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/plugin_messages.h" + +#if defined(OS_LINUX) +#include "base/linux_util.h" +#endif // OS_LINUX + +ChildProcessHost::ChildProcessHost() + : ALLOW_THIS_IN_INITIALIZER_LIST(listener_(this)), + opening_channel_(false) { +} + +ChildProcessHost::~ChildProcessHost() { +} + +// static +FilePath ChildProcessHost::GetChildPath(bool allow_self) { + FilePath child_path; + + child_path = CommandLine::ForCurrentProcess()->GetSwitchValuePath( + switches::kBrowserSubprocessPath); + if (!child_path.empty()) + return child_path; + +#if defined(OS_MACOSX) + // On the Mac, the child executable lives at a predefined location within + // the app bundle's versioned directory. + return chrome::GetVersionedDirectory(). + Append(chrome::kHelperProcessExecutablePath); +#endif + +#if defined(OS_LINUX) + // Use /proc/self/exe rather than our known binary path so updates + // can't swap out the binary from underneath us. + if (allow_self) + return FilePath("/proc/self/exe"); +#endif + + // On most platforms, the child executable is the same as the current + // executable. + PathService::Get(base::FILE_EXE, &child_path); + return child_path; +} + +#if defined(OS_WIN) +// static +void ChildProcessHost::PreCacheFont(LOGFONT font) { + // If a child process is running in a sandbox, GetTextMetrics() + // can sometimes fail. If a font has not been loaded + // previously, GetTextMetrics() will try to load the font + // from the font file. However, the sandboxed process does + // not have permissions to access any font files and + // the call fails. So we make the browser pre-load the + // font for us by using a dummy call to GetTextMetrics of + // the same font. + + // Maintain a circular queue for the fonts and DCs to be cached. + // font_index maintains next available location in the queue. + static const int kFontCacheSize = 32; + static HFONT fonts[kFontCacheSize] = {0}; + static HDC hdcs[kFontCacheSize] = {0}; + static size_t font_index = 0; + + UMA_HISTOGRAM_COUNTS_100("Memory.CachedFontAndDC", + fonts[kFontCacheSize-1] ? kFontCacheSize : static_cast<int>(font_index)); + + HDC hdc = GetDC(NULL); + HFONT font_handle = CreateFontIndirect(&font); + DCHECK(NULL != font_handle); + + HGDIOBJ old_font = SelectObject(hdc, font_handle); + DCHECK(NULL != old_font); + + TEXTMETRIC tm; + BOOL ret = GetTextMetrics(hdc, &tm); + DCHECK(ret); + + if (fonts[font_index] || hdcs[font_index]) { + // We already have too many fonts, we will delete one and take it's place. + DeleteObject(fonts[font_index]); + ReleaseDC(NULL, hdcs[font_index]); + } + + fonts[font_index] = font_handle; + hdcs[font_index] = hdc; + font_index = (font_index + 1) % kFontCacheSize; +} +#endif // OS_WIN + + +bool ChildProcessHost::CreateChannel() { + channel_id_ = ChildProcessInfo::GenerateRandomChannelID(this); + channel_.reset(new IPC::Channel( + channel_id_, IPC::Channel::MODE_SERVER, &listener_)); + if (!channel_->Connect()) + return false; + + // Make sure these messages get sent first. +#if defined(IPC_MESSAGE_LOG_ENABLED) + bool enabled = IPC::Logging::current()->Enabled(); + SendOnChannel(new PluginProcessMsg_SetIPCLoggingEnabled(enabled)); +#endif + + SendOnChannel(new PluginProcessMsg_AskBeforeShutdown()); + + opening_channel_ = true; + + return true; +} + +void ChildProcessHost::InstanceCreated() { + Notify(NotificationType::CHILD_INSTANCE_CREATED); +} + +bool ChildProcessHost::SendOnChannel(IPC::Message* msg) { + if (!channel_.get()) { + delete msg; + return false; + } + return channel_->Send(msg); +} + +void ChildProcessHost::OnChildDied() { + delete this; +} + +ChildProcessHost::ListenerHook::ListenerHook(ChildProcessHost* host) + : host_(host) { +} + +void ChildProcessHost::ListenerHook::OnMessageReceived( + const IPC::Message& msg) { +#ifdef IPC_MESSAGE_LOG_ENABLED + IPC::Logging* logger = IPC::Logging::current(); + if (msg.type() == IPC_LOGGING_ID) { + logger->OnReceivedLoggingMessage(msg); + return; + } + + if (logger->Enabled()) + logger->OnPreDispatchMessage(msg); +#endif + + bool handled = host_->InterceptMessageFromChild(msg); + + if (!handled) { + if (msg.type() == PluginProcessHostMsg_ShutdownRequest::ID) { + if (host_->CanShutdown()) + host_->SendOnChannel(new PluginProcessMsg_Shutdown()); + } else { + host_->OnMessageReceived(msg); + } + } + +#ifdef IPC_MESSAGE_LOG_ENABLED + if (logger->Enabled()) + logger->OnPostDispatchMessage(msg, host_->channel_id_); +#endif +} + +void ChildProcessHost::ListenerHook::OnChannelConnected(int32 peer_pid) { + host_->opening_channel_ = false; + host_->OnChannelConnected(peer_pid); + // Notify in the main loop of the connection. + host_->Notify(NotificationType::CHILD_PROCESS_HOST_CONNECTED); +} + +void ChildProcessHost::ListenerHook::OnChannelError() { + host_->opening_channel_ = false; + host_->OnChannelError(); + + // This will delete host_, which will also destroy this! + host_->OnChildDied(); +} + +void ChildProcessHost::ForceShutdown() { + SendOnChannel(new PluginProcessMsg_Shutdown()); +} diff --git a/chrome/common/child_process_host.h b/chrome/common/child_process_host.h new file mode 100644 index 0000000..865a1ac --- /dev/null +++ b/chrome/common/child_process_host.h @@ -0,0 +1,123 @@ +// Copyright (c) 2010 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 CHROME_COMMON_CHILD_PROCESS_HOST_H_ +#define CHROME_COMMON_CHILD_PROCESS_HOST_H_ + +#include <list> +#include <string> + +// Must be included early (e.g. before chrome/common/plugin_messages.h) +#include "ipc/ipc_logging.h" + +// Putting this before ipc_logging.h does not work (OS_WIN isn't defined) +#if defined(OS_WIN) +#include <windows.h> +#endif // defined(OS_WIN) + +#include "base/basictypes.h" +#include "base/file_path.h" +#include "base/scoped_ptr.h" +#include "chrome/common/notification_type.h" +#include "ipc/ipc_channel.h" + + +class CommandLine; + +// Provides common functionality for hosting a child process and processing IPC +// messages between the host and the child process. Subclasses are responsible +// for the actual launching and terminating of the child processes. +// +class ChildProcessHost : public IPC::Channel::Listener { + public: + virtual ~ChildProcessHost(); + + // Returns the pathname to be used for a child process. If a subprocess + // pathname was specified on the command line, that will be used. Otherwise, + // the default child process pathname will be returned. On most platforms, + // this will be the same as the currently-executing process. + // + // The argument allow_self is used on Linux to indicate that we allow us to + // fork from /proc/self/exe rather than using the "real" app path. This + // prevents autoupdate from confusing us if it changes the file out from + // under us. You will generally want to set this to true, except when there + // is an override to the command line (for example, we're forking a renderer + // in gdb). In this case, you'd use GetChildPath to get the real executable + // file name, and then prepend the GDB command to the command line. + // + // On failure, returns an empty FilePath. + static FilePath GetChildPath(bool allow_self); + +#if defined(OS_WIN) + // See comments in the cc file. This is a common hack needed for a process + // hosting a sandboxed child process. Hence it lives in this file. + static void PreCacheFont(LOGFONT font); +#endif // defined(OS_WIN) + + protected: + ChildProcessHost(); + + // A helper method to send an IPC message to the child on the channel. + // It behavies just like IPC::Message::Sender::Send. The implementor takes + // ownership of the given Message regardless of whether or not this method + // succeeds. This class does not implement IPC::Message::Sender to prevent + // conflicts with subclasses which indirectly could inherit from + // IPC::Message::Sender. + bool SendOnChannel(IPC::Message* msg); + + // Derived classes return true if it's ok to shut down the child process. + virtual bool CanShutdown() = 0; + + // Send the shutdown message to the child process. + // Does not check if CanShutdown is true. + virtual void ForceShutdown(); + + // Creates the IPC channel. Returns true iff it succeeded. + virtual bool CreateChannel(); + + // Notifies us that an instance has been created on this child process. + virtual void InstanceCreated(); + + // IPC::Channel::Listener implementation: + virtual void OnMessageReceived(const IPC::Message& msg) { } + virtual void OnChannelConnected(int32 peer_pid) { } + virtual void OnChannelError() { } + + bool opening_channel() { return opening_channel_; } + const std::string& channel_id() { return channel_id_; } + IPC::Channel* channel() { return channel_.get(); } + + // Called when the child process goes away. + virtual void OnChildDied(); + // Allows the derived implementation to intercept a message before it is + // handed to the IPC::Channel::Listener::OnMessageReceived implementation. + virtual bool InterceptMessageFromChild(const IPC::Message& msg) { + return false; + } + // Subclasses can implement specific notification methods. + virtual void Notify(NotificationType type) { } + + private: + // By using an internal class as the IPC::Channel::Listener, we can intercept + // OnMessageReceived/OnChannelConnected and do our own processing before + // calling the subclass' implementation. + class ListenerHook : public IPC::Channel::Listener { + public: + explicit ListenerHook(ChildProcessHost* host); + virtual void OnMessageReceived(const IPC::Message& msg); + virtual void OnChannelConnected(int32 peer_pid); + virtual void OnChannelError(); + private: + ChildProcessHost* host_; + }; + + ListenerHook listener_; + + bool opening_channel_; // True while we're waiting the channel to be opened. + scoped_ptr<IPC::Channel> channel_; + std::string channel_id_; +}; + +#endif // CHROME_COMMON_CHILD_PROCESS_HOST_H_ + diff --git a/chrome/common/child_process_info.cc b/chrome/common/child_process_info.cc new file mode 100644 index 0000000..f08cb55 --- /dev/null +++ b/chrome/common/child_process_info.cc @@ -0,0 +1,130 @@ +// Copyright (c) 2009 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 "chrome/common/child_process_info.h" + +#include <limits> + +#include "app/l10n_util.h" +#include "base/atomicops.h" +#include "base/i18n/rtl.h" +#include "base/logging.h" +#include "base/process_util.h" +#include "base/rand_util.h" +#include "base/string_util.h" +#include "grit/generated_resources.h" + +ChildProcessInfo::ChildProcessInfo(const ChildProcessInfo& original) + : type_(original.type_), + name_(original.name_), + version_(original.version_), + id_(original.id_), + process_(original.process_) { +} + +ChildProcessInfo::~ChildProcessInfo() { +} + +ChildProcessInfo& ChildProcessInfo::operator=( + const ChildProcessInfo& original) { + if (&original != this) { + type_ = original.type_; + name_ = original.name_; + version_ = original.version_; + id_ = original.id_; + process_ = original.process_; + } + return *this; +} + +std::wstring ChildProcessInfo::GetTypeNameInEnglish( + ChildProcessInfo::ProcessType type) { + switch (type) { + case BROWSER_PROCESS: + return L"Browser"; + case RENDER_PROCESS: + return L"Tab"; + case PLUGIN_PROCESS: + return L"Plug-in"; + case WORKER_PROCESS: + return L"Web Worker"; + case UTILITY_PROCESS: + return L"Utility"; + case PROFILE_IMPORT_PROCESS: + return L"Profile Import helper"; + case ZYGOTE_PROCESS: + return L"Zygote"; + case SANDBOX_HELPER_PROCESS: + return L"Sandbox helper"; + case NACL_LOADER_PROCESS: + return L"Native Client module"; + case NACL_BROKER_PROCESS: + return L"Native Client broker"; + case GPU_PROCESS: + return L"GPU"; + case UNKNOWN_PROCESS: + default: + DCHECK(false) << "Unknown child process type!"; + return L"Unknown"; + } +} + +std::wstring ChildProcessInfo::GetLocalizedTitle() const { + std::wstring title = name_; + if (type_ == ChildProcessInfo::PLUGIN_PROCESS && title.empty()) + title = l10n_util::GetString(IDS_TASK_MANAGER_UNKNOWN_PLUGIN_NAME); + + // Explicitly mark name as LTR if there is no strong RTL character, + // to avoid the wrong concatenation result similar to "!Yahoo! Mail: the + // best web-based Email: NIGULP", in which "NIGULP" stands for the Hebrew + // or Arabic word for "plugin". + base::i18n::AdjustStringForLocaleDirection(title, &title); + + int message_id; + if (type_ == ChildProcessInfo::PLUGIN_PROCESS) { + message_id = IDS_TASK_MANAGER_PLUGIN_PREFIX; + return l10n_util::GetStringF(message_id, title, version_.c_str()); + } else if (type_ == ChildProcessInfo::WORKER_PROCESS) { + message_id = IDS_TASK_MANAGER_WORKER_PREFIX; + } else if (type_ == ChildProcessInfo::UTILITY_PROCESS) { + message_id = IDS_TASK_MANAGER_UTILITY_PREFIX; + } else if (type_ == ChildProcessInfo::PROFILE_IMPORT_PROCESS) { + message_id = IDS_TASK_MANAGER_PROFILE_IMPORT_PREFIX; + } else if (type_ == ChildProcessInfo::NACL_LOADER_PROCESS) { + message_id = IDS_TASK_MANAGER_NACL_PREFIX; + } else if (type_ == ChildProcessInfo::NACL_BROKER_PROCESS) { + message_id = IDS_TASK_MANAGER_NACL_BROKER_PREFIX; + } else { + DCHECK(false) << "Need localized name for child process type."; + return title; + } + + return l10n_util::GetStringF(message_id, title); +} + +ChildProcessInfo::ChildProcessInfo(ProcessType type, int id) : type_(type) { + if (id == -1) + id_ = GenerateChildProcessUniqueId(); + else + id_ = id; +} + +std::string ChildProcessInfo::GenerateRandomChannelID(void* instance) { + // Note: the string must start with the current process id, this is how + // child processes determine the pid of the parent. + // Build the channel ID. This is composed of a unique identifier for the + // parent browser process, an identifier for the child instance, and a random + // component. We use a random component so that a hacked child process can't + // cause denial of service by causing future named pipe creation to fail. + return StringPrintf("%d.%p.%d", + base::GetCurrentProcId(), instance, + base::RandInt(0, std::numeric_limits<int>::max())); +} + +// static +int ChildProcessInfo::GenerateChildProcessUniqueId() { + // This function must be threadsafe. + static base::subtle::Atomic32 last_unique_child_id = 0; + return base::subtle::NoBarrier_AtomicIncrement(&last_unique_child_id, 1); +} diff --git a/chrome/common/child_process_info.h b/chrome/common/child_process_info.h new file mode 100644 index 0000000..bc36c18 --- /dev/null +++ b/chrome/common/child_process_info.h @@ -0,0 +1,113 @@ +// Copyright (c) 2009 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 CHROME_COMMON_CHILD_PROCESS_INFO_H_ +#define CHROME_COMMON_CHILD_PROCESS_INFO_H_ + +#include <string> + +#include "base/process.h" + +// Holds information about a child process. +class ChildProcessInfo { + public: + // NOTE: Do not remove or reorder the elements in this enum, and only add new + // items at the end. We depend on these specific values in a histogram. + enum ProcessType { + UNKNOWN_PROCESS = 1, + BROWSER_PROCESS, + RENDER_PROCESS, + PLUGIN_PROCESS, + WORKER_PROCESS, + NACL_LOADER_PROCESS, + UTILITY_PROCESS, + PROFILE_IMPORT_PROCESS, + ZYGOTE_PROCESS, + SANDBOX_HELPER_PROCESS, + NACL_BROKER_PROCESS, + GPU_PROCESS + }; + + ChildProcessInfo(const ChildProcessInfo& original); + virtual ~ChildProcessInfo(); + + ChildProcessInfo& operator=(const ChildProcessInfo& original); + + // Returns the type of the process. + ProcessType type() const { return type_; } + + // Returns the name of the process. i.e. for plugins it might be Flash, while + // for workers it might be the domain that it's from. + std::wstring name() const { return name_; } + + // Returns the version of the exe, this only appliest to plugins. Otherwise + // the string is empty. + std::wstring version() const { return version_; } + + // Getter to the process handle. + base::ProcessHandle handle() const { return process_.handle(); } + + // The unique identifier for this child process. This identifier is NOT a + // process ID, and will be unique for all types of child process for + // one run of the browser. + int id() const { return id_; } + + void SetProcessBackgrounded() const { process_.SetProcessBackgrounded(true); } + + // Returns an English name of the process type, should only be used for non + // user-visible strings, or debugging pages like about:memory. + static std::wstring GetTypeNameInEnglish(ProcessType type); + + // Returns a localized title for the child process. For example, a plugin + // process would be "Plug-in: Flash" when name is "Flash". + std::wstring GetLocalizedTitle() const; + + // We define the < operator so that the ChildProcessInfo can be used as a key + // in a std::map. + bool operator <(const ChildProcessInfo& rhs) const { + if (process_.handle() != rhs.process_.handle()) + return process_ .handle() < rhs.process_.handle(); + return false; + } + + bool operator ==(const ChildProcessInfo& rhs) const { + return process_.handle() == rhs.process_.handle(); + } + + // Generates a unique channel name for a child renderer/plugin process. + // The "instance" pointer value is baked into the channel id. + static std::string GenerateRandomChannelID(void* instance); + + // Returns a unique ID to identify a child process. On construction, this + // function will be used to generate the id_, but it is also used to generate + // IDs for the RenderProcessHost, which doesn't inherit from us, and whose IDs + // must be unique for all child processes. + // + // This function is threadsafe since RenderProcessHost is on the UI thread, + // but normally this will be used on the IO thread. + static int GenerateChildProcessUniqueId(); + + protected: + // Derived objects need to use this constructor so we know what type we are. + // If the caller has already generated a unique ID for this child process, + // it should pass it as the second argument. Otherwise, -1 should be passed + // and a unique ID will be automatically generated. + ChildProcessInfo(ProcessType type, int id); + + void set_type(ProcessType type) { type_ = type; } + void set_name(const std::wstring& name) { name_ = name; } + void set_version(const std::wstring& ver) { version_ = ver; } + void set_handle(base::ProcessHandle handle) { process_.set_handle(handle); } + + private: + ProcessType type_; + std::wstring name_; + std::wstring version_; + int id_; + + // The handle to the process. + mutable base::Process process_; +}; + +#endif // CHROME_COMMON_CHILD_PROCESS_INFO_H_ diff --git a/chrome/common/child_process_logging.h b/chrome/common/child_process_logging.h new file mode 100644 index 0000000..84a288c --- /dev/null +++ b/chrome/common/child_process_logging.h @@ -0,0 +1,81 @@ +// Copyright (c) 2010 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 CHROME_COMMON_CHILD_PROCESS_LOGGING_H_ +#define CHROME_COMMON_CHILD_PROCESS_LOGGING_H_ + +#include <set> +#include <string> + +#include "base/basictypes.h" +#include "chrome/common/gpu_info.h" +#include "googleurl/src/gurl.h" + +#if defined(OS_WIN) +// The maximum number of active extensions we will report. +// Also used in chrome/app, but we define it here to avoid a common->app +// dependency. +static const int kMaxReportedActiveExtensions = 10; +#endif + +namespace child_process_logging { + +// Sets the URL that is logged if the child process crashes. Use GURL() to clear +// the URL. +void SetActiveURL(const GURL& url); + +// Sets the Client ID that is used as GUID if a Chrome process crashes. +void SetClientId(const std::string& client_id); + +// Sets the list of "active" extensions in this process. We overload "active" to +// mean different things depending on the process type: +// - browser: all enabled extensions +// - renderer: the unique set of extension ids from all content scripts +// - extension: the id of each extension running in this process (there can be +// multiple because of process collapsing). +void SetActiveExtensions(const std::set<std::string>& extension_ids); + +// Sets the data on the gpu to send along with crash reports. +void SetGpuInfo(const GPUInfo& gpu_info); + +// Simple wrapper class that sets the active URL in it's constructor and clears +// the active URL in the destructor. +class ScopedActiveURLSetter { + public: + explicit ScopedActiveURLSetter(const GURL& url) { + SetActiveURL(url); + } + + ~ScopedActiveURLSetter() { + SetActiveURL(GURL()); + } + + private: + DISALLOW_COPY_AND_ASSIGN(ScopedActiveURLSetter); +}; + +} // namespace child_process_logging + +#if defined(OS_MACOSX) && __OBJC__ + +@class NSString; + +typedef void (*SetCrashKeyValueFuncPtr)(NSString*, NSString*); +typedef void (*ClearCrashKeyValueFuncPtr)(NSString*); + +namespace child_process_logging { +void SetCrashKeyFunctions(SetCrashKeyValueFuncPtr set_key_func, + ClearCrashKeyValueFuncPtr clear_key_func); +void SetActiveURLImpl(const GURL& url, + SetCrashKeyValueFuncPtr set_key_func, + ClearCrashKeyValueFuncPtr clear_key_func); + +extern const int kMaxNumCrashURLChunks; +extern const int kMaxNumURLChunkValueLength; +extern const char *kUrlChunkFormatStr; +} // namespace child_process_logging + +#endif // defined(OS_MACOSX) && __OBJC__ + +#endif // CHROME_COMMON_CHILD_PROCESS_LOGGING_H_ diff --git a/chrome/common/child_process_logging_linux.cc b/chrome/common/child_process_logging_linux.cc new file mode 100644 index 0000000..94cb34b --- /dev/null +++ b/chrome/common/child_process_logging_linux.cc @@ -0,0 +1,42 @@ +// Copyright (c) 2010 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 "chrome/common/child_process_logging.h" + +#include "base/logging.h" +#include "base/string_util.h" +#include "chrome/common/gpu_info.h" +#include "chrome/installer/util/google_update_settings.h" +#include "googleurl/src/gurl.h" + +namespace child_process_logging { + +// We use a static string to hold the most recent active url. If we crash, the +// crash handler code will send the contents of this string to the browser. +std::string active_url; + +void SetActiveURL(const GURL& url) { + active_url = url.possibly_invalid_spec(); +} + +void SetClientId(const std::string& client_id) { + std::string str(client_id); + ReplaceSubstringsAfterOffset(&str, 0, "-", ""); + + if (str.empty()) + return; + + std::wstring wstr = ASCIIToWide(str); + GoogleUpdateSettings::SetMetricsId(wstr); +} + +void SetActiveExtensions(const std::set<std::string>& extension_ids) { + // TODO(port) +} + +void SetGpuInfo(const GPUInfo& gpu_info) { + // TODO(rlp): Bug 38737. +} + +} // namespace child_process_logging diff --git a/chrome/common/child_process_logging_mac.mm b/chrome/common/child_process_logging_mac.mm new file mode 100644 index 0000000..f0356cd --- /dev/null +++ b/chrome/common/child_process_logging_mac.mm @@ -0,0 +1,136 @@ +// Copyright (c) 2009 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 "chrome/common/child_process_logging.h" + +#import <Foundation/Foundation.h> + +#include "base/string_util.h" +#include "chrome/common/gpu_info.h" +#include "chrome/installer/util/google_update_settings.h" +#include "googleurl/src/gurl.h" + +namespace child_process_logging { + +const int kMaxNumCrashURLChunks = 8; +const int kMaxNumURLChunkValueLength = 255; +const char *kUrlChunkFormatStr = "url-chunk-%d"; +const char *kGuidParamName = "guid"; +const char *kGPUVendorIdParamName = "vendid"; +const char *kGPUDeviceIdParamName = "devid"; +const char *kGPUDriverVersionParamName = "driver"; +const char *kGPUPixelShaderVersionParamName = "psver"; +const char *kGPUVertexShaderVersionParamName = "vsver"; + +static SetCrashKeyValueFuncPtr g_set_key_func; +static ClearCrashKeyValueFuncPtr g_clear_key_func; + +void SetCrashKeyFunctions(SetCrashKeyValueFuncPtr set_key_func, + ClearCrashKeyValueFuncPtr clear_key_func) { + g_set_key_func = set_key_func; + g_clear_key_func = clear_key_func; +} + +void SetActiveURLImpl(const GURL& url, + SetCrashKeyValueFuncPtr set_key_func, + ClearCrashKeyValueFuncPtr clear_key_func) { + + NSString *kUrlChunkFormatStr_utf8 = [NSString + stringWithUTF8String:kUrlChunkFormatStr]; + + // First remove any old url chunks we might have lying around. + for (int i = 0; i < kMaxNumCrashURLChunks; i++) { + // On Windows the url-chunk items are 1-based, so match that. + NSString *key = [NSString stringWithFormat:kUrlChunkFormatStr_utf8, i+1]; + clear_key_func(key); + } + + const std::string& raw_url_utf8 = url.possibly_invalid_spec(); + NSString *raw_url = [NSString stringWithUTF8String:raw_url_utf8.c_str()]; + size_t raw_url_length = [raw_url length]; + + // Bail on zero-length URLs. + if (raw_url_length == 0) { + return; + } + + // Parcel the URL up into up to 8, 255 byte segments. + size_t start_ofs = 0; + for (int i = 0; + i < kMaxNumCrashURLChunks && start_ofs < raw_url_length; + ++i) { + + // On Windows the url-chunk items are 1-based, so match that. + NSString *key = [NSString stringWithFormat:kUrlChunkFormatStr_utf8, i+1]; + NSRange range; + range.location = start_ofs; + range.length = std::min((size_t)kMaxNumURLChunkValueLength, + raw_url_length - start_ofs); + NSString *value = [raw_url substringWithRange:range]; + set_key_func(key, value); + + // Next chunk. + start_ofs += kMaxNumURLChunkValueLength; + } +} + +void SetClientIdImpl(const std::string& client_id, + SetCrashKeyValueFuncPtr set_key_func) { + NSString *key = [NSString stringWithUTF8String:kGuidParamName]; + NSString *value = [NSString stringWithUTF8String:client_id.c_str()]; + set_key_func(key, value); +} + +void SetActiveURL(const GURL& url) { + if (g_set_key_func && g_clear_key_func) + SetActiveURLImpl(url, g_set_key_func, g_clear_key_func); +} + +void SetClientId(const std::string& client_id) { + std::string str(client_id); + ReplaceSubstringsAfterOffset(&str, 0, "-", ""); + + if (g_set_key_func) + SetClientIdImpl(str, g_set_key_func); + + std::wstring wstr = ASCIIToWide(str); + GoogleUpdateSettings::SetMetricsId(wstr); +} + +void SetActiveExtensions(const std::set<std::string>& extension_ids) { + // TODO(port) +} + +void SetGpuKeyValue(const char* param_name, const std::string& value_str, + SetCrashKeyValueFuncPtr set_key_func) { + NSString *key = [NSString stringWithUTF8String:param_name]; + NSString *value = [NSString stringWithUTF8String:value_str.c_str()]; + set_key_func(key, value); +} + +void SetGpuInfoImpl(const GPUInfo& gpu_info, + SetCrashKeyValueFuncPtr set_key_func) { + SetGpuKeyValue(kGPUVendorIdParamName, + UintToString(gpu_info.vendor_id()), + set_key_func); + SetGpuKeyValue(kGPUDeviceIdParamName, + UintToString(gpu_info.device_id()), + set_key_func); + SetGpuKeyValue(kGPUDriverVersionParamName, + WideToASCII(gpu_info.driver_version()), + set_key_func); + SetGpuKeyValue(kGPUPixelShaderVersionParamName, + UintToString(gpu_info.pixel_shader_version()), + set_key_func); + SetGpuKeyValue(kGPUVertexShaderVersionParamName, + UintToString(gpu_info.vertex_shader_version()), + set_key_func); +} + +void SetGpuInfo(const GPUInfo& gpu_info) { + if (g_set_key_func) + SetGpuInfoImpl(gpu_info, g_set_key_func); +} + +} // namespace child_process_logging diff --git a/chrome/common/child_process_logging_mac_unittest.mm b/chrome/common/child_process_logging_mac_unittest.mm new file mode 100644 index 0000000..a751287 --- /dev/null +++ b/chrome/common/child_process_logging_mac_unittest.mm @@ -0,0 +1,141 @@ +// Copyright (c) 2009 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 "chrome/common/child_process_logging.h" + +#import <Foundation/Foundation.h> + +#include "base/logging.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/platform_test.h" + +typedef PlatformTest ChildProcessLoggingTest; + +namespace { + +// Class to mock breakpad's setkeyvalue/clearkeyvalue functions needed for +// SetActiveRendererURLImpl. +// The Keys are stored in a static dictionary and methods are provided to +// verify correctness. +class MockBreakpadKeyValueStore { + public: + MockBreakpadKeyValueStore() { + // Only one of these objects can be active at once. + DCHECK(dict == NULL); + dict = [[NSMutableDictionary alloc] init]; + } + + ~MockBreakpadKeyValueStore() { + // Only one of these objects can be active at once. + DCHECK(dict != NULL); + [dict release]; + dict = NULL; + } + + static void SetKeyValue(NSString* key, NSString* value) { + DCHECK(dict != NULL); + [dict setObject:value forKey:key]; + } + + static void ClearKeyValue(NSString *key) { + DCHECK(dict != NULL); + [dict removeObjectForKey:key]; + } + + int CountDictionaryEntries() { + return [dict count]; + } + + bool VerifyDictionaryContents(const std::string &url) { + using child_process_logging::kMaxNumCrashURLChunks; + using child_process_logging::kMaxNumURLChunkValueLength; + using child_process_logging::kUrlChunkFormatStr; + + int num_url_chunks = CountDictionaryEntries(); + EXPECT_TRUE(num_url_chunks <= kMaxNumCrashURLChunks); + + NSString *kUrlChunkFormatStr_utf8 = [NSString + stringWithUTF8String:kUrlChunkFormatStr]; + + NSString *accumulated_url = @""; + for (int i = 0; i < num_url_chunks; ++i) { + // URL chunk names are 1-based. + NSString *key = [NSString stringWithFormat:kUrlChunkFormatStr_utf8, i+1]; + EXPECT_TRUE(key != NULL); + NSString *value = [dict objectForKey:key]; + EXPECT_TRUE([value length] > 0); + EXPECT_TRUE([value length] <= (unsigned)kMaxNumURLChunkValueLength); + accumulated_url = [accumulated_url stringByAppendingString:value]; + } + + NSString *expected_url = [NSString stringWithUTF8String:url.c_str()]; + return([accumulated_url isEqualToString:expected_url]); + } + + private: + static NSMutableDictionary* dict; + DISALLOW_COPY_AND_ASSIGN(MockBreakpadKeyValueStore); +}; + +// static +NSMutableDictionary* MockBreakpadKeyValueStore::dict; + +} // namespace + +// Call through to SetActiveURLImpl using the functions from +// MockBreakpadKeyValueStore. +void SetActiveURLWithMock(const GURL& url) { + using child_process_logging::SetActiveURLImpl; + + SetCrashKeyValueFuncPtr setFunc = MockBreakpadKeyValueStore::SetKeyValue; + ClearCrashKeyValueFuncPtr clearFunc = + MockBreakpadKeyValueStore::ClearKeyValue; + + SetActiveURLImpl(url, setFunc, clearFunc); +} + +TEST_F(ChildProcessLoggingTest, TestUrlSplitting) { + using child_process_logging::kMaxNumCrashURLChunks; + using child_process_logging::kMaxNumURLChunkValueLength; + + const std::string short_url("http://abc/"); + std::string long_url("http://"); + std::string overflow_url("http://"); + + long_url += std::string(kMaxNumURLChunkValueLength * 2, 'a'); + long_url += "/"; + + int max_num_chars_stored_in_dump = kMaxNumURLChunkValueLength * + kMaxNumCrashURLChunks; + overflow_url += std::string(max_num_chars_stored_in_dump + 1, 'a'); + overflow_url += "/"; + + // Check that Clearing NULL URL works. + MockBreakpadKeyValueStore mock; + SetActiveURLWithMock(GURL()); + EXPECT_EQ(mock.CountDictionaryEntries(), 0); + + // Check that we can set a URL. + SetActiveURLWithMock(GURL(short_url.c_str())); + EXPECT_TRUE(mock.VerifyDictionaryContents(short_url)); + EXPECT_EQ(mock.CountDictionaryEntries(), 1); + SetActiveURLWithMock(GURL()); + EXPECT_EQ(mock.CountDictionaryEntries(), 0); + + // Check that we can replace a long url with a short url. + SetActiveURLWithMock(GURL(long_url.c_str())); + EXPECT_TRUE(mock.VerifyDictionaryContents(long_url)); + SetActiveURLWithMock(GURL(short_url.c_str())); + EXPECT_TRUE(mock.VerifyDictionaryContents(short_url)); + SetActiveURLWithMock(GURL()); + EXPECT_EQ(mock.CountDictionaryEntries(), 0); + + + // Check that overflow works correctly. + SetActiveURLWithMock(GURL(overflow_url.c_str())); + EXPECT_TRUE(mock.VerifyDictionaryContents( + overflow_url.substr(0, max_num_chars_stored_in_dump))); + SetActiveURLWithMock(GURL()); + EXPECT_EQ(mock.CountDictionaryEntries(), 0); +} diff --git a/chrome/common/child_process_logging_win.cc b/chrome/common/child_process_logging_win.cc new file mode 100644 index 0000000..1b18e6e --- /dev/null +++ b/chrome/common/child_process_logging_win.cc @@ -0,0 +1,115 @@ +// Copyright (c) 2010 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 "chrome/common/child_process_logging.h" + +#include <windows.h> + +#include "base/string_util.h" +#include "base/utf_string_conversions.h" +#include "chrome/common/chrome_constants.h" +#include "chrome/installer/util/google_update_settings.h" +#include "googleurl/src/gurl.h" + +namespace child_process_logging { +// exported in breakpad_win.cc: void __declspec(dllexport) __cdecl SetActiveURL. +typedef void (__cdecl *MainSetActiveURL)(const wchar_t*); + +// exported in breakpad_win.cc: void __declspec(dllexport) __cdecl SetClientId. +typedef void (__cdecl *MainSetClientId)(const wchar_t*); + +// exported in breakpad_win.cc: +// void __declspec(dllexport) __cdecl SetExtensionID. +typedef void (__cdecl *MainSetExtensionID)(size_t, const wchar_t*); + +// exported in breakpad_win.cc: void __declspec(dllexport) __cdecl SetGpuInfo. +typedef void (__cdecl *MainSetGpuInfo)(const wchar_t*, const wchar_t*, + const wchar_t*, const wchar_t*, + const wchar_t*); + +void SetActiveURL(const GURL& url) { + static MainSetActiveURL set_active_url = NULL; + // note: benign race condition on set_active_url. + if (!set_active_url) { + HMODULE exe_module = GetModuleHandle(chrome::kBrowserProcessExecutableName); + if (!exe_module) + return; + set_active_url = reinterpret_cast<MainSetActiveURL>( + GetProcAddress(exe_module, "SetActiveURL")); + if (!set_active_url) + return; + } + + (set_active_url)(UTF8ToWide(url.possibly_invalid_spec()).c_str()); +} + +void SetClientId(const std::string& client_id) { + std::string str(client_id); + // Remove all instance of '-' char from the GUID. So BCD-WXY becomes BCDWXY. + ReplaceSubstringsAfterOffset(&str, 0, "-", ""); + + if (str.empty()) + return; + + std::wstring wstr = ASCIIToWide(str); + std::wstring old_wstr; + if (!GoogleUpdateSettings::GetMetricsId(&old_wstr) || + wstr != old_wstr) + GoogleUpdateSettings::SetMetricsId(wstr); + + static MainSetClientId set_client_id = NULL; + if (!set_client_id) { + HMODULE exe_module = GetModuleHandle(chrome::kBrowserProcessExecutableName); + if (!exe_module) + return; + set_client_id = reinterpret_cast<MainSetClientId>( + GetProcAddress(exe_module, "SetClientId")); + if (!set_client_id) + return; + } + (set_client_id)(wstr.c_str()); +} + +void SetActiveExtensions(const std::set<std::string>& extension_ids) { + static MainSetExtensionID set_extension_id = NULL; + if (!set_extension_id) { + HMODULE exe_module = GetModuleHandle(chrome::kBrowserProcessExecutableName); + if (!exe_module) + return; + set_extension_id = reinterpret_cast<MainSetExtensionID>( + GetProcAddress(exe_module, "SetExtensionID")); + if (!set_extension_id) + return; + } + + std::set<std::string>::const_iterator iter = extension_ids.begin(); + for (size_t i = 0; i < kMaxReportedActiveExtensions; ++i) { + if (iter != extension_ids.end()) { + (set_extension_id)(i, ASCIIToWide(iter->c_str()).c_str()); + ++iter; + } else { + (set_extension_id)(i, L""); + } + } +} + +void SetGpuInfo(const GPUInfo& gpu_info) { + static MainSetGpuInfo set_gpu_info = NULL; + if (!set_gpu_info) { + HMODULE exe_module = GetModuleHandle(chrome::kBrowserProcessExecutableName); + if (!exe_module) + return; + set_gpu_info = reinterpret_cast<MainSetGpuInfo>( + GetProcAddress(exe_module, "SetGpuInfo")); + if (!set_gpu_info) + return; + } + (set_gpu_info)(UintToWString(gpu_info.vendor_id()).c_str(), + UintToWString(gpu_info.device_id()).c_str(), + gpu_info.driver_version().c_str(), + UintToWString(gpu_info.pixel_shader_version()).c_str(), + UintToWString(gpu_info.vertex_shader_version()).c_str()); +} + +} // namespace child_process_logging diff --git a/chrome/common/child_thread.cc b/chrome/common/child_thread.cc new file mode 100644 index 0000000..91d276e --- /dev/null +++ b/chrome/common/child_thread.cc @@ -0,0 +1,182 @@ +// Copyright (c) 2009 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 "chrome/common/child_thread.h" + +#include "base/string_util.h" +#include "base/command_line.h" +#include "chrome/common/child_process.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/notification_service.h" +#include "chrome/common/plugin_messages.h" +#include "chrome/common/socket_stream_dispatcher.h" +#include "ipc/ipc_logging.h" +#include "ipc/ipc_message.h" +#include "ipc/ipc_sync_message_filter.h" +#include "ipc/ipc_switches.h" +#include "webkit/glue/webkit_glue.h" + + +ChildThread::ChildThread() { + channel_name_ = CommandLine::ForCurrentProcess()->GetSwitchValueASCII( + switches::kProcessChannelID); + Init(); +} + +ChildThread::ChildThread(const std::string& channel_name) + : channel_name_(channel_name) { + Init(); +} + +void ChildThread::Init() { + check_with_browser_before_shutdown_ = false; + on_channel_error_called_ = false; + message_loop_ = MessageLoop::current(); + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUserAgent)) { + webkit_glue::SetUserAgent( + CommandLine::ForCurrentProcess()->GetSwitchValueASCII( + switches::kUserAgent)); + } + + channel_.reset(new IPC::SyncChannel(channel_name_, + IPC::Channel::MODE_CLIENT, this, NULL, + ChildProcess::current()->io_message_loop(), true, + ChildProcess::current()->GetShutDownEvent())); +#ifdef IPC_MESSAGE_LOG_ENABLED + IPC::Logging::current()->SetIPCSender(this); +#endif + + resource_dispatcher_.reset(new ResourceDispatcher(this)); + socket_stream_dispatcher_.reset(new SocketStreamDispatcher()); + + sync_message_filter_ = + new IPC::SyncMessageFilter(ChildProcess::current()->GetShutDownEvent()); + channel_->AddFilter(sync_message_filter_.get()); + + // When running in unit tests, there is already a NotificationService object. + // Since only one can exist at a time per thread, check first. + if (!NotificationService::current()) + notification_service_.reset(new NotificationService); +} + +ChildThread::~ChildThread() { +#ifdef IPC_MESSAGE_LOG_ENABLED + IPC::Logging::current()->SetIPCSender(NULL); +#endif + + channel_->RemoveFilter(sync_message_filter_.get()); + + // The ChannelProxy object caches a pointer to the IPC thread, so need to + // reset it as it's not guaranteed to outlive this object. + // NOTE: this also has the side-effect of not closing the main IPC channel to + // the browser process. This is needed because this is the signal that the + // browser uses to know that this process has died, so we need it to be alive + // until this process is shut down, and the OS closes the handle + // automatically. We used to watch the object handle on Windows to do this, + // but it wasn't possible to do so on POSIX. + channel_->ClearIPCMessageLoop(); +} + +void ChildThread::OnChannelError() { + set_on_channel_error_called(true); + MessageLoop::current()->Quit(); +} + +bool ChildThread::Send(IPC::Message* msg) { + if (!channel_.get()) { + delete msg; + return false; + } + + return channel_->Send(msg); +} + +void ChildThread::AddRoute(int32 routing_id, IPC::Channel::Listener* listener) { + DCHECK(MessageLoop::current() == message_loop()); + + router_.AddRoute(routing_id, listener); +} + +void ChildThread::RemoveRoute(int32 routing_id) { + DCHECK(MessageLoop::current() == message_loop()); + + router_.RemoveRoute(routing_id); +} + +IPC::Channel::Listener* ChildThread::ResolveRoute(int32 routing_id) { + DCHECK(MessageLoop::current() == message_loop()); + + return router_.ResolveRoute(routing_id); +} + +webkit_glue::ResourceLoaderBridge* ChildThread::CreateBridge( + const webkit_glue::ResourceLoaderBridge::RequestInfo& request_info, + int host_renderer_id, + int host_render_view_id) { + return resource_dispatcher()-> + CreateBridge(request_info, host_renderer_id, host_render_view_id); +} + + +void ChildThread::OnMessageReceived(const IPC::Message& msg) { + // Resource responses are sent to the resource dispatcher. + if (resource_dispatcher_->OnMessageReceived(msg)) + return; + if (socket_stream_dispatcher_->OnMessageReceived(msg)) + return; + + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(ChildThread, msg) + IPC_MESSAGE_HANDLER(PluginProcessMsg_AskBeforeShutdown, OnAskBeforeShutdown) + IPC_MESSAGE_HANDLER(PluginProcessMsg_Shutdown, OnShutdown) +#if defined(IPC_MESSAGE_LOG_ENABLED) + IPC_MESSAGE_HANDLER(PluginProcessMsg_SetIPCLoggingEnabled, + OnSetIPCLoggingEnabled) +#endif + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + + if (handled) + return; + + if (msg.routing_id() == MSG_ROUTING_CONTROL) { + OnControlMessageReceived(msg); + } else { + router_.OnMessageReceived(msg); + } +} + +void ChildThread::OnAskBeforeShutdown() { + check_with_browser_before_shutdown_ = true; +} + +void ChildThread::OnShutdown() { + MessageLoop::current()->Quit(); +} + +#if defined(IPC_MESSAGE_LOG_ENABLED) +void ChildThread::OnSetIPCLoggingEnabled(bool enable) { + if (enable) + IPC::Logging::current()->Enable(); + else + IPC::Logging::current()->Disable(); +} +#endif // IPC_MESSAGE_LOG_ENABLED + +ChildThread* ChildThread::current() { + return ChildProcess::current()->main_thread(); +} + +void ChildThread::OnProcessFinalRelease() { + if (on_channel_error_called_ || !check_with_browser_before_shutdown_) { + MessageLoop::current()->Quit(); + return; + } + + // The child process shutdown sequence is a request response based mechanism, + // where we send out an initial feeler request to the child process host + // instance in the browser to verify if it's ok to shutdown the child process. + // The browser then sends back a response if it's ok to shutdown. + Send(new PluginProcessHostMsg_ShutdownRequest); +} diff --git a/chrome/common/child_thread.h b/chrome/common/child_thread.h new file mode 100644 index 0000000..72af5aa --- /dev/null +++ b/chrome/common/child_thread.h @@ -0,0 +1,123 @@ +// Copyright (c) 2009 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 CHROME_COMMON_CHILD_THREAD_H_ +#define CHROME_COMMON_CHILD_THREAD_H_ + +#include "base/basictypes.h" +#include "base/scoped_ptr.h" +#include "chrome/common/message_router.h" +#include "chrome/common/resource_dispatcher.h" +#include "ipc/ipc_sync_channel.h" +#include "ipc/ipc_message.h" + +class NotificationService; +class SocketStreamDispatcher; + +namespace IPC { +class SyncMessageFilter; +} + +// The main thread of a child process derives from this class. +class ChildThread : public IPC::Channel::Listener, + public IPC::Message::Sender { + public: + // Creates the thread. + ChildThread(); + // Used for single-process mode. + explicit ChildThread(const std::string& channel_name); + virtual ~ChildThread(); + + // IPC::Message::Sender implementation: + virtual bool Send(IPC::Message* msg); + + // See documentation on MessageRouter for AddRoute and RemoveRoute + void AddRoute(int32 routing_id, IPC::Channel::Listener* listener); + void RemoveRoute(int32 routing_id); + + IPC::Channel::Listener* ResolveRoute(int32 routing_id); + + // Creates a ResourceLoaderBridge. + // Tests can override this method if they want a custom loading behavior. + virtual webkit_glue::ResourceLoaderBridge* CreateBridge( + const webkit_glue::ResourceLoaderBridge::RequestInfo& request_info, + int host_renderer_id, + int host_render_view_id); + + ResourceDispatcher* resource_dispatcher() { + return resource_dispatcher_.get(); + } + + SocketStreamDispatcher* socket_stream_dispatcher() { + return socket_stream_dispatcher_.get(); + } + + // Safe to call on any thread, as long as it's guaranteed that the thread's + // lifetime is less than the main thread. + IPC::SyncMessageFilter* sync_message_filter() { return sync_message_filter_; } + + MessageLoop* message_loop() { return message_loop_; } + + // Returns the one child thread. + static ChildThread* current(); + + protected: + friend class ChildProcess; + + // Called when the process refcount is 0. + void OnProcessFinalRelease(); + + virtual void OnControlMessageReceived(const IPC::Message& msg) { } + virtual void OnAskBeforeShutdown(); + virtual void OnShutdown(); + +#ifdef IPC_MESSAGE_LOG_ENABLED + virtual void OnSetIPCLoggingEnabled(bool enable); +#endif + + IPC::SyncChannel* channel() { return channel_.get(); } + + void set_on_channel_error_called(bool on_channel_error_called) { + on_channel_error_called_ = on_channel_error_called; + } + + private: + void Init(); + + // IPC::Channel::Listener implementation: + virtual void OnMessageReceived(const IPC::Message& msg); + virtual void OnChannelError(); + + std::string channel_name_; + scoped_ptr<IPC::SyncChannel> channel_; + + // Allows threads other than the main thread to send sync messages. + scoped_refptr<IPC::SyncMessageFilter> sync_message_filter_; + + // Implements message routing functionality to the consumers of ChildThread. + MessageRouter router_; + + // Handles resource loads for this process. + scoped_ptr<ResourceDispatcher> resource_dispatcher_; + + // Handles SocketStream for this process. + scoped_ptr<SocketStreamDispatcher> socket_stream_dispatcher_; + + // If true, checks with the browser process before shutdown. This avoids race + // conditions if the process refcount is 0 but there's an IPC message inflight + // that would addref it. + bool check_with_browser_before_shutdown_; + + // The OnChannelError() callback was invoked - the channel is dead, don't + // attempt to communicate. + bool on_channel_error_called_; + + MessageLoop* message_loop_; + + scoped_ptr<NotificationService> notification_service_; + + DISALLOW_COPY_AND_ASSIGN(ChildThread); +}; + +#endif // CHROME_COMMON_CHILD_THREAD_H_ diff --git a/chrome/common/chrome_constants.cc b/chrome/common/chrome_constants.cc new file mode 100644 index 0000000..47f0d52 --- /dev/null +++ b/chrome/common/chrome_constants.cc @@ -0,0 +1,139 @@ +// Copyright (c) 2006-2008 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 "chrome/common/chrome_constants.h" + +#include "base/file_path.h" + +#define FPL FILE_PATH_LITERAL + +#if defined(OS_MACOSX) +#if defined(GOOGLE_CHROME_BUILD) +#define PRODUCT_STRING "Google Chrome" +#define PRODUCT_STRING_W L"Google Chrome" +#elif defined(CHROMIUM_BUILD) +#define PRODUCT_STRING "Chromium" +#define PRODUCT_STRING_W L"Chromium" +#else +#error Unknown branding +#endif +#endif // OS_MACOSX + +namespace chrome { + +// The following should not be used for UI strings; they are meant +// for system strings only. UI changes should be made in the GRD. +#if defined(OS_WIN) +const wchar_t kBrowserProcessExecutableName[] = L"chrome.exe"; +const wchar_t kHelperProcessExecutableName[] = L"chrome.exe"; +#elif defined(OS_LINUX) +const wchar_t kBrowserProcessExecutableName[] = L"chrome"; +// Helper processes end up with a name of "exe" due to execing via +// /proc/self/exe. See bug 22703. +const wchar_t kHelperProcessExecutableName[] = L"exe"; +#elif defined(OS_MACOSX) +const wchar_t kBrowserProcessExecutableName[] = PRODUCT_STRING_W; +const wchar_t kHelperProcessExecutableName[] = PRODUCT_STRING_W L" Helper"; +#endif // OS_* +#if defined(OS_WIN) +const wchar_t kBrowserProcessExecutablePath[] = L"chrome.exe"; +const FilePath::CharType kHelperProcessExecutablePath[] = FPL("chrome.exe"); +#elif defined(OS_LINUX) +const wchar_t kBrowserProcessExecutablePath[] = L"chrome"; +const FilePath::CharType kHelperProcessExecutablePath[] = FPL("chrome"); +#elif defined(OS_MACOSX) +const wchar_t kBrowserProcessExecutablePath[] = + PRODUCT_STRING_W L".app/Contents/MacOS/" PRODUCT_STRING_W; +const FilePath::CharType kHelperProcessExecutablePath[] = + FPL(PRODUCT_STRING " Helper.app/Contents/MacOS/" PRODUCT_STRING " Helper"); +#endif // OS_* +#if defined(OS_MACOSX) +const FilePath::CharType kFrameworkName[] = + FPL(PRODUCT_STRING " Framework.framework"); +#endif // OS_MACOSX +const wchar_t kNaClAppName[] = L"nacl64"; +#if defined(GOOGLE_CHROME_BUILD) +const wchar_t kBrowserAppName[] = L"Chrome"; +const char kStatsFilename[] = "ChromeStats2"; +#else +const wchar_t kBrowserAppName[] = L"Chromium"; +const char kStatsFilename[] = "ChromiumStats2"; +#endif + +#if defined(OS_WIN) +const wchar_t kStatusTrayWindowClass[] = L"Chrome_StatusTrayWindow"; +#endif // defined(OS_WIN) + +const wchar_t kMessageWindowClass[] = L"Chrome_MessageWindow"; +const wchar_t kCrashReportLog[] = L"Reported Crashes.txt"; +const wchar_t kTestingInterfaceDLL[] = L"testing_interface.dll"; +const wchar_t kNotSignedInProfile[] = L"Default"; +const wchar_t kNotSignedInID[] = L"not-signed-in"; +const wchar_t kBrowserResourcesDll[] = L"chrome.dll"; +const FilePath::CharType kExtensionFileExtension[] = FPL("crx"); + +// filenames +const FilePath::CharType kArchivedHistoryFilename[] = FPL("Archived History"); +const FilePath::CharType kCacheDirname[] = FPL("Cache"); +const FilePath::CharType kMediaCacheDirname[] = FPL("Media Cache"); +const FilePath::CharType kOffTheRecordMediaCacheDirname[] = + FPL("Incognito Media Cache"); +const FilePath::CharType kAppCacheDirname[] = FPL("Application Cache"); +const FilePath::CharType kChromePluginDataDirname[] = FPL("Plugin Data"); +const FilePath::CharType kThemePackFilename[] = FPL("Cached Theme.pak"); +const FilePath::CharType kCookieFilename[] = FPL("Cookies"); +const FilePath::CharType kExtensionsCookieFilename[] = FPL("Extension Cookies"); +const FilePath::CharType kFaviconsFilename[] = FPL("Favicons"); +const FilePath::CharType kHistoryFilename[] = FPL("History"); +const FilePath::CharType kLocalStateFilename[] = FPL("Local State"); +const FilePath::CharType kPreferencesFilename[] = FPL("Preferences"); +const FilePath::CharType kSafeBrowsingFilename[] = FPL("Safe Browsing"); +// WARNING: SingletonSocket can't contain spaces, because otherwise +// chrome_process_util_linux would be broken. +const FilePath::CharType kSingletonSocketFilename[] = FPL("SingletonSocket"); +const FilePath::CharType kSingletonLockFilename[] = FPL("SingletonLock"); +const FilePath::CharType kThumbnailsFilename[] = FPL("Thumbnails"); +const FilePath::CharType kNewTabThumbnailsFilename[] = FPL("Top Thumbnails"); +const FilePath::CharType kTopSitesFilename[] = FPL("Top Sites"); +const wchar_t kUserDataDirname[] = L"User Data"; +const FilePath::CharType kUserScriptsDirname[] = FPL("User Scripts"); +const FilePath::CharType kWebDataFilename[] = FPL("Web Data"); +const FilePath::CharType kBookmarksFileName[] = FPL("Bookmarks"); +const FilePath::CharType kHistoryBookmarksFileName[] = + FPL("Bookmarks From History"); +const FilePath::CharType kCustomDictionaryFileName[] = + FPL("Custom Dictionary.txt"); +const FilePath::CharType kLoginDataFileName[] = FPL("Login Data"); +const FilePath::CharType kJumpListIconDirname[] = FPL("JumpListIcons"); +const FilePath::CharType kWebAppDirname[] = FPL("Web Applications"); +const FilePath::CharType kServiceStateFileName[] = FPL("Service State"); + +// This number used to be limited to 32 in the past (see b/535234). +const unsigned int kMaxRendererProcessCount = 42; +const int kStatsMaxThreads = 32; +const int kStatsMaxCounters = 300; + +const size_t kMaxTitleChars = 4 * 1024; +const size_t kMaxURLChars = 2 * 1024 * 1024; +const size_t kMaxURLDisplayChars = 32 * 1024; + +// We don't enable record mode in the released product because users could +// potentially be tricked into running a product in record mode without +// knowing it. Enable in debug builds. Playback mode is allowed always, +// because it is useful for testing and not hazardous by itself. +#ifndef NDEBUG +const bool kRecordModeEnabled = true; +#else +const bool kRecordModeEnabled = false; +#endif + +const int kHistogramSynchronizerReservedSequenceNumber = 0; + +const int kMaxSessionHistoryEntries = 50; + +const wchar_t kChromiumRendererIdProperty[] = L"ChromiumRendererId"; + +} // namespace chrome + +#undef FPL diff --git a/chrome/common/chrome_constants.h b/chrome/common/chrome_constants.h new file mode 100644 index 0000000..a1efdbf --- /dev/null +++ b/chrome/common/chrome_constants.h @@ -0,0 +1,95 @@ +// Copyright (c) 2006-2008 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 handful of resource-like constants related to the Chrome application. + +#ifndef CHROME_COMMON_CHROME_CONSTANTS_H_ +#define CHROME_COMMON_CHROME_CONSTANTS_H_ + +#include "base/file_path.h" + +namespace chrome { + +extern const char kChromeVersion[]; + +extern const wchar_t kBrowserProcessExecutableName[]; +extern const wchar_t kHelperProcessExecutableName[]; +extern const wchar_t kBrowserProcessExecutablePath[]; +extern const FilePath::CharType kHelperProcessExecutablePath[]; +#if defined(OS_MACOSX) +extern const FilePath::CharType kFrameworkName[]; +#endif +extern const wchar_t kBrowserAppName[]; +#if defined(OS_WIN) +extern const wchar_t kStatusTrayWindowClass[]; +#endif // defined(OS_WIN) +extern const wchar_t kMessageWindowClass[]; +extern const wchar_t kCrashReportLog[]; +extern const wchar_t kTestingInterfaceDLL[]; +extern const wchar_t kNotSignedInProfile[]; +extern const wchar_t kNotSignedInID[]; +extern const char kStatsFilename[]; +extern const wchar_t kBrowserResourcesDll[]; +extern const wchar_t kNaClAppName[]; +extern const FilePath::CharType kExtensionFileExtension[]; + +// filenames +extern const FilePath::CharType kArchivedHistoryFilename[]; +extern const FilePath::CharType kCacheDirname[]; +extern const FilePath::CharType kMediaCacheDirname[]; +extern const FilePath::CharType kOffTheRecordMediaCacheDirname[]; +extern const FilePath::CharType kAppCacheDirname[]; +extern const FilePath::CharType kChromePluginDataDirname[]; +extern const FilePath::CharType kThemePackFilename[]; +extern const FilePath::CharType kCookieFilename[]; +extern const FilePath::CharType kExtensionsCookieFilename[]; +extern const FilePath::CharType kFaviconsFilename[]; +extern const FilePath::CharType kHistoryFilename[]; +extern const FilePath::CharType kLocalStateFilename[]; +extern const FilePath::CharType kPreferencesFilename[]; +extern const FilePath::CharType kSafeBrowsingFilename[]; +extern const FilePath::CharType kSingletonSocketFilename[]; +extern const FilePath::CharType kSingletonLockFilename[]; +extern const FilePath::CharType kThumbnailsFilename[]; +extern const FilePath::CharType kNewTabThumbnailsFilename[]; +extern const FilePath::CharType kTopSitesFilename[]; +extern const wchar_t kUserDataDirname[]; +extern const FilePath::CharType kUserScriptsDirname[]; +extern const FilePath::CharType kWebDataFilename[]; +extern const FilePath::CharType kBookmarksFileName[]; +extern const FilePath::CharType kHistoryBookmarksFileName[]; +extern const FilePath::CharType kCustomDictionaryFileName[]; +extern const FilePath::CharType kLoginDataFileName[]; +extern const FilePath::CharType kJumpListIconDirname[]; +extern const FilePath::CharType kWebAppDirname[]; +extern const FilePath::CharType kServiceStateFileName[]; + +extern const unsigned int kMaxRendererProcessCount; +extern const int kStatsMaxThreads; +extern const int kStatsMaxCounters; + +// The maximum number of characters of the document's title that we're willing +// to accept in the browser process. +extern const size_t kMaxTitleChars; +// The maximum number of characters in the URL that we're willing to accept +// in the browser process. It is set low enough to avoid damage to the browser +// but high enough that a web site can abuse location.hash for a little storage. +// We have different values for "max accepted" and "max displayed" because +// a data: URI may be legitimately massive, but the full URI would kill all +// known operating systems if you dropped it into a UI control. +extern const size_t kMaxURLChars; +extern const size_t kMaxURLDisplayChars; + +extern const bool kRecordModeEnabled; + +extern const int kHistogramSynchronizerReservedSequenceNumber; + +// The maximum number of session history entries per tab. +extern const int kMaxSessionHistoryEntries; + +extern const wchar_t kChromiumRendererIdProperty[]; + +} // namespace chrome + +#endif // CHROME_COMMON_CHROME_CONSTANTS_H_ diff --git a/chrome/common/chrome_counters.cc b/chrome/common/chrome_counters.cc new file mode 100644 index 0000000..fea0906 --- /dev/null +++ b/chrome/common/chrome_counters.cc @@ -0,0 +1,52 @@ +// Copyright (c) 2006-2008 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 "chrome/common/chrome_counters.h" + +#include "base/stats_counters.h" + +namespace chrome { + +// Note: We use the construct-on-first-use pattern here, because we don't +// want to fight with any static initializer ordering problems later. +// The downside of this is that the objects don't ever get cleaned up. +// But they are small and this is okay. + +// Note: Because these are constructed on-first-use, there is a slight +// race condition - two threads could initialize the same counter. +// If this happened, the stats table would still work just fine; +// we'd leak the extraneous StatsCounter object once, and that +// would be it. But these are small objects, so this is ok. + +StatsCounterTimer& Counters::chrome_main() { + static StatsCounterTimer* ctr = new StatsCounterTimer("Chrome.Init"); + return *ctr; +} + +StatsCounterTimer& Counters::renderer_main() { + static StatsCounterTimer* ctr = new StatsCounterTimer("Chrome.RendererInit"); + return *ctr; +} + +StatsCounterTimer& Counters::spellcheck_init() { + static StatsCounterTimer* ctr = new StatsCounterTimer("SpellCheck.Init"); + return *ctr; +} + +StatsRate& Counters::spellcheck_lookup() { + static StatsRate* ctr = new StatsRate("SpellCheck.Lookup"); + return *ctr; +} + +StatsCounterTimer& Counters::plugin_load() { + static StatsCounterTimer* ctr = new StatsCounterTimer("ChromePlugin.Load"); + return *ctr; +} + +StatsRate& Counters::plugin_intercept() { + static StatsRate* ctr = new StatsRate("ChromePlugin.Intercept"); + return *ctr; +} + +} // namespace chrome diff --git a/chrome/common/chrome_counters.h b/chrome/common/chrome_counters.h new file mode 100644 index 0000000..14cfa21 --- /dev/null +++ b/chrome/common/chrome_counters.h @@ -0,0 +1,39 @@ +// Copyright (c) 2006-2008 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. + +// Counters used within the browser. + +#ifndef CHROME_COMMON_CHROME_COUNTERS_H_ +#define CHROME_COMMON_CHROME_COUNTERS_H_ + +class StatsCounter; +class StatsCounterTimer; +class StatsRate; + +namespace chrome { + +class Counters { + public: + // The amount of time spent in chrome initialization. + static StatsCounterTimer& chrome_main(); + + // The amount of time spent in renderer initialization. + static StatsCounterTimer& renderer_main(); + + // Time spent in spellchecker initialization. + static StatsCounterTimer& spellcheck_init(); + + // Time/Count of spellcheck lookups. + static StatsRate& spellcheck_lookup(); + + // Time spent loading the Chrome plugins. + static StatsCounterTimer& plugin_load(); + + // Time/Count of plugin network interception. + static StatsRate& plugin_intercept(); +}; + +} // namespace chrome + +#endif // CHROME_COMMON_CHROME_COUNTERS_H_ diff --git a/chrome/common/chrome_descriptors.h b/chrome/common/chrome_descriptors.h new file mode 100644 index 0000000..8a4f6ee --- /dev/null +++ b/chrome/common/chrome_descriptors.h @@ -0,0 +1,16 @@ +// Copyright (c) 2009 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 CHROME_COMMON_CHROME_DESCRIPTORS_H_ +#define CHROME_COMMON_CHROME_DESCRIPTORS_H_ + +#include "ipc/ipc_descriptors.h" +// This is a list of global descriptor keys to be used with the +// base::GlobalDescriptors object (see base/global_descriptors_posix.h) +enum { + kCrashDumpSignal = kPrimaryIPCChannel + 1, + kSandboxIPCChannel = kPrimaryIPCChannel + 2, // http://code.google.com/p/chromium/LinuxSandboxIPC +}; + +#endif // CHROME_COMMON_CHROME_DESCRIPTORS_H_ diff --git a/chrome/common/chrome_paths.cc b/chrome/common/chrome_paths.cc new file mode 100644 index 0000000..6f77510 --- /dev/null +++ b/chrome/common/chrome_paths.cc @@ -0,0 +1,316 @@ +// Copyright (c) 2006-2010 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 "chrome/common/chrome_paths.h" + +#include "base/command_line.h" +#include "base/file_util.h" +#include "base/logging.h" +#include "base/path_service.h" +#include "base/string_util.h" +#include "base/sys_info.h" +#include "chrome/common/chrome_constants.h" +#include "chrome/common/chrome_paths_internal.h" +#include "chrome/common/chrome_switches.h" + +#if defined(OS_MACOSX) +#include "base/mac_util.h" +#endif + +namespace { + +// File name of the internal Flash plugin on different platforms. +const FilePath::CharType kInternalFlashPluginFileName[] = +#if defined(OS_MACOSX) + FILE_PATH_LITERAL("Flash Player Plugin for Chrome.plugin"); +#elif defined(OS_WIN) + FILE_PATH_LITERAL("gcswf32.dll"); +#else // OS_LINUX, etc. + FILE_PATH_LITERAL("libgcflashplayer.so"); +#endif + +} // namespace + +namespace chrome { + +// Gets the path for internal plugins. +bool GetInternalPluginsDirectory(FilePath* result) { +#if defined(OS_MACOSX) + // If called from Chrome, get internal plugins from a subdirectory of the + // framework. + if (mac_util::AmIBundled()) { + *result = chrome::GetFrameworkBundlePath(); + DCHECK(!result->empty()); + *result = result->Append("Internet Plug-Ins"); + return true; + } + // In tests, just look in the module directory (below). +#endif + + // The rest of the world expects plugins in the module directory. + return PathService::Get(base::DIR_MODULE, result); +} + +bool GetGearsPluginPathFromCommandLine(FilePath* path) { +#ifndef NDEBUG + // for debugging, support a cmd line based override + FilePath plugin_path = + CommandLine::ForCurrentProcess()->GetSwitchValuePath( + switches::kGearsPluginPathOverride); + *path = plugin_path; + return !plugin_path.empty(); +#else + return false; +#endif +} + +bool PathProvider(int key, FilePath* result) { + // Some keys are just aliases... + switch (key) { + case chrome::DIR_APP: + return PathService::Get(base::DIR_MODULE, result); + case chrome::DIR_LOGS: +#ifdef NDEBUG + // Release builds write to the data dir + return PathService::Get(chrome::DIR_USER_DATA, result); +#else + // Debug builds write next to the binary (in the build tree) +#if defined(OS_MACOSX) + if (!PathService::Get(base::DIR_EXE, result)) + return false; + if (mac_util::AmIBundled()) { + // If we're called from chrome, dump it beside the app (outside the + // app bundle), if we're called from a unittest, we'll already + // outside the bundle so use the exe dir. + // exe_dir gave us .../Chromium.app/Contents/MacOS/Chromium. + *result = result->DirName(); + *result = result->DirName(); + *result = result->DirName(); + } + return true; +#else + return PathService::Get(base::DIR_EXE, result); +#endif // defined(OS_MACOSX) +#endif // NDEBUG + case chrome::FILE_RESOURCE_MODULE: + return PathService::Get(base::FILE_MODULE, result); + } + + // Assume that we will not need to create the directory if it does not exist. + // This flag can be set to true for the cases where we want to create it. + bool create_dir = false; + + FilePath cur; + switch (key) { + case chrome::DIR_USER_DATA: + if (!GetDefaultUserDataDirectory(&cur)) { + NOTREACHED(); + return false; + } + create_dir = true; + break; + case chrome::DIR_USER_DOCUMENTS: + if (!GetUserDocumentsDirectory(&cur)) + return false; + create_dir = true; + break; + case chrome::DIR_DEFAULT_DOWNLOADS_SAFE: +#if defined(OS_WIN) + if (!GetUserDownloadsDirectorySafe(&cur)) + return false; + break; +#else + // Fall through for all other platforms. +#endif + case chrome::DIR_DEFAULT_DOWNLOADS: + if (!GetUserDownloadsDirectory(&cur)) + return false; + // Do not create the download directory here, we have done it twice now + // and annoyed a lot of users. + break; + case chrome::DIR_CRASH_DUMPS: + // The crash reports are always stored relative to the default user data + // directory. This avoids the problem of having to re-initialize the + // exception handler after parsing command line options, which may + // override the location of the app's profile directory. + if (!GetDefaultUserDataDirectory(&cur)) + return false; + cur = cur.Append(FILE_PATH_LITERAL("Crash Reports")); + create_dir = true; + break; + case chrome::DIR_USER_DESKTOP: + if (!GetUserDesktop(&cur)) + return false; + break; + case chrome::DIR_RESOURCES: +#if defined(OS_MACOSX) + cur = mac_util::MainAppBundlePath(); + cur = cur.Append(FILE_PATH_LITERAL("Resources")); +#else + if (!PathService::Get(chrome::DIR_APP, &cur)) + return false; + cur = cur.Append(FILE_PATH_LITERAL("resources")); +#endif + break; + case chrome::DIR_SHARED_RESOURCES: + if (!PathService::Get(chrome::DIR_RESOURCES, &cur)) + return false; + cur = cur.Append(FILE_PATH_LITERAL("shared")); + break; + case chrome::DIR_INSPECTOR: + if (!PathService::Get(chrome::DIR_RESOURCES, &cur)) + return false; + cur = cur.Append(FILE_PATH_LITERAL("inspector")); + break; + case chrome::DIR_APP_DICTIONARIES: +#if defined(OS_LINUX) || defined(OS_MACOSX) + // We can't write into the EXE dir on Linux, so keep dictionaries + // alongside the safe browsing database in the user data dir. + // And we don't want to write into the bundle on the Mac, so push + // it to the user data dir there also. + if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) + return false; +#else + if (!PathService::Get(base::DIR_EXE, &cur)) + return false; +#endif + cur = cur.Append(FILE_PATH_LITERAL("Dictionaries")); + create_dir = true; + break; + case chrome::DIR_USER_DATA_TEMP: + if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) + return false; + cur = cur.Append(FILE_PATH_LITERAL("Temp")); + create_dir = true; + break; + case chrome::DIR_INTERNAL_PLUGINS: + if (!GetInternalPluginsDirectory(&cur)) + return false; + break; + case chrome::FILE_LOCAL_STATE: + if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) + return false; + cur = cur.Append(chrome::kLocalStateFilename); + break; + case chrome::FILE_RECORDED_SCRIPT: + if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) + return false; + cur = cur.Append(FILE_PATH_LITERAL("script.log")); + break; + case chrome::FILE_GEARS_PLUGIN: + if (!GetGearsPluginPathFromCommandLine(&cur)) { +#if defined(OS_WIN) + // Search for gears.dll alongside chrome.dll first. This new model + // allows us to package gears.dll with the Chrome installer and update + // it while Chrome is running. + if (!GetInternalPluginsDirectory(&cur)) + return false; + cur = cur.Append(FILE_PATH_LITERAL("gears.dll")); + + if (!file_util::PathExists(cur)) { + if (!PathService::Get(base::DIR_EXE, &cur)) + return false; + cur = cur.Append(FILE_PATH_LITERAL("plugins")); + cur = cur.Append(FILE_PATH_LITERAL("gears")); + cur = cur.Append(FILE_PATH_LITERAL("gears.dll")); + } +#else + // No gears.dll on non-Windows systems. + return false; +#endif + } + break; + case chrome::FILE_FLASH_PLUGIN: + if (!GetInternalPluginsDirectory(&cur)) + return false; + cur = cur.Append(kInternalFlashPluginFileName); + if (!file_util::PathExists(cur)) + return false; + break; + case chrome::FILE_PDF_PLUGIN: + if (!GetInternalPluginsDirectory(&cur)) + return false; +#if defined(OS_WIN) + cur = cur.Append(FILE_PATH_LITERAL("pdf.dll")); +#elif defined(OS_MACOSX) + cur = cur.Append(FILE_PATH_LITERAL("PDF.plugin")); +#else // Linux and Chrome OS + cur = cur.Append(FILE_PATH_LITERAL("libpdf.so")); +#endif + break; + case chrome::FILE_RESOURCES_PACK: +#if defined(OS_MACOSX) + if (mac_util::AmIBundled()) { + cur = mac_util::MainAppBundlePath(); + cur = cur.Append(FILE_PATH_LITERAL("Resources")) + .Append(FILE_PATH_LITERAL("resources.pak")); + break; + } + // If we're not bundled on mac, resources.pak should be next to the + // binary (e.g., for unit tests). +#endif + if (!PathService::Get(base::DIR_MODULE, &cur)) + return false; + cur = cur.Append(FILE_PATH_LITERAL("resources.pak")); + break; +#if defined(OS_CHROMEOS) + case chrome::FILE_CHROMEOS_API: + if (!PathService::Get(base::DIR_MODULE, &cur)) + return false; + cur = cur.Append(FILE_PATH_LITERAL("chromeos")); + cur = cur.Append(FILE_PATH_LITERAL("libcros.so")); + break; +#endif + // The following are only valid in the development environment, and + // will fail if executed from an installed executable (because the + // generated path won't exist). + case chrome::DIR_TEST_DATA: + if (!PathService::Get(base::DIR_SOURCE_ROOT, &cur)) + return false; + cur = cur.Append(FILE_PATH_LITERAL("chrome")); + cur = cur.Append(FILE_PATH_LITERAL("test")); + cur = cur.Append(FILE_PATH_LITERAL("data")); + if (!file_util::PathExists(cur)) // we don't want to create this + return false; + break; + case chrome::DIR_TEST_TOOLS: + if (!PathService::Get(base::DIR_SOURCE_ROOT, &cur)) + return false; + cur = cur.Append(FILE_PATH_LITERAL("chrome")); + cur = cur.Append(FILE_PATH_LITERAL("tools")); + cur = cur.Append(FILE_PATH_LITERAL("test")); + if (!file_util::PathExists(cur)) // we don't want to create this + return false; + break; +#if !defined(OS_MACOSX) && defined(OS_POSIX) + case chrome::DIR_POLICY_FILES: { +#if defined(GOOGLE_CHROME_BUILD) + cur = FilePath(FILE_PATH_LITERAL("/etc/opt/chrome/policies")); +#else + cur = FilePath(FILE_PATH_LITERAL("/etc/chromium/policies")); +#endif + if (!file_util::PathExists(cur)) // we don't want to create this + return false; + break; + } +#endif + default: + return false; + } + + if (create_dir && !file_util::PathExists(cur) && + !file_util::CreateDirectory(cur)) + return false; + + *result = cur; + return true; +} + +// This cannot be done as a static initializer sadly since Visual Studio will +// eliminate this object file if there is no direct entry point into it. +void RegisterPathProvider() { + PathService::RegisterProvider(PathProvider, PATH_START, PATH_END); +} + +} // namespace chrome diff --git a/chrome/common/chrome_paths.h b/chrome/common/chrome_paths.h new file mode 100644 index 0000000..2d90e0a --- /dev/null +++ b/chrome/common/chrome_paths.h @@ -0,0 +1,80 @@ +// Copyright (c) 2006-2010 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 CHROME_COMMON_CHROME_PATHS_H__ +#define CHROME_COMMON_CHROME_PATHS_H__ + +#include "build/build_config.h" + +// This file declares path keys for the chrome module. These can be used with +// the PathService to access various special directories and files. + +namespace chrome { + +enum { + PATH_START = 1000, + + DIR_APP = PATH_START, // Directory where dlls and data reside. + DIR_LOGS, // Directory where logs should be written. + DIR_USER_DATA, // Directory where user data can be written. + DIR_CRASH_DUMPS, // Directory where crash dumps are written. + DIR_USER_DESKTOP, // Directory that correspond to the desktop. + DIR_RESOURCES, // Directory containing separate file resources + // used by Chrome at runtime. + DIR_SHARED_RESOURCES, // Directory containing js and css files used + // by DOMUI and component extensions. + DIR_INSPECTOR, // Directory where web inspector is located. + DIR_APP_DICTIONARIES, // Directory where the global dictionaries are. + DIR_USER_DOCUMENTS, // Directory for a user's "My Documents". + DIR_DEFAULT_DOWNLOADS_SAFE, // Directory for a user's + // "My Documents/Downloads". + DIR_DEFAULT_DOWNLOADS, // Directory for a user's downloads. + DIR_USER_DATA_TEMP, // A temp directory within DIR_USER_DATA. Use + // this when a temporary file or directory will + // be moved into the profile, to avoid issues + // moving across volumes. See crbug.com/13044 . + DIR_INTERNAL_PLUGINS, // Directory where internal plugins reside. +#if !defined(OS_MACOSX) && defined(OS_POSIX) + DIR_POLICY_FILES, // Directory for system-wide read-only + // policy files that allow sys-admins + // to set policies for chrome. This directory + // contains subdirectories. +#endif + FILE_RESOURCE_MODULE, // Full path and filename of the module that + // contains embedded resources (version, + // strings, images, etc.). + FILE_LOCAL_STATE, // Path and filename to the file in which + // machine/installation-specific state is saved. + FILE_RECORDED_SCRIPT, // Full path to the script.log file that + // contains recorded browser events for + // playback. + FILE_GEARS_PLUGIN, // Full path to the gears.dll plugin file. + FILE_FLASH_PLUGIN, // Full path to the internal Flash plugin file. + FILE_PDF_PLUGIN, // Full path to the internal PDF plugin file. + FILE_LIBAVCODEC, // Full path to libavcodec media decoding + // library. + FILE_LIBAVFORMAT, // Full path to libavformat media parsing + // library. + FILE_LIBAVUTIL, // Full path to libavutil media utility library. + FILE_RESOURCES_PACK, // Full path to the .pak file containing + // binary data (e.g., html files and images + // used by interal pages). +#if defined(OS_CHROMEOS) + FILE_CHROMEOS_API, // Full path to chrome os api shared object. +#endif + + + // Valid only in development environment; TODO(darin): move these + DIR_TEST_DATA, // Directory where unit test data resides. + DIR_TEST_TOOLS, // Directory where unit test tools reside. + + PATH_END +}; + +// Call once to register the provider for the path keys defined above. +void RegisterPathProvider(); + +} // namespace chrome + +#endif // CHROME_COMMON_CHROME_PATHS_H__ diff --git a/chrome/common/chrome_paths_internal.h b/chrome/common/chrome_paths_internal.h new file mode 100644 index 0000000..7d731e1 --- /dev/null +++ b/chrome/common/chrome_paths_internal.h @@ -0,0 +1,60 @@ +// Copyright (c) 2006-2008 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 CHROME_COMMON_CHROME_PATHS_INTERNAL_H_ +#define CHROME_COMMON_CHROME_PATHS_INTERNAL_H_ + +#include "build/build_config.h" +#include "base/file_path.h" + +namespace chrome { + +// Get the path to the user's data directory, regardless of whether +// DIR_USER_DATA has been overridden by a command-line option. +bool GetDefaultUserDataDirectory(FilePath* result); + +// This returns the base directory in which Chrome Frame stores user profiles. +// Note that this cannot be wrapped in a preprocessor define since +// CF and Google Chrome want to share the same binaries. +bool GetChromeFrameUserDataDirectory(FilePath* result); + +// Get the path to the user's documents directory. +bool GetUserDocumentsDirectory(FilePath* result); + +#if defined (OS_WIN) +// Gets the path to a safe default download directory for a user. +bool GetUserDownloadsDirectorySafe(FilePath* result); +#endif + +// Get the path to the user's downloads directory. +bool GetUserDownloadsDirectory(FilePath* result); + +// The path to the user's desktop. +bool GetUserDesktop(FilePath* result); + +#if defined(OS_MACOSX) +// The "versioned directory" is a directory in the browser .app bundle. It +// contains the bulk of the application, except for the things that the system +// requires be located at spepcific locations. The versioned directory is +// in the .app at Contents/Versions/w.x.y.z. +FilePath GetVersionedDirectory(); + +// This overrides the directory returned by |GetVersionedDirectory()|, to be +// used when |GetVersionedDirectory()| can't automatically determine the proper +// location. This is the case when the browser didn't load itself but by, e.g., +// the app mode loader. This should be called before |ChromeMain()|. This takes +// ownership of the object |path| and the caller must not delete it. +void SetOverrideVersionedDirectory(const FilePath* path); + +// Most of the application is further contained within the framework. The +// framework bundle is located within the versioned directory at a specific +// path. The only components in the versioned directory not included in the +// framework are things that also depend on the framework, such as the helper +// app bundle. +FilePath GetFrameworkBundlePath(); +#endif // OS_MACOSX + +} // namespace chrome + +#endif // CHROME_COMMON_CHROME_PATHS_INTERNAL_H_ diff --git a/chrome/common/chrome_paths_linux.cc b/chrome/common/chrome_paths_linux.cc new file mode 100644 index 0000000..32a9925 --- /dev/null +++ b/chrome/common/chrome_paths_linux.cc @@ -0,0 +1,76 @@ +// Copyright (c) 2010 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 "chrome/common/chrome_paths_internal.h" + +#include "base/env_var.h" +#include "base/file_util.h" +#include "base/scoped_ptr.h" +#include "base/xdg_util.h" + +namespace chrome { + +// See http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html +// for a spec on where config files go. The net effect for most +// systems is we use ~/.config/chromium/ for Chromium and +// ~/.config/google-chrome/ for official builds. +// (This also helps us sidestep issues with other apps grabbing ~/.chromium .) +bool GetDefaultUserDataDirectory(FilePath* result) { + scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create()); + FilePath config_dir( + base::GetXDGDirectory(env.get(), "XDG_CONFIG_HOME", ".config")); +#if defined(GOOGLE_CHROME_BUILD) + *result = config_dir.Append("google-chrome"); +#else + *result = config_dir.Append("chromium"); +#endif + return true; +} + +bool GetChromeFrameUserDataDirectory(FilePath* result) { + scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create()); + FilePath config_dir( + base::GetXDGDirectory(env.get(), "XDG_CONFIG_HOME", ".config")); +#if defined(GOOGLE_CHROME_BUILD) + *result = config_dir.Append("google-chrome-frame"); +#else + *result = config_dir.Append("chrome-frame"); +#endif + return true; +} + +bool GetUserDocumentsDirectory(FilePath* result) { + scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create()); + *result = base::GetXDGUserDirectory(env.get(), "DOCUMENTS", "Documents"); + return true; +} + +// We respect the user's preferred download location, unless it is +// ~ or their desktop directory, in which case we default to ~/Downloads. +bool GetUserDownloadsDirectory(FilePath* result) { + scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create()); + *result = base::GetXDGUserDirectory(env.get(), "DOWNLOAD", "Downloads"); + + FilePath home = file_util::GetHomeDir(); + if (*result == home) { + *result = home.Append("Downloads"); + return true; + } + + FilePath desktop; + GetUserDesktop(&desktop); + if (*result == desktop) { + *result = home.Append("Downloads"); + } + + return true; +} + +bool GetUserDesktop(FilePath* result) { + scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create()); + *result = base::GetXDGUserDirectory(env.get(), "DESKTOP", "Desktop"); + return true; +} + +} // namespace chrome diff --git a/chrome/common/chrome_paths_mac.mm b/chrome/common/chrome_paths_mac.mm new file mode 100644 index 0000000..c7db483 --- /dev/null +++ b/chrome/common/chrome_paths_mac.mm @@ -0,0 +1,108 @@ +// Copyright (c) 2006-2008 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 "chrome/common/chrome_paths_internal.h" + +#import <Cocoa/Cocoa.h> + +#include "base/base_paths.h" +#include "base/logging.h" +#include "base/mac_util.h" +#include "base/path_service.h" +#include "chrome/common/chrome_constants.h" + +namespace { +const FilePath* g_override_versioned_directory = NULL; +} // namespace + +namespace chrome { + +bool GetDefaultUserDataDirectory(FilePath* result) { + bool success = false; + if (result && PathService::Get(base::DIR_APP_DATA, result)) { +#if defined(GOOGLE_CHROME_BUILD) + *result = result->Append("Google").Append("Chrome"); +#else + *result = result->Append("Chromium"); +#endif + success = true; + } + return success; +} + +bool GetChromeFrameUserDataDirectory(FilePath* result) { + bool success = false; + if (result && PathService::Get(base::DIR_APP_DATA, result)) { +#if defined(GOOGLE_CHROME_BUILD) + *result = result->Append("Google").Append("Chrome Frame"); +#else + *result = result->Append("Chrome Frame"); +#endif + success = true; + } + return success; +} + +bool GetUserDocumentsDirectory(FilePath* result) { + return mac_util::GetUserDirectory(NSDocumentDirectory, result); +} + +bool GetUserDownloadsDirectory(FilePath* result) { + return mac_util::GetUserDirectory(NSDownloadsDirectory, result); +} + +bool GetUserDesktop(FilePath* result) { + return mac_util::GetUserDirectory(NSDesktopDirectory, result); +} + +FilePath GetVersionedDirectory() { + if (g_override_versioned_directory) + return *g_override_versioned_directory; + + // Start out with the path to the running executable. + FilePath path; + PathService::Get(base::FILE_EXE, &path); + + // One step up to MacOS, another to Contents. + path = path.DirName().DirName(); + DCHECK_EQ(path.BaseName().value(), "Contents"); + + if (mac_util::IsBackgroundOnlyProcess()) { + // path identifies the helper .app's Contents directory in the browser + // .app's versioned directory. Go up two steps to get to the browser + // .app's versioned directory. + path = path.DirName().DirName(); + DCHECK_EQ(path.BaseName().value(), kChromeVersion); + } else { + // Go into the versioned directory. + path = path.Append("Versions").Append(kChromeVersion); + } + + return path; +} + +void SetOverrideVersionedDirectory(const FilePath* path) { + if (path != g_override_versioned_directory) { + delete g_override_versioned_directory; + g_override_versioned_directory = path; + } +} + +FilePath GetFrameworkBundlePath() { + // It's tempting to use +[NSBundle bundleWithIdentifier:], but it's really + // slow (about 30ms on 10.5 and 10.6), despite Apple's documentation stating + // that it may be more efficient than +bundleForClass:. +bundleForClass: + // itself takes 1-2ms. Getting an NSBundle from a path, on the other hand, + // essentially takes no time at all, at least when the bundle has already + // been loaded as it will have been in this case. The FilePath operations + // needed to compute the framework's path are also effectively free, so that + // is the approach that is used here. NSBundle is also documented as being + // not thread-safe, and thread safety may be a concern here. + + // The framework bundle is at a known path and name from the browser .app's + // versioned directory. + return GetVersionedDirectory().Append(kFrameworkName); +} + +} // namespace chrome diff --git a/chrome/common/chrome_paths_win.cc b/chrome/common/chrome_paths_win.cc new file mode 100644 index 0000000..4d7709d --- /dev/null +++ b/chrome/common/chrome_paths_win.cc @@ -0,0 +1,94 @@ +// Copyright (c) 2006-2008 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 "chrome/common/chrome_paths_internal.h" + +#include <windows.h> +#include <knownfolders.h> +#include <shellapi.h> +#include <shlobj.h> +#include <shobjidl.h> + +#include "app/win_util.h" +#include "base/file_path.h" +#include "base/path_service.h" +#include "base/scoped_comptr_win.h" +#include "chrome/common/chrome_constants.h" +#include "chrome/installer/util/browser_distribution.h" + +namespace chrome { + +bool GetDefaultUserDataDirectory(FilePath* result) { + if (!PathService::Get(base::DIR_LOCAL_APP_DATA, result)) + return false; + BrowserDistribution* dist = BrowserDistribution::GetDistribution(); + *result = result->Append(dist->GetInstallSubDir()); + *result = result->Append(chrome::kUserDataDirname); + return true; +} + +bool GetChromeFrameUserDataDirectory(FilePath* result) { + if (!PathService::Get(base::DIR_LOCAL_APP_DATA, result)) + return false; +#if defined(GOOGLE_CHROME_BUILD) + *result = result->Append(FILE_PATH_LITERAL("Google")); +#endif + *result = result->Append(L"Chrome Frame"); + *result = result->Append(chrome::kUserDataDirname); + return true; +} + +bool GetUserDocumentsDirectory(FilePath* result) { + wchar_t path_buf[MAX_PATH]; + if (FAILED(SHGetFolderPath(NULL, CSIDL_MYDOCUMENTS, NULL, + SHGFP_TYPE_CURRENT, path_buf))) + return false; + *result = FilePath(path_buf); + return true; +} + +// Return a default path for downloads that is safe. +// We just use 'Downloads' under DIR_USER_DOCUMENTS. Localizing +// 'downloads' is not a good idea because Chrome's UI language +// can be changed. +bool GetUserDownloadsDirectorySafe(FilePath* result) { + if (!GetUserDocumentsDirectory(result)) + return false; + + *result = result->Append(L"Downloads"); + return true; +} + +// On Vista and higher, use the downloads known folder. Since it can be +// relocated to point to a "dangerous" folder, callers should validate that the +// returned path is not dangerous before using it. +bool GetUserDownloadsDirectory(FilePath* result) { + typedef HRESULT (WINAPI *GetKnownFolderPath)( + REFKNOWNFOLDERID, DWORD, HANDLE, PWSTR*); + GetKnownFolderPath f = reinterpret_cast<GetKnownFolderPath>( + GetProcAddress(GetModuleHandle(L"shell32.dll"), "SHGetKnownFolderPath")); + win_util::CoMemReleaser<wchar_t> path_buf; + if (f && SUCCEEDED(f(FOLDERID_Downloads, 0, NULL, &path_buf))) { + *result = FilePath(std::wstring(path_buf)); + return true; + } + return GetUserDownloadsDirectorySafe(result); +} + +bool GetUserDesktop(FilePath* result) { + // We need to go compute the value. It would be nice to support paths + // with names longer than MAX_PATH, but the system functions don't seem + // to be designed for it either, with the exception of GetTempPath + // (but other things will surely break if the temp path is too long, + // so we don't bother handling it. + wchar_t system_buffer[MAX_PATH]; + system_buffer[0] = 0; + if (FAILED(SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, NULL, + SHGFP_TYPE_CURRENT, system_buffer))) + return false; + *result = FilePath(system_buffer); + return true; +} + +} // namespace chrome diff --git a/chrome/common/chrome_plugin_api.h b/chrome/common/chrome_plugin_api.h new file mode 100644 index 0000000..e5230cd --- /dev/null +++ b/chrome/common/chrome_plugin_api.h @@ -0,0 +1,566 @@ +// Copyright (c) 2009 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 header specifies the Chrome Plugin API. It is based heavily on NPAPI. +// The key difference is that Chrome plugins can be loaded for the lifetime +// of the browser, and are not tied to a specific web page. +// +// NOTE: This API is not final and may change or go away at any point. +// +// All strings in the API are UTF8-encoded unless otherwise noted. + +#ifndef CHROME_COMMON_CHROME_PLUGIN_API_H__ +#define CHROME_COMMON_CHROME_PLUGIN_API_H__ + +#include "base/basictypes.h" + +#ifndef STDCALL +#ifdef WIN32 +#define STDCALL __stdcall +#else +#define STDCALL +#endif // WIN32 +#endif // STDCALL + +#ifdef __cplusplus +extern "C" { +#endif + +// The current version of the API, used by the 'version' field of CPPluginFuncs +// and CPBrowserFuncs. +#define CP_MAJOR_VERSION 0 +#define CP_MINOR_VERSION 11 +#define CP_VERSION ((CP_MAJOR_VERSION << 8) | (CP_MINOR_VERSION)) + +#define CP_GET_MAJOR_VERSION(version) ((version & 0xff00) >> 8) +#define CP_GET_MINOR_VERSION(version) (version & 0x00ff) + +typedef unsigned char CPBool; + +// Chrome plugins can be loaded into different process types. +typedef enum { + CP_PROCESS_BROWSER = 0, + CP_PROCESS_PLUGIN, + CP_PROCESS_RENDERER, +} CPProcessType; + +// Return codes. Error values are negative. +typedef enum { + // No error + CPERR_SUCCESS = 0, + + // (network) An asynchronous IO operation is not complete + CPERR_IO_PENDING = -1, + + // Generic failure + CPERR_FAILURE = -2, + + // The API versions used by plugin and host are incompatible + CPERR_INVALID_VERSION = -3, + + // The operation was cancelled + CPERR_CANCELLED = -4, + + // An invalid parameter was passed + CPERR_INVALID_PARAMETER = -5, +} CPError; + +// Types of response info metadata to query using CPP_GetResponseInfo. +typedef enum { + // HTTP status code. + CPRESPONSEINFO_HTTP_STATUS = 0, + + // Raw headers from the server, including the status line. Headers should + // be delimited by "\0", and end with "\0\0" (a blank line). + CPRESPONSEINFO_HTTP_RAW_HEADERS = 1, +} CPResponseInfoType; + +// An identifier for the plugin used by the browser. +typedef struct _CPID_t { + int unused; +} CPID_t; +typedef struct _CPID_t* CPID; + +// An identifier that encapsulates the browsing context needed by various APIs. +// This includes information about what tab a request was made from, and what +// profile is active. Note that this ID is global to all processes, so it can +// be passed from one process to another. The value 0 is reserved for an +// undefined context. +typedef uint32 CPBrowsingContext; + +// Types of context info to query using CPB_GetBrowsingContextInfo. +typedef enum { + // The data directory for the profile associated with this context as a + // pointer to a null-terminated string. The plugin can save persistent data + // to this directory. The returned pointer should be freed using CPB_Free. + CPBROWSINGCONTEXT_DATA_DIR_PTR = 0, + + // The locale language code used for the browser UI. The returned pointer + // should be freed using CPB_Free. + CPBROWSINGCONTEXT_UI_LOCALE_PTR = 1, +} CPBrowsingContextInfoType; + +// A network request object. +typedef struct _CPRequest { + void* pdata; // plugin private data + const char* url; // the URL being requested + const char* method; // the request method as an uppercase string (ex: "GET") + CPBrowsingContext context; // context in which this request was made +} CPRequest; + +typedef enum { + CPREQUESTLOAD_NORMAL = 0, + + // This is "normal reload", meaning an if-none-match/if-modified-since query + CPREQUESTLOAD_VALIDATE_CACHE = 1 << 0, + + // This is "shift-reload", meaning a "pragma: no-cache" end-to-end fetch + CPREQUESTLOAD_BYPASS_CACHE = 1 << 1, + + // This is a back/forward style navigation where the cached content should + // be preferred over any protocol specific cache validation. + CPREQUESTLOAD_PREFERRING_CACHE = 1 << 2, + + // This is a navigation that will fail if it cannot serve the requested + // resource from the cache (or some equivalent local store). + CPREQUESTLOAD_ONLY_FROM_CACHE = 1 << 3, + + // This is a navigation that will not use the cache at all. It does not + // impact the HTTP request headers. + CPREQUESTLOAD_DISABLE_CACHE = 1 << 4, + + // This navigation should not be intercepted by plugins. + CPREQUESTLOAD_DISABLE_INTERCEPT = 1 << 5, + + // This request should be loaded synchronously. What this means is that + // CPR_StartRequest and CPR_Read will never return CPERR_IO_PENDING - they + // will block until a response is available, and return success or failure. + CPREQUESTLOAD_SYNCHRONOUS = 1 << 20, +} CPRequestLoadFlags; + +// +// Functions provided by plugin to host. +// + +// Called when the browser is unloading the plugin. +typedef CPError (STDCALL *CPP_ShutdownFunc)(void); + +// Returns true if the plugin is interested in handling this request. +typedef CPBool (STDCALL *CPP_ShouldInterceptRequestFunc)(CPRequest* request); + +// Called when an HTML dialog was closed. json_retval is the JSON string +// containing the return value sent back by the dialog (using Chrome's +// JavaScript DOM bindings). +typedef void (STDCALL *CPP_HtmlDialogClosedFunc)( + void* plugin_context, const char* json_retval); + +// Asks the plugin to handle the given command. 'command_data' is command- +// specific data used for some builtin commands: see gears_api.h for +// possible types. It is only valid for the duration of this call. +typedef CPError (STDCALL *CPP_HandleCommandFunc)( + CPBrowsingContext context, int command, void* command_data); + +// +// Functions provided by host to plugin. +// + +// Asks the host to handle the given command. 'command_data' is +// command-specific data used for some builtin commands: see gears_api.h for +// possible types. It is only valid for the duration of this call. +typedef CPError (STDCALL *CPB_HandleCommandFunc)( + CPID id, CPBrowsingContext context, int command, void* command_data); + +// Asks the browser to enable/disable request interception for this plugin for +// the given schemes. 'schemes' is an array of strings containing the scheme +// names the plugin wishes to handle; case is ignored. If 'schemes' is NULL or +// empty, request interception is disabled for this plugin. Multiple calls to +// this function will add to the existing set of enabled schemes. The browser +// should call the plugin's CPP_ShouldInterceptRequestFunc for any network +// requests it makes that match a given scheme. The browser may choose not to +// allow the plugin to intercept certain protocols. +typedef void (STDCALL *CPB_EnableRequestInterceptFunc)( + CPID id, const char** schemes, uint32 num_schemes); + +// Asks the browser to create a request object for the given method/url. +// Returns CPERR_SUCCESS and puts the new object into the 'request' field on +// success, or an error code on failure. The plugin must call CPR_EndRequest +// to clean up the request object when it is done with it. +typedef CPError (STDCALL *CPB_CreateRequestFunc)( + CPID id, CPBrowsingContext context, const char* method, const char* url, + CPRequest** request); + +// Queries the browser's cookie store for cookies set for the given URL. +// Sets 'cookies' to an allocated string containing the cookies as +// semicolon-delimited "name=value" pairs on success, NULL on failure. +// The memory should be freed using CPB_Free when done. +typedef CPError (STDCALL *CPB_GetCookiesFunc)( + CPID id, CPBrowsingContext context, const char* url, char** cookies); + +// Allocates memory for the given size using the browser's allocator. Call +// CPB_Free when done. +typedef void* (STDCALL *CPB_AllocFunc)(uint32 size); + +// Frees a pointer allocated by CPB_Alloc. +typedef void (STDCALL *CPB_FreeFunc)(void* memory); + + +// Sets a flag that influences when the plugin process created to host +// the plugin is shutdown. Generally, the plugin process is terminated +// when no more plugin instances exist, this is the default behavior. +// If keep_alive is non-zero, the process will not be terminated when +// the instance count goes to zero. Note: a non-zero keep_alive value +// does not prevent the plugin process from being terminated upon +// overall browser shutdown. +typedef void (STDCALL *CPB_SetKeepProcessAliveFunc)(CPID id, + CPBool keep_alive); + +// Asks the browser to show an HTML dialog to the user. The dialog contents +// should be loaded from the given URL. The 'json_arguments' is a JSON string +// that the dialog can fetch using Chrome's JavaScript DOM bindings. This call +// will block until the dialog is closed. On success, 'json_retval' will +// contain the JSON string sent back by the dialog (using Chrome's JavaScript +// DOM bindings), and CPERR_SUCCESS is returned. 'json_retval' should be freed +// using CPB_Free when done. +typedef CPError (STDCALL *CPB_ShowHtmlDialogModalFunc)( + CPID id, CPBrowsingContext context, const char* url, int width, int height, + const char* json_arguments, char** json_retval); + +// Similar to CPB_ShowHtmlDialogModalFunc, but does not block. When the dialog +// is closed, CPP_HtmlDialogClosed is called with the JSON return value and the +// given 'plugin_context', which may be used by the plugin to associate other +// data with the dialog. +typedef CPError (STDCALL *CPB_ShowHtmlDialogFunc)( + CPID id, CPBrowsingContext context, const char* url, int width, int height, + const char* json_arguments, void* plugin_context); + +// Get the browsing context associated with the given NPAPI instance. +typedef CPBrowsingContext (STDCALL *CPB_GetBrowsingContextFromNPPFunc)( + struct _NPP* npp); + +// Queries for some meta data associated with the given browsing context. See +// CPBrowsingContextInfoType for possible queries. If buf_size is too small to +// contain the entire data, the return value will indicate the size required. +// Otherwise, the return value is a CPError or CPERR_SUCCESS. +typedef int (STDCALL *CPB_GetBrowsingContextInfoFunc)( + CPID id, CPBrowsingContext context, CPBrowsingContextInfoType type, + void* buf, uint32 buf_size); + +// Given an URL string, returns the string of command-line arguments that should +// be passed to start the browser at the given URL. 'arguments' should be freed +// using CPB_Free when done. +typedef CPError (STDCALL *CPB_GetCommandLineArgumentsFunc)( + CPID id, CPBrowsingContext context, const char* url, char** arguments); + +// Asks the browser to let the plugin handle the given UI command. When the +// command is invoked, the browser will call CPP_HandleCommand. 'command' +// should be an integer identifier. Currently only builtin commands are +// supported, but in the future we may want to let plugins add custom menu +// commands with their own descriptions. +typedef CPError (STDCALL *CPB_AddUICommandFunc)(CPID id, int command); + +// +// Functions related to making network requests. +// Both the host and plugin will implement their own versions of these. +// + +// Starts the request. Returns CPERR_SUCCESS if the request could be started +// immediately, at which point the response info is available to be read. +// Returns CPERR_IO_PENDING if an asynchronous operation was started, and the +// caller should wait for CPRR_StartCompleted to be called before reading the +// response info. Returns an error code on failure. +typedef CPError (STDCALL *CPR_StartRequestFunc)(CPRequest* request); + +// Stops or cancels the request. The caller should not access the request +// object after this call. If an asynchronous IO operation is pending, the +// operation is aborted and the caller will not receive a callback for it. +typedef void (STDCALL *CPR_EndRequestFunc)(CPRequest* request, CPError reason); + +// Sets the additional request headers to append to the standard headers that +// would normally be made with this request. Headers should be \r\n-delimited, +// with no terminating \r\n. Extra headers are not checked against the standard +// headers for duplicates. Must be called before CPRR_StartCompletedFunc. +// Plugins should avoid setting the following headers: User-Agent, +// Content-Length. +typedef void (STDCALL *CPR_SetExtraRequestHeadersFunc)(CPRequest* request, + const char* headers); + +// Sets the load flags for this request. 'flags' is a bitwise-OR of +// CPRequestLoadFlags. Must be called before CPRR_StartCompletedFunc. +typedef void (STDCALL *CPR_SetRequestLoadFlagsFunc)(CPRequest* request, + uint32 flags); + +// Appends binary data to the request body of a POST or PUT request. The caller +// should set the "Content-Type" header to the appropriate mime type using +// CPR_SetExtraRequestHeadersFunc. This can be called multiple times to append +// a sequence of data segments to upload. Must be called before +// CPR_StartRequestFunc. +typedef void (STDCALL *CPR_AppendDataToUploadFunc)( + CPRequest* request, const char* bytes, int bytes_len); + +// Appends the contents of a file to the request body of a POST or PUT request. +// 'offset' and 'length' can be used to append a subset of the file. Pass zero +// for 'length' and 'offset' to upload the entire file. 'offset' +// indicates where the data to upload begins in the file. 'length' indicates +// how much of the file to upload. A 'length' of zero is interpretted as to +// end-of-file. If 'length' and 'offset' indicate a range beyond end of file, +// the amount sent is clipped at eof. +// See CPR_AppendDataToUploadFunc for additional usage information. +// (added in v0.4) +typedef CPError (STDCALL *CPR_AppendFileToUploadFunc)( + CPRequest* request, const char* filepath, uint64 offset, uint64 length); + +// Queries for some response meta data. See CPResponseInfoType for possible +// queries. If buf_size is too small to contain the entire data, the return +// value will indicate the size required. Otherwise, the return value is a +// CPError or CPERR_SUCCESS. +typedef int (STDCALL *CPR_GetResponseInfoFunc)( + CPRequest* request, CPResponseInfoType type, + void* buf, uint32 buf_size); + +// Attempts to read a request's response data. The number of bytes read is +// returned; 0 indicates an EOF. CPERR_IO_PENDING is returned if an +// asynchronous operation was started, and CPRR_ReadCompletedFunc will be called +// when it completes; 'buf' must be available until the operation completes. +// Returns an error code on failure. +typedef int (STDCALL *CPR_ReadFunc)( + CPRequest* request, void* buf, uint32 buf_size); + +// +// Functions related to serving network requests. +// Both the host and plugin will implement their own versions of these. +// + +// Called upon a server-initiated redirect. The request will still hold the +// original URL, and 'new_url' will be the redirect destination. +typedef void (STDCALL *CPRR_ReceivedRedirectFunc)(CPRequest* request, + const char* new_url); + +// Called when an asynchronous CPR_StartRequest call has completed, once all +// redirects are followed. On success, 'result' holds CPERR_SUCCESS and the +// response info is available to be read via CPR_GetResponseInfo. On error, +// 'result' holds the error code. +typedef void (STDCALL *CPRR_StartCompletedFunc)(CPRequest* request, + CPError result); + +// Called when an asynchronous CPR_Read call has completed. On success, +// 'bytes_read' will hold the number of bytes read into the buffer that was +// passed to CPR_Read; 0 indicates an EOF, and the request object will be +// destroyed after the call completes. On failure, 'bytes_read' holds the error +// code. +typedef void (STDCALL *CPRR_ReadCompletedFunc)(CPRequest* request, + int bytes_read); + +// Called as upload progress is being made for async POST requests. +// (added in v0.5) +typedef void (STDCALL *CPRR_UploadProgressFunc)(CPRequest* request, + uint64 position, + uint64 size); + +// +// Functions to support the sending and receipt of messages between processes. +// + +// Returns true if the plugin process is running +typedef CPBool (STDCALL *CPB_IsPluginProcessRunningFunc)(CPID id); + +// Returns the type of the current process. +typedef CPProcessType (STDCALL *CPB_GetProcessTypeFunc)(CPID id); + +// Asks the browser to send raw data to the other process hosting an instance of +// this plugin. If needed, the plugin process will be started prior to sending +// the message. +typedef CPError (STDCALL *CPB_SendMessageFunc)(CPID id, + const void *data, + uint32 data_len); + +// Asks the browser to send raw data to the other process hosting an instance of +// this plugin. This function only works from the plugin or renderer process. +// This function blocks until the message is processed. The memory should be +// freed using CPB_Free when done. +typedef CPError (STDCALL *CPB_SendSyncMessageFunc)(CPID id, + const void *data, + uint32 data_len, + void **retval, + uint32 *retval_len); + +// This function asynchronously calls the provided function on the plugin +// thread. user_data is passed as the argument to the function. +typedef CPError (STDCALL *CPB_PluginThreadAsyncCallFunc)(CPID id, + void (*func)(void *), + void *user_data); + +// This function creates an open file dialog. The process is granted access +// to any files that are selected. |multiple_files| determines if more than +// one file can be selected. +typedef CPError (STDCALL *CPB_OpenFileDialogFunc)(CPID id, + CPBrowsingContext context, + bool multiple_files, + const char *title, + const char *filter, + void *user_data); + +// Informs the plugin of raw data having been sent from another process. +typedef void (STDCALL *CPP_OnMessageFunc)(void *data, uint32 data_len); + +// Informs the plugin of raw data having been sent from another process. +typedef void (STDCALL *CPP_OnSyncMessageFunc)(void *data, uint32 data_len, + void **retval, + uint32 *retval_len); + +// Informs the plugin that the file dialog has completed, and contains the +// results. +typedef void (STDCALL *CPP_OnFileDialogResultFunc)(void *data, + const char **files, + uint32 files_len); + +// Asks the browser to verify that NPObject* 'event' is the current drag event +// the browser is dispatching, and extract drag data from the event if so. On +// success, returns the drag 'identity' (an up-counter that the browser chrome +// increases each time a user drag enters a renderer tab), the drag 'event_id' +// and the 'drag_type' being a utf8 encoded string with values "Files", "Text" +// or "URL". If 'add_data' is true, also return the 'drag_data', again a utf8 +// encoded string with the data for the drag type. For drag type "Files", the +// data is a backspace delimited list of file paths. +// +// The call fails with a CPError if 'event' is an invalid drag event, and sets +// the 'identity' and 'event_id' to 0. Note: on success, non-NULL 'drag_type' +// and 'drag_data' should be freed with CPB_Free() when done. +typedef CPError (STDCALL *CPB_GetDragDataFunc)( + CPID id, CPBrowsingContext context, struct NPObject* event, bool add_data, + int32* identity, int32* event_id, char** drag_type, char** drag_data); + +// Asks the browser to verify that NPObject* 'event' is the current drag event +// the browser is dispatching and show the requested drop 'effect' if so. The +// browser displays drop effects during dragenter and dragover events, to give +// user visible feedback (with a drag cursor, typically) to indicate whether a +// subsequent drop event will succeed or not. The implementation supports the +// so-called "copy" and "none" effects. When 'effect' is non-zero, the "copy" +// effect is shown. Otherwise, the "none" effect is shown, which prevents the +// subsequent drop event from succeeding. Returns CPError on failure, meaning +// the 'event' is an invalid drag event. +// +// Note: 'effect' is int to allow for new effects in future. For example, the +// HTML5-defined drop effects "move" and "link". +typedef CPError (STDCALL *CPB_SetDropEffectFunc)( + CPID id, CPBrowsingContext context, struct NPObject* event, int effect); + +// For drag type "Files", the drag data returned by CPB_GetDragDataFunc() is a +// backspace delimited list of file paths. Use this routine to pass that data +// to the browser process to verify that the renderer has permission to access +// the files. Returns CPERR_SUCCESS if access is allowed. +typedef CPError (STDCALL *CPB_AllowFileDropFunc)( + CPID id, CPBrowsingContext context, const char* file_drag_data); + +// Function table for issuing requests using via the other side's network stack. +// For the plugin, this functions deal with issuing requests through the +// browser. For the browser, these functions deal with allowing the plugin to +// intercept requests. +typedef struct _CPRequestFuncs { + uint16 size; + CPR_SetExtraRequestHeadersFunc set_extra_request_headers; + CPR_SetRequestLoadFlagsFunc set_request_load_flags; + CPR_AppendDataToUploadFunc append_data_to_upload; + CPR_StartRequestFunc start_request; + CPR_EndRequestFunc end_request; + CPR_GetResponseInfoFunc get_response_info; + CPR_ReadFunc read; + CPR_AppendFileToUploadFunc append_file_to_upload; +} CPRequestFuncs; + +// Function table for handling requests issued by the other side. For the +// plugin, these deal with serving requests that the plugin has intercepted. For +// the browser, these deal with serving requests that the plugin has issued +// through us. +typedef struct _CPResponseFuncs { + uint16 size; + CPRR_ReceivedRedirectFunc received_redirect; + CPRR_StartCompletedFunc start_completed; + CPRR_ReadCompletedFunc read_completed; + CPRR_UploadProgressFunc upload_progress; +} CPResponseFuncs; + +// Function table of CPP functions (functions provided by plugin to host). This +// structure is filled in by the plugin in the CP_Initialize call, except for +// the 'size' field, which is set by the browser. The version fields should be +// set to those that the plugin was compiled using. +typedef struct _CPPluginFuncs { + uint16 size; + uint16 version; + CPRequestFuncs* request_funcs; + CPResponseFuncs* response_funcs; + CPP_ShutdownFunc shutdown; + CPP_ShouldInterceptRequestFunc should_intercept_request; + CPP_OnMessageFunc on_message; + CPP_HtmlDialogClosedFunc html_dialog_closed; + CPP_HandleCommandFunc handle_command; + CPP_OnSyncMessageFunc on_sync_message; + CPP_OnFileDialogResultFunc on_file_dialog_result; +} CPPluginFuncs; + +// Function table CPB functions (functions provided by host to plugin). +// This structure is filled in by the browser and provided to the plugin. The +// plugin will likely want to save a copy of this structure to make calls +// back to the browser. +typedef struct _CPBrowserFuncs { + uint16 size; + uint16 version; + CPRequestFuncs* request_funcs; + CPResponseFuncs* response_funcs; + CPB_EnableRequestInterceptFunc enable_request_intercept; + CPB_CreateRequestFunc create_request; + CPB_GetCookiesFunc get_cookies; + CPB_AllocFunc alloc; + CPB_FreeFunc free; + CPB_SetKeepProcessAliveFunc set_keep_process_alive; + CPB_ShowHtmlDialogModalFunc show_html_dialog_modal; + CPB_ShowHtmlDialogFunc show_html_dialog; + CPB_IsPluginProcessRunningFunc is_plugin_process_running; + CPB_GetProcessTypeFunc get_process_type; + CPB_SendMessageFunc send_message; + CPB_GetBrowsingContextFromNPPFunc get_browsing_context_from_npp; + CPB_GetBrowsingContextInfoFunc get_browsing_context_info; + CPB_GetCommandLineArgumentsFunc get_command_line_arguments; + CPB_AddUICommandFunc add_ui_command; + CPB_HandleCommandFunc handle_command; + CPB_SendSyncMessageFunc send_sync_message; + CPB_PluginThreadAsyncCallFunc plugin_thread_async_call; + CPB_OpenFileDialogFunc open_file_dialog; + CPB_GetDragDataFunc get_drag_data; + CPB_SetDropEffectFunc set_drop_effect; + CPB_AllowFileDropFunc allow_file_drop; +} CPBrowserFuncs; + + +// +// DLL exports +// + +// This export is optional. +// Prior to calling CP_Initialize, the browser may negotiate with the plugin +// regarding which version of the CPAPI to utilize. 'min_version' is the +// lowest version of the interface supported by the browser, 'max_version' is +// the highest supported version. The plugin can specify which version within +// the range should be used. This version will be reflected in the version field +// of the CPBrowserFuncs struct passed to CP_Initialize. If this function +// returns an error code, CP_Initialize will not be called. If function is not +// exported by the chrome plugin module, CP_Initiailize will be called with +// a version of the host's choosing. +typedef CPError (STDCALL *CP_VersionNegotiateFunc)( + uint16 min_version, uint16 max_version, uint16 *selected_version); + +// 'bfuncs' are the browser functions provided to the plugin. 'id' is the +// plugin identifier that the plugin should use when calling browser functions. +// The plugin should initialize 'pfuncs' with pointers to its own functions, +// or return an error code. +// All functions and entry points should be called on the same thread. The +// plugin should not attempt to call a browser function from a thread other +// than the one CP_InitializeFunc is called from. +typedef CPError (STDCALL *CP_InitializeFunc)( + CPID id, const CPBrowserFuncs* bfuncs, CPPluginFuncs* pfuncs); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // CHROME_COMMON_CHROME_PLUGIN_API_H_ diff --git a/chrome/common/chrome_plugin_lib.cc b/chrome/common/chrome_plugin_lib.cc new file mode 100644 index 0000000..daf6bb7 --- /dev/null +++ b/chrome/common/chrome_plugin_lib.cc @@ -0,0 +1,290 @@ +// Copyright (c) 2006-2008 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 "chrome/common/chrome_plugin_lib.h" + +#include "base/command_line.h" +#include "base/hash_tables.h" +#include "base/histogram.h" +#include "base/message_loop.h" +#include "base/path_service.h" +#include "base/perftimer.h" +#include "base/thread.h" +#if defined(OS_WIN) +#include "base/registry.h" +#endif +#include "base/string_util.h" +#include "chrome/common/chrome_counters.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/notification_service.h" +#include "chrome/common/chrome_paths.h" +#include "webkit/glue/plugins/plugin_list.h" + +using base::TimeDelta; + +// TODO(port): revisit when plugins happier +#if defined(OS_WIN) +const TCHAR ChromePluginLib::kRegistryChromePlugins[] = + _T("Software\\Google\\Chrome\\Plugins"); +static const TCHAR kRegistryLoadOnStartup[] = _T("LoadOnStartup"); +static const TCHAR kRegistryPath[] = _T("Path"); +#endif + +typedef base::hash_map<FilePath, scoped_refptr<ChromePluginLib> > + PluginMap; + +// A map of all the instantiated plugins. +static PluginMap* g_loaded_libs; + +// The thread plugins are loaded and used in, lazily initialized upon +// the first creation call. +static PlatformThreadId g_plugin_thread_id = 0; +static MessageLoop* g_plugin_thread_loop = NULL; + +static bool IsSingleProcessMode() { + // We don't support ChromePlugins in single-process mode. + return CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess); +} + +// static +bool ChromePluginLib::IsInitialized() { + return (g_loaded_libs != NULL); +} + +// static +ChromePluginLib* ChromePluginLib::Create(const FilePath& filename, + const CPBrowserFuncs* bfuncs) { + // Keep a map of loaded plugins to ensure we only load each library once. + if (!g_loaded_libs) { + g_loaded_libs = new PluginMap(); + g_plugin_thread_id = PlatformThread::CurrentId(); + g_plugin_thread_loop = MessageLoop::current(); + } + DCHECK(IsPluginThread()); + + PluginMap::const_iterator iter = g_loaded_libs->find(filename); + if (iter != g_loaded_libs->end()) + return iter->second; + + scoped_refptr<ChromePluginLib> plugin(new ChromePluginLib(filename)); + if (!plugin->CP_Initialize(bfuncs)) + return NULL; + + (*g_loaded_libs)[filename] = plugin; + return plugin; +} + +// static +ChromePluginLib* ChromePluginLib::Find(const FilePath& filename) { + if (g_loaded_libs) { + PluginMap::const_iterator iter = g_loaded_libs->find(filename); + if (iter != g_loaded_libs->end()) + return iter->second; + } + return NULL; +} + +// static +void ChromePluginLib::Destroy(const FilePath& filename) { + DCHECK(g_loaded_libs); + PluginMap::iterator iter = g_loaded_libs->find(filename); + if (iter != g_loaded_libs->end()) { + iter->second->Unload(); + g_loaded_libs->erase(iter); + } +} + +// static +bool ChromePluginLib::IsPluginThread() { + return PlatformThread::CurrentId() == g_plugin_thread_id; +} + +// static +MessageLoop* ChromePluginLib::GetPluginThreadLoop() { + return g_plugin_thread_loop; +} + +// static +void ChromePluginLib::RegisterPluginsWithNPAPI() { + // We don't support ChromePlugins in single-process mode. + if (IsSingleProcessMode()) + return; + + FilePath path; + // Register Gears, if available. + if (PathService::Get(chrome::FILE_GEARS_PLUGIN, &path)) + NPAPI::PluginList::Singleton()->AddExtraPluginPath(path); +} + +static void LogPluginLoadTime(const TimeDelta &time) { + UMA_HISTOGRAM_TIMES("Gears.LoadTime", time); +} + +// static +void ChromePluginLib::LoadChromePlugins(const CPBrowserFuncs* bfuncs) { + static bool loaded = false; + if (loaded) + return; + loaded = true; + + // We don't support ChromePlugins in single-process mode. + if (IsSingleProcessMode()) + return; + + FilePath path; + if (!PathService::Get(chrome::FILE_GEARS_PLUGIN, &path)) + return; + + PerfTimer timer; + ChromePluginLib::Create(path, bfuncs); + LogPluginLoadTime(timer.Elapsed()); + + // TODO(mpcomplete): disabled loading of plugins from the registry until we + // phase out registry keys from the gears installer. +#if 0 + for (RegistryKeyIterator iter(HKEY_CURRENT_USER, kRegistryChromePlugins); + iter.Valid(); ++iter) { + // Use the registry to gather plugin across the file system. + std::wstring reg_path = kRegistryChromePlugins; + reg_path.append(L"\\"); + reg_path.append(iter.Name()); + RegKey key(HKEY_CURRENT_USER, reg_path.c_str()); + + DWORD is_persistent; + if (key.ReadValueDW(kRegistryLoadOnStartup, &is_persistent) && + is_persistent) { + std::wstring path; + if (key.ReadValue(kRegistryPath, &path)) { + ChromePluginLib::Create(path, bfuncs); + } + } + } +#endif +} + +// static +void ChromePluginLib::UnloadAllPlugins() { + if (g_loaded_libs) { + PluginMap::iterator it; + for (PluginMap::iterator it = g_loaded_libs->begin(); + it != g_loaded_libs->end(); ++it) { + it->second->Unload(); + } + delete g_loaded_libs; + g_loaded_libs = NULL; + } +} + +const CPPluginFuncs& ChromePluginLib::functions() const { + DCHECK(initialized_); + DCHECK(IsPluginThread()); + return plugin_funcs_; +} + +ChromePluginLib::ChromePluginLib(const FilePath& filename) + : filename_(filename), +#if defined(OS_WIN) + module_(0), +#endif + initialized_(false), + CP_VersionNegotiate_(NULL), + CP_Initialize_(NULL) { + memset((void*)&plugin_funcs_, 0, sizeof(plugin_funcs_)); +} + +ChromePluginLib::~ChromePluginLib() { +} + +bool ChromePluginLib::CP_Initialize(const CPBrowserFuncs* bfuncs) { + LOG(INFO) << "ChromePluginLib::CP_Initialize(" << filename_.value() << + "): initialized=" << initialized_; + if (initialized_) + return true; + + if (!Load()) + return false; + + if (CP_VersionNegotiate_) { + uint16 selected_version = 0; + CPError rv = CP_VersionNegotiate_(CP_VERSION, CP_VERSION, + &selected_version); + if ( (rv != CPERR_SUCCESS) || (selected_version != CP_VERSION)) + return false; + } + + plugin_funcs_.size = sizeof(plugin_funcs_); + CPError rv = CP_Initialize_(cpid(), bfuncs, &plugin_funcs_); + initialized_ = (rv == CPERR_SUCCESS) && + (CP_GET_MAJOR_VERSION(plugin_funcs_.version) == CP_MAJOR_VERSION) && + (CP_GET_MINOR_VERSION(plugin_funcs_.version) <= CP_MINOR_VERSION); + LOG(INFO) << "ChromePluginLib::CP_Initialize(" << filename_.value() << + "): initialized=" << initialized_ << + "): result=" << rv; + + return initialized_; +} + +void ChromePluginLib::CP_Shutdown() { + DCHECK(initialized_); + functions().shutdown(); + initialized_ = false; + memset((void*)&plugin_funcs_, 0, sizeof(plugin_funcs_)); +} + +int ChromePluginLib::CP_Test(void* param) { + DCHECK(initialized_); + if (!CP_Test_) + return -1; + return CP_Test_(param); +} + +bool ChromePluginLib::Load() { +#if !defined(OS_WIN) + // Mac and Linux won't implement Gears. + return false; +#else + DCHECK(module_ == 0); + + module_ = LoadLibrary(filename_.value().c_str()); + if (module_ == 0) + return false; + + // required initialization function + CP_Initialize_ = reinterpret_cast<CP_InitializeFunc> + (GetProcAddress(module_, "CP_Initialize")); + + if (!CP_Initialize_) { + FreeLibrary(module_); + module_ = 0; + return false; + } + + // optional version negotiation function + CP_VersionNegotiate_ = reinterpret_cast<CP_VersionNegotiateFunc> + (GetProcAddress(module_, "CP_VersionNegotiate")); + + // optional test function + CP_Test_ = reinterpret_cast<CP_TestFunc> + (GetProcAddress(module_, "CP_Test")); + + return true; +#endif +} + +void ChromePluginLib::Unload() { + NotificationService::current()->Notify( + NotificationType::CHROME_PLUGIN_UNLOADED, + Source<ChromePluginLib>(this), + NotificationService::NoDetails()); + + if (initialized_) + CP_Shutdown(); + +#if defined(OS_WIN) + if (module_) { + FreeLibrary(module_); + module_ = 0; + } +#endif +} diff --git a/chrome/common/chrome_plugin_lib.h b/chrome/common/chrome_plugin_lib.h new file mode 100644 index 0000000..5027cfc --- /dev/null +++ b/chrome/common/chrome_plugin_lib.h @@ -0,0 +1,106 @@ +// Copyright (c) 2010 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 CHROME_COMMON_CHROME_PLUGIN_LIB_H_ +#define CHROME_COMMON_CHROME_PLUGIN_LIB_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/file_path.h" +#include "base/ref_counted.h" +#include "chrome/common/chrome_plugin_api.h" + +class MessageLoop; + +// A ChromePluginLib is a single Chrome Plugin Library. +// This class is used in the browser process (IO thread), and the plugin process +// (plugin thread). It should not be accessed on other threads, because it +// issues a NOTIFY_CHROME_PLUGIN_UNLOADED notification. +class ChromePluginLib : public base::RefCounted<ChromePluginLib> { + public: + static bool IsInitialized(); + static ChromePluginLib* Create(const FilePath& filename, + const CPBrowserFuncs* bfuncs); + static ChromePluginLib* Find(const FilePath& filename); + static void Destroy(const FilePath& filename); + static bool IsPluginThread(); + static MessageLoop* GetPluginThreadLoop(); + + static ChromePluginLib* FromCPID(CPID id) { + return reinterpret_cast<ChromePluginLib*>(id); + } + + // Adds Chrome plugins to the NPAPI plugin list. + static void RegisterPluginsWithNPAPI(); + + // Loads all the plugins that are marked as "LoadOnStartup" in the + // registry. This should only be called in the browser process. + static void LoadChromePlugins(const CPBrowserFuncs* bfuncs); + + // Unloads all the loaded plugins and cleans up the plugin map. + static void UnloadAllPlugins(); + + // Returns true if the plugin is currently loaded. + bool is_loaded() const { return initialized_; } + + // Get the Plugin's function pointer table. + const CPPluginFuncs& functions() const; + + CPID cpid() { return reinterpret_cast<CPID>(this); } + + const FilePath& filename() { return filename_; } + + // Plugin API functions + + // Method to call a test function in the plugin, used for unit tests. + int CP_Test(void* param); + +#if defined(OS_WIN) + // The registry path to search for Chrome Plugins/ + static const TCHAR kRegistryChromePlugins[]; +#endif // defined(OS_WIN) + + private: + friend class base::RefCounted<ChromePluginLib>; + + explicit ChromePluginLib(const FilePath& filename); + ~ChromePluginLib(); + + // Method to initialize a Plugin. + // Initialize can be safely called multiple times. + bool CP_Initialize(const CPBrowserFuncs* bfuncs); + + // Method to shutdown a Plugin. + void CP_Shutdown(); + + // Attempts to load the plugin. + // Returns true if it is a legitimate plugin, false otherwise + bool Load(); + + // Unloads the plugin. + void Unload(); + + FilePath filename_; // the path to the plugin +#if defined(OS_WIN) + // TODO(port): Remove ifdefs when we have portable replacement for HMODULE. + HMODULE module_; // the opened plugin handle +#endif // defined(OS_WIN) + bool initialized_; // is the plugin initialized + + // Exported symbols from the plugin, looked up by name. + CP_VersionNegotiateFunc CP_VersionNegotiate_; + CP_InitializeFunc CP_Initialize_; + + // Additional function pointers provided by the plugin. + CPPluginFuncs plugin_funcs_; + + // Used for unit tests. + typedef int (STDCALL *CP_TestFunc)(void*); + CP_TestFunc CP_Test_; + + DISALLOW_COPY_AND_ASSIGN(ChromePluginLib); +}; + +#endif // CHROME_COMMON_CHROME_PLUGIN_LIB_H_ diff --git a/chrome/common/chrome_plugin_util.cc b/chrome/common/chrome_plugin_util.cc new file mode 100644 index 0000000..08be12b --- /dev/null +++ b/chrome/common/chrome_plugin_util.cc @@ -0,0 +1,182 @@ +// Copyright (c) 2010 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 "chrome/common/chrome_plugin_util.h" + +#include <algorithm> + +#include "base/command_line.h" +#include "base/file_util.h" +#include "base/message_loop.h" +#include "base/utf_string_conversions.h" +#include "chrome/common/chrome_plugin_lib.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/notification_service.h" +#include "net/base/load_flags.h" +#include "net/http/http_response_headers.h" + +// +// ScopableCPRequest +// + +ScopableCPRequest::ScopableCPRequest(const char* u, const char* m, + CPBrowsingContext c) { + pdata = NULL; + data = NULL; +#if defined(OS_WIN) + url = _strdup(u); + method = _strdup(m); +#else + url = strdup(u); + method = strdup(m); +#endif + context = c; +} + +ScopableCPRequest::~ScopableCPRequest() { + pdata = NULL; + data = NULL; + free(const_cast<char*>(url)); + free(const_cast<char*>(method)); +} + +// +// PluginHelper +// + +// static +void PluginHelper::DestroyAllHelpersForPlugin(ChromePluginLib* plugin) { + NotificationService::current()->Notify( + NotificationType::CHROME_PLUGIN_UNLOADED, + Source<ChromePluginLib>(plugin), + NotificationService::NoDetails()); +} + +PluginHelper::PluginHelper(ChromePluginLib* plugin) : plugin_(plugin) { + DCHECK(CalledOnValidThread()); + registrar_.Add(this, NotificationType::CHROME_PLUGIN_UNLOADED, + Source<ChromePluginLib>(plugin_)); +} + +PluginHelper::~PluginHelper() { + DCHECK(CalledOnValidThread()); +} + +void PluginHelper::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + DCHECK(CalledOnValidThread()); + DCHECK(type == NotificationType::CHROME_PLUGIN_UNLOADED); + DCHECK(plugin_ == Source<ChromePluginLib>(source).ptr()); + + delete this; +} + +// +// PluginResponseUtils +// + +uint32 PluginResponseUtils::CPLoadFlagsToNetFlags(uint32 flags) { + uint32 net_flags = 0; +#define HANDLE_FLAG(name) \ + if (flags & CPREQUEST##name) \ + net_flags |= net::name + + HANDLE_FLAG(LOAD_VALIDATE_CACHE); + HANDLE_FLAG(LOAD_BYPASS_CACHE); + HANDLE_FLAG(LOAD_PREFERRING_CACHE); + HANDLE_FLAG(LOAD_ONLY_FROM_CACHE); + HANDLE_FLAG(LOAD_DISABLE_CACHE); + HANDLE_FLAG(LOAD_DISABLE_INTERCEPT); + + net_flags |= net::LOAD_ENABLE_UPLOAD_PROGRESS; + + return net_flags; +} + +int PluginResponseUtils::GetResponseInfo( + const net::HttpResponseHeaders* response_headers, + CPResponseInfoType type, void* buf, size_t buf_size) { + if (!response_headers) + return CPERR_FAILURE; + + switch (type) { + case CPRESPONSEINFO_HTTP_STATUS: + if (buf && buf_size) { + int status = response_headers->response_code(); + memcpy(buf, &status, std::min(buf_size, sizeof(status))); + } + break; + case CPRESPONSEINFO_HTTP_RAW_HEADERS: { + const std::string& headers = response_headers->raw_headers(); + if (buf_size < headers.size()+1) + return static_cast<int>(headers.size()+1); + if (buf) + memcpy(buf, headers.c_str(), headers.size()+1); + break; + } + default: + return CPERR_INVALID_VERSION; + } + + return CPERR_SUCCESS; +} + +CPError CPB_GetCommandLineArgumentsCommon(const char* url, + std::string* arguments) { + const CommandLine cmd = *CommandLine::ForCurrentProcess(); + std::wstring arguments_w; + + // Use the same UserDataDir for new launches that we currently have set. + FilePath user_data_dir = cmd.GetSwitchValuePath(switches::kUserDataDir); + if (!user_data_dir.empty()) { + // Make sure user_data_dir is an absolute path. + if (file_util::AbsolutePath(&user_data_dir) && + file_util::PathExists(user_data_dir)) { + // TODO(evanm): use CommandLine APIs instead of this. + arguments_w += std::wstring(L"--") + ASCIIToWide(switches::kUserDataDir) + + L"=\"" + user_data_dir.ToWStringHack() + L"\" "; + } + } + +#if defined (OS_CHROMEOS) + std::wstring profile = cmd.GetSwitchValue(switches::kProfile); + if (!profile.empty()) { + arguments_w += std::wstring(L"--") + ASCIIToWide(switches::kProfile) + + L"=\"" + profile + L"\" "; + } +#endif + + // Use '--app=url' instead of just 'url' to launch the browser with minimal + // chrome. + // Note: Do not change this flag! Old Gears shortcuts will break if you do! + std::string url_string(url); + ReplaceSubstringsAfterOffset(&url_string, 0, "\\", "%5C"); + ReplaceSubstringsAfterOffset(&url_string, 0, "\"", "%22"); + ReplaceSubstringsAfterOffset(&url_string, 0, ";", "%3B"); + ReplaceSubstringsAfterOffset(&url_string, 0, "$", "%24"); +#if defined(OS_WIN) // Windows shortcuts can't escape % so we use \x instead. + ReplaceSubstringsAfterOffset(&url_string, 0, "%", "\\x"); +#endif + std::wstring url_w = UTF8ToWide(url_string); + // TODO(evanm): use CommandLine APIs instead of this. + arguments_w += std::wstring(L"--") + ASCIIToWide(switches::kApp) + + L"=\"" + url_w + L"\""; + + *arguments = WideToUTF8(arguments_w); + + return CPERR_SUCCESS; +} + +// +// Host functions shared by browser and plugin processes +// + +void* STDCALL CPB_Alloc(uint32 size) { + return malloc(size); +} + +void STDCALL CPB_Free(void* memory) { + free(memory); +} diff --git a/chrome/common/chrome_plugin_util.h b/chrome/common/chrome_plugin_util.h new file mode 100644 index 0000000..7714a53 --- /dev/null +++ b/chrome/common/chrome_plugin_util.h @@ -0,0 +1,87 @@ +// Copyright (c) 2006-2008 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 CHROME_COMMON_CHROME_PLUGIN_UTIL_H_ +#define CHROME_COMMON_CHROME_PLUGIN_UTIL_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/non_thread_safe.h" +#include "base/ref_counted.h" +#include "chrome/common/chrome_plugin_api.h" +#include "chrome/common/notification_registrar.h" + +class ChromePluginLib; +class MessageLoop; +namespace net { +class HttpResponseHeaders; +} + +// A helper struct to ensure the CPRequest data is cleaned up when done. +// This class is reused for requests made by the browser (and intercepted by the +// plugin) as well as those made by the plugin. +struct ScopableCPRequest : public CPRequest { + template<class T> + static T GetData(CPRequest* request) { + return static_cast<T>(static_cast<ScopableCPRequest*>(request)->data); + } + + ScopableCPRequest(const char* url, const char* method, + CPBrowsingContext context); + ~ScopableCPRequest(); + + void* data; +}; + +// This is a base class for plugin-related objects that need to go away when +// the plugin unloads. This object also verifies that it is created and +// destroyed on the same thread. +class PluginHelper : public NotificationObserver, public NonThreadSafe { + public: + static void DestroyAllHelpersForPlugin(ChromePluginLib* plugin); + + explicit PluginHelper(ChromePluginLib* plugin); + virtual ~PluginHelper(); + + // NotificationObserver + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + protected: + NotificationRegistrar registrar_; + + scoped_refptr<ChromePluginLib> plugin_; + + DISALLOW_COPY_AND_ASSIGN(PluginHelper); +}; + +// A class of utility functions for dealing with request responses. +class PluginResponseUtils { + public: + // Helper to convert request load flags from the plugin API to the net API + // versions. + static uint32 CPLoadFlagsToNetFlags(uint32 flags); + + // Common implementation of a CPR_GetResponseInfo call. + static int GetResponseInfo( + const net::HttpResponseHeaders* response_headers, + CPResponseInfoType type, void* buf, size_t buf_size); +}; + +// Helper to allocate a string using the given CPB_Alloc function. +inline char* CPB_StringDup(CPB_AllocFunc alloc, const std::string& str) { + char* cstr = static_cast<char*>(alloc(static_cast<uint32>(str.length() + 1))); + memcpy(cstr, str.c_str(), str.length() + 1); // Include null terminator. + return cstr; +} + +CPError CPB_GetCommandLineArgumentsCommon(const char* url, + std::string* arguments); + +void* STDCALL CPB_Alloc(uint32 size); +void STDCALL CPB_Free(void* memory); + +#endif // CHROME_COMMON_CHROME_PLUGIN_UTIL_H_ diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc new file mode 100644 index 0000000..3c4255a --- /dev/null +++ b/chrome/common/chrome_switches.cc @@ -0,0 +1,1129 @@ +// Copyright (c) 2010 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 "chrome/common/chrome_switches.h" + +#include "base/base_switches.h" +#include "base/command_line.h" + +namespace switches { + +// ----------------------------------------------------------------------------- +// Can't find the switch you are looking for? try looking in +// base/base_switches.cc instead. +// ----------------------------------------------------------------------------- + +// Activate (make foreground) myself on launch. Helpful when Chrome +// is launched on the command line (e.g. by Selenium). Only needed on Mac. +const char kActivateOnLaunch[] = "activate-on-launch"; + +// By default, file:// URIs cannot read other file:// URIs. This is an +// override for developers who need the old behavior for testing. +const char kAllowFileAccessFromFiles[] = "allow-file-access-from-files"; + +// Allows debugging of sandboxed processes (see zygote_main_linux.cc). +const char kAllowSandboxDebugging[] = "allow-sandbox-debugging"; + +// Allows injecting extensions and user scripts on the extensions +// gallery site. Normally prevented for security reasons, but can be +// useful for automation testing of the gallery. +const char kAllowScriptingGallery[] = "allow-scripting-gallery"; + +// Enable web inspector for all windows, even if they're part of the browser. +// Allows us to use our dev tools to debug browser windows itself. +const char kAlwaysEnableDevTools[] = "always-enable-dev-tools"; + +// Specifies that the associated value should be launched in "application" mode. +const char kApp[] = "app"; + +// Specifies that the extension-app with the specified id should be launched +// according to its configuration. +const char kAppId[] = "app-id"; + +// Lacks meaning with out kApp. Causes the specified app to be launched in an +// panel window. +const char kAppLaunchAsPanel[] = "app-launch-as-panel"; + +// Makes the app launcher popup when a new tab is created. +const char kAppsPanel[] = "apps-panel"; + +// The URL to use for the gallery link in the app launcher. +const char kAppsGalleryURL[] = "apps-gallery-url"; + +// Disable throbber for extension apps. +const char kAppsNoThrob[] = "apps-no-throb"; + +// Whether to display the "Debug" link for app launch behavior. +const char kAppsDebug[] = "apps-debug"; + +// Authentication white list for servers +const char kAuthServerWhitelist[] = "auth-server-whitelist"; + +// The value of this switch tells the app to listen for and broadcast +// automation-related messages on IPC channel with the given ID. +const char kAutomationClientChannelID[] = "automation-channel"; + +// Causes the browser process to throw an assertion on startup. +const char kBrowserAssertTest[] = "assert-test"; + +// Causes the browser process to crash on startup. +const char kBrowserCrashTest[] = "crash-test"; + +// Path to the exe to run for the renderer and plugin subprocesses. +const char kBrowserSubprocessPath[] = "browser-subprocess-path"; + +// Run Chrome in Chrome Frame mode. This means that Chrome expects to be run +// as a dependent process of the Chrome Frame plugin. +const char kChromeFrame[] = "chrome-frame"; + +// The unique id to be used for this cloud print proxy instance. +const char kCloudPrintProxyId[] = "cloud-print-proxy-id"; + +// The URL of the cloud print service to use, overrides any value +// stored in preferences, and the default. Only used if the cloud +// print service has been enabled (see enable-cloud-print). +const char kCloudPrintServiceURL[] = "cloud-print-service"; + +// The Country we should use. This is normally obtained from the operating +// system during first run and cached in the preferences afterwards. This is a +// string value, the 2 letter code from ISO 3166-1. +const char kCountry[] = "country"; + +// Enables support to debug printing subsystem. +const char kDebugPrint[] = "debug-print"; + +// Triggers a pletora of diagnostic modes. +const char kDiagnostics[] = "diagnostics"; + +// Disables the alternate window station for the renderer. +const char kDisableAltWinstation[] = "disable-winsta"; + +// Disable the ApplicationCache. +const char kDisableApplicationCache[] = "disable-application-cache"; + +// Replaces the audio IPC layer for <audio> and <video> with a mock audio +// device, useful when using remote desktop or machines without sound cards. +// This is temporary until we fix the underlying problem. +// +// TODO(scherkus): remove --disable-audio when we have a proper fallback +// mechanism. +const char kDisableAudio[] = "disable-audio"; + +// Disable CNAME lookup of the host when generating the Kerberos SPN for a +// Negotiate challenge. See HttpAuthHandlerNegotiate::CreateSPN +// for more background. +const char kDisableAuthNegotiateCnameLookup[] = + "disable-auth-negotiate-cname-lookup"; + +// Disable limits on the number of backing stores. Can prevent blinking for +// users with many windows/tabs and lots of memory. +const char kDisableBackingStoreLimit[] = "disable-backing-store-limit"; + +// Disable support for cached byte-ranges. +const char kDisableByteRangeSupport[] = "disable-byte-range-support"; + +// Disables the custom JumpList on Windows 7. +const char kDisableCustomJumpList[] = "disable-custom-jumplist"; + +// Disables HTML5 DB support. +const char kDisableDatabases[] = "disable-databases"; + +// Disables desktop notifications (default enabled on windows). +const char kDisableDesktopNotifications[] = "disable-desktop-notifications"; + +// Browser flag to disable the web inspector for all renderers. +const char kDisableDevTools[] = "disable-dev-tools"; + +// Disable extensions. +const char kDisableExtensions[] = "disable-extensions"; + +// Disable checking for user opt-in for extensions that want to inject script +// into file URLs (ie, always allow it). This is used during automated testing. +const char kDisableExtensionsFileAccessCheck[] = + "disable-extensions-file-access-check"; + +// Suppresses support for the Geolocation javascript API. +const char kDisableGeolocation[] = "disable-geolocation"; + +// Suppresses hang monitor dialogs in renderer processes. +const char kDisableHangMonitor[] = "disable-hang-monitor"; + +// Disable the internal Flash Player. +const char kDisableInternalFlash[] = "disable-internal-flash"; + +// Don't resolve hostnames to IPv6 addresses. This can be used when debugging +// issues relating to IPv6, but shouldn't otherwise be needed. Be sure to +// file bugs if something isn't working properly in the presence of IPv6. +// This flag can be overidden by the "enable-ipv6" flag. +const char kDisableIPv6[] = "disable-ipv6"; + +// Don't execute JavaScript (browser JS like the new tab page still runs). +const char kDisableJavaScript[] = "disable-javascript"; + +// Prevent Java from running. +const char kDisableJava[] = "disable-java"; + +// Disable LocalStorage. +const char kDisableLocalStorage[] = "disable-local-storage"; + +// Force logging to be disabled. Logging is enabled by default in debug +// builds. +const char kDisableLogging[] = "disable-logging"; + +// Whether we should prevent the new tab page from showing the first run +// notification. +const char kDisableNewTabFirstRun[] = "disable-new-tab-first-run"; + +// Prevent plugins from running. +const char kDisablePlugins[] = "disable-plugins"; + +// Disable pop-up blocking. +const char kDisablePopupBlocking[] = "disable-popup-blocking"; + +// Normally when the user attempts to navigate to a page that was the result of +// a post we prompt to make sure they want to. This switch may be used to +// disable that check. This switch is used during automated testing. +const char kDisablePromptOnRepost[] = "disable-prompt-on-repost"; + +// Disable remote web font support. SVG font should always work whether +// this option is specified or not. +const char kDisableRemoteFonts[] = "disable-remote-fonts"; + +// Turns off the accessibility in the renderer. +const char kDisableRendererAccessibility[] = "disable-renderer-accessibility"; + +// Disable session storage. +const char kDisableSessionStorage[] = "disable-session-storage"; + +// Enable shared workers. Functionality not yet complete. +const char kDisableSharedWorkers[] = "disable-shared-workers"; + +// Disable site-specific tailoring to compatibility issues in WebKit. +const char kDisableSiteSpecificQuirks[] = "disable-site-specific-quirks"; + +// Disable syncing browser data to a Google Account. +const char kDisableSync[] = "disable-sync"; + +// Disable syncing of autofill. +const char kDisableSyncAutofill[] = "disable-sync-autofill"; + +// Disable syncing of bookmarks. +const char kDisableSyncBookmarks[] = "disable-sync-bookmarks"; + +// Disable syncing of extensions. +const char kDisableSyncExtensions[] = "disable-sync-extensions"; + +// Disable syncing of passwords. +const char kDisableSyncPasswords[] = "disable-sync-passwords"; + +// Disable syncing of preferences. +const char kDisableSyncPreferences[] = "disable-sync-preferences"; + +// Disable syncing of themes. +const char kDisableSyncThemes[] = "disable-sync-themes"; + +// Disable syncing of typed urls. +const char kDisableSyncTypedUrls[] = "disable-sync-typed-urls"; + +// TabCloseableStateWatcher disallows closing of tabs and browsers under certain +// situations on ChromeOS. Some tests expect tabs or browsers to close, so we +// need a switch to disable the watcher. +const char kDisableTabCloseableStateWatcher[] = + "disable-tab-closeable-state-watcher"; + +// Enables the backend service for web resources, used in the new tab page for +// loading tips and recommendations from a JSON feed. +const char kDisableWebResources[] = "disable-web-resources"; + +// Don't enforce the same-origin policy. (Used by people testing their sites.) +const char kDisableWebSecurity[] = "disable-web-security"; + +// Disable Web Sockets support. +const char kDisableWebSockets[] = "disable-web-sockets"; + +// Use a specific disk cache location, rather than one derived from the +// UserDatadir. +const char kDiskCacheDir[] = "disk-cache-dir"; + +// Forces the maximum disk space to be used by the disk cache, in bytes. +const char kDiskCacheSize[] = "disk-cache-size"; + +const char kDnsLogDetails[] = "dns-log-details"; + +// Disables prefetching of DNS information. +const char kDnsPrefetchDisable[] = "dns-prefetch-disable"; + +// Specifies if the dom_automation_controller_ needs to be bound in the +// renderer. This binding happens on per-frame basis and hence can potentially +// be a performance bottleneck. One should only enable it when automating +// dom based tests. +const char kDomAutomationController[] = "dom-automation"; + +// Dump any accumualted histograms to the log when browser terminates (requires +// logging to be enabled to really do anything). Used by developers and test +// scripts. +const char kDumpHistogramsOnExit[] = "dump-histograms-on-exit"; + +// Enable gpu-accelerated compositing. +const char kEnableAcceleratedCompositing[] = "enable-accelerated-compositing"; + +// Enables AeroPeek for each tab. (This switch only works on Windows 7). +const char kEnableAeroPeekTabs[] = "enable-aero-peek-tabs"; + +// Enable experimental extension apps. +const char kEnableApps[] = "enable-apps"; + +// Enable the inclusion of non-standard ports when generating the Kerberos SPN +// in response to a Negotiate challenge. See HttpAuthHandlerNegotiate::CreateSPN +// for more background. +const char kEnableAuthNegotiatePort[] = "enable-auth-negotiate-port"; + +// Enables the benchmarking extensions. +const char kEnableBenchmarking[] = "enable-benchmarking"; + +// This applies only when the process type is "service". Enables the +// Chromoting Host Process within the service process. +const char kEnableChromoting[] = "enable-chromoting"; + +// This applies only when the process type is "service". Enables the +// Cloud Print Proxy component within the service process. +const char kEnableCloudPrintProxy[] = "enable-cloud-print-proxy"; + +// Enables the Cloud Print dialog hosting code. +const char kEnableCloudPrint[] = "enable-cloud-print"; + +// Enables extension APIs that are in development. +const char kEnableExperimentalExtensionApis[] = + "enable-experimental-extension-apis"; + +// Enable experimental WebGL support. +const char kEnableExperimentalWebGL[] = "enable-webgl"; + +// Enable experimental timeline API. +const char kEnableExtensionTimelineApi[] = "enable-extension-timeline-api"; + +// Enable extension toolstrips (deprecated API - will be removed). +const char kEnableExtensionToolstrips[] = "enable-extension-toolstrips"; + +// Enable the fastback page cache. +const char kEnableFastback[] = "enable-fastback"; + +// By default, cookies are not allowed on file://. They are needed for +// testing, for example page cycler and layout tests. See bug 1157243. +const char kEnableFileCookies[] = "enable-file-cookies"; + +// Enable the Indexed Database API. +const char kEnableIndexedDatabase[] = "enable-indexed-database"; + +// Use the InMemoryURLIndex to back the HistoryURLProvider for autocomplete +// results. If not set, defaults to using the InMemoryDatabase. +const char kEnableInMemoryURLIndex[] = "enable-in-memory-url-index"; + +// Enable IPv6 support, even if probes suggest that it may not be fully +// supported. Some probes may require internet connections, and this flag will +// allow support independent of application testing. +// This flag overrides "disable-ipv6" which appears elswhere in this file. +const char kEnableIPv6[] = "enable-ipv6"; + +// Enable the GLSL translator. +const char kEnableGLSLTranslator[] = "enable-glsl-translator"; + +// Enable the GPU plugin and Pepper 3D rendering. +const char kEnableGPUPlugin[] = "enable-gpu-plugin"; + +// Enable experimental GPU rendering for backing store and video. +const char kEnableGPURendering[] = "enable-gpu-rendering"; + +// Force logging to be enabled. Logging is disabled by default in release +// builds. +const char kEnableLogging[] = "enable-logging"; + +// Allows reporting memory info (JS heap size) to page. +const char kEnableMemoryInfo[] = "enable-memory-info"; + +// On Windows, converts the page to the currently-installed monitor profile. +// This does NOT enable color management for images. The source is still +// assumed to be sRGB. +const char kEnableMonitorProfile[] = "enable-monitor-profile"; + +// Runs the Native Client inside the renderer process and enables GPU plugin +// (internally adds kInternalNaCl and lEnableGpuPlugin to the command line). +const char kEnableNaCl[] = "enable-nacl"; + +// Enable Native Web Worker support. +const char kEnableNativeWebWorkers[] = "enable-native-web-workers"; + +// Enable speculative TCP/IP preconnection. +const char kEnablePreconnect[] = "enable-preconnect"; + +// Enable caching of pre-parsed JS script data. See http://crbug.com/32407. +const char kEnablePreparsedJsCaching[] = "enable-preparsed-js-caching"; + +// Enable print preview (work in progress). +const char kEnablePrintPreview[] = "enable-print-preview"; + +// Enable the IsSearchProviderInstalled and InstallSearchProvider with an extra +// parameter to indicate if the provider should be the default. +const char kEnableSearchProviderApiV2[] = "enable-search-provider-api-v2"; + +// Enables StatsTable, logging statistics to a global named shared memory table. +const char kEnableStatsTable[] = "enable-stats-table"; + +// Enable syncing browser data to a Google Account. +const char kEnableSync[] = "enable-sync"; + +// Enable syncing browser autofill. +const char kEnableSyncAutofill[] = "enable-sync-autofill"; + +// Enable syncing browser bookmarks. +const char kEnableSyncBookmarks[] = "enable-sync-bookmarks"; + +// Enable syncing browser extensions. +const char kEnableSyncExtensions[] = "enable-sync-extensions"; + +// Enable syncing browser passwords. +const char kEnableSyncPasswords[] = "enable-sync-passwords"; + +// Enable syncing browser preferences. +const char kEnableSyncPreferences[] = "enable-sync-preferences"; + +// Enable syncing browser themes. +const char kEnableSyncThemes[] = "enable-sync-themes"; + +// Enable syncing browser typed urls. +const char kEnableSyncTypedUrls[] = "enable-sync-typed-urls"; + +// Enable tabbed options, ie: dom-ui version of options window. +const char kEnableTabbedOptions[] = "enable-tabbed-options"; + +// Whether or not the touch events API is exposed. +const char kEnableTouch[] = "enable-touch"; + +// Enables the option to show tabs as a vertical stack down the side of the +// browser window. +const char kEnableVerticalTabs[] = "enable-vertical-tabs"; + +// Enables support for fullscreen video. Current implementation is +// incomplete and this flag is used for development and testing. +const char kEnableVideoFullscreen[] = "enable-video-fullscreen"; + +// Enables video layering where video is rendered as a separate layer outside +// of the backing store. +const char kEnableVideoLayering[] = "enable-video-layering"; + +// Enables video logging where video elements log playback performance data to +// the debug log. +const char kEnableVideoLogging[] = "enable-video-logging"; + +// Spawn threads to watch for excessive delays in specified message loops. +// User should set breakpoints on Alarm() to examine problematic thread. +// Usage: -enable-watchdog=[ui][io] +// Order of the listed sub-arguments does not matter. +const char kEnableWatchdog[] = "enable-watchdog"; + +// Disable WebKit's XSSAuditor. The XSSAuditor mitigates reflective XSS. +const char kEnableXSSAuditor[] = "enable-xss-auditor"; + +// Enables the experimental Negotiate authentication protocol. +const char kExperimentalEnableNegotiateAuth[] = + "experimental-enable-negotiate-auth"; + +// Enables experimental features for Spellchecker. Right now, the first +// experimental feature is auto spell correct, which corrects words which are +// misppelled by typing the word with two consecutive letters swapped. The +// features that will be added next are: +// 1 - Allow multiple spellcheckers to work simultaneously. +// 2 - Allow automatic detection of spell check language. +// TODO(sidchat): Implement the above fetaures to work under this flag. +const char kExperimentalSpellcheckerFeatures[] = + "experimental-spellchecker-features"; + +// Explicitly allow additional ports using a comma separated list of port +// numbers. +const char kExplicitlyAllowedPorts[] = "explicitly-allowed-ports"; + +// Causes the process to run as an extension subprocess. +const char kExtensionProcess[] = "extension"; + +// Frequency in seconds for Extensions auto-update. +const char kExtensionsUpdateFrequency[] = "extensions-update-frequency"; + +// The file descriptor limit is set to the value of this switch, subject to the +// OS hard limits. Useful for testing that file descriptor exhaustion is handled +// gracefully. +const char kFileDescriptorLimit[] = "file-descriptor-limit"; + +// Display the First Run experience when the browser is started, regardless of +// whether or not it's actually the first run. +const char kFirstRun[] = "first-run"; + +// Some field tests may rendomized in the browser, and the randomly selected +// outcome needs to be propogated to the renderer. For instance, this is used +// to modify histograms recorded in the renderer, or to get the renderer to +// also set of its state (initialize, or not initialize components) to match the +// experiment(s). +// The argument is a string-ized list of experiment names, and the associated +// value that was randomly selected. In the recent implementetaion, the +// persistent representation generated by field_trial.cc and later decoded, is a +// list of name and value pairs, separated by slashes. See field trial.cc for +// current details. +const char kForceFieldTestNameAndValue[] = "force-fieldtest"; + +// Extra command line options for launching the GPU process (normally used +// for debugging). Use like renderer-cmd-prefix. +const char kGpuLauncher[] = "gpu-launcher"; + +// Makes this process a GPU sub-process. +const char kGpuProcess[] = "gpu-process"; + +// Causes the GPU process to display a dialog on launch. +const char kGpuStartupDialog[] = "gpu-startup-dialog"; + +// These flags show the man page on Linux. They are equivalent to each +// other. +const char kHelp[] = "help"; +const char kHelpShort[] = "h"; + +// Make Windows happy by allowing it to show "Enable access to this program" +// checkbox in Add/Remove Programs->Set Program Access and Defaults. This +// only shows an error box because the only way to hide Chrome is by +// uninstalling it. +const char kHideIcons[] = "hide-icons"; + +// The value of this switch specifies which page will be displayed +// in newly-opened tabs. We need this for testing purposes so +// that the UI tests don't depend on what comes up for http://google.com. +const char kHomePage[] = "homepage"; + +// Comma separated list of rules that control how hostnames are mapped. +// +// For example: +// "MAP * 127.0.0.1" --> Forces all hostnames to be mapped to 127.0.0.1 +// "MAP *.google.com proxy" --> Forces all google.com subdomains to be +// resolved to "proxy". +// "MAP test.com [::1]:77 --> Forces "test.com" to resolve to IPv6 loopback. +// Will also force the port of the resulting +// socket address to be 77. +// "MAP * baz, EXCLUDE www.google.com" --> Remaps everything to "baz", +// except for "www.google.com". +// +// These mappings apply to the endpoint host in a URLRequest (the TCP connect +// and host resolver in a direct connection, and the CONNECT in an http proxy +// connection, and the endpoint host in a SOCKS proxy connection). +const char kHostRules[] = "host-rules"; + +// The maximum number of concurrent host resolve requests (i.e. DNS) to allow. +const char kHostResolverParallelism[] = "host-resolver-parallelism"; + +// These mappings only apply to the host resolver. +const char kHostResolverRules[] = "host-resolver-rules"; + +// Perform importing from another browser. The value associated with this +// setting encodes the target browser and what items to import. +const char kImport[] = "import"; + +// Perform bookmark importing from an HTML file. The value associated with this +// setting encodes the file path. It may be used jointly with kImport. +const char kImportFromFile[] = "import-from-file"; + +// Runs plugins inside the renderer process +const char kInProcessPlugins[] = "in-process-plugins"; + +// Runs WebGL inside the renderer process. +const char kInProcessWebGL[] = "in-process-webgl"; + +// Causes the browser to launch directly in incognito mode. +const char kIncognito[] = "incognito"; + +// Back up the profile. +const char kInstallerTestBackup[] = "backup"; + +// Control the build under test. +const char kInstallerTestBuild[] = "build"; + +// Uninstall before running the tests. +const char kInstallerTestClean[] = "clean"; + +// Force the installer tests to run, regardless of the current platform. +const char kInstallerTestForce[] = "force"; + +// Runs the Native Client inside the renderer process. +const char kInternalNaCl[] = "internal-nacl"; + +// Runs a trusted Pepper plugin inside the renderer process. +const char kInternalPepper[] = "internal-pepper"; + +// The following flags allow users who can reproduce crbug/35198 +// to enable extra logging and behaviors. They will be removed once +// the issue is fixed. +const char kIssue35198CrxDirBrowser[] = "issue35198-crxdir-browser"; +const char kIssue35198ExtraLogging[] = "issue35198-logging"; +const char kIssue35198Permission[] = "issue35198-permission"; + +// Specifies the flags passed to JS engine +const char kJavaScriptFlags[] = "js-flags"; + +// Used for testing - keeps browser alive after last browser window closes. +const char kKeepAliveForTest[] = "keep-alive-for-test"; + +// Load an extension from the specified directory. +const char kLoadExtension[] = "load-extension"; + +// Load an NPAPI plugin from the specified path. +const char kLoadPlugin[] = "load-plugin"; + +// Load NPAPI plugins from the specified directory. +const char kExtraPluginDir[] = "extra-plugin-dir"; + +// Will filter log messages to show only the messages that are prefixed +// with the specified value. See also kEnableLogging and kLoggingLevel. +const char kLogFilterPrefix[] = "log-filter-prefix"; + +// Make plugin processes log their sent and received messages to LOG(INFO). +const char kLogPluginMessages[] = "log-plugin-messages"; + +// Sets the minimum log level. Valid values are from 0 to 3: +// INFO = 0, WARNING = 1, LOG_ERROR = 2, LOG_FATAL = 3. +const char kLoggingLevel[] = "log-level"; + +// Make Chrome default browser +const char kMakeDefaultBrowser[] = "make-default-browser"; + +// Forces the maximum disk space to be used by the media cache, in bytes. +const char kMediaCacheSize[] = "media-cache-size"; + +// Enable dynamic loading of the Memory Profiler DLL, which will trace +// all memory allocations during the run. +const char kMemoryProfiling[] = "memory-profile"; + +// Enable histograming of tasks served by MessageLoop. See about:histograms/Loop +// for results, which show frequency of messages on each thread, including APC +// count, object signalling count, etc. +const char kMessageLoopHistogrammer[] = "message-loop-histogrammer"; + +// Enables the recording of metrics reports but disables reporting. In +// contrast to kDisableMetrics, this executes all the code that a normal client +// would use for reporting, except the report is dropped rather than sent to +// the server. This is useful for finding issues in the metrics code during UI +// and performance tests. +const char kMetricsRecordingOnly[] = "metrics-recording-only"; + +// Causes the process to run as a NativeClient broker +// (used for launching NaCl loader processes on 64-bit Windows). +const char kNaClBrokerProcess[] = "nacl-broker"; + +// Causes the process to run as a NativeClient loader. +const char kNaClLoaderProcess[] = "nacl-loader"; + +// Causes the Native Client process to display a dialog on launch. +const char kNaClStartupDialog[] = "nacl-startup-dialog"; + +// Disables the default browser check. Useful for UI/browser tests where we +// want to avoid having the default browser info-bar displayed. +const char kNoDefaultBrowserCheck[] = "no-default-browser-check"; + +// Don't record/playback events when using record & playback. +const char kNoEvents[] = "no-events"; + +// Bypass the First Run experience when the browser is started, regardless of +// whether or not it's actually the first run. Overrides kFirstRun in case +// you're for some reason tempted to pass them both. +const char kNoFirstRun[] = "no-first-run"; + +// Support a separate switch that enables the v8 playback extension. +// The extension causes javascript calls to Date.now() and Math.random() +// to return consistent values, such that subsequent loads of the same +// page will result in consistent js-generated data and XHR requests. +// Pages may still be able to generate inconsistent data from plugins. +const char kNoJsRandomness[] = "no-js-randomness"; + +// Don't send HTTP-Referer headers. +const char kNoReferrers[] = "no-referrers"; + +// Don't use a proxy server, always make direct connections. Overrides any +// other proxy server flags that are passed. +const char kNoProxyServer[] = "no-proxy-server"; + +// Runs the renderer outside the sandbox. +const char kNoSandbox[] = "no-sandbox"; + +// Specifies the maximum number of threads to use for running the Proxy +// Autoconfig (PAC) script. +const char kNumPacThreads[] = "num-pac-threads"; + +// Launch URL in new browser window. +const char kOpenInNewWindow[] = "new-window"; + +// Package an extension to a .crx installable file from a given directory. +const char kPackExtension[] = "pack-extension"; + +// Optional PEM private key is to use in signing packaged .crx. +const char kPackExtensionKey[] = "pack-extension-key"; + +// Specifies the path to the user data folder for the parent profile. +const char kParentProfile[] = "parent-profile"; + +// Read previously recorded data from the cache. Only cached data is read. +// See kRecordMode. +const char kPlaybackMode[] = "playback-mode"; + +// Specifies the plugin data directory, which is where plugins (Gears +// specifically) will store its state. +const char kPluginDataDir[] = "plugin-data-dir"; + +// Specifies a command that should be used to launch the plugin process. Useful +// for running the plugin process through purify or quantify. Ex: +// --plugin-launcher="path\to\purify /Run=yes" +const char kPluginLauncher[] = "plugin-launcher"; + +// Tells the plugin process the path of the plugin to load +const char kPluginPath[] = "plugin-path"; + +// Causes the process to run as a plugin subprocess. +const char kPluginProcess[] = "plugin"; + +// Causes the plugin process to display a dialog on launch. +const char kPluginStartupDialog[] = "plugin-startup-dialog"; + +// Enable TCP/IP preconnection, and DNS preresolution, even if a proxy might +// possibly be used for connections. +const char kPreconnectDespiteProxy[] = "preconnect-despite-proxy"; + +// Establishes a channel to the GPU process asynchronously and (re)launches it +// if necessary when a renderer process starts. +const char kPrelaunchGpuProcess[] = "prelaunch-gpu-process"; + +// Prints the pages on the screen. +const char kPrint[] = "print"; + +// Runs a single process for each site (i.e., group of pages from the same +// registered domain) the user visits. We default to using a renderer process +// for each site instance (i.e., group of pages from the same registered +// domain with script connections to each other). +const char kProcessPerSite[] = "process-per-site"; + +// Runs each set of script-connected tabs (i.e., a BrowsingInstance) in its own +// renderer process. We default to using a renderer process for each +// site instance (i.e., group of pages from the same registered domain with +// script connections to each other). +const char kProcessPerTab[] = "process-per-tab"; + +// Output the product version information and quit. Used as an internal api to +// detect the installed version of Chrome on Linux. +const char kProductVersion[] = "product-version"; + +// Causes the process to run as a profile import subprocess. +const char kProfileImportProcess[] = "profile-import"; + +// Force proxy auto-detection. +const char kProxyAutoDetect[] = "proxy-auto-detect"; + +// Specify a list of hosts for whom we bypass proxy settings and use direct +// connections. Ignored if --proxy-auto-detect or --no-proxy-server are +// also specified. +// This is a comma separated list of bypass rules. See: +// "net/proxy/proxy_bypass_rules.h" for the format of these rules. +const char kProxyBypassList[] = "proxy-bypass-list"; + +// Use the pac script at the given URL +const char kProxyPacUrl[] = "proxy-pac-url"; + +// Use a specified proxy server, overrides system settings. This switch only +// affects HTTP and HTTPS requests. +const char kProxyServer[] = "proxy-server"; + +// Adds a "Purge memory" button to the Task Manager, which tries to dump as +// much memory as possible. This is mostly useful for testing how well the +// MemoryPurger functionality works. +// +// NOTE: This is only implemented for Views. +const char kPurgeMemoryButton[] = "purge-memory-button"; + +// Chrome supports a playback and record mode. Record mode saves *everything* +// to the cache. Playback mode reads data exclusively from the cache. This +// allows us to record a session into the cache and then replay it at will. +// See also kPlaybackMode. +const char kRecordMode[] = "record-mode"; + +// Register pepper plugins that should be loaded into the renderer. +const char kRegisterPepperPlugins[] = "register-pepper-plugins"; + +// Enable remote debug over HTTP on the specified port. +const char kRemoteDebuggingPort[] = "remote-debugging-port"; + +// Enable remote debug / automation shell on the specified port. +const char kRemoteShellPort[] = "remote-shell-port"; + +// Causes the renderer process to throw an assertion on launch. +const char kRendererAssertTest[] = "renderer-assert-test"; + +#if !defined(OFFICIAL_BUILD) +// Causes the renderer process to throw an assertion on launch. +const char kRendererCheckFalseTest[] = "renderer-check-false-test"; +#endif + +// On POSIX only: the contents of this flag are prepended to the renderer +// command line. Useful values might be "valgrind" or "xterm -e gdb --args". +const char kRendererCmdPrefix[] = "renderer-cmd-prefix"; + +// Causes the renderer process to crash on launch. +const char kRendererCrashTest[] = "renderer-crash-test"; + +// Causes the process to run as renderer instead of as browser. +const char kRendererProcess[] = "renderer"; + +// Causes the renderer process to display a dialog on launch. +const char kRendererStartupDialog[] = "renderer-startup-dialog"; + +// Causes the URLs of BackgroundContents to be remembered and re-launched when +// the browser restarts. +const char kRestoreBackgroundContents[] = "restore-background-contents"; + +// Indicates the last session should be restored on startup. This overrides +// the preferences value and is primarily intended for testing. The value of +// this switch is the number of tabs to wait until loaded before +// 'load completed' is sent to the ui_test. +const char kRestoreLastSession[] = "restore-last-session"; + +// Runs the plugin processes inside the sandbox. +const char kSafePlugins[] = "safe-plugins"; + +// URL prefix used by safebrowsing to fetch hash, download data and +// report malware. +const char kSbInfoURLPrefix[] = "safebrowsing-info-url-prefix"; +// URL prefix used by safebrowsing to get MAC key. +const char kSbMacKeyURLPrefix[] = "safebrowsing-mackey-url-prefix"; +// If present, safebrowsing only performs update when +// SafeBrowsingProtocolManager::ForceScheduleNextUpdate() is explicitly called. +// This is used for testing only. +const char kSbDisableAutoUpdate[] = "safebrowsing-disable-auto-update"; + +// Enable support for SDCH filtering (dictionary based expansion of content). +// Optional argument is *the* only domain name that will have SDCH suppport. +// Default is "-enable-sdch" to advertise SDCH on all domains. +// Sample usage with argument: "-enable-sdch=.google.com" +// SDCH is currently only supported server-side for searches on google.com. +const char kSdchFilter[] = "enable-sdch"; + +// Enables the showing of an info-bar instructing user they can search directly +// from the omnibox. +const char kSearchInOmniboxHint[] = "search-in-omnibox-hint"; + +// Causes the process to run as a service process. +const char kServiceProcess[] = "service"; + +// The LSID of the account to use for the service process. +const char kServiceAccountLsid[] = "service-account-lsid"; + +// See kHideIcons. +const char kShowIcons[] = "show-icons"; + +// Renders a border around composited Render Layers to help debug and study +// layer compositing. +const char kShowCompositedLayerBorders[] = "show-composited-layer-borders"; + +// Visibly render a border around paint rects in the web page to help debug +// and study painting behavior. +const char kShowPaintRects[] = "show-paint-rects"; + +// Whether to show the link to the Google Privacy Dashboard on the Sync options +// panel. +const char kShowPrivacyDashboardLink[] = "show-privacy-dashboard-link"; + +// Change the DCHECKS to dump memory and continue instead of displaying error +// dialog. This is valid only in Release mode when --enable-dcheck is +// specified. +const char kSilentDumpOnDCHECK[] = "silent-dump-on-dcheck"; + +// Replaces the buffered data source for <audio> and <video> with a simplified +// resource loader that downloads the entire resource into memory. +// +// TODO(scherkus): remove --simple-data-source when our media resource loading +// is cleaned up and playback testing completed. +const char kSimpleDataSource[] = "simple-data-source"; + +// Runs the renderer and plugins in the same process as the browser +const char kSingleProcess[] = "single-process"; + +// Start the browser maximized, regardless of any previous settings. +const char kStartMaximized[] = "start-maximized"; + +// Control Sync XMPP client settings. +const char kSyncAllowPlain[] = "allow-plain"; + +// Control Sync XMPP client settings. +const char kSyncDisableTls[] = "disable-tls"; + +// Email used for sync. +const char kSyncEmail[] = "email"; + +// Use the SyncerThread implementation that matches up with the old pthread +// impl semantics, but using Chrome synchronization primitives. The only +// difference between this and the default is that we now have no timeout on +// Stop(). Should only use if you experience problems with the default. +const char kSyncerThreadTimedStop[] = "syncer-thread-timed-stop"; + +// Override the default notification method for sync. +const char kSyncNotificationMethod[] = "sync-notification-method"; + +// Password used for sync. +const char kSyncPassword[] = "password"; + +// Port used for sync. +const char kSyncPort[] = "port"; + +// Server used for sync. +const char kSyncServer[] = "server"; + +// Override the default server used for profile sync. +const char kSyncServiceURL[] = "sync-url"; + +// Use the (new, untested) Chrome-socket-based buzz::AsyncSocket +// implementation for notifications. +const char kSyncUseChromeAsyncSocket[] = "sync-use-chrome-async-socket"; + +// Control Sync XMPP client settings. +const char kSyncUseSslTcp[] = "use-ssl-tcp"; + +// Control Sync XMPP client settings. +const char kSyncUseCacheInvalidation[] = "use-cache-invalidation"; + +// Pass the name of the current running automated test to Chrome. +const char kTestName[] = "test-name"; + +// Runs the security test for the renderer sandbox. +const char kTestSandbox[] = "test-sandbox"; + +// Runs the security test for the NaCl loader sandbox. +const char kTestNaClSandbox[] = "test-nacl-sandbox"; + +// Pass the type of the current test harness ("browser" or "ui") +const char kTestType[] = "test-type"; + +// The value of this switch tells the app to listen for and broadcast +// testing-related messages on IPC channel with the given ID. +const char kTestingChannelID[] = "testing-channel"; + +// Enables using TopSites instead of ThumbnailDatabase (and +// ThumbnailStore) for getting thumbnails for the new tab page. +const char kTopSites[] = "top-sites"; + +// Excludes these plugins from the plugin sandbox. +// This is a comma-separated list of plugin library names. +const char kTrustedPlugins[] = "trusted-plugins"; + +// Experimental. Shows a dialog asking the user to try chrome. This flag +// is to be used only by the upgrade process. +const char kTryChromeAgain[] = "try-chrome-again"; + +// Runs un-installation steps that were done by chrome first-run. +const char kUninstall[] = "uninstall"; + +// Use Spdy for the transport protocol instead of HTTP. +// This is a temporary testing flag. +const char kUseSpdy[] = "use-spdy"; + +// These two flags are used to force http and https requests to fixed ports. +const char kFixedHttpPort[] = "testing-fixed-http-port"; +const char kFixedHttpsPort[] = "testing-fixed-https-port"; + +// Ignore certificate related errors. +const char kIgnoreCertificateErrors[] = "ignore-certificate-errors"; + +// Set the maximum SPDY sessions per domain. +const char kMaxSpdySessionsPerDomain[] = "max-spdy-sessions-per-domain"; + +// Use the low fragmentation heap for the CRT. +const char kUseLowFragHeapCrt[] = "use-lf-heap"; + +// A string used to override the default user agent with a custom one. +const char kUserAgent[] = "user-agent"; + +// Specifies the user data directory, which is where the browser will look +// for all of its state. +const char kUserDataDir[] = "user-data-dir"; + +// directory to locate user scripts in as an over-ride of the default +const char kUserScriptsDir[] = "user-scripts-dir"; + +// On POSIX only: the contents of this flag are prepended to the utility +// process command line. Useful values might be "valgrind" or "xterm -e gdb +// --args". +const char kUtilityCmdPrefix[] = "utility-cmd-prefix"; + +// Causes the process to run as a utility subprocess. +const char kUtilityProcess[] = "utility"; + +// The utility process is sandboxed, with access to one directory. This flag +// specifies the directory that can be accessed. +const char kUtilityProcessAllowedDir[] = "utility-allowed-dir"; + +// Print version information and quit. +const char kVersion[] = "version"; + +// Will add kWaitForDebugger to every child processes. If a value is passed, it +// will be used as a filter to determine if the child process should have the +// kWaitForDebugger flag passed on or not. +const char kWaitForDebuggerChildren[] = "wait-for-debugger-children"; + +// Causes the worker process allocation to use as many processes as cores. +const char kWebWorkerProcessPerCore[] = "web-worker-process-per-core"; + +// Causes workers to run together in one process, depending on their domains. +// Note this is duplicated in webworkerclient_impl.cc +const char kWebWorkerShareProcesses[] = "web-worker-share-processes"; + +// Use WinHTTP to fetch and evaluate PAC scripts. Otherwise the default is +// to use Chromium's network stack to fetch, and V8 to evaluate. +const char kWinHttpProxyResolver[] = "winhttp-proxy-resolver"; + +// Causes the process to run as a worker subprocess. +const char kWorkerProcess[] = "worker"; + +// The prefix used when starting the zygote process. (i.e. 'gdb --args') +const char kZygoteCmdPrefix[] = "zygote-cmd-prefix"; + +// Causes the process to run as a renderer zygote. +const char kZygoteProcess[] = "zygote"; + +#if defined(OS_CHROMEOS) +// Enable the redirection of viewable document requests to the Google +// Document Viewer. +const char kEnableGView[] = "enable-gview"; + +// Should we show the image based login? +const char kEnableLoginImages[] = "enable-login-images"; + +// Enable Chrome-as-a-login-manager behavior. +const char kLoginManager[] = "login-manager"; +// Allows to override the first login screen. The value should be the name +// of the first login screen to show (see +// chrome/browser/chromeos/login/login_wizard_view.cc for actual names). +// Ignored if kLoginManager is not specified. +// TODO(avayvod): Remove when the switch is no longer needed for testing. +const char kLoginScreen[] = "login-screen"; +// Allows control over the initial login screen size. Pass width,height. +const char kLoginScreenSize[] = "login-screen-size"; + +// Attempts to load libcros and validate it, then exits. A nonzero return code +// means the library could not be loaded correctly. +const char kTestLoadLibcros[] = "test-load-libcros"; + +// TODO(davemoore) Delete this once chromeos has started using +// login-profile as its arg. +const char kProfile[] = "profile"; + +// Specifies the profile to use once a chromeos user is logged in. +const char kLoginProfile[] = "login-profile"; + +// Specifies the user which is already logged in. +const char kLoginUser[] = "login-user"; + +// Use the frame layout used in chromeos. +const char kChromeosFrame[] = "chromeos-frame"; + +// Set logging output to the given file. +const char kChromeosLogToFile[] = "logtofile"; + +// Specify startup customization manifest. +// TODO(denisromanov): delete this when not needed for testing. +const char kStartupManifest[] = "startup-manifest"; + +// Specify services customization manifest. +// TODO(denisromanov): delete this when not needed for testing. +const char kServicesManifest[] = "services-manifest"; + +#endif + +#if defined(OS_LINUX) +// Specify the amount the trackpad should scroll by. +const char kScrollPixels[] = "scroll-pixels"; +#endif + +#if defined(OS_MACOSX) || defined(OS_WIN) +// Use the system SSL library (Secure Transport on Mac, SChannel on Windows) +// instead of NSS for SSL. +const char kUseSystemSSL[] = "use-system-ssl"; +#endif + +#if defined(OS_POSIX) +// Bypass the error dialog when the profile lock couldn't be attained. +// A flag, generated internally by Chrome for renderer and other helper process +// command lines on Linux and Mac. It tells the helper process to enable crash +// dumping and reporting, because helpers cannot access the profile or other +// files needed to make this decision. +// If passed to the browser, it'll be passed on to all the helper processes +// as well, thereby force-enabling the crash reporter. +const char kEnableCrashReporter[] = "enable-crash-reporter"; + +// This switch is used during automated testing. +const char kNoProcessSingletonDialog[] = "no-process-singleton-dialog"; + +#if !defined(OS_MACOSX) +// Specifies which password store to use (detect, default, gnome, kwallet). +const char kPasswordStore[] = "password-store"; +#endif +#endif + +#if defined(OS_MACOSX) +// Cause the OS X sandbox write to syslog every time an access to a resource +// is denied by the sandbox. +const char kEnableSandboxLogging[] = "enable-sandbox-logging"; + +// Temporary flag to prevent Flash from negotiating the Core Animation drawing +// model. This will be removed once the last issues have been resolved. +const char kDisableFlashCoreAnimation[] = "disable-flash-core-animation"; +#else +// Enable Kiosk mode. +const char kKioskMode[] = "kiosk"; +#endif + +#ifndef NDEBUG +// Debug only switch to specify which gears plugin dll to load. +const char kGearsPluginPathOverride[] = "gears-plugin-path"; + +// Makes sure any sync login attempt will fail with an error. (Only +// used for testing.) +const char kInvalidateSyncLogin[] = "invalidate-sync-login"; + +// Makes sure any sync xmpp login attempt will fail with an error. (Only +// used for testing.) +const char kInvalidateSyncXmppLogin[] = "invalidate-sync-xmpp-login"; + +// Debug only switch to specify which websocket live experiment host to be used. +// If host is specified, it also makes initial delay shorter (5 min to 5 sec) +// to make it faster to test websocket live experiment code. +const char kWebSocketLiveExperimentHost[] = "websocket-live-experiment-host"; +#endif + +// USE_SECCOMP_SANDBOX controls whether the seccomp sandbox is opt-in or -out. +// TODO(evan): unify all of these once we turn the seccomp sandbox always +// on. Also remove the #include of command_line.h above. +#if defined(USE_SECCOMP_SANDBOX) +// Disable the seccomp sandbox (Linux only) +const char kDisableSeccompSandbox[] = "disable-seccomp-sandbox"; +#else +// Enable the seccomp sandbox (Linux only) +const char kEnableSeccompSandbox[] = "enable-seccomp-sandbox"; +#endif + +bool SeccompSandboxEnabled() { +#if defined(USE_SECCOMP_SANDBOX) + return !CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableSeccompSandbox); +#else + return CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableSeccompSandbox); +#endif +} + +// ----------------------------------------------------------------------------- +// DO NOT ADD YOUR CRAP TO THE BOTTOM OF THIS FILE. +// +// You were going to just dump your switches here, weren't you? Instead, +// please put them in alphabetical order above, or in order inside the +// appropriate ifdef at the bottom. The order should match the header. +// ----------------------------------------------------------------------------- + +} // namespace switches diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h new file mode 100644 index 0000000..70a8268 --- /dev/null +++ b/chrome/common/chrome_switches.h @@ -0,0 +1,354 @@ +// Copyright (c) 2010 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. + +// Defines all the command-line switches used by Chrome. + +#ifndef CHROME_COMMON_CHROME_SWITCHES_H_ +#define CHROME_COMMON_CHROME_SWITCHES_H_ + +#include "build/build_config.h" +#include "base/base_switches.h" + +namespace switches { + +// ----------------------------------------------------------------------------- +// Can't find the switch you are looking for? Try looking in +// base/base_switches.cc instead. +// ----------------------------------------------------------------------------- + +// All switches in alphabetical order. The switches should be documented +// alongside the definition of their values in the .cc file. +extern const char kActivateOnLaunch[]; +extern const char kAllowFileAccessFromFiles[]; +extern const char kAllowSandboxDebugging[]; +extern const char kAllowScriptingGallery[]; +extern const char kAlwaysEnableDevTools[]; +extern const char kApp[]; +extern const char kAppId[]; +extern const char kAppLaunchAsPanel[]; +extern const char kAppsDebug[]; +extern const char kAppsPanel[]; +extern const char kAppsGalleryURL[]; +extern const char kAppsNoThrob[]; +extern const char kAuthServerWhitelist[]; +extern const char kAutomationClientChannelID[]; +extern const char kBrowserAssertTest[]; +extern const char kBrowserCrashTest[]; +extern const char kBrowserSubprocessPath[]; +extern const char kChromeFrame[]; +extern const char kCloudPrintProxyId[]; +extern const char kCloudPrintServiceURL[]; +extern const char kCountry[]; +extern const char kDebugPrint[]; +extern const char kDiagnostics[]; +extern const char kDisableAltWinstation[]; +extern const char kDisableApplicationCache[]; +extern const char kDisableAudio[]; +extern const char kDisableAuthNegotiateCnameLookup[]; +extern const char kDisableBackingStoreLimit[]; +extern const char kDisableByteRangeSupport[]; +extern const char kDisableCustomJumpList[]; +extern const char kDisableDatabases[]; +extern const char kDisableDesktopNotifications[]; +extern const char kDisableDevTools[]; +extern const char kDisableExtensions[]; +extern const char kDisableExtensionsFileAccessCheck[]; +extern const char kDisableGeolocation[]; +extern const char kDisableHangMonitor[]; +extern const char kDisableInternalFlash[]; +extern const char kDisableIPv6[]; +extern const char kDisableJavaScript[]; +extern const char kDisableJava[]; +extern const char kDisableLocalStorage[]; +extern const char kDisableLogging[]; +extern const char kDisableNewTabFirstRun[]; +extern const char kDisablePlugins[]; +extern const char kDisablePopupBlocking[]; +extern const char kDisablePromptOnRepost[]; +extern const char kDisableRemoteFonts[]; +extern const char kDisableRendererAccessibility[]; +extern const char kDisableSessionStorage[]; +extern const char kDisableSharedWorkers[]; +extern const char kDisableSiteSpecificQuirks[]; +extern const char kDisableSync[]; +extern const char kDisableSyncAutofill[]; +extern const char kDisableSyncBookmarks[]; +extern const char kDisableSyncExtensions[]; +extern const char kDisableSyncPasswords[]; +extern const char kDisableSyncPreferences[]; +extern const char kDisableSyncThemes[]; +extern const char kDisableSyncTypedUrls[]; +extern const char kDisableTabCloseableStateWatcher[]; +extern const char kDisableWebResources[]; +extern const char kDisableWebSecurity[]; +extern const char kDisableWebSockets[]; +extern const char kDiskCacheDir[]; +extern const char kDiskCacheSize[]; +extern const char kDnsLogDetails[]; +extern const char kDnsPrefetchDisable[]; +extern const char kDomAutomationController[]; +extern const char kDumpHistogramsOnExit[]; +extern const char kEnableAcceleratedCompositing[]; +extern const char kEnableAeroPeekTabs[]; +extern const char kEnableApps[]; +extern const char kEnableAuthNegotiatePort[]; +extern const char kEnableBenchmarking[]; +extern const char kEnableChromoting[]; +extern const char kEnableCloudPrintProxy[]; +extern const char kEnableCloudPrint[]; +extern const char kEnableExperimentalExtensionApis[]; +extern const char kEnableExperimentalWebGL[]; +extern const char kEnableExtensionTimelineApi[]; +extern const char kEnableExtensionToolstrips[]; +extern const char kEnableFastback[]; +extern const char kEnableFileCookies[]; +extern const char kEnableGLSLTranslator[]; +extern const char kEnableGPUPlugin[]; +extern const char kEnableGPURendering[]; +extern const char kEnableIndexedDatabase[]; +extern const char kEnableInMemoryURLIndex[]; +extern const char kEnableIPv6[]; +extern const char kEnableLogging[]; +extern const char kEnableMemoryInfo[]; +extern const char kEnableMonitorProfile[]; +extern const char kEnableNaCl[]; +extern const char kEnableNativeWebWorkers[]; +extern const char kEnablePreparsedJsCaching[]; +extern const char kEnablePreconnect[]; +extern const char kEnablePrintPreview[]; +extern const char kEnableSearchProviderApiV2[]; +extern const char kEnableStatsTable[]; +extern const char kEnableSync[]; +extern const char kEnableSyncAutofill[]; +extern const char kEnableSyncBookmarks[]; +extern const char kEnableSyncExtensions[]; +extern const char kEnableSyncPasswords[]; +extern const char kEnableSyncPreferences[]; +extern const char kEnableSyncThemes[]; +extern const char kEnableSyncTypedUrls[]; +extern const char kEnableTabbedOptions[]; +extern const char kEnableTouch[]; +extern const char kEnableVerticalTabs[]; +extern const char kEnableVideoFullscreen[]; +extern const char kEnableVideoLayering[]; +extern const char kEnableVideoLogging[]; +extern const char kEnableWatchdog[]; +extern const char kEnableXSSAuditor[]; +// Experimental features. +extern const char kExperimentalEnableNegotiateAuth[]; +extern const char kExperimentalSpellcheckerFeatures[]; +// End experimental features. +extern const char kExplicitlyAllowedPorts[]; +extern const char kExtensionProcess[]; +extern const char kExtensionsUpdateFrequency[]; +extern const char kFileDescriptorLimit[]; +extern const char kFirstRun[]; +extern const char kForceFieldTestNameAndValue[]; +extern const char kGpuLauncher[]; +extern const char kGpuProcess[]; +extern const char kGpuStartupDialog[]; +extern const char kHelp[]; +extern const char kHelpShort[]; +extern const char kHideIcons[]; +extern const char kHomePage[]; +extern const char kHostRules[]; +extern const char kHostResolverParallelism[]; +extern const char kHostResolverRules[]; +extern const char kImport[]; +extern const char kImportFromFile[]; +extern const char kInProcessPlugins[]; +extern const char kInProcessWebGL[]; +extern const char kIncognito[]; +extern const char kInstallerTestBackup[]; +extern const char kInstallerTestBuild[]; +extern const char kInstallerTestClean[]; +extern const char kInstallerTestForce[]; +extern const char kInternalNaCl[]; +extern const char kInternalPepper[]; +extern const char kIssue35198CrxDirBrowser[]; +extern const char kIssue35198ExtraLogging[]; +extern const char kIssue35198Permission[]; +extern const char kJavaScriptFlags[]; +extern const char kKeepAliveForTest[]; +extern const char kLoadExtension[]; +extern const char kLoadPlugin[]; +extern const char kExtraPluginDir[]; +extern const char kLogFilterPrefix[]; +extern const char kLogPluginMessages[]; +extern const char kLoggingLevel[]; +extern const char kMakeDefaultBrowser[]; +extern const char kMediaCacheSize[]; +extern const char kMemoryProfiling[]; +extern const char kMessageLoopHistogrammer[]; +extern const char kMetricsRecordingOnly[]; +extern const char kNaClBrokerProcess[]; +extern const char kNaClLoaderProcess[]; +extern const char kNaClStartupDialog[]; +extern const char kNoDefaultBrowserCheck[]; +extern const char kNoEvents[]; +extern const char kNoFirstRun[]; +extern const char kNoJsRandomness[]; +extern const char kNoProxyServer[]; +extern const char kNoReferrers[]; +extern const char kNoSandbox[]; +extern const char kNumPacThreads[]; +extern const char kOpenInNewWindow[]; +extern const char kPackExtension[]; +extern const char kPackExtensionKey[]; +extern const char kParentProfile[]; +extern const char kPlaybackMode[]; +extern const char kPluginDataDir[]; +extern const char kPluginLauncher[]; +extern const char kPluginPath[]; +extern const char kPluginProcess[]; +extern const char kPluginStartupDialog[]; +extern const char kPreconnectDespiteProxy[]; +extern const char kPrelaunchGpuProcess[]; +extern const char kPrint[]; +extern const char kProcessPerSite[]; +extern const char kProcessPerTab[]; +extern const char kProductVersion[]; +extern const char kProfileImportProcess[]; +extern const char kProxyAutoDetect[]; +extern const char kProxyBypassList[]; +extern const char kProxyPacUrl[]; +extern const char kProxyServer[]; +extern const char kPurgeMemoryButton[]; +extern const char kRecordMode[]; +extern const char kRegisterPepperPlugins[]; +extern const char kRemoteDebuggingPort[]; +extern const char kRemoteShellPort[]; +extern const char kRendererAssertTest[]; +extern const char kRendererCmdPrefix[]; +extern const char kRendererCrashTest[]; +extern const char kRendererProcess[]; +extern const char kRendererStartupDialog[]; +extern const char kRestoreBackgroundContents[]; +extern const char kRestoreLastSession[]; +extern const char kSafePlugins[]; +extern const char kSbInfoURLPrefix[]; +extern const char kSbMacKeyURLPrefix[]; +extern const char kSbDisableAutoUpdate[]; +extern const char kSdchFilter[]; +extern const char kSearchInOmniboxHint[]; +extern const char kServiceProcess[]; +extern const char kServiceAccountLsid[]; +extern const char kShowCompositedLayerBorders[]; +extern const char kShowIcons[]; +extern const char kShowPaintRects[]; +extern const char kShowPrivacyDashboardLink[]; +extern const char kSilentDumpOnDCHECK[]; +extern const char kSimpleDataSource[]; +extern const char kSingleProcess[]; +extern const char kStartMaximized[]; +extern const char kSyncAllowPlain[]; +extern const char kSyncDisableTls[]; +extern const char kSyncEmail[]; +extern const char kSyncerThreadTimedStop[]; +extern const char kSyncNotificationMethod[]; +extern const char kSyncPassword[]; +extern const char kSyncPort[]; +extern const char kSyncServer[]; +extern const char kSyncServiceURL[]; +extern const char kSyncUseChromeAsyncSocket[]; +extern const char kSyncUseSslTcp[]; +extern const char kSyncUseCacheInvalidation[]; +extern const char kTestNaClSandbox[]; +extern const char kTestName[]; +extern const char kTestSandbox[]; +extern const char kTestType[]; +extern const char kTestingChannelID[]; +extern const char kTopSites[]; +extern const char kTrustedPlugins[]; +extern const char kTryChromeAgain[]; +extern const char kUninstall[]; +extern const char kUseSpdy[]; +extern const char kFixedHttpPort[]; +extern const char kFixedHttpsPort[]; +extern const char kIgnoreCertificateErrors[]; +extern const char kMaxSpdySessionsPerDomain[]; +extern const char kUseLowFragHeapCrt[]; +extern const char kUserAgent[]; +extern const char kUserDataDir[]; +extern const char kUserScriptsDir[]; +extern const char kUtilityCmdPrefix[]; +extern const char kUtilityProcess[]; +extern const char kUtilityProcessAllowedDir[]; +extern const char kVersion[]; +extern const char kWaitForDebuggerChildren[]; +extern const char kWebWorkerProcessPerCore[]; +extern const char kWebWorkerShareProcesses[]; +extern const char kWinHttpProxyResolver[]; +extern const char kWorkerProcess[]; +extern const char kZygoteCmdPrefix[]; +extern const char kZygoteProcess[]; + +#if defined(OS_CHROMEOS) +extern const char kEnableGView[]; +extern const char kEnableLoginImages[]; +extern const char kLoginManager[]; +// TODO(avayvod): Remove this flag when it's unnecessary for testing +// purposes. +extern const char kLoginScreen[]; +extern const char kLoginScreenSize[]; +extern const char kTestLoadLibcros[]; +extern const char kProfile[]; +extern const char kLoginProfile[]; +extern const char kLoginUser[]; +extern const char kChromeosFrame[]; +extern const char kChromeosLogToFile[]; +// TODO(denisromanov): Remove this flag when it is not needed for testing. +extern const char kStartupManifest[]; +// TODO(denisromanov): Remove this flag when it is not needed for testing, too. +extern const char kServicesManifest[]; +#endif + +#if defined(OS_LINUX) +extern const char kScrollPixels[]; +#endif + +#if defined(OS_MACOSX) || defined(OS_WIN) +extern const char kUseSystemSSL[]; +#endif + +#if defined(OS_POSIX) +extern const char kEnableCrashReporter[]; +extern const char kNoProcessSingletonDialog[]; +#if !defined(OS_MACOSX) +extern const char kPasswordStore[]; +#endif +#endif + +#if defined(OS_MACOSX) +extern const char kDisableFlashCoreAnimation[]; +extern const char kEnableSandboxLogging[]; +#else +extern const char kKioskMode[]; +#endif + +#ifndef NDEBUG +extern const char kGearsPluginPathOverride[]; +extern const char kInvalidateSyncLogin[]; +extern const char kInvalidateSyncXmppLogin[]; +extern const char kWebSocketLiveExperimentHost[]; +#endif + +#if !defined(OFFICIAL_BUILD) +extern const char kRendererCheckFalseTest[]; +#endif + +#if defined(USE_SECCOMP_SANDBOX) +extern const char kDisableSeccompSandbox[]; +#else +extern const char kEnableSeccompSandbox[]; +#endif +// Return true if the switches indicate the seccomp sandbox is enabled. +bool SeccompSandboxEnabled(); + +// DON'T ADD RANDOM STUFF HERE. Put it in the main section above in +// alphabetical order, or in one of the ifdefs (also in order in each section). + +} // namespace switches + +#endif // CHROME_COMMON_CHROME_SWITCHES_H_ diff --git a/chrome/common/chrome_version_info.cc b/chrome/common/chrome_version_info.cc new file mode 100644 index 0000000..1b1d479 --- /dev/null +++ b/chrome/common/chrome_version_info.cc @@ -0,0 +1,52 @@ +// Copyright (c) 2010 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 "chrome/common/chrome_version_info.h" + +#include "base/basictypes.h" +#include "base/file_version_info.h" +#include "build/build_config.h" + +#if defined(OS_POSIX) && !defined(OS_MACOSX) +#include "chrome/common/chrome_version_info_posix.h" + +// Posix files don't have per-file version information, so we get chrome +// version information from chrome_version_info_posix.h, a generated header. +class ChromeVersionInfoPosix : public FileVersionInfo { + public: + ChromeVersionInfoPosix() {} + + virtual std::wstring company_name() { return COMPANY_NAME; } + virtual std::wstring company_short_name() { return COMPANY_SHORT_NAME; } + virtual std::wstring product_name() { return PRODUCT_NAME; } + virtual std::wstring product_short_name() { return PRODUCT_SHORT_NAME; } + virtual std::wstring internal_name() { return INTERNAL_NAME; } + virtual std::wstring product_version() { return PRODUCT_VERSION; } + virtual std::wstring private_build() { return PRIVATE_BUILD; } + virtual std::wstring special_build() { return SPECIAL_BUILD; } + virtual std::wstring comments() { return COMMENTS; } + virtual std::wstring original_filename() { return ORIGINAL_FILENAME; } + virtual std::wstring file_description() { return FILE_DESCRIPTION; } + virtual std::wstring file_version() { return FILE_VERSION; } + virtual std::wstring legal_copyright() { return LEGAL_COPYRIGHT; } + virtual std::wstring legal_trademarks() { return LEGAL_TRADEMARKS; } + virtual std::wstring last_change() { return LAST_CHANGE; } + virtual bool is_official_build() { return OFFICIAL_BUILD; } + + private: + DISALLOW_COPY_AND_ASSIGN(ChromeVersionInfoPosix); +}; +#endif + +namespace chrome { + +FileVersionInfo* GetChromeVersionInfo() { +#if defined(OS_WIN) || defined(OS_MACOSX) + return FileVersionInfo::CreateFileVersionInfoForCurrentModule(); +#elif defined(OS_POSIX) + return new ChromeVersionInfoPosix(); +#endif +} + +} // namespace chrome diff --git a/chrome/common/chrome_version_info.h b/chrome/common/chrome_version_info.h new file mode 100644 index 0000000..e3bfad7 --- /dev/null +++ b/chrome/common/chrome_version_info.h @@ -0,0 +1,18 @@ +// Copyright (c) 2010 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 CHROME_COMMON_CHROME_VERSION_INFO_H_ +#define CHROME_COMMON_CHROME_VERSION_INFO_H_ + +class FileVersionInfo; + +namespace chrome { + +// Creates a FileVersionInfo for the app, Chrome. Returns NULL in case of +// error. The returned object should be deleted when you are done with it. +FileVersionInfo* GetChromeVersionInfo(); + +} // namespace chrome + +#endif // CHROME_COMMON_CHROME_VERSION_INFO_H_ diff --git a/chrome/common/chrome_version_info_posix.h.version b/chrome/common/chrome_version_info_posix.h.version new file mode 100644 index 0000000..56a8fea --- /dev/null +++ b/chrome/common/chrome_version_info_posix.h.version @@ -0,0 +1,26 @@ +// Copyright (c) 2010 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 CHROME_COMMON_CHROME_VERSION_INFO_POSIX_H_ +#define CHROME_COMMON_CHROME_VERSION_INFO_POSIX_H_ + +#define COMPANY_NAME L"@COMPANY_FULLNAME@" +#define FILE_DESCRIPTION L"@PRODUCT_FULLNAME@" +#define FILE_VERSION L"@MAJOR@.@MINOR@.@BUILD@.@PATCH@" +#define LEGAL_COPYRIGHT L"@COPYRIGHT@" +#define PRODUCT_NAME L"@PRODUCT_FULLNAME@" +#define PRODUCT_VERSION L"@MAJOR@.@MINOR@.@BUILD@.@PATCH@" +#define COMPANY_SHORT_NAME L"@COMPANY_SHORTNAME@" +#define PRODUCT_SHORT_NAME L"@PRODUCT_SHORTNAME@" +#define LAST_CHANGE L"@LASTCHANGE@" +#define OFFICIAL_BUILD @OFFICIAL_BUILD@ +// TODO(mmoss) Do these have values for Linux? +#define INTERNAL_NAME L"" +#define ORIGINAL_FILENAME L"" +#define PRIVATE_BUILD L"" +#define SPECIAL_BUILD L"" +#define COMMENTS L"" +#define LEGAL_TRADEMARKS L"" + +#endif // CHROME_COMMON_CHROME_VERSION_INFO_POSIX_H_ diff --git a/chrome/common/common.sb b/chrome/common/common.sb new file mode 100644 index 0000000..71c73cf --- /dev/null +++ b/chrome/common/common.sb @@ -0,0 +1,33 @@ +;; +;; Copyright (c) 2010 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 configuration file isn't used on it's own, but instead implicity included +; at the start of all other sandbox configuration files in Chrome. +(version 1) +(deny default) + +; Support for programmatically enabling verbose debugging. +;ENABLE_LOGGING (debug deny) + +; Allow sending signals to self - http://crbug.com/20370 +(allow signal (target self)) + +; Needed for full-page-zoomed controls - http://crbug.com/11325 +(allow sysctl-read) + +; Each line is marked with the System version that needs it. +; This profile is tested with the following system versions: +; 10.5.6, 10.6 + +; Allow following symlinks +(allow file-read-metadata) ; 10.5.6 + +; Loading System Libraries. +(allow file-read-data (regex #"^/System/Library/Frameworks($|/)")) ; 10.5.6 +(allow file-read-data (regex #"^/System/Library/PrivateFrameworks($|/)")) ; 10.5.6 +(allow file-read-data (regex #"^/System/Library/CoreServices($|/)")) ; 10.5.6 + +; Needed for IPC on 10.6 +;10.6_ONLY (allow ipc-posix-shm)
\ No newline at end of file diff --git a/chrome/common/common.vsprops b/chrome/common/common.vsprops new file mode 100644 index 0000000..a834391 --- /dev/null +++ b/chrome/common/common.vsprops @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="common (chrome)" + InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\third_party\icu\build\using_icu.vsprops;$(SolutionDir)..\third_party\zlib\using_zlib.vsprops;$(SolutionDir)..\third_party\libpng\using_libpng.vsprops;$(SolutionDir)..\skia\using_skia.vsprops;$(SolutionDir)..\tools\grit\build\using_generated_resources.vsprops;$(SolutionDir)..\third_party\libxml\build\using_libxml.vsprops;$(SolutionDir)..\third_party\npapi\using_npapi.vsprops;$(SolutionDir)..\chrome\third_party\wtl\using_wtl.vsprops;$(SolutionDir)\common\extra_defines.vsprops" + > +</VisualStudioPropertySheet> diff --git a/chrome/common/common_glue.cc b/chrome/common/common_glue.cc new file mode 100644 index 0000000..95417ab --- /dev/null +++ b/chrome/common/common_glue.cc @@ -0,0 +1,49 @@ +// Copyright (c) 2006-2008 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 "app/app_switches.h" +#include "app/l10n_util.h" +#include "base/command_line.h" +#include "base/path_service.h" +#include "base/string16.h" +#include "base/utf_string_conversions.h" +#include "build/build_config.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/plugin/npobject_util.h" +#include "googleurl/src/url_util.h" +#include "webkit/glue/webkit_glue.h" + +namespace webkit_glue { + +bool GetExeDirectory(FilePath* path) { + return PathService::Get(base::DIR_EXE, path); +} + +bool GetApplicationDirectory(FilePath* path) { + return PathService::Get(chrome::DIR_APP, path); +} + +bool IsPluginRunningInRendererProcess() { + return !IsPluginProcess(); +} + +std::wstring GetWebKitLocale() { + // The browser process should have passed the locale to the renderer via the + // --lang command line flag. In single process mode, this will return the + // wrong value. TODO(tc): Fix this for single process mode. + const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); + const std::wstring& lang = + parsed_command_line.GetSwitchValue(switches::kLang); + DCHECK(!lang.empty() || + (!parsed_command_line.HasSwitch(switches::kRendererProcess) && + !parsed_command_line.HasSwitch(switches::kPluginProcess))); + return lang; +} + +string16 GetLocalizedString(int message_id) { + return WideToUTF16(l10n_util::GetString(message_id)); +} + +} // namespace webkit_glue diff --git a/chrome/common/common_param_traits.cc b/chrome/common/common_param_traits.cc new file mode 100644 index 0000000..e655435 --- /dev/null +++ b/chrome/common/common_param_traits.cc @@ -0,0 +1,458 @@ +// Copyright (c) 2010 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 "chrome/common/common_param_traits.h" + +#include "chrome/common/chrome_constants.h" +#include "chrome/common/content_settings.h" +#include "chrome/common/thumbnail_score.h" +#include "gfx/rect.h" +#include "googleurl/src/gurl.h" +#include "printing/native_metafile.h" +#include "printing/page_range.h" + +#ifndef EXCLUDE_SKIA_DEPENDENCIES +#include "third_party/skia/include/core/SkBitmap.h" +#endif +#include "webkit/glue/dom_operations.h" +#include "webkit/glue/password_form.h" + +namespace IPC { + +#ifndef EXCLUDE_SKIA_DEPENDENCIES + +namespace { + +struct SkBitmap_Data { + // The configuration for the bitmap (bits per pixel, etc). + SkBitmap::Config fConfig; + + // The width of the bitmap in pixels. + uint32 fWidth; + + // The height of the bitmap in pixels. + uint32 fHeight; + + void InitSkBitmapDataForTransfer(const SkBitmap& bitmap) { + fConfig = bitmap.config(); + fWidth = bitmap.width(); + fHeight = bitmap.height(); + } + + // Returns whether |bitmap| successfully initialized. + bool InitSkBitmapFromData(SkBitmap* bitmap, const char* pixels, + size_t total_pixels) const { + if (total_pixels) { + bitmap->setConfig(fConfig, fWidth, fHeight, 0); + if (!bitmap->allocPixels()) + return false; + if (total_pixels != bitmap->getSize()) + return false; + memcpy(bitmap->getPixels(), pixels, total_pixels); + } + return true; + } +}; + +} // namespace + + +void ParamTraits<SkBitmap>::Write(Message* m, const SkBitmap& p) { + size_t fixed_size = sizeof(SkBitmap_Data); + SkBitmap_Data bmp_data; + bmp_data.InitSkBitmapDataForTransfer(p); + m->WriteData(reinterpret_cast<const char*>(&bmp_data), + static_cast<int>(fixed_size)); + size_t pixel_size = p.getSize(); + SkAutoLockPixels p_lock(p); + m->WriteData(reinterpret_cast<const char*>(p.getPixels()), + static_cast<int>(pixel_size)); +} + +bool ParamTraits<SkBitmap>::Read(const Message* m, void** iter, SkBitmap* r) { + const char* fixed_data; + int fixed_data_size = 0; + if (!m->ReadData(iter, &fixed_data, &fixed_data_size) || + (fixed_data_size <= 0)) { + NOTREACHED(); + return false; + } + if (fixed_data_size != sizeof(SkBitmap_Data)) + return false; // Message is malformed. + + const char* variable_data; + int variable_data_size = 0; + if (!m->ReadData(iter, &variable_data, &variable_data_size) || + (variable_data_size < 0)) { + NOTREACHED(); + return false; + } + const SkBitmap_Data* bmp_data = + reinterpret_cast<const SkBitmap_Data*>(fixed_data); + return bmp_data->InitSkBitmapFromData(r, variable_data, variable_data_size); +} + +void ParamTraits<SkBitmap>::Log(const SkBitmap& p, std::wstring* l) { + l->append(StringPrintf(L"<SkBitmap>")); +} + +#endif // EXCLUDE_SKIA_DEPENDENCIES + +void ParamTraits<GURL>::Write(Message* m, const GURL& p) { + m->WriteString(p.possibly_invalid_spec()); + // TODO(brettw) bug 684583: Add encoding for query params. +} + +bool ParamTraits<GURL>::Read(const Message* m, void** iter, GURL* p) { + std::string s; + if (!m->ReadString(iter, &s) || s.length() > chrome::kMaxURLChars) { + *p = GURL(); + return false; + } + *p = GURL(s); + return true; +} + +void ParamTraits<GURL>::Log(const GURL& p, std::wstring* l) { + l->append(UTF8ToWide(p.spec())); +} + +void ParamTraits<gfx::Point>::Write(Message* m, const gfx::Point& p) { + m->WriteInt(p.x()); + m->WriteInt(p.y()); +} + +bool ParamTraits<gfx::Point>::Read(const Message* m, void** iter, + gfx::Point* r) { + int x, y; + if (!m->ReadInt(iter, &x) || + !m->ReadInt(iter, &y)) + return false; + r->set_x(x); + r->set_y(y); + return true; +} + +void ParamTraits<gfx::Point>::Log(const gfx::Point& p, std::wstring* l) { + l->append(StringPrintf(L"(%d, %d)", p.x(), p.y())); +} + + +void ParamTraits<gfx::Rect>::Write(Message* m, const gfx::Rect& p) { + m->WriteInt(p.x()); + m->WriteInt(p.y()); + m->WriteInt(p.width()); + m->WriteInt(p.height()); +} + +bool ParamTraits<gfx::Rect>::Read(const Message* m, void** iter, gfx::Rect* r) { + int x, y, w, h; + if (!m->ReadInt(iter, &x) || + !m->ReadInt(iter, &y) || + !m->ReadInt(iter, &w) || + !m->ReadInt(iter, &h)) + return false; + r->set_x(x); + r->set_y(y); + r->set_width(w); + r->set_height(h); + return true; +} + +void ParamTraits<gfx::Rect>::Log(const gfx::Rect& p, std::wstring* l) { + l->append(StringPrintf(L"(%d, %d, %d, %d)", p.x(), p.y(), + p.width(), p.height())); +} + + +void ParamTraits<gfx::Size>::Write(Message* m, const gfx::Size& p) { + m->WriteInt(p.width()); + m->WriteInt(p.height()); +} + +bool ParamTraits<gfx::Size>::Read(const Message* m, void** iter, gfx::Size* r) { + int w, h; + if (!m->ReadInt(iter, &w) || + !m->ReadInt(iter, &h)) + return false; + r->set_width(w); + r->set_height(h); + return true; +} + +void ParamTraits<gfx::Size>::Log(const gfx::Size& p, std::wstring* l) { + l->append(StringPrintf(L"(%d, %d)", p.width(), p.height())); +} + +void ParamTraits<ContentSetting>::Write(Message* m, const param_type& p) { + WriteParam(m, static_cast<int>(p)); +} + +bool ParamTraits<ContentSetting>::Read(const Message* m, void** iter, + param_type* r) { + int value; + if (!ReadParam(m, iter, &value)) + return false; + if (value < 0 || value >= static_cast<int>(CONTENT_SETTING_NUM_SETTINGS)) + return false; + *r = static_cast<param_type>(value); + return true; +} + +void ParamTraits<ContentSetting>::Log(const param_type& p, std::wstring* l) { + LogParam(static_cast<int>(p), l); +} + +void ParamTraits<ContentSettings>::Write( + Message* m, const ContentSettings& settings) { + for (size_t i = 0; i < arraysize(settings.settings); ++i) + WriteParam(m, settings.settings[i]); +} + +bool ParamTraits<ContentSettings>::Read( + const Message* m, void** iter, ContentSettings* r) { + for (size_t i = 0; i < arraysize(r->settings); ++i) { + if (!ReadParam(m, iter, &r->settings[i])) + return false; + } + return true; +} + +void ParamTraits<ContentSettings>::Log( + const ContentSettings& p, std::wstring* l) { + l->append(StringPrintf(L"<ContentSettings>")); +} + +void ParamTraits<webkit_glue::WebApplicationInfo>::Write( + Message* m, const webkit_glue::WebApplicationInfo& p) { + WriteParam(m, p.title); + WriteParam(m, p.description); + WriteParam(m, p.app_url); + WriteParam(m, p.icons.size()); + for (size_t i = 0; i < p.icons.size(); ++i) { + WriteParam(m, p.icons[i].url); + WriteParam(m, p.icons[i].width); + WriteParam(m, p.icons[i].height); + } +} + +bool ParamTraits<webkit_glue::WebApplicationInfo>::Read( + const Message* m, void** iter, webkit_glue::WebApplicationInfo* r) { + size_t icon_count; + bool result = + ReadParam(m, iter, &r->title) && + ReadParam(m, iter, &r->description) && + ReadParam(m, iter, &r->app_url) && + ReadParam(m, iter, &icon_count); + if (!result) + return false; + for (size_t i = 0; i < icon_count; ++i) { + param_type::IconInfo icon_info; + result = + ReadParam(m, iter, &icon_info.url) && + ReadParam(m, iter, &icon_info.width) && + ReadParam(m, iter, &icon_info.height); + if (!result) + return false; + r->icons.push_back(icon_info); + } + return true; +} + +void ParamTraits<webkit_glue::WebApplicationInfo>::Log( + const webkit_glue::WebApplicationInfo& p, std::wstring* l) { + l->append(L"<WebApplicationInfo>"); +} + +void ParamTraits<URLRequestStatus>::Write(Message* m, const param_type& p) { + WriteParam(m, static_cast<int>(p.status())); + WriteParam(m, p.os_error()); +} + +bool ParamTraits<URLRequestStatus>::Read(const Message* m, void** iter, + param_type* r) { + int status, os_error; + if (!ReadParam(m, iter, &status) || + !ReadParam(m, iter, &os_error)) + return false; + r->set_status(static_cast<URLRequestStatus::Status>(status)); + r->set_os_error(os_error); + return true; +} + +void ParamTraits<URLRequestStatus>::Log(const param_type& p, std::wstring* l) { + std::wstring status; + switch (p.status()) { + case URLRequestStatus::SUCCESS: + status = L"SUCCESS"; + break; + case URLRequestStatus::IO_PENDING: + status = L"IO_PENDING "; + break; + case URLRequestStatus::HANDLED_EXTERNALLY: + status = L"HANDLED_EXTERNALLY"; + break; + case URLRequestStatus::CANCELED: + status = L"CANCELED"; + break; + case URLRequestStatus::FAILED: + status = L"FAILED"; + break; + default: + status = L"UNKNOWN"; + break; + } + if (p.status() == URLRequestStatus::FAILED) + l->append(L"("); + + LogParam(status, l); + + if (p.status() == URLRequestStatus::FAILED) { + l->append(L", "); + LogParam(p.os_error(), l); + l->append(L")"); + } +} + +void ParamTraits<ThumbnailScore>::Write(Message* m, const param_type& p) { + IPC::ParamTraits<double>::Write(m, p.boring_score); + IPC::ParamTraits<bool>::Write(m, p.good_clipping); + IPC::ParamTraits<bool>::Write(m, p.at_top); + IPC::ParamTraits<base::Time>::Write(m, p.time_at_snapshot); +} + +bool ParamTraits<ThumbnailScore>::Read(const Message* m, void** iter, + param_type* r) { + double boring_score; + bool good_clipping, at_top; + base::Time time_at_snapshot; + if (!IPC::ParamTraits<double>::Read(m, iter, &boring_score) || + !IPC::ParamTraits<bool>::Read(m, iter, &good_clipping) || + !IPC::ParamTraits<bool>::Read(m, iter, &at_top) || + !IPC::ParamTraits<base::Time>::Read(m, iter, &time_at_snapshot)) + return false; + + r->boring_score = boring_score; + r->good_clipping = good_clipping; + r->at_top = at_top; + r->time_at_snapshot = time_at_snapshot; + return true; +} + +void ParamTraits<ThumbnailScore>::Log(const param_type& p, std::wstring* l) { + l->append(StringPrintf(L"(%f, %d, %d)", + p.boring_score, p.good_clipping, p.at_top)); +} + +void ParamTraits<Geoposition::ErrorCode>::Write( + Message* m, const Geoposition::ErrorCode& p) { + int error_code = p; + WriteParam(m, error_code); +} + +bool ParamTraits<Geoposition::ErrorCode>::Read( + const Message* m, void** iter, Geoposition::ErrorCode* p) { + int error_code_param = 0; + bool ret = ReadParam(m, iter, &error_code_param); + *p = static_cast<Geoposition::ErrorCode>(error_code_param); + return ret; +} + +void ParamTraits<Geoposition::ErrorCode>::Log( + const Geoposition::ErrorCode& p, std::wstring* l) { + int error_code = p; + l->append(StringPrintf(L"<Geoposition::ErrorCode>%d", error_code)); +} + +void ParamTraits<Geoposition>::Write(Message* m, const Geoposition& p) { + WriteParam(m, p.latitude); + WriteParam(m, p.longitude); + WriteParam(m, p.accuracy); + WriteParam(m, p.altitude); + WriteParam(m, p.altitude_accuracy); + WriteParam(m, p.speed); + WriteParam(m, p.heading); + WriteParam(m, p.timestamp); + WriteParam(m, p.error_code); + WriteParam(m, p.error_message); +} + +bool ParamTraits<Geoposition>::Read( + const Message* m, void** iter, Geoposition* p) { + bool ret = ReadParam(m, iter, &p->latitude); + ret = ret && ReadParam(m, iter, &p->longitude); + ret = ret && ReadParam(m, iter, &p->accuracy); + ret = ret && ReadParam(m, iter, &p->altitude); + ret = ret && ReadParam(m, iter, &p->altitude_accuracy); + ret = ret && ReadParam(m, iter, &p->speed); + ret = ret && ReadParam(m, iter, &p->heading); + ret = ret && ReadParam(m, iter, &p->timestamp); + ret = ret && ReadParam(m, iter, &p->error_code); + ret = ret && ReadParam(m, iter, &p->error_message); + return ret; +} + +void ParamTraits<Geoposition>::Log(const Geoposition& p, std::wstring* l) { + l->append( + StringPrintf( + L"<Geoposition>" + L"%.6f %.6f %.6f %.6f " + L"%.6f %.6f %.6f ", + p.latitude, p.longitude, p.accuracy, p.altitude, + p.altitude_accuracy, p.speed, p.heading)); + LogParam(p.timestamp, l); + l->append(L" "); + l->append(UTF8ToWide(p.error_message)); + LogParam(p.error_code, l); +} + +void ParamTraits<printing::PageRange>::Write(Message* m, const param_type& p) { + WriteParam(m, p.from); + WriteParam(m, p.to); +} + +bool ParamTraits<printing::PageRange>::Read( + const Message* m, void** iter, param_type* p) { + return ReadParam(m, iter, &p->from) && + ReadParam(m, iter, &p->to); +} + +void ParamTraits<printing::PageRange>::Log( + const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.to, l); + l->append(L", "); + LogParam(p.from, l); + l->append(L")"); +} + +void ParamTraits<printing::NativeMetafile>::Write( + Message* m, const param_type& p) { + std::vector<uint8> buffer; + uint32 size = p.GetDataSize(); + if (size) { + buffer.resize(size); + p.GetData(&buffer.front(), size); + } + WriteParam(m, buffer); +} + +bool ParamTraits<printing::NativeMetafile>::Read( + const Message* m, void** iter, param_type* p) { + std::vector<uint8> buffer; +#if defined(OS_WIN) + return ReadParam(m, iter, &buffer) && + p->CreateFromData(&buffer.front(), static_cast<uint32>(buffer.size())); +#else // defined(OS_WIN) + return ReadParam(m, iter, &buffer) && + p->Init(&buffer.front(), static_cast<uint32>(buffer.size())); +#endif // defined(OS_WIN) +} + +void ParamTraits<printing::NativeMetafile>::Log( + const param_type& p, std::wstring* l) { + l->append(StringPrintf(L"<printing::NativeMetafile>")); +} + +} // namespace IPC diff --git a/chrome/common/common_param_traits.h b/chrome/common/common_param_traits.h new file mode 100644 index 0000000..b4ec78e --- /dev/null +++ b/chrome/common/common_param_traits.h @@ -0,0 +1,428 @@ +// Copyright (c) 2010 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 shared by more than one child process. + +#ifndef CHROME_COMMON_COMMON_PARAM_TRAITS_H_ +#define CHROME_COMMON_COMMON_PARAM_TRAITS_H_ + +#include <vector> + +#include "app/surface/transport_dib.h" +#include "chrome/common/content_settings.h" +#include "chrome/common/geoposition.h" +#include "chrome/common/page_zoom.h" +#include "gfx/native_widget_types.h" +#include "ipc/ipc_message_utils.h" +#include "net/base/upload_data.h" +#include "net/url_request/url_request_status.h" +#include "printing/native_metafile.h" +#include "webkit/glue/password_form.h" +#include "webkit/glue/webcursor.h" +#include "webkit/glue/window_open_disposition.h" + +// Forward declarations. +class GURL; +class SkBitmap; +class DictionaryValue; +class ListValue; +struct ThumbnailScore; +class URLRequestStatus; + +namespace gfx { +class Point; +class Rect; +class Size; +} // namespace gfx + +namespace printing { +struct PageRange; +} // namespace printing + +namespace webkit_glue { +struct PasswordForm; +struct WebApplicationInfo; +} // namespace webkit_glue + +namespace IPC { + +template <> +struct ParamTraits<SkBitmap> { + typedef SkBitmap param_type; + static void Write(Message* m, const param_type& p); + + // Note: This function expects parameter |r| to be of type &SkBitmap since + // r->SetConfig() and r->SetPixels() are called. + static bool Read(const Message* m, void** iter, param_type* r); + + static void Log(const param_type& p, std::wstring* l); +}; + + +template <> +struct ParamTraits<GURL> { + typedef GURL param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, void** iter, param_type* p); + static void Log(const param_type& p, std::wstring* l); +}; + + +template <> +struct ParamTraits<gfx::Point> { + typedef gfx::Point param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, void** iter, param_type* r); + static void Log(const param_type& p, std::wstring* l); +}; + +template <> +struct ParamTraits<gfx::Rect> { + typedef gfx::Rect param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, void** iter, param_type* r); + static void Log(const param_type& p, std::wstring* l); +}; + +template <> +struct ParamTraits<gfx::Size> { + typedef gfx::Size param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, void** iter, param_type* r); + static void Log(const param_type& p, std::wstring* l); +}; + +template <> +struct ParamTraits<ContentSetting> { + typedef ContentSetting param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, void** iter, param_type* r); + static void Log(const param_type& p, std::wstring* l); +}; + +template <> +struct ParamTraits<ContentSettingsType> { + typedef ContentSettingsType param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, static_cast<int>(p)); + } + static bool Read(const Message* m, void** iter, param_type* r) { + int value; + if (!ReadParam(m, iter, &value)) + return false; + if (value < 0 || value >= static_cast<int>(CONTENT_SETTINGS_NUM_TYPES)) + return false; + *r = static_cast<param_type>(value); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + LogParam(static_cast<int>(p), l); + } +}; + +template <> +struct ParamTraits<ContentSettings> { + typedef ContentSettings param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, void** iter, param_type* r); + static void Log(const param_type& p, std::wstring* l); +}; + +template <> +struct ParamTraits<gfx::NativeWindow> { + typedef gfx::NativeWindow param_type; + static void Write(Message* m, const param_type& p) { +#if defined(OS_WIN) + // HWNDs are always 32 bits on Windows, even on 64 bit systems. + m->WriteUInt32(reinterpret_cast<uint32>(p)); +#else + m->WriteData(reinterpret_cast<const char*>(&p), sizeof(p)); +#endif + } + static bool Read(const Message* m, void** iter, param_type* r) { +#if defined(OS_WIN) + return m->ReadUInt32(iter, reinterpret_cast<uint32*>(r)); +#else + const char *data; + int data_size = 0; + bool result = m->ReadData(iter, &data, &data_size); + if (result && data_size == sizeof(gfx::NativeWindow)) { + memcpy(r, data, sizeof(gfx::NativeWindow)); + } else { + result = false; + NOTREACHED(); + } + return result; +#endif + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<gfx::NativeWindow>"); + } +}; + +template <> +struct ParamTraits<PageZoom::Function> { + typedef PageZoom::Function param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, static_cast<int>(p)); + } + static bool Read(const Message* m, void** iter, param_type* r) { + int value; + if (!ReadParam(m, iter, &value)) + return false; + *r = static_cast<param_type>(value); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + LogParam(static_cast<int>(p), l); + } +}; + + +template <> +struct ParamTraits<WindowOpenDisposition> { + typedef WindowOpenDisposition param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, static_cast<int>(p)); + } + static bool Read(const Message* m, void** iter, param_type* r) { + int value; + if (!ReadParam(m, iter, &value)) + return false; + *r = static_cast<param_type>(value); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + LogParam(static_cast<int>(p), l); + } +}; + + +template <> +struct ParamTraits<WebCursor> { + typedef WebCursor param_type; + static void Write(Message* m, const param_type& p) { + p.Serialize(m); + } + static bool Read(const Message* m, void** iter, param_type* r) { + return r->Deserialize(m, iter); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<WebCursor>"); + } +}; + + +template <> +struct ParamTraits<webkit_glue::WebApplicationInfo> { + typedef webkit_glue::WebApplicationInfo param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, void** iter, param_type* r); + static void Log(const param_type& p, std::wstring* l); +}; + + +#if defined(OS_WIN) +template<> +struct ParamTraits<TransportDIB::Id> { + typedef TransportDIB::Id param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.handle); + WriteParam(m, p.sequence_num); + } + static bool Read(const Message* m, void** iter, param_type* r) { + return (ReadParam(m, iter, &r->handle) && + ReadParam(m, iter, &r->sequence_num)); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"TransportDIB("); + LogParam(p.handle, l); + l->append(L", "); + LogParam(p.sequence_num, l); + l->append(L")"); + } +}; +#endif + +// Traits for URLRequestStatus +template <> +struct ParamTraits<URLRequestStatus> { + typedef URLRequestStatus param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, void** iter, param_type* r); + static void Log(const param_type& p, std::wstring* l); +}; + + +// Traits for net::UploadData::Element. +template <> +struct ParamTraits<net::UploadData::Element> { + typedef net::UploadData::Element param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, static_cast<int>(p.type())); + if (p.type() == net::UploadData::TYPE_BYTES) { + m->WriteData(&p.bytes()[0], static_cast<int>(p.bytes().size())); + } else { + WriteParam(m, p.file_path()); + WriteParam(m, p.file_range_offset()); + WriteParam(m, p.file_range_length()); + WriteParam(m, p.expected_file_modification_time()); + } + } + static bool Read(const Message* m, void** iter, param_type* r) { + int type; + if (!ReadParam(m, iter, &type)) + return false; + if (type == net::UploadData::TYPE_BYTES) { + const char* data; + int len; + if (!m->ReadData(iter, &data, &len)) + return false; + r->SetToBytes(data, len); + } else { + DCHECK(type == net::UploadData::TYPE_FILE); + FilePath file_path; + uint64 offset, length; + base::Time expected_modification_time; + if (!ReadParam(m, iter, &file_path)) + return false; + if (!ReadParam(m, iter, &offset)) + return false; + if (!ReadParam(m, iter, &length)) + return false; + if (!ReadParam(m, iter, &expected_modification_time)) + return false; + r->SetToFilePathRange(file_path, offset, length, + expected_modification_time); + } + return true; + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<net::UploadData::Element>"); + } +}; + +// Traits for net::UploadData. +template <> +struct ParamTraits<scoped_refptr<net::UploadData> > { + typedef scoped_refptr<net::UploadData> param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.get() != NULL); + if (p) { + WriteParam(m, *p->elements()); + WriteParam(m, p->identifier()); + } + } + static bool Read(const Message* m, void** iter, param_type* r) { + bool has_object; + if (!ReadParam(m, iter, &has_object)) + return false; + if (!has_object) + return true; + std::vector<net::UploadData::Element> elements; + if (!ReadParam(m, iter, &elements)) + return false; + int64 identifier; + if (!ReadParam(m, iter, &identifier)) + return false; + *r = new net::UploadData; + (*r)->swap_elements(&elements); + (*r)->set_identifier(identifier); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<net::UploadData>"); + } +}; + +template<> +struct ParamTraits<ThumbnailScore> { + typedef ThumbnailScore param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, void** iter, param_type* r); + static void Log(const param_type& p, std::wstring* l); +}; + +template <> +struct ParamTraits<Geoposition> { + typedef Geoposition param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, void** iter, param_type* p); + static void Log(const param_type& p, std::wstring* l); +}; + +template <> +struct ParamTraits<Geoposition::ErrorCode> { + typedef Geoposition::ErrorCode param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, void** iter, param_type* p); + static void Log(const param_type& p, std::wstring* l); +}; + +template <> +struct ParamTraits<webkit_glue::PasswordForm> { + typedef webkit_glue::PasswordForm param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.signon_realm); + WriteParam(m, p.origin); + WriteParam(m, p.action); + WriteParam(m, p.submit_element); + WriteParam(m, p.username_element); + WriteParam(m, p.username_value); + WriteParam(m, p.password_element); + WriteParam(m, p.password_value); + WriteParam(m, p.old_password_element); + WriteParam(m, p.old_password_value); + WriteParam(m, p.ssl_valid); + WriteParam(m, p.preferred); + WriteParam(m, p.blacklisted_by_user); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->signon_realm) && + ReadParam(m, iter, &p->origin) && + ReadParam(m, iter, &p->action) && + ReadParam(m, iter, &p->submit_element) && + ReadParam(m, iter, &p->username_element) && + ReadParam(m, iter, &p->username_value) && + ReadParam(m, iter, &p->password_element) && + ReadParam(m, iter, &p->password_value) && + ReadParam(m, iter, &p->old_password_element) && + ReadParam(m, iter, &p->old_password_value) && + ReadParam(m, iter, &p->ssl_valid) && + ReadParam(m, iter, &p->preferred) && + ReadParam(m, iter, &p->blacklisted_by_user); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<PasswordForm>"); + } +}; + +template <> +struct ParamTraits<printing::PageRange> { + typedef printing::PageRange param_type; + static void Write(Message* m, const param_type& p); + + static bool Read(const Message* m, void** iter, param_type* r); + + static void Log(const param_type& p, std::wstring* l); +}; + +template <> +struct ParamTraits<printing::NativeMetafile> { + typedef printing::NativeMetafile param_type; + static void Write(Message* m, const param_type& p); + + static bool Read(const Message* m, void** iter, param_type* r); + + static void Log(const param_type& p, std::wstring* l); +}; + +} // namespace IPC + +#endif // CHROME_COMMON_COMMON_PARAM_TRAITS_H_ diff --git a/chrome/common/common_param_traits_unittest.cc b/chrome/common/common_param_traits_unittest.cc new file mode 100644 index 0000000..032f471 --- /dev/null +++ b/chrome/common/common_param_traits_unittest.cc @@ -0,0 +1,279 @@ +// Copyright (c) 2006-2008 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 <string.h> +#include <utility> + +#include "base/scoped_ptr.h" +#include "base/values.h" +#include "chrome/common/common_param_traits.h" +#include "gfx/rect.h" +#include "googleurl/src/gurl.h" +#include "ipc/ipc_message.h" +#include "ipc/ipc_message_utils.h" +#include "printing/native_metafile.h" +#include "printing/page_range.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkBitmap.h" + +#ifndef NDEBUG +namespace { +void IgnoreAssertHandler(const std::string& str) { +} +} // namespace + +#endif // NDEBUG + +// Tests that serialize/deserialize correctly understand each other +TEST(IPCMessageTest, Serialize) { + const char* serialize_cases[] = { + "http://www.google.com/", + "http://user:pass@host.com:888/foo;bar?baz#nop", + "#inva://idurl/", + }; + + for (size_t i = 0; i < arraysize(serialize_cases); i++) { + GURL input(serialize_cases[i]); + IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); + IPC::ParamTraits<GURL>::Write(&msg, input); + + GURL output; + void* iter = NULL; + EXPECT_TRUE(IPC::ParamTraits<GURL>::Read(&msg, &iter, &output)); + + // We want to test each component individually to make sure its range was + // correctly serialized and deserialized, not just the spec. + EXPECT_EQ(input.possibly_invalid_spec(), output.possibly_invalid_spec()); + EXPECT_EQ(input.is_valid(), output.is_valid()); + EXPECT_EQ(input.scheme(), output.scheme()); + EXPECT_EQ(input.username(), output.username()); + EXPECT_EQ(input.password(), output.password()); + EXPECT_EQ(input.host(), output.host()); + EXPECT_EQ(input.port(), output.port()); + EXPECT_EQ(input.path(), output.path()); + EXPECT_EQ(input.query(), output.query()); + EXPECT_EQ(input.ref(), output.ref()); + } + + // Also test the corrupt case. + IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); + msg.WriteInt(99); + GURL output; + void* iter = NULL; + EXPECT_FALSE(IPC::ParamTraits<GURL>::Read(&msg, &iter, &output)); +} + +// Tests std::pair serialization +TEST(IPCMessageTest, Pair) { + typedef std::pair<std::string, std::string> TestPair; + + TestPair input("foo", "bar"); + IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); + IPC::ParamTraits<TestPair>::Write(&msg, input); + + TestPair output; + void* iter = NULL; + EXPECT_TRUE(IPC::ParamTraits<TestPair>::Read(&msg, &iter, &output)); + EXPECT_EQ(output.first, "foo"); + EXPECT_EQ(output.second, "bar"); + +} + +// Tests bitmap serialization. +TEST(IPCMessageTest, Bitmap) { + SkBitmap bitmap; + + bitmap.setConfig(SkBitmap::kARGB_8888_Config, 10, 5); + bitmap.allocPixels(); + memset(bitmap.getPixels(), 'A', bitmap.getSize()); + + IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); + IPC::ParamTraits<SkBitmap>::Write(&msg, bitmap); + + SkBitmap output; + void* iter = NULL; + EXPECT_TRUE(IPC::ParamTraits<SkBitmap>::Read(&msg, &iter, &output)); + + EXPECT_EQ(bitmap.config(), output.config()); + EXPECT_EQ(bitmap.width(), output.width()); + EXPECT_EQ(bitmap.height(), output.height()); + EXPECT_EQ(bitmap.rowBytes(), output.rowBytes()); + EXPECT_EQ(bitmap.getSize(), output.getSize()); + EXPECT_EQ(memcmp(bitmap.getPixels(), output.getPixels(), bitmap.getSize()), + 0); + + // Also test the corrupt case. + IPC::Message bad_msg(1, 2, IPC::Message::PRIORITY_NORMAL); + // Copy the first message block over to |bad_msg|. + const char* fixed_data; + int fixed_data_size; + iter = NULL; + msg.ReadData(&iter, &fixed_data, &fixed_data_size); + bad_msg.WriteData(fixed_data, fixed_data_size); + // Add some bogus pixel data. + const size_t bogus_pixels_size = bitmap.getSize() * 2; + scoped_array<char> bogus_pixels(new char[bogus_pixels_size]); + memset(bogus_pixels.get(), 'B', bogus_pixels_size); + bad_msg.WriteData(bogus_pixels.get(), bogus_pixels_size); + // Make sure we don't read out the bitmap! + SkBitmap bad_output; + iter = NULL; + EXPECT_FALSE(IPC::ParamTraits<SkBitmap>::Read(&bad_msg, &iter, &bad_output)); +} + +TEST(IPCMessageTest, ListValue) { + ListValue input; + input.Set(0, Value::CreateRealValue(42.42)); + input.Set(1, Value::CreateStringValue("forty")); + input.Set(2, Value::CreateNullValue()); + + IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); + IPC::WriteParam(&msg, input); + + ListValue output; + void* iter = NULL; + EXPECT_TRUE(IPC::ReadParam(&msg, &iter, &output)); + + EXPECT_TRUE(input.Equals(&output)); + + // Also test the corrupt case. + IPC::Message bad_msg(1, 2, IPC::Message::PRIORITY_NORMAL); + bad_msg.WriteInt(99); + iter = NULL; + EXPECT_FALSE(IPC::ReadParam(&bad_msg, &iter, &output)); +} + +TEST(IPCMessageTest, DictionaryValue) { + DictionaryValue input; + input.Set(L"null", Value::CreateNullValue()); + input.Set(L"bool", Value::CreateBooleanValue(true)); + input.Set(L"int", Value::CreateIntegerValue(42)); + + scoped_ptr<DictionaryValue> subdict(new DictionaryValue()); + subdict->Set(L"str", Value::CreateStringValue("forty two")); + subdict->Set(L"bool", Value::CreateBooleanValue(false)); + + scoped_ptr<ListValue> sublist(new ListValue()); + sublist->Set(0, Value::CreateRealValue(42.42)); + sublist->Set(1, Value::CreateStringValue("forty")); + sublist->Set(2, Value::CreateStringValue("two")); + subdict->Set(L"list", sublist.release()); + + input.Set(L"dict", subdict.release()); + + IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); + IPC::WriteParam(&msg, input); + + DictionaryValue output; + void* iter = NULL; + EXPECT_TRUE(IPC::ReadParam(&msg, &iter, &output)); + + EXPECT_TRUE(input.Equals(&output)); + + // Also test the corrupt case. + IPC::Message bad_msg(1, 2, IPC::Message::PRIORITY_NORMAL); + bad_msg.WriteInt(99); + iter = NULL; + EXPECT_FALSE(IPC::ReadParam(&bad_msg, &iter, &output)); +} + +TEST(IPCMessageTest, Geoposition) { + Geoposition input; + input.latitude = 0.1; + input.longitude = 51.3; + input.accuracy = 13.7; + input.altitude = 42.24; + input.altitude_accuracy = 9.3; + input.speed = 55; + input.heading = 120; + input.timestamp = base::Time::FromInternalValue(1977); + input.error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE; + input.error_message = "unittest error message for geoposition"; + + IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); + IPC::WriteParam(&msg, input); + + Geoposition output; + void* iter = NULL; + EXPECT_TRUE(IPC::ReadParam(&msg, &iter, &output)); + EXPECT_EQ(input.altitude, output.altitude); + EXPECT_EQ(input.altitude_accuracy, output.altitude_accuracy); + EXPECT_EQ(input.latitude, output.latitude); + EXPECT_EQ(input.longitude, output.longitude); + EXPECT_EQ(input.accuracy, output.accuracy); + EXPECT_EQ(input.heading, output.heading); + EXPECT_EQ(input.speed, output.speed); + EXPECT_EQ(input.error_code, output.error_code); + EXPECT_EQ(input.error_message, output.error_message); + + std::wstring log_message; + IPC::LogParam(output, &log_message); + EXPECT_STREQ(L"<Geoposition>" + L"0.100000 51.300000 13.700000 42.240000 " + L"9.300000 55.000000 120.000000 " + L"1977 unittest error message for geoposition" + L"<Geoposition::ErrorCode>2", + log_message.c_str()); +} + +// Tests printing::PageRange serialization +TEST(IPCMessageTest, PageRange) { + printing::PageRange input; + input.from = 2; + input.to = 45; + IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); + IPC::ParamTraits<printing::PageRange>::Write(&msg, input); + + printing::PageRange output; + void* iter = NULL; + EXPECT_TRUE(IPC::ParamTraits<printing::PageRange>::Read( + &msg, &iter, &output)); + EXPECT_TRUE(input == output); +} + +// Tests printing::NativeMetafile serialization. +TEST(IPCMessageTest, Metafile) { + // TODO(sanjeevr): Make this test meaningful for non-Windows platforms. We + // need to initialize the metafile using alternate means on the other OSes. +#if defined(OS_WIN) + printing::NativeMetafile metafile; + RECT test_rect = {0, 0, 100, 100}; + // Create a metsfile using the screen DC as a reference. + metafile.CreateDc(NULL, NULL); + metafile.CloseDc(); + + IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); + IPC::ParamTraits<printing::NativeMetafile>::Write(&msg, metafile); + + printing::NativeMetafile output; + void* iter = NULL; + EXPECT_TRUE(IPC::ParamTraits<printing::NativeMetafile>::Read( + &msg, &iter, &output)); + + EXPECT_EQ(metafile.GetDataSize(), output.GetDataSize()); + EXPECT_EQ(metafile.GetBounds(), output.GetBounds()); + EXPECT_EQ(::GetDeviceCaps(metafile.hdc(), LOGPIXELSX), + ::GetDeviceCaps(output.hdc(), LOGPIXELSX)); + + // Also test the corrupt case. + IPC::Message bad_msg(1, 2, IPC::Message::PRIORITY_NORMAL); + // Write some bogus metafile data. + const size_t bogus_data_size = metafile.GetDataSize() * 2; + scoped_array<char> bogus_data(new char[bogus_data_size]); + memset(bogus_data.get(), 'B', bogus_data_size); + bad_msg.WriteData(bogus_data.get(), bogus_data_size); + // Make sure we don't read out the metafile! + printing::NativeMetafile bad_output; + iter = NULL; + // The Emf code on Windows DCHECKs if it cannot create the metafile. +#ifndef NDEBUG + logging::SetLogAssertHandler(IgnoreAssertHandler); +#endif // NDEBUG + EXPECT_FALSE(IPC::ParamTraits<printing::NativeMetafile>::Read( + &bad_msg, &iter, &bad_output)); +#else // defined(OS_WIN) + NOTIMPLEMENTED(); +#endif // defined(OS_WIN) +} + diff --git a/chrome/common/common_resources.grd b/chrome/common/common_resources.grd new file mode 100644 index 0000000..ea1b784 --- /dev/null +++ b/chrome/common/common_resources.grd @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<grit latest_public_release="0" current_release="1"> + <outputs> + <output filename="grit/common_resources.h" type="rc_header"> + <emit emit_type='prepend'></emit> + </output> + <output filename="common_resources.pak" type="data_package" /> + <output filename="common_resources.rc" type="rc_all" /> + </outputs> + <release seq="1"> + <includes> + <include name="IDR_EXTENSION_API_JSON" file="extensions\api\extension_api.json" type="BINDATA" /> + <include name="IDR_I18N_TEMPLATE_JS" file="..\browser\resources\shared\js\i18n_template.js" type="BINDATA" /> + <include name="IDR_JSTEMPLATE_JS" file="..\third_party\jstemplate\jstemplate_compiled.js" type="BINDATA" /> + </includes> + </release> +</grit> diff --git a/chrome/common/content_settings.cc b/chrome/common/content_settings.cc new file mode 100644 index 0000000..89eaa59 --- /dev/null +++ b/chrome/common/content_settings.cc @@ -0,0 +1,11 @@ +// Copyright (c) 2010 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 "chrome/common/content_settings.h" + +ContentSetting IntToContentSetting(int content_setting) { + return ((content_setting < 0) || + (content_setting >= CONTENT_SETTING_NUM_SETTINGS)) ? + CONTENT_SETTING_DEFAULT : static_cast<ContentSetting>(content_setting); +} diff --git a/chrome/common/content_settings.h b/chrome/common/content_settings.h new file mode 100644 index 0000000..10fdcb5 --- /dev/null +++ b/chrome/common/content_settings.h @@ -0,0 +1,40 @@ +// Copyright (c) 2010 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 CHROME_COMMON_CONTENT_SETTINGS_H_ +#define CHROME_COMMON_CONTENT_SETTINGS_H_ + +#include "chrome/common/content_settings_types.h" + +// Different settings that can be assigned for a particular content type. We +// give the user the ability to set these on a global and per-host basis. +enum ContentSetting { + CONTENT_SETTING_DEFAULT = 0, + CONTENT_SETTING_ALLOW, + CONTENT_SETTING_BLOCK, + CONTENT_SETTING_ASK, + CONTENT_SETTING_SESSION_ONLY, + CONTENT_SETTING_NUM_SETTINGS +}; + +// Range-checked conversion of an int to a ContentSetting, for use when reading +// prefs off disk. +ContentSetting IntToContentSetting(int content_setting); + +// Aggregates the permissions for the different content types. +struct ContentSettings { + ContentSettings() { + for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) + settings[i] = CONTENT_SETTING_DEFAULT; + } + + explicit ContentSettings(ContentSetting default_setting) { + for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) + settings[i] = default_setting; + } + + ContentSetting settings[CONTENT_SETTINGS_NUM_TYPES]; +}; + +#endif // CHROME_COMMON_CONTENT_SETTINGS_H_ diff --git a/chrome/common/content_settings_helper.cc b/chrome/common/content_settings_helper.cc new file mode 100644 index 0000000..315b5e4 --- /dev/null +++ b/chrome/common/content_settings_helper.cc @@ -0,0 +1,22 @@ +// Copyright (c) 2010 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 "chrome/common/content_settings_helper.h" + +#include "base/utf_string_conversions.h" +#include "base/string_piece.h" +#include "chrome/common/url_constants.h" +#include "googleurl/src/gurl.h" + +namespace content_settings_helper { + +std::wstring OriginToWString(const GURL& origin) { + std::string port_component((origin.IntPort() != url_parse::PORT_UNSPECIFIED) ? + ":" + origin.port() : ""); + std::string scheme_component(!origin.SchemeIs(chrome::kHttpScheme) ? + origin.scheme() + chrome::kStandardSchemeSeparator : ""); + return UTF8ToWide(scheme_component + origin.host() + port_component); +} + +} // namespace content_settings_helper diff --git a/chrome/common/content_settings_helper.h b/chrome/common/content_settings_helper.h new file mode 100644 index 0000000..0aa2947 --- /dev/null +++ b/chrome/common/content_settings_helper.h @@ -0,0 +1,20 @@ +// Copyright (c) 2010 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 CHROME_COMMON_CONTENT_SETTINGS_HELPER_H_ +#define CHROME_COMMON_CONTENT_SETTINGS_HELPER_H_ + +#include <string> + +class GURL; + +namespace content_settings_helper { + +// Return simplified string representing origin. If origin is using http or +// the standard port, those parts are not included in the output. +std::wstring OriginToWString(const GURL& origin); + +} // namespace content_settings_helper + +#endif // CHROME_COMMON_CONTENT_SETTINGS_HELPER_H_ diff --git a/chrome/common/content_settings_helper_unittest.cc b/chrome/common/content_settings_helper_unittest.cc new file mode 100644 index 0000000..d46eda6 --- /dev/null +++ b/chrome/common/content_settings_helper_unittest.cc @@ -0,0 +1,42 @@ +// Copyright (c) 2010 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 "chrome/common/content_settings_helper.h" + +#include "googleurl/src/gurl.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(ContentSettingsHelperTest, OriginToWString) { + // Urls with "http": + const GURL kUrl0("http://www.foo.com/bar"); + const GURL kUrl1("http://foo.com/bar"); + + const GURL kUrl2("http://www.foo.com:81/bar"); + const GURL kUrl3("http://foo.com:81/bar"); + + // Urls with "https": + const GURL kUrl4("https://www.foo.com/bar"); + const GURL kUrl5("https://foo.com/bar"); + + const GURL kUrl6("https://www.foo.com:81/bar"); + const GURL kUrl7("https://foo.com:81/bar"); + + // Now check the first group of urls with just "http": + EXPECT_EQ(L"www.foo.com", content_settings_helper::OriginToWString(kUrl0)); + EXPECT_EQ(L"foo.com", content_settings_helper::OriginToWString(kUrl1)); + + EXPECT_EQ(L"www.foo.com:81", content_settings_helper::OriginToWString(kUrl2)); + EXPECT_EQ(L"foo.com:81", content_settings_helper::OriginToWString(kUrl3)); + + // Now check the second group of urls with "https": + EXPECT_EQ(L"https://www.foo.com", + content_settings_helper::OriginToWString(kUrl4)); + EXPECT_EQ(L"https://foo.com", + content_settings_helper::OriginToWString(kUrl5)); + + EXPECT_EQ(L"https://www.foo.com:81", + content_settings_helper::OriginToWString(kUrl6)); + EXPECT_EQ(L"https://foo.com:81", + content_settings_helper::OriginToWString(kUrl7)); +} diff --git a/chrome/common/content_settings_types.h b/chrome/common/content_settings_types.h new file mode 100644 index 0000000..2e2a563 --- /dev/null +++ b/chrome/common/content_settings_types.h @@ -0,0 +1,24 @@ +// Copyright (c) 2010 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 CHROME_COMMON_CONTENT_SETTINGS_TYPES_H_ +#define CHROME_COMMON_CONTENT_SETTINGS_TYPES_H_ + +// A particular type of content to care about. We give the user various types +// of controls over each of these. +enum ContentSettingsType { + // "DEFAULT" is only used as an argument to the Content Settings Window + // opener; there it means "whatever was last shown". + CONTENT_SETTINGS_TYPE_DEFAULT = -1, + CONTENT_SETTINGS_TYPE_COOKIES = 0, + CONTENT_SETTINGS_TYPE_IMAGES, + CONTENT_SETTINGS_TYPE_JAVASCRIPT, + CONTENT_SETTINGS_TYPE_PLUGINS, + CONTENT_SETTINGS_TYPE_POPUPS, + CONTENT_SETTINGS_TYPE_GEOLOCATION, + CONTENT_SETTINGS_TYPE_NOTIFICATIONS, + CONTENT_SETTINGS_NUM_TYPES +}; + +#endif // CHROME_COMMON_CONTENT_SETTINGS_TYPES_H_ diff --git a/chrome/common/css_colors.h b/chrome/common/css_colors.h new file mode 100644 index 0000000..d952e98 --- /dev/null +++ b/chrome/common/css_colors.h @@ -0,0 +1,25 @@ +// Copyright (c) 2009 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 CHROME_COMMON_CSS_COLORS_H_ +#define CHROME_COMMON_CSS_COLORS_H_ + +#include <utility> + +#include "base/basictypes.h" +#include "third_party/WebKit/WebKit/chromium/public/WebColor.h" +#include "third_party/WebKit/WebKit/chromium/public/WebColorName.h" + +// Functionality related to sending the values of CSS colors to the renderer. +class CSSColors { + public: + typedef WebKit::WebColorName CSSColorName; + typedef std::pair<CSSColorName, WebKit::WebColor> CSSColorMapping; + + private: + DISALLOW_COPY_AND_ASSIGN(CSSColors); +}; + +#endif // CHROME_COMMON_CSS_COLORS_H_ + diff --git a/chrome/common/database_util.cc b/chrome/common/database_util.cc new file mode 100644 index 0000000..c62e5fa --- /dev/null +++ b/chrome/common/database_util.cc @@ -0,0 +1,53 @@ +// Copyright (c) 2010 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 "chrome/common/database_util.h" + +#include "chrome/common/child_thread.h" +#include "chrome/common/render_messages.h" +#include "ipc/ipc_sync_message_filter.h" +#include "third_party/sqlite/preprocessed/sqlite3.h" +#include "third_party/WebKit/WebKit/chromium/public/WebString.h" + +using WebKit::WebKitClient; +using WebKit::WebString; + +WebKitClient::FileHandle DatabaseUtil::databaseOpenFile( + const WebString& vfs_file_name, int desired_flags) { + IPC::PlatformFileForTransit file_handle = + IPC::InvalidPlatformFileForTransit(); + + scoped_refptr<IPC::SyncMessageFilter> filter = + ChildThread::current()->sync_message_filter(); + filter->Send(new ViewHostMsg_DatabaseOpenFile( + vfs_file_name, desired_flags, &file_handle)); + + return IPC::PlatformFileForTransitToPlatformFile(file_handle); +} + +int DatabaseUtil::databaseDeleteFile( + const WebString& vfs_file_name, bool sync_dir) { + int rv = SQLITE_IOERR_DELETE; + scoped_refptr<IPC::SyncMessageFilter> filter = + ChildThread::current()->sync_message_filter(); + filter->Send(new ViewHostMsg_DatabaseDeleteFile( + vfs_file_name, sync_dir, &rv)); + return rv; +} + +long DatabaseUtil::databaseGetFileAttributes(const WebString& vfs_file_name) { + int32 rv = -1; + scoped_refptr<IPC::SyncMessageFilter> filter = + ChildThread::current()->sync_message_filter(); + filter->Send(new ViewHostMsg_DatabaseGetFileAttributes(vfs_file_name, &rv)); + return rv; +} + +long long DatabaseUtil::databaseGetFileSize(const WebString& vfs_file_name) { + int64 rv = 0LL; + scoped_refptr<IPC::SyncMessageFilter> filter = + ChildThread::current()->sync_message_filter(); + filter->Send(new ViewHostMsg_DatabaseGetFileSize(vfs_file_name, &rv)); + return rv; +} diff --git a/chrome/common/database_util.h b/chrome/common/database_util.h new file mode 100644 index 0000000..9c263af --- /dev/null +++ b/chrome/common/database_util.h @@ -0,0 +1,22 @@ +// Copyright (c) 2010 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 CHROME_COMMON_DATABASE_UTIL_H_ +#define CHROME_COMMON_DATABASE_UTIL_H_ + +#include "webkit/glue/webkitclient_impl.h" + +// A class of utility functions used by RendererWebKitClientImpl and +// WorkerWebKitClientImpl to handle database file accesses. +class DatabaseUtil { + public: + static WebKit::WebKitClient::FileHandle databaseOpenFile( + const WebKit::WebString& vfs_file_name, int desired_flags); + static int databaseDeleteFile(const WebKit::WebString& vfs_file_name, + bool sync_dir); + static long databaseGetFileAttributes(const WebKit::WebString& vfs_file_name); + static long long databaseGetFileSize(const WebKit::WebString& vfs_file_name); +}; + +#endif // CHROME_COMMON_DATABASE_UTIL_H_ diff --git a/chrome/common/db_message_filter.cc b/chrome/common/db_message_filter.cc new file mode 100644 index 0000000..8e3bbc6 --- /dev/null +++ b/chrome/common/db_message_filter.cc @@ -0,0 +1,37 @@ +// Copyright (c) 2010 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 "chrome/common/db_message_filter.h" + +#include "chrome/common/render_messages.h" +#include "third_party/WebKit/WebKit/chromium/public/WebDatabase.h" + +DBMessageFilter::DBMessageFilter() { +} + +bool DBMessageFilter::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(DBMessageFilter, message) + IPC_MESSAGE_HANDLER(ViewMsg_DatabaseUpdateSize, OnDatabaseUpdateSize) + IPC_MESSAGE_HANDLER(ViewMsg_DatabaseCloseImmediately, + OnDatabaseCloseImmediately) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void DBMessageFilter::OnDatabaseUpdateSize(const string16& origin_identifier, + const string16& database_name, + int64 database_size, + int64 space_available) { + WebKit::WebDatabase::updateDatabaseSize( + origin_identifier, database_name, database_size, space_available); +} + +void DBMessageFilter::OnDatabaseCloseImmediately( + const string16& origin_identifier, + const string16& database_name) { + WebKit::WebDatabase::closeDatabaseImmediately( + origin_identifier, database_name); +} diff --git a/chrome/common/db_message_filter.h b/chrome/common/db_message_filter.h new file mode 100644 index 0000000..1cb07d8 --- /dev/null +++ b/chrome/common/db_message_filter.h @@ -0,0 +1,27 @@ +// Copyright (c) 2010 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 CHROME_COMMON_DB_MESSAGE_FILTER_H_ +#define CHROME_COMMON_DB_MESSAGE_FILTER_H_ + +#include "ipc/ipc_channel_proxy.h" + +// Receives database messages from the browser process and processes them on the +// IO thread. +class DBMessageFilter : public IPC::ChannelProxy::MessageFilter { + public: + DBMessageFilter(); + + private: + virtual bool OnMessageReceived(const IPC::Message& message); + + void OnDatabaseUpdateSize(const string16& origin_identifier, + const string16& database_name, + int64 database_size, + int64 space_available); + void OnDatabaseCloseImmediately(const string16& origin_identifier, + const string16& database_name); +}; + +#endif // CHROME_COMMON_DB_MESSAGE_FILTER_H_ diff --git a/chrome/common/debug_flags.cc b/chrome/common/debug_flags.cc new file mode 100644 index 0000000..dd2eaee --- /dev/null +++ b/chrome/common/debug_flags.cc @@ -0,0 +1,50 @@ +// Copyright (c) 2006-2008 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 "chrome/common/debug_flags.h" + +#include "base/base_switches.h" +#include "base/command_line.h" +#include "base/utf_string_conversions.h" +#include "chrome/common/chrome_switches.h" +#include "ipc/ipc_switches.h" + +bool DebugFlags::ProcessDebugFlags(CommandLine* command_line, + ChildProcessInfo::ProcessType type, + bool is_in_sandbox) { + bool should_help_child = false; + const CommandLine& current_cmd_line = *CommandLine::ForCurrentProcess(); + if (current_cmd_line.HasSwitch(switches::kDebugChildren)) { + // Look to pass-on the kDebugOnStart flag. + std::string value = current_cmd_line.GetSwitchValueASCII( + switches::kDebugChildren); + if (value.empty() || + (type == ChildProcessInfo::WORKER_PROCESS && + value == switches::kWorkerProcess) || + (type == ChildProcessInfo::RENDER_PROCESS && + value == switches::kRendererProcess) || + (type == ChildProcessInfo::PLUGIN_PROCESS && + value == switches::kPluginProcess)) { + command_line->AppendSwitch(switches::kDebugOnStart); + should_help_child = true; + } + command_line->AppendSwitchWithValue(switches::kDebugChildren, value); + } else if (current_cmd_line.HasSwitch(switches::kWaitForDebuggerChildren)) { + // Look to pass-on the kWaitForDebugger flag. + std::string value = current_cmd_line.GetSwitchValueASCII( + switches::kWaitForDebuggerChildren); + if (value.empty() || + (type == ChildProcessInfo::WORKER_PROCESS && + value == switches::kWorkerProcess) || + (type == ChildProcessInfo::RENDER_PROCESS && + value == switches::kRendererProcess) || + (type == ChildProcessInfo::PLUGIN_PROCESS && + value == switches::kPluginProcess)) { + command_line->AppendSwitch(switches::kWaitForDebugger); + } + command_line->AppendSwitchWithValue(switches::kWaitForDebuggerChildren, + value); + } + return should_help_child; +} diff --git a/chrome/common/debug_flags.h b/chrome/common/debug_flags.h new file mode 100644 index 0000000..231d2ca --- /dev/null +++ b/chrome/common/debug_flags.h @@ -0,0 +1,28 @@ +// Copyright (c) 2006-2008 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 CHROME_COMMON_DEBUG_FLAGS_H__ +#define CHROME_COMMON_DEBUG_FLAGS_H__ + +#include "chrome/common/child_process_info.h" + +class CommandLine; + +class DebugFlags { + public: + + // Updates the command line arguments with debug-related flags. If + // debug flags have been used with this process, they will be + // filtered and added to command_line as needed. is_in_sandbox must + // be true if the child process will be in a sandbox. + // + // Returns true if the caller should "help" the child process by + // calling the JIT debugger on it. It may only happen if + // is_in_sandbox is true. + static bool ProcessDebugFlags(CommandLine* command_line, + ChildProcessInfo::ProcessType type, + bool is_in_sandbox); +}; + +#endif // CHROME_COMMON_DEBUG_FLAGS_H__ diff --git a/chrome/common/default_plugin.cc b/chrome/common/default_plugin.cc new file mode 100644 index 0000000..bba738b --- /dev/null +++ b/chrome/common/default_plugin.cc @@ -0,0 +1,33 @@ +// Copyright (c) 2010 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 "chrome/common/default_plugin.h" + +#include "chrome/default_plugin/plugin_main.h" +#include "webkit/glue/plugins/plugin_list.h" + +namespace chrome { + +void RegisterInternalDefaultPlugin() { + const NPAPI::PluginVersionInfo default_plugin = { + FilePath(kDefaultPluginLibraryName), + L"Default Plug-in", + L"Provides functionality for installing third-party plug-ins", + L"1", + L"*", + L"", + L"", + { +#if !defined(OS_POSIX) || defined(OS_MACOSX) + default_plugin::NP_GetEntryPoints, +#endif + default_plugin::NP_Initialize, + default_plugin::NP_Shutdown + } + }; + + NPAPI::PluginList::Singleton()->RegisterInternalPlugin(default_plugin); +} + +} // namespace chrome diff --git a/chrome/common/default_plugin.h b/chrome/common/default_plugin.h new file mode 100644 index 0000000..e3394e8 --- /dev/null +++ b/chrome/common/default_plugin.h @@ -0,0 +1,15 @@ +// Copyright (c) 2010 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 CHROME_COMMON_DEFAULT_PLUGIN_H_ +#define CHROME_COMMON_DEFAULT_PLUGIN_H_ + +namespace chrome { + +// Register the default plugin as an internal plugin in the PluginList. +void RegisterInternalDefaultPlugin(); + +} // namespace chrome + +#endif // CHROME_COMMON_DEFAULT_PLUGIN_H_ diff --git a/chrome/common/deprecated/event_sys-inl.h b/chrome/common/deprecated/event_sys-inl.h new file mode 100644 index 0000000..62fa350 --- /dev/null +++ b/chrome/common/deprecated/event_sys-inl.h @@ -0,0 +1,341 @@ +// Copyright (c) 2009 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 CHROME_COMMON_DEPRECATED_EVENT_SYS_INL_H_ +#define CHROME_COMMON_DEPRECATED_EVENT_SYS_INL_H_ + +#include <map> + +#include "base/atomicops.h" +#include "base/basictypes.h" +#include "base/condition_variable.h" +#include "base/lock.h" +#include "base/logging.h" +#include "base/message_loop.h" +#include "base/port.h" +#include "chrome/common/deprecated/event_sys.h" + +// How to use Channels: + +// 0. Assume Bob is the name of the class from which you want to broadcast +// events. +// 1. Choose an EventType. This could be an Enum or something more complicated. +// 2. Create an EventTraits class for your EventType. It must have +// two members: +// +// typedef x EventType; +// static bool IsChannelShutdownEvent(const EventType& event); +// +// 3. Add an EventChannel<MyEventTraits>* instance and event_channel() const; +// accessor to Bob. +// Delete the channel ordinarily in Bob's destructor, or whenever you want. +// 4. To broadcast events, call bob->event_channel()->NotifyListeners(event). +// 5. Only call NotifyListeners from a single thread at a time. + +// How to use Listeners/Hookups: + +// 0. Assume you want a class called Lisa to listen to events from Bob. +// 1. Create an event handler method in Lisa. Its single argument should be of +// your event type. +// 2. Add a EventListenerHookup* hookup_ member to Lisa. +// 3. Initialize the hookup by calling: +// +// hookup_ = NewEventListenerHookup(bob->event_channel(), +// this, +// &Lisa::HandleEvent); +// +// 4. Delete hookup_ in Lisa's destructor, or anytime sooner to stop receiving +// events. + +// An Event Channel is a source, or broadcaster of events. Listeners subscribe +// by calling the AddListener() method. The owner of the channel calls the +// NotifyListeners() method. +// +// Don't inherit from this class. Just make an event_channel member and an +// event_channel() accessor. + +// No reason why CallbackWaiters has to be templatized. +class CallbackWaiters { + public: + CallbackWaiters() : waiter_count_(0), + callback_done_(false), + condvar_(&mutex_) { + } + ~CallbackWaiters() { + DCHECK_EQ(0, waiter_count_); + } + void WaitForCallbackToComplete(Lock* listeners_mutex) { + { + AutoLock lock(mutex_); + waiter_count_ += 1; + listeners_mutex->Release(); + while (!callback_done_) + condvar_.Wait(); + waiter_count_ -= 1; + if (0 != waiter_count_) + return; + } + delete this; + } + + void Signal() { + AutoLock lock(mutex_); + callback_done_ = true; + condvar_.Broadcast(); + } + + protected: + int waiter_count_; + bool callback_done_; + Lock mutex_; + ConditionVariable condvar_; +}; + +template <typename EventTraitsType, typename NotifyLock, + typename ScopedNotifyLocker> +class EventChannel { + public: + typedef EventTraitsType EventTraits; + typedef typename EventTraits::EventType EventType; + typedef EventListener<EventType> Listener; + + protected: + typedef std::map<Listener*, bool> Listeners; + + public: + // The shutdown event gets send in the EventChannel's destructor. + explicit EventChannel(const EventType& shutdown_event) + : current_listener_callback_(NULL), + callback_waiters_(NULL), + shutdown_event_(shutdown_event) { + } + + ~EventChannel() { + // Tell all the listeners that the channel is being deleted. + NotifyListeners(shutdown_event_); + + // Make sure all the listeners have been disconnected. Otherwise, they + // will try to call RemoveListener() at a later date. +#if defined(DEBUG) + AutoLock lock(listeners_mutex_); + for (typename Listeners::iterator i = listeners_.begin(); + i != listeners_.end(); ++i) { + DCHECK(i->second) << "Listener not disconnected"; + } +#endif + } + + // Never call this twice for the same listener. + // + // Thread safe. + void AddListener(Listener* listener) { + AutoLock lock(listeners_mutex_); + typename Listeners::iterator found = listeners_.find(listener); + if (found == listeners_.end()) { + listeners_.insert(std::make_pair(listener, + false)); // Not dead yet. + } else { + DCHECK(found->second) << "Attempted to add the same listener twice."; + found->second = false; // Not dead yet. + } + } + + // If listener's callback is currently executing, this method waits until the + // callback completes before returning. + // + // Thread safe. + void RemoveListener(Listener* listener) { + bool wait = false; + listeners_mutex_.Acquire(); + typename Listeners::iterator found = listeners_.find(listener); + if (found != listeners_.end()) { + found->second = true; // Mark as dead. + wait = (found->first == current_listener_callback_ && + (MessageLoop::current() != current_listener_callback_message_loop_)); + } + if (!wait) { + listeners_mutex_.Release(); + return; + } + if (NULL == callback_waiters_) + callback_waiters_ = new CallbackWaiters; + callback_waiters_->WaitForCallbackToComplete(&listeners_mutex_); + } + + // Blocks until all listeners have been notified. + // + // NOT thread safe. Must only be called by one thread at a time. + void NotifyListeners(const EventType& event) { + ScopedNotifyLocker lock_notify(notify_lock_); + listeners_mutex_.Acquire(); + DCHECK(NULL == current_listener_callback_); + current_listener_callback_message_loop_ = MessageLoop::current(); + typename Listeners::iterator i = listeners_.begin(); + while (i != listeners_.end()) { + if (i->second) { // Clean out dead listeners + listeners_.erase(i++); + continue; + } + current_listener_callback_ = i->first; + listeners_mutex_.Release(); + + i->first->HandleEvent(event); + + listeners_mutex_.Acquire(); + current_listener_callback_ = NULL; + if (NULL != callback_waiters_) { + callback_waiters_->Signal(); + callback_waiters_ = NULL; + } + + ++i; + } + listeners_mutex_.Release(); + } + + // A map iterator remains valid until the element it points to gets removed + // from the map, so a map is perfect for our needs. + // + // Map value is a bool, true means the Listener is dead. + Listeners listeners_; + // NULL means no callback is currently being called. + Listener* current_listener_callback_; + // Only valid when current_listener is not NULL. + // The thread on which the callback is executing. + MessageLoop* current_listener_callback_message_loop_; + // Win32 Event that is usually NULL. Only created when another thread calls + // Remove while in callback. Owned and closed by the thread calling Remove(). + CallbackWaiters* callback_waiters_; + + Lock listeners_mutex_; // Protects all members above. + const EventType shutdown_event_; + NotifyLock notify_lock_; + + DISALLOW_COPY_AND_ASSIGN(EventChannel); +}; + +// An EventListenerHookup hooks up a method in your class to an EventChannel. +// Deleting the hookup disconnects from the EventChannel. +// +// Contains complexity of inheriting from Listener class and managing lifetimes. +// +// Create using NewEventListenerHookup() to avoid explicit template arguments. +class EventListenerHookup { + public: + virtual ~EventListenerHookup() { } +}; + +template <typename EventChannel, typename EventTraits, + class Derived> +class EventListenerHookupImpl : public EventListenerHookup, +public EventListener<typename EventTraits::EventType> { + public: + explicit EventListenerHookupImpl(EventChannel* channel) + : channel_(channel), deleted_(NULL) { + channel->AddListener(this); + connected_ = true; + } + + ~EventListenerHookupImpl() { + if (NULL != deleted_) + *deleted_ = true; + if (connected_) + channel_->RemoveListener(this); + } + + typedef typename EventTraits::EventType EventType; + virtual void HandleEvent(const EventType& event) { + DCHECK(connected_); + bool deleted = false; + deleted_ = &deleted; + static_cast<Derived*>(this)->Callback(event); + if (deleted) // The callback (legally) deleted this. + return; // The only safe thing to do. + deleted_ = NULL; + if (EventTraits::IsChannelShutdownEvent(event)) { + channel_->RemoveListener(this); + connected_ = false; + } + } + + protected: + EventChannel* const channel_; + bool connected_; + bool* deleted_; // Allows the handler to delete the hookup. +}; + +// SimpleHookup just passes the event to the callback message. +template <typename EventChannel, typename EventTraits, + typename CallbackObject, typename CallbackMethod> +class SimpleHookup + : public EventListenerHookupImpl<EventChannel, EventTraits, + SimpleHookup<EventChannel, + EventTraits, + CallbackObject, + CallbackMethod> > { + public: + SimpleHookup(EventChannel* channel, CallbackObject* cbobject, + CallbackMethod cbmethod) + : EventListenerHookupImpl<EventChannel, EventTraits, + SimpleHookup>(channel), cbobject_(cbobject), + cbmethod_(cbmethod) { } + + typedef typename EventTraits::EventType EventType; + void Callback(const EventType& event) { + (cbobject_->*cbmethod_)(event); + } + CallbackObject* const cbobject_; + CallbackMethod const cbmethod_; +}; + +// ArgHookup also passes an additional arg to the callback method. +template <typename EventChannel, typename EventTraits, + typename CallbackObject, typename CallbackMethod, + typename CallbackArg0> +class ArgHookup + : public EventListenerHookupImpl<EventChannel, EventTraits, + ArgHookup<EventChannel, EventTraits, + CallbackObject, + CallbackMethod, + CallbackArg0> > { + public: + ArgHookup(EventChannel* channel, CallbackObject* cbobject, + CallbackMethod cbmethod, CallbackArg0 arg0) + : EventListenerHookupImpl<EventChannel, EventTraits, + ArgHookup>(channel), cbobject_(cbobject), + cbmethod_(cbmethod), arg0_(arg0) { } + + typedef typename EventTraits::EventType EventType; + void Callback(const EventType& event) { + (cbobject_->*cbmethod_)(arg0_, event); + } + CallbackObject* const cbobject_; + CallbackMethod const cbmethod_; + CallbackArg0 const arg0_; +}; + + +template <typename EventChannel, typename CallbackObject, + typename CallbackMethod> +EventListenerHookup* NewEventListenerHookup(EventChannel* channel, + CallbackObject* cbobject, + CallbackMethod cbmethod) { + return new SimpleHookup<EventChannel, + typename EventChannel::EventTraits, + CallbackObject, CallbackMethod>(channel, cbobject, cbmethod); +} + +template <typename EventChannel, typename CallbackObject, + typename CallbackMethod, typename CallbackArg0> +EventListenerHookup* NewEventListenerHookup(EventChannel* channel, + CallbackObject* cbobject, + CallbackMethod cbmethod, + CallbackArg0 arg0) { + return new ArgHookup<EventChannel, + typename EventChannel::EventTraits, + CallbackObject, CallbackMethod, CallbackArg0>(channel, cbobject, + cbmethod, arg0); +} + +#endif // CHROME_COMMON_DEPRECATED_EVENT_SYS_INL_H_ diff --git a/chrome/common/deprecated/event_sys.h b/chrome/common/deprecated/event_sys.h new file mode 100644 index 0000000..bec8144 --- /dev/null +++ b/chrome/common/deprecated/event_sys.h @@ -0,0 +1,45 @@ +// Copyright (c) 2009 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 CHROME_COMMON_DEPRECATED_EVENT_SYS_H_ +#define CHROME_COMMON_DEPRECATED_EVENT_SYS_H_ + +// TODO: This class should be removed or moved to Notifier code. +// See Bug 42450 (http://code.google.com/p/chromium/issues/detail?id=42450). + +class AutoLock; +class Lock; + +// An abstract base class for listening to events. +// +// Don't inherit from this class yourself. Using NewEventListenerHookup() is +// much easier. +template <typename EventType> +class EventListener { + public: + virtual void HandleEvent(const EventType& event) = 0; +}; + +// See the -inl.h for details about the following. + +template <typename EventTraits, typename NotifyLock = Lock, + typename ScopedNotifyLocker = AutoLock> +class EventChannel; + +class EventListenerHookup; + +template <typename EventChannel, typename CallbackObject, + typename CallbackMethod> +EventListenerHookup* NewEventListenerHookup(EventChannel* channel, + CallbackObject* cbobject, + CallbackMethod cbmethod); + +template <typename EventChannel, typename CallbackObject, + typename CallbackMethod, typename CallbackArg0> +EventListenerHookup* NewEventListenerHookup(EventChannel* channel, + CallbackObject* cbobject, + CallbackMethod cbmethod, + CallbackArg0 arg0); + +#endif // CHROME_COMMON_DEPRECATED_EVENT_SYS_H_ diff --git a/chrome/common/deprecated/event_sys_unittest.cc b/chrome/common/deprecated/event_sys_unittest.cc new file mode 100644 index 0000000..c70d3f7 --- /dev/null +++ b/chrome/common/deprecated/event_sys_unittest.cc @@ -0,0 +1,271 @@ +// Copyright (c) 2009 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 <iosfwd> +#include <sstream> +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/logging.h" +#include "base/message_loop.h" +#include "base/platform_thread.h" +#include "base/port.h" +#include "build/build_config.h" +#include "chrome/common/deprecated/event_sys-inl.h" +#include "testing/gtest/include/gtest/gtest.h" + +using std::endl; +using std::ostream; +using std::string; +using std::stringstream; +using std::vector; + +namespace { + +class Pair; + +struct TestEvent { + Pair* source; + enum { + A_CHANGED, B_CHANGED, PAIR_BEING_DELETED, + } what_happened; + int old_value; +}; + +struct TestEventTraits { + typedef TestEvent EventType; + static bool IsChannelShutdownEvent(const TestEvent& event) { + return TestEvent::PAIR_BEING_DELETED == event.what_happened; + } +}; + +class Pair { + public: + typedef EventChannel<TestEventTraits> Channel; + explicit Pair(const string& name) : name_(name), a_(0), b_(0) { + TestEvent shutdown = { this, TestEvent::PAIR_BEING_DELETED, 0 }; + event_channel_ = new Channel(shutdown); + } + ~Pair() { + delete event_channel_; + } + void set_a(int n) { + TestEvent event = { this, TestEvent::A_CHANGED, a_ }; + a_ = n; + event_channel_->NotifyListeners(event); + } + void set_b(int n) { + TestEvent event = { this, TestEvent::B_CHANGED, b_ }; + b_ = n; + event_channel_->NotifyListeners(event); + } + int a() const { return a_; } + int b() const { return b_; } + const string& name() { return name_; } + Channel* event_channel() const { return event_channel_; } + + protected: + const string name_; + int a_; + int b_; + Channel* event_channel_; +}; + +class EventLogger { + public: + explicit EventLogger(ostream& out) : out_(out) { } + ~EventLogger() { + for (Hookups::iterator i = hookups_.begin(); i != hookups_.end(); ++i) + delete *i; + } + + void Hookup(const string name, Pair::Channel* channel) { + hookups_.push_back(NewEventListenerHookup(channel, this, + &EventLogger::HandlePairEvent, + name)); + } + + void HandlePairEvent(const string& name, const TestEvent& event) { + const char* what_changed = NULL; + int new_value = 0; + Hookups::iterator dead; + switch (event.what_happened) { + case TestEvent::A_CHANGED: + what_changed = "A"; + new_value = event.source->a(); + break; + case TestEvent::B_CHANGED: + what_changed = "B"; + new_value = event.source->b(); + break; + case TestEvent::PAIR_BEING_DELETED: + out_ << name << " heard " << event.source->name() << " being deleted." + << endl; + return; + default: + FAIL() << "Bad event.what_happened: " << event.what_happened; + break; + } + out_ << name << " heard " << event.source->name() << "'s " << what_changed + << " change from " + << event.old_value << " to " << new_value << endl; + } + + typedef vector<EventListenerHookup*> Hookups; + Hookups hookups_; + ostream& out_; +}; + +const char golden_result[] = "Larry heard Sally's B change from 0 to 2\n" +"Larry heard Sally's A change from 1 to 3\n" +"Lewis heard Sam's B change from 0 to 5\n" +"Larry heard Sally's A change from 3 to 6\n" +"Larry heard Sally being deleted.\n"; + +TEST(EventSys, Basic) { + Pair sally("Sally"), sam("Sam"); + sally.set_a(1); + stringstream log; + EventLogger logger(log); + logger.Hookup("Larry", sally.event_channel()); + sally.set_b(2); + sally.set_a(3); + sam.set_a(4); + logger.Hookup("Lewis", sam.event_channel()); + sam.set_b(5); + sally.set_a(6); + // Test that disconnect within callback doesn't deadlock. + TestEvent event = {&sally, TestEvent::PAIR_BEING_DELETED, 0 }; + sally.event_channel()->NotifyListeners(event); + sally.set_a(7); + ASSERT_EQ(log.str(), golden_result); +} + + +// This goes pretty far beyond the normal use pattern, so don't use +// ThreadTester as an example of what to do. +class ThreadTester : public EventListener<TestEvent>, + public PlatformThread::Delegate { + public: + explicit ThreadTester(Pair* pair) + : pair_(pair), remove_event_(&remove_event_mutex_), + remove_event_bool_(false), completed_(false) { + pair_->event_channel()->AddListener(this); + } + ~ThreadTester() { + pair_->event_channel()->RemoveListener(this); + for (size_t i = 0; i < threads_.size(); i++) { + PlatformThread::Join(threads_[i].thread); + } + } + + struct ThreadInfo { + PlatformThreadHandle thread; + }; + + struct ThreadArgs { + ConditionVariable* thread_running_cond; + Lock* thread_running_mutex; + bool thread_running; + }; + + void Go() { + Lock thread_running_mutex; + ConditionVariable thread_running_cond(&thread_running_mutex); + ThreadArgs args; + ThreadInfo info; + args.thread_running_cond = &(thread_running_cond); + args.thread_running_mutex = &(thread_running_mutex); + args.thread_running = false; + args_ = args; + ASSERT_TRUE(PlatformThread::Create(0, this, &info.thread)); + thread_running_mutex.Acquire(); + while ((args_.thread_running) == false) { + thread_running_cond.Wait(); + } + thread_running_mutex.Release(); + threads_.push_back(info); + } + + // PlatformThread::Delegate methods. + virtual void ThreadMain() { + // Make sure each thread gets a current MessageLoop in TLS. + // This test should use chrome threads for testing, but I'll leave it like + // this for the moment since it requires a big chunk of rewriting and I + // want the test passing while I checkpoint my CL. Technically speaking, + // there should be no functional difference. + MessageLoop message_loop; + args_.thread_running_mutex->Acquire(); + args_.thread_running = true; + args_.thread_running_cond->Signal(); + args_.thread_running_mutex->Release(); + + remove_event_mutex_.Acquire(); + while (remove_event_bool_ == false) { + remove_event_.Wait(); + } + remove_event_mutex_.Release(); + + // Normally, you'd just delete the hookup. This is very bad style, but + // necessary for the test. + pair_->event_channel()->RemoveListener(this); + + completed_mutex_.Acquire(); + completed_ = true; + completed_mutex_.Release(); + } + + void HandleEvent(const TestEvent& event) { + remove_event_mutex_.Acquire(); + remove_event_bool_ = true; + remove_event_.Broadcast(); + remove_event_mutex_.Release(); + + PlatformThread::YieldCurrentThread(); + + completed_mutex_.Acquire(); + if (completed_) + FAIL() << "A test thread exited too early."; + completed_mutex_.Release(); + } + + Pair* pair_; + ConditionVariable remove_event_; + Lock remove_event_mutex_; + bool remove_event_bool_; + Lock completed_mutex_; + bool completed_; + vector<ThreadInfo> threads_; + ThreadArgs args_; +}; + +TEST(EventSys, Multithreaded) { + Pair sally("Sally"); + ThreadTester a(&sally); + for (int i = 0; i < 3; ++i) + a.Go(); + sally.set_b(99); +} + +class HookupDeleter { + public: + void HandleEvent(const TestEvent& event) { + delete hookup_; + hookup_ = NULL; + } + EventListenerHookup* hookup_; +}; + +TEST(EventSys, InHandlerDeletion) { + Pair sally("Sally"); + HookupDeleter deleter; + deleter.hookup_ = NewEventListenerHookup(sally.event_channel(), + &deleter, + &HookupDeleter::HandleEvent); + sally.set_a(1); + ASSERT_TRUE(NULL == deleter.hookup_); +} + +} // namespace diff --git a/chrome/common/desktop_notifications/active_notification_tracker.cc b/chrome/common/desktop_notifications/active_notification_tracker.cc new file mode 100644 index 0000000..9822711 --- /dev/null +++ b/chrome/common/desktop_notifications/active_notification_tracker.cc @@ -0,0 +1,70 @@ +// Copyright (c) 2009 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 "chrome/common/desktop_notifications/active_notification_tracker.h" + +#include "base/message_loop.h" +#include "base/scoped_ptr.h" +#include "third_party/WebKit/WebKit/chromium/public/WebNotification.h" +#include "third_party/WebKit/WebKit/chromium/public/WebNotificationPermissionCallback.h" + +using WebKit::WebNotification; +using WebKit::WebNotificationPermissionCallback; + +bool ActiveNotificationTracker::GetId( + const WebNotification& notification, int& id) { + ReverseTable::iterator iter = reverse_notification_table_.find(notification); + if (iter == reverse_notification_table_.end()) + return false; + id = iter->second; + return true; +} + +bool ActiveNotificationTracker::GetNotification( + int id, WebNotification* notification) { + WebNotification* lookup = notification_table_.Lookup(id); + if (!lookup) + return false; + + *notification = *lookup; + return true; +} + +int ActiveNotificationTracker::RegisterNotification( + const WebKit::WebNotification& proxy) { + WebNotification* notification = new WebNotification(proxy); + int id = notification_table_.Add(notification); + reverse_notification_table_[proxy] = id; + return id; +} + +void ActiveNotificationTracker::UnregisterNotification(int id) { + // We want to free the notification after removing it from the table. + scoped_ptr<WebNotification> notification(notification_table_.Lookup(id)); + notification_table_.Remove(id); + DCHECK(notification.get()); + if (notification.get()) + reverse_notification_table_.erase(*notification); +} + +void ActiveNotificationTracker::Clear() { + while (!reverse_notification_table_.empty()) { + ReverseTable::iterator iter = reverse_notification_table_.begin(); + UnregisterNotification((*iter).second); + } +} + +WebNotificationPermissionCallback* ActiveNotificationTracker::GetCallback( + int id) { + return callback_table_.Lookup(id); +} + +int ActiveNotificationTracker::RegisterPermissionRequest( + WebNotificationPermissionCallback* callback) { + return callback_table_.Add(callback); +} + +void ActiveNotificationTracker::OnPermissionRequestComplete(int id) { + callback_table_.Remove(id); +} diff --git a/chrome/common/desktop_notifications/active_notification_tracker.h b/chrome/common/desktop_notifications/active_notification_tracker.h new file mode 100644 index 0000000..1676f32 --- /dev/null +++ b/chrome/common/desktop_notifications/active_notification_tracker.h @@ -0,0 +1,52 @@ +// Copyright (c) 2009 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 CHROME_COMMON_DESKTOP_NOTIFICATIONS_ACTIVE_NOTIFICATION_TRACKER_H_ +#define CHROME_COMMON_DESKTOP_NOTIFICATIONS_ACTIVE_NOTIFICATION_TRACKER_H_ + +#include <map> + +#include "base/basictypes.h" +#include "base/id_map.h" +#include "base/hash_tables.h" +#include "third_party/WebKit/WebKit/chromium/public/WebNotification.h" + +namespace WebKit { +class WebNotificationPermissionCallback; +} + +// This class manages the set of active Notification objects in either +// a render or worker process. This class should be accessed only on +// the main thread. +class ActiveNotificationTracker { + public: + ActiveNotificationTracker() {} + + // Methods for tracking active notification objects. + int RegisterNotification(const WebKit::WebNotification& notification); + void UnregisterNotification(int id); + bool GetId(const WebKit::WebNotification& notification, int& id); + bool GetNotification(int id, WebKit::WebNotification* notification); + + // Methods for tracking active permission requests. + int RegisterPermissionRequest( + WebKit::WebNotificationPermissionCallback* callback); + void OnPermissionRequestComplete(int id); + WebKit::WebNotificationPermissionCallback* GetCallback(int id); + + // Clears out all active notifications. Useful on page navigation. + void Clear(); + + private: + typedef std::map<WebKit::WebNotification, int> ReverseTable; + + // Tracking maps for active notifications and permission requests. + IDMap<WebKit::WebNotification> notification_table_; + ReverseTable reverse_notification_table_; + IDMap<WebKit::WebNotificationPermissionCallback> callback_table_; + + DISALLOW_COPY_AND_ASSIGN(ActiveNotificationTracker); +}; + +#endif // CHROME_COMMON_DESKTOP_NOTIFICATIONS_ACTIVE_NOTIFICATION_TRACKER_H_ diff --git a/chrome/common/desktop_notifications/active_notification_tracker_unittest.cc b/chrome/common/desktop_notifications/active_notification_tracker_unittest.cc new file mode 100644 index 0000000..b741d35 --- /dev/null +++ b/chrome/common/desktop_notifications/active_notification_tracker_unittest.cc @@ -0,0 +1,25 @@ +// Copyright (c) 2010 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 "chrome/common/desktop_notifications/active_notification_tracker.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(ActiveNotificationTrackerTest, TestLookupAndClear) { + ActiveNotificationTracker tracker; + + WebKit::WebNotification notification1; + int id1 = tracker.RegisterNotification(notification1); + + WebKit::WebNotification notification2; + int id2 = tracker.RegisterNotification(notification2); + + WebKit::WebNotification result; + tracker.GetNotification(id1, &result); + EXPECT_TRUE(result == notification1); + + tracker.GetNotification(id2, &result); + EXPECT_TRUE(result == notification2); + + tracker.Clear(); +} diff --git a/chrome/common/devtools_messages.h b/chrome/common/devtools_messages.h new file mode 100644 index 0000000..a46d72b --- /dev/null +++ b/chrome/common/devtools_messages.h @@ -0,0 +1,38 @@ +// Copyright (c) 2009 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 CHROME_COMMON_DEVTOOLS_MESSAGES_H_ +#define CHROME_COMMON_DEVTOOLS_MESSAGES_H_ + +#include "ipc/ipc_message_utils.h" +#include "webkit/glue/devtools_message_data.h" + +namespace IPC { + +// Traits for DevToolsMessageData structure to pack/unpack. +template <> +struct ParamTraits<DevToolsMessageData> { + typedef DevToolsMessageData param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.class_name); + WriteParam(m, p.method_name); + WriteParam(m, p.arguments); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->class_name) && + ReadParam(m, iter, &p->method_name) && + ReadParam(m, iter, &p->arguments); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<DevToolsMessageData>"); + } +}; + +} // namespace IPC + +#define MESSAGES_INTERNAL_FILE "chrome/common/devtools_messages_internal.h" +#include "ipc/ipc_message_macros.h" + +#endif // CHROME_COMMON_DEVTOOLS_MESSAGES_H_ diff --git a/chrome/common/devtools_messages_internal.h b/chrome/common/devtools_messages_internal.h new file mode 100644 index 0000000..dcc8eee --- /dev/null +++ b/chrome/common/devtools_messages_internal.h @@ -0,0 +1,96 @@ +// Copyright (c) 2009 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 header is meant to be included in multiple passes, hence no traditional +// header guard. +// See ipc_message_macros.h for explanation of the macros and passes. + +// Developer tools consist of the following parts: +// +// DevToolsAgent lives in the renderer of an inspected page and provides access +// to the pages resources, DOM, v8 etc. by means of IPC messages. +// +// DevToolsClient is a thin delegate that lives in the tools front-end +// renderer and converts IPC messages to frontend method calls and allows the +// frontend to send messages to the DevToolsAgent. +// +// All the messages are routed through browser process. There is a +// DevToolsManager living in the browser process that is responsible for +// routing logistics. It is also capable of sending direct messages to the +// agent rather than forwarding messages between agents and clients only. +// +// Chain of communication between the components may be described by the +// following diagram: +// ---------------------------- +// | (tools frontend | +// | renderer process) | +// | | -------------------- +// |tools <--> DevToolsClient+<-- IPC -->+ (browser process) | +// |frontend | | | +// ---------------------------- ---------+---------- +// ^ +// | +// IPC +// | +// v +// --------------------------+-------- +// | inspected page <--> DevToolsAgent | +// | | +// | (inspected page renderer process) | +// ----------------------------------- +// +// This file describes developer tools message types. + +#include "ipc/ipc_message_macros.h" +#include "webkit/glue/devtools_message_data.h" + +// These are messages sent from DevToolsAgent to DevToolsClient through the +// browser. +IPC_BEGIN_MESSAGES(DevToolsClient) + + // Sends glue-level Rpc message to the client. + IPC_MESSAGE_CONTROL1(DevToolsClientMsg_RpcMessage, + DevToolsMessageData /* message data */) + +IPC_END_MESSAGES(DevToolsClient) + + +//----------------------------------------------------------------------------- +// These are messages sent from DevToolsClient to DevToolsAgent through the +// browser. +IPC_BEGIN_MESSAGES(DevToolsAgent) + + // Tells agent that there is a client host connected to it. + IPC_MESSAGE_CONTROL1(DevToolsAgentMsg_Attach, + std::vector<std::string> /* runtime_features */) + + // Tells agent that there is no longer a client host connected to it. + IPC_MESSAGE_CONTROL0(DevToolsAgentMsg_Detach) + + // Sends glue-level Rpc message to the agent. + IPC_MESSAGE_CONTROL1(DevToolsAgentMsg_RpcMessage, + DevToolsMessageData /* message data */) + + // Send debugger command to the debugger agent. Debugger commands should + // be handled on IO thread(while all other devtools messages are handled in + // the render thread) to allow executing the commands when v8 is on a + // breakpoint. + IPC_MESSAGE_CONTROL1(DevToolsAgentMsg_DebuggerCommand, + std::string /* command */) + + // This command is sent to debugger when user wants to pause script execution + // immediately. This message should be processed on the IO thread so that it + // can have effect even if the Renderer thread is busy with JavaScript + // execution. + IPC_MESSAGE_CONTROL0(DevToolsAgentMsg_DebuggerPauseScript) + + // Inspect element with the given coordinates. + IPC_MESSAGE_CONTROL2(DevToolsAgentMsg_InspectElement, + int /* x */, + int /* y */) + + // Enables/disables the apu agent. + IPC_MESSAGE_CONTROL1(DevToolsAgentMsg_SetApuAgentEnabled, bool /* enabled */) + +IPC_END_MESSAGES(DevToolsAgent) diff --git a/chrome/common/dom_storage_common.h b/chrome/common/dom_storage_common.h new file mode 100644 index 0000000..96fc508 --- /dev/null +++ b/chrome/common/dom_storage_common.h @@ -0,0 +1,16 @@ +// Copyright (c) 2009 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 CHROME_COMMON_DOM_STORAGE_COMMON_H_ +#define CHROME_COMMON_DOM_STORAGE_COMMON_H_ + +const int64 kLocalStorageNamespaceId = 0; +const int64 kInvalidSessionStorageNamespaceId = kLocalStorageNamespaceId; + +enum DOMStorageType { + DOM_STORAGE_LOCAL = 0, + DOM_STORAGE_SESSION +}; + +#endif // CHROME_COMMON_DOM_STORAGE_COMMON_H_ diff --git a/chrome/common/edit_command.h b/chrome/common/edit_command.h new file mode 100644 index 0000000..4fc373e --- /dev/null +++ b/chrome/common/edit_command.h @@ -0,0 +1,24 @@ +// Copyright (c) 2009 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 CHROME_COMMON_EDIT_COMMAND_H_ +#define CHROME_COMMON_EDIT_COMMAND_H_ + +#include <string> +#include <vector> + +// Types related to sending edit commands to the renderer. +struct EditCommand { + EditCommand() { } + EditCommand(const std::string& n, const std::string& v) + : name(n), value(v) { + } + + std::string name; + std::string value; +}; + +typedef std::vector<EditCommand> EditCommands; + +#endif // CHROME_COMMON_EDIT_COMMAND_H_ diff --git a/chrome/common/env_vars.cc b/chrome/common/env_vars.cc new file mode 100644 index 0000000..dc2648c --- /dev/null +++ b/chrome/common/env_vars.cc @@ -0,0 +1,40 @@ +// Copyright (c) 2010 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 "chrome/common/env_vars.h" + +namespace env_vars { + +// We call running in unattended mode (for automated testing) "headless". +// This mode can be enabled using this variable or by the kNoErrorDialogs +// switch. +const char kHeadless[] = "CHROME_HEADLESS"; + +// The name of the log file. +const char kLogFileName[] = "CHROME_LOG_FILE"; + +// If this environment variable is set, Chrome on Windows will log +// to Event Tracing for Windows. +const char kEtwLogging[] = "CHROME_ETW_LOGGING"; + +// CHROME_CRASHED exists if a previous instance of chrome has crashed. This +// triggers the 'restart chrome' dialog. CHROME_RESTART contains the strings +// that are needed to show the dialog. +const char kShowRestart[] = "CHROME_CRASHED"; +const char kRestartInfo[] = "CHROME_RESTART"; + +// The strings RIGHT_TO_LEFT and LEFT_TO_RIGHT indicate the locale direction. +// For example, for Hebrew and Arabic locales, we use RIGHT_TO_LEFT so that the +// dialog is displayed using the right orientation. +const char kRtlLocale[] = "RIGHT_TO_LEFT"; +const char kLtrLocale[] = "LEFT_TO_RIGHT"; + +// If the out-of-process breakpad could not be installed, we set this variable +// according to the process. +const char kNoOOBreakpad[] = "NO_OO_BREAKPAD"; + +// Number of times to run a given startup_tests unit test. +const char kStartupTestsNumCycles[] = "STARTUP_TESTS_NUMCYCLES"; + +} // namespace env_vars diff --git a/chrome/common/env_vars.h b/chrome/common/env_vars.h new file mode 100644 index 0000000..1c5bc5d --- /dev/null +++ b/chrome/common/env_vars.h @@ -0,0 +1,24 @@ +// Copyright (c) 2010 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. + +// Defines all the environment variables used by Chrome. + +#ifndef CHROME_COMMON_ENV_VARS_H__ +#define CHROME_COMMON_ENV_VARS_H__ + +namespace env_vars { + +extern const char kHeadless[]; +extern const char kLogFileName[]; +extern const char kEtwLogging[]; +extern const char kShowRestart[]; +extern const char kRestartInfo[]; +extern const char kRtlLocale[]; +extern const char kLtrLocale[]; +extern const char kNoOOBreakpad[]; +extern const char kStartupTestsNumCycles[]; + +} // namespace env_vars + +#endif // CHROME_COMMON_ENV_VARS_H__ diff --git a/chrome/common/extra_defines.vsprops b/chrome/common/extra_defines.vsprops new file mode 100644 index 0000000..963972f --- /dev/null +++ b/chrome/common/extra_defines.vsprops @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="extra"
+ >
+</VisualStudioPropertySheet>
diff --git a/chrome/common/font_descriptor_mac.h b/chrome/common/font_descriptor_mac.h new file mode 100644 index 0000000..25ae9db --- /dev/null +++ b/chrome/common/font_descriptor_mac.h @@ -0,0 +1,32 @@ +// Copyright (c) 2010 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 CHROME_COMMON_FONT_DESCRIPTOR_MAC_H_ +#define CHROME_COMMON_FONT_DESCRIPTOR_MAC_H_ + +#include "base/string16.h" + +#ifdef __OBJC__ +@class NSFont; +#else +class NSFont; +#endif + +// Container to allow serializing an NSFont over IPC. +struct FontDescriptor { + explicit FontDescriptor(NSFont* font); + + FontDescriptor() : font_point_size(0) {} + + // Return an autoreleased NSFont corresponding to the font description. + NSFont* nsFont() const; + + // Name of the font. + string16 font_name; + + // Size in points. + float font_point_size; +}; + +#endif // CHROME_COMMON_FONT_DESCRIPTOR_MAC_H_ diff --git a/chrome/common/font_descriptor_mac.mm b/chrome/common/font_descriptor_mac.mm new file mode 100644 index 0000000..485c215 --- /dev/null +++ b/chrome/common/font_descriptor_mac.mm @@ -0,0 +1,20 @@ +// Copyright (c) 2010 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 "chrome/common/font_descriptor_mac.h" + +#include <Cocoa/Cocoa.h> + +#include "base/sys_string_conversions.h" + +FontDescriptor::FontDescriptor(NSFont* font) { + font_name = base::SysNSStringToUTF16([font fontName]); + font_point_size = [font pointSize]; +} + +NSFont* FontDescriptor::nsFont() const { + NSString* font_name_ns = base::SysUTF16ToNSString(font_name); + NSFont* font = [NSFont fontWithName:font_name_ns size:font_point_size]; + return font; +} diff --git a/chrome/common/font_descriptor_mac_unittest.mm b/chrome/common/font_descriptor_mac_unittest.mm new file mode 100644 index 0000000..442e8e2 --- /dev/null +++ b/chrome/common/font_descriptor_mac_unittest.mm @@ -0,0 +1,91 @@ +// Copyright (c) 2010 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 "chrome/common/font_descriptor_mac.h" + +#include <Cocoa/Cocoa.h> + +#include "base/logging.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/platform_test.h" + +namespace { + +class FontSerializationTest : public PlatformTest {}; + + +// Compare 2 fonts, make sure they point at the same font definition and have +// the same style. Only Bold & Italic style attributes are tested since those +// are the only ones we care about at the moment. +bool CompareFonts(NSFont* font1, NSFont* font2) { + ATSFontRef id1 = CTFontGetPlatformFont(reinterpret_cast<CTFontRef>(font1), 0); + ATSFontRef id2 = CTFontGetPlatformFont(reinterpret_cast<CTFontRef>(font2), 0); + + if (id1 != id2) { + LOG(ERROR) << "ATSFontRefs for " + << [[font1 fontName] UTF8String] + << " and " + << [[font2 fontName] UTF8String] + << " are different"; + return false; + } + + CGFloat size1 = [font1 pointSize]; + CGFloat size2 = [font2 pointSize]; + if (size1 != size2) { + LOG(ERROR) << "font sizes for " + << [[font1 fontName] UTF8String] << " (" << size1 << ")" + << "and" + << [[font2 fontName] UTF8String] << " (" << size2 << ")" + << " are different"; + return false; + } + + NSFontTraitMask traits1 = [[NSFontManager sharedFontManager] + traitsOfFont:font1]; + NSFontTraitMask traits2 = [[NSFontManager sharedFontManager] + traitsOfFont:font2]; + + bool is_bold1 = traits1 & NSBoldFontMask; + bool is_bold2 = traits2 & NSBoldFontMask; + bool is_italic1 = traits1 & NSItalicFontMask; + bool is_italic2 = traits2 & NSItalicFontMask; + + if (is_bold1 != is_bold2 || is_italic1 != is_italic2) { + LOG(ERROR) << "Style information for " + << [[font1 fontName] UTF8String] + << " and " + << [[font2 fontName] UTF8String] + << " are different"; + return false; + } + + return true; +} + +// Verify that serialization and deserialization of fonts with various styles +// is performed correctly by FontDescriptor. +TEST_F(FontSerializationTest, StyledFonts) { + NSFont* plain_font = [NSFont systemFontOfSize:12.0]; + ASSERT_TRUE(plain_font != nil); + FontDescriptor desc_plain(plain_font); + EXPECT_TRUE(CompareFonts(plain_font, desc_plain.nsFont())); + + NSFont* bold_font = [NSFont boldSystemFontOfSize:30.0]; + ASSERT_TRUE(bold_font != nil); + FontDescriptor desc_bold(bold_font); + EXPECT_TRUE(CompareFonts(bold_font, desc_bold.nsFont())); + + NSFont* italic_bold_font = + [[NSFontManager sharedFontManager] + fontWithFamily:@"Courier" + traits:(NSBoldFontMask | NSItalicFontMask) + weight:5 + size:18.0]; + ASSERT_TRUE(italic_bold_font != nil); + FontDescriptor desc_italic_bold(italic_bold_font); + EXPECT_TRUE(CompareFonts(italic_bold_font, desc_italic_bold.nsFont())); +} + +} // namsepace diff --git a/chrome/common/font_loader_mac.h b/chrome/common/font_loader_mac.h new file mode 100644 index 0000000..2ec42bc --- /dev/null +++ b/chrome/common/font_loader_mac.h @@ -0,0 +1,55 @@ +// Copyright (c) 2010 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 CHROME_COMMON_FONT_LOADER_MAC_H_ +#define CHROME_COMMON_FONT_LOADER_MAC_H_ + +#include <ApplicationServices/ApplicationServices.h> + +#include "base/shared_memory.h" +#include "base/string16.h" + +#ifdef __OBJC__ +@class NSFont; +#else +class NSFont; +#endif + +// Provides functionality to transmit fonts over IPC. +// +// Note about font formats: .dfont (datafork suitcase) fonts are currently not +// supported by this code since ATSFontActivateFromMemory() can't handle them +// directly. + +class FontLoader { + public: + // Load a font specified by |font_to_encode| into a shared memory buffer + // suitable for sending over IPC. + // + // On return: + // returns true on success, false on failure. + // |font_data| - shared memory buffer containing the raw data for the font + // file. + // |font_data_size| - size of data contained in |font_data|. + static bool LoadFontIntoBuffer(NSFont* font_to_encode, + base::SharedMemory* font_data, + uint32* font_data_size); + + // Given a shared memory buffer containing the raw data for a font file, load + // the font and return a container ref. + // + // |data| - A shared memory handle pointing to the raw data from a font file. + // |data_size| - Size of |data|. + // + // On return: + // returns true on success, false on failure. + // |font_container| - A font container corresponding to the designated font. + // The caller is responsible for releasing this value via ATSFontDeactivate() + // when done + static bool ATSFontContainerFromBuffer(base::SharedMemoryHandle font_data, + uint32 font_data_size, + ATSFontContainerRef* font_container); +}; + +#endif // CHROME_COMMON_FONT_LOADER_MAC_H_ diff --git a/chrome/common/font_loader_mac.mm b/chrome/common/font_loader_mac.mm new file mode 100644 index 0000000..849ae87 --- /dev/null +++ b/chrome/common/font_loader_mac.mm @@ -0,0 +1,116 @@ +// Copyright (c) 2010 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 "chrome/common/font_loader_mac.h" + +#import <Cocoa/Cocoa.h> + +#include "base/basictypes.h" +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/logging.h" +#include "base/mac_util.h" +#include "base/scoped_cftyperef.h" +#include "base/sys_string_conversions.h" + +// static +bool FontLoader::LoadFontIntoBuffer(NSFont* font_to_encode, + base::SharedMemory* font_data, + uint32* font_data_size) { + CHECK(font_data && font_data_size); + *font_data_size = 0; + + // Used only for logging. + std::string font_name([[font_to_encode fontName] UTF8String]); + + // Load appropriate NSFont. + if (!font_to_encode) { + LOG(ERROR) << "Failed to load font " << font_name; + return false; + } + + // NSFont -> ATSFontRef. + ATSFontRef ats_font = + CTFontGetPlatformFont(reinterpret_cast<CTFontRef>(font_to_encode), NULL); + if (!ats_font) { + LOG(ERROR) << "Conversion to ATSFontRef failed for " << font_name; + return false; + } + + // ATSFontRef -> File path. + // Warning: Calling this function on a font activated from memory will result + // in failure with a -50 - paramErr. This may occur if + // CreateCGFontFromBuffer() is called in the same process as this function + // e.g. when writing a unit test that exercises these two functions together. + // If said unit test were to load a system font and activate it from memory + // it becomes impossible for the system to the find the original file ref + // since the font now lives in memory as far as it's concerned. + FSRef font_fsref; + if (ATSFontGetFileReference(ats_font, &font_fsref) != noErr) { + LOG(ERROR) << "Failed to find font file for " << font_name; + return false; + } + FilePath font_path = FilePath(mac_util::PathFromFSRef(font_fsref)); + + // Load file into shared memory buffer. + int64 font_file_size_64 = -1; + if (!file_util::GetFileSize(font_path, &font_file_size_64)) { + LOG(ERROR) << "Couldn't get font file size for " << font_path.value(); + return false; + } + + if (font_file_size_64 <= 0 || font_file_size_64 >= kint32max) { + LOG(ERROR) << "Bad size for font file " << font_path.value(); + return false; + } + + int32 font_file_size_32 = static_cast<int32>(font_file_size_64); + if (!font_data->Create(L"", false, false, font_file_size_32)) { + LOG(ERROR) << "Failed to create shmem area for " << font_name; + return false; + } + + if (!font_data->Map(font_file_size_32)) { + LOG(ERROR) << "Failed to map shmem area for " << font_name; + return false; + } + + int32 amt_read = file_util::ReadFile(font_path, + reinterpret_cast<char*>(font_data->memory()), + font_file_size_32); + if (amt_read != font_file_size_32) { + LOG(ERROR) << "Failed to read font data for " << font_path.value(); + return false; + } + + *font_data_size = font_file_size_32; + return true; +} + +// static +bool FontLoader::ATSFontContainerFromBuffer(base::SharedMemoryHandle font_data, + uint32 font_data_size, + ATSFontContainerRef* font_container) +{ + CHECK(font_container); + + using base::SharedMemory; + DCHECK(SharedMemory::IsHandleValid(font_data)); + DCHECK_GT(font_data_size, 0U); + + SharedMemory shm(font_data, true); + if (!shm.Map(font_data_size)) + return false; + + // A value of 3 means the font is private and can't be seen by anyone else. + // This is the value used by WebKit when activating remote fonts. + const ATSFontContext kFontContextPrivate = 3; + OSStatus err = ATSFontActivateFromMemory(shm.memory(), font_data_size, + kFontContextPrivate, kATSFontFormatUnspecified, NULL, + kATSOptionFlagsDefault, font_container); + if (err != noErr || !font_container) + return false; + + return true; +} diff --git a/chrome/common/gears_api.h b/chrome/common/gears_api.h new file mode 100644 index 0000000..9aba014 --- /dev/null +++ b/chrome/common/gears_api.h @@ -0,0 +1,97 @@ +// Copyright (c) 2006-2008 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 header specifies extensions to the Chrome Plugin API to support Gears. + +#ifndef CHROME_COMMON_GEARS_API_H__ +#define CHROME_COMMON_GEARS_API_H__ + +#include "chrome/common/chrome_plugin_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// CommandIDs used when Chrome calls into Gears using CPP_HandleCommand. +// Note: do not change the enum values. We want to preserve backwards +// compatibility. +typedef enum { + // Ask gears to show its settings dialog. Typical usage is for the plugin + // to display it using a call to CPB_ShowHtmlDialog. No command_data is + // provided. + GEARSPLUGINCOMMAND_SHOW_SETTINGS = 0, + + // Ask gears to create a shortcut to a web page. command_data points + // to a GearsShortcutData struct. + GEARSPLUGINCOMMAND_CREATE_SHORTCUT = 1, + + // Query gears for the list of installed shortcuts. command_data points + // to a GearsShortcutList struct. + GEARSPLUGINCOMMAND_GET_SHORTCUT_LIST = 2, +} GearsPluginCommand; + +// CommandIDs used when Gears calls into Chrome using CPB_HandleCommand. +// Note: do not change the enum values. We want to preserve backwards +// compatibility. +typedef enum { + // Tell chrome that the GEARSPLUGINCOMMAND_CREATE_SHORTCUT command is done, + // and the user has closed the dialog. command_data points to the same + // GearsShortcutData struct that was passed to the plugin command. + GEARSBROWSERCOMMAND_CREATE_SHORTCUT_DONE = 1, + + // Notifies the browser of changes to the gears shortcuts database. + // command_data is null. + GEARSBROWSERCOMMAND_NOTIFY_SHORTCUTS_CHANGED = 3, +} GearsBrowserCommand; + +// Note: currently only 16x16, 32x32, 48x48, and 128x128 icons are supported. +typedef struct _GearsShortcutIcon { + const char* size; // unused + const char* url; // the URL of the icon, which should be a PNG image + int width; // width of the icon + int height; // height of the icon +} GearsShortcutIcon; + +// Command data for GEARSPLUGINCOMMAND_CREATE_SHORTCUT. +typedef struct _GearsShortcutData { + const char* name; // the shortcut's name (also used as the filename) + const char* url; // the URL that the shortcut should launch + const char* description; // an optional description + GearsShortcutIcon icons[4]; // list of icons to use for this shortcut +} GearsShortcutData; + +// Command data for GEARSPLUGINCOMMAND_CREATE_SHORTCUT used in 0.6 and later. +// This struct is backwards compatible with the first version. +// http://b/viewIssue?id=1331408 - Chrome sanitizes 'name' for compatibility +// with older versions of Gears that expect this. 'orig_name' is unsanitized, +// which allows Gears to do its own validation. +typedef struct _GearsShortcutData2 { + const char* name; // unused - for back compat with above struct + const char* url; // the URL that the shortcut should launch + const char* description; // an optional description + GearsShortcutIcon icons[4]; // list of icons to use for this shortcut + const char* orig_name; // the shortcut's unmodified filename (added in 0.6) +} GearsShortcutData2; + +// Command data for GEARSPLUGINCOMMAND_GET_SHORTCUT_LIST. +typedef struct _GearsShortcutList { + // Note: these are output params, set by Gears. There are no input params. + // Memory for these shortcuts, including the strings they hold, should be + // freed by the browser using CPB_Free. + GearsShortcutData* shortcuts; // array of installed shortcuts + uint32 num_shortcuts; // size of the array +} GearsShortcutList; + +// Command data for GEARSBROWSERCOMMAND_CREATE_SHORTCUT_DONE +typedef struct _GearsCreateShortcutResult { + GearsShortcutData2* shortcut; // pointer to struct passed to + // GEARSPLUGINCOMMAND_CREATE_SHORTCUT + CPError result; // CPERR_SUCCESS if shortcut was created, or error otherwise +} GearsCreateShortcutResult; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // CHROME_COMMON_GEARS_API_H_ diff --git a/chrome/common/geoposition.cc b/chrome/common/geoposition.cc new file mode 100644 index 0000000..f8f087c --- /dev/null +++ b/chrome/common/geoposition.cc @@ -0,0 +1,66 @@ +// Copyright (c) 2010 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 "chrome/common/geoposition.h" + +namespace { +// Sentinel values to mark invalid data. (WebKit carries companion is_valid +// bools for this purpose; we may eventually follow that approach, but +// sentinels worked OK in the gears code this is based on.) +const double kBadLatitudeLongitude = 200; +// Lowest point on land is at approximately -400 meters. +const int kBadAltitude = -10000; +const int kBadAccuracy = -1; // Accuracy must be non-negative. +const int64 kBadTimestamp = kint64min; +const int kBadHeading = -1; // Heading must be non-negative. +const int kBadSpeed = -1; +} + +Geoposition::Geoposition() + : latitude(kBadLatitudeLongitude), + longitude(kBadLatitudeLongitude), + altitude(kBadAltitude), + accuracy(kBadAccuracy), + altitude_accuracy(kBadAccuracy), + heading(kBadHeading), + speed(kBadSpeed), + error_code(ERROR_CODE_NONE) { +} + +bool Geoposition::is_valid_latlong() const { + return latitude >= -90.0 && latitude <= 90.0 && + longitude >= -180.0 && longitude <= 180.0; +} + +bool Geoposition::is_valid_altitude() const { + return altitude > kBadAltitude; +} + +bool Geoposition::is_valid_accuracy() const { + return accuracy >= 0.0; +} + +bool Geoposition::is_valid_altitude_accuracy() const { + return altitude_accuracy >= 0.0; +} + +bool Geoposition::is_valid_heading() const { + return heading >= 0 && heading <= 360; +} + +bool Geoposition::is_valid_speed() const { + return speed >= 0; +} + +bool Geoposition::is_valid_timestamp() const { + return !timestamp.is_null(); +} + +bool Geoposition::IsValidFix() const { + return is_valid_latlong() && is_valid_accuracy() && is_valid_timestamp(); +} + +bool Geoposition::IsInitialized() const { + return error_code != ERROR_CODE_NONE || IsValidFix(); +} diff --git a/chrome/common/geoposition.h b/chrome/common/geoposition.h new file mode 100644 index 0000000..f2db64c --- /dev/null +++ b/chrome/common/geoposition.h @@ -0,0 +1,64 @@ +// Copyright (c) 2010 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 declares the Position structure, which is used to represent a +// position fix. Originally derived from +// http://gears.googlecode.com/svn/trunk/gears/geolocation/geolocation.h + +#ifndef CHROME_COMMON_GEOPOSITION_H_ +#define CHROME_COMMON_GEOPOSITION_H_ + +#include <string> +#include "base/time.h" + +// The internal representation of a geo position. Some properties use different +// types when passed to JavaScript. +struct Geoposition { + public: + // Error codes for returning to JavaScript. These values are defined by the + // W3C spec. Note that Gears does not use all of these codes, but we need + // values for all of them to allow us to provide the constants on the error + // object. + enum ErrorCode { + ERROR_CODE_NONE = 0, // Chrome addition + ERROR_CODE_PERMISSION_DENIED = 1, + ERROR_CODE_POSITION_UNAVAILABLE = 2, + ERROR_CODE_TIMEOUT = 3, + }; + + Geoposition(); + + bool is_valid_latlong() const; + bool is_valid_altitude() const; + bool is_valid_accuracy() const; + bool is_valid_altitude_accuracy() const; + bool is_valid_heading() const; + bool is_valid_speed() const; + bool is_valid_timestamp() const; + + // A valid fix has a valid latitude, longitude, accuracy and timestamp. + bool IsValidFix() const; + + // A position is considered initialized if it has either a valid fix or + // an error code other than NONE. + bool IsInitialized() const; + + // These properties correspond to the JavaScript Position object. + double latitude; // In degrees + double longitude; // In degrees + double altitude; // In metres + double accuracy; // In metres + double altitude_accuracy; // In metres + double heading; // In degrees clockwise relative to the true north + double speed; // In meters per second + // Timestamp for this position fix object taken from the host computer's + // system clock (i.e. from Time::Now(), not the source device's clock). + base::Time timestamp; + + // These properties are returned to JavaScript as a PositionError object. + ErrorCode error_code; + std::string error_message; // Human-readable error message +}; + +#endif // CHROME_COMMON_GEOPOSITION_H_ diff --git a/chrome/common/googleurl_dummy.cc b/chrome/common/googleurl_dummy.cc new file mode 100644 index 0000000..f55c263 --- /dev/null +++ b/chrome/common/googleurl_dummy.cc @@ -0,0 +1,18 @@ +// Copyright (c) 2010 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. + +namespace url_util { + +// A dummy version of the url_util function called by url_constants.cc for all +// process types. For some processes, we don't want to link against googleurl. +// rather than having complicated versions of that library (32 and 64 bit ones +// on Windows) we just instead link this file in cases where googleurl isn't +// otherwise necessary. +void AddStandardScheme(const char* new_scheme) { +} + +void LockStandardSchemes() { +} + +} // namespace url_util diff --git a/chrome/common/gpu_info.cc b/chrome/common/gpu_info.cc new file mode 100644 index 0000000..b1add77 --- /dev/null +++ b/chrome/common/gpu_info.cc @@ -0,0 +1,41 @@ +// Copyright (c) 2006-2010 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 "chrome/common/gpu_info.h" + +GPUInfo::GPUInfo() + : vendor_id_(0), device_id_(0), driver_version_(L""), + pixel_shader_version_(0), vertex_shader_version_(0) { +} + +uint32 GPUInfo::vendor_id() const { + return vendor_id_; +} + +uint32 GPUInfo::device_id() const { + return device_id_; +} + +std::wstring GPUInfo::driver_version() const { + return driver_version_; +} + +uint32 GPUInfo::pixel_shader_version() const { + return pixel_shader_version_; +} + +uint32 GPUInfo::vertex_shader_version() const { + return vertex_shader_version_; +} + +void GPUInfo::SetGraphicsInfo(uint32 vendor_id, uint32 device_id, + const std::wstring& driver_version, + uint32 pixel_shader_version, + uint32 vertex_shader_version) { + vendor_id_ = vendor_id; + device_id_ = device_id; + driver_version_ = driver_version; + pixel_shader_version_ = pixel_shader_version; + vertex_shader_version_ = vertex_shader_version; +} diff --git a/chrome/common/gpu_info.h b/chrome/common/gpu_info.h new file mode 100644 index 0000000..65b5075 --- /dev/null +++ b/chrome/common/gpu_info.h @@ -0,0 +1,54 @@ +// Copyright (c) 2006-2010 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 CHROME_COMMON_GPU_INFO_H__ +#define CHROME_COMMON_GPU_INFO_H__ + +// Provides access to the GPU information for the system +// on which chrome is currently running. + +#include <string> + +#include "base/basictypes.h" + +class GPUInfo { + public: + GPUInfo(); + ~GPUInfo() {} + + // Return the DWORD (uint32) representing the graphics card vendor id. + uint32 vendor_id() const; + + // Return the DWORD (uint32) representing the graphics card device id. + // Device ids are unique to vendor, not to one another. + uint32 device_id() const; + + // Return the version of the graphics driver currently installed. + // This will typically be something + std::wstring driver_version() const; + + // Return the version of the pixel/fragment shader used by the gpu. + // This will typically be a number less than 10 so storing as a float + // should be okay. + uint32 pixel_shader_version() const; + + // Return the version of the vertex shader used by the gpu. + // This will typically be a number less than 10 so storing as a float + // should be okay. + uint32 vertex_shader_version() const; + + // Populate variables with passed in values + void SetGraphicsInfo(uint32 vendor_id, uint32 device_id, + const std::wstring& driver_version, + uint32 pixel_shader_version, + uint32 vertex_shader_version); + private: + uint32 vendor_id_; + uint32 device_id_; + std::wstring driver_version_; + uint32 pixel_shader_version_; + uint32 vertex_shader_version_; +}; + +#endif // CHROME_COMMON_GPU_INFO_H__ diff --git a/chrome/common/gpu_info_unittest.cc b/chrome/common/gpu_info_unittest.cc new file mode 100644 index 0000000..4d469f6 --- /dev/null +++ b/chrome/common/gpu_info_unittest.cc @@ -0,0 +1,17 @@ +// Copyright (c) 2006-2010 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/logging.h" +#include "chrome/common/gpu_info.h" +#include "testing/gtest/include/gtest/gtest.h" + +// Test that an empty GPUInfo has valid members +TEST(GPUInfoBasicTest, EmptyGPUInfo) { + GPUInfo gpu_info; + EXPECT_EQ(gpu_info.vendor_id(), 0u); + EXPECT_EQ(gpu_info.device_id(), 0u); + EXPECT_EQ(gpu_info.driver_version(), L""); + EXPECT_EQ(gpu_info.pixel_shader_version(), 0u); + EXPECT_EQ(gpu_info.vertex_shader_version(), 0u); +} diff --git a/chrome/common/gpu_messages.h b/chrome/common/gpu_messages.h new file mode 100644 index 0000000..16f2860 --- /dev/null +++ b/chrome/common/gpu_messages.h @@ -0,0 +1,87 @@ +// Copyright (c) 2010 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 CHROME_COMMON_GPU_MESSAGES_H_ +#define CHROME_COMMON_GPU_MESSAGES_H_ + +#include <vector> + +#include "app/surface/transport_dib.h" +#include "base/basictypes.h" +#include "base/process.h" +#include "chrome/common/common_param_traits.h" +#include "chrome/common/gpu_info.h" +#include "chrome/common/gpu_native_window_handle.h" +#include "gfx/native_widget_types.h" +#include "gfx/rect.h" +#include "gfx/size.h" +#include "gpu/command_buffer/common/command_buffer.h" + +namespace IPC { +template <> +struct ParamTraits<GPUInfo> { + typedef GPUInfo param_type; + static void Write(Message* m, const param_type& p) { + m->WriteUInt32(p.vendor_id()); + m->WriteUInt32(p.device_id()); + m->WriteWString(p.driver_version()); + m->WriteUInt32(p.pixel_shader_version()); + m->WriteUInt32(p.vertex_shader_version()); + } + static bool Read(const Message* m, void** iter, param_type* p) { + uint32 vendor_id; + uint32 device_id; + std::wstring driver_version; + uint32 pixel_shader_version; + uint32 vertex_shader_version; + bool ret = m->ReadUInt32(iter, &vendor_id); + ret = ret && m->ReadUInt32(iter, &device_id); + ret = ret && m->ReadWString(iter, &driver_version); + ret = ret && m->ReadUInt32(iter, &pixel_shader_version); + ret = ret && m->ReadUInt32(iter, &vertex_shader_version); + p->SetGraphicsInfo(vendor_id, device_id, driver_version, + pixel_shader_version, vertex_shader_version); + return ret; + } + static void Log(const param_type& p, std::wstring* l) { + l->append(StringPrintf(L"<GPUInfo> %x %x %ls", + p.vendor_id(), p.device_id(), p.driver_version().c_str())); + } +}; + +template <> +struct ParamTraits<gpu::CommandBuffer::State> { + typedef gpu::CommandBuffer::State param_type; + static void Write(Message* m, const param_type& p) { + m->WriteInt(p.num_entries); + m->WriteInt(p.get_offset); + m->WriteInt(p.put_offset); + m->WriteInt(p.token); + m->WriteInt(p.error); + } + static bool Read(const Message* m, void** iter, param_type* p) { + int32 temp; + if (m->ReadInt(iter, &p->num_entries) && + m->ReadInt(iter, &p->get_offset) && + m->ReadInt(iter, &p->put_offset) && + m->ReadInt(iter, &p->token) && + m->ReadInt(iter, &temp)) { + p->error = static_cast<gpu::error::Error>(temp); + return true; + } else { + return false; + } + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<CommandBuffer::State>"); + } +}; +} // namespace IPC + +#define MESSAGES_INTERNAL_FILE \ + "chrome/common/gpu_messages_internal.h" +#include "ipc/ipc_message_macros.h" + +#endif // CHROME_COMMON_GPU_MESSAGES_H_ + diff --git a/chrome/common/gpu_messages_internal.h b/chrome/common/gpu_messages_internal.h new file mode 100644 index 0000000..fa9a83f --- /dev/null +++ b/chrome/common/gpu_messages_internal.h @@ -0,0 +1,213 @@ +// Copyright (c) 2010 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 header is meant to be included in multiple passes, hence no traditional +// header guard. It is included by backing_store_messages_internal.h +// See ipc_message_macros.h for explanation of the macros and passes. + +// This file needs to be included again, even though we're actually included +// from it via utility_messages.h. +#include "base/shared_memory.h" +#include "chrome/common/gpu_info.h" +#include "gfx/size.h" +#include "ipc/ipc_channel_handle.h" +#include "ipc/ipc_message_macros.h" + +//------------------------------------------------------------------------------ +// GPU Messages +// These are messages from the browser to the GPU process. +IPC_BEGIN_MESSAGES(Gpu) + + // Tells the GPU process to create a new channel for communication with a + // given renderer. The channel name is returned in a + // GpuHostMsg_ChannelEstablished message. The renderer ID is passed so that + // the GPU process reuses an existing channel to that process if it exists. + // This ID is a unique opaque identifier generated by the browser process. + IPC_MESSAGE_CONTROL1(GpuMsg_EstablishChannel, + int /* renderer_id */) + + // Provides a synchronization point to guarantee that the processing of + // previous asynchronous messages (i.e., GpuMsg_EstablishChannel) has + // completed. (This message can't be synchronous because the + // GpuProcessHost uses an IPC::ChannelProxy, which sends all messages + // asynchronously.) Results in a GpuHostMsg_SynchronizeReply. + IPC_MESSAGE_CONTROL0(GpuMsg_Synchronize) + + IPC_MESSAGE_CONTROL2(GpuMsg_NewRenderWidgetHostView, + GpuNativeWindowHandle, /* parent window */ + int32 /* view_id */) + + // Creates a new backing store. + IPC_MESSAGE_ROUTED2(GpuMsg_NewBackingStore, + int32, /* backing_store_routing_id */ + gfx::Size /* size */) + + // Creates a new video layer. + IPC_MESSAGE_ROUTED2(GpuMsg_NewVideoLayer, + int32, /* video_layer_routing_id */ + gfx::Size /* size */) + + // Updates the backing store with the given bitmap. The GPU process will send + // back a GpuHostMsg_PaintToBackingStore_ACK after the paint is complete to + // let the caller know the TransportDIB can be freed or reused. + IPC_MESSAGE_ROUTED4(GpuMsg_PaintToBackingStore, + base::ProcessId, /* process */ + TransportDIB::Id, /* bitmap */ + gfx::Rect, /* bitmap_rect */ + std::vector<gfx::Rect>) /* copy_rects */ + + + IPC_MESSAGE_ROUTED4(GpuMsg_ScrollBackingStore, + int, /* dx */ + int, /* dy */ + gfx::Rect, /* clip_rect */ + gfx::Size) /* view_size */ + + // Tells the GPU process that the RenderWidgetHost has painted the window. + // Depending on the platform, the accelerated content may need to be painted + // over the top. + IPC_MESSAGE_ROUTED0(GpuMsg_WindowPainted) + + // Updates the video layer with the given YUV data. The GPU process will send + // back a GpuHostMsg_PaintToVideoLayer_ACK after the paint is complete to + // let the caller know the TransportDIB can be freed or reused. + IPC_MESSAGE_ROUTED3(GpuMsg_PaintToVideoLayer, + base::ProcessId, /* process */ + TransportDIB::Id, /* bitmap */ + gfx::Rect) /* bitmap_rect */ + +IPC_END_MESSAGES(Gpu) + +//------------------------------------------------------------------------------ +// GPU Host Messages +// These are messages from the GPU process to the browser. +IPC_BEGIN_MESSAGES(GpuHost) + + // Sent in response to GpuMsg_PaintToBackingStore, see that for more. + IPC_MESSAGE_ROUTED0(GpuHostMsg_PaintToBackingStore_ACK) + + // Sent in response to GpuMsg_PaintToVideoLayer, see that for more. + IPC_MESSAGE_ROUTED0(GpuHostMsg_PaintToVideoLayer_ACK) + + // Response to a GpuHostMsg_EstablishChannel message. + IPC_MESSAGE_CONTROL2(GpuHostMsg_ChannelEstablished, + IPC::ChannelHandle, /* channel_handle */ + GPUInfo /* GPU logging stats */) + + // Response to a GpuMsg_Synchronize message. + IPC_MESSAGE_CONTROL0(GpuHostMsg_SynchronizeReply) + +#if defined(OS_LINUX) + // Get the XID for a view ID. + IPC_SYNC_MESSAGE_CONTROL1_1(GpuHostMsg_GetViewXID, + gfx::NativeViewId, /* view */ + unsigned long /* xid */) +#endif + +IPC_END_MESSAGES(GpuHost) + +//------------------------------------------------------------------------------ +// GPU Channel Messages +// These are messages from a renderer process to the GPU process. +IPC_BEGIN_MESSAGES(GpuChannel) + + // Tells the GPU process to create a new command buffer that renders directly + // to a native view. A corresponding GpuCommandBufferStub is created. + IPC_SYNC_MESSAGE_CONTROL1_1(GpuChannelMsg_CreateViewCommandBuffer, + gfx::NativeViewId, /* view */ + int32 /* route_id */) + + // Tells the GPU process to create a new command buffer that renders to an + // offscreen frame buffer. If parent_route_id is not zero, the texture backing + // the frame buffer is mapped into the corresponding parent command buffer's + // namespace, with the name of parent_texture_id. This ID is in the parent's + // namespace. + IPC_SYNC_MESSAGE_CONTROL3_1(GpuChannelMsg_CreateOffscreenCommandBuffer, + int32, /* parent_route_id */ + gfx::Size, /* size */ + uint32, /* parent_texture_id */ + int32 /* route_id */) + + // The CommandBufferProxy sends this to the GpuCommandBufferStub in its + // destructor, so that the stub deletes the actual WebPluginDelegateImpl + // object that it's hosting. + // TODO(apatrick): Implement this. + IPC_MESSAGE_CONTROL1(GpuChannelMsg_DestroyCommandBuffer, + int32 /* instance_id */) + +IPC_END_MESSAGES(GpuChannel) + +//------------------------------------------------------------------------------ +// GPU Command Buffer Messages +// These are messages from a renderer process to the GPU process relating to a +// single OpenGL context. +IPC_BEGIN_MESSAGES(GpuCommandBuffer) + // Initialize a command buffer with the given number of command entries. + // Returns the shared memory handle for the command buffer mapped to the + // calling process. + IPC_SYNC_MESSAGE_ROUTED1_1(GpuCommandBufferMsg_Initialize, + int32 /* size */, + base::SharedMemoryHandle /* ring_buffer */) + + // Get the current state of the command buffer. + IPC_SYNC_MESSAGE_ROUTED0_1(GpuCommandBufferMsg_GetState, + gpu::CommandBuffer::State /* state */) + + // Get the current state of the command buffer asynchronously. State is + // returned via UpdateState message. + IPC_MESSAGE_ROUTED0(GpuCommandBufferMsg_AsyncGetState) + + // Synchronize the put and get offsets of both processes. Caller passes its + // current put offset. Current state (including get offset) is returned. + IPC_SYNC_MESSAGE_ROUTED1_1(GpuCommandBufferMsg_Flush, + int32 /* put_offset */, + gpu::CommandBuffer::State /* state */) + + // Asynchronously synchronize the put and get offsets of both processes. + // Caller passes its current put offset. Current state (including get offset) + // is returned via an UpdateState message. + IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_AsyncFlush, + int32 /* put_offset */) + + // Return the current state of the command buffer following a request via + // an AsyncGetState or AsyncFlush message. + IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_UpdateState, + gpu::CommandBuffer::State /* state */) + + // Create a shared memory transfer buffer. Returns an id that can be used to + // identify the transfer buffer from a comment. + IPC_SYNC_MESSAGE_ROUTED1_1(GpuCommandBufferMsg_CreateTransferBuffer, + int32 /* size */, + int32 /* id */) + + // Destroy a previously created transfer buffer. + IPC_SYNC_MESSAGE_ROUTED1_0(GpuCommandBufferMsg_DestroyTransferBuffer, + int32 /* id */) + + // Get the shared memory handle for a transfer buffer mapped to the callers + // process. + IPC_SYNC_MESSAGE_ROUTED1_2(GpuCommandBufferMsg_GetTransferBuffer, + int32 /* id */, + base::SharedMemoryHandle /* transfer_buffer */, + uint32 /* size */) + + // Send from command buffer stub to proxy when window is invalid and must be + // repainted. + IPC_MESSAGE_ROUTED0(GpuCommandBufferMsg_NotifyRepaint) + + // Tells the GPU process to resize an offscreen frame buffer. + IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_ResizeOffscreenFrameBuffer, + gfx::Size /* size */) + +#if defined(OS_MACOSX) + // On Mac OS X the GPU plugin must be offscreen, because there is no + // true cross-process window hierarchy. For this reason we must send + // resize events explicitly to the command buffer stub so it can + // reallocate its backing store and send the new one back to the + // browser. This message is currently used only on 10.6 and later. + IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_SetWindowSize, + gfx::Size /* size */) +#endif + +IPC_END_MESSAGES(GpuCommandBuffer) diff --git a/chrome/common/gpu_messages_unittest.cc b/chrome/common/gpu_messages_unittest.cc new file mode 100644 index 0000000..5215949 --- /dev/null +++ b/chrome/common/gpu_messages_unittest.cc @@ -0,0 +1,35 @@ +// Copyright (c) 2006-2010 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/logging.h" +#include "base/scoped_ptr.h" +#include "chrome/common/gpu_info.h" +#include "chrome/common/gpu_messages.h" +#include "ipc/ipc_message.h" +#include "ipc/ipc_message_utils.h" +#include "testing/gtest/include/gtest/gtest.h" + +// Test GPUInfo serialization +TEST(GPUIPCMessageTest, GPUInfo) { + GPUInfo input; + // Test variables taken from Lenovo T61 + input.SetGraphicsInfo(0x10de, 0x429, L"6.14.11.7715", + 0xffff0300, 0xfffe0300); + + IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); + IPC::WriteParam(&msg, input); + + GPUInfo output; + void* iter = NULL; + EXPECT_TRUE(IPC::ReadParam(&msg, &iter, &output)); + EXPECT_EQ(input.vendor_id(), output.vendor_id()); + EXPECT_EQ(input.device_id(), output.device_id()); + EXPECT_EQ(input.driver_version(), output.driver_version()); + EXPECT_EQ(input.pixel_shader_version(), output.pixel_shader_version()); + EXPECT_EQ(input.vertex_shader_version(), output.vertex_shader_version()); + + std::wstring log_message; + IPC::LogParam(output, &log_message); + EXPECT_STREQ(L"<GPUInfo> 10de 429 6.14.11.7715", log_message.c_str()); +} diff --git a/chrome/common/gpu_native_window_handle.h b/chrome/common/gpu_native_window_handle.h new file mode 100644 index 0000000..11e8cda --- /dev/null +++ b/chrome/common/gpu_native_window_handle.h @@ -0,0 +1,41 @@ +// Copyright (c) 2010 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 CHROME_COMMON_GPU_NATIVE_WINDOW_HANDLE_H_ +#define CHROME_COMMON_GPU_NATIVE_WINDOW_HANDLE_H_ + +#include "build/build_config.h" + +// This file defines the window handle type used by the GPU process IPC layer. +// This is different than gfx::NativeWindow[Id] since on X, this is an XID. +// Normally, Chrome deals with either GTK window pointers, or magic window +// IDs that the app generates. The GPU process needs to know the real XID. + +#if defined(OS_WIN) + +#include <windows.h> + +typedef HWND GpuNativeWindowHandle; + +#elif defined(OS_MACOSX) + +// The GPU process isn't supported on Mac yet. Defining this arbitrarily allows +// us to not worry about the integration points not compiling. +typedef int GpuNativeWindowHandle; + +#elif defined(USE_X11) + +// Forward declar XID ourselves to avoid pulling in all of the X headers, which +// can cause compile problems for some parts of the project. +typedef unsigned long XID; + +typedef XID GpuNativeWindowHandle; + +#else + +#error define GpuNativeWindowHandle + +#endif + +#endif // CHROME_COMMON_GPU_NATIVE_WINDOW_HANDLE_H_ diff --git a/chrome/common/gpu_plugin.cc b/chrome/common/gpu_plugin.cc new file mode 100644 index 0000000..af009f9 --- /dev/null +++ b/chrome/common/gpu_plugin.cc @@ -0,0 +1,44 @@ +// Copyright (c) 2009 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 "chrome/common/gpu_plugin.h" + +#include "base/command_line.h" +#include "base/string_util.h" +#include "chrome/common/chrome_switches.h" +#include "gpu/gpu_plugin/gpu_plugin.h" +#include "webkit/glue/plugins/plugin_list.h" + +#if defined(ENABLE_GPU) +#include "webkit/glue/plugins/plugin_constants_win.h" +#endif + +namespace chrome { + +void RegisterInternalGPUPlugin() { +#if defined(ENABLE_GPU) + static const std::wstring kWideMimeType = ASCIIToWide(kGPUPluginMimeType); + static const NPAPI::PluginVersionInfo kGPUPluginInfo = { + FilePath(FILE_PATH_LITERAL("gpu-plugin")), + L"GPU Plug-in", + L"GPU Rendering Plug-in", + L"1", + kWideMimeType.c_str(), + L"", + L"", + { +#if !defined(OS_POSIX) || defined(OS_MACOSX) + gpu_plugin::NP_GetEntryPoints, +#endif + gpu_plugin::NP_Initialize, + gpu_plugin::NP_Shutdown + } + }; + + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableGPUPlugin)) + NPAPI::PluginList::Singleton()->RegisterInternalPlugin(kGPUPluginInfo); +#endif // ENABLE_GPU +} + +} // namespace chrome diff --git a/chrome/common/gpu_plugin.h b/chrome/common/gpu_plugin.h new file mode 100644 index 0000000..3fd609e --- /dev/null +++ b/chrome/common/gpu_plugin.h @@ -0,0 +1,15 @@ +// Copyright (c) 2009 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 CHROME_COMMON_GPU_PLUGIN_H_ +#define CHROME_COMMON_GPU_PLUGIN_H_ + +namespace chrome { + +// Register the GPU plugin as an internal plugin in the PluginList. +void RegisterInternalGPUPlugin(); + +} // namespace chrome + +#endif // CHROME_COMMON_GPU_PLUGIN_H_ diff --git a/chrome/common/important_file_writer.cc b/chrome/common/important_file_writer.cc new file mode 100644 index 0000000..3466958 --- /dev/null +++ b/chrome/common/important_file_writer.cc @@ -0,0 +1,150 @@ +// Copyright (c) 2010 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 "chrome/common/important_file_writer.h" + +#include <stdio.h> + +#include <ostream> +#include <string> + +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/logging.h" +#include "base/message_loop_proxy.h" +#include "base/string_util.h" +#include "base/task.h" +#include "base/thread.h" +#include "base/time.h" + +using base::TimeDelta; + +namespace { + +const int kDefaultCommitIntervalMs = 10000; + +class WriteToDiskTask : public Task { + public: + WriteToDiskTask(const FilePath& path, const std::string& data) + : path_(path), + data_(data) { + } + + virtual void Run() { + // Write the data to a temp file then rename to avoid data loss if we crash + // while writing the file. Ensure that the temp file is on the same volume + // as target file, so it can be moved in one step, and that the temp file + // is securely created. + FilePath tmp_file_path; + FILE* tmp_file = file_util::CreateAndOpenTemporaryFileInDir( + path_.DirName(), &tmp_file_path); + if (!tmp_file) { + LogFailure("could not create temporary file"); + return; + } + + size_t bytes_written = fwrite(data_.data(), 1, data_.length(), tmp_file); + if (!file_util::CloseFile(tmp_file)) { + file_util::Delete(tmp_file_path, false); + LogFailure("failed to close temporary file"); + return; + } + if (bytes_written < data_.length()) { + file_util::Delete(tmp_file_path, false); + LogFailure("error writing, bytes_written=" + UintToString( + static_cast<unsigned int>(bytes_written))); + return; + } + + if (file_util::ReplaceFile(tmp_file_path, path_)) { + LogSuccess(); + return; + } + + file_util::Delete(tmp_file_path, false); + LogFailure("could not rename temporary file"); + } + + private: + void LogSuccess() { + LOG(INFO) << "successfully saved " << path_.value(); + } + + void LogFailure(const std::string& message) { + LOG(WARNING) << "failed to write " << path_.value() + << ": " << message; + } + + const FilePath path_; + const std::string data_; + + DISALLOW_COPY_AND_ASSIGN(WriteToDiskTask); +}; + +} // namespace + +ImportantFileWriter::ImportantFileWriter( + const FilePath& path, base::MessageLoopProxy* file_message_loop_proxy) + : path_(path), + file_message_loop_proxy_(file_message_loop_proxy), + serializer_(NULL), + commit_interval_(TimeDelta::FromMilliseconds( + kDefaultCommitIntervalMs)) { + DCHECK(CalledOnValidThread()); + DCHECK(file_message_loop_proxy_.get()); +} + +ImportantFileWriter::~ImportantFileWriter() { + // We're usually a member variable of some other object, which also tends + // to be our serializer. It may not be safe to call back to the parent object + // being destructed. + DCHECK(!HasPendingWrite()); +} + +bool ImportantFileWriter::HasPendingWrite() const { + DCHECK(CalledOnValidThread()); + return timer_.IsRunning(); +} + +void ImportantFileWriter::WriteNow(const std::string& data) { + DCHECK(CalledOnValidThread()); + + if (HasPendingWrite()) + timer_.Stop(); + + // TODO(sanjeevr): Add a DCHECK for the return value of PostTask. + // (Some tests fail if we add the DCHECK and they need to be fixed first). + file_message_loop_proxy_->PostTask(FROM_HERE, + new WriteToDiskTask(path_, data)); +} + +void ImportantFileWriter::ScheduleWrite(DataSerializer* serializer) { + DCHECK(CalledOnValidThread()); + + DCHECK(serializer); + serializer_ = serializer; + + if (!MessageLoop::current()) { + // Happens in unit tests. + DoScheduledWrite(); + return; + } + + if (!timer_.IsRunning()) { + timer_.Start(commit_interval_, this, + &ImportantFileWriter::DoScheduledWrite); + } +} + +void ImportantFileWriter::DoScheduledWrite() { + DCHECK(serializer_); + std::string data; + if (serializer_->SerializeData(&data)) { + WriteNow(data); + } else { + LOG(WARNING) << "failed to serialize data to be saved in " + << path_.value(); + } + serializer_ = NULL; +} diff --git a/chrome/common/important_file_writer.h b/chrome/common/important_file_writer.h new file mode 100644 index 0000000..d4f57a0 --- /dev/null +++ b/chrome/common/important_file_writer.h @@ -0,0 +1,112 @@ +// Copyright (c) 2009 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 CHROME_COMMON_IMPORTANT_FILE_WRITER_H_ +#define CHROME_COMMON_IMPORTANT_FILE_WRITER_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/file_path.h" +#include "base/non_thread_safe.h" +#include "base/ref_counted.h" +#include "base/time.h" +#include "base/timer.h" + +namespace base { +class MessageLoopProxy; +class Thread; +} + +// Helper to ensure that a file won't be corrupted by the write (for example on +// application crash). Consider a naive way to save an important file F: +// +// 1. Open F for writing, truncating it. +// 2. Write new data to F. +// +// It's good when it works, but it gets very bad if step 2. doesn't complete. +// It can be caused by a crash, a computer hang, or a weird I/O error. And you +// end up with a broken file. +// +// To be safe, we don't start with writing directly to F. Instead, we write to +// to a temporary file. Only after that write is successful, we rename the +// temporary file to target filename. +// +// If you want to know more about this approach and ext3/ext4 fsync issues, see +// http://valhenson.livejournal.com/37921.html +class ImportantFileWriter : public NonThreadSafe { + public: + // Used by ScheduleSave to lazily provide the data to be saved. Allows us + // to also batch data serializations. + class DataSerializer { + public: + virtual ~DataSerializer() {} + + // Should put serialized string in |data| and return true on successful + // serialization. Will be called on the same thread on which + // ImportantFileWriter has been created. + virtual bool SerializeData(std::string* data) = 0; + }; + + // Initialize the writer. + // |path| is the name of file to write. + // |file_message_loop_proxy| is the MessageLoopProxy for a thread on which + // file I/O can be done. + // All non-const methods, ctor and dtor must be called on the same thread. + ImportantFileWriter(const FilePath& path, + base::MessageLoopProxy* file_message_loop_proxy); + + // You have to ensure that there are no pending writes at the moment + // of destruction. + ~ImportantFileWriter(); + + FilePath path() const { return path_; } + + // Returns true if there is a scheduled write pending which has not yet + // been started. + bool HasPendingWrite() const; + + // Save |data| to target filename. Does not block. If there is a pending write + // scheduled by ScheduleWrite, it is cancelled. + void WriteNow(const std::string& data); + + // Schedule a save to target filename. Data will be serialized and saved + // to disk after the commit interval. If another ScheduleWrite is issued + // before that, only one serialization and write to disk will happen, and + // the most recent |serializer| will be used. This operation does not block. + // |serializer| should remain valid through the lifetime of + // ImportantFileWriter. + void ScheduleWrite(DataSerializer* serializer); + + // Serialize data pending to be saved and execute write on backend thread. + void DoScheduledWrite(); + + base::TimeDelta commit_interval() const { + return commit_interval_; + } + + void set_commit_interval(const base::TimeDelta& interval) { + commit_interval_ = interval; + } + + private: + // Path being written to. + const FilePath path_; + + // MessageLoopProxy for the thread on which file I/O can be done. + scoped_refptr<base::MessageLoopProxy> file_message_loop_proxy_; + + // Timer used to schedule commit after ScheduleWrite. + base::OneShotTimer<ImportantFileWriter> timer_; + + // Serializer which will provide the data to be saved. + DataSerializer* serializer_; + + // Time delta after which scheduled data will be written to disk. + base::TimeDelta commit_interval_; + + DISALLOW_COPY_AND_ASSIGN(ImportantFileWriter); +}; + +#endif // CHROME_COMMON_IMPORTANT_FILE_WRITER_H_ diff --git a/chrome/common/important_file_writer_unittest.cc b/chrome/common/important_file_writer_unittest.cc new file mode 100644 index 0000000..3d44ae0 --- /dev/null +++ b/chrome/common/important_file_writer_unittest.cc @@ -0,0 +1,115 @@ +// Copyright (c) 2009 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 "chrome/common/important_file_writer.h" + +#include "base/compiler_specific.h" +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/logging.h" +#include "base/message_loop.h" +#include "base/scoped_temp_dir.h" +#include "base/thread.h" +#include "base/time.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +std::string GetFileContent(const FilePath& path) { + std::string content; + if (!file_util::ReadFileToString(path, &content)) { + NOTREACHED(); + } + return content; +} + +class DataSerializer : public ImportantFileWriter::DataSerializer { + public: + explicit DataSerializer(const std::string& data) : data_(data) { + } + + virtual bool SerializeData(std::string* output) { + output->assign(data_); + return true; + } + + private: + const std::string data_; +}; + +} // namespace + +class ImportantFileWriterTest : public testing::Test { + public: + ImportantFileWriterTest() { } + virtual void SetUp() { + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + file_ = temp_dir_.path().AppendASCII("test-file"); + } + + protected: + FilePath file_; + MessageLoop loop_; + + private: + ScopedTempDir temp_dir_; +}; + +TEST_F(ImportantFileWriterTest, Basic) { + ImportantFileWriter writer(file_, + base::MessageLoopProxy::CreateForCurrentThread()); + EXPECT_FALSE(file_util::PathExists(writer.path())); + writer.WriteNow("foo"); + loop_.RunAllPending(); + + ASSERT_TRUE(file_util::PathExists(writer.path())); + EXPECT_EQ("foo", GetFileContent(writer.path())); +} + +TEST_F(ImportantFileWriterTest, ScheduleWrite) { + ImportantFileWriter writer(file_, + base::MessageLoopProxy::CreateForCurrentThread()); + writer.set_commit_interval(base::TimeDelta::FromMilliseconds(25)); + EXPECT_FALSE(writer.HasPendingWrite()); + DataSerializer serializer("foo"); + writer.ScheduleWrite(&serializer); + EXPECT_TRUE(writer.HasPendingWrite()); + MessageLoop::current()->PostDelayedTask(FROM_HERE, + new MessageLoop::QuitTask(), 100); + MessageLoop::current()->Run(); + EXPECT_FALSE(writer.HasPendingWrite()); + ASSERT_TRUE(file_util::PathExists(writer.path())); + EXPECT_EQ("foo", GetFileContent(writer.path())); +} + +TEST_F(ImportantFileWriterTest, DoScheduledWrite) { + ImportantFileWriter writer(file_, + base::MessageLoopProxy::CreateForCurrentThread()); + EXPECT_FALSE(writer.HasPendingWrite()); + DataSerializer serializer("foo"); + writer.ScheduleWrite(&serializer); + EXPECT_TRUE(writer.HasPendingWrite()); + writer.DoScheduledWrite(); + MessageLoop::current()->PostDelayedTask(FROM_HERE, + new MessageLoop::QuitTask(), 100); + MessageLoop::current()->Run(); + EXPECT_FALSE(writer.HasPendingWrite()); + ASSERT_TRUE(file_util::PathExists(writer.path())); + EXPECT_EQ("foo", GetFileContent(writer.path())); +} + +TEST_F(ImportantFileWriterTest, BatchingWrites) { + ImportantFileWriter writer(file_, + base::MessageLoopProxy::CreateForCurrentThread()); + writer.set_commit_interval(base::TimeDelta::FromMilliseconds(25)); + DataSerializer foo("foo"), bar("bar"), baz("baz"); + writer.ScheduleWrite(&foo); + writer.ScheduleWrite(&bar); + writer.ScheduleWrite(&baz); + MessageLoop::current()->PostDelayedTask(FROM_HERE, + new MessageLoop::QuitTask(), 100); + MessageLoop::current()->Run(); + ASSERT_TRUE(file_util::PathExists(writer.path())); + EXPECT_EQ("baz", GetFileContent(writer.path())); +} diff --git a/chrome/common/indexed_db_key.cc b/chrome/common/indexed_db_key.cc new file mode 100644 index 0000000..1c09ea2 --- /dev/null +++ b/chrome/common/indexed_db_key.cc @@ -0,0 +1,54 @@ +// Copyright (c) 2010 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 "chrome/common/indexed_db_key.h" + +#include "base/logging.h" +#include "third_party/WebKit/WebKit/chromium/public/WebString.h" + +using WebKit::WebIDBKey; + +IndexedDBKey::IndexedDBKey() + : type_(WebIDBKey::InvalidType) { +} + +IndexedDBKey::IndexedDBKey(const WebIDBKey& key) + : type_(key.type()), + string_(key.type() == WebIDBKey::StringType + ? static_cast<string16>(key.string()) : string16()), + number_(key.type() == WebIDBKey::NumberType ? key.number() : 0) { +} + +void IndexedDBKey::SetNull() { + type_ = WebIDBKey::NullType; +} + +void IndexedDBKey::SetInvalid() { + type_ = WebIDBKey::InvalidType; +} + +void IndexedDBKey::Set(const string16& string) { + type_ = WebIDBKey::StringType; + string_ = string; +} + +void IndexedDBKey::Set(int32_t number) { + type_ = WebIDBKey::NumberType; + number_ = number; +} + +IndexedDBKey::operator WebIDBKey() const { + switch (type_) { + case WebIDBKey::NullType: + return WebIDBKey::createNull(); + case WebIDBKey::StringType: + return WebIDBKey(string_); + case WebIDBKey::NumberType: + return WebIDBKey(number_); + case WebIDBKey::InvalidType: + return WebIDBKey::createInvalid(); + } + NOTREACHED(); + return WebIDBKey::createInvalid(); +} diff --git a/chrome/common/indexed_db_key.h b/chrome/common/indexed_db_key.h new file mode 100644 index 0000000..13bfae3 --- /dev/null +++ b/chrome/common/indexed_db_key.h @@ -0,0 +1,34 @@ +// Copyright (c) 2010 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 CHROME_COMMON_INDEXED_DB_KEY_H_ +#define CHROME_COMMON_INDEXED_DB_KEY_H_ + +#include "base/basictypes.h" +#include "base/string16.h" +#include "third_party/WebKit/WebKit/chromium/public/WebIDBKey.h" + +class IndexedDBKey { + public: + IndexedDBKey(); // Defaults to WebKit::WebIDBKey::InvalidType. + explicit IndexedDBKey(const WebKit::WebIDBKey& key); + + void SetNull(); + void SetInvalid(); + void Set(const string16& string); + void Set(int32_t number); + + WebKit::WebIDBKey::Type type() const { return type_; } + const string16& string() const { return string_; } + int32_t number() const { return number_; } + + operator WebKit::WebIDBKey() const; + + private: + WebKit::WebIDBKey::Type type_; + string16 string_; + int32_t number_; +}; + +#endif // CHROME_COMMON_INDEXED_DB_KEY_H_ diff --git a/chrome/common/ipc_test_sink.cc b/chrome/common/ipc_test_sink.cc new file mode 100644 index 0000000..04fd065 --- /dev/null +++ b/chrome/common/ipc_test_sink.cc @@ -0,0 +1,57 @@ +// Copyright (c) 2010 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 "chrome/common/ipc_test_sink.h" + +namespace IPC { + +TestSink::TestSink() { +} + +TestSink::~TestSink() { +} + +bool TestSink::Send(IPC::Message* message) { + OnMessageReceived(*message); + delete message; + return true; +} + +void TestSink::OnMessageReceived(const Message& msg) { + messages_.push_back(Message(msg)); +} + +void TestSink::ClearMessages() { + messages_.clear(); +} + +const Message* TestSink::GetMessageAt(size_t index) const { + if (index >= messages_.size()) + return NULL; + return &messages_[index]; +} + +const Message* TestSink::GetFirstMessageMatching(uint32 id) const { + for (size_t i = 0; i < messages_.size(); i++) { + if (messages_[i].type() == id) + return &messages_[i]; + } + return NULL; +} + +const Message* TestSink::GetUniqueMessageMatching(uint32 id) const { + size_t found_index = 0; + size_t found_count = 0; + for (size_t i = 0; i < messages_.size(); i++) { + if (messages_[i].type() == id) { + found_count++; + found_index = i; + } + } + if (found_count != 1) + return NULL; // Didn't find a unique one. + return &messages_[found_index]; +} + +} // namespace IPC diff --git a/chrome/common/ipc_test_sink.h b/chrome/common/ipc_test_sink.h new file mode 100644 index 0000000..96e91c0 --- /dev/null +++ b/chrome/common/ipc_test_sink.h @@ -0,0 +1,89 @@ +// Copyright (c) 2010 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 CHROME_COMMON_IPC_TEST_SINK_H_ +#define CHROME_COMMON_IPC_TEST_SINK_H_ + +#include <utility> +#include <vector> + +#include "base/basictypes.h" +#include "ipc/ipc_channel.h" +#include "ipc/ipc_message.h" + +namespace IPC { + +// This test sink provides a "sink" for IPC messages that are sent. It allows +// the caller to query messages received in various different ways. It is +// designed for tests for objects that use the IPC system. +// +// Typical usage: +// +// test_sink.ClearMessages(); +// do_something(); +// +// // We should have gotten exactly one update state message. +// EXPECT_TRUE(test_sink.GetUniqeMessageMatching(ViewHostMsg_Update::ID)); +// // ...and no start load messages. +// EXPECT_FALSE(test_sink.GetFirstMessageMatching(ViewHostMsg_Start::ID)); +// +// // Now inspect a message. This assumes a message that was declared like +// // this: IPC_MESSAGE_ROUTED2(ViewMsg_Foo, bool, int) +// IPC::Message* msg = test_sink.GetFirstMessageMatching(ViewMsg_Foo::ID)); +// ASSERT_TRUE(msg); +// bool first_param; +// int second_param; +// ViewMsg_Foo::Read(msg, &first_param, &second_param); +// +// // Go on to the next phase of the test. +// test_sink.ClearMessages(); +// +// To hook up the sink, all you need to do is call OnMessageReceived when a +// message is received. +class TestSink : public IPC::Channel { + public: + TestSink(); + ~TestSink(); + + // Interface in IPC::Channel. This copies the message to the sink and then + // deletes it. + virtual bool Send(IPC::Message* message); + + // Used by the source of the messages to send the message to the sink. This + // will make a copy of the message and store it in the list. + void OnMessageReceived(const Message& msg); + + // Returns the number of messages in the queue. + size_t message_count() const { return messages_.size(); } + + // Clears the message queue of saved messages. + void ClearMessages(); + + // Returns the message at the given index in the queue. The index may be out + // of range, in which case the return value is NULL. The returned pointer will + // only be valid until another message is received or the list is cleared. + const Message* GetMessageAt(size_t index) const; + + // Returns the first message with the given ID in the queue. If there is no + // message with the given ID, returns NULL. The returned pointer will only be + // valid until another message is received or the list is cleared. + const Message* GetFirstMessageMatching(uint32 id) const; + + // Returns the message with the given ID in the queue. If there is no such + // message or there is more than one of that message, this will return NULL + // (with the expectation that you'll do an ASSERT_TRUE() on the result). + // The returned pointer will only be valid until another message is received + // or the list is cleared. + const Message* GetUniqueMessageMatching(uint32 id) const; + + private: + // The actual list of received messages. + std::vector<Message> messages_; + + DISALLOW_COPY_AND_ASSIGN(TestSink); +}; + +} // namespace IPC + +#endif // CHROME_COMMON_IPC_TEST_SINK_H_ diff --git a/chrome/common/json_pref_store.cc b/chrome/common/json_pref_store.cc new file mode 100644 index 0000000..9acfcb2 --- /dev/null +++ b/chrome/common/json_pref_store.cc @@ -0,0 +1,130 @@ +// Copyright (c) 2010 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 "chrome/common/json_pref_store.h" + +#include <algorithm> + +#include "base/file_util.h" +#include "base/values.h" +#include "chrome/common/json_value_serializer.h" + +namespace { + +// Some extensions we'll tack on to copies of the Preferences files. +const FilePath::CharType* kBadExtension = FILE_PATH_LITERAL("bad"); + +} // namespace + +JsonPrefStore::JsonPrefStore(const FilePath& filename, + base::MessageLoopProxy* file_message_loop_proxy) + : path_(filename), + prefs_(new DictionaryValue()), + read_only_(false), + writer_(filename, file_message_loop_proxy) { +} + +JsonPrefStore::~JsonPrefStore() { + if (writer_.HasPendingWrite() && !read_only_) + writer_.DoScheduledWrite(); +} + +PrefStore::PrefReadError JsonPrefStore::ReadPrefs() { + JSONFileValueSerializer serializer(path_); + + int error_code = 0; + std::string error_msg; + scoped_ptr<Value> value(serializer.Deserialize(&error_code, &error_msg)); + if (!value.get()) { +#if defined(GOOGLE_CHROME_BUILD) + // This log could be used for more detailed client-side error diagnosis, + // but since this triggers often with unit tests, we need to disable it + // in non-official builds. + PLOG(ERROR) << "Error reading Preferences: " << error_msg << " " << + path_.value(); +#endif + PrefReadError error; + switch (error_code) { + case JSONFileValueSerializer::JSON_ACCESS_DENIED: + // If the file exists but is simply unreadable, put the file into a + // state where we don't try to save changes. Otherwise, we could + // clobber the existing prefs. + error = PREF_READ_ERROR_ACCESS_DENIED; + read_only_ = true; + break; + case JSONFileValueSerializer::JSON_CANNOT_READ_FILE: + error = PREF_READ_ERROR_FILE_OTHER; + read_only_ = true; + break; + case JSONFileValueSerializer::JSON_FILE_LOCKED: + error = PREF_READ_ERROR_FILE_LOCKED; + read_only_ = true; + break; + case JSONFileValueSerializer::JSON_NO_SUCH_FILE: + // If the file just doesn't exist, maybe this is first run. In any case + // there's no harm in writing out default prefs in this case. + error = PREF_READ_ERROR_NO_FILE; + break; + default: + error = PREF_READ_ERROR_JSON_PARSE; + // JSON errors indicate file corruption of some sort. + // Since the file is corrupt, move it to the side and continue with + // empty preferences. This will result in them losing their settings. + // We keep the old file for possible support and debugging assistance + // as well as to detect if they're seeing these errors repeatedly. + // TODO(erikkay) Instead, use the last known good file. + FilePath bad = path_.ReplaceExtension(kBadExtension); + + // If they've ever had a parse error before, put them in another bucket. + // TODO(erikkay) if we keep this error checking for very long, we may + // want to differentiate between recent and long ago errors. + if (file_util::PathExists(bad)) + error = PREF_READ_ERROR_JSON_REPEAT; + file_util::Move(path_, bad); + break; + } + return error; + } + + // Preferences should always have a dictionary root. + if (!value->IsType(Value::TYPE_DICTIONARY)) { + // See comment for the default case above. + read_only_ = true; + return PREF_READ_ERROR_JSON_TYPE; + } + + prefs_.reset(static_cast<DictionaryValue*>(value.release())); + + return PREF_READ_ERROR_NONE; +} + +bool JsonPrefStore::WritePrefs() { + std::string data; + if (!SerializeData(&data)) + return false; + + // Lie about our ability to save. + if (read_only_) + return true; + + writer_.WriteNow(data); + return true; +} + +void JsonPrefStore::ScheduleWritePrefs() { + if (read_only_) + return; + + writer_.ScheduleWrite(this); +} + +bool JsonPrefStore::SerializeData(std::string* output) { + // TODO(tc): Do we want to prune webkit preferences that match the default + // value? + JSONStringValueSerializer serializer(output); + serializer.set_pretty_print(true); + scoped_ptr<DictionaryValue> copy(prefs_->DeepCopyWithoutEmptyChildren()); + return serializer.Serialize(*(copy.get())); +} + diff --git a/chrome/common/json_pref_store.h b/chrome/common/json_pref_store.h new file mode 100644 index 0000000..70f5dee --- /dev/null +++ b/chrome/common/json_pref_store.h @@ -0,0 +1,56 @@ +// Copyright (c) 2010 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 CHROME_COMMON_JSON_PREF_STORE_H_ +#define CHROME_COMMON_JSON_PREF_STORE_H_ + +#include <string> + +#include "base/scoped_ptr.h" +#include "chrome/common/pref_store.h" +#include "chrome/common/important_file_writer.h" + +namespace base { +class MessageLoopProxy; +} + +class DictionaryValue; +class FilePath; + +class JsonPrefStore : public PrefStore, + public ImportantFileWriter::DataSerializer { + public: + // |file_message_loop_proxy| is the MessageLoopProxy for a thread on which + // file I/O can be done. + JsonPrefStore(const FilePath& pref_filename, + base::MessageLoopProxy* file_message_loop_proxy); + virtual ~JsonPrefStore(); + + // PrefStore methods: + virtual bool ReadOnly() { return read_only_; } + + virtual DictionaryValue* prefs() { return prefs_.get(); } + + virtual PrefReadError ReadPrefs(); + + virtual bool WritePrefs(); + + virtual void ScheduleWritePrefs(); + + // ImportantFileWriter::DataSerializer methods: + virtual bool SerializeData(std::string* data); + + private: + FilePath path_; + + scoped_ptr<DictionaryValue> prefs_; + + bool read_only_; + + // Helper for safely writing pref data. + ImportantFileWriter writer_; +}; + +#endif // CHROME_COMMON_JSON_PREF_STORE_H_ + diff --git a/chrome/common/json_pref_store_unittest.cc b/chrome/common/json_pref_store_unittest.cc new file mode 100644 index 0000000..7d00030 --- /dev/null +++ b/chrome/common/json_pref_store_unittest.cc @@ -0,0 +1,150 @@ +// Copyright (c) 2010 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 "app/test/data/resource.h" +#include "base/file_util.h" +#include "base/message_loop.h" +#include "base/message_loop_proxy.h" +#include "base/path_service.h" +#include "base/scoped_ptr.h" +#include "base/string_util.h" +#include "base/thread.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/common/json_pref_store.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/pref_names.h" +#include "testing/gtest/include/gtest/gtest.h" + +class JsonPrefStoreTest : public testing::Test { + protected: + virtual void SetUp() { + message_loop_proxy_ = base::MessageLoopProxy::CreateForCurrentThread(); + // Name a subdirectory of the temp directory. + ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &test_dir_)); + test_dir_ = test_dir_.AppendASCII("JsonPrefStoreTest"); + + // Create a fresh, empty copy of this directory. + file_util::Delete(test_dir_, true); + file_util::CreateDirectory(test_dir_); + + ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_dir_)); + data_dir_ = data_dir_.AppendASCII("pref_service"); + ASSERT_TRUE(file_util::PathExists(data_dir_)); + } + + virtual void TearDown() { + // Clean up test directory + ASSERT_TRUE(file_util::Delete(test_dir_, true)); + ASSERT_FALSE(file_util::PathExists(test_dir_)); + } + + // the path to temporary directory used to contain the test operations + FilePath test_dir_; + // the path to the directory where the test data is stored + FilePath data_dir_; + // A message loop that we can use as the file thread message loop. + MessageLoop message_loop_; + scoped_refptr<base::MessageLoopProxy> message_loop_proxy_; +}; + +// Test fallback behavior for a nonexistent file. +TEST_F(JsonPrefStoreTest, NonExistentFile) { + FilePath bogus_input_file = data_dir_.AppendASCII("read.txt"); + ASSERT_FALSE(file_util::PathExists(bogus_input_file)); + JsonPrefStore pref_store(bogus_input_file, message_loop_proxy_.get()); + EXPECT_EQ(PrefStore::PREF_READ_ERROR_NO_FILE, pref_store.ReadPrefs()); + EXPECT_FALSE(pref_store.ReadOnly()); + EXPECT_TRUE(pref_store.prefs()->empty()); +} + +// Test fallback behavior for an invalid file. +TEST_F(JsonPrefStoreTest, InvalidFile) { + FilePath invalid_file_original = data_dir_.AppendASCII("invalid.json"); + FilePath invalid_file = test_dir_.AppendASCII("invalid.json"); + ASSERT_TRUE(file_util::CopyFile(invalid_file_original, invalid_file)); + JsonPrefStore pref_store(invalid_file, message_loop_proxy_.get()); + EXPECT_EQ(PrefStore::PREF_READ_ERROR_JSON_PARSE, pref_store.ReadPrefs()); + EXPECT_FALSE(pref_store.ReadOnly()); + EXPECT_TRUE(pref_store.prefs()->empty()); + + // The file should have been moved aside. + EXPECT_FALSE(file_util::PathExists(invalid_file)); + FilePath moved_aside = test_dir_.AppendASCII("invalid.bad"); + EXPECT_TRUE(file_util::PathExists(moved_aside)); + EXPECT_TRUE(file_util::TextContentsEqual(invalid_file_original, + moved_aside)); +} + +TEST_F(JsonPrefStoreTest, Basic) { + ASSERT_TRUE(file_util::CopyFile(data_dir_.AppendASCII("read.json"), + test_dir_.AppendASCII("write.json"))); + + // Test that the persistent value can be loaded. + FilePath input_file = test_dir_.AppendASCII("write.json"); + ASSERT_TRUE(file_util::PathExists(input_file)); + JsonPrefStore pref_store(input_file, message_loop_proxy_.get()); + ASSERT_EQ(PrefStore::PREF_READ_ERROR_NONE, pref_store.ReadPrefs()); + ASSERT_FALSE(pref_store.ReadOnly()); + DictionaryValue* prefs = pref_store.prefs(); + + // The JSON file looks like this: + // { + // "homepage": "http://www.cnn.com", + // "some_directory": "/usr/local/", + // "tabs": { + // "new_windows_in_tabs": true, + // "max_tabs": 20 + // } + // } + + const wchar_t kNewWindowsInTabs[] = L"tabs.new_windows_in_tabs"; + const wchar_t kMaxTabs[] = L"tabs.max_tabs"; + const wchar_t kLongIntPref[] = L"long_int.pref"; + + std::wstring cnn(L"http://www.cnn.com"); + + std::wstring string_value; + EXPECT_TRUE(prefs->GetString(prefs::kHomePage, &string_value)); + EXPECT_EQ(cnn, string_value); + + const wchar_t kSomeDirectory[] = L"some_directory"; + + FilePath::StringType path; + EXPECT_TRUE(prefs->GetString(kSomeDirectory, &path)); + EXPECT_EQ(FilePath::StringType(FILE_PATH_LITERAL("/usr/local/")), path); + FilePath some_path(FILE_PATH_LITERAL("/usr/sbin/")); + prefs->SetString(kSomeDirectory, some_path.value()); + EXPECT_TRUE(prefs->GetString(kSomeDirectory, &path)); + EXPECT_EQ(some_path.value(), path); + + // Test reading some other data types from sub-dictionaries. + bool boolean; + EXPECT_TRUE(prefs->GetBoolean(kNewWindowsInTabs, &boolean)); + EXPECT_TRUE(boolean); + + prefs->SetBoolean(kNewWindowsInTabs, false); + EXPECT_TRUE(prefs->GetBoolean(kNewWindowsInTabs, &boolean)); + EXPECT_FALSE(boolean); + + int integer; + EXPECT_TRUE(prefs->GetInteger(kMaxTabs, &integer)); + EXPECT_EQ(20, integer); + prefs->SetInteger(kMaxTabs, 10); + EXPECT_TRUE(prefs->GetInteger(kMaxTabs, &integer)); + EXPECT_EQ(10, integer); + + prefs->SetString(kLongIntPref, Int64ToWString(214748364842LL)); + EXPECT_TRUE(prefs->GetString(kLongIntPref, &string_value)); + EXPECT_EQ(214748364842LL, StringToInt64(WideToUTF16Hack(string_value))); + + // Serialize and compare to expected output. + FilePath output_file = input_file; + FilePath golden_output_file = data_dir_.AppendASCII("write.golden.json"); + ASSERT_TRUE(file_util::PathExists(golden_output_file)); + ASSERT_TRUE(pref_store.WritePrefs()); + MessageLoop::current()->RunAllPending(); + EXPECT_TRUE(file_util::TextContentsEqual(golden_output_file, output_file)); + ASSERT_TRUE(file_util::Delete(output_file, false)); +} diff --git a/chrome/common/json_value_serializer.cc b/chrome/common/json_value_serializer.cc new file mode 100644 index 0000000..df92afd --- /dev/null +++ b/chrome/common/json_value_serializer.cc @@ -0,0 +1,108 @@ +// Copyright (c) 2006-2008 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 "chrome/common/json_value_serializer.h" + +#include "base/file_util.h" +#include "base/json/json_reader.h" +#include "base/json/json_writer.h" +#include "base/string_util.h" + +const char* JSONFileValueSerializer::kAccessDenied = "Access denied."; +const char* JSONFileValueSerializer::kCannotReadFile = "Can't read file."; +const char* JSONFileValueSerializer::kFileLocked = "File locked."; +const char* JSONFileValueSerializer::kNoSuchFile = "File doesn't exist."; + +JSONStringValueSerializer::~JSONStringValueSerializer() {} + +bool JSONStringValueSerializer::Serialize(const Value& root) { + if (!json_string_ || initialized_with_const_string_) + return false; + + base::JSONWriter::Write(&root, pretty_print_, json_string_); + return true; +} + +Value* JSONStringValueSerializer::Deserialize(int* error_code, + std::string* error_str) { + if (!json_string_) + return NULL; + + return base::JSONReader::ReadAndReturnError(*json_string_, + allow_trailing_comma_, + error_code, + error_str); +} + +/******* File Serializer *******/ + +bool JSONFileValueSerializer::Serialize(const Value& root) { + std::string json_string; + JSONStringValueSerializer serializer(&json_string); + serializer.set_pretty_print(true); + bool result = serializer.Serialize(root); + if (!result) + return false; + + int data_size = static_cast<int>(json_string.size()); + if (file_util::WriteFile(json_file_path_, + json_string.data(), + data_size) != data_size) + return false; + + return true; +} + +int JSONFileValueSerializer::ReadFileToString(std::string* json_string) { + DCHECK(json_string); + if (!file_util::ReadFileToString(json_file_path_, json_string)) { +#if defined(OS_WIN) + int error = ::GetLastError(); + if (error == ERROR_SHARING_VIOLATION || error == ERROR_LOCK_VIOLATION) { + return JSON_FILE_LOCKED; + } else if (error == ERROR_ACCESS_DENIED) { + return JSON_ACCESS_DENIED; + } +#endif + if (!file_util::PathExists(json_file_path_)) + return JSON_NO_SUCH_FILE; + else + return JSON_CANNOT_READ_FILE; + } + return JSON_NO_ERROR; +} + +const char* JSONFileValueSerializer::GetErrorMessageForCode(int error_code) { + switch (error_code) { + case JSON_NO_ERROR: + return ""; + case JSON_ACCESS_DENIED: + return kAccessDenied; + case JSON_CANNOT_READ_FILE: + return kCannotReadFile; + case JSON_FILE_LOCKED: + return kFileLocked; + case JSON_NO_SUCH_FILE: + return kNoSuchFile; + default: + NOTREACHED(); + return ""; + } +} + +Value* JSONFileValueSerializer::Deserialize(int* error_code, + std::string* error_str) { + std::string json_string; + int error = ReadFileToString(&json_string); + if (error != JSON_NO_ERROR) { + if (error_code) + *error_code = error; + if (error_str) + *error_str = GetErrorMessageForCode(error); + return NULL; + } + + JSONStringValueSerializer serializer(json_string); + return serializer.Deserialize(error_code, error_str); +} diff --git a/chrome/common/json_value_serializer.h b/chrome/common/json_value_serializer.h new file mode 100644 index 0000000..7919cfe --- /dev/null +++ b/chrome/common/json_value_serializer.h @@ -0,0 +1,127 @@ +// Copyright (c) 2009 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 CHROME_COMMON_JSON_VALUE_SERIALIZER_H_ +#define CHROME_COMMON_JSON_VALUE_SERIALIZER_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/file_path.h" +#include "base/values.h" + +class JSONStringValueSerializer : public ValueSerializer { + public: + // json_string is the string that will be source of the deserialization + // or the destination of the serialization. The caller of the constructor + // retains ownership of the string. + explicit JSONStringValueSerializer(std::string* json_string) + : json_string_(json_string), + initialized_with_const_string_(false), + pretty_print_(false), + allow_trailing_comma_(false) { + } + + // This version allows initialization with a const string reference for + // deserialization only. + explicit JSONStringValueSerializer(const std::string& json_string) + : json_string_(&const_cast<std::string&>(json_string)), + initialized_with_const_string_(true), + pretty_print_(false), + allow_trailing_comma_(false) { + } + + ~JSONStringValueSerializer(); + + // Attempt to serialize the data structure represented by Value into + // JSON. If the return value is true, the result will have been written + // into the string passed into the constructor. + bool Serialize(const Value& root); + + // Attempt to deserialize the data structure encoded in the string passed + // in to the constructor into a structure of Value objects. If the return + // value is NULL, and if |error_code| is non-null, |error_code| will + // contain an integer error code (either JsonFileError or JsonParseError). + // If |error_message| is non-null, it will be filled in with a formatted + // error message including the location of the error if appropriate. + // The caller takes ownership of the returned value. + Value* Deserialize(int* error_code, std::string* error_message); + + void set_pretty_print(bool new_value) { pretty_print_ = new_value; } + bool pretty_print() { return pretty_print_; } + + void set_allow_trailing_comma(bool new_value) { + allow_trailing_comma_ = new_value; + } + + private: + std::string* json_string_; + bool initialized_with_const_string_; + bool pretty_print_; // If true, serialization will span multiple lines. + // If true, deserialization will allow trailing commas. + bool allow_trailing_comma_; + + DISALLOW_COPY_AND_ASSIGN(JSONStringValueSerializer); +}; + +class JSONFileValueSerializer : public ValueSerializer { + public: + // json_file_patch is the path of a file that will be source of the + // deserialization or the destination of the serialization. + // When deserializing, the file should exist, but when serializing, the + // serializer will attempt to create the file at the specified location. + explicit JSONFileValueSerializer(const FilePath& json_file_path) + : json_file_path_(json_file_path) {} + + ~JSONFileValueSerializer() {} + + // DO NOT USE except in unit tests to verify the file was written properly. + // We should never serialize directly to a file since this will block the + // thread. Instead, serialize to a string and write to the file you want on + // the file thread. + // + // Attempt to serialize the data structure represented by Value into + // JSON. If the return value is true, the result will have been written + // into the file whose name was passed into the constructor. + bool Serialize(const Value& root); + + // Attempt to deserialize the data structure encoded in the file passed + // in to the constructor into a structure of Value objects. If the return + // value is NULL, and if |error_code| is non-null, |error_code| will + // contain an integer error code (either JsonFileError or JsonParseError). + // If |error_message| is non-null, it will be filled in with a formatted + // error message including the location of the error if appropriate. + // The caller takes ownership of the returned value. + Value* Deserialize(int* error_code, std::string* error_message); + + // This enum is designed to safely overlap with JSONReader::JsonParseError. + enum JsonFileError { + JSON_NO_ERROR = 0, + JSON_ACCESS_DENIED = 1000, + JSON_CANNOT_READ_FILE, + JSON_FILE_LOCKED, + JSON_NO_SUCH_FILE + }; + + // File-specific error messages that can be returned. + static const char* kAccessDenied; + static const char* kCannotReadFile; + static const char* kFileLocked; + static const char* kNoSuchFile; + + // Convert an error code into an error message. |error_code| is assumed to + // be a JsonFileError. + static const char* GetErrorMessageForCode(int error_code); + + private: + FilePath json_file_path_; + + // A wrapper for file_util::ReadFileToString which returns a non-zero + // JsonFileError if there were file errors. + int ReadFileToString(std::string* json_string); + + DISALLOW_IMPLICIT_CONSTRUCTORS(JSONFileValueSerializer); +}; + +#endif // CHROME_COMMON_JSON_VALUE_SERIALIZER_H_ diff --git a/chrome/common/json_value_serializer_perftest.cc b/chrome/common/json_value_serializer_perftest.cc new file mode 100644 index 0000000..504ddb2 --- /dev/null +++ b/chrome/common/json_value_serializer_perftest.cc @@ -0,0 +1,90 @@ +// Copyright (c) 2006-2008 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 <vector> + +#include "base/file_util.h" +#include "base/path_service.h" +#include "base/perftimer.h" +#include "base/string_util.h" +#include "base/values.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/json_value_serializer.h" +#include "chrome/common/logging_chrome.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { +class JSONValueSerializerTests : public testing::Test { + protected: + virtual void SetUp() { + static const char* const kTestFilenames[] = { + "serializer_nested_test.js", + "serializer_test.js", + "serializer_test_nowhitespace.js", + }; + + // Load test cases + for (size_t i = 0; i < arraysize(kTestFilenames); ++i) { + FilePath filename; + EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &filename)); + filename = filename.AppendASCII(kTestFilenames[i]); + + std::string test_case; + EXPECT_TRUE(file_util::ReadFileToString(filename, &test_case)); + test_cases_.push_back(test_case); + } + } + + // Holds json strings to be tested. + std::vector<std::string> test_cases_; +}; + +} // namespace + +// Test deserialization of a json string into a Value object. We run the test +// using 3 sample strings for both the current decoder and jsoncpp's decoder. +TEST_F(JSONValueSerializerTests, Reading) { + printf("\n"); + const int kIterations = 100000; + + // Test chrome json implementation + PerfTimeLogger chrome_timer("chrome"); + for (int i = 0; i < kIterations; ++i) { + for (size_t j = 0; j < test_cases_.size(); ++j) { + JSONStringValueSerializer reader(test_cases_[j]); + scoped_ptr<Value> root(reader.Deserialize(NULL, NULL)); + ASSERT_TRUE(root.get()); + } + } + chrome_timer.Done(); +} + +TEST_F(JSONValueSerializerTests, CompactWriting) { + printf("\n"); + const int kIterations = 100000; + // Convert test cases to Value objects. + std::vector<Value*> test_cases; + for (size_t i = 0; i < test_cases_.size(); ++i) { + JSONStringValueSerializer reader(test_cases_[i]); + Value* root = reader.Deserialize(NULL, NULL); + ASSERT_TRUE(root); + test_cases.push_back(root); + } + + PerfTimeLogger chrome_timer("chrome"); + for (int i = 0; i < kIterations; ++i) { + for (size_t j = 0; j < test_cases.size(); ++j) { + std::string json; + JSONStringValueSerializer reader(&json); + ASSERT_TRUE(reader.Serialize(*test_cases[j])); + } + } + chrome_timer.Done(); + + // Clean up test cases. + for (size_t i = 0; i < test_cases.size(); ++i) { + delete test_cases[i]; + test_cases[i] = NULL; + } +} diff --git a/chrome/common/json_value_serializer_unittest.cc b/chrome/common/json_value_serializer_unittest.cc new file mode 100644 index 0000000..3f40dcc --- /dev/null +++ b/chrome/common/json_value_serializer_unittest.cc @@ -0,0 +1,348 @@ +// Copyright (c) 2006-2008 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/basictypes.h" +#include "base/file_util.h" +#include "base/json/json_reader.h" +#include "base/json/json_writer.h" +#include "base/path_service.h" +#include "base/string_util.h" +#include "base/values.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/json_value_serializer.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(JSONValueSerializerTest, Roundtrip) { + const std::string original_serialization = + "{\"bool\":true,\"int\":42,\"list\":[1,2],\"null\":null,\"real\":3.14}"; + JSONStringValueSerializer serializer(original_serialization); + scoped_ptr<Value> root(serializer.Deserialize(NULL, NULL)); + ASSERT_TRUE(root.get()); + ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); + + DictionaryValue* root_dict = static_cast<DictionaryValue*>(root.get()); + + Value* null_value = NULL; + ASSERT_TRUE(root_dict->Get(L"null", &null_value)); + ASSERT_TRUE(null_value); + ASSERT_TRUE(null_value->IsType(Value::TYPE_NULL)); + + bool bool_value = false; + ASSERT_TRUE(root_dict->GetBoolean(L"bool", &bool_value)); + ASSERT_TRUE(bool_value); + + int int_value = 0; + ASSERT_TRUE(root_dict->GetInteger(L"int", &int_value)); + ASSERT_EQ(42, int_value); + + double real_value = 0.0; + ASSERT_TRUE(root_dict->GetReal(L"real", &real_value)); + ASSERT_DOUBLE_EQ(3.14, real_value); + + // We shouldn't be able to write using this serializer, since it was + // initialized with a const string. + ASSERT_FALSE(serializer.Serialize(*root_dict)); + + std::string test_serialization = ""; + JSONStringValueSerializer mutable_serializer(&test_serialization); + ASSERT_TRUE(mutable_serializer.Serialize(*root_dict)); + ASSERT_EQ(original_serialization, test_serialization); + + mutable_serializer.set_pretty_print(true); + ASSERT_TRUE(mutable_serializer.Serialize(*root_dict)); + // JSON output uses a different newline style on Windows than on other + // platforms. +#if defined(OS_WIN) +#define JSON_NEWLINE "\r\n" +#else +#define JSON_NEWLINE "\n" +#endif + const std::string pretty_serialization = + "{" JSON_NEWLINE + " \"bool\": true," JSON_NEWLINE + " \"int\": 42," JSON_NEWLINE + " \"list\": [ 1, 2 ]," JSON_NEWLINE + " \"null\": null," JSON_NEWLINE + " \"real\": 3.14" JSON_NEWLINE + "}" JSON_NEWLINE; +#undef JSON_NEWLINE + ASSERT_EQ(pretty_serialization, test_serialization); +} + +TEST(JSONValueSerializerTest, StringEscape) { + std::wstring all_chars; + for (int i = 1; i < 256; ++i) { + all_chars += static_cast<wchar_t>(i); + } + // Generated in in Firefox using the following js (with an extra backslash for + // double quote): + // var s = ''; + // for (var i = 1; i < 256; ++i) { s += String.fromCharCode(i); } + // uneval(s).replace(/\\/g, "\\\\"); + std::string all_chars_expected = + "\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000B\\f\\r" + "\\u000E\\u000F\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017" + "\\u0018\\u0019\\u001A\\u001B\\u001C\\u001D\\u001E\\u001F !\\\"" + "#$%&'()*+,-./0123456789:;\\u003C=\\u003E?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\" + "\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\\u007F\\u0080\\u0081\\u0082\\u0083" + "\\u0084\\u0085\\u0086\\u0087\\u0088\\u0089\\u008A\\u008B\\u008C\\u008D" + "\\u008E\\u008F\\u0090\\u0091\\u0092\\u0093\\u0094\\u0095\\u0096\\u0097" + "\\u0098\\u0099\\u009A\\u009B\\u009C\\u009D\\u009E\\u009F\\u00A0\\u00A1" + "\\u00A2\\u00A3\\u00A4\\u00A5\\u00A6\\u00A7\\u00A8\\u00A9\\u00AA\\u00AB" + "\\u00AC\\u00AD\\u00AE\\u00AF\\u00B0\\u00B1\\u00B2\\u00B3\\u00B4\\u00B5" + "\\u00B6\\u00B7\\u00B8\\u00B9\\u00BA\\u00BB\\u00BC\\u00BD\\u00BE\\u00BF" + "\\u00C0\\u00C1\\u00C2\\u00C3\\u00C4\\u00C5\\u00C6\\u00C7\\u00C8\\u00C9" + "\\u00CA\\u00CB\\u00CC\\u00CD\\u00CE\\u00CF\\u00D0\\u00D1\\u00D2\\u00D3" + "\\u00D4\\u00D5\\u00D6\\u00D7\\u00D8\\u00D9\\u00DA\\u00DB\\u00DC\\u00DD" + "\\u00DE\\u00DF\\u00E0\\u00E1\\u00E2\\u00E3\\u00E4\\u00E5\\u00E6\\u00E7" + "\\u00E8\\u00E9\\u00EA\\u00EB\\u00EC\\u00ED\\u00EE\\u00EF\\u00F0\\u00F1" + "\\u00F2\\u00F3\\u00F4\\u00F5\\u00F6\\u00F7\\u00F8\\u00F9\\u00FA\\u00FB" + "\\u00FC\\u00FD\\u00FE\\u00FF"; + + std::string expected_output = "{\"all_chars\":\"" + all_chars_expected + + "\"}"; + // Test JSONWriter interface + std::string output_js; + DictionaryValue valueRoot; + valueRoot.SetString(L"all_chars", all_chars); + base::JSONWriter::Write(&valueRoot, false, &output_js); + ASSERT_EQ(expected_output, output_js); + + // Test JSONValueSerializer interface (uses JSONWriter). + JSONStringValueSerializer serializer(&output_js); + ASSERT_TRUE(serializer.Serialize(valueRoot)); + ASSERT_EQ(expected_output, output_js); +} + +TEST(JSONValueSerializerTest, UnicodeStrings) { + // unicode string json -> escaped ascii text + DictionaryValue root; + std::wstring test(L"\x7F51\x9875"); + root.SetString(L"web", test); + + std::string expected = "{\"web\":\"\\u7F51\\u9875\"}"; + + std::string actual; + JSONStringValueSerializer serializer(&actual); + ASSERT_TRUE(serializer.Serialize(root)); + ASSERT_EQ(expected, actual); + + // escaped ascii text -> json + JSONStringValueSerializer deserializer(expected); + scoped_ptr<Value> deserial_root(deserializer.Deserialize(NULL, NULL)); + ASSERT_TRUE(deserial_root.get()); + DictionaryValue* dict_root = + static_cast<DictionaryValue*>(deserial_root.get()); + std::wstring web_value; + ASSERT_TRUE(dict_root->GetString(L"web", &web_value)); + ASSERT_EQ(test, web_value); +} + +TEST(JSONValueSerializerTest, HexStrings) { + // hex string json -> escaped ascii text + DictionaryValue root; + std::wstring test(L"\x01\x02"); + root.SetString(L"test", test); + + std::string expected = "{\"test\":\"\\u0001\\u0002\"}"; + + std::string actual; + JSONStringValueSerializer serializer(&actual); + ASSERT_TRUE(serializer.Serialize(root)); + ASSERT_EQ(expected, actual); + + // escaped ascii text -> json + JSONStringValueSerializer deserializer(expected); + scoped_ptr<Value> deserial_root(deserializer.Deserialize(NULL, NULL)); + ASSERT_TRUE(deserial_root.get()); + DictionaryValue* dict_root = + static_cast<DictionaryValue*>(deserial_root.get()); + std::wstring test_value; + ASSERT_TRUE(dict_root->GetString(L"test", &test_value)); + ASSERT_EQ(test, test_value); + + // Test converting escaped regular chars + std::string escaped_chars = "{\"test\":\"\\u0067\\u006f\"}"; + JSONStringValueSerializer deserializer2(escaped_chars); + deserial_root.reset(deserializer2.Deserialize(NULL, NULL)); + ASSERT_TRUE(deserial_root.get()); + dict_root = static_cast<DictionaryValue*>(deserial_root.get()); + ASSERT_TRUE(dict_root->GetString(L"test", &test_value)); + ASSERT_EQ(std::wstring(L"go"), test_value); +} + +TEST(JSONValueSerializerTest, AllowTrailingComma) { + scoped_ptr<Value> root; + scoped_ptr<Value> root_expected; + std::string test_with_commas("{\"key\": [true,],}"); + std::string test_no_commas("{\"key\": [true]}"); + + JSONStringValueSerializer serializer(test_with_commas); + serializer.set_allow_trailing_comma(true); + JSONStringValueSerializer serializer_expected(test_no_commas); + root.reset(serializer.Deserialize(NULL, NULL)); + ASSERT_TRUE(root.get()); + root_expected.reset(serializer_expected.Deserialize(NULL, NULL)); + ASSERT_TRUE(root_expected.get()); + ASSERT_TRUE(root->Equals(root_expected.get())); +} + +namespace { + +void ValidateJsonList(const std::string& json) { + scoped_ptr<Value> root(base::JSONReader::Read(json, false)); + ASSERT_TRUE(root.get() && root->IsType(Value::TYPE_LIST)); + ListValue* list = static_cast<ListValue*>(root.get()); + ASSERT_EQ(1U, list->GetSize()); + Value* elt = NULL; + ASSERT_TRUE(list->Get(0, &elt)); + int value = 0; + ASSERT_TRUE(elt && elt->GetAsInteger(&value)); + ASSERT_EQ(1, value); +} + +} // namespace + +TEST(JSONValueSerializerTest, JSONReaderComments) { + ValidateJsonList("[ // 2, 3, ignore me ] \n1 ]"); + ValidateJsonList("[ /* 2, \n3, ignore me ]*/ \n1 ]"); + ValidateJsonList("//header\n[ // 2, \n// 3, \n1 ]// footer"); + ValidateJsonList("/*\n[ // 2, \n// 3, \n1 ]*/[1]"); + ValidateJsonList("[ 1 /* one */ ] /* end */"); + ValidateJsonList("[ 1 //// ,2\r\n ]"); + + scoped_ptr<Value> root; + + // It's ok to have a comment in a string. + root.reset(base::JSONReader::Read("[\"// ok\\n /* foo */ \"]", false)); + ASSERT_TRUE(root.get() && root->IsType(Value::TYPE_LIST)); + ListValue* list = static_cast<ListValue*>(root.get()); + ASSERT_EQ(1U, list->GetSize()); + Value* elt = NULL; + ASSERT_TRUE(list->Get(0, &elt)); + std::wstring value; + ASSERT_TRUE(elt && elt->GetAsString(&value)); + ASSERT_EQ(L"// ok\n /* foo */ ", value); + + // You can't nest comments. + root.reset(base::JSONReader::Read("/* /* inner */ outer */ [ 1 ]", false)); + ASSERT_FALSE(root.get()); + + // Not a open comment token. + root.reset(base::JSONReader::Read("/ * * / [1]", false)); + ASSERT_FALSE(root.get()); +} + +class JSONFileValueSerializerTest : public testing::Test { +protected: + virtual void SetUp() { + // Name a subdirectory of the temp directory. + ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &test_dir_)); + test_dir_ = + test_dir_.Append(FILE_PATH_LITERAL("JSONFileValueSerializerTest")); + + // Create a fresh, empty copy of this directory. + file_util::Delete(test_dir_, true); + file_util::CreateDirectory(test_dir_); + } + virtual void TearDown() { + // Clean up test directory + ASSERT_TRUE(file_util::Delete(test_dir_, false)); + ASSERT_FALSE(file_util::PathExists(test_dir_)); + } + + // the path to temporary directory used to contain the test operations + FilePath test_dir_; +}; + +TEST_F(JSONFileValueSerializerTest, Roundtrip) { + FilePath original_file_path; + ASSERT_TRUE( + PathService::Get(chrome::DIR_TEST_DATA, &original_file_path)); + original_file_path = + original_file_path.Append(FILE_PATH_LITERAL("serializer_test.js")); + + ASSERT_TRUE(file_util::PathExists(original_file_path)); + + JSONFileValueSerializer deserializer(original_file_path); + scoped_ptr<Value> root; + root.reset(deserializer.Deserialize(NULL, NULL)); + + ASSERT_TRUE(root.get()); + ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); + + DictionaryValue* root_dict = static_cast<DictionaryValue*>(root.get()); + + Value* null_value = NULL; + ASSERT_TRUE(root_dict->Get(L"null", &null_value)); + ASSERT_TRUE(null_value); + ASSERT_TRUE(null_value->IsType(Value::TYPE_NULL)); + + bool bool_value = false; + ASSERT_TRUE(root_dict->GetBoolean(L"bool", &bool_value)); + ASSERT_TRUE(bool_value); + + int int_value = 0; + ASSERT_TRUE(root_dict->GetInteger(L"int", &int_value)); + ASSERT_EQ(42, int_value); + + std::wstring string_value; + ASSERT_TRUE(root_dict->GetString(L"string", &string_value)); + ASSERT_EQ(L"hello", string_value); + + // Now try writing. + const FilePath written_file_path = + test_dir_.Append(FILE_PATH_LITERAL("test_output.js")); + + ASSERT_FALSE(file_util::PathExists(written_file_path)); + JSONFileValueSerializer serializer(written_file_path); + ASSERT_TRUE(serializer.Serialize(*root)); + ASSERT_TRUE(file_util::PathExists(written_file_path)); + + // Now compare file contents. + EXPECT_TRUE(file_util::TextContentsEqual(original_file_path, + written_file_path)); + EXPECT_TRUE(file_util::Delete(written_file_path, false)); +} + +TEST_F(JSONFileValueSerializerTest, RoundtripNested) { + FilePath original_file_path; + ASSERT_TRUE( + PathService::Get(chrome::DIR_TEST_DATA, &original_file_path)); + original_file_path = + original_file_path.Append(FILE_PATH_LITERAL("serializer_nested_test.js")); + + ASSERT_TRUE(file_util::PathExists(original_file_path)); + + JSONFileValueSerializer deserializer(original_file_path); + scoped_ptr<Value> root; + root.reset(deserializer.Deserialize(NULL, NULL)); + ASSERT_TRUE(root.get()); + + // Now try writing. + FilePath written_file_path = + test_dir_.Append(FILE_PATH_LITERAL("test_output.js")); + + ASSERT_FALSE(file_util::PathExists(written_file_path)); + JSONFileValueSerializer serializer(written_file_path); + ASSERT_TRUE(serializer.Serialize(*root)); + ASSERT_TRUE(file_util::PathExists(written_file_path)); + + // Now compare file contents. + EXPECT_TRUE(file_util::TextContentsEqual(original_file_path, + written_file_path)); + EXPECT_TRUE(file_util::Delete(written_file_path, false)); +} + +TEST_F(JSONFileValueSerializerTest, NoWhitespace) { + FilePath source_file_path; + ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_file_path)); + source_file_path = source_file_path.Append( + FILE_PATH_LITERAL("serializer_test_nowhitespace.js")); + ASSERT_TRUE(file_util::PathExists(source_file_path)); + JSONFileValueSerializer serializer(source_file_path); + scoped_ptr<Value> root; + root.reset(serializer.Deserialize(NULL, NULL)); + ASSERT_TRUE(root.get()); +} diff --git a/chrome/common/jstemplate_builder.cc b/chrome/common/jstemplate_builder.cc new file mode 100644 index 0000000..628edd7 --- /dev/null +++ b/chrome/common/jstemplate_builder.cc @@ -0,0 +1,116 @@ +// Copyright (c) 2006-2008 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 helper function for using JsTemplate. See jstemplate_builder.h for more +// info. + +#include "chrome/common/jstemplate_builder.h" + +#include "app/resource_bundle.h" +#include "base/logging.h" +#include "base/string_util.h" +#include "chrome/common/json_value_serializer.h" + +#include "grit/common_resources.h" + +namespace jstemplate_builder { + +std::string GetTemplateHtml(const base::StringPiece& html_template, + const DictionaryValue* json, + const base::StringPiece& template_id) { + std::string output(html_template.data(), html_template.size()); + AppendJsonHtml(json, &output); + AppendJsTemplateSourceHtml(&output); + AppendJsTemplateProcessHtml(template_id, &output); + return output; +} + +std::string GetI18nTemplateHtml(const base::StringPiece& html_template, + const DictionaryValue* json) { + std::string output(html_template.data(), html_template.size()); + AppendJsonHtml(json, &output); + AppendI18nTemplateSourceHtml(&output); + AppendI18nTemplateProcessHtml(&output); + return output; +} + +std::string GetTemplatesHtml(const base::StringPiece& html_template, + const DictionaryValue* json, + const base::StringPiece& template_id) { + std::string output(html_template.data(), html_template.size()); + AppendI18nTemplateSourceHtml(&output); + AppendJsTemplateSourceHtml(&output); + AppendJsonHtml(json, &output); + AppendI18nTemplateProcessHtml(&output); + AppendJsTemplateProcessHtml(template_id, &output); + return output; +} + +void AppendJsonHtml(const DictionaryValue* json, std::string* output) { + // Convert the template data to a json string. + DCHECK(json) << "must include json data structure"; + + std::string jstext; + JSONStringValueSerializer serializer(&jstext); + serializer.Serialize(*json); + // </ confuses the HTML parser because it could be a </script> tag. So we + // replace </ with <\/. The extra \ will be ignored by the JS engine. + ReplaceSubstringsAfterOffset(&jstext, 0, "</", "<\\/"); + + output->append("<script>"); + output->append("var templateData = "); + output->append(jstext); + output->append(";"); + output->append("</script>"); +} + +void AppendJsTemplateSourceHtml(std::string* output) { + // fetch and cache the pointer of the jstemplate resource source text. + static const base::StringPiece jstemplate_src( + ResourceBundle::GetSharedInstance().GetRawDataResource( + IDR_JSTEMPLATE_JS)); + + if (jstemplate_src.empty()) { + NOTREACHED() << "Unable to get jstemplate src"; + return; + } + + output->append("<script>"); + output->append(jstemplate_src.data(), jstemplate_src.size()); + output->append("</script>"); +} + +void AppendJsTemplateProcessHtml(const base::StringPiece& template_id, + std::string* output) { + output->append("<script>"); + output->append("var tp = document.getElementById('"); + output->append(template_id.data(), template_id.size()); + output->append("');"); + output->append("jstProcess(new JsEvalContext(templateData), tp);"); + output->append("</script>"); +} + +void AppendI18nTemplateSourceHtml(std::string* output) { + // fetch and cache the pointer of the jstemplate resource source text. + static const base::StringPiece i18n_template_src( + ResourceBundle::GetSharedInstance().GetRawDataResource( + IDR_I18N_TEMPLATE_JS)); + + if (i18n_template_src.empty()) { + NOTREACHED() << "Unable to get i18n template src"; + return; + } + + output->append("<script>"); + output->append(i18n_template_src.data(), i18n_template_src.size()); + output->append("</script>"); +} + +void AppendI18nTemplateProcessHtml(std::string* output) { + output->append("<script>"); + output->append("i18nTemplate.process(document, templateData);"); + output->append("</script>"); +} + +} // namespace jstemplate_builder diff --git a/chrome/common/jstemplate_builder.h b/chrome/common/jstemplate_builder.h new file mode 100644 index 0000000..ac8285f --- /dev/null +++ b/chrome/common/jstemplate_builder.h @@ -0,0 +1,69 @@ +// Copyright (c) 2006-2008 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 provides some helper methods for building and rendering an +// internal html page. The flow is as follows: +// - instantiate a builder given a webframe that we're going to render content +// into +// - load the template html and load the jstemplate javascript into the frame +// - given a json data object, run the jstemplate javascript which fills in +// template values + +#ifndef CHROME_COMMON_JSTEMPLATE_BUILDER_H_ +#define CHROME_COMMON_JSTEMPLATE_BUILDER_H_ + +#include <string> + +class DictionaryValue; +namespace base { +class StringPiece; +} + +namespace jstemplate_builder { + +// A helper function that generates a string of HTML to be loaded. The +// string includes the HTML and the javascript code necessary to generate the +// full page with support for JsTemplates. +std::string GetTemplateHtml(const base::StringPiece& html_template, + const DictionaryValue* json, + const base::StringPiece& template_id); + +// A helper function that generates a string of HTML to be loaded. The +// string includes the HTML and the javascript code necessary to generate the +// full page with support for i18n Templates. +std::string GetI18nTemplateHtml(const base::StringPiece& html_template, + const DictionaryValue* json); + +// A helper function that generates a string of HTML to be loaded. The +// string includes the HTML and the javascript code necessary to generate the +// full page with support for both i18n Templates and JsTemplates. +std::string GetTemplatesHtml(const base::StringPiece& html_template, + const DictionaryValue* json, + const base::StringPiece& template_id); + +// The following functions build up the different parts that the above +// templates use. + +// Appends a script tag with a variable name |templateData| that has the JSON +// assigned to it. +void AppendJsonHtml(const DictionaryValue* json, std::string* output); + +// Appends the source for JsTemplates in a script tag. +void AppendJsTemplateSourceHtml(std::string* output); + +// Appends the code that processes the JsTemplate with the JSON. You should +// call AppendJsTemplateSourceHtml and AppendJsonHtml before calling this. +void AppendJsTemplateProcessHtml(const base::StringPiece& template_id, + std::string* output); + +// Appends the source for i18n Templates in a script tag. +void AppendI18nTemplateSourceHtml(std::string* output); + +// Appends the code that processes the i18n Template with the JSON. You +// should call AppendJsTemplateSourceHtml and AppendJsonHtml before calling +// this. +void AppendI18nTemplateProcessHtml(std::string* output); + +} // namespace jstemplate_builder +#endif // CHROME_COMMON_JSTEMPLATE_BUILDER_H_ diff --git a/chrome/common/libxml_utils.cc b/chrome/common/libxml_utils.cc new file mode 100644 index 0000000..f06df72 --- /dev/null +++ b/chrome/common/libxml_utils.cc @@ -0,0 +1,143 @@ +// Copyright (c) 2009 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 "chrome/common/libxml_utils.h" + +#include "base/compiler_specific.h" +#include "base/logging.h" +#include "base/string_util.h" + +#include "libxml/xmlreader.h" + +std::string XmlStringToStdString(const xmlChar* xmlstring) { + // xmlChar*s are UTF-8, so this cast is safe. + if (xmlstring) + return std::string(reinterpret_cast<const char*>(xmlstring)); + else + return ""; +} + +XmlReader::XmlReader() + : reader_(NULL), + ALLOW_THIS_IN_INITIALIZER_LIST( + error_func_(this, &XmlReader::GenericErrorCallback)) { +} + +XmlReader::~XmlReader() { + if (reader_) + xmlFreeTextReader(reader_); +} + +// static +void XmlReader::GenericErrorCallback(void* context, const char* msg, ...) { + va_list args; + va_start(args, msg); + + XmlReader* reader = static_cast<XmlReader*>(context); + reader->errors_.append(StringPrintV(msg, args)); + va_end(args); +} + +bool XmlReader::Load(const std::string& input) { + const int kParseOptions = XML_PARSE_RECOVER | // recover on errors + XML_PARSE_NONET; // forbid network access + // TODO(evanm): Verify it's OK to pass NULL for the URL and encoding. + // The libxml code allows for these, but it's unclear what effect is has. + reader_ = xmlReaderForMemory(input.data(), static_cast<int>(input.size()), + NULL, NULL, kParseOptions); + return reader_ != NULL; +} + +bool XmlReader::LoadFile(const std::string& file_path) { + + const int kParseOptions = XML_PARSE_RECOVER | // recover on errors + XML_PARSE_NONET; // forbid network access + reader_ = xmlReaderForFile(file_path.c_str(), NULL, kParseOptions); + return reader_ != NULL; +} + +bool XmlReader::NodeAttribute(const char* name, std::string* out) { + xmlChar* value = xmlTextReaderGetAttribute(reader_, BAD_CAST name); + if (!value) + return false; + *out = XmlStringToStdString(value); + xmlFree(value); + return true; +} + +bool XmlReader::ReadElementContent(std::string* content) { + DCHECK(NodeType() == XML_READER_TYPE_ELEMENT); + const int start_depth = Depth(); + + if (xmlTextReaderIsEmptyElement(reader_)) { + // Empty tag. We succesfully read the content, but it's + // empty. + *content = ""; + // Advance past this empty tag. + if (!Read()) + return false; + return true; + } + + // Advance past opening element tag. + if (!Read()) + return false; + + // Read the content. We read up until we hit a closing tag at the + // same level as our starting point. + while (NodeType() != XML_READER_TYPE_END_ELEMENT || Depth() != start_depth) { + *content += XmlStringToStdString(xmlTextReaderConstValue(reader_)); + if (!Read()) + return false; + } + + // Advance past ending element tag. + DCHECK_EQ(NodeType(), XML_READER_TYPE_END_ELEMENT); + if (!Read()) + return false; + + return true; +} + +bool XmlReader::SkipToElement() { + do { + switch (NodeType()) { + case XML_READER_TYPE_ELEMENT: + return true; + case XML_READER_TYPE_END_ELEMENT: + return false; + default: + // Skip all other node types. + continue; + } + } while (Read()); + return false; +} + + +// XmlWriter functions + +XmlWriter::XmlWriter() + : writer_(NULL), + buffer_(NULL) {} + +XmlWriter::~XmlWriter() { + if (writer_) + xmlFreeTextWriter(writer_); + if (buffer_) + xmlBufferFree(buffer_); +} + +void XmlWriter::StartWriting() { + buffer_ = xmlBufferCreate(); + writer_ = xmlNewTextWriterMemory(buffer_, 0); + xmlTextWriterSetIndent(writer_, 1); + xmlTextWriterStartDocument(writer_, NULL, NULL, NULL); +} + +void XmlWriter::StopWriting() { + xmlTextWriterEndDocument(writer_); + xmlFreeTextWriter(writer_); + writer_ = NULL; +} diff --git a/chrome/common/libxml_utils.h b/chrome/common/libxml_utils.h new file mode 100644 index 0000000..1484139 --- /dev/null +++ b/chrome/common/libxml_utils.h @@ -0,0 +1,182 @@ +// Copyright (c) 2006-2008 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 CHROME_COMMON_LIBXML_UTILS_H__ +#define CHROME_COMMON_LIBXML_UTILS_H__ + +#include <string> + +#include "libxml/xmlreader.h" +#include "libxml/xmlwriter.h" + +// Converts a libxml xmlChar* into a UTF-8 std::string. +// NULL inputs produce an empty string. +std::string XmlStringToStdString(const xmlChar* xmlstring); + +// libxml uses a global error function pointer for reporting errors. +// A ScopedXmlErrorFunc object lets you change the global error pointer +// for the duration of the object's lifetime. +class ScopedXmlErrorFunc { + public: + ScopedXmlErrorFunc(void* context, xmlGenericErrorFunc func) { + old_error_func_ = xmlGenericError; + old_error_context_ = xmlGenericErrorContext; + xmlSetGenericErrorFunc(context, func); + } + ~ScopedXmlErrorFunc() { + xmlSetGenericErrorFunc(old_error_context_, old_error_func_); + } + + private: + xmlGenericErrorFunc old_error_func_; + void* old_error_context_; +}; + +// XmlReader is a wrapper class around libxml's xmlReader, +// providing a simplified C++ API. +class XmlReader { + public: + XmlReader(); + ~XmlReader(); + + // Load a document into the reader from memory. |input| must be UTF-8 and + // exist for the lifetime of this object. Returns false on error. + // TODO(evanm): handle encodings other than UTF-8? + bool Load(const std::string& input); + + // Load a document into the reader from a file. Returns false on error. + bool LoadFile(const std::string& file_path); + + // Wrappers around libxml functions ----------------------------------------- + + // Read() advances to the next node. Returns false on EOF or error. + bool Read() { return xmlTextReaderRead(reader_) == 1; } + + // Next(), when pointing at an opening tag, advances to the node after + // the matching closing tag. Returns false on EOF or error. + bool Next() { return xmlTextReaderNext(reader_) == 1; } + + // Return the depth in the tree of the current node. + int Depth() { return xmlTextReaderDepth(reader_); } + + // Returns the "local" name of the current node. + // For a tag like <foo:bar>, this is the string "foo:bar". + std::string NodeName() { + return XmlStringToStdString(xmlTextReaderConstLocalName(reader_)); + } + + // When pointing at a tag, retrieves the value of an attribute. + // Returns false on failure. + // E.g. for <foo bar:baz="a">, NodeAttribute("bar:baz", &value) + // returns true and |value| is set to "a". + bool NodeAttribute(const char* name, std::string* value); + + // Helper functions not provided by libxml ---------------------------------- + + // Return the string content within an element. + // "<foo>bar</foo>" is a sequence of three nodes: + // (1) open tag, (2) text, (3) close tag. + // With the reader currently at (1), this returns the text of (2), + // and advances past (3). + // Returns false on error. + bool ReadElementContent(std::string* content); + + // Skip to the next opening tag, returning false if we reach a closing + // tag or EOF first. + // If currently on an opening tag, doesn't advance at all. + bool SkipToElement(); + + // Returns the errors reported by libxml, if any. + // (libxml normally just dumps these errors to stderr.) + const std::string& errors() const { return errors_; } + + private: + // A callback for libxml to report errors. + static void GenericErrorCallback(void* context, const char* msg, ...); + + // Returns the libxml node type of the current node. + int NodeType() { return xmlTextReaderNodeType(reader_); } + + // The underlying libxml xmlTextReader. + xmlTextReaderPtr reader_; + + // error_func_ is used to reassign libxml's global error function + // to report errors into |errors_| for the lifetime of this object. + ScopedXmlErrorFunc error_func_; + std::string errors_; +}; + +// XmlWriter is a wrapper class around libxml's xmlWriter, +// providing a simplified C++ API. +// StartWriting must be called before other methods, and StopWriting +// must be called before GetWrittenString() will return results. +class XmlWriter { + public: + XmlWriter(); + ~XmlWriter(); + + // Allocates the xmlTextWriter and an xmlBuffer and starts an XML document. + // This must be called before any other functions. By default, indenting is + // set to true. + void StartWriting(); + + // Ends the XML document and frees the xmlTextWriter. + // This must be called before GetWrittenString() is called. + void StopWriting(); + // Wrappers around libxml functions ----------------------------------------- + + // All following elements will be indented to match their depth. + void StartIndenting() { xmlTextWriterSetIndent(writer_, 1); } + + // All follow elements will not be indented. + void StopIndenting() { xmlTextWriterSetIndent(writer_, 0); } + + // Start an element with the given name. All future elements added will be + // children of this element, until it is ended. Returns false on error. + bool StartElement(const std::string& element_name) { + return xmlTextWriterStartElement(writer_, + BAD_CAST element_name.c_str()) >= 0; + } + + // Ends the current open element. Returns false on error. + bool EndElement() { + return xmlTextWriterEndElement(writer_) >= 0; + } + + // Adds an attribute to the current open element. Returns false on error. + bool AddAttribute(const std::string& attribute_name, + const std::string& attribute_value) { + return xmlTextWriterWriteAttribute(writer_, + BAD_CAST attribute_name.c_str(), + BAD_CAST attribute_value.c_str()) >= 0; + } + + // Adds a new element with name |element_name| and content |content| + // to the buffer. Example: <|element_name|>|content|</|element_name|> + // Returns false on errors. + bool WriteElement(const std::string& element_name, + const std::string& content) { + return xmlTextWriterWriteElement(writer_, + BAD_CAST element_name.c_str(), + BAD_CAST content.c_str()) >= 0; + } + + // Helper functions not provided by xmlTextWriter --------------------------- + + // Returns the string that has been written to the buffer. + std::string GetWrittenString() { + if (buffer_ == NULL) + return ""; + return XmlStringToStdString(buffer_->content); + } + + private: + // The underlying libxml xmlTextWriter. + xmlTextWriterPtr writer_; + + // Stores the output. + xmlBufferPtr buffer_; +}; + +#endif // CHROME_COMMON_LIBXML_UTILS_H__ diff --git a/chrome/common/logging_chrome.cc b/chrome/common/logging_chrome.cc new file mode 100644 index 0000000..c3bdb77 --- /dev/null +++ b/chrome/common/logging_chrome.cc @@ -0,0 +1,294 @@ +// Copyright (c) 2010 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 "build/build_config.h" + +// Need to include this before most other files because it defines +// IPC_MESSAGE_LOG_ENABLED. We need to use it to define +// IPC_MESSAGE_MACROS_LOG_ENABLED so render_messages.h will generate the +// ViewMsgLog et al. functions. +#include "ipc/ipc_message.h" + +// On Windows, the about:ipc dialog shows IPCs; on POSIX, we hook up a +// logger in this file. (We implement about:ipc on Mac but implement +// the loggers here anyway). We need to do this real early to be sure +// IPC_MESSAGE_MACROS_LOG_ENABLED doesn't get undefined. +#if defined(OS_POSIX) && defined(IPC_MESSAGE_LOG_ENABLED) +#define IPC_MESSAGE_MACROS_LOG_ENABLED +#include "chrome/common/devtools_messages.h" +#include "chrome/common/plugin_messages.h" +#include "chrome/common/render_messages.h" +#include "chrome/common/worker_messages.h" +#endif + +#if defined(OS_WIN) +#include <windows.h> +#endif + +#include <fstream> + +#include "chrome/common/logging_chrome.h" + +#include "base/command_line.h" +#include "base/compiler_specific.h" +#include "base/debug_util.h" +#include "base/env_var.h" +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/logging.h" +#include "base/path_service.h" +#include "base/time.h" +#include "base/utf_string_conversions.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/env_vars.h" +#include "ipc/ipc_logging.h" +#if defined(OS_WIN) +#include "base/logging_win.h" +#include <initguid.h> +#endif + +// When true, this means that error dialogs should not be shown. +static bool dialogs_are_suppressed_ = false; + +// This should be true for exactly the period between the end of +// InitChromeLogging() and the beginning of CleanupChromeLogging(). +static bool chrome_logging_initialized_ = false; + +#if defined(OS_WIN) +// {7FE69228-633E-4f06-80C1-527FEA23E3A7} +DEFINE_GUID(kChromeTraceProviderName, + 0x7fe69228, 0x633e, 0x4f06, 0x80, 0xc1, 0x52, 0x7f, 0xea, 0x23, 0xe3, 0xa7); +#endif + +// Assertion handler for logging errors that occur when dialogs are +// silenced. To record a new error, pass the log string associated +// with that error in the str parameter. +MSVC_DISABLE_OPTIMIZE(); +static void SilentRuntimeAssertHandler(const std::string& str) { + DebugUtil::BreakDebugger(); +} +static void SilentRuntimeReportHandler(const std::string& str) { +} +MSVC_ENABLE_OPTIMIZE(); + +// Suppresses error/assertion dialogs and enables the logging of +// those errors into silenced_errors_. +static void SuppressDialogs() { + if (dialogs_are_suppressed_) + return; + + logging::SetLogAssertHandler(SilentRuntimeAssertHandler); + logging::SetLogReportHandler(SilentRuntimeReportHandler); + +#if defined(OS_WIN) + UINT new_flags = SEM_FAILCRITICALERRORS | + SEM_NOGPFAULTERRORBOX | + SEM_NOOPENFILEERRORBOX; + + // Preserve existing error mode, as discussed at http://t/dmea + UINT existing_flags = SetErrorMode(new_flags); + SetErrorMode(existing_flags | new_flags); +#endif + + dialogs_are_suppressed_ = true; +} + +namespace logging { + +LoggingDestination DetermineLogMode(const CommandLine& command_line) { + // only use OutputDebugString in debug mode +#ifdef NDEBUG + bool enable_logging = false; + const char *kInvertLoggingSwitch = switches::kEnableLogging; + const logging::LoggingDestination kDefaultLoggingMode = + logging::LOG_ONLY_TO_FILE; +#else + bool enable_logging = true; + const char *kInvertLoggingSwitch = switches::kDisableLogging; + const logging::LoggingDestination kDefaultLoggingMode = + logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG; +#endif + + if (command_line.HasSwitch(kInvertLoggingSwitch)) + enable_logging = !enable_logging; + + logging::LoggingDestination log_mode; + if (enable_logging) { + // Let --enable-logging=stderr force only stderr, particularly useful for + // non-debug builds where otherwise you can't get logs to stderr at all. + if (command_line.GetSwitchValueASCII(switches::kEnableLogging) == "stderr") + log_mode = logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG; + else + log_mode = kDefaultLoggingMode; + } else { + log_mode = logging::LOG_NONE; + } + return log_mode; +} + +#if defined(OS_CHROMEOS) +void SetUpSymlink(const FilePath& symlink_path, const FilePath& new_log_path) { + // We don't care if the unlink fails; we're going to continue anyway. + if (unlink(symlink_path.value().c_str()) == -1) + PLOG(WARNING) << "Unable to unlink " << symlink_path.value(); + if (symlink(new_log_path.value().c_str(), + symlink_path.value().c_str()) == -1) { + PLOG(ERROR) << "Unable to create symlink " << symlink_path.value() + << " pointing at " << new_log_path.value(); + } +} + +FilePath TimestampLog(const FilePath& new_log_file, base::Time timestamp) { + base::Time::Exploded time_deets; + timestamp.LocalExplode(&time_deets); + std::string suffix = StringPrintf("_%02d%02d%02d-%02d%02d%02d", + time_deets.year, + time_deets.month, + time_deets.day_of_month, + time_deets.hour, + time_deets.minute, + time_deets.second); + FilePath new_log_path = new_log_file.InsertBeforeExtension(suffix); + SetUpSymlink(new_log_file, new_log_path); + + return new_log_path; +} + +void RedirectChromeLogging(const FilePath& new_log_dir, + const CommandLine& command_line, + OldFileDeletionState delete_old_log_file) { + FilePath log_file_name = GetLogFileName().BaseName(); + FilePath new_log_path = + TimestampLog(new_log_dir.Append(log_file_name), base::Time::Now()); + InitLogging(new_log_path.value().c_str(), + DetermineLogMode(command_line), + logging::LOCK_LOG_FILE, + delete_old_log_file); +} +#endif + +void InitChromeLogging(const CommandLine& command_line, + OldFileDeletionState delete_old_log_file) { + DCHECK(!chrome_logging_initialized_) << + "Attempted to initialize logging when it was already initialized."; + +#if defined(OS_POSIX) && defined(IPC_MESSAGE_LOG_ENABLED) + IPC::Logging::SetLoggerFunctions(g_log_function_mapping); +#endif + + FilePath log_path = GetLogFileName(); +#if defined(OS_CHROMEOS) + log_path = TimestampLog(log_path, base::Time::Now()); +#endif + + logging::InitLogging(log_path.value().c_str(), + DetermineLogMode(command_line), + logging::LOCK_LOG_FILE, + delete_old_log_file); + + // we want process and thread IDs because we have a lot of things running + logging::SetLogItems(true, true, false, true); + + // We call running in unattended mode "headless", and allow + // headless mode to be configured either by the Environment + // Variable or by the Command Line Switch. This is for + // automated test purposes. + scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create()); + if (env->HasEnv(env_vars::kHeadless) || + command_line.HasSwitch(switches::kNoErrorDialogs)) + SuppressDialogs(); + + std::string log_filter_prefix = + command_line.GetSwitchValueASCII(switches::kLogFilterPrefix); + logging::SetLogFilterPrefix(log_filter_prefix.c_str()); + + // Use a minimum log level if the command line has one, otherwise set the + // default to LOG_WARNING. + std::string log_level = command_line.GetSwitchValueASCII( + switches::kLoggingLevel); + int level = 0; + if (StringToInt(log_level, &level)) { + if ((level >= 0) && (level < LOG_NUM_SEVERITIES)) + logging::SetMinLogLevel(level); + } else { + logging::SetMinLogLevel(LOG_WARNING); + } + +#if defined(OS_WIN) + // Enable trace control and transport through event tracing for Windows. + if (env->HasEnv(env_vars::kEtwLogging)) + logging::LogEventProvider::Initialize(kChromeTraceProviderName); +#endif + + chrome_logging_initialized_ = true; +} + +// This is a no-op, but we'll keep it around in case +// we need to do more cleanup in the future. +void CleanupChromeLogging() { + DCHECK(chrome_logging_initialized_) << + "Attempted to clean up logging when it wasn't initialized."; + + CloseLogFile(); + + chrome_logging_initialized_ = false; +} + +FilePath GetLogFileName() { + std::string filename; + scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create()); + if (env->GetEnv(env_vars::kLogFileName, &filename) && !filename.empty()) { +#if defined(OS_WIN) + return FilePath(UTF8ToWide(filename).c_str()); +#elif defined(OS_POSIX) + return FilePath(filename.c_str()); +#endif + } + + const FilePath log_filename(FILE_PATH_LITERAL("chrome_debug.log")); + FilePath log_path; + + if (PathService::Get(chrome::DIR_LOGS, &log_path)) { + log_path = log_path.Append(log_filename); + return log_path; + } else { + // error with path service, just use some default file somewhere + return log_filename; + } +} + +bool DialogsAreSuppressed() { + return dialogs_are_suppressed_; +} + +size_t GetFatalAssertions(AssertionList* assertions) { + // In this function, we don't assume that assertions is non-null, so + // that if you just want an assertion count, you can pass in NULL. + if (assertions) + assertions->clear(); + size_t assertion_count = 0; + + std::ifstream log_file; + log_file.open(GetLogFileName().value().c_str()); + if (!log_file.is_open()) + return 0; + + std::string utf8_line; + std::wstring wide_line; + while (!log_file.eof()) { + getline(log_file, utf8_line); + if (utf8_line.find(":FATAL:") != std::string::npos) { + wide_line = UTF8ToWide(utf8_line); + if (assertions) + assertions->push_back(wide_line); + ++assertion_count; + } + } + log_file.close(); + + return assertion_count; +} + +} // namespace logging diff --git a/chrome/common/logging_chrome.h b/chrome/common/logging_chrome.h new file mode 100644 index 0000000..57c3906 --- /dev/null +++ b/chrome/common/logging_chrome.h @@ -0,0 +1,68 @@ +// Copyright (c) 2006-2008 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 CHROME_COMMON_LOGGING_CHROME_H__ +#define CHROME_COMMON_LOGGING_CHROME_H__ + +#include <string> +#include <vector> + +#include "base/logging.h" + +class CommandLine; +class FilePath; + +namespace base { +class Time; +} + +namespace logging { + +// Call to initialize logging for Chrome. This sets up the chrome-specific +// logfile naming scheme and might do other things like log modules and +// setting levels in the future. +// +// The main process might want to delete any old log files on startup by +// setting delete_old_log_file, but the renderer processes should not, or +// they will delete each others' logs. +// +// XXX +// Setting suppress_error_dialogs to true disables any dialogs that would +// normally appear for assertions and crashes, and makes any catchable +// errors (namely assertions) available via GetSilencedErrorCount() +// and GetSilencedError(). +void InitChromeLogging(const CommandLine& command_line, + OldFileDeletionState delete_old_log_file); + +#if defined(OS_CHROMEOS) +void RedirectChromeLogging(const FilePath& new_log_dir, + const CommandLine& command_line, + OldFileDeletionState delete_old_log_file); +#endif + +// Call when done using logging for Chrome. +void CleanupChromeLogging(); + +// Returns the fully-qualified name of the log file. +FilePath GetLogFileName(); + +// Returns true when error/assertion dialogs are to be shown, +// false otherwise. +bool DialogsAreSuppressed(); + +typedef std::vector<std::wstring> AssertionList; + +// Gets the list of fatal assertions in the current log file, and +// returns the number of fatal assertions. (If you don't care +// about the actual list of assertions, you can pass in NULL.) +// NOTE: Since this reads the log file to determine the assertions, +// this operation is O(n) over the length of the log. +// NOTE: This can fail if the file is locked for writing. However, +// this is unlikely as this function is most useful after +// the program writing the log has terminated. +size_t GetFatalAssertions(AssertionList* assertions); + +} // namespace logging + +#endif // CHROME_COMMON_LOGGING_CHROME_H_ diff --git a/chrome/common/logging_chrome_uitest.cc b/chrome/common/logging_chrome_uitest.cc new file mode 100644 index 0000000..f92525e --- /dev/null +++ b/chrome/common/logging_chrome_uitest.cc @@ -0,0 +1,189 @@ +// Copyright (c) 2010 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 "build/build_config.h" + +#if defined(OS_WIN) +#include <windows.h> +#endif + +#include <string> + +#include "base/basictypes.h" +#include "base/command_line.h" +#include "base/env_var.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/env_vars.h" +#include "chrome/common/logging_chrome.h" +#include "chrome/test/automation/browser_proxy.h" +#include "chrome/test/ui/ui_test.h" +#include "testing/gtest/include/gtest/gtest.h" + +class ChromeLoggingTest : public testing::Test { + public: + // Stores the current value of the log file name environment + // variable and sets the variable to new_value. + void SaveEnvironmentVariable(std::string new_value) { + scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create()); + if (!env->GetEnv(env_vars::kLogFileName, &environment_filename_)) + environment_filename_ = ""; + + env->SetEnv(env_vars::kLogFileName, new_value); + } + + // Restores the value of the log file nave environment variable + // previously saved by SaveEnvironmentVariable(). + void RestoreEnvironmentVariable() { + scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create()); + env->SetEnv(env_vars::kLogFileName, environment_filename_); + } + + private: + std::string environment_filename_; // Saves real environment value. +}; + +// Tests the log file name getter without an environment variable. +TEST_F(ChromeLoggingTest, LogFileName) { + SaveEnvironmentVariable(""); + + FilePath filename = logging::GetLogFileName(); + ASSERT_NE(FilePath::StringType::npos, + filename.value().find(FILE_PATH_LITERAL("chrome_debug.log"))); + + RestoreEnvironmentVariable(); +} + +// Tests the log file name getter with an environment variable. +TEST_F(ChromeLoggingTest, EnvironmentLogFileName) { + SaveEnvironmentVariable("test value"); + + FilePath filename = logging::GetLogFileName(); + ASSERT_EQ(FilePath(FILE_PATH_LITERAL("test value")).value(), + filename.value()); + + RestoreEnvironmentVariable(); +} + +#if defined(OS_LINUX) && (!defined(NDEBUG) || !defined(USE_LINUX_BREAKPAD)) +// On Linux in Debug mode, Chrome generates a SIGTRAP. +// we do not catch SIGTRAPs, thus no crash dump. +// This also does not work if Breakpad is disabled. +#define EXPECTED_ASSERT_CRASHES 0 +#else +#define EXPECTED_ASSERT_CRASHES 1 +#endif + +#if !defined(NDEBUG) // We don't have assertions in release builds. +// Tests whether we correctly fail on browser assertions during tests. +class AssertionTest : public UITest { + protected: + AssertionTest() : UITest() { + // Initial loads will never complete due to assertion. + wait_for_initial_loads_ = false; + + // We're testing the renderer rather than the browser assertion here, + // because the browser assertion would flunk the test during SetUp() + // (since TAU wouldn't be able to find the browser window). + launch_arguments_.AppendSwitch(switches::kRendererAssertTest); + } +}; + +// Launch the app in assertion test mode, then close the app. +#if defined(OS_WIN) +// http://crbug.com/26715 +#define Assertion DISABLED_Assertion +#elif defined(OS_MACOSX) +// Crash service doesn't exist for the Mac yet: http://crbug.com/45243 +#define Assertion DISABLED_Assertion +#endif +TEST_F(AssertionTest, Assertion) { + if (UITest::in_process_renderer()) { + // in process mode doesn't do the crashing. + expected_errors_ = 0; + expected_crashes_ = 0; + } else { + expected_errors_ = 1; + expected_crashes_ = EXPECTED_ASSERT_CRASHES; + } +} +#endif // !defined(NDEBUG) + +#if !defined(OFFICIAL_BUILD) +// Only works on Linux in Release mode with CHROME_HEADLESS=1 +class CheckFalseTest : public UITest { + protected: + CheckFalseTest() : UITest() { + // Initial loads will never complete due to assertion. + wait_for_initial_loads_ = false; + + // We're testing the renderer rather than the browser assertion here, + // because the browser assertion would flunk the test during SetUp() + // (since TAU wouldn't be able to find the browser window). + launch_arguments_.AppendSwitch(switches::kRendererCheckFalseTest); + } +}; + +#if defined(OS_WIN) +// http://crbug.com/38497 +#define CheckFails FLAKY_CheckFails +#elif defined(OS_MACOSX) +// Crash service doesn't exist for the Mac yet: http://crbug.com/45243 +#define CheckFails DISABLED_CheckFails +#elif defined(OS_LINUX) +// TODO(phajdan) Fix this - http://crbug.com/49838 +#define CheckFails FAILS_CheckFails +#endif +// Launch the app in assertion test mode, then close the app. +TEST_F(CheckFalseTest, CheckFails) { + if (UITest::in_process_renderer()) { + // in process mode doesn't do the crashing. + expected_errors_ = 0; + expected_crashes_ = 0; + } else { + expected_errors_ = 1; + expected_crashes_ = EXPECTED_ASSERT_CRASHES; + } +} +#endif // !defined(OFFICIAL_BUILD) + +// Tests whether we correctly fail on browser crashes during UI Tests. +class RendererCrashTest : public UITest { + protected: + RendererCrashTest() : UITest() { + // Initial loads will never complete due to crash. + wait_for_initial_loads_ = false; + + launch_arguments_.AppendSwitch(switches::kRendererCrashTest); + } +}; + +#if defined(OS_LINUX) && !defined(USE_LINUX_BREAKPAD) +// On Linux, do not expect a crash dump if Breakpad is disabled. +#define EXPECTED_CRASH_CRASHES 0 +#else +#define EXPECTED_CRASH_CRASHES 1 +#endif + +#if defined(OS_WIN) +// http://crbug.com/32048 +#define Crash FLAKY_Crash +#elif defined(OS_CHROMEOS) +// http://crbug.com/43115 +#define Crash DISABLED_Crash +#elif defined(OS_MACOSX) +// Crash service doesn't exist for the Mac yet: http://crbug.com/45243 +#define Crash DISABLED_Crash +#endif +// Launch the app in renderer crash test mode, then close the app. +TEST_F(RendererCrashTest, Crash) { + if (UITest::in_process_renderer()) { + // in process mode doesn't do the crashing. + expected_crashes_ = 0; + } else { + scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0)); + ASSERT_TRUE(browser.get()); + ASSERT_TRUE(browser->WaitForTabCountToBecome(1, action_max_timeout_ms())); + expected_crashes_ = EXPECTED_CRASH_CRASHES; + } +} diff --git a/chrome/common/mach_message_source_mac.cc b/chrome/common/mach_message_source_mac.cc new file mode 100644 index 0000000..1249d8a --- /dev/null +++ b/chrome/common/mach_message_source_mac.cc @@ -0,0 +1,66 @@ +// Copyright (c) 2008 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 "chrome/common/mach_message_source_mac.h" + +#include "base/logging.h" + +MachMessageSource::MachMessageSource(mach_port_t port, + MachPortListener* msg_listener, + bool* success) { + DCHECK(msg_listener); + DCHECK(success); + DCHECK(port != MACH_PORT_NULL); + + CFMachPortContext port_context = {0}; + port_context.info = msg_listener; + + scoped_cftyperef<CFMachPortRef> cf_mach_port_ref( + CFMachPortCreateWithPort(kCFAllocatorDefault, + port, + MachMessageSource::OnReceiveMachMessage, + &port_context, + NULL)); + + if (cf_mach_port_ref.get() == NULL) { + LOG(WARNING) << "CFMachPortCreate failed"; + *success = false; + return; + } + + // Create a RL source. + machport_runloop_ref_.reset( + CFMachPortCreateRunLoopSource(kCFAllocatorDefault, + cf_mach_port_ref.get(), + 0)); + + if (machport_runloop_ref_.get() == NULL) { + LOG(WARNING) << "CFMachPortCreateRunLoopSource failed"; + *success = false; + return; + } + + CFRunLoopAddSource(CFRunLoopGetCurrent(), + machport_runloop_ref_.get(), + kCFRunLoopCommonModes); + *success = true; +} + +MachMessageSource::~MachMessageSource() { + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), + machport_runloop_ref_.get(), + kCFRunLoopCommonModes); +} + +// static +void MachMessageSource::OnReceiveMachMessage(CFMachPortRef port, void* msg, + CFIndex size, void* closure) { + MachPortListener *msg_listener = static_cast<MachPortListener*>(closure); + size_t msg_size = (size < 0) ? 0 : static_cast<size_t>(size); + DCHECK(msg && msg_size > 0); // this should never happen! + + if (msg_listener && msg && msg_size > 0) { + msg_listener->OnMachMessageReceived(msg, msg_size); + } +} diff --git a/chrome/common/mach_message_source_mac.h b/chrome/common/mach_message_source_mac.h new file mode 100644 index 0000000..f57539d --- /dev/null +++ b/chrome/common/mach_message_source_mac.h @@ -0,0 +1,59 @@ +// Copyright (c) 2008 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 CHROME_COMMON_MACH_MESSAGE_SOURCE_MAC_H_ +#define CHROME_COMMON_MACH_MESSAGE_SOURCE_MAC_H_ + +#include <CoreServices/CoreServices.h> + +#include "base/scoped_cftyperef.h" + +// Handles registering and cleaning up after a CFRunloopSource for a Mach port. +// Messages received on the port are piped through to a delegate. +// +// Example: +// class MyListener : public MachMessageSource::MachPortListener { +// public: +// void OnMachMessageReceived(void* mach_msg, size_t size) { +// printf("received message on Mach port\n"); +// } +// }; +// +// mach_port_t a_port = ...; +// MyListener listener; +// bool success = false; +// MachMessageSource message_source(port, listener, &success); +// +// if (!success) { +// exit(1); // Couldn't register mach runloop source. +// } +// +// CFRunLoopRun(); // Process messages on runloop... +class MachMessageSource { + public: + // Classes that want to listen on a Mach port can implement + // OnMachMessageReceived, |mach_msg| is a pointer to the raw message data and + // |size| is the buffer size; + class MachPortListener { + public: + virtual void OnMachMessageReceived(void* mach_msg, size_t size) = 0; + }; + + // |listener| is a week reference passed to CF, it needs to remain in + // existence till this object is destroeyd. + MachMessageSource(mach_port_t port, + MachPortListener* listener, + bool* success); + ~MachMessageSource(); + + private: + // Called by CF when a new message arrives on the Mach port. + static void OnReceiveMachMessage(CFMachPortRef port, void* msg, CFIndex size, + void* closure); + + scoped_cftyperef<CFRunLoopSourceRef> machport_runloop_ref_; + DISALLOW_COPY_AND_ASSIGN(MachMessageSource); +}; + +#endif // CHROME_COMMON_MACH_MESSAGE_SOURCE_MAC_H_ diff --git a/chrome/common/main_function_params.h b/chrome/common/main_function_params.h new file mode 100644 index 0000000..b224892 --- /dev/null +++ b/chrome/common/main_function_params.h @@ -0,0 +1,33 @@ +// Copyright (c) 2009 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. + +// Wrapper to the parameter list for the "main" entry points (browser, renderer, +// plugin) to shield the call sites from the differences between platforms +// (e.g., POSIX doesn't need to pass any sandbox information). + +#ifndef CHROME_COMMON_MAIN_FUNCTION_PARAMS_H_ +#define CHROME_COMMON_MAIN_FUNCTION_PARAMS_H_ + +#include "base/command_line.h" +#include "chrome/common/sandbox_init_wrapper.h" + +namespace base { +class ScopedNSAutoreleasePool; +}; +class Task; + +struct MainFunctionParams { + MainFunctionParams(const CommandLine& cl, const SandboxInitWrapper& sb, + base::ScopedNSAutoreleasePool* pool) + : command_line_(cl), sandbox_info_(sb), autorelease_pool_(pool), + ui_task(NULL) { } + const CommandLine& command_line_; + const SandboxInitWrapper& sandbox_info_; + base::ScopedNSAutoreleasePool* autorelease_pool_; + // Used by InProcessBrowserTest. If non-null BrowserMain schedules this + // task to run on the MessageLoop and BrowserInit is not invoked. + Task* ui_task; +}; + +#endif // CHROME_COMMON_MAIN_FUNCTION_PARAMS_H_ diff --git a/chrome/common/message_router.cc b/chrome/common/message_router.cc new file mode 100644 index 0000000..b73f2d0 --- /dev/null +++ b/chrome/common/message_router.cc @@ -0,0 +1,46 @@ +// Copyright (c) 2006-2008 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 "chrome/common/message_router.h" + +void MessageRouter::OnControlMessageReceived(const IPC::Message& msg) { + NOTREACHED() << + "should override in subclass if you care about control messages"; +} + +bool MessageRouter::Send(IPC::Message* msg) { + NOTREACHED() << + "should override in subclass if you care about sending messages"; + return false; +} + +void MessageRouter::AddRoute(int32 routing_id, + IPC::Channel::Listener* listener) { + routes_.AddWithID(listener, routing_id); +} + +void MessageRouter::RemoveRoute(int32 routing_id) { + routes_.Remove(routing_id); +} + +void MessageRouter::OnMessageReceived(const IPC::Message& msg) { + if (msg.routing_id() == MSG_ROUTING_CONTROL) { + OnControlMessageReceived(msg); + } else { + RouteMessage(msg); + } +} + +bool MessageRouter::RouteMessage(const IPC::Message& msg) { + IPC::Channel::Listener* listener = ResolveRoute(msg.routing_id()); + if (!listener) + return false; + + listener->OnMessageReceived(msg); + return true; +} + +IPC::Channel::Listener* MessageRouter::ResolveRoute(int32 routing_id) { + return routes_.Lookup(routing_id); +} diff --git a/chrome/common/message_router.h b/chrome/common/message_router.h new file mode 100644 index 0000000..35d2a5d --- /dev/null +++ b/chrome/common/message_router.h @@ -0,0 +1,62 @@ +// Copyright (c) 2006-2008 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 CHROME_COMMON_MESSAGE_ROUTER_H__ +#define CHROME_COMMON_MESSAGE_ROUTER_H__ + +#include "base/id_map.h" +#include "ipc/ipc_channel.h" + +// The MessageRouter handles all incoming messages sent to it by routing them +// to the correct listener. Routing is based on the Message's routing ID. +// Since routing IDs are typically assigned asynchronously by the browser +// process, the MessageRouter has the notion of pending IDs for listeners that +// have not yet been assigned a routing ID. +// +// When a message arrives, the routing ID is used to index the set of routes to +// find a listener. If a listener is found, then the message is passed to it. +// Otherwise, the message is ignored if its routing ID is not equal to +// MSG_ROUTING_CONTROL. +// +// The MessageRouter supports the IPC::Message::Sender interface for outgoing +// messages, but does not define a meaningful implementation of it. The +// subclass of MessageRouter is intended to provide that if appropriate. +// +// The MessageRouter can be used as a concrete class provided its Send method +// is not called and it does not receive any control messages. + +class MessageRouter : public IPC::Channel::Listener, + public IPC::Message::Sender { + public: + MessageRouter() {} + virtual ~MessageRouter() {} + + // Implemented by subclasses to handle control messages + virtual void OnControlMessageReceived(const IPC::Message& msg); + + // IPC::Channel::Listener implementation: + virtual void OnMessageReceived(const IPC::Message& msg); + + // Like OnMessageReceived, except it only handles routed messages. Returns + // true if the message was dispatched, or false if there was no listener for + // that route id. + virtual bool RouteMessage(const IPC::Message& msg); + + // IPC::Message::Sender implementation: + virtual bool Send(IPC::Message* msg); + + // Called to add/remove a listener for a particular message routing ID. + void AddRoute(int32 routing_id, IPC::Channel::Listener* listener); + void RemoveRoute(int32 routing_id); + + IPC::Channel::Listener* ResolveRoute(int32 routing_id); + + private: + // A list of all listeners with assigned routing IDs. + IDMap<IPC::Channel::Listener> routes_; + + DISALLOW_COPY_AND_ASSIGN(MessageRouter); +}; + +#endif // CHROME_COMMON_MESSAGE_ROUTER_H__ diff --git a/chrome/common/metrics_helpers.cc b/chrome/common/metrics_helpers.cc new file mode 100644 index 0000000..3bbaf3b --- /dev/null +++ b/chrome/common/metrics_helpers.cc @@ -0,0 +1,516 @@ +// Copyright (c) 2009 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 "chrome/common/metrics_helpers.h" + +#if defined(USE_SYSTEM_LIBBZ2) +#include <bzlib.h> +#else +#include "third_party/bzip2/bzlib.h" +#endif + +#include "base/base64.h" +#include "base/time.h" +#include "base/basictypes.h" +#include "base/file_util.h" +#include "base/md5.h" +#include "base/perftimer.h" +#include "base/scoped_ptr.h" +#include "base/string_util.h" +#include "base/sys_info.h" +#include "base/utf_string_conversions.h" +#include "base/third_party/nspr/prtime.h" +#include "chrome/common/logging_chrome.h" +#include "googleurl/src/gurl.h" +#include "libxml/xmlwriter.h" + +#define OPEN_ELEMENT_FOR_SCOPE(name) ScopedElement scoped_element(this, name) + +using base::Time; +using base::TimeDelta; + +// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx +#if defined(OS_WIN) +extern "C" IMAGE_DOS_HEADER __ImageBase; +#endif + +namespace { + +// libxml take xmlChar*, which is unsigned char* +inline const unsigned char* UnsignedChar(const char* input) { + return reinterpret_cast<const unsigned char*>(input); +} + +} // namespace + +class MetricsLogBase::XmlWrapper { + public: + XmlWrapper() + : doc_(NULL), + buffer_(NULL), + writer_(NULL) { + buffer_ = xmlBufferCreate(); + DCHECK(buffer_); + + #if defined(OS_CHROMEOS) + writer_ = xmlNewTextWriterDoc(&doc_, /* compression */ 0); + #else + writer_ = xmlNewTextWriterMemory(buffer_, /* compression */ 0); + #endif // OS_CHROMEOS + DCHECK(writer_); + + int result = xmlTextWriterSetIndent(writer_, 2); + DCHECK_EQ(0, result); + } + + ~XmlWrapper() { + FreeDocWriter(); + if (buffer_) { + xmlBufferFree(buffer_); + buffer_ = NULL; + } + } + + void FreeDocWriter() { + if (writer_) { + xmlFreeTextWriter(writer_); + writer_ = NULL; + } + if (doc_) { + xmlFreeDoc(doc_); + doc_ = NULL; + } + } + + xmlDocPtr doc() const { return doc_; } + xmlTextWriterPtr writer() const { return writer_; } + xmlBufferPtr buffer() const { return buffer_; } + + private: + xmlDocPtr doc_; + xmlBufferPtr buffer_; + xmlTextWriterPtr writer_; +}; + +// static +std::string MetricsLogBase::version_extension_; + +MetricsLogBase::MetricsLogBase(const std::string& client_id, int session_id, + const std::string& version_string) + : start_time_(Time::Now()), + client_id_(client_id), + session_id_(IntToString(session_id)), + locked_(false), + xml_wrapper_(new XmlWrapper), + num_events_(0) { + + StartElement("log"); + WriteAttribute("clientid", client_id_); + WriteInt64Attribute("buildtime", GetBuildTime()); + WriteAttribute("appversion", version_string); +} + +MetricsLogBase::~MetricsLogBase() { + delete xml_wrapper_; +} + +void MetricsLogBase::CloseLog() { + DCHECK(!locked_); + locked_ = true; + + int result = xmlTextWriterEndDocument(xml_wrapper_->writer()); + DCHECK_GE(result, 0); + + result = xmlTextWriterFlush(xml_wrapper_->writer()); + DCHECK_GE(result, 0); + +#if defined(OS_CHROMEOS) + xmlNodePtr root = xmlDocGetRootElement(xml_wrapper_->doc()); + if (!hardware_class_.empty()) { + // The hardware class is determined after the first ongoing log is + // constructed, so this adds the root element's "hardwareclass" + // attribute when the log is closed instead. + xmlNewProp(root, UnsignedChar("hardwareclass"), + UnsignedChar(hardware_class_.c_str())); + } + + // Flattens the XML tree into a character buffer. + PerfTimer dump_timer; + result = xmlNodeDump(xml_wrapper_->buffer(), xml_wrapper_->doc(), + root, /* level */ 0, /* format */ 1); + DCHECK_GE(result, 0); + UMA_HISTOGRAM_TIMES("UMA.XMLNodeDumpTime", dump_timer.Elapsed()); + + PerfTimer free_timer; + xml_wrapper_->FreeDocWriter(); + UMA_HISTOGRAM_TIMES("UMA.XMLWriterDestructionTime", free_timer.Elapsed()); +#endif // OS_CHROMEOS +} + +int MetricsLogBase::GetEncodedLogSize() { + DCHECK(locked_); + return xml_wrapper_->buffer()->use; +} + +bool MetricsLogBase::GetEncodedLog(char* buffer, int buffer_size) { + DCHECK(locked_); + if (buffer_size < GetEncodedLogSize()) + return false; + + memcpy(buffer, xml_wrapper_->buffer()->content, GetEncodedLogSize()); + return true; +} + +std::string MetricsLogBase::GetEncodedLogString() { + DCHECK(locked_); + return std::string(reinterpret_cast<char*>(xml_wrapper_->buffer()->content)); +} + +int MetricsLogBase::GetElapsedSeconds() { + return static_cast<int>((Time::Now() - start_time_).InSeconds()); +} + +std::string MetricsLogBase::CreateHash(const std::string& value) { + MD5Context ctx; + MD5Init(&ctx); + MD5Update(&ctx, value.data(), value.length()); + + MD5Digest digest; + MD5Final(&digest, &ctx); + + uint64 reverse_uint64; + // UMA only uses first 8 chars of hash. We use the above uint64 instead + // of a unsigned char[8] so that we don't run into strict aliasing issues + // in the LOG statement below when trying to interpret reverse as a uint64. + unsigned char* reverse = reinterpret_cast<unsigned char *>(&reverse_uint64); + DCHECK(arraysize(digest.a) >= sizeof(reverse_uint64)); + for (size_t i = 0; i < sizeof(reverse_uint64); ++i) + reverse[i] = digest.a[sizeof(reverse_uint64) - i - 1]; + // The following log is VERY helpful when folks add some named histogram into + // the code, but forgot to update the descriptive list of histograms. When + // that happens, all we get to see (server side) is a hash of the histogram + // name. We can then use this logging to find out what histogram name was + // being hashed to a given MD5 value by just running the version of Chromium + // in question with --enable-logging. + LOG(INFO) << "Metrics: Hash numeric [" << value << "]=[" + << reverse_uint64 << "]"; + return std::string(reinterpret_cast<char*>(digest.a), arraysize(digest.a)); +} + +std::string MetricsLogBase::CreateBase64Hash(const std::string& string) { + std::string encoded_digest; + if (base::Base64Encode(CreateHash(string), &encoded_digest)) { + DLOG(INFO) << "Metrics: Hash [" << encoded_digest << "]=[" << string << "]"; + return encoded_digest; + } + return std::string(); +} + +void MetricsLogBase::RecordUserAction(const char* key) { + DCHECK(!locked_); + + std::string command_hash = CreateBase64Hash(key); + if (command_hash.empty()) { + NOTREACHED() << "Unable generate encoded hash of command: " << key; + return; + } + + OPEN_ELEMENT_FOR_SCOPE("uielement"); + WriteAttribute("action", "command"); + WriteAttribute("targetidhash", command_hash); + + // TODO(jhughes): Properly track windows. + WriteIntAttribute("window", 0); + WriteCommonEventAttributes(); + + ++num_events_; +} + +void MetricsLogBase::RecordLoadEvent(int window_id, + const GURL& url, + PageTransition::Type origin, + int session_index, + TimeDelta load_time) { + DCHECK(!locked_); + + OPEN_ELEMENT_FOR_SCOPE("document"); + WriteAttribute("action", "load"); + WriteIntAttribute("docid", session_index); + WriteIntAttribute("window", window_id); + WriteAttribute("loadtime", Int64ToString(load_time.InMilliseconds())); + + std::string origin_string; + + switch (PageTransition::StripQualifier(origin)) { + // TODO(jhughes): Some of these mappings aren't right... we need to add + // some values to the server's enum. + case PageTransition::LINK: + case PageTransition::MANUAL_SUBFRAME: + origin_string = "link"; + break; + + case PageTransition::TYPED: + origin_string = "typed"; + break; + + case PageTransition::AUTO_BOOKMARK: + origin_string = "bookmark"; + break; + + case PageTransition::AUTO_SUBFRAME: + case PageTransition::RELOAD: + origin_string = "refresh"; + break; + + case PageTransition::GENERATED: + case PageTransition::KEYWORD: + origin_string = "global-history"; + break; + + case PageTransition::START_PAGE: + origin_string = "start-page"; + break; + + case PageTransition::FORM_SUBMIT: + origin_string = "form-submit"; + break; + + default: + NOTREACHED() << "Received an unknown page transition type: " << + PageTransition::StripQualifier(origin); + } + if (!origin_string.empty()) + WriteAttribute("origin", origin_string); + + WriteCommonEventAttributes(); + + ++num_events_; +} + +void MetricsLogBase::RecordWindowEvent(WindowEventType type, + int window_id, + int parent_id) { + DCHECK(!locked_); + + OPEN_ELEMENT_FOR_SCOPE("window"); + WriteAttribute("action", WindowEventTypeToString(type)); + WriteAttribute("windowid", IntToString(window_id)); + if (parent_id >= 0) + WriteAttribute("parent", IntToString(parent_id)); + WriteCommonEventAttributes(); + + ++num_events_; +} + +std::string MetricsLogBase::GetCurrentTimeString() { + return Uint64ToString(Time::Now().ToTimeT()); +} + +// These are the attributes that are common to every event. +void MetricsLogBase::WriteCommonEventAttributes() { + WriteAttribute("session", session_id_); + WriteAttribute("time", GetCurrentTimeString()); +} + +void MetricsLogBase::WriteAttribute(const std::string& name, + const std::string& value) { + DCHECK(!locked_); + DCHECK(!name.empty()); + + int result = xmlTextWriterWriteAttribute(xml_wrapper_->writer(), + UnsignedChar(name.c_str()), + UnsignedChar(value.c_str())); + DCHECK_GE(result, 0); +} + +void MetricsLogBase::WriteIntAttribute(const std::string& name, int value) { + WriteAttribute(name, IntToString(value)); +} + +void MetricsLogBase::WriteInt64Attribute(const std::string& name, int64 value) { + WriteAttribute(name, Int64ToString(value)); +} + +// static +const char* MetricsLogBase::WindowEventTypeToString(WindowEventType type) { + switch (type) { + case WINDOW_CREATE: return "create"; + case WINDOW_OPEN: return "open"; + case WINDOW_CLOSE: return "close"; + case WINDOW_DESTROY: return "destroy"; + + default: + NOTREACHED(); + return "unknown"; // Can't return NULL as this is used in a required + // attribute. + } +} + +void MetricsLogBase::StartElement(const char* name) { + DCHECK(!locked_); + DCHECK(name); + + int result = xmlTextWriterStartElement(xml_wrapper_->writer(), + UnsignedChar(name)); + DCHECK_GE(result, 0); +} + +void MetricsLogBase::EndElement() { + DCHECK(!locked_); + + int result = xmlTextWriterEndElement(xml_wrapper_->writer()); + DCHECK_GE(result, 0); +} + +// static +int64 MetricsLogBase::GetBuildTime() { + static int64 integral_build_time = 0; + if (!integral_build_time) { + Time time; + const char* kDateTime = __DATE__ " " __TIME__ " GMT"; + bool result = Time::FromString(ASCIIToWide(kDateTime).c_str(), &time); + DCHECK(result); + integral_build_time = static_cast<int64>(time.ToTimeT()); + } + return integral_build_time; +} + +// TODO(JAR): A The following should really be part of the histogram class. +// Internal state is being needlessly exposed, and it would be hard to reuse +// this code. If we moved this into the Histogram class, then we could use +// the same infrastructure for logging StatsCounters, RatesCounters, etc. +void MetricsLogBase::RecordHistogramDelta( + const Histogram& histogram, + const Histogram::SampleSet& snapshot) { + DCHECK(!locked_); + DCHECK_NE(0, snapshot.TotalCount()); + snapshot.CheckSize(histogram); + + // We will ignore the MAX_INT/infinite value in the last element of range[]. + + OPEN_ELEMENT_FOR_SCOPE("histogram"); + + WriteAttribute("name", CreateBase64Hash(histogram.histogram_name())); + + WriteInt64Attribute("sum", snapshot.sum()); + WriteInt64Attribute("sumsquares", snapshot.square_sum()); + + for (size_t i = 0; i < histogram.bucket_count(); i++) { + if (snapshot.counts(i)) { + OPEN_ELEMENT_FOR_SCOPE("histogrambucket"); + WriteIntAttribute("min", histogram.ranges(i)); + WriteIntAttribute("max", histogram.ranges(i + 1)); + WriteIntAttribute("count", snapshot.counts(i)); + } + } +} + + +// MetricsServiceBase +MetricsServiceBase::MetricsServiceBase() + : pending_log_(NULL), + compressed_log_(), + current_log_(NULL), + logged_samples_() { +} + +MetricsServiceBase::~MetricsServiceBase() { + if (pending_log_) { + delete pending_log_; + pending_log_ = NULL; + } + if (current_log_) { + delete current_log_; + current_log_ = NULL; + } +} + +// This implementation is based on the Firefox MetricsService implementation. +bool MetricsServiceBase::Bzip2Compress(const std::string& input, + std::string* output) { + bz_stream stream = {0}; + // As long as our input is smaller than the bzip2 block size, we should get + // the best compression. For example, if your input was 250k, using a block + // size of 300k or 500k should result in the same compression ratio. Since + // our data should be under 100k, using the minimum block size of 100k should + // allocate less temporary memory, but result in the same compression ratio. + int result = BZ2_bzCompressInit(&stream, + 1, // 100k (min) block size + 0, // quiet + 0); // default "work factor" + if (result != BZ_OK) { // out of memory? + return false; + } + + output->clear(); + + stream.next_in = const_cast<char*>(input.data()); + stream.avail_in = static_cast<int>(input.size()); + // NOTE: we don't need a BZ_RUN phase since our input buffer contains + // the entire input + do { + output->resize(output->size() + 1024); + stream.next_out = &((*output)[stream.total_out_lo32]); + stream.avail_out = static_cast<int>(output->size()) - stream.total_out_lo32; + result = BZ2_bzCompress(&stream, BZ_FINISH); + } while (result == BZ_FINISH_OK); + if (result != BZ_STREAM_END) // unknown failure? + return false; + result = BZ2_bzCompressEnd(&stream); + DCHECK(result == BZ_OK); + + output->resize(stream.total_out_lo32); + + return true; +} + +void MetricsServiceBase::RecordCurrentHistograms() { + DCHECK(current_log_); + + StatisticsRecorder::Histograms histograms; + StatisticsRecorder::GetHistograms(&histograms); + for (StatisticsRecorder::Histograms::const_iterator it = histograms.begin(); + histograms.end() != it; + ++it) { + if ((*it)->flags() & Histogram::kUmaTargetedHistogramFlag) + RecordHistogram(**it); + } +} + +void MetricsServiceBase::RecordHistogram(const Histogram& histogram) { + // Get up-to-date snapshot of sample stats. + Histogram::SampleSet snapshot; + histogram.SnapshotSample(&snapshot); + + const std::string& histogram_name = histogram.histogram_name(); + + // Find the already sent stats, or create an empty set. + LoggedSampleMap::iterator it = logged_samples_.find(histogram_name); + Histogram::SampleSet* already_logged; + if (logged_samples_.end() == it) { + // Add new entry + already_logged = &logged_samples_[histogram.histogram_name()]; + already_logged->Resize(histogram); // Complete initialization. + } else { + already_logged = &(it->second); + // Deduct any stats we've already logged from our snapshot. + snapshot.Subtract(*already_logged); + } + + // Snapshot now contains only a delta to what we've already_logged. + + if (snapshot.TotalCount() > 0) { + current_log_->RecordHistogramDelta(histogram, snapshot); + // Add new data into our running total. + already_logged->Add(snapshot); + } +} + +void MetricsServiceBase::DiscardPendingLog() { + if (pending_log_) { // Shutdown might have deleted it! + delete pending_log_; + pending_log_ = NULL; + } + compressed_log_.clear(); +} diff --git a/chrome/common/metrics_helpers.h b/chrome/common/metrics_helpers.h new file mode 100644 index 0000000..8051273 --- /dev/null +++ b/chrome/common/metrics_helpers.h @@ -0,0 +1,223 @@ +// Copyright (c) 2010 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 defines a set of user experience metrics data recorded by +// the MetricsService. This is the unit of data that is sent to the server. + +#ifndef CHROME_COMMON_METRICS_HELPERS_H_ +#define CHROME_COMMON_METRICS_HELPERS_H_ + +#include <map> +#include <string> + +#include "base/basictypes.h" +#include "base/histogram.h" +#include "base/time.h" +#include "chrome/common/page_transition_types.h" + +class GURL; +class MetricsLog; + +// This class provides base functionality for logging metrics data. +class MetricsLogBase { + public: + // Creates a new metrics log + // client_id is the identifier for this profile on this installation + // session_id is an integer that's incremented on each application launch + MetricsLogBase(const std::string& client_id, int session_id, + const std::string& version_string); + virtual ~MetricsLogBase(); + + // Records a user-initiated action. + void RecordUserAction(const char* key); + + enum WindowEventType { + WINDOW_CREATE = 0, + WINDOW_OPEN, + WINDOW_CLOSE, + WINDOW_DESTROY + }; + + void RecordWindowEvent(WindowEventType type, int window_id, int parent_id); + + // Records a page load. + // window_id - the index of the tab in which the load took place + // url - which URL was loaded + // origin - what kind of action initiated the load + // load_time - how long it took to load the page + void RecordLoadEvent(int window_id, + const GURL& url, + PageTransition::Type origin, + int session_index, + base::TimeDelta load_time); + + // Record any changes in a given histogram for transmission. + void RecordHistogramDelta(const Histogram& histogram, + const Histogram::SampleSet& snapshot); + + // Stop writing to this record and generate the encoded representation. + // None of the Record* methods can be called after this is called. + void CloseLog(); + + // These methods allow retrieval of the encoded representation of the + // record. They can only be called after CloseLog() has been called. + // GetEncodedLog returns false if buffer_size is less than + // GetEncodedLogSize(); + int GetEncodedLogSize(); + bool GetEncodedLog(char* buffer, int buffer_size); + // Returns an empty string on failure. + std::string GetEncodedLogString(); + + // Returns the amount of time in seconds that this log has been in use. + int GetElapsedSeconds(); + + int num_events() { return num_events_; } + + void set_hardware_class(const std::string& hardware_class) { + hardware_class_ = hardware_class; + } + + // Creates an MD5 hash of the given value, and returns hash as a byte + // buffer encoded as a std::string. + static std::string CreateHash(const std::string& value); + + // Return a base64-encoded MD5 hash of the given string. + static std::string CreateBase64Hash(const std::string& string); + + // Get the GMT buildtime for the current binary, expressed in seconds since + // Januray 1, 1970 GMT. + // The value is used to identify when a new build is run, so that previous + // reliability stats, from other builds, can be abandoned. + static int64 GetBuildTime(); + + // Use |extension| in all uploaded appversions in addition to the standard + // version string. + static void set_version_extension(const std::string& extension) { + version_extension_ = extension; + } + + virtual MetricsLog* AsMetricsLog() { + return NULL; + } + + protected: + class XmlWrapper; + + // Returns a string containing the current time. + // Virtual so that it can be overridden for testing. + virtual std::string GetCurrentTimeString(); + // Helper class that invokes StartElement from constructor, and EndElement + // from destructor. + // + // Use the macro OPEN_ELEMENT_FOR_SCOPE to help avoid usage problems. + class ScopedElement { + public: + ScopedElement(MetricsLogBase* log, const std::string& name) : log_(log) { + DCHECK(log); + log->StartElement(name.c_str()); + } + + ScopedElement(MetricsLogBase* log, const char* name) : log_(log) { + DCHECK(log); + log->StartElement(name); + } + + ~ScopedElement() { + log_->EndElement(); + } + + private: + MetricsLogBase* log_; + }; + friend class ScopedElement; + + static const char* WindowEventTypeToString(WindowEventType type); + + // Frees the resources allocated by the XML document writer: the + // main writer object as well as the XML tree structure, if + // applicable. + void FreeDocWriter(); + + // Convenience versions of xmlWriter functions + void StartElement(const char* name); + void EndElement(); + void WriteAttribute(const std::string& name, const std::string& value); + void WriteIntAttribute(const std::string& name, int value); + void WriteInt64Attribute(const std::string& name, int64 value); + + // Write the attributes that are common to every metrics event type. + void WriteCommonEventAttributes(); + + // An extension that is appended to the appversion in each log. + static std::string version_extension_; + + base::Time start_time_; + base::Time end_time_; + + std::string client_id_; + std::string session_id_; + std::string hardware_class_; + + // locked_ is true when record has been packed up for sending, and should + // no longer be written to. It is only used for sanity checking and is + // not a real lock. + bool locked_; + + // Isolated to limit the dependency on the XML library for our consumers. + XmlWrapper* xml_wrapper_; + + int num_events_; // the number of events recorded in this log + + DISALLOW_COPY_AND_ASSIGN(MetricsLogBase); +}; + +// This class provides base functionality for logging metrics data. +// TODO(ananta) +// Factor out more common code from chrome and chrome frame metrics service +// into this class. +class MetricsServiceBase { + protected: + MetricsServiceBase(); + virtual ~MetricsServiceBase(); + + // Check to see if there is a log that needs to be, or is being, transmitted. + bool pending_log() const { + return pending_log_ || !compressed_log_.empty(); + } + + // Compress the report log in |input| using bzip2, store the result in + // |output|. + bool Bzip2Compress(const std::string& input, std::string* output); + + // Discard |pending_log_|, and clear |compressed_log_|. Called after + // processing of this log is complete. + void DiscardPendingLog(); + + // Record complete list of histograms into the current log. + // Called when we close a log. + void RecordCurrentHistograms(); + + // Record a specific histogram . + void RecordHistogram(const Histogram& histogram); + + // A log that we are currently transmiting, or about to try to transmit. + MetricsLogBase* pending_log_; + + // An alternate form of |pending_log_|. We persistently save this version + // into prefs if we can't transmit it. As a result, sometimes all we have is + // the compressed text version. + std::string compressed_log_; + + // The log that we are still appending to. + MetricsLogBase* current_log_; + + // Maintain a map of histogram names to the sample stats we've sent. + typedef std::map<std::string, Histogram::SampleSet> LoggedSampleMap; + + // For histograms, record what we've already logged (as a sample for each + // histogram) so that we can send only the delta with the next log. + LoggedSampleMap logged_samples_; +}; + +#endif // CHROME_COMMON_METRICS_HELPERS_H_ diff --git a/chrome/common/mru_cache.h b/chrome/common/mru_cache.h new file mode 100644 index 0000000..b2643f8 --- /dev/null +++ b/chrome/common/mru_cache.h @@ -0,0 +1,252 @@ +// Copyright (c) 2009 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 contains a template for a Most Recently Used cache that allows +// constant-time access to items using a key, but easy identification of the +// least-recently-used items for removal. Each key can only be associated with +// one payload item at a time. +// +// The key object will be stored twice, so it should support efficient copying. +// +// NOTE: While all operations are O(1), this code is written for +// legibility rather than optimality. If future profiling identifies this as +// a bottleneck, there is room for smaller values of 1 in the O(1). :] + +#ifndef CHROME_COMMON_MRU_CACHE_H__ +#define CHROME_COMMON_MRU_CACHE_H__ + +#include <list> +#include <map> +#include <utility> + +#include "base/basictypes.h" +#include "base/logging.h" + +// MRUCacheBase ---------------------------------------------------------------- + +// Base class for the MRU cache specializations defined below. +// The deletor will get called on all payloads that are being removed or +// replaced. +template <class KeyType, class PayloadType, class DeletorType> +class MRUCacheBase { + public: + // The payload of the list. This maintains a copy of the key so we can + // efficiently delete things given an element of the list. + typedef std::pair<KeyType, PayloadType> value_type; + + private: + typedef std::list<value_type> PayloadList; + typedef std::map<KeyType, typename PayloadList::iterator> KeyIndex; + + public: + typedef typename PayloadList::size_type size_type; + + typedef typename PayloadList::iterator iterator; + typedef typename PayloadList::const_iterator const_iterator; + typedef typename PayloadList::reverse_iterator reverse_iterator; + typedef typename PayloadList::const_reverse_iterator const_reverse_iterator; + + enum { NO_AUTO_EVICT = 0 }; + + // The max_size is the size at which the cache will prune its members to when + // a new item is inserted. If the caller wants to manager this itself (for + // example, maybe it has special work to do when something is evicted), it + // can pass NO_AUTO_EVICT to not restrict the cache size. + explicit MRUCacheBase(size_type max_size) : max_size_(max_size) { + } + + virtual ~MRUCacheBase() { + iterator i = begin(); + while (i != end()) + i = Erase(i); + } + + // Inserts a payload item with the given key. If an existing item has + // the same key, it is removed prior to insertion. An iterator indicating the + // inserted item will be returned (this will always be the front of the list). + // + // The payload will be copied. In the case of an OwningMRUCache, this function + // will take ownership of the pointer. + iterator Put(const KeyType& key, const PayloadType& payload) { + // Remove any existing payload with that key. + typename KeyIndex::iterator index_iter = index_.find(key); + if (index_iter != index_.end()) { + // Erase the reference to it. This will call the deletor on the removed + // element. The index reference will be replaced in the code below. + Erase(index_iter->second); + } else if (max_size_ != NO_AUTO_EVICT) { + // New item is being inserted which might make it larger than the maximum + // size: kick the oldest thing out if necessary. + ShrinkToSize(max_size_ - 1); + } + + ordering_.push_front(value_type(key, payload)); + index_[key] = ordering_.begin(); + return ordering_.begin(); + } + + // Retrieves the contents of the given key, or end() if not found. This method + // has the side effect of moving the requested item to the front of the + // recency list. + // + // TODO(brettw) We may want a const version of this function in the future. + iterator Get(const KeyType& key) { + typename KeyIndex::iterator index_iter = index_.find(key); + if (index_iter == index_.end()) + return end(); + typename PayloadList::iterator iter = index_iter->second; + + // Move the touched item to the front of the recency ordering. + ordering_.splice(ordering_.begin(), ordering_, iter); + return ordering_.begin(); + } + + // Retrieves the payload associated with a given key and returns it via + // result without affecting the ordering (unlike Get). + // + // TODO(brettw) We may want a const version of this function in the future. + iterator Peek(const KeyType& key) { + typename KeyIndex::const_iterator index_iter = index_.find(key); + if (index_iter == index_.end()) + return end(); + return index_iter->second; + } + + // Erases the item referenced by the given iterator. An iterator to the item + // following it will be returned. The iterator must be valid. + iterator Erase(iterator pos) { + deletor_(pos->second); + index_.erase(pos->first); + return ordering_.erase(pos); + } + + // MRUCache entries are often processed in reverse order, so we add this + // convenience function (not typically defined by STL containers). + reverse_iterator Erase(reverse_iterator pos) { + // We have to actually give it the incremented iterator to delete, since + // the forward iterator that base() returns is actually one past the item + // being iterated over. + return reverse_iterator(Erase((++pos).base())); + } + + // Shrinks the cache so it only holds |new_size| items. If |new_size| is + // bigger or equal to the current number of items, this will do nothing. + void ShrinkToSize(size_type new_size) { + for (size_type i = size(); i > new_size; i--) + Erase(rbegin()); + } + + // Deletes everything from the cache. + void Clear() { + for (typename PayloadList::iterator i(ordering_.begin()); + i != ordering_.end(); ++i) + deletor_(i->second); + index_.clear(); + ordering_.clear(); + } + + // Returns the number of elements in the cache. + size_type size() const { + // We don't use ordering_.size() for the return value because + // (as a linked list) it can be O(n). + DCHECK(index_.size() == ordering_.size()); + return index_.size(); + } + + // Allows iteration over the list. Forward iteration starts with the most + // recent item and works backwards. + // + // Note that since these iterators are actually iterators over a list, you + // can keep them as you insert or delete things (as long as you don't delete + // the one you are pointing to) and they will still be valid. + iterator begin() { return ordering_.begin(); } + const_iterator begin() const { ordering_.begin(); } + iterator end() { return ordering_.end(); } + const_iterator end() const { return ordering_.end(); } + + reverse_iterator rbegin() { return ordering_.rbegin(); } + const_reverse_iterator rbegin() const { ordering_.rbegin(); } + reverse_iterator rend() { return ordering_.rend(); } + const_reverse_iterator rend() const { return ordering_.rend(); } + + bool empty() const { return ordering_.empty(); } + + private: + PayloadList ordering_; + KeyIndex index_; + + size_type max_size_; + + DeletorType deletor_; + + DISALLOW_COPY_AND_ASSIGN(MRUCacheBase); +}; + +// MRUCache -------------------------------------------------------------------- + +// A functor that does nothing. Used by the MRUCache. +template<class PayloadType> +class MRUCacheNullDeletor { + public: + void operator()(PayloadType& payload) { + } +}; + +// A container that does not do anything to free its data. Use this when storing +// value types (as opposed to pointers) in the list. +template <class KeyType, class PayloadType> +class MRUCache : public MRUCacheBase<KeyType, + PayloadType, + MRUCacheNullDeletor<PayloadType> > { + private: + typedef MRUCacheBase<KeyType, PayloadType, + MRUCacheNullDeletor<PayloadType> > ParentType; + + public: + // See MRUCacheBase, noting the possibility of using NO_AUTO_EVICT. + explicit MRUCache(typename ParentType::size_type max_size) + : ParentType(max_size) { + } + virtual ~MRUCache() { + } + + private: + DISALLOW_COPY_AND_ASSIGN(MRUCache); +}; + +// OwningMRUCache -------------------------------------------------------------- + +template<class PayloadType> +class MRUCachePointerDeletor { + public: + void operator()(PayloadType& payload) { + delete payload; + } +}; + +// A cache that owns the payload type, which must be a non-const pointer type. +// The pointers will be deleted when they are removed, replaced, or when the +// cache is destroyed. +template <class KeyType, class PayloadType> +class OwningMRUCache + : public MRUCacheBase<KeyType, + PayloadType, + MRUCachePointerDeletor<PayloadType> > { + private: + typedef MRUCacheBase<KeyType, PayloadType, + MRUCachePointerDeletor<PayloadType> > ParentType; + + public: + // See MRUCacheBase, noting the possibility of using NO_AUTO_EVICT. + explicit OwningMRUCache(typename ParentType::size_type max_size) + : ParentType(max_size) { + } + virtual ~OwningMRUCache() { + } + + private: + DISALLOW_COPY_AND_ASSIGN(OwningMRUCache); +}; + +#endif // CHROME_COMMON_MRU_CACHE_H__ diff --git a/chrome/common/mru_cache_unittest.cc b/chrome/common/mru_cache_unittest.cc new file mode 100644 index 0000000..7cfb7d8 --- /dev/null +++ b/chrome/common/mru_cache_unittest.cc @@ -0,0 +1,253 @@ +// Copyright (c) 2009 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/basictypes.h" +#include "chrome/common/mru_cache.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +int cached_item_live_count = 0; + +struct CachedItem { + CachedItem() : value(0) { + cached_item_live_count++; + } + + explicit CachedItem(int new_value) : value(new_value) { + cached_item_live_count++; + } + + explicit CachedItem(const CachedItem& other) : value(other.value) { + cached_item_live_count++; + } + + ~CachedItem() { + cached_item_live_count--; + } + + int value; +}; + +} // namespace + +TEST(MRUCacheTest, Basic) { + typedef MRUCache<int, CachedItem> Cache; + Cache cache(Cache::NO_AUTO_EVICT); + + // Check failure conditions + { + CachedItem test_item; + EXPECT_TRUE(cache.Get(0) == cache.end()); + EXPECT_TRUE(cache.Peek(0) == cache.end()); + } + + static const int kItem1Key = 5; + CachedItem item1(10); + Cache::iterator inserted_item = cache.Put(kItem1Key, item1); + EXPECT_EQ(1U, cache.size()); + + // Check that item1 was properly inserted. + { + Cache::iterator found = cache.Get(kItem1Key); + EXPECT_TRUE(inserted_item == cache.begin()); + EXPECT_TRUE(found != cache.end()); + + found = cache.Peek(kItem1Key); + EXPECT_TRUE(found != cache.end()); + + EXPECT_EQ(kItem1Key, found->first); + EXPECT_EQ(item1.value, found->second.value); + } + + static const int kItem2Key = 7; + CachedItem item2(12); + cache.Put(kItem2Key, item2); + EXPECT_EQ(2U, cache.size()); + + // Check that item1 is the oldest since item2 was added afterwards. + { + Cache::reverse_iterator oldest = cache.rbegin(); + ASSERT_TRUE(oldest != cache.rend()); + EXPECT_EQ(kItem1Key, oldest->first); + EXPECT_EQ(item1.value, oldest->second.value); + } + + // Check that item1 is still accessible by key. + { + Cache::iterator test_item = cache.Get(kItem1Key); + ASSERT_TRUE(test_item != cache.end()); + EXPECT_EQ(kItem1Key, test_item->first); + EXPECT_EQ(item1.value, test_item->second.value); + } + + // Check that retrieving item1 pushed item2 to oldest. + { + Cache::reverse_iterator oldest = cache.rbegin(); + ASSERT_TRUE(oldest != cache.rend()); + EXPECT_EQ(kItem2Key, oldest->first); + EXPECT_EQ(item2.value, oldest->second.value); + } + + // Remove the oldest item and check that item1 is now the only member. + { + Cache::reverse_iterator next = cache.Erase(cache.rbegin()); + + EXPECT_EQ(1U, cache.size()); + + EXPECT_TRUE(next == cache.rbegin()); + EXPECT_EQ(kItem1Key, next->first); + EXPECT_EQ(item1.value, next->second.value); + + cache.Erase(cache.begin()); + EXPECT_EQ(0U, cache.size()); + } + + // Check that Clear() works properly. + cache.Put(kItem1Key, item1); + cache.Put(kItem2Key, item2); + EXPECT_EQ(2U, cache.size()); + cache.Clear(); + EXPECT_EQ(0U, cache.size()); +} + +TEST(MRUCacheTest, GetVsPeek) { + typedef MRUCache<int, CachedItem> Cache; + Cache cache(Cache::NO_AUTO_EVICT); + + static const int kItem1Key = 1; + CachedItem item1(10); + cache.Put(kItem1Key, item1); + + static const int kItem2Key = 2; + CachedItem item2(20); + cache.Put(kItem2Key, item2); + + // This should do nothing since the size is bigger than the number of items. + cache.ShrinkToSize(100); + + // Check that item1 starts out as oldest + { + Cache::reverse_iterator iter = cache.rbegin(); + ASSERT_TRUE(iter != cache.rend()); + EXPECT_EQ(kItem1Key, iter->first); + EXPECT_EQ(item1.value, iter->second.value); + } + + // Check that Peek doesn't change ordering + { + Cache::iterator peekiter = cache.Peek(kItem1Key); + ASSERT_TRUE(peekiter != cache.end()); + + Cache::reverse_iterator iter = cache.rbegin(); + ASSERT_TRUE(iter != cache.rend()); + EXPECT_EQ(kItem1Key, iter->first); + EXPECT_EQ(item1.value, iter->second.value); + } +} + +TEST(MRUCacheTest, KeyReplacement) { + typedef MRUCache<int, CachedItem> Cache; + Cache cache(Cache::NO_AUTO_EVICT); + + static const int kItem1Key = 1; + CachedItem item1(10); + cache.Put(kItem1Key, item1); + + static const int kItem2Key = 2; + CachedItem item2(20); + cache.Put(kItem2Key, item2); + + static const int kItem3Key = 3; + CachedItem item3(30); + cache.Put(kItem3Key, item3); + + static const int kItem4Key = 4; + CachedItem item4(40); + cache.Put(kItem4Key, item4); + + CachedItem item5(50); + cache.Put(kItem3Key, item5); + + EXPECT_EQ(4U, cache.size()); + for (int i = 0; i < 3; ++i) { + Cache::reverse_iterator iter = cache.rbegin(); + ASSERT_TRUE(iter != cache.rend()); + } + + // Make it so only the most important element is there. + cache.ShrinkToSize(1); + + Cache::iterator iter = cache.begin(); + EXPECT_EQ(kItem3Key, iter->first); + EXPECT_EQ(item5.value, iter->second.value); +} + +// Make sure that the owning version release its pointers properly. +TEST(MRUCacheTest, Owning) { + typedef OwningMRUCache<int, CachedItem*> Cache; + Cache cache(Cache::NO_AUTO_EVICT); + + int initial_count = cached_item_live_count; + + // First insert and item and then overwrite it. + static const int kItem1Key = 1; + cache.Put(kItem1Key, new CachedItem(20)); + cache.Put(kItem1Key, new CachedItem(22)); + + // There should still be one item, and one extra live item. + Cache::iterator iter = cache.Get(kItem1Key); + EXPECT_EQ(1U, cache.size()); + EXPECT_TRUE(iter != cache.end()); + EXPECT_EQ(initial_count + 1, cached_item_live_count); + + // Now remove it. + cache.Erase(cache.begin()); + EXPECT_EQ(initial_count, cached_item_live_count); + + // Now try another cache that goes out of scope to make sure its pointers + // go away. + { + Cache cache2(Cache::NO_AUTO_EVICT); + cache2.Put(1, new CachedItem(20)); + cache2.Put(2, new CachedItem(20)); + } + + // There should be no objects leaked. + EXPECT_EQ(initial_count, cached_item_live_count); + + // Check that Clear() also frees things correctly. + { + Cache cache2(Cache::NO_AUTO_EVICT); + cache2.Put(1, new CachedItem(20)); + cache2.Put(2, new CachedItem(20)); + EXPECT_EQ(initial_count + 2, cached_item_live_count); + cache2.Clear(); + EXPECT_EQ(initial_count, cached_item_live_count); + } +} + +TEST(MRUCacheTest, AutoEvict) { + typedef OwningMRUCache<int, CachedItem*> Cache; + static const Cache::size_type kMaxSize = 3; + + int initial_count = cached_item_live_count; + + { + Cache cache(kMaxSize); + + static const int kItem1Key = 1, kItem2Key = 2, kItem3Key = 3, kItem4Key = 4; + cache.Put(kItem1Key, new CachedItem(20)); + cache.Put(kItem2Key, new CachedItem(21)); + cache.Put(kItem3Key, new CachedItem(22)); + cache.Put(kItem4Key, new CachedItem(23)); + + // The cache should only have kMaxSize items in it even though we inserted + // more. + EXPECT_EQ(kMaxSize, cache.size()); + } + + // There should be no objects leaked. + EXPECT_EQ(initial_count, cached_item_live_count); +} diff --git a/chrome/common/nacl_cmd_line.cc b/chrome/common/nacl_cmd_line.cc new file mode 100644 index 0000000..a54f196 --- /dev/null +++ b/chrome/common/nacl_cmd_line.cc @@ -0,0 +1,40 @@ +// Copyright (c) 2010 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/command_line.h" +#include "chrome/common/chrome_constants.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/logging_chrome.h" + +namespace nacl { + void CopyNaClCommandLineArguments(CommandLine* cmd_line) { + const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); + if (logging::DialogsAreSuppressed()) + cmd_line->AppendSwitch(switches::kNoErrorDialogs); + + // Propagate the following switches to the NaCl loader command line (along + // with any associated values) if present in the browser command line. + // TODO(gregoryd): check which flags of those below can be supported. + static const char* const switch_names[] = { + switches::kNoSandbox, + switches::kTestNaClSandbox, + switches::kDisableBreakpad, + switches::kFullMemoryCrashReport, + switches::kEnableLogging, + switches::kDisableLogging, + switches::kLoggingLevel, + switches::kEnableDCHECK, + switches::kSilentDumpOnDCHECK, + switches::kMemoryProfiling, + }; + + for (size_t i = 0; i < arraysize(switch_names); ++i) { + if (browser_command_line.HasSwitch(switch_names[i])) { + cmd_line->AppendSwitchWithValue( + switch_names[i], + browser_command_line.GetSwitchValueASCII(switch_names[i])); + } + } + } +} diff --git a/chrome/common/nacl_cmd_line.h b/chrome/common/nacl_cmd_line.h new file mode 100644 index 0000000..1091e11 --- /dev/null +++ b/chrome/common/nacl_cmd_line.h @@ -0,0 +1,16 @@ +// Copyright (c) 2010 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 CHROME_COMMON_NACL_CMD_LINE_H_ +#define CHROME_COMMON_NACL_CMD_LINE_H_ + +#include "base/command_line.h" + +namespace nacl { + // Copy all the relevant arguments from the command line of the current + // process to cmd_line that will be used for launching the NaCl loader/broker. + void CopyNaClCommandLineArguments(CommandLine* cmd_line); +} + +#endif // CHROME_COMMON_NACL_CMD_LINE_H_ diff --git a/chrome/common/nacl_messages.h b/chrome/common/nacl_messages.h new file mode 100644 index 0000000..8d360dd --- /dev/null +++ b/chrome/common/nacl_messages.h @@ -0,0 +1,19 @@ +// Copyright (c) 2009 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. + +// Defines messages between the browser and NaCl process. + +#ifndef CHROME_COMMON_NACL_MESSAGES_H_ +#define CHROME_COMMON_NACL_MESSAGES_H_ + +#include <string> + +#include "base/basictypes.h" +#include "ipc/ipc_message_utils.h" + +#define MESSAGES_INTERNAL_FILE "chrome/common/nacl_messages_internal.h" +#include "ipc/ipc_message_macros.h" + +#endif // CHROME_COMMON_NACL_MESSAGES_H_ + diff --git a/chrome/common/nacl_messages_internal.h b/chrome/common/nacl_messages_internal.h new file mode 100644 index 0000000..abde832 --- /dev/null +++ b/chrome/common/nacl_messages_internal.h @@ -0,0 +1,30 @@ +// Copyright (c) 2009 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 "chrome/common/nacl_types.h" +#include "ipc/ipc_message_macros.h" + +//----------------------------------------------------------------------------- +// NaClProcess messages +// These are messages sent from the browser to the NaCl process. +IPC_BEGIN_MESSAGES(NaClProcess) + // Tells the NaCl process to start. + IPC_MESSAGE_CONTROL2(NaClProcessMsg_Start, + int /* descriptor id */, + nacl::FileDescriptor /* handle value */) + + // Tells the NaCl broker to launch a NaCl loader process. + IPC_MESSAGE_CONTROL1(NaClProcessMsg_LaunchLoaderThroughBroker, + std::wstring /* channel ID for the loader */) + + // Notify the browser process that the loader was launched successfully. + IPC_MESSAGE_CONTROL2(NaClProcessMsg_LoaderLaunched, + std::wstring, /* channel ID for the loader */ + base::ProcessHandle /* loader process handle */) + + // Notify the broker that all loader processes have been terminated and it + // should shutdown. + IPC_MESSAGE_CONTROL0(NaClProcessMsg_StopBroker) +IPC_END_MESSAGES(NaClProcess) + diff --git a/chrome/common/nacl_types.h b/chrome/common/nacl_types.h new file mode 100644 index 0000000..5c5f5dc --- /dev/null +++ b/chrome/common/nacl_types.h @@ -0,0 +1,29 @@ +// Copyright (c) 2009 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. + +// Handle passing definitions for NaCl +#ifndef CHROME_COMMON_NACL_TYPES_H_ +#define CHROME_COMMON_NACL_TYPES_H_ + +#if defined(OS_POSIX) +#include "base/file_descriptor_posix.h" +#endif + +// TODO(gregoryd): add a Windows definition for base::FileDescriptor +namespace nacl { +#if defined(OS_WIN) + // We assume that HANDLE always uses less than 32 bits + typedef int FileDescriptor; + inline HANDLE ToNativeHandle(const FileDescriptor& desc) { + return reinterpret_cast<HANDLE>(desc); + } +#elif defined(OS_POSIX) + typedef base::FileDescriptor FileDescriptor; + inline int ToNativeHandle(const FileDescriptor& desc) { + return desc.fd; + } +#endif +} + +#endif // CHROME_COMMON_NACL_TYPES_H_ diff --git a/chrome/common/native_web_keyboard_event.h b/chrome/common/native_web_keyboard_event.h new file mode 100644 index 0000000..381ad31 --- /dev/null +++ b/chrome/common/native_web_keyboard_event.h @@ -0,0 +1,63 @@ +// Copyright (c) 2009 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 CHROME_COMMON_NATIVE_WEB_KEYBOARD_EVENT_H_ +#define CHROME_COMMON_NATIVE_WEB_KEYBOARD_EVENT_H_ + +#include "base/basictypes.h" +#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h" + +#if defined(OS_WIN) +#include <windows.h> +#elif defined(OS_MACOSX) +#ifdef __OBJC__ +@class NSEvent; +#else +class NSEvent; +#endif // __OBJC__ +#elif defined(OS_POSIX) +typedef struct _GdkEventKey GdkEventKey; +#endif + +// Owns a platform specific event; used to pass own and pass event through +// platform independent code. +struct NativeWebKeyboardEvent : public WebKit::WebKeyboardEvent { + NativeWebKeyboardEvent(); + +#if defined(OS_WIN) + NativeWebKeyboardEvent(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); +#elif defined(OS_MACOSX) + explicit NativeWebKeyboardEvent(NSEvent *event); + NativeWebKeyboardEvent(wchar_t character, + int state, + double time_stamp_seconds); +#elif defined(OS_LINUX) + explicit NativeWebKeyboardEvent(const GdkEventKey* event); + NativeWebKeyboardEvent(wchar_t character, + int state, + double time_stamp_seconds); +#endif + + NativeWebKeyboardEvent(const NativeWebKeyboardEvent& event); + ~NativeWebKeyboardEvent(); + + NativeWebKeyboardEvent& operator=(const NativeWebKeyboardEvent& event); + +#if defined(OS_WIN) + MSG os_event; +#elif defined(OS_MACOSX) + NSEvent* os_event; +#elif defined(OS_LINUX) + GdkEventKey* os_event; +#endif + + // True if the browser should ignore this event if it's not handled by the + // renderer. This happens for RawKeyDown events that are created while IME is + // active and is necessary to prevent backspace from doing "history back" if + // it is hit in ime mode. + // Currently, it's only used by Linux and Mac ports. + bool skip_in_browser; +}; + +#endif // CHROME_COMMON_NATIVE_WEB_KEYBOARD_EVENT_H_ diff --git a/chrome/common/native_web_keyboard_event_linux.cc b/chrome/common/native_web_keyboard_event_linux.cc new file mode 100644 index 0000000..571550e --- /dev/null +++ b/chrome/common/native_web_keyboard_event_linux.cc @@ -0,0 +1,76 @@ +// Copyright (c) 2009 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 "chrome/common/native_web_keyboard_event.h" + +#include <gdk/gdk.h> + +#include "third_party/WebKit/WebKit/chromium/public/gtk/WebInputEventFactory.h" + +using WebKit::WebInputEventFactory; + +namespace { + +void CopyEventTo(const GdkEventKey* in, GdkEventKey** out) { + if (in) { + *out = reinterpret_cast<GdkEventKey*>( + gdk_event_copy( + reinterpret_cast<GdkEvent*>(const_cast<GdkEventKey*>(in)))); + } else { + *out = NULL; + } +} + +void FreeEvent(GdkEventKey* event) { + if (event) { + gdk_event_free(reinterpret_cast<GdkEvent*>(event)); + } +} + +} // namespace + + +NativeWebKeyboardEvent::NativeWebKeyboardEvent() + : os_event(NULL), + skip_in_browser(false) { +} + +NativeWebKeyboardEvent::NativeWebKeyboardEvent(const GdkEventKey* native_event) + : WebKeyboardEvent(WebInputEventFactory::keyboardEvent(native_event)), + skip_in_browser(false) { + CopyEventTo(native_event, &os_event); +} + +NativeWebKeyboardEvent::NativeWebKeyboardEvent(wchar_t character, + int state, + double time_stamp_seconds) + : WebKeyboardEvent(WebInputEventFactory::keyboardEvent(character, + state, + time_stamp_seconds)), + os_event(NULL), + skip_in_browser(false) { +} + +NativeWebKeyboardEvent::NativeWebKeyboardEvent( + const NativeWebKeyboardEvent& other) + : WebKeyboardEvent(other), + skip_in_browser(other.skip_in_browser) { + CopyEventTo(other.os_event, &os_event); +} + +NativeWebKeyboardEvent& NativeWebKeyboardEvent::operator=( + const NativeWebKeyboardEvent& other) { + WebKeyboardEvent::operator=(other); + + FreeEvent(os_event); + CopyEventTo(other.os_event, &os_event); + + skip_in_browser = other.skip_in_browser; + + return *this; +} + +NativeWebKeyboardEvent::~NativeWebKeyboardEvent() { + FreeEvent(os_event); +} diff --git a/chrome/common/native_web_keyboard_event_mac.mm b/chrome/common/native_web_keyboard_event_mac.mm new file mode 100644 index 0000000..0c11033 --- /dev/null +++ b/chrome/common/native_web_keyboard_event_mac.mm @@ -0,0 +1,56 @@ +// Copyright (c) 2009 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 "chrome/common/native_web_keyboard_event.h" + +#import <AppKit/AppKit.h> + +#include "third_party/WebKit/WebKit/chromium/public/mac/WebInputEventFactory.h" + +using WebKit::WebInputEventFactory; + +NativeWebKeyboardEvent::NativeWebKeyboardEvent() + : os_event(NULL), + skip_in_browser(false) { +} + +NativeWebKeyboardEvent::NativeWebKeyboardEvent(NSEvent* event) + : WebKeyboardEvent(WebInputEventFactory::keyboardEvent(event)), + os_event([event retain]), + skip_in_browser(false) { +} + +NativeWebKeyboardEvent::NativeWebKeyboardEvent(wchar_t character, + int modifiers, + double time_stamp_seconds) + : WebKeyboardEvent(WebInputEventFactory::keyboardEvent(character, + modifiers, + time_stamp_seconds)), + os_event(NULL), + skip_in_browser(false) { +} + +NativeWebKeyboardEvent::NativeWebKeyboardEvent( + const NativeWebKeyboardEvent& other) + : WebKeyboardEvent(other), + os_event([other.os_event retain]), + skip_in_browser(other.skip_in_browser) { +} + +NativeWebKeyboardEvent& NativeWebKeyboardEvent::operator=( + const NativeWebKeyboardEvent& other) { + WebKeyboardEvent::operator=(other); + + NSObject* previous = os_event; + os_event = [other.os_event retain]; + [previous release]; + + skip_in_browser = other.skip_in_browser; + + return *this; +} + +NativeWebKeyboardEvent::~NativeWebKeyboardEvent() { + [os_event release]; +} diff --git a/chrome/common/native_web_keyboard_event_win.cc b/chrome/common/native_web_keyboard_event_win.cc new file mode 100644 index 0000000..7608ec6 --- /dev/null +++ b/chrome/common/native_web_keyboard_event_win.cc @@ -0,0 +1,54 @@ +// Copyright (c) 2009 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 "chrome/common/native_web_keyboard_event.h" + +#include "third_party/WebKit/WebKit/chromium/public/win/WebInputEventFactory.h" + +using WebKit::WebInputEventFactory; +using WebKit::WebKeyboardEvent; + +NativeWebKeyboardEvent::NativeWebKeyboardEvent() + : skip_in_browser(false) { + memset(&os_event, 0, sizeof(os_event)); +} + +NativeWebKeyboardEvent::NativeWebKeyboardEvent( + HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) + : WebKeyboardEvent( + WebInputEventFactory::keyboardEvent(hwnd, message, wparam, lparam)), + skip_in_browser(false) { + os_event.hwnd = hwnd; + os_event.message = message; + os_event.wParam = wparam; + os_event.lParam = lparam; +} + +NativeWebKeyboardEvent::NativeWebKeyboardEvent( + const NativeWebKeyboardEvent& other) + : WebKeyboardEvent(other), + skip_in_browser(other.skip_in_browser) { + os_event.hwnd = other.os_event.hwnd; + os_event.message = other.os_event.message; + os_event.wParam = other.os_event.wParam; + os_event.lParam = other.os_event.lParam; +} + +NativeWebKeyboardEvent& NativeWebKeyboardEvent::operator=( + const NativeWebKeyboardEvent& other) { + WebKeyboardEvent::operator=(other); + + os_event.hwnd = other.os_event.hwnd; + os_event.message = other.os_event.message; + os_event.wParam = other.os_event.wParam; + os_event.lParam = other.os_event.lParam; + + skip_in_browser = other.skip_in_browser; + + return *this; +} + +NativeWebKeyboardEvent::~NativeWebKeyboardEvent() { + // Noop under windows +} diff --git a/chrome/common/native_window_notification_source.h b/chrome/common/native_window_notification_source.h new file mode 100644 index 0000000..4cc75b8 --- /dev/null +++ b/chrome/common/native_window_notification_source.h @@ -0,0 +1,29 @@ +// Copyright (c) 2006-2008 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 CHROME_COMMON_NATIVE_WINDOW_NOTIFICATION_SOURCE_H_ +#define CHROME_COMMON_NATIVE_WINDOW_NOTIFICATION_SOURCE_H_ + +#include "chrome/common/notification_source.h" +#include "gfx/native_widget_types.h" + +// Specialization of the Source class for native windows. On Windows, these are +// HWNDs rather than pointers, and since the Source class expects a pointer +// type, this is necessary. On Mac/Linux, these are pointers, so this is +// unnecessary but harmless. +template<> +class Source<gfx::NativeWindow> : public NotificationSource { + public: + explicit Source(gfx::NativeWindow wnd) : NotificationSource(wnd) {} + + explicit Source(const NotificationSource& other) + : NotificationSource(other) {} + + gfx::NativeWindow operator->() const { return ptr(); } + gfx::NativeWindow ptr() const { + return static_cast<gfx::NativeWindow>(const_cast<void*>(ptr_)); + } +}; + +#endif // CHROME_COMMON_NATIVE_WINDOW_NOTIFICATION_SOURCE_H_ diff --git a/chrome/common/navigation_gesture.h b/chrome/common/navigation_gesture.h new file mode 100644 index 0000000..bb99497 --- /dev/null +++ b/chrome/common/navigation_gesture.h @@ -0,0 +1,22 @@ +// Copyright (c) 2006-2009 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 CHROME_COMMON_NAVIGATION_GESTURE_H_ +#define CHROME_COMMON_NAVIGATION_GESTURE_H_ + +enum NavigationGesture { + NavigationGestureUser, // User initiated navigation/load. This is not + // currently used due to the untrustworthy nature + // of userGestureHint (wasRunByUserGesture). See + // bug 1051891. + NavigationGestureAuto, // Non-user initiated navigation / load. For example + // onload or setTimeout triggered document.location + // changes, and form.submits. See bug 1046841 for + // some cases that should be treated this way but + // aren't yet. + NavigationGestureUnknown, // What we assign when userGestureHint returns true + // because we can't trust it. +}; + +#endif // CHROME_COMMON_NAVIGATION_GESTURE_H_ diff --git a/chrome/common/navigation_types.h b/chrome/common/navigation_types.h new file mode 100644 index 0000000..c871201 --- /dev/null +++ b/chrome/common/navigation_types.h @@ -0,0 +1,66 @@ +// Copyright (c) 2006-2008 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 CHROME_COMMON_NAVIGATION_TYPES_H_ +#define CHROME_COMMON_NAVIGATION_TYPES_H_ + +#include "base/basictypes.h" + +// Indicates different types of navigations that can occur that we will handle +// separately. +class NavigationType { + public: + enum Type { + // Unknown type. + UNKNOWN, + + // A new page was navigated in the main frame. + NEW_PAGE, + + // Renavigating to an existing navigation entry. The entry is guaranteed to + // exist in the list, or else it would be a new page or IGNORE navigation. + EXISTING_PAGE, + + // The same page has been reloaded as a result of the user requesting + // navigation to that same page (like pressing Enter in the URL bar). This + // is not the same as an in-page navigation because we'll actually have a + // pending entry for the load, which is then meaningless. + SAME_PAGE, + + // In page navigations are when the reference fragment changes. This will + // be in the main frame only (we won't even get notified of in-page + // subframe navigations). It may be for any page, not necessarily the last + // committed one (for example, whey going back to a page with a ref). + IN_PAGE, + + // A new subframe was manually navigated by the user. We will create a new + // NavigationEntry so they can go back to the previous subframe content + // using the back button. + NEW_SUBFRAME, + + // A subframe in the page was automatically loaded or navigated to such that + // a new navigation entry should not be created. There are two cases: + // 1. Stuff like iframes containing ads that the page loads automatically. + // The user doesn't want to see these, so we just update the existing + // navigation entry. + // 2. Going back/forward to previous subframe navigations. We don't create + // a new entry here either, just update the last committed entry. + // These two cases are actually pretty different, they just happen to + // require almost the same code to handle. + AUTO_SUBFRAME, + + // Nothing happened. This happens when we get information about a page we + // don't know anything about. It can also happen when an iframe in a popup + // navigated to about:blank is navigated. Nothing needs to be done. + NAV_IGNORE, + }; + + private: + // This class is for scoping only, so you shouldn't create an instance of it. + NavigationType() {} + + DISALLOW_COPY_AND_ASSIGN(NavigationType); +}; + +#endif // CHROME_COMMON_NAVIGATION_TYPES_H_ diff --git a/chrome/common/net/gaia/gaia_auth_consumer.h b/chrome/common/net/gaia/gaia_auth_consumer.h new file mode 100644 index 0000000..b7b215c --- /dev/null +++ b/chrome/common/net/gaia/gaia_auth_consumer.h @@ -0,0 +1,73 @@ +// Copyright (c) 2010 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 CHROME_COMMON_NET_GAIA_GAIA_AUTH_CONSUMER_H_ +#define CHROME_COMMON_NET_GAIA_GAIA_AUTH_CONSUMER_H_ + +#include <string> + +// An interface that defines the callbacks for objects that +// GaiaAuthenticator2 can return data to. +class GaiaAuthConsumer { + public: + struct ClientLoginResult { + inline ClientLoginResult() {} + inline ClientLoginResult(const std::string& new_sid, + const std::string& new_lsid, + const std::string& new_token, + const std::string& new_data) + : sid(new_sid), + lsid(new_lsid), + token(new_token), + data(new_data) {} + + inline bool operator==(const ClientLoginResult &b) const { + return sid == b.sid && + lsid == b.lsid && + token == b.token && + data == b.data; + } + + std::string sid; + std::string lsid; + std::string token; + // TODO(chron): Remove the data field later. Don't use it if possible. + std::string data; // Full contents of ClientLogin return. + }; + + enum GaiaAuthErrorCode { + NETWORK_ERROR, + REQUEST_CANCELED, + TWO_FACTOR, // Callers can treat this as a success. + PERMISSION_DENIED + }; + + struct GaiaAuthError { + inline bool operator==(const GaiaAuthError &b) const { + if (code != b.code) { + return false; + } + if (code == NETWORK_ERROR) { + return network_error == b.network_error; + } + return true; + } + + GaiaAuthErrorCode code; + int network_error; // This field is only valid if NETWORK_ERROR occured. + std::string data; // TODO(chron): Remove this field. Should preparse data. + }; + + virtual ~GaiaAuthConsumer() {} + + virtual void OnClientLoginSuccess(const ClientLoginResult& result) {} + virtual void OnClientLoginFailure(const GaiaAuthError& error) {} + + virtual void OnIssueAuthTokenSuccess(const std::string& service, + const std::string& auth_token) {} + virtual void OnIssueAuthTokenFailure(const std::string& service, + const GaiaAuthError& error) {} +}; + +#endif // CHROME_COMMON_NET_GAIA_GAIA_AUTH_CONSUMER_H_ diff --git a/chrome/common/net/gaia/gaia_authenticator.cc b/chrome/common/net/gaia/gaia_authenticator.cc new file mode 100644 index 0000000..f544e94 --- /dev/null +++ b/chrome/common/net/gaia/gaia_authenticator.cc @@ -0,0 +1,376 @@ +// Copyright (c) 2009 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 "chrome/common/net/gaia/gaia_authenticator.h" + +#include <string> +#include <utility> +#include <vector> + +#include "base/basictypes.h" +#include "base/port.h" +#include "base/string_split.h" +#include "chrome/common/deprecated/event_sys-inl.h" +#include "chrome/common/net/http_return.h" +#include "googleurl/src/gurl.h" +#include "net/base/escape.h" + +using std::pair; +using std::string; +using std::vector; + +namespace gaia { + +static const char kGaiaV1IssueAuthTokenPath[] = "/accounts/IssueAuthToken"; + +static const char kGetUserInfoPath[] = "/accounts/GetUserInfo"; + +// Sole constructor with initializers for all fields. +GaiaAuthenticator::GaiaAuthenticator(const string& user_agent, + const string& service_id, + const string& gaia_url) + : user_agent_(user_agent), + service_id_(service_id), + gaia_url_(gaia_url), + request_count_(0), + delay_(0), + next_allowed_auth_attempt_time_(0), + early_auth_attempt_count_(0), + message_loop_(NULL) { + GaiaAuthEvent done = { GaiaAuthEvent::GAIA_AUTHENTICATOR_DESTROYED, None, + this }; + channel_ = new Channel(done); +} + +GaiaAuthenticator::~GaiaAuthenticator() { + delete channel_; +} + +// mutex_ must be entered before calling this function. +GaiaAuthenticator::AuthParams GaiaAuthenticator::MakeParams( + const string& user_name, + const string& password, + const string& captcha_token, + const string& captcha_value) { + AuthParams params; + params.request_id = ++request_count_; + params.email = user_name; + params.password = password; + params.captcha_token = captcha_token; + params.captcha_value = captcha_value; + params.authenticator = this; + return params; +} + +bool GaiaAuthenticator::Authenticate(const string& user_name, + const string& password, + const string& captcha_token, + const string& captcha_value) { + DCHECK_EQ(MessageLoop::current(), message_loop_); + + AuthParams const params = + MakeParams(user_name, password, captcha_token, captcha_value); + return AuthenticateImpl(params); +} + +bool GaiaAuthenticator::AuthenticateWithLsid(const string& lsid) { + auth_results_.lsid = lsid; + // We need to lookup the email associated with this LSID cookie in order to + // update |auth_results_| with the correct values. + if (LookupEmail(&auth_results_)) { + auth_results_.email = auth_results_.primary_email; + return IssueAuthToken(&auth_results_, service_id_); + } + return false; +} + +bool GaiaAuthenticator::AuthenticateImpl(const AuthParams& params) { + DCHECK_EQ(MessageLoop::current(), message_loop_); + AuthResults results; + const bool succeeded = AuthenticateImpl(params, &results); + if (params.request_id == request_count_) { + auth_results_ = results; + GaiaAuthEvent event = { succeeded ? GaiaAuthEvent::GAIA_AUTH_SUCCEEDED + : GaiaAuthEvent::GAIA_AUTH_FAILED, + results.auth_error, this }; + channel_->NotifyListeners(event); + } + return succeeded; +} + +// This method makes an HTTP request to the Gaia server, and calls other +// methods to help parse the response. If authentication succeeded, then +// Gaia-issued cookies are available in the respective variables; if +// authentication failed, then the exact error is available as an enum. If the +// client wishes to save the credentials, the last parameter must be true. +// If a subsequent request is made with fresh credentials, the saved credentials +// are wiped out; any subsequent request to the zero-parameter overload of this +// method preserves the saved credentials. +bool GaiaAuthenticator::AuthenticateImpl(const AuthParams& params, + AuthResults* results) { + DCHECK_EQ(MessageLoop::current(), message_loop_); + results->auth_error = ConnectionUnavailable; + results->email = params.email.data(); + results->password = params.password; + + // The aim of this code is to start failing requests if due to a logic error + // in the program we're hammering GAIA. +#if defined(OS_WIN) + __time32_t now = _time32(0); +#else // defined(OS_WIN) + time_t now = time(0); +#endif // defined(OS_WIN) + + if (now > next_allowed_auth_attempt_time_) { + next_allowed_auth_attempt_time_ = now + 1; + // If we're more than 2 minutes past the allowed time we reset the early + // attempt count. + if (now - next_allowed_auth_attempt_time_ > 2 * 60) { + delay_ = 1; + early_auth_attempt_count_ = 0; + } + } else { + ++early_auth_attempt_count_; + // Allow 3 attempts, but then limit. + if (early_auth_attempt_count_ > 3) { + delay_ = GetBackoffDelaySeconds(delay_); + next_allowed_auth_attempt_time_ = now + delay_; + return false; + } + } + + return PerformGaiaRequest(params, results); +} + +bool GaiaAuthenticator::PerformGaiaRequest(const AuthParams& params, + AuthResults* results) { + DCHECK_EQ(MessageLoop::current(), message_loop_); + GURL gaia_auth_url(gaia_url_); + + string post_body; + post_body += "Email=" + EscapeUrlEncodedData(params.email); + post_body += "&Passwd=" + EscapeUrlEncodedData(params.password); + post_body += "&source=" + EscapeUrlEncodedData(user_agent_); + post_body += "&service=" + service_id_; + if (!params.captcha_token.empty() && !params.captcha_value.empty()) { + post_body += "&logintoken=" + EscapeUrlEncodedData(params.captcha_token); + post_body += "&logincaptcha=" + EscapeUrlEncodedData(params.captcha_value); + } + post_body += "&PersistentCookie=true"; + // We set it to GOOGLE (and not HOSTED or HOSTED_OR_GOOGLE) because we only + // allow consumer logins. + post_body += "&accountType=GOOGLE"; + + string message_text; + unsigned long server_response_code; + if (!Post(gaia_auth_url, post_body, &server_response_code, &message_text)) { + results->auth_error = ConnectionUnavailable; + return false; + } + + // Parse reply in two different ways, depending on if request failed or + // succeeded. + if (RC_FORBIDDEN == server_response_code) { + ExtractAuthErrorFrom(message_text, results); + return false; + } else if (RC_REQUEST_OK == server_response_code) { + ExtractTokensFrom(message_text, results); + if (!IssueAuthToken(results, service_id_)) { + return false; + } + + return LookupEmail(results); + } else { + results->auth_error = Unknown; + return false; + } +} + +bool GaiaAuthenticator::LookupEmail(AuthResults* results) { + DCHECK_EQ(MessageLoop::current(), message_loop_); + // Use the provided Gaia server, but change the path to what V1 expects. + GURL url(gaia_url_); // Gaia server. + GURL::Replacements repl; + // Needs to stay in scope till GURL is out of scope. + string path(kGetUserInfoPath); + repl.SetPathStr(path); + url = url.ReplaceComponents(repl); + + string post_body; + post_body += "LSID="; + post_body += EscapeUrlEncodedData(results->lsid); + + unsigned long server_response_code; + string message_text; + if (!Post(url, post_body, &server_response_code, &message_text)) { + return false; + } + + // Check if we received a valid AuthToken; if not, ignore it. + if (RC_FORBIDDEN == server_response_code) { + // Server says we're not authenticated. + ExtractAuthErrorFrom(message_text, results); + return false; + } else if (RC_REQUEST_OK == server_response_code) { + typedef vector<pair<string, string> > Tokens; + Tokens tokens; + base::SplitStringIntoKeyValuePairs(message_text, '=', '\n', &tokens); + for (Tokens::iterator i = tokens.begin(); i != tokens.end(); ++i) { + if ("accountType" == i->first) { + // We never authenticate an email as a hosted account. + DCHECK_EQ("GOOGLE", i->second); + } else if ("email" == i->first) { + results->primary_email = i->second; + } + } + return true; + } + return false; +} + +// We need to call this explicitly when we need to obtain a long-lived session +// token. +bool GaiaAuthenticator::IssueAuthToken(AuthResults* results, + const string& service_id) { + DCHECK_EQ(MessageLoop::current(), message_loop_); + // Use the provided Gaia server, but change the path to what V1 expects. + GURL url(gaia_url_); // Gaia server. + GURL::Replacements repl; + // Needs to stay in scope till GURL is out of scope. + string path(kGaiaV1IssueAuthTokenPath); + repl.SetPathStr(path); + url = url.ReplaceComponents(repl); + + string post_body; + post_body += "LSID="; + post_body += EscapeUrlEncodedData(results->lsid); + post_body += "&service=" + service_id; + post_body += "&Session=true"; + + unsigned long server_response_code; + string message_text; + if (!Post(url, post_body, &server_response_code, &message_text)) { + return false; + } + + // Check if we received a valid AuthToken; if not, ignore it. + if (RC_FORBIDDEN == server_response_code) { + // Server says we're not authenticated. + ExtractAuthErrorFrom(message_text, results); + return false; + } else if (RC_REQUEST_OK == server_response_code) { + // Note that the format of message_text is different from what is returned + // in the first request, or to the sole request that is made to Gaia V2. + // Specifically, the entire string is the AuthToken, and looks like: + // "<token>" rather than "AuthToken=<token>". Thus, we need not use + // ExtractTokensFrom(...), but simply assign the token. + int last_index = message_text.length() - 1; + if ('\n' == message_text[last_index]) + message_text.erase(last_index); + results->auth_token = message_text; + return true; + } + return false; +} + +// Helper method that extracts tokens from a successful reply, and saves them +// in the right fields. +void GaiaAuthenticator::ExtractTokensFrom(const string& response, + AuthResults* results) { + vector<pair<string, string> > tokens; + base::SplitStringIntoKeyValuePairs(response, '=', '\n', &tokens); + for (vector<pair<string, string> >::iterator i = tokens.begin(); + i != tokens.end(); ++i) { + if (i->first == "SID") { + results->sid = i->second; + } else if (i->first == "LSID") { + results->lsid = i->second; + } else if (i->first == "Auth") { + results->auth_token = i->second; + } + } +} + +// Helper method that extracts tokens from a failure response, and saves them +// in the right fields. +void GaiaAuthenticator::ExtractAuthErrorFrom(const string& response, + AuthResults* results) { + vector<pair<string, string> > tokens; + base::SplitStringIntoKeyValuePairs(response, '=', '\n', &tokens); + for (vector<pair<string, string> >::iterator i = tokens.begin(); + i != tokens.end(); ++i) { + if (i->first == "Error") { + results->error_msg = i->second; + } else if (i->first == "Url") { + results->auth_error_url = i->second; + } else if (i->first == "CaptchaToken") { + results->captcha_token = i->second; + } else if (i->first == "CaptchaUrl") { + results->captcha_url = i->second; + } + } + + // Convert string error messages to enum values. Each case has two different + // strings; the first one is the most current and the second one is + // deprecated, but available. + const string& error_msg = results->error_msg; + if (error_msg == "BadAuthentication" || error_msg == "badauth") { + results->auth_error = BadAuthentication; + } else if (error_msg == "NotVerified" || error_msg == "nv") { + results->auth_error = NotVerified; + } else if (error_msg == "TermsNotAgreed" || error_msg == "tna") { + results->auth_error = TermsNotAgreed; + } else if (error_msg == "Unknown" || error_msg == "unknown") { + results->auth_error = Unknown; + } else if (error_msg == "AccountDeleted" || error_msg == "adel") { + results->auth_error = AccountDeleted; + } else if (error_msg == "AccountDisabled" || error_msg == "adis") { + results->auth_error = AccountDisabled; + } else if (error_msg == "CaptchaRequired" || error_msg == "cr") { + results->auth_error = CaptchaRequired; + } else if (error_msg == "ServiceUnavailable" || error_msg == "ire") { + results->auth_error = ServiceUnavailable; + } +} + +// Reset all stored credentials, perhaps in preparation for letting a different +// user sign in. +void GaiaAuthenticator::ResetCredentials() { + DCHECK_EQ(MessageLoop::current(), message_loop_); + AuthResults blank; + auth_results_ = blank; +} + +void GaiaAuthenticator::SetUsernamePassword(const string& username, + const string& password) { + DCHECK_EQ(MessageLoop::current(), message_loop_); + auth_results_.password = password; + auth_results_.email = username; +} + +void GaiaAuthenticator::SetUsername(const string& username) { + DCHECK_EQ(MessageLoop::current(), message_loop_); + auth_results_.email = username; +} + +void GaiaAuthenticator::RenewAuthToken(const string& auth_token) { + DCHECK_EQ(MessageLoop::current(), message_loop_); + DCHECK(!this->auth_token().empty()); + auth_results_.auth_token = auth_token; +} +void GaiaAuthenticator::SetAuthToken(const string& auth_token) { + DCHECK_EQ(MessageLoop::current(), message_loop_); + auth_results_.auth_token = auth_token; +} + +bool GaiaAuthenticator::Authenticate(const string& user_name, + const string& password) { + DCHECK_EQ(MessageLoop::current(), message_loop_); + const string empty; + return Authenticate(user_name, password, empty, + empty); +} + +} // namepace gaia + diff --git a/chrome/common/net/gaia/gaia_authenticator.h b/chrome/common/net/gaia/gaia_authenticator.h new file mode 100644 index 0000000..d34af2d --- /dev/null +++ b/chrome/common/net/gaia/gaia_authenticator.h @@ -0,0 +1,302 @@ +// Copyright (c) 2009 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. +// +// Use this class to authenticate users with Gaia and access cookies sent +// by the Gaia servers. This class cannot be used on its own becaue it relies +// on a subclass to provide the virtual Post and GetBackoffDelaySeconds methods. +// +// Sample usage: +// class ActualGaiaAuthenticator : public gaia::GaiaAuthenticator { +// Provides actual implementation of Post and GetBackoffDelaySeconds. +// }; +// ActualGaiaAuthenticator gaia_auth("User-Agent", SERVICE_NAME, kGaiaUrl); +// if (gaia_auth.Authenticate("email", "passwd", SAVE_IN_MEMORY_ONLY, +// true)) { // Synchronous +// // Do something with: gaia_auth.auth_token(), or gaia_auth.sid(), +// // or gaia_auth.lsid() +// } +// +// Credentials can also be preserved for subsequent requests, though these are +// saved in plain-text in memory, and not very secure on client systems. The +// email address associated with the Gaia account can be read; the password is +// write-only. + +// TODO(sanjeevr): This class has been moved here from the bookmarks sync code. +// While it is a generic class that handles GAIA authentication, there are some +// artifacts of the sync code which needs to be cleaned up. +#ifndef CHROME_COMMON_NET_GAIA_GAIA_AUTHENTICATOR_H_ +#define CHROME_COMMON_NET_GAIA_GAIA_AUTHENTICATOR_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/message_loop.h" +#include "chrome/common/deprecated/event_sys.h" +#include "googleurl/src/gurl.h" +#include "testing/gtest/include/gtest/gtest_prod.h" // For FRIEND_TEST + +namespace gaia { + +static const char kGaiaUrl[] = + "https://www.google.com:443/accounts/ClientLogin"; + +// Error codes from Gaia. These will be set correctly for both Gaia V1 +// (/ClientAuth) and V2 (/ClientLogin) +enum AuthenticationError { + None = 0, + BadAuthentication = 1, + NotVerified = 2, + TermsNotAgreed = 3, + Unknown = 4, + AccountDeleted = 5, + AccountDisabled = 6, + CaptchaRequired = 7, + ServiceUnavailable = 8, + // Errors generated by this class not Gaia. + CredentialsNotSet = 9, + ConnectionUnavailable = 10 +}; + +class GaiaAuthenticator; + +struct GaiaAuthEvent { + enum { + GAIA_AUTH_FAILED, + GAIA_AUTH_SUCCEEDED, + GAIA_AUTHENTICATOR_DESTROYED + } + what_happened; + AuthenticationError error; + const GaiaAuthenticator* authenticator; + + // Lets us use GaiaAuthEvent as its own traits type in hookups. + typedef GaiaAuthEvent EventType; + static inline bool IsChannelShutdownEvent(const GaiaAuthEvent& event) { + return event.what_happened == GAIA_AUTHENTICATOR_DESTROYED; + } +}; + +// GaiaAuthenticator can be used to pass user credentials to Gaia and obtain +// cookies set by the Gaia servers. +class GaiaAuthenticator { + FRIEND_TEST(GaiaAuthenticatorTest, TestNewlineAtEndOfAuthTokenRemoved); + public: + + // Since GaiaAuthenticator can be used for any service, or by any client, you + // must include a user-agent and a service-id when creating one. The + // user_agent is a short string used for simple log analysis. gaia_url is used + // to choose the server to authenticate with (e.g. + // http://www.google.com/accounts/ClientLogin). + GaiaAuthenticator(const std::string& user_agent, + const std::string& service_id, + const std::string& gaia_url); + + virtual ~GaiaAuthenticator(); + + // This object should only be invoked from the AuthWatcherThread message + // loop, which is injected here. + void set_message_loop(const MessageLoop* loop) { + message_loop_ = loop; + } + + // Pass credentials to authenticate with, or use saved credentials via an + // overload. If authentication succeeds, you can retrieve the authentication + // token via the respective accessors. Returns a boolean indicating whether + // authentication succeeded or not. + bool Authenticate(const std::string& user_name, const std::string& password, + const std::string& captcha_token, + const std::string& captcha_value); + + bool Authenticate(const std::string& user_name, const std::string& password); + + // Pass the LSID to authenticate with. If the authentication succeeds, you can + // retrieve the authetication token via the respective accessors. Returns a + // boolean indicating whether authentication succeeded or not. + // Always returns a long lived token. + bool AuthenticateWithLsid(const std::string& lsid); + + // Resets all stored cookies to their default values. + void ResetCredentials(); + + void SetUsernamePassword(const std::string& username, + const std::string& password); + + void SetUsername(const std::string& username); + + // Virtual for testing + virtual void RenewAuthToken(const std::string& auth_token); + void SetAuthToken(const std::string& auth_token); + + struct AuthResults { + std::string email; + std::string password; + + // Fields that store various cookies. + std::string sid; + std::string lsid; + std::string auth_token; + + std::string primary_email; + + // Fields for items returned when authentication fails. + std::string error_msg; + enum AuthenticationError auth_error; + std::string auth_error_url; + std::string captcha_token; + std::string captcha_url; + + AuthResults() : auth_error(None) {} + }; + + protected: + + struct AuthParams { + GaiaAuthenticator* authenticator; + uint32 request_id; + std::string email; + std::string password; + std::string captcha_token; + std::string captcha_value; + }; + + // mutex_ must be entered before calling this function. + AuthParams MakeParams(const std::string& user_name, + const std::string& password, + const std::string& captcha_token, + const std::string& captcha_value); + + // The real Authenticate implementations. + bool AuthenticateImpl(const AuthParams& params); + bool AuthenticateImpl(const AuthParams& params, AuthResults* results); + + // virtual for testing purposes. + virtual bool PerformGaiaRequest(const AuthParams& params, + AuthResults* results); + virtual bool Post(const GURL& url, const std::string& post_body, + unsigned long* response_code, std::string* response_body) { + return false; + } + + // Caller should fill in results->LSID before calling. Result in + // results->primary_email. + virtual bool LookupEmail(AuthResults* results); + + // Subclasses must override to provide a backoff delay. It is virtual instead + // of pure virtual for testing purposes. + // TODO(sanjeevr): This should be made pure virtual. But this class is + // currently directly being used in sync/engine/authenticator.cc, which is + // wrong. + virtual int GetBackoffDelaySeconds(int current_backoff_delay) { + NOTREACHED(); + return current_backoff_delay; + } + + public: + // Retrieve email. + inline std::string email() const { + DCHECK_EQ(MessageLoop::current(), message_loop_); + return auth_results_.email; + } + + // Retrieve password. + inline std::string password() const { + DCHECK_EQ(MessageLoop::current(), message_loop_); + return auth_results_.password; + } + + // Retrieve AuthToken, if previously authenticated; otherwise returns "". + inline std::string auth_token() const { + DCHECK_EQ(MessageLoop::current(), message_loop_); + return auth_results_.auth_token; + } + + // Retrieve SID cookie. For details, see the Google Accounts documentation. + inline std::string sid() const { + DCHECK_EQ(MessageLoop::current(), message_loop_); + return auth_results_.sid; + } + + // Retrieve LSID cookie. For details, see the Google Accounts documentation. + inline std::string lsid() const { + DCHECK_EQ(MessageLoop::current(), message_loop_); + return auth_results_.lsid; + } + + // Get last authentication error. + inline enum AuthenticationError auth_error() const { + DCHECK_EQ(MessageLoop::current(), message_loop_); + return auth_results_.auth_error; + } + + inline std::string auth_error_url() const { + DCHECK_EQ(MessageLoop::current(), message_loop_); + return auth_results_.auth_error_url; + } + + inline std::string captcha_token() const { + DCHECK_EQ(MessageLoop::current(), message_loop_); + return auth_results_.captcha_token; + } + + inline std::string captcha_url() const { + DCHECK_EQ(MessageLoop::current(), message_loop_); + return auth_results_.captcha_url; + } + + inline AuthResults results() const { + DCHECK_EQ(MessageLoop::current(), message_loop_); + return auth_results_; + } + + typedef EventChannel<GaiaAuthEvent, Lock> Channel; + + inline Channel* channel() const { + return channel_; + } + + private: + bool IssueAuthToken(AuthResults* results, const std::string& service_id); + + // Helper method to parse response when authentication succeeds. + void ExtractTokensFrom(const std::string& response, AuthResults* results); + // Helper method to parse response when authentication fails. + void ExtractAuthErrorFrom(const std::string& response, AuthResults* results); + + // Fields for the obvious data items. + const std::string user_agent_; + const std::string service_id_; + const std::string gaia_url_; + + AuthResults auth_results_; + + // When multiple async requests are running, only the one that started most + // recently updates the values. + // + // Note that even though this code was written to handle multiple requests + // simultaneously, the sync code issues auth requests one at a time. + uint32 request_count_; + + Channel* channel_; + + // Used to compute backoff time for next allowed authentication. + int delay_; // In seconds. + // On Windows, time_t is 64-bit by default. Even though we have defined the + // _USE_32BIT_TIME_T preprocessor flag, other libraries including this header + // may not have that preprocessor flag defined resulting in mismatched class + // sizes. So we explicitly define it as 32-bit on Windows. + // TODO(sanjeevr): Change this to to use base::Time +#if defined(OS_WIN) + __time32_t next_allowed_auth_attempt_time_; +#else // defined(OS_WIN) + time_t next_allowed_auth_attempt_time_; +#endif // defined(OS_WIN) + int early_auth_attempt_count_; + + // The message loop all our methods are invoked on. + const MessageLoop* message_loop_; +}; + +} // namespace gaia +#endif // CHROME_COMMON_NET_GAIA_GAIA_AUTHENTICATOR_H_ + diff --git a/chrome/common/net/gaia/gaia_authenticator2.cc b/chrome/common/net/gaia/gaia_authenticator2.cc new file mode 100644 index 0000000..abc0efe --- /dev/null +++ b/chrome/common/net/gaia/gaia_authenticator2.cc @@ -0,0 +1,292 @@ +// Copyright (c) 2010 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 "chrome/common/net/gaia/gaia_authenticator2.h" + +#include <string> + +#include "base/string_split.h" +#include "base/string_util.h" +#include "chrome/common/net/gaia/gaia_auth_consumer.h" +#include "chrome/common/net/http_return.h" +#include "chrome/common/net/url_request_context_getter.h" +#include "net/base/load_flags.h" +#include "net/url_request/url_request_status.h" +#include "third_party/libjingle/source/talk/base/urlencode.h" + +// TODO(chron): Add sourceless version of this formatter. +// static +const char GaiaAuthenticator2::kClientLoginFormat[] = + "Email=%s&" + "Passwd=%s&" + "PersistentCookie=%s&" + "accountType=%s&" + "source=%s&" + "service=%s"; +// static +const char GaiaAuthenticator2::kClientLoginCaptchaFormat[] = + "Email=%s&" + "Passwd=%s&" + "PersistentCookie=%s&" + "accountType=%s&" + "source=%s&" + "service=%s&" + "logintoken=%s&" + "logincaptcha=%s"; +// static +const char GaiaAuthenticator2::kIssueAuthTokenFormat[] = + "SID=%s&" + "LSID=%s&" + "service=%s&" + "Session=true"; + +// static +const char GaiaAuthenticator2::kCookiePersistence[] = "true"; +// static +const char GaiaAuthenticator2::kAccountType[] = "HOSTED_OR_GOOGLE"; +// static +const char GaiaAuthenticator2::kChromeOSSource[] = "chromeos"; +// static +// Service name for Gaia Contacts API. API is used to get user's image. +const char GaiaAuthenticator2::kContactsService[] = "cp"; +// static +const char GaiaAuthenticator2::kSecondFactor[] = "Info=InvalidSecondFactor"; + +// TODO(chron): These urls are also in auth_response_handler.h. +// The URLs for different calls in the Google Accounts programmatic login API. +const char GaiaAuthenticator2::kClientLoginUrl[] = + "https://www.google.com/accounts/ClientLogin"; +const char GaiaAuthenticator2::kIssueAuthTokenUrl[] = + "https://www.google.com/accounts/IssueAuthToken"; + +GaiaAuthenticator2::GaiaAuthenticator2(GaiaAuthConsumer* consumer, + const std::string& source, + URLRequestContextGetter* getter) + : consumer_(consumer), + getter_(getter), + source_(source), + client_login_gurl_(kClientLoginUrl), + issue_auth_token_gurl_(kIssueAuthTokenUrl), + fetch_pending_(false) {} + +GaiaAuthenticator2::~GaiaAuthenticator2() {} + +bool GaiaAuthenticator2::HasPendingFetch() { + return fetch_pending_; +} + +void GaiaAuthenticator2::CancelRequest() { + fetcher_.reset(); + fetch_pending_ = false; +} + +// static +URLFetcher* GaiaAuthenticator2::CreateGaiaFetcher( + URLRequestContextGetter* getter, + const std::string& body, + const GURL& gaia_gurl, + URLFetcher::Delegate* delegate) { + + URLFetcher* to_return = + URLFetcher::Create(0, + gaia_gurl, + URLFetcher::POST, + delegate); + to_return->set_request_context(getter); + to_return->set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES); + to_return->set_upload_data("application/x-www-form-urlencoded", body); + return to_return; +} + +// static +std::string GaiaAuthenticator2::MakeClientLoginBody( + const std::string& username, + const std::string& password, + const std::string& source, + const char* service, + const std::string& login_token, + const std::string& login_captcha) { + + if (login_token.empty() || login_captcha.empty()) { + return StringPrintf(kClientLoginFormat, + UrlEncodeString(username).c_str(), + UrlEncodeString(password).c_str(), + kCookiePersistence, + kAccountType, + source.c_str(), + service); + } + + return StringPrintf(kClientLoginCaptchaFormat, + UrlEncodeString(username).c_str(), + UrlEncodeString(password).c_str(), + kCookiePersistence, + kAccountType, + source.c_str(), + service, + UrlEncodeString(login_token).c_str(), + UrlEncodeString(login_captcha).c_str()); + +} + +// static +std::string GaiaAuthenticator2::MakeIssueAuthTokenBody( + const std::string& sid, + const std::string& lsid, + const char* const service) { + + return StringPrintf(kIssueAuthTokenFormat, + UrlEncodeString(sid).c_str(), + UrlEncodeString(lsid).c_str(), + service); +} + +// Helper method that extracts tokens from a successful reply. +// static +void GaiaAuthenticator2::ParseClientLoginResponse(const std::string& data, + std::string* sid, + std::string* lsid, + std::string* token) { + using std::vector; + using std::pair; + using std::string; + + vector<pair<string, string> > tokens; + base::SplitStringIntoKeyValuePairs(data, '=', '\n', &tokens); + for (vector<pair<string, string> >::iterator i = tokens.begin(); + i != tokens.end(); ++i) { + if (i->first == "SID") { + sid->assign(i->second); + } else if (i->first == "LSID") { + lsid->assign(i->second); + } else if (i->first == "Auth") { + token->assign(i->second); + } + } +} + +void GaiaAuthenticator2::StartClientLogin(const std::string& username, + const std::string& password, + const char* const service, + const std::string& login_token, + const std::string& login_captcha) { + + DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; + + // This class is thread agnostic, so be sure to call this only on the + // same thread each time. + LOG(INFO) << "Starting new ClientLogin fetch for:" << username; + + // Must outlive fetcher_. + request_body_ = MakeClientLoginBody(username, + password, + source_, + service, + login_token, + login_captcha); + fetcher_.reset(CreateGaiaFetcher(getter_, + request_body_, + client_login_gurl_, + this)); + fetch_pending_ = true; + fetcher_->Start(); +} + +void GaiaAuthenticator2::StartIssueAuthToken(const std::string& sid, + const std::string& lsid, + const char* const service) { + + DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; + + LOG(INFO) << "Starting IssueAuthToken for: " << service; + requested_service_ = service; + request_body_ = MakeIssueAuthTokenBody(sid, lsid, service); + fetcher_.reset(CreateGaiaFetcher(getter_, + request_body_, + issue_auth_token_gurl_, + this)); + fetch_pending_ = true; + fetcher_->Start(); +} + +GaiaAuthConsumer::GaiaAuthError GaiaAuthenticator2::GenerateAuthError( + const std::string& data, + const URLRequestStatus& status) { + + GaiaAuthConsumer::GaiaAuthError error; + error.data = data; + + if (!status.is_success()) { + if (status.status() == URLRequestStatus::CANCELED) { + error.code = GaiaAuthConsumer::REQUEST_CANCELED; + } else { + error.code = GaiaAuthConsumer::NETWORK_ERROR; + error.network_error = status.os_error(); + LOG(WARNING) << "Could not reach Google Accounts servers: errno " + << status.os_error(); + } + } else { + if (IsSecondFactorSuccess(data)) { + error.code = GaiaAuthConsumer::TWO_FACTOR; + } else { + error.code = GaiaAuthConsumer::PERMISSION_DENIED; + } + } + + return error; +} + +void GaiaAuthenticator2::OnClientLoginFetched(const std::string& data, + const URLRequestStatus& status, + int response_code) { + + if (status.is_success() && response_code == RC_REQUEST_OK) { + LOG(INFO) << "ClientLogin successful!"; + std::string sid; + std::string lsid; + std::string token; + ParseClientLoginResponse(data, &sid, &lsid, &token); + consumer_->OnClientLoginSuccess( + GaiaAuthConsumer::ClientLoginResult(sid, lsid, token, data)); + } else { + consumer_->OnClientLoginFailure(GenerateAuthError(data, status)); + } +} + +void GaiaAuthenticator2::OnIssueAuthTokenFetched( + const std::string& data, + const URLRequestStatus& status, + int response_code) { + if (status.is_success() && response_code == RC_REQUEST_OK) { + // Only the bare token is returned in the body of this Gaia call + // without any padding. + consumer_->OnIssueAuthTokenSuccess(requested_service_, data); + } else { + consumer_->OnIssueAuthTokenFailure(requested_service_, + GenerateAuthError(data, status)); + } +} + +void GaiaAuthenticator2::OnURLFetchComplete(const URLFetcher* source, + const GURL& url, + const URLRequestStatus& status, + int response_code, + const ResponseCookies& cookies, + const std::string& data) { + fetch_pending_ = false; + if (url == client_login_gurl_) { + OnClientLoginFetched(data, status, response_code); + } else if (url == issue_auth_token_gurl_) { + OnIssueAuthTokenFetched(data, status, response_code); + } else { + NOTREACHED(); + } +} + +// static +bool GaiaAuthenticator2::IsSecondFactorSuccess( + const std::string& alleged_error) { + return alleged_error.find(kSecondFactor) != + std::string::npos; +} diff --git a/chrome/common/net/gaia/gaia_authenticator2.h b/chrome/common/net/gaia/gaia_authenticator2.h new file mode 100644 index 0000000..0e6c203 --- /dev/null +++ b/chrome/common/net/gaia/gaia_authenticator2.h @@ -0,0 +1,157 @@ +// Copyright (c) 2010 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 CHROME_COMMON_NET_GAIA_GAIA_AUTHENTICATOR2_H_ +#define CHROME_COMMON_NET_GAIA_GAIA_AUTHENTICATOR2_H_ + +#include <string> + +#include "base/gtest_prod_util.h" +#include "base/scoped_ptr.h" +#include "chrome/common/net/gaia/gaia_auth_consumer.h" +#include "chrome/common/net/url_fetcher.h" +#include "googleurl/src/gurl.h" + +// Authenticate a user against the Google Accounts ClientLogin API +// with various capabilities and return results to a GaiaAuthConsumer. +// +// In the future, we will also issue auth tokens from this class. +// This class should be used on a single thread, but it can be whichever thread +// that you like. +// +// This class can handle one request at a time. To parallelize requests, +// create multiple GaiaAuthenticator2's. + +class GaiaAuthenticator2Test; + +class GaiaAuthenticator2 : public URLFetcher::Delegate { + public: + // Constants to use in the ClientLogin request POST body. + static const char kChromeOSSource[]; + static const char kContactsService[]; + + // The URLs for different calls in the Google Accounts programmatic login API. + static const char kClientLoginUrl[]; + static const char kIssueAuthTokenUrl[]; + + // Magic string indicating that, while a second factor is still + // needed to complete authentication, the user provided the right password. + static const char kSecondFactor[]; + + // This will later be hidden behind an auth service which caches + // tokens. + GaiaAuthenticator2(GaiaAuthConsumer* consumer, + const std::string& source, + URLRequestContextGetter* getter); + virtual ~GaiaAuthenticator2(); + + // GaiaAuthConsumer will be called on the original thread + // after results come back. This class is thread agnostic. + // You can't make more than request at a time. + void StartClientLogin(const std::string& username, + const std::string& password, + const char* const service, + const std::string& login_token, + const std::string& login_captcha); + + // GaiaAuthConsumer will be called on the original thread + // after results come back. This class is thread agnostic. + // You can't make more than one request at a time. + void StartIssueAuthToken(const std::string& sid, + const std::string& lsid, + const char* const service); + + // Implementation of URLFetcher::Delegate + void OnURLFetchComplete(const URLFetcher* source, + const GURL& url, + const URLRequestStatus& status, + int response_code, + const ResponseCookies& cookies, + const std::string& data); + + // StartClientLogin been called && results not back yet? + bool HasPendingFetch(); + + // Stop any URL fetches in progress. + void CancelRequest(); + + private: + // ClientLogin body constants that don't change + static const char kCookiePersistence[]; + static const char kAccountType[]; + + // The format of the POST body for ClientLogin. + static const char kClientLoginFormat[]; + // The format of said POST body when CAPTCHA token & answer are specified. + static const char kClientLoginCaptchaFormat[]; + // The format of the POST body for IssueAuthToken. + static const char kIssueAuthTokenFormat[]; + + // Process the results of a ClientLogin fetch. + void OnClientLoginFetched(const std::string& data, + const URLRequestStatus& status, + int response_code); + + void OnIssueAuthTokenFetched(const std::string& data, + const URLRequestStatus& status, + int response_code); + + // Tokenize the results of a ClientLogin fetch. + static void ParseClientLoginResponse(const std::string& data, + std::string* sid, + std::string* lsid, + std::string* token); + + // From a URLFetcher result, generate an appropriate GaiaAuthError. + // From the API documentation, both IssueAuthToken and ClientLogin have + // the same error returns. + static GaiaAuthConsumer::GaiaAuthError GenerateAuthError( + const std::string& data, + const URLRequestStatus& status); + + // Is this a special case Gaia error for TwoFactor auth? + static bool IsSecondFactorSuccess(const std::string& alleged_error); + + // Given parameters, create a ClientLogin request body. + static std::string MakeClientLoginBody(const std::string& username, + const std::string& password, + const std::string& source, + const char* const service, + const std::string& login_token, + const std::string& login_captcha); + // Supply the sid / lsid returned from ClientLogin in order to + // request a long lived auth token for a service. + static std::string MakeIssueAuthTokenBody(const std::string& sid, + const std::string& lsid, + const char* const service); + + // Create a fetcher useable for making any Gaia request. + static URLFetcher* CreateGaiaFetcher(URLRequestContextGetter* getter, + const std::string& body, + const GURL& gaia_gurl_, + URLFetcher::Delegate* delegate); + + + // These fields are common to GaiaAuthenticator2, same every request + GaiaAuthConsumer* const consumer_; + URLRequestContextGetter* const getter_; + std::string source_; + const GURL client_login_gurl_; + const GURL issue_auth_token_gurl_; + + // While a fetch is going on: + scoped_ptr<URLFetcher> fetcher_; + std::string request_body_; + std::string requested_service_; // Currently tracked for IssueAuthToken only + bool fetch_pending_; + + friend class GaiaAuthenticator2Test; + FRIEND_TEST_ALL_PREFIXES(GaiaAuthenticator2Test, LoginNetFailure); + FRIEND_TEST_ALL_PREFIXES(GaiaAuthenticator2Test, CheckNormalErrorCode); + FRIEND_TEST_ALL_PREFIXES(GaiaAuthenticator2Test, CheckTwoFactorResponse); + + DISALLOW_COPY_AND_ASSIGN(GaiaAuthenticator2); +}; + +#endif // CHROME_COMMON_NET_GAIA_GAIA_AUTHENTICATOR2_H_ diff --git a/chrome/common/net/gaia/gaia_authenticator2_unittest.cc b/chrome/common/net/gaia/gaia_authenticator2_unittest.cc new file mode 100644 index 0000000..4e4dc82 --- /dev/null +++ b/chrome/common/net/gaia/gaia_authenticator2_unittest.cc @@ -0,0 +1,360 @@ +// Copyright (c) 2010 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 complete set of unit tests for GaiaAuthenticator2. +// Originally ported from GoogleAuthenticator tests. + +#include <string> + +#include "base/message_loop.h" +#include "base/string_util.h" +#include "chrome/common/net/gaia/gaia_auth_consumer.h" +#include "chrome/common/net/gaia/gaia_authenticator2.h" +#include "chrome/common/net/gaia/gaia_authenticator2_unittest.h" +#include "chrome/common/net/http_return.h" +#include "chrome/common/net/test_url_fetcher_factory.h" +#include "chrome/common/net/url_fetcher.h" +#include "chrome/test/testing_profile.h" +#include "googleurl/src/gurl.h" +#include "net/base/net_errors.h" +#include "net/url_request/url_request_status.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ::testing::_; + +class GaiaAuthenticator2Test : public testing::Test { + public: + GaiaAuthenticator2Test() + : client_login_source_(GaiaAuthenticator2::kClientLoginUrl), + issue_auth_token_source_(GaiaAuthenticator2::kIssueAuthTokenUrl) {} + + void RunParsingTest(const std::string& data, + const std::string& sid, + const std::string& lsid, + const std::string& token) { + std::string out_sid; + std::string out_lsid; + std::string out_token; + + GaiaAuthenticator2::ParseClientLoginResponse(data, + &out_sid, + &out_lsid, + &out_token); + EXPECT_EQ(lsid, out_lsid); + EXPECT_EQ(sid, out_sid); + EXPECT_EQ(token, out_token); + } + + ResponseCookies cookies_; + GURL client_login_source_; + GURL issue_auth_token_source_; + TestingProfile profile_; +}; + +class MockGaiaConsumer : public GaiaAuthConsumer { + public: + MockGaiaConsumer() {} + ~MockGaiaConsumer() {} + + MOCK_METHOD1(OnClientLoginSuccess, void(const ClientLoginResult& result)); + MOCK_METHOD2(OnIssueAuthTokenSuccess, void(const std::string& service, + const std::string& token)); + MOCK_METHOD1(OnClientLoginFailure, void(const GaiaAuthError& error)); + MOCK_METHOD2(OnIssueAuthTokenFailure, void(const std::string& service, + const GaiaAuthError& error)); +}; + +TEST_F(GaiaAuthenticator2Test, ErrorComparator) { + GaiaAuthConsumer::GaiaAuthError expected_error; + expected_error.code = GaiaAuthConsumer::NETWORK_ERROR; + expected_error.network_error = -101; + + GaiaAuthConsumer::GaiaAuthError matching_error; + matching_error.code = GaiaAuthConsumer::NETWORK_ERROR; + matching_error.network_error = -101; + + EXPECT_TRUE(expected_error == matching_error); + + expected_error.network_error = 6; + + EXPECT_FALSE(expected_error == matching_error); + + expected_error.code = GaiaAuthConsumer::PERMISSION_DENIED; + matching_error.code = GaiaAuthConsumer::PERMISSION_DENIED; + + EXPECT_TRUE(expected_error == matching_error); +} + +TEST_F(GaiaAuthenticator2Test, LoginNetFailure) { + int error_no = net::ERR_CONNECTION_RESET; + URLRequestStatus status(URLRequestStatus::FAILED, error_no); + + GaiaAuthConsumer::GaiaAuthError expected_error; + expected_error.code = GaiaAuthConsumer::NETWORK_ERROR; + expected_error.network_error = error_no; + + MockGaiaConsumer consumer; + EXPECT_CALL(consumer, OnClientLoginFailure(expected_error)) + .Times(1); + + GaiaAuthenticator2 auth(&consumer, std::string(), + profile_.GetRequestContext()); + + auth.OnURLFetchComplete(NULL, + client_login_source_, + status, + 0, + cookies_, + std::string()); +} + +TEST_F(GaiaAuthenticator2Test, TokenNetFailure) { + int error_no = net::ERR_CONNECTION_RESET; + URLRequestStatus status(URLRequestStatus::FAILED, error_no); + + GaiaAuthConsumer::GaiaAuthError expected_error; + expected_error.code = GaiaAuthConsumer::NETWORK_ERROR; + expected_error.network_error = error_no; + + MockGaiaConsumer consumer; + EXPECT_CALL(consumer, OnIssueAuthTokenFailure(_, expected_error)) + .Times(1); + + GaiaAuthenticator2 auth(&consumer, std::string(), + profile_.GetRequestContext()); + + auth.OnURLFetchComplete(NULL, + issue_auth_token_source_, + status, + 0, + cookies_, + std::string()); +} + + +TEST_F(GaiaAuthenticator2Test, LoginDenied) { + std::string data("Error: NO!"); + URLRequestStatus status(URLRequestStatus::SUCCESS, 0); + + GaiaAuthConsumer::GaiaAuthError expected_error; + expected_error.code = GaiaAuthConsumer::PERMISSION_DENIED; + + MockGaiaConsumer consumer; + EXPECT_CALL(consumer, OnClientLoginFailure(expected_error)) + .Times(1); + + GaiaAuthenticator2 auth(&consumer, std::string(), + profile_.GetRequestContext()); + auth.OnURLFetchComplete(NULL, + client_login_source_, + status, + RC_FORBIDDEN, + cookies_, + data); +} + +TEST_F(GaiaAuthenticator2Test, ParseRequest) { + RunParsingTest("SID=sid\nLSID=lsid\nAuth=auth\n", "sid", "lsid", "auth"); + RunParsingTest("LSID=lsid\nSID=sid\nAuth=auth\n", "sid", "lsid", "auth"); + RunParsingTest("SID=sid\nLSID=lsid\nAuth=auth", "sid", "lsid", "auth"); + RunParsingTest("SID=sid\nAuth=auth\n", "sid", "", "auth"); + RunParsingTest("LSID=lsid\nAuth=auth\n", "", "lsid", "auth"); + RunParsingTest("\nAuth=auth\n", "", "", "auth"); + RunParsingTest("SID=sid", "sid", "", ""); +} + +TEST_F(GaiaAuthenticator2Test, OnlineLogin) { + std::string data("SID=sid\nLSID=lsid\nAuth=auth\n"); + + GaiaAuthConsumer::ClientLoginResult result; + result.lsid = "lsid"; + result.sid = "sid"; + result.token = "auth"; + result.data = data; + + MockGaiaConsumer consumer; + EXPECT_CALL(consumer, OnClientLoginSuccess(result)) + .Times(1); + + GaiaAuthenticator2 auth(&consumer, std::string(), + profile_.GetRequestContext()); + URLRequestStatus status(URLRequestStatus::SUCCESS, 0); + auth.OnURLFetchComplete(NULL, + client_login_source_, + status, + RC_REQUEST_OK, + cookies_, + data); +} + +TEST_F(GaiaAuthenticator2Test, WorkingIssueAuthToken) { + MockGaiaConsumer consumer; + EXPECT_CALL(consumer, OnIssueAuthTokenSuccess(_, "token")) + .Times(1); + + GaiaAuthenticator2 auth(&consumer, std::string(), + profile_.GetRequestContext()); + URLRequestStatus status(URLRequestStatus::SUCCESS, 0); + auth.OnURLFetchComplete(NULL, + issue_auth_token_source_, + status, + RC_REQUEST_OK, + cookies_, + "token"); +} + +TEST_F(GaiaAuthenticator2Test, CheckTwoFactorResponse) { + std::string response = + StringPrintf("Error=BadAuthentication\n%s\n", + GaiaAuthenticator2::kSecondFactor); + EXPECT_TRUE(GaiaAuthenticator2::IsSecondFactorSuccess(response)); +} + +TEST_F(GaiaAuthenticator2Test, CheckNormalErrorCode) { + std::string response = "Error=BadAuthentication\n"; + EXPECT_FALSE(GaiaAuthenticator2::IsSecondFactorSuccess(response)); +} + +TEST_F(GaiaAuthenticator2Test, TwoFactorLogin) { + std::string response = + StringPrintf("Error=BadAuthentication\n%s\n", + GaiaAuthenticator2::kSecondFactor); + + GaiaAuthConsumer::GaiaAuthError error; + error.code = GaiaAuthConsumer::TWO_FACTOR; + + MockGaiaConsumer consumer; + EXPECT_CALL(consumer, OnClientLoginFailure(error)) + .Times(1); + + GaiaAuthenticator2 auth(&consumer, std::string(), + profile_.GetRequestContext()); + URLRequestStatus status(URLRequestStatus::SUCCESS, 0); + auth.OnURLFetchComplete(NULL, + client_login_source_, + status, + RC_FORBIDDEN, + cookies_, + response); +} + +TEST_F(GaiaAuthenticator2Test, FullLogin) { + MockGaiaConsumer consumer; + EXPECT_CALL(consumer, OnClientLoginSuccess(_)) + .Times(1); + + TestingProfile profile; + + MockFactory factory; + URLFetcher::set_factory(&factory); + + GaiaAuthenticator2 auth(&consumer, std::string(), + profile_.GetRequestContext()); + auth.StartClientLogin("username", + "password", + "service", + std::string(), + std::string()); + + URLFetcher::set_factory(NULL); +} + +TEST_F(GaiaAuthenticator2Test, FullLoginFailure) { + MockGaiaConsumer consumer; + EXPECT_CALL(consumer, OnClientLoginFailure(_)) + .Times(1); + + TestingProfile profile; + + MockFactory factory; + URLFetcher::set_factory(&factory); + factory.set_success(false); + + GaiaAuthenticator2 auth(&consumer, std::string(), + profile_.GetRequestContext()); + auth.StartClientLogin("username", + "password", + "service", + std::string(), + std::string()); + + URLFetcher::set_factory(NULL); +} + +TEST_F(GaiaAuthenticator2Test, ClientFetchPending) { + MockGaiaConsumer consumer; + EXPECT_CALL(consumer, OnClientLoginSuccess(_)) + .Times(1); + + TestingProfile profile; + TestURLFetcherFactory factory; + URLFetcher::set_factory(&factory); + + GaiaAuthenticator2 auth(&consumer, std::string(), + profile_.GetRequestContext()); + auth.StartClientLogin("username", + "password", + "service", + std::string(), + std::string()); + + URLFetcher::set_factory(NULL); + EXPECT_TRUE(auth.HasPendingFetch()); + auth.OnURLFetchComplete(NULL, + client_login_source_, + URLRequestStatus(URLRequestStatus::SUCCESS, 0), + RC_REQUEST_OK, + cookies_, + "SID=sid\nLSID=lsid\nAuth=auth\n"); + EXPECT_FALSE(auth.HasPendingFetch()); +} + +TEST_F(GaiaAuthenticator2Test, FullTokenSuccess) { + MockGaiaConsumer consumer; + EXPECT_CALL(consumer, OnIssueAuthTokenSuccess("service", "token")) + .Times(1); + + TestingProfile profile; + TestURLFetcherFactory factory; + URLFetcher::set_factory(&factory); + + GaiaAuthenticator2 auth(&consumer, std::string(), + profile_.GetRequestContext()); + auth.StartIssueAuthToken("sid", "lsid", "service"); + + URLFetcher::set_factory(NULL); + EXPECT_TRUE(auth.HasPendingFetch()); + auth.OnURLFetchComplete(NULL, + issue_auth_token_source_, + URLRequestStatus(URLRequestStatus::SUCCESS, 0), + RC_REQUEST_OK, + cookies_, + "token"); + EXPECT_FALSE(auth.HasPendingFetch()); +} + +TEST_F(GaiaAuthenticator2Test, FullTokenFailure) { + MockGaiaConsumer consumer; + EXPECT_CALL(consumer, OnIssueAuthTokenFailure("service", _)) + .Times(1); + + TestingProfile profile; + TestURLFetcherFactory factory; + URLFetcher::set_factory(&factory); + + GaiaAuthenticator2 auth(&consumer, std::string(), + profile_.GetRequestContext()); + auth.StartIssueAuthToken("sid", "lsid", "service"); + + URLFetcher::set_factory(NULL); + EXPECT_TRUE(auth.HasPendingFetch()); + auth.OnURLFetchComplete(NULL, + issue_auth_token_source_, + URLRequestStatus(URLRequestStatus::SUCCESS, 0), + RC_FORBIDDEN, + cookies_, + ""); + EXPECT_FALSE(auth.HasPendingFetch()); +} diff --git a/chrome/common/net/gaia/gaia_authenticator2_unittest.h b/chrome/common/net/gaia/gaia_authenticator2_unittest.h new file mode 100644 index 0000000..d392ee8 --- /dev/null +++ b/chrome/common/net/gaia/gaia_authenticator2_unittest.h @@ -0,0 +1,71 @@ +// Copyright (c) 2010 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 collection of classes that are useful when testing things that use a +// GaiaAuthenticator2. + +#ifndef CHROME_COMMON_NET_GAIA_GAIA_AUTHENTICATOR2_UNITTEST_H_ +#define CHROME_COMMON_NET_GAIA_GAIA_AUTHENTICATOR2_UNITTEST_H_ + +#include "chrome/common/net/gaia/gaia_authenticator2.h" +#include "chrome/common/net/url_fetcher.h" +#include "chrome/common/net/http_return.h" +#include "net/url_request/url_request_status.h" + +// Responds as though ClientLogin returned from the server. +class MockFetcher : public URLFetcher { + public: + MockFetcher(bool success, + const GURL& url, + URLFetcher::RequestType request_type, + URLFetcher::Delegate* d) + : URLFetcher(url, request_type, d), + success_(success), + url_(url) {} + ~MockFetcher() {} + void Start() { + URLRequestStatus::Status code; + int http_code; + if (success_) { + http_code = RC_REQUEST_OK; + code = URLRequestStatus::SUCCESS; + } else { + http_code = RC_FORBIDDEN; + code = URLRequestStatus::FAILED; + } + + URLRequestStatus status(code, 0); + delegate()->OnURLFetchComplete(NULL, + url_, + status, + http_code, + ResponseCookies(), + std::string()); + } + private: + bool success_; + GURL url_; + DISALLOW_COPY_AND_ASSIGN(MockFetcher); +}; + +class MockFactory : public URLFetcher::Factory { + public: + MockFactory() + : success_(true) {} + ~MockFactory() {} + URLFetcher* CreateURLFetcher(int id, + const GURL& url, + URLFetcher::RequestType request_type, + URLFetcher::Delegate* d) { + return new MockFetcher(success_, url, request_type, d); + } + void set_success(bool success) { + success_ = success; + } + private: + bool success_; + DISALLOW_COPY_AND_ASSIGN(MockFactory); +}; + +#endif // CHROME_COMMON_NET_GAIA_GAIA_AUTHENTICATOR2_UNITTEST_H_ diff --git a/chrome/common/net/gaia/gaia_authenticator_unittest.cc b/chrome/common/net/gaia/gaia_authenticator_unittest.cc new file mode 100644 index 0000000..25a92d0 --- /dev/null +++ b/chrome/common/net/gaia/gaia_authenticator_unittest.cc @@ -0,0 +1,49 @@ +// Copyright (c) 2009 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 "chrome/common/net/gaia/gaia_authenticator.h" + +#include <string> + +#include "chrome/common/net/http_return.h" +#include "googleurl/src/gurl.h" +#include "testing/gtest/include/gtest/gtest.h" + +using std::string; + +namespace gaia { + +class GaiaAuthenticatorTest : public testing::Test { }; + +class GaiaAuthMockForGaiaAuthenticator : public GaiaAuthenticator { + public: + GaiaAuthMockForGaiaAuthenticator() + : GaiaAuthenticator("useragent", "serviceid", "http://gaia_url") {} + ~GaiaAuthMockForGaiaAuthenticator() {} + protected: + bool Post(const GURL& url, const string& post_body, + unsigned long* response_code, string* response_body) { + *response_code = RC_REQUEST_OK; + response_body->assign("body\n"); + return true; + } + + int GetBackoffDelaySeconds( + int current_backoff_delay) { + // Dummy delay value. + return 5; + } +}; + +TEST(GaiaAuthenticatorTest, TestNewlineAtEndOfAuthTokenRemoved) { + GaiaAuthMockForGaiaAuthenticator mock_auth; + MessageLoop message_loop; + mock_auth.set_message_loop(&message_loop); + GaiaAuthenticator::AuthResults results; + EXPECT_TRUE(mock_auth.IssueAuthToken(&results, "sid")); + EXPECT_EQ(0, results.auth_token.compare("body")); +} + +} // namespace gaia + diff --git a/chrome/common/net/http_return.h b/chrome/common/net/http_return.h new file mode 100644 index 0000000..f47d1bb --- /dev/null +++ b/chrome/common/net/http_return.h @@ -0,0 +1,17 @@ +// Copyright (c) 2009 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 CHROME_COMMON_NET_HTTP_RETURN_H_ +#define CHROME_COMMON_NET_HTTP_RETURN_H_ + +// TODO(sanjeevr): This has been moved from the sync library so it only +// contains a few HTTP return codes. Add more HTTP return codes. +enum HTTPReturnCode { + RC_REQUEST_OK = 200, + RC_UNAUTHORIZED = 401, + RC_FORBIDDEN = 403, +}; + +#endif // CHROME_COMMON_NET_HTTP_RETURN_H_ + diff --git a/chrome/common/net/net_resource_provider.cc b/chrome/common/net/net_resource_provider.cc new file mode 100644 index 0000000..6992470 --- /dev/null +++ b/chrome/common/net/net_resource_provider.cc @@ -0,0 +1,63 @@ +// Copyright (c) 2009 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 "chrome/common/net/net_resource_provider.h" + +#include <string> + +#include "app/l10n_util.h" +#include "app/resource_bundle.h" +#include "base/string_piece.h" +#include "base/values.h" +#include "chrome/common/jstemplate_builder.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" +#include "grit/net_resources.h" + +namespace { + +// The net module doesn't have access to this HTML or the strings that need to +// be localized. The Chrome locale will never change while we're running, so +// it's safe to have a static string that we always return a pointer into. +// This allows us to have the ResourceProvider return a pointer into the actual +// resource (via a StringPiece), instead of always copying resources. +struct LazyDirectoryListerCacher { + LazyDirectoryListerCacher() { + DictionaryValue value; + value.SetString(L"header", + l10n_util::GetString(IDS_DIRECTORY_LISTING_HEADER)); + value.SetString(L"parentDirText", + l10n_util::GetString(IDS_DIRECTORY_LISTING_PARENT)); + value.SetString(L"headerName", + l10n_util::GetString(IDS_DIRECTORY_LISTING_NAME)); + value.SetString(L"headerSize", + l10n_util::GetString(IDS_DIRECTORY_LISTING_SIZE)); + value.SetString(L"headerDateModified", + l10n_util::GetString(IDS_DIRECTORY_LISTING_DATE_MODIFIED)); + value.SetString(L"listingParsingErrorBoxText", + l10n_util::GetStringF(IDS_DIRECTORY_LISTING_PARSING_ERROR_BOX_TEXT, + l10n_util::GetString(IDS_PRODUCT_NAME))); + html_data = jstemplate_builder::GetI18nTemplateHtml( + ResourceBundle::GetSharedInstance().GetRawDataResource( + IDR_DIR_HEADER_HTML), + &value); + } + + std::string html_data; +}; + +} // namespace + +namespace chrome_common_net { + +base::StringPiece NetResourceProvider(int key) { + static LazyDirectoryListerCacher lazy_dir_lister; + + if (IDR_DIR_HEADER_HTML == key) + return base::StringPiece(lazy_dir_lister.html_data); + + return ResourceBundle::GetSharedInstance().GetRawDataResource(key); +} + +} // namespace chrome_common_net diff --git a/chrome/common/net/net_resource_provider.h b/chrome/common/net/net_resource_provider.h new file mode 100644 index 0000000..4965adf --- /dev/null +++ b/chrome/common/net/net_resource_provider.h @@ -0,0 +1,19 @@ +// Copyright (c) 2009 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 CHROME_COMMON_NET_NET_RESOURCE_PROVIDER_H_ +#define CHROME_COMMON_NET_NET_RESOURCE_PROVIDER_H_ + +namespace base { +class StringPiece; +} + +namespace chrome_common_net { + +// This is called indirectly by the network layer to access resources. +base::StringPiece NetResourceProvider(int key); + +} // namespace chrome_common_net + +#endif // CHROME_COMMON_NET_NET_RESOURCE_PROVIDER_H_ diff --git a/chrome/common/net/predictor_common.h b/chrome/common/net/predictor_common.h new file mode 100644 index 0000000..c1d995f --- /dev/null +++ b/chrome/common/net/predictor_common.h @@ -0,0 +1,29 @@ +// Copyright (c) 2006-2008 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 has shared types used across IPC between render_dns_master.cc +// and dns_master.cc + +#ifndef CHROME_COMMON_NET_PREDICTOR_COMMON_H_ +#define CHROME_COMMON_NET_PREDICTOR_COMMON_H_ + +#include <string> +#include <vector> + +#include "googleurl/src/gurl.h" + +namespace chrome_common_net { + +// IPC messages are passed from the renderer to the browser in the form of +// Namelist instances. +// Each element of this vector is a hostname that needs to be looked up. +// The hostnames should never be empty strings. +typedef std::vector<std::string> NameList; +// TODO(jar): We still need to switch to passing scheme/host/port in UrlList, +// instead of NameList, from renderer (where content of pages are scanned for +// links) to browser (where we perform predictive actions). +typedef std::vector<GURL> UrlList; +} + +#endif // CHROME_COMMON_NET_PREDICTOR_COMMON_H_ diff --git a/chrome/common/net/socket_stream.h b/chrome/common/net/socket_stream.h new file mode 100644 index 0000000..6c1ad92 --- /dev/null +++ b/chrome/common/net/socket_stream.h @@ -0,0 +1,14 @@ +// Copyright (c) 2009 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 CHROME_COMMON_NET_SOCKET_STREAM_H_ +#define CHROME_COMMON_NET_SOCKET_STREAM_H_ + +namespace chrome_common_net { + +const int kNoSocketId = 0; + +} // namespace chrome_common_net + +#endif // CHROME_COMMON_NET_SOCKET_STREAM_H_ diff --git a/chrome/common/net/test_url_fetcher_factory.cc b/chrome/common/net/test_url_fetcher_factory.cc new file mode 100644 index 0000000..6ab3a49 --- /dev/null +++ b/chrome/common/net/test_url_fetcher_factory.cc @@ -0,0 +1,27 @@ +// Copyright (c) 2009 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 "chrome/common/net/test_url_fetcher_factory.h" + +TestURLFetcher::TestURLFetcher(const GURL& url, + URLFetcher::RequestType request_type, + URLFetcher::Delegate* d) + : URLFetcher(url, request_type, d), + original_url_(url) { +} + +URLFetcher* TestURLFetcherFactory::CreateURLFetcher( + int id, + const GURL& url, + URLFetcher::RequestType request_type, + URLFetcher::Delegate* d) { + TestURLFetcher* fetcher = new TestURLFetcher(url, request_type, d); + fetchers_[id] = fetcher; + return fetcher; +} + +TestURLFetcher* TestURLFetcherFactory::GetFetcherByID(int id) const { + Fetchers::const_iterator i = fetchers_.find(id); + return i == fetchers_.end() ? NULL : i->second; +} diff --git a/chrome/common/net/test_url_fetcher_factory.h b/chrome/common/net/test_url_fetcher_factory.h new file mode 100644 index 0000000..2e4ea45 --- /dev/null +++ b/chrome/common/net/test_url_fetcher_factory.h @@ -0,0 +1,82 @@ +// Copyright (c) 2009 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 CHROME_COMMON_NET_TEST_URL_FETCHER_FACTORY_H_ +#define CHROME_COMMON_NET_TEST_URL_FETCHER_FACTORY_H_ + +#include <map> +#include <string> + +#include "chrome/common/net/url_fetcher.h" +#include "googleurl/src/gurl.h" + +// TestURLFetcher and TestURLFetcherFactory are used for testing consumers of +// URLFetcher. TestURLFetcherFactory is a URLFetcher::Factory that creates +// TestURLFetchers. TestURLFetcher::Start is overriden to do nothing. It is +// expected that you'll grab the delegate from the TestURLFetcher and invoke +// the callback method when appropriate. In this way it's easy to mock a +// URLFetcher. +// Typical usage: +// // TestURLFetcher requires a MessageLoop: +// MessageLoopForUI message_loop; +// // Create and register factory. +// TestURLFetcherFactory factory; +// URLFetcher::set_factory(&factory); +// // Do something that triggers creation of a URLFetcher. +// TestURLFetcher* fetcher = factory.GetFetcherByID(expected_id); +// DCHECK(fetcher); +// // Notify delegate with whatever data you want. +// fetcher->delegate()->OnURLFetchComplete(...); +// // Make sure consumer of URLFetcher does the right thing. +// ... +// // Reset factory. +// URLFetcher::set_factory(NULL); + + +class TestURLFetcher : public URLFetcher { + public: + TestURLFetcher(const GURL& url, RequestType request_type, Delegate* d); + + // Returns the delegate installed on the URLFetcher. + Delegate* delegate() const { return URLFetcher::delegate(); } + + // Overriden to do nothing. It is assumed the caller will notify the delegate. + virtual void Start() {} + + // URL we were created with. Because of how we're using URLFetcher url() + // always returns an empty URL. Chances are you'll want to use original_url() + // in your tests. + const GURL& original_url() const { return original_url_; } + + // Returns the data uploaded on this URLFetcher. + const std::string& upload_data() const { return URLFetcher::upload_data(); } + + private: + const GURL original_url_; + + DISALLOW_COPY_AND_ASSIGN(TestURLFetcher); +}; + +// Simple URLFetcher::Factory method that creates TestURLFetchers. All fetchers +// are registered in a map by the id passed to the create method. +class TestURLFetcherFactory : public URLFetcher::Factory { + public: + TestURLFetcherFactory() {} + + virtual URLFetcher* CreateURLFetcher(int id, + const GURL& url, + URLFetcher::RequestType request_type, + URLFetcher::Delegate* d); + + TestURLFetcher* GetFetcherByID(int id) const; + + private: + // Maps from id passed to create to the returned URLFetcher. + typedef std::map<int, TestURLFetcher*> Fetchers; + Fetchers fetchers_; + + DISALLOW_COPY_AND_ASSIGN(TestURLFetcherFactory); +}; + +#endif // CHROME_COMMON_NET_TEST_URL_FETCHER_FACTORY_H_ diff --git a/chrome/common/net/url_fetcher.cc b/chrome/common/net/url_fetcher.cc new file mode 100644 index 0000000..a74255b --- /dev/null +++ b/chrome/common/net/url_fetcher.cc @@ -0,0 +1,377 @@ +// Copyright (c) 2009 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 "chrome/common/net/url_fetcher.h" + +#include "base/compiler_specific.h" +#include "base/message_loop_proxy.h" +#include "base/string_util.h" +#include "base/thread.h" +#include "chrome/common/net/url_fetcher_protect.h" +#include "chrome/common/net/url_request_context_getter.h" +#include "googleurl/src/gurl.h" +#include "net/base/load_flags.h" +#include "net/base/io_buffer.h" +#include "net/http/http_request_headers.h" +#include "net/http/http_response_headers.h" +#include "net/url_request/url_request.h" +#include "net/url_request/url_request_context.h" + +static const int kBufferSize = 4096; + +bool URLFetcher::g_interception_enabled = false; + +class URLFetcher::Core + : public base::RefCountedThreadSafe<URLFetcher::Core>, + public MessageLoop::DestructionObserver, + public URLRequest::Delegate { + public: + // For POST requests, set |content_type| to the MIME type of the content + // and set |content| to the data to upload. |flags| are flags to apply to + // the load operation--these should be one or more of the LOAD_* flags + // defined in url_request.h. + Core(URLFetcher* fetcher, + const GURL& original_url, + RequestType request_type, + URLFetcher::Delegate* d); + + // Starts the load. It's important that this not happen in the constructor + // because it causes the IO thread to begin AddRef()ing and Release()ing + // us. If our caller hasn't had time to fully construct us and take a + // reference, the IO thread could interrupt things, run a task, Release() + // us, and destroy us, leaving the caller with an already-destroyed object + // when construction finishes. + void Start(); + + // Stops any in-progress load and ensures no callback will happen. It is + // safe to call this multiple times. + void Stop(); + + // MessageLoop::DestructionObserver implementation. We are only registered as + // a DestructionObserver when |request_| exists. + virtual void WillDestroyCurrentMessageLoop(); + + // URLRequest::Delegate implementation. + virtual void OnResponseStarted(URLRequest* request); + virtual void OnReadCompleted(URLRequest* request, int bytes_read); + + URLFetcher::Delegate* delegate() const { return delegate_; } + + private: + friend class base::RefCountedThreadSafe<URLFetcher::Core>; + + ~Core() {} + + // Wrapper functions that allow us to ensure actions happen on the right + // thread. + void StartURLRequest(); + void CancelURLRequest(); + void OnCompletedURLRequest(const URLRequestStatus& status); + + URLFetcher* fetcher_; // Corresponding fetcher object + GURL original_url_; // The URL we were asked to fetch + GURL url_; // The URL we eventually wound up at + RequestType request_type_; // What type of request is this? + URLFetcher::Delegate* delegate_; // Object to notify on completion + MessageLoop* delegate_loop_; // Message loop of the creating thread + scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_; + // The message loop proxy for the thread + // on which the request IO happens. + URLRequest* request_; // The actual request this wraps + int load_flags_; // Flags for the load operation + int response_code_; // HTTP status code for the request + std::string data_; // Results of the request + scoped_refptr<net::IOBuffer> buffer_; + // Read buffer + scoped_refptr<URLRequestContextGetter> request_context_getter_; + // Cookie/cache info for the request + ResponseCookies cookies_; // Response cookies + net::HttpRequestHeaders extra_request_headers_; + scoped_refptr<net::HttpResponseHeaders> response_headers_; + + std::string upload_content_; // HTTP POST payload + std::string upload_content_type_; // MIME type of POST payload + + // The overload protection entry for this URL. This is used to + // incrementally back off how rapidly we'll send requests to a particular + // URL, to avoid placing too much demand on the remote resource. We update + // this with the status of all requests as they return, and in turn use it + // to determine how long to wait before making another request. + URLFetcherProtectEntry* protect_entry_; + // |num_retries_| indicates how many times we've failed to successfully + // fetch this URL. Once this value exceeds the maximum number of retries + // specified by the protection manager, we'll give up. + int num_retries_; + + // True if the URLFetcher has been cancelled. + bool was_cancelled_; + + friend class URLFetcher; + DISALLOW_COPY_AND_ASSIGN(Core); +}; + +// static +URLFetcher::Factory* URLFetcher::factory_ = NULL; + +URLFetcher::URLFetcher(const GURL& url, + RequestType request_type, + Delegate* d) + : ALLOW_THIS_IN_INITIALIZER_LIST( + core_(new Core(this, url, request_type, d))), + automatically_retry_on_5xx_(true) { +} + +URLFetcher::~URLFetcher() { + core_->Stop(); +} + +// static +URLFetcher* URLFetcher::Create(int id, const GURL& url, + RequestType request_type, Delegate* d) { + return factory_ ? factory_->CreateURLFetcher(id, url, request_type, d) : + new URLFetcher(url, request_type, d); +} + +URLFetcher::Core::Core(URLFetcher* fetcher, + const GURL& original_url, + RequestType request_type, + URLFetcher::Delegate* d) + : fetcher_(fetcher), + original_url_(original_url), + request_type_(request_type), + delegate_(d), + delegate_loop_(MessageLoop::current()), + request_(NULL), + load_flags_(net::LOAD_NORMAL), + response_code_(-1), + buffer_(new net::IOBuffer(kBufferSize)), + protect_entry_(URLFetcherProtectManager::GetInstance()->Register( + original_url_.host())), + num_retries_(0), + was_cancelled_(false) { +} + +void URLFetcher::Core::Start() { + DCHECK(delegate_loop_); + CHECK(request_context_getter_) << "We need an URLRequestContext!"; + io_message_loop_proxy_ = request_context_getter_->GetIOMessageLoopProxy(); + CHECK(io_message_loop_proxy_.get()) << "We need an IO message loop proxy"; + io_message_loop_proxy_->PostDelayedTask( + FROM_HERE, + NewRunnableMethod(this, &Core::StartURLRequest), + protect_entry_->UpdateBackoff(URLFetcherProtectEntry::SEND)); +} + +void URLFetcher::Core::Stop() { + DCHECK_EQ(MessageLoop::current(), delegate_loop_); + delegate_ = NULL; + fetcher_ = NULL; + if (io_message_loop_proxy_.get()) { + io_message_loop_proxy_->PostTask( + FROM_HERE, NewRunnableMethod(this, &Core::CancelURLRequest)); + } +} + +void URLFetcher::Core::WillDestroyCurrentMessageLoop() { + CancelURLRequest(); + // Don't bother to try and notify the delegate thread portion of this object, + // since if the IO thread is shutting down, everything is shutting down, and + // we just want to avoid leaks. +} + +void URLFetcher::Core::OnResponseStarted(URLRequest* request) { + DCHECK(request == request_); + DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); + if (request_->status().is_success()) { + response_code_ = request_->GetResponseCode(); + response_headers_ = request_->response_headers(); + } + + int bytes_read = 0; + // Some servers may treat HEAD requests as GET requests. To free up the + // network connection as soon as possible, signal that the request has + // completed immediately, without trying to read any data back (all we care + // about is the response code and headers, which we already have). + if (request_->status().is_success() && (request_type_ != HEAD)) + request_->Read(buffer_, kBufferSize, &bytes_read); + OnReadCompleted(request_, bytes_read); +} + +void URLFetcher::Core::OnReadCompleted(URLRequest* request, int bytes_read) { + DCHECK(request == request_); + DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); + + url_ = request->url(); + + do { + if (!request_->status().is_success() || bytes_read <= 0) + break; + data_.append(buffer_->data(), bytes_read); + } while (request_->Read(buffer_, kBufferSize, &bytes_read)); + + if (request_->status().is_success()) + request_->GetResponseCookies(&cookies_); + + // See comments re: HEAD requests in OnResponseStarted(). + if (!request_->status().is_io_pending() || (request_type_ == HEAD)) { + delegate_loop_->PostTask(FROM_HERE, NewRunnableMethod( + this, &Core::OnCompletedURLRequest, request_->status())); + delete request_; + request_ = NULL; + MessageLoop::current()->RemoveDestructionObserver(this); + } +} + +void URLFetcher::Core::StartURLRequest() { + DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); + + if (was_cancelled_) { + // Since StartURLRequest() is posted as a *delayed* task, it may + // run after the URLFetcher was already stopped. + return; + } + + CHECK(request_context_getter_); + DCHECK(!request_); + + MessageLoop::current()->AddDestructionObserver(this); + + request_ = new URLRequest(original_url_, this); + int flags = request_->load_flags() | load_flags_; + if (!g_interception_enabled) { + flags = flags | net::LOAD_DISABLE_INTERCEPT; + } + request_->set_load_flags(flags); + request_->set_context(request_context_getter_->GetURLRequestContext()); + + switch (request_type_) { + case GET: + break; + + case POST: + DCHECK(!upload_content_.empty()); + DCHECK(!upload_content_type_.empty()); + + request_->set_method("POST"); + extra_request_headers_.SetHeader(net::HttpRequestHeaders::kContentType, + upload_content_type_); + request_->AppendBytesToUpload(upload_content_.data(), + static_cast<int>(upload_content_.size())); + break; + + case HEAD: + request_->set_method("HEAD"); + break; + + default: + NOTREACHED(); + } + + if (!extra_request_headers_.IsEmpty()) + request_->SetExtraRequestHeaders(extra_request_headers_); + + request_->Start(); +} + +void URLFetcher::Core::CancelURLRequest() { + DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); + + if (request_) { + request_->Cancel(); + delete request_; + request_ = NULL; + MessageLoop::current()->RemoveDestructionObserver(this); + } + // Release the reference to the request context. There could be multiple + // references to URLFetcher::Core at this point so it may take a while to + // delete the object, but we cannot delay the destruction of the request + // context. + request_context_getter_ = NULL; + was_cancelled_ = true; +} + +void URLFetcher::Core::OnCompletedURLRequest(const URLRequestStatus& status) { + DCHECK(MessageLoop::current() == delegate_loop_); + + // Checks the response from server. + if (response_code_ >= 500) { + // When encountering a server error, we will send the request again + // after backoff time. + int64 back_off_time = + protect_entry_->UpdateBackoff(URLFetcherProtectEntry::FAILURE); + if (delegate_) { + fetcher_->backoff_delay_ = + base::TimeDelta::FromMilliseconds(back_off_time); + } + ++num_retries_; + // Restarts the request if we still need to notify the delegate. + if (delegate_) { + if (fetcher_->automatically_retry_on_5xx_ && + num_retries_ <= protect_entry_->max_retries()) { + io_message_loop_proxy_->PostDelayedTask( + FROM_HERE, + NewRunnableMethod(this, &Core::StartURLRequest), back_off_time); + } else { + delegate_->OnURLFetchComplete(fetcher_, url_, status, response_code_, + cookies_, data_); + } + } + } else { + protect_entry_->UpdateBackoff(URLFetcherProtectEntry::SUCCESS); + if (delegate_) { + fetcher_->backoff_delay_ = base::TimeDelta(); + delegate_->OnURLFetchComplete(fetcher_, url_, status, response_code_, + cookies_, data_); + } + } +} + +void URLFetcher::set_upload_data(const std::string& upload_content_type, + const std::string& upload_content) { + core_->upload_content_type_ = upload_content_type; + core_->upload_content_ = upload_content; +} + +const std::string& URLFetcher::upload_data() const { + return core_->upload_content_; +} + +void URLFetcher::set_load_flags(int load_flags) { + core_->load_flags_ = load_flags; +} + +int URLFetcher::load_flags() const { + return core_->load_flags_; +} + +void URLFetcher::set_extra_request_headers( + const std::string& extra_request_headers) { + core_->extra_request_headers_.Clear(); + core_->extra_request_headers_.AddHeadersFromString(extra_request_headers); +} + +void URLFetcher::set_request_context( + URLRequestContextGetter* request_context_getter) { + core_->request_context_getter_ = request_context_getter; +} + +void URLFetcher::set_automatcally_retry_on_5xx(bool retry) { + automatically_retry_on_5xx_ = retry; +} + +net::HttpResponseHeaders* URLFetcher::response_headers() const { + return core_->response_headers_; +} + +void URLFetcher::Start() { + core_->Start(); +} + +const GURL& URLFetcher::url() const { + return core_->url_; +} + +URLFetcher::Delegate* URLFetcher::delegate() const { + return core_->delegate(); +} diff --git a/chrome/common/net/url_fetcher.h b/chrome/common/net/url_fetcher.h new file mode 100644 index 0000000..9572478 --- /dev/null +++ b/chrome/common/net/url_fetcher.h @@ -0,0 +1,192 @@ +// Copyright (c) 2010 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 contains URLFetcher, a wrapper around URLRequest that handles +// low-level details like thread safety, ref counting, and incremental buffer +// reading. This is useful for callers who simply want to get the data from a +// URL and don't care about all the nitty-gritty details. + +#ifndef CHROME_COMMON_NET_URL_FETCHER_H_ +#define CHROME_COMMON_NET_URL_FETCHER_H_ + +#include <string> + +#include "base/message_loop.h" +#include "base/ref_counted.h" +#include "base/time.h" + +class GURL; +typedef std::vector<std::string> ResponseCookies; +class URLFetcher; +class URLRequestContextGetter; +class URLRequestStatus; + +namespace net { +class HttpResponseHeaders; +} + +// To use this class, create an instance with the desired URL and a pointer to +// the object to be notified when the URL has been loaded: +// URLFetcher* fetcher = new URLFetcher("http://www.google.com", this); +// +// Then, optionally set properties on this object, like the request context or +// extra headers: +// fetcher->SetExtraRequestHeaders("X-Foo: bar"); +// +// Finally, start the request: +// fetcher->Start(); +// +// The object you supply as a delegate must inherit from URLFetcher::Delegate; +// when the fetch is completed, OnURLFetchComplete() will be called with the +// resulting status and (if applicable) HTTP response code. From that point +// until the original URLFetcher instance is destroyed, you may examine the +// provided status and data for the URL. (You should copy these objects if you +// need them to live longer than the URLFetcher instance.) If the URLFetcher +// instance is destroyed before the callback happens, the fetch will be +// canceled and no callback will occur. +// +// You may create the URLFetcher instance on any thread; OnURLFetchComplete() +// will be called back on the same thread you use to create the instance. +// +// +// NOTE: By default URLFetcher requests are NOT intercepted, except when +// interception is explicitly enabled in tests. + +class URLFetcher { + public: + enum RequestType { + GET, + POST, + HEAD, + }; + + class Delegate { + public: + // This will be called when the URL has been fetched, successfully or not. + // |response_code| is the HTTP response code (200, 404, etc.) if + // applicable. |url|, |status| and |data| are all valid until the + // URLFetcher instance is destroyed. + virtual void OnURLFetchComplete(const URLFetcher* source, + const GURL& url, + const URLRequestStatus& status, + int response_code, + const ResponseCookies& cookies, + const std::string& data) = 0; + }; + + // URLFetcher::Create uses the currently registered Factory to create the + // URLFetcher. Factory is intended for testing. + class Factory { + public: + virtual URLFetcher* CreateURLFetcher(int id, + const GURL& url, + RequestType request_type, + Delegate* d) = 0; + }; + + // |url| is the URL to send the request to. + // |request_type| is the type of request to make. + // |d| the object that will receive the callback on fetch completion. + URLFetcher(const GURL& url, RequestType request_type, Delegate* d); + + virtual ~URLFetcher(); + + // Sets the factory used by the static method Create to create a URLFetcher. + // URLFetcher does not take ownership of |factory|. A value of NULL results + // in a URLFetcher being created directly. +#if defined(UNIT_TEST) + static void set_factory(Factory* factory) { factory_ = factory; } +#endif + + // Normally interception is disabled for URLFetcher, but you can use this + // to enable it for tests. Also see the set_factory method for another way + // of testing code that uses an URLFetcher. + static void enable_interception_for_tests(bool enabled) { + g_interception_enabled = enabled; + } + + // Creates a URLFetcher, ownership returns to the caller. If there is no + // Factory (the default) this creates and returns a new URLFetcher. See the + // constructor for a description of the args. |id| may be used during testing + // to identify who is creating the URLFetcher. + static URLFetcher* Create(int id, const GURL& url, RequestType request_type, + Delegate* d); + + // Sets data only needed by POSTs. All callers making POST requests should + // call this before the request is started. |upload_content_type| is the MIME + // type of the content, while |upload_content| is the data to be sent (the + // Content-Length header value will be set to the length of this data). + void set_upload_data(const std::string& upload_content_type, + const std::string& upload_content); + + // Set one or more load flags as defined in net/base/load_flags.h. Must be + // called before the request is started. + void set_load_flags(int load_flags); + + // Returns the current load flags. + int load_flags() const; + + // Set extra headers on the request. Must be called before the request + // is started. + void set_extra_request_headers(const std::string& extra_request_headers); + + // Set the URLRequestContext on the request. Must be called before the + // request is started. + void set_request_context(URLRequestContextGetter* request_context_getter); + + // If |retry| is false, 5xx responses will be propagated to the observer, + // if it is true URLFetcher will automatically re-execute the request, + // after backoff_delay() elapses. URLFetcher has it set to true by default. + void set_automatcally_retry_on_5xx(bool retry); + + // Returns the back-off delay before the request will be retried, + // when a 5xx response was received. + base::TimeDelta backoff_delay() const { return backoff_delay_; } + + // Sets the back-off delay, allowing to mock 5xx requests in unit-tests. +#if defined(UNIT_TEST) + void set_backoff_delay(base::TimeDelta backoff_delay) { + backoff_delay_ = backoff_delay; + } +#endif // defined(UNIT_TEST) + + // Retrieve the response headers from the request. Must only be called after + // the OnURLFetchComplete callback has run. + virtual net::HttpResponseHeaders* response_headers() const; + + // Start the request. After this is called, you may not change any other + // settings. + virtual void Start(); + + // Return the URL that this fetcher is processing. + const GURL& url() const; + + protected: + // Returns the delegate. + Delegate* delegate() const; + + // Used by tests. + const std::string& upload_data() const; + + private: + class Core; + + scoped_refptr<Core> core_; + + static Factory* factory_; + + // If |automatically_retry_on_5xx_| is false, 5xx responses will be + // propagated to the observer, if it is true URLFetcher will automatically + // re-execute the request, after the back-off delay has expired. + // true by default. + bool automatically_retry_on_5xx_; + // Back-off time delay. 0 by default. + base::TimeDelta backoff_delay_; + + static bool g_interception_enabled; + + DISALLOW_COPY_AND_ASSIGN(URLFetcher); +}; + +#endif // CHROME_COMMON_NET_URL_FETCHER_H_ diff --git a/chrome/common/net/url_fetcher_protect.cc b/chrome/common/net/url_fetcher_protect.cc new file mode 100644 index 0000000..05c8e2e --- /dev/null +++ b/chrome/common/net/url_fetcher_protect.cc @@ -0,0 +1,176 @@ +// Copyright (c) 2006-2008 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 "chrome/common/net/url_fetcher_protect.h" + +#include "base/logging.h" + +// URLFetcherProtectEntry ---------------------------------------------------- + +using base::TimeDelta; +using base::TimeTicks; + +// Default parameters. Time is in milliseconds. +// static +const int URLFetcherProtectEntry::kDefaultSlidingWindowPeriod = 2000; + +const int URLFetcherProtectEntry::kDefaultMaxSendThreshold = 20; +const int URLFetcherProtectEntry::kDefaultMaxRetries = 0; + +const int URLFetcherProtectEntry::kDefaultInitialTimeout = 100; +const double URLFetcherProtectEntry::kDefaultMultiplier = 2.0; +const int URLFetcherProtectEntry::kDefaultConstantFactor = 100; +const int URLFetcherProtectEntry::kDefaultMaximumTimeout = 60000; + + +URLFetcherProtectEntry::URLFetcherProtectEntry() + : sliding_window_period_(kDefaultSlidingWindowPeriod), + max_send_threshold_(kDefaultMaxSendThreshold), + max_retries_(kDefaultMaxRetries), + initial_timeout_(kDefaultInitialTimeout), + multiplier_(kDefaultMultiplier), + constant_factor_(kDefaultConstantFactor), + maximum_timeout_(kDefaultMaximumTimeout) { + ResetBackoff(); +} + +URLFetcherProtectEntry::URLFetcherProtectEntry(int sliding_window_period, + int max_send_threshold, + int max_retries, + int initial_timeout, + double multiplier, + int constant_factor, + int maximum_timeout) + : sliding_window_period_(sliding_window_period), + max_send_threshold_(max_send_threshold), + max_retries_(max_retries), + initial_timeout_(initial_timeout), + multiplier_(multiplier), + constant_factor_(constant_factor), + maximum_timeout_(maximum_timeout) { + ResetBackoff(); +} + +int64 URLFetcherProtectEntry::UpdateBackoff(EventType event_type) { + // request may be sent in different threads + AutoLock lock(lock_); + + TimeDelta t; + switch (event_type) { + case SEND: + t = AntiOverload(); + break; + case SUCCESS: + t = ResetBackoff(); + break; + case FAILURE: + t = IncreaseBackoff(); + break; + default: + NOTREACHED(); + } + + int64 wait = t.InMilliseconds(); + DCHECK(wait >= 0); + return wait; +} + +TimeDelta URLFetcherProtectEntry::AntiOverload() { + TimeDelta sw = TimeDelta::FromMilliseconds(sliding_window_period_); + TimeTicks now = TimeTicks::Now(); + // Estimate when the next request will be sent. + release_time_ = now; + if (send_log_.size() > 0) { + release_time_ = std::max(release_time_, send_log_.back()); + } + // Checks if there are too many send events in recent time. + if (send_log_.size() >= static_cast<unsigned>(max_send_threshold_)) { + release_time_ = std::max(release_time_, send_log_.front() + sw); + } + // Logs the new send event. + send_log_.push(release_time_); + // Drops the out-of-date events in the event list. + while (!send_log_.empty() && + (send_log_.front() + sw <= send_log_.back())) { + send_log_.pop(); + } + return release_time_ - now; +} + +TimeDelta URLFetcherProtectEntry::ResetBackoff() { + timeout_period_ = initial_timeout_; + release_time_ = TimeTicks::Now(); + return TimeDelta::FromMilliseconds(0); +} + +TimeDelta URLFetcherProtectEntry::IncreaseBackoff() { + TimeTicks now = TimeTicks::Now(); + + release_time_ = std::max(release_time_, now) + + TimeDelta::FromMilliseconds(timeout_period_); + + // Calculates the new backoff time. + timeout_period_ = static_cast<int> + (multiplier_ * timeout_period_ + constant_factor_); + if (maximum_timeout_ && timeout_period_ > maximum_timeout_) + timeout_period_ = maximum_timeout_; + + return release_time_ - now; +} + +// URLFetcherProtectManager -------------------------------------------------- + +// static +scoped_ptr<URLFetcherProtectManager> URLFetcherProtectManager::protect_manager_; +Lock URLFetcherProtectManager::lock_; + +URLFetcherProtectManager::~URLFetcherProtectManager() { + // Deletes all entries + ProtectService::iterator i; + for (i = services_.begin(); i != services_.end(); ++i) { + if (i->second) + delete i->second; + } +} + +// static +URLFetcherProtectManager* URLFetcherProtectManager::GetInstance() { + AutoLock lock(lock_); + + if (protect_manager_.get() == NULL) { + protect_manager_.reset(new URLFetcherProtectManager()); + } + return protect_manager_.get(); +} + +URLFetcherProtectEntry* URLFetcherProtectManager::Register( + const std::string& id) { + AutoLock lock(lock_); + + ProtectService::iterator i = services_.find(id); + + if (i != services_.end()) { + // The entry exists. + return i->second; + } + + // Creates a new entry. + URLFetcherProtectEntry* entry = new URLFetcherProtectEntry(); + services_[id] = entry; + return entry; +} + +URLFetcherProtectEntry* URLFetcherProtectManager::Register( + const std::string& id, URLFetcherProtectEntry* entry) { + AutoLock lock(lock_); + + ProtectService::iterator i = services_.find(id); + if (i != services_.end()) { + // The entry exists. + delete i->second; + } + + services_[id] = entry; + return entry; +} diff --git a/chrome/common/net/url_fetcher_protect.h b/chrome/common/net/url_fetcher_protect.h new file mode 100644 index 0000000..0b9c624 --- /dev/null +++ b/chrome/common/net/url_fetcher_protect.h @@ -0,0 +1,146 @@ +// Copyright (c) 2006-2008 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 implements backoff in the suggest system so that we don't +// DOS the Suggest servers when using URLFetcher. + +#ifndef CHROME_COMMON_NET_URL_FETCHER_PROTECT_H_ +#define CHROME_COMMON_NET_URL_FETCHER_PROTECT_H_ + +#include <map> +#include <queue> +#include <string> + +#include "base/lock.h" +#include "base/scoped_ptr.h" +#include "base/time.h" + + +// This class is used to manage one service's rate protection. It maintains +// a queue of connection successes and failures and analyzes the requests +// over some period of time, in order to deduce the backoff time of every +// request. +// The backoff algorithm consists of two parts. Firstly, avoid too many +// send events in a sliding window. That will prevent traffic overload. +// Secondly, exponential backoff is used when receiving an error message +// from server. Exponential backoff period is calculated using the following +// formula: +// +// initial backoff time (the first time to receive error) +// backoff = k * current_backoff + c (the second, third, ... error) +// maximum backoff time (when backoff > maximum backoff time) +// +// where |k| is the multiplier, and |c| is the constant factor. +class URLFetcherProtectEntry { + public: + enum EventType { + SEND, // request will be sent out + SUCCESS, // successful response + FAILURE // no response or error + }; + + URLFetcherProtectEntry(); + URLFetcherProtectEntry(int sliding_window_period, int max_send_threshold, + int max_retries, int initial_timeout, + double multiplier, int constant_factor, + int maximum_timeout); + + + virtual ~URLFetcherProtectEntry() { } + + // When a connection event happens, log it to the queue, and recalculate + // the timeout period. It returns the backoff time, in milliseconds, that + // indicates to the sender how long should it wait before sending the request. + // If the request is allowed to be sent immediately, the backoff time is 0. + int64 UpdateBackoff(EventType event_type); + + // Returns the max retries allowed. + int max_retries() const { + return max_retries_; + } + + private: + // When a request comes, calculate the release time for it. + // Returns the backoff time before sending. + base::TimeDelta AntiOverload(); + // Resets backoff when service is ok. + // Returns the backoff time before sending. + base::TimeDelta ResetBackoff(); + // Calculates new backoff when encountering a failure. + // Returns the backoff time before sending. + base::TimeDelta IncreaseBackoff(); + + // Default parameters. Time is in milliseconds. + static const int kDefaultSlidingWindowPeriod; + static const int kDefaultMaxSendThreshold; + static const int kDefaultMaxRetries; + static const int kDefaultInitialTimeout; + static const double kDefaultMultiplier; + static const int kDefaultConstantFactor; + static const int kDefaultMaximumTimeout; + + // time to consider events when checking backoff + int sliding_window_period_; + + // maximum number of requests allowed in sliding window period + int max_send_threshold_; + // maximum retris allowed + int max_retries_; + + // initial timeout on first failure + int initial_timeout_; + // factor by which to multiply on exponential backoff (e.g., 2.0) + double multiplier_; + // constant time term to add to each attempt + int constant_factor_; + // maximum amount of time between requests + int maximum_timeout_; + + // current exponential backoff period + int timeout_period_; + // time that protection is scheduled to end + base::TimeTicks release_time_; + + // Sets up a lock to ensure thread safe. + Lock lock_; + + // A list of the recent send events. We ues them to decide whether + // there are too many requests sent in sliding window. + std::queue<base::TimeTicks> send_log_; + + DISALLOW_COPY_AND_ASSIGN(URLFetcherProtectEntry); +}; + + +// This singleton class is used to manage all protect entries. +// Now we use the host name as service id. +class URLFetcherProtectManager { + public: + ~URLFetcherProtectManager(); + + // Returns the global instance of this class. + static URLFetcherProtectManager* GetInstance(); + + // Registers a new entry in this service. If the entry already exists, + // just returns it. Ownership of the return object remains with the manager. + URLFetcherProtectEntry* Register(const std::string& id); + // Always registers the entry even when it exists; any existing entry for this + // id will be deleted and existing references to it will become invalid. + // Ownership of the return object remains with the manager. + URLFetcherProtectEntry* Register(const std::string& id, + URLFetcherProtectEntry* entry); + + private: + URLFetcherProtectManager() { } + + typedef std::map<const std::string, URLFetcherProtectEntry*> ProtectService; + + static Lock lock_; + static scoped_ptr<URLFetcherProtectManager> protect_manager_; + ProtectService services_; + + DISALLOW_COPY_AND_ASSIGN(URLFetcherProtectManager); +}; + +#endif // CHROME_COMMON_NET_URL_FETCHER_PROTECT_H_ diff --git a/chrome/common/net/url_fetcher_unittest.cc b/chrome/common/net/url_fetcher_unittest.cc new file mode 100644 index 0000000..5e39c2a --- /dev/null +++ b/chrome/common/net/url_fetcher_unittest.cc @@ -0,0 +1,613 @@ +// Copyright (c) 2006-2008 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/message_loop_proxy.h" +#include "base/thread.h" +#include "base/waitable_event.h" +#include "chrome/common/chrome_plugin_lib.h" +#include "chrome/common/net/url_fetcher.h" +#include "chrome/common/net/url_fetcher_protect.h" +#include "chrome/common/net/url_request_context_getter.h" +#include "net/http/http_response_headers.h" +#include "net/test/test_server.h" +#include "net/url_request/url_request_unittest.h" +#include "testing/gtest/include/gtest/gtest.h" + +using base::Time; +using base::TimeDelta; + +// TODO(eroman): Add a regression test for http://crbug.com/40505. + +namespace { + +const wchar_t kDocRoot[] = L"chrome/test/data"; + +class TestURLRequestContextGetter : public URLRequestContextGetter { + public: + explicit TestURLRequestContextGetter( + base::MessageLoopProxy* io_message_loop_proxy) + : io_message_loop_proxy_(io_message_loop_proxy) { + } + virtual URLRequestContext* GetURLRequestContext() { + if (!context_) + context_ = new TestURLRequestContext(); + return context_; + } + virtual scoped_refptr<base::MessageLoopProxy> GetIOMessageLoopProxy() { + return io_message_loop_proxy_; + } + + protected: + scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_; + + private: + ~TestURLRequestContextGetter() {} + + scoped_refptr<URLRequestContext> context_; +}; + +class URLFetcherTest : public testing::Test, public URLFetcher::Delegate { + public: + URLFetcherTest() : fetcher_(NULL) { } + + // Creates a URLFetcher, using the program's main thread to do IO. + virtual void CreateFetcher(const GURL& url); + + // URLFetcher::Delegate + virtual void OnURLFetchComplete(const URLFetcher* source, + const GURL& url, + const URLRequestStatus& status, + int response_code, + const ResponseCookies& cookies, + const std::string& data); + + scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy() { + return io_message_loop_proxy_; + } + + protected: + virtual void SetUp() { + testing::Test::SetUp(); + + io_message_loop_proxy_ = base::MessageLoopProxy::CreateForCurrentThread(); + + // Ensure that any plugin operations done by other tests are cleaned up. + ChromePluginLib::UnloadAllPlugins(); + } + + // URLFetcher is designed to run on the main UI thread, but in our tests + // we assume that the current thread is the IO thread where the URLFetcher + // dispatches its requests to. When we wish to simulate being used from + // a UI thread, we dispatch a worker thread to do so. + MessageLoopForIO io_loop_; + scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_; + + URLFetcher* fetcher_; +}; + +// Version of URLFetcherTest that does a POST instead +class URLFetcherPostTest : public URLFetcherTest { + public: + virtual void CreateFetcher(const GURL& url); + + // URLFetcher::Delegate + virtual void OnURLFetchComplete(const URLFetcher* source, + const GURL& url, + const URLRequestStatus& status, + int response_code, + const ResponseCookies& cookies, + const std::string& data); +}; + +// Version of URLFetcherTest that tests headers. +class URLFetcherHeadersTest : public URLFetcherTest { + public: + // URLFetcher::Delegate + virtual void OnURLFetchComplete(const URLFetcher* source, + const GURL& url, + const URLRequestStatus& status, + int response_code, + const ResponseCookies& cookies, + const std::string& data); +}; + +// Version of URLFetcherTest that tests overload protection. +class URLFetcherProtectTest : public URLFetcherTest { + public: + virtual void CreateFetcher(const GURL& url); + // URLFetcher::Delegate + virtual void OnURLFetchComplete(const URLFetcher* source, + const GURL& url, + const URLRequestStatus& status, + int response_code, + const ResponseCookies& cookies, + const std::string& data); + private: + Time start_time_; +}; + +// Version of URLFetcherTest that tests overload protection, when responses +// passed through. +class URLFetcherProtectTestPassedThrough : public URLFetcherTest { + public: + virtual void CreateFetcher(const GURL& url); + // URLFetcher::Delegate + virtual void OnURLFetchComplete(const URLFetcher* source, + const GURL& url, + const URLRequestStatus& status, + int response_code, + const ResponseCookies& cookies, + const std::string& data); + private: + Time start_time_; +}; + +// Version of URLFetcherTest that tests bad HTTPS requests. +class URLFetcherBadHTTPSTest : public URLFetcherTest { + public: + URLFetcherBadHTTPSTest(); + + // URLFetcher::Delegate + virtual void OnURLFetchComplete(const URLFetcher* source, + const GURL& url, + const URLRequestStatus& status, + int response_code, + const ResponseCookies& cookies, + const std::string& data); + + private: + FilePath cert_dir_; +}; + +// Version of URLFetcherTest that tests request cancellation on shutdown. +class URLFetcherCancelTest : public URLFetcherTest { + public: + virtual void CreateFetcher(const GURL& url); + // URLFetcher::Delegate + virtual void OnURLFetchComplete(const URLFetcher* source, + const GURL& url, + const URLRequestStatus& status, + int response_code, + const ResponseCookies& cookies, + const std::string& data); + + void CancelRequest(); +}; + +// Version of TestURLRequestContext that posts a Quit task to the IO +// thread once it is deleted. +class CancelTestURLRequestContext : public TestURLRequestContext { + virtual ~CancelTestURLRequestContext() { + // The d'tor should execute in the IO thread. Post the quit task to the + // current thread. + MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); + } +}; + +class CancelTestURLRequestContextGetter : public URLRequestContextGetter { + public: + explicit CancelTestURLRequestContextGetter( + base::MessageLoopProxy* io_message_loop_proxy) + : io_message_loop_proxy_(io_message_loop_proxy), + context_created_(false, false) { + } + virtual URLRequestContext* GetURLRequestContext() { + if (!context_) { + context_ = new CancelTestURLRequestContext(); + context_created_.Signal(); + } + return context_; + } + virtual scoped_refptr<base::MessageLoopProxy> GetIOMessageLoopProxy() { + return io_message_loop_proxy_; + } + void WaitForContextCreation() { + context_created_.Wait(); + } + + private: + ~CancelTestURLRequestContextGetter() {} + + scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_; + base::WaitableEvent context_created_; + scoped_refptr<URLRequestContext> context_; +}; + +// Wrapper that lets us call CreateFetcher() on a thread of our choice. We +// could make URLFetcherTest refcounted and use PostTask(FROM_HERE.. ) to call +// CreateFetcher() directly, but the ownership of the URLFetcherTest is a bit +// confusing in that case because GTest doesn't know about the refcounting. +// It's less confusing to just do it this way. +class FetcherWrapperTask : public Task { + public: + FetcherWrapperTask(URLFetcherTest* test, const GURL& url) + : test_(test), url_(url) { } + virtual void Run() { + test_->CreateFetcher(url_); + } + + private: + URLFetcherTest* test_; + GURL url_; +}; + +void URLFetcherTest::CreateFetcher(const GURL& url) { + fetcher_ = new URLFetcher(url, URLFetcher::GET, this); + fetcher_->set_request_context(new TestURLRequestContextGetter( + io_message_loop_proxy())); + fetcher_->Start(); +} + +void URLFetcherTest::OnURLFetchComplete(const URLFetcher* source, + const GURL& url, + const URLRequestStatus& status, + int response_code, + const ResponseCookies& cookies, + const std::string& data) { + EXPECT_TRUE(status.is_success()); + EXPECT_EQ(200, response_code); // HTTP OK + EXPECT_FALSE(data.empty()); + + delete fetcher_; // Have to delete this here and not in the destructor, + // because the destructor won't necessarily run on the + // same thread that CreateFetcher() did. + + io_message_loop_proxy()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); + // If the current message loop is not the IO loop, it will be shut down when + // the main loop returns and this thread subsequently goes out of scope. +} + +void URLFetcherPostTest::CreateFetcher(const GURL& url) { + fetcher_ = new URLFetcher(url, URLFetcher::POST, this); + fetcher_->set_request_context(new TestURLRequestContextGetter( + io_message_loop_proxy())); + fetcher_->set_upload_data("application/x-www-form-urlencoded", + "bobsyeruncle"); + fetcher_->Start(); +} + +void URLFetcherPostTest::OnURLFetchComplete(const URLFetcher* source, + const GURL& url, + const URLRequestStatus& status, + int response_code, + const ResponseCookies& cookies, + const std::string& data) { + EXPECT_EQ(std::string("bobsyeruncle"), data); + URLFetcherTest::OnURLFetchComplete(source, url, status, response_code, + cookies, data); +} + +void URLFetcherHeadersTest::OnURLFetchComplete( + const URLFetcher* source, + const GURL& url, + const URLRequestStatus& status, + int response_code, + const ResponseCookies& cookies, + const std::string& data) { + std::string header; + EXPECT_TRUE(source->response_headers()->GetNormalizedHeader("cache-control", + &header)); + EXPECT_EQ("private", header); + URLFetcherTest::OnURLFetchComplete(source, url, status, response_code, + cookies, data); +} + +void URLFetcherProtectTest::CreateFetcher(const GURL& url) { + fetcher_ = new URLFetcher(url, URLFetcher::GET, this); + fetcher_->set_request_context(new TestURLRequestContextGetter( + io_message_loop_proxy())); + start_time_ = Time::Now(); + fetcher_->Start(); +} + +void URLFetcherProtectTest::OnURLFetchComplete(const URLFetcher* source, + const GURL& url, + const URLRequestStatus& status, + int response_code, + const ResponseCookies& cookies, + const std::string& data) { + const TimeDelta one_second = TimeDelta::FromMilliseconds(1000); + if (response_code >= 500) { + // Now running ServerUnavailable test. + // It takes more than 1 second to finish all 11 requests. + EXPECT_TRUE(Time::Now() - start_time_ >= one_second); + EXPECT_TRUE(status.is_success()); + EXPECT_FALSE(data.empty()); + delete fetcher_; + io_message_loop_proxy()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); + } else { + // Now running Overload test. + static int count = 0; + count++; + if (count < 20) { + fetcher_->Start(); + } else { + // We have already sent 20 requests continuously. And we expect that + // it takes more than 1 second due to the overload pretection settings. + EXPECT_TRUE(Time::Now() - start_time_ >= one_second); + URLFetcherTest::OnURLFetchComplete(source, url, status, response_code, + cookies, data); + } + } +} + +void URLFetcherProtectTestPassedThrough::CreateFetcher(const GURL& url) { + fetcher_ = new URLFetcher(url, URLFetcher::GET, this); + fetcher_->set_request_context(new TestURLRequestContextGetter( + io_message_loop_proxy())); + fetcher_->set_automatcally_retry_on_5xx(false); + start_time_ = Time::Now(); + fetcher_->Start(); +} + +void URLFetcherProtectTestPassedThrough::OnURLFetchComplete( + const URLFetcher* source, + const GURL& url, + const URLRequestStatus& status, + int response_code, + const ResponseCookies& cookies, + const std::string& data) { + const TimeDelta one_minute = TimeDelta::FromMilliseconds(60000); + if (response_code >= 500) { + // Now running ServerUnavailable test. + // It should get here on the first attempt, so almost immediately and + // *not* to attempt to execute all 11 requests (2.5 minutes). + EXPECT_TRUE(Time::Now() - start_time_ < one_minute); + EXPECT_TRUE(status.is_success()); + // Check that suggested back off time is bigger than 0. + EXPECT_GT(fetcher_->backoff_delay().InMicroseconds(), 0); + EXPECT_FALSE(data.empty()); + delete fetcher_; + io_message_loop_proxy()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); + } else { + // We should not get here! + FAIL(); + } +} + + +URLFetcherBadHTTPSTest::URLFetcherBadHTTPSTest() { + PathService::Get(base::DIR_SOURCE_ROOT, &cert_dir_); + cert_dir_ = cert_dir_.AppendASCII("chrome"); + cert_dir_ = cert_dir_.AppendASCII("test"); + cert_dir_ = cert_dir_.AppendASCII("data"); + cert_dir_ = cert_dir_.AppendASCII("ssl"); + cert_dir_ = cert_dir_.AppendASCII("certificates"); +} + +// The "server certificate expired" error should result in automatic +// cancellation of the request by +// URLRequest::Delegate::OnSSLCertificateError. +void URLFetcherBadHTTPSTest::OnURLFetchComplete( + const URLFetcher* source, + const GURL& url, + const URLRequestStatus& status, + int response_code, + const ResponseCookies& cookies, + const std::string& data) { + // This part is different from URLFetcherTest::OnURLFetchComplete + // because this test expects the request to be cancelled. + EXPECT_EQ(URLRequestStatus::CANCELED, status.status()); + EXPECT_EQ(net::ERR_ABORTED, status.os_error()); + EXPECT_EQ(-1, response_code); + EXPECT_TRUE(cookies.empty()); + EXPECT_TRUE(data.empty()); + + // The rest is the same as URLFetcherTest::OnURLFetchComplete. + delete fetcher_; + io_message_loop_proxy()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); +} + +void URLFetcherCancelTest::CreateFetcher(const GURL& url) { + fetcher_ = new URLFetcher(url, URLFetcher::GET, this); + CancelTestURLRequestContextGetter* context_getter = + new CancelTestURLRequestContextGetter(io_message_loop_proxy()); + fetcher_->set_request_context(context_getter); + fetcher_->Start(); + // We need to wait for the creation of the URLRequestContext, since we + // rely on it being destroyed as a signal to end the test. + context_getter->WaitForContextCreation(); + CancelRequest(); +} + +void URLFetcherCancelTest::OnURLFetchComplete(const URLFetcher* source, + const GURL& url, + const URLRequestStatus& status, + int response_code, + const ResponseCookies& cookies, + const std::string& data) { + // We should have cancelled the request before completion. + ADD_FAILURE(); + delete fetcher_; + io_message_loop_proxy()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); +} + +void URLFetcherCancelTest::CancelRequest() { + delete fetcher_; + // The URLFetcher's test context will post a Quit task once it is + // deleted. So if this test simply hangs, it means cancellation + // did not work. +} + +TEST_F(URLFetcherTest, SameThreadsTest) { + // Create the fetcher on the main thread. Since IO will happen on the main + // thread, this will test URLFetcher's ability to do everything on one + // thread. + scoped_refptr<HTTPTestServer> server = + HTTPTestServer::CreateServer(kDocRoot, NULL); + ASSERT_TRUE(NULL != server.get()); + + CreateFetcher(GURL(server->TestServerPage("defaultresponse"))); + + MessageLoop::current()->Run(); +} + +TEST_F(URLFetcherTest, DifferentThreadsTest) { + scoped_refptr<HTTPTestServer> server = + HTTPTestServer::CreateServer(kDocRoot, NULL); + ASSERT_TRUE(NULL != server.get()); + // Create a separate thread that will create the URLFetcher. The current + // (main) thread will do the IO, and when the fetch is complete it will + // terminate the main thread's message loop; then the other thread's + // message loop will be shut down automatically as the thread goes out of + // scope. + base::Thread t("URLFetcher test thread"); + ASSERT_TRUE(t.Start()); + t.message_loop()->PostTask(FROM_HERE, new FetcherWrapperTask(this, + GURL(server->TestServerPage("defaultresponse")))); + + MessageLoop::current()->Run(); +} + +TEST_F(URLFetcherPostTest, Basic) { + scoped_refptr<HTTPTestServer> server = + HTTPTestServer::CreateServer(kDocRoot, NULL); + ASSERT_TRUE(NULL != server.get()); + CreateFetcher(GURL(server->TestServerPage("echo"))); + MessageLoop::current()->Run(); +} + +TEST_F(URLFetcherHeadersTest, Headers) { + scoped_refptr<HTTPTestServer> server = + HTTPTestServer::CreateServer(L"net/data/url_request_unittest", NULL); + ASSERT_TRUE(NULL != server.get()); + CreateFetcher(GURL(server->TestServerPage("files/with-headers.html"))); + MessageLoop::current()->Run(); + // The actual tests are in the URLFetcherHeadersTest fixture. +} + +TEST_F(URLFetcherProtectTest, Overload) { + scoped_refptr<HTTPTestServer> server = + HTTPTestServer::CreateServer(kDocRoot, NULL); + ASSERT_TRUE(NULL != server.get()); + GURL url = GURL(server->TestServerPage("defaultresponse")); + + // Registers an entry for test url. It only allows 3 requests to be sent + // in 200 milliseconds. + URLFetcherProtectManager* manager = URLFetcherProtectManager::GetInstance(); + URLFetcherProtectEntry* entry = + new URLFetcherProtectEntry(200, 3, 11, 1, 2.0, 0, 256); + manager->Register(url.host(), entry); + + CreateFetcher(url); + + MessageLoop::current()->Run(); +} + +TEST_F(URLFetcherProtectTest, ServerUnavailable) { + scoped_refptr<HTTPTestServer> server = + HTTPTestServer::CreateServer(L"chrome/test/data", NULL); + ASSERT_TRUE(NULL != server.get()); + GURL url = GURL(server->TestServerPage("files/server-unavailable.html")); + + // Registers an entry for test url. The backoff time is calculated by: + // new_backoff = 2.0 * old_backoff + 0 + // and maximum backoff time is 256 milliseconds. + // Maximum retries allowed is set to 11. + URLFetcherProtectManager* manager = URLFetcherProtectManager::GetInstance(); + URLFetcherProtectEntry* entry = + new URLFetcherProtectEntry(200, 3, 11, 1, 2.0, 0, 256); + manager->Register(url.host(), entry); + + CreateFetcher(url); + + MessageLoop::current()->Run(); +} + +TEST_F(URLFetcherProtectTestPassedThrough, ServerUnavailablePropagateResponse) { + scoped_refptr<HTTPTestServer> server = + HTTPTestServer::CreateServer(L"chrome/test/data", NULL); + ASSERT_TRUE(NULL != server.get()); + GURL url = GURL(server->TestServerPage("files/server-unavailable.html")); + + // Registers an entry for test url. The backoff time is calculated by: + // new_backoff = 2.0 * old_backoff + 0 + // and maximum backoff time is 256 milliseconds. + // Maximum retries allowed is set to 11. + URLFetcherProtectManager* manager = URLFetcherProtectManager::GetInstance(); + // Total time if *not* for not doing automatic backoff would be 150s. + // In reality it should be "as soon as server responds". + URLFetcherProtectEntry* entry = + new URLFetcherProtectEntry(200, 3, 11, 100, 2.0, 0, 150000); + manager->Register(url.host(), entry); + + CreateFetcher(url); + + MessageLoop::current()->Run(); +} + + +TEST_F(URLFetcherBadHTTPSTest, BadHTTPSTest) { + scoped_refptr<HTTPSTestServer> server = + HTTPSTestServer::CreateExpiredServer(kDocRoot); + ASSERT_TRUE(NULL != server.get()); + + CreateFetcher(GURL(server->TestServerPage("defaultresponse"))); + + MessageLoop::current()->Run(); +} + +TEST_F(URLFetcherCancelTest, ReleasesContext) { + scoped_refptr<HTTPTestServer> server = + HTTPTestServer::CreateServer(L"chrome/test/data", NULL); + ASSERT_TRUE(NULL != server.get()); + GURL url = GURL(server->TestServerPage("files/server-unavailable.html")); + + // Registers an entry for test url. The backoff time is calculated by: + // new_backoff = 2.0 * old_backoff + 0 + // The initial backoff is 2 seconds and maximum backoff is 4 seconds. + // Maximum retries allowed is set to 2. + URLFetcherProtectManager* manager = URLFetcherProtectManager::GetInstance(); + URLFetcherProtectEntry* entry = + new URLFetcherProtectEntry(200, 3, 2, 2000, 2.0, 0, 4000); + manager->Register(url.host(), entry); + + // Create a separate thread that will create the URLFetcher. The current + // (main) thread will do the IO, and when the fetch is complete it will + // terminate the main thread's message loop; then the other thread's + // message loop will be shut down automatically as the thread goes out of + // scope. + base::Thread t("URLFetcher test thread"); + ASSERT_TRUE(t.Start()); + t.message_loop()->PostTask(FROM_HERE, new FetcherWrapperTask(this, url)); + + MessageLoop::current()->Run(); +} + +TEST_F(URLFetcherCancelTest, CancelWhileDelayedStartTaskPending) { + scoped_refptr<HTTPTestServer> server = + HTTPTestServer::CreateServer(L"chrome/test/data", NULL); + ASSERT_TRUE(NULL != server.get()); + GURL url = GURL(server->TestServerPage("files/server-unavailable.html")); + + // Register an entry for test url. + // + // Ideally we would mock URLFetcherProtectEntry to return XXX seconds + // in response to entry->UpdateBackoff(SEND). + // + // Unfortunately this function is time sensitive, so we fudge some numbers + // to make it at least somewhat likely to have a non-zero deferred + // delay when running. + // + // Using a sliding window of 2 seconds, and max of 1 request, under a fast + // run we expect to have a 4 second delay when posting the Start task. + URLFetcherProtectManager* manager = URLFetcherProtectManager::GetInstance(); + URLFetcherProtectEntry* entry = + new URLFetcherProtectEntry(2000, 1, 2, 2000, 2.0, 0, 4000); + EXPECT_EQ(0, entry->UpdateBackoff(URLFetcherProtectEntry::SEND)); + entry->UpdateBackoff(URLFetcherProtectEntry::SEND); // Returns about 2000. + manager->Register(url.host(), entry); + + // The next request we try to send will be delayed by ~4 seconds. + // The slower the test runs, the less the delay will be (since it takes the + // time difference from now). + + base::Thread t("URLFetcher test thread"); + ASSERT_TRUE(t.Start()); + t.message_loop()->PostTask(FROM_HERE, new FetcherWrapperTask(this, url)); + + MessageLoop::current()->Run(); +} + +} // namespace. diff --git a/chrome/common/net/url_request_context_getter.cc b/chrome/common/net/url_request_context_getter.cc new file mode 100644 index 0000000..e58b794 --- /dev/null +++ b/chrome/common/net/url_request_context_getter.cc @@ -0,0 +1,27 @@ +// Copyright (c) 2009 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/message_loop_proxy.h" +#include "chrome/common/net/url_request_context_getter.h" +#include "net/url_request/url_request_context.h" + +net::CookieStore* URLRequestContextGetter::GetCookieStore() { + return GetURLRequestContext()->cookie_store(); +} + +void URLRequestContextGetter::OnDestruct() { + scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy = + GetIOMessageLoopProxy(); + DCHECK(io_message_loop_proxy); + if (io_message_loop_proxy) { + if (io_message_loop_proxy->BelongsToCurrentThread()) { + delete this; + } else { + io_message_loop_proxy->DeleteSoon(FROM_HERE, this); + } + } + // If no IO message loop proxy was available, we will just leak memory. + // This is also true if the IO thread is gone. +} + diff --git a/chrome/common/net/url_request_context_getter.h b/chrome/common/net/url_request_context_getter.h new file mode 100644 index 0000000..dcc77b3 --- /dev/null +++ b/chrome/common/net/url_request_context_getter.h @@ -0,0 +1,55 @@ +// Copyright (c) 2009 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 CHROME_COMMON_NET_URL_REQUEST_CONTEXT_GETTER_H_ +#define CHROME_COMMON_NET_URL_REQUEST_CONTEXT_GETTER_H_ + +#include "base/ref_counted.h" +#include "base/task.h" + +namespace base { +class MessageLoopProxy; +} + +namespace net { +class CookieStore; +} + +class URLRequestContext; +struct URLRequestContextGetterTraits; + +// Interface for retrieving an URLRequestContext. +class URLRequestContextGetter + : public base::RefCountedThreadSafe<URLRequestContextGetter, + URLRequestContextGetterTraits> { + public: + virtual URLRequestContext* GetURLRequestContext() = 0; + + // Defaults to GetURLRequestContext()->cookie_store(), but + // implementations can override it. + virtual net::CookieStore* GetCookieStore(); + // Returns a MessageLoopProxy corresponding to the thread on which the + // request IO happens (the thread on which the returned URLRequestContext + // may be used). + virtual scoped_refptr<base::MessageLoopProxy> GetIOMessageLoopProxy() = 0; + + protected: + friend class DeleteTask<URLRequestContextGetter>; + friend struct URLRequestContextGetterTraits; + + virtual ~URLRequestContextGetter() {} + private: + // OnDestruct is meant to ensure deletion on the thread on which the request + // IO happens. + void OnDestruct(); +}; + +struct URLRequestContextGetterTraits { + static void Destruct(URLRequestContextGetter* context_getter) { + context_getter->OnDestruct(); + } +}; + +#endif // CHROME_COMMON_NET_URL_REQUEST_CONTEXT_GETTER_H_ + diff --git a/chrome/common/net/url_request_intercept_job.cc b/chrome/common/net/url_request_intercept_job.cc new file mode 100644 index 0000000..ed68fcd --- /dev/null +++ b/chrome/common/net/url_request_intercept_job.cc @@ -0,0 +1,226 @@ +// Copyright (c) 2006-2008 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 job type handles Chrome plugin network interception. When a plugin +// wants to intercept a request, a job of this type is created. The intercept +// job communicates with the plugin to retrieve the response headers and data. + +#include "chrome/common/net/url_request_intercept_job.h" + +#include "base/message_loop.h" +#include "base/string_util.h" +#include "chrome/common/chrome_plugin_lib.h" +#include "chrome/common/notification_service.h" +#include "net/base/io_buffer.h" +#include "net/base/net_errors.h" +#include "net/http/http_response_headers.h" +#include "net/url_request/url_request.h" + +using base::Time; +using base::TimeDelta; + +// +// URLRequestInterceptJob +// + +URLRequestInterceptJob::URLRequestInterceptJob(URLRequest* request, + ChromePluginLib* plugin, + ScopableCPRequest* cprequest) + : URLRequestJob(request), + cprequest_(cprequest), + plugin_(plugin), + read_buffer_(NULL) { + cprequest_->data = this; // see FromCPRequest(). + + registrar_.Add(this, NotificationType::CHROME_PLUGIN_UNLOADED, + Source<ChromePluginLib>(plugin_)); +} + +URLRequestInterceptJob::~URLRequestInterceptJob() { + if (plugin_) { + plugin_->functions().request_funcs->end_request(cprequest_.get(), + CPERR_SUCCESS); + } +} + +void URLRequestInterceptJob::DetachPlugin() { + registrar_.RemoveAll(); + plugin_ = NULL; +} + +void URLRequestInterceptJob::Start() { + // Start reading asynchronously so that all error reporting and data + // callbacks happen as they would for network requests. + MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( + this, &URLRequestInterceptJob::StartAsync)); +} + +void URLRequestInterceptJob::Kill() { + if (plugin_) { + plugin_->functions().request_funcs->end_request(cprequest_.get(), + CPERR_CANCELLED); + DetachPlugin(); + } + URLRequestJob::Kill(); +} + +bool URLRequestInterceptJob::ReadRawData(net::IOBuffer* dest, int dest_size, + int* bytes_read) { + DCHECK_NE(dest_size, 0); + DCHECK(bytes_read); + + if (!plugin_) + return false; + + int rv = plugin_->functions().request_funcs->read(cprequest_.get(), + dest->data(), dest_size); + if (rv >= 0) { + *bytes_read = rv; + return true; + } + + if (rv == CPERR_IO_PENDING) { + read_buffer_ = dest; + read_buffer_size_ = dest_size; + SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0)); + } else { + // TODO(mpcomplete): better error code + NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, net::ERR_FAILED)); + } + + return false; +} + +bool URLRequestInterceptJob::GetMimeType(std::string* mime_type) const { + return request_->response_headers()->GetMimeType(mime_type); +} + +bool URLRequestInterceptJob::GetCharset(std::string* charset) { + return request_->response_headers()->GetCharset(charset); +} + +bool URLRequestInterceptJob::GetContentEncodings( + std::vector<Filter::FilterType>* encoding_types) { + DCHECK(encoding_types->empty()); + if (!request_->response_headers()) + return false; + + std::string encoding_type; + void* iter = NULL; + while (request_->response_headers()->EnumerateHeader( + &iter, "Content-Encoding", &encoding_type)) { + encoding_types->push_back(Filter::ConvertEncodingToType(encoding_type)); + } + + // Even if encoding types are empty, there is a chance that we need to add + // some decoding, as some proxies strip encoding completely. In such cases, + // we may need to add (for example) SDCH filtering (when the context suggests + // it is appropriate). + Filter::FixupEncodingTypes(*this, encoding_types); + return !encoding_types->empty(); +} + +void URLRequestInterceptJob::GetResponseInfo(net::HttpResponseInfo* info) { + if (!plugin_) + return; + + std::string raw_headers; + int size = plugin_->functions().request_funcs->get_response_info( + cprequest_.get(), CPRESPONSEINFO_HTTP_RAW_HEADERS, NULL, 0); + int rv = size < 0 ? size : + plugin_->functions().request_funcs->get_response_info( + cprequest_.get(), CPRESPONSEINFO_HTTP_RAW_HEADERS, + WriteInto(&raw_headers, size+1), size); + if (rv != CPERR_SUCCESS) { + // TODO(mpcomplete): what should we do here? + raw_headers = "HTTP/1.1 404 Not Found" + '\0'; + } + + info->headers = new net::HttpResponseHeaders(raw_headers); + + if (request_->url().SchemeIsSecure()) { + // Make up a fake certificate for intercepted data since we don't have + // access to the real SSL info. + // TODO(mpcomplete): we should probably have the interception API transmit + // the SSL info, but the only consumer of this API (Gears) doesn't keep that + // around. We should change that. + const char* kCertIssuer = "Chrome Internal"; + const int kLifetimeDays = 100; + + DLOG(WARNING) << "Issuing a fake SSL certificate for interception of URL " + << request_->url(); + + info->ssl_info.cert = + new net::X509Certificate(request_->url().GetWithEmptyPath().spec(), + kCertIssuer, + Time::Now(), + Time::Now() + + TimeDelta::FromDays(kLifetimeDays)); + info->ssl_info.cert_status = 0; + info->ssl_info.security_bits = 0; + } +} + +int URLRequestInterceptJob::GetResponseCode() const { + if (!plugin_) + return -1; + + int status = 200; + plugin_->functions().request_funcs->get_response_info( + cprequest_.get(), CPRESPONSEINFO_HTTP_STATUS, &status, sizeof(status)); + + return status; +} + +bool URLRequestInterceptJob::IsRedirectResponse(GURL* location, + int* http_status_code) { + if (!request_->response_headers()) + return false; + + std::string value; + if (!request_->response_headers()->IsRedirect(&value)) + return false; + + *location = request_->url().Resolve(value); + *http_status_code = request_->response_headers()->response_code(); + return true; +} + +void URLRequestInterceptJob::StartAsync() { + // We may have been orphaned... + if (!request_ || !plugin_) + return; + + int rv = plugin_->functions().request_funcs->start_request(cprequest_.get()); + if (rv != CPERR_IO_PENDING) + OnStartCompleted(rv); +} + +void URLRequestInterceptJob::OnStartCompleted(int result) { + if (result != CPERR_SUCCESS) { + NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, + net::ERR_CONNECTION_FAILED)); + return; + } + + NotifyHeadersComplete(); +} + +void URLRequestInterceptJob::OnReadCompleted(int bytes_read) { + if (bytes_read < 0) { + NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, net::ERR_FAILED)); + return; + } + + SetStatus(URLRequestStatus()); // clear the async flag + NotifyReadComplete(bytes_read); +} + +void URLRequestInterceptJob::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + DCHECK(type == NotificationType::CHROME_PLUGIN_UNLOADED); + DCHECK(plugin_ == Source<ChromePluginLib>(source).ptr()); + DetachPlugin(); +} diff --git a/chrome/common/net/url_request_intercept_job.h b/chrome/common/net/url_request_intercept_job.h new file mode 100644 index 0000000..3b7058b --- /dev/null +++ b/chrome/common/net/url_request_intercept_job.h @@ -0,0 +1,67 @@ +// Copyright (c) 2006-2008 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 CHROME_COMMON_NET_URL_REQUEST_INTERCEPT_JOB_H_ +#define CHROME_COMMON_NET_URL_REQUEST_INTERCEPT_JOB_H_ + +#include <string> + +#include "base/scoped_ptr.h" +#include "net/url_request/url_request_job.h" +#include "chrome/common/chrome_plugin_api.h" +#include "chrome/common/chrome_plugin_util.h" +#include "chrome/common/notification_registrar.h" + +class ChromePluginLib; +class URLRequest; + +// A request job that handles network requests intercepted by a Chrome plugin. +class URLRequestInterceptJob + : public URLRequestJob, public NotificationObserver { + public: + static URLRequestInterceptJob* FromCPRequest(CPRequest* request) { + return ScopableCPRequest::GetData<URLRequestInterceptJob*>(request); + } + + URLRequestInterceptJob(URLRequest* request, ChromePluginLib* plugin, + ScopableCPRequest* cprequest); + virtual ~URLRequestInterceptJob(); + + // Plugin callbacks. + void OnStartCompleted(int result); + void OnReadCompleted(int bytes_read); + + // URLRequestJob + virtual void Start(); + virtual void Kill(); + virtual bool GetMimeType(std::string* mime_type) const; + virtual bool GetCharset(std::string* charset); + virtual void GetResponseInfo(net::HttpResponseInfo* info); + virtual int GetResponseCode() const; + virtual bool GetContentEncodings( + std::vector<Filter::FilterType>* encoding_types); + virtual bool IsRedirectResponse(GURL* location, int* http_status_code); + + // NotificationObserver + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + protected: + virtual bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read); + + private: + void StartAsync(); + void DetachPlugin(); + + NotificationRegistrar registrar_; + scoped_ptr<ScopableCPRequest> cprequest_; + ChromePluginLib* plugin_; + net::IOBuffer* read_buffer_; + int read_buffer_size_; + + DISALLOW_COPY_AND_ASSIGN(URLRequestInterceptJob); +}; + +#endif // CHROME_COMMON_NET_URL_REQUEST_INTERCEPT_JOB_H_ diff --git a/chrome/common/notification_details.cc b/chrome/common/notification_details.cc new file mode 100644 index 0000000..4455faa --- /dev/null +++ b/chrome/common/notification_details.cc @@ -0,0 +1,18 @@ +// Copyright (c) 2010 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 "chrome/common/notification_details.h" + +NotificationDetails::NotificationDetails() : ptr_(NULL) { +} + +NotificationDetails::NotificationDetails(const NotificationDetails& other) + : ptr_(other.ptr_) { +} + +NotificationDetails::NotificationDetails(const void* ptr) : ptr_(ptr) { +} + +NotificationDetails::~NotificationDetails() { +} diff --git a/chrome/common/notification_details.h b/chrome/common/notification_details.h new file mode 100644 index 0000000..92c1906 --- /dev/null +++ b/chrome/common/notification_details.h @@ -0,0 +1,56 @@ +// Copyright (c) 2006-2008 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 defines the type used to provide details for NotificationService +// notifications. + +#ifndef CHROME_COMMON_NOTIFICATION_DETAILS_H__ +#define CHROME_COMMON_NOTIFICATION_DETAILS_H__ + +#include "base/basictypes.h" + +// Do not declare a NotificationDetails directly--use either +// "Details<detailsclassname>(detailsclasspointer)" or +// NotificationService::NoDetails(). +class NotificationDetails { + public: + NotificationDetails(); + NotificationDetails(const NotificationDetails& other); + ~NotificationDetails(); + + // NotificationDetails can be used as the index for a map; this method + // returns the pointer to the current details as an identifier, for use as a + // map index. + uintptr_t map_key() const { return reinterpret_cast<uintptr_t>(ptr_); } + + bool operator!=(const NotificationDetails& other) const { + return ptr_ != other.ptr_; + } + + bool operator==(const NotificationDetails& other) const { + return ptr_ == other.ptr_; + } + + protected: + explicit NotificationDetails(const void* ptr); + + // Declaring this const allows Details<T> to be used with both T = Foo and + // T = const Foo. + const void* ptr_; +}; + +template <class T> +class Details : public NotificationDetails { + public: + // TODO(erg): Our code hard relies on implicit conversion + Details(T* ptr) : NotificationDetails(ptr) {} // NOLINT + Details(const NotificationDetails& other) // NOLINT + : NotificationDetails(other) {} + + T* operator->() const { return ptr(); } + // The casts here allow this to compile with both T = Foo and T = const Foo. + T* ptr() const { return static_cast<T*>(const_cast<void*>(ptr_)); } +}; + +#endif // CHROME_COMMON_NOTIFICATION_DETAILS_H__ diff --git a/chrome/common/notification_observer.h b/chrome/common/notification_observer.h new file mode 100644 index 0000000..8ad4d4a --- /dev/null +++ b/chrome/common/notification_observer.h @@ -0,0 +1,24 @@ +// Copyright (c) 2009 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 CHROME_COMMON_NOTIFICATION_OBSERVER_H_ +#define CHROME_COMMON_NOTIFICATION_OBSERVER_H_ + +class NotificationDetails; +class NotificationSource; +class NotificationType; + +// This is the base class for notification observers. When a matching +// notification is posted to the notification service, Observe is called. +class NotificationObserver { + public: + NotificationObserver(); + virtual ~NotificationObserver(); + + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) = 0; +}; + +#endif // CHROME_COMMON_NOTIFICATION_OBSERVER_H_ diff --git a/chrome/common/notification_observer_mock.h b/chrome/common/notification_observer_mock.h new file mode 100644 index 0000000..9eeb665 --- /dev/null +++ b/chrome/common/notification_observer_mock.h @@ -0,0 +1,24 @@ +// Copyright (c) 2009 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 CHROME_COMMON_NOTIFICATION_OBSERVER_MOCK_H_ +#define CHROME_COMMON_NOTIFICATION_OBSERVER_MOCK_H_ + +#include "chrome/common/notification_details.h" +#include "chrome/common/notification_observer.h" +#include "chrome/common/notification_source.h" +#include "chrome/common/notification_type.h" +#include "testing/gmock/include/gmock/gmock.h" + +class NotificationObserverMock : public NotificationObserver { + public: + NotificationObserverMock() {} + virtual ~NotificationObserverMock() {} + + MOCK_METHOD3(Observe, void(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details)); +}; + +#endif // CHROME_COMMON_NOTIFICATION_OBSERVER_MOCK_H_ diff --git a/chrome/common/notification_registrar.cc b/chrome/common/notification_registrar.cc new file mode 100644 index 0000000..7ec5cda --- /dev/null +++ b/chrome/common/notification_registrar.cc @@ -0,0 +1,108 @@ +// Copyright (c) 2010 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 "chrome/common/notification_registrar.h" + +#include <algorithm> + +#include "base/logging.h" +#include "chrome/common/notification_service.h" +#include "base/platform_thread.h" + +namespace { + +void CheckCalledOnValidThread(PlatformThreadId thread_id) { + PlatformThreadId current_thread_id = PlatformThread::CurrentId(); + CHECK(current_thread_id == thread_id) << "called on invalid thread: " + << thread_id << " vs. " + << current_thread_id; +} + +} // namespace + +struct NotificationRegistrar::Record { + bool operator==(const Record& other) const; + + NotificationObserver* observer; + NotificationType type; + NotificationSource source; + PlatformThreadId thread_id; +}; + +bool NotificationRegistrar::Record::operator==(const Record& other) const { + return observer == other.observer && + type == other.type && + source == other.source; + // thread_id is for debugging purpose and thus not compared here. +} + +NotificationRegistrar::NotificationRegistrar() { +} + +NotificationRegistrar::~NotificationRegistrar() { + RemoveAll(); +} + +void NotificationRegistrar::Add(NotificationObserver* observer, + NotificationType type, + const NotificationSource& source) { + Record record = { observer, type, source, PlatformThread::CurrentId() }; + + DCHECK(std::find(registered_.begin(), registered_.end(), record) == + registered_.end()) << "Duplicate registration."; + registered_.push_back(record); + + NotificationService::current()->AddObserver(observer, type, source); +} + +void NotificationRegistrar::Remove(NotificationObserver* observer, + NotificationType type, + const NotificationSource& source) { + Record record = { observer, type, source }; + RecordVector::iterator found = std::find( + registered_.begin(), registered_.end(), record); + if (found == registered_.end()) { + NOTREACHED() << "Trying to remove unregistered observer of type " << + type.value << " from list of size " << registered_.size() << "."; + return; + } + CheckCalledOnValidThread(found->thread_id); + + registered_.erase(found); + + // This can be NULL if our owner outlives the NotificationService, e.g. if our + // owner is a Singleton. + NotificationService* service = NotificationService::current(); + if (service) + service->RemoveObserver(observer, type, source); +} + +void NotificationRegistrar::RemoveAll() { + // Early-exit if no registrations, to avoid calling + // NotificationService::current. If we've constructed an object with a + // NotificationRegistrar member, but haven't actually used the notification + // service, and we reach prgram exit, then calling current() below could try + // to initialize the service's lazy TLS pointer during exit, which throws + // wrenches at things. + if (registered_.empty()) + return; + + + // This can be NULL if our owner outlives the NotificationService, e.g. if our + // owner is a Singleton. + NotificationService* service = NotificationService::current(); + if (service) { + for (size_t i = 0; i < registered_.size(); i++) { + CheckCalledOnValidThread(registered_[i].thread_id); + service->RemoveObserver(registered_[i].observer, + registered_[i].type, + registered_[i].source); + } + } + registered_.clear(); +} + +bool NotificationRegistrar::IsEmpty() const { + return registered_.empty(); +} diff --git a/chrome/common/notification_registrar.h b/chrome/common/notification_registrar.h new file mode 100644 index 0000000..f8dd743 --- /dev/null +++ b/chrome/common/notification_registrar.h @@ -0,0 +1,56 @@ +// Copyright (c) 2010 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 CHROME_COMMON_NOTIFICATION_REGISTRAR_H_ +#define CHROME_COMMON_NOTIFICATION_REGISTRAR_H_ + +#include <vector> + +#include "base/basictypes.h" +#include "chrome/common/notification_observer.h" + +// Aids in registering for notifications and ensures that all registered +// notifications are unregistered when the class is destroyed. +// +// The intended use is that you make a NotificationRegistrar member in your +// class and use it to register your notifications instead of going through the +// notification service directly. It will automatically unregister them for +// you. +class NotificationRegistrar { + public: + // This class must not be derived from (we don't have a virtual destructor so + // it won't work). Instead, use it as a member in your class. + NotificationRegistrar(); + ~NotificationRegistrar(); + + // Wrappers around NotificationService::[Add|Remove]Observer. + void Add(NotificationObserver* observer, + NotificationType type, + const NotificationSource& source); + void Remove(NotificationObserver* observer, + NotificationType type, + const NotificationSource& source); + + // Unregisters all notifications. + void RemoveAll(); + + // Returns true if no notifications are registered. + bool IsEmpty() const; + + private: + struct Record; + + // We keep registered notifications in a simple vector. This means we'll do + // brute-force searches when removing them individually, but individual + // removal is uncommon, and there will typically only be a couple of + // notifications anyway. + typedef std::vector<Record> RecordVector; + + // Lists all notifications we're currently registered for. + RecordVector registered_; + + DISALLOW_COPY_AND_ASSIGN(NotificationRegistrar); +}; + +#endif // CHROME_COMMON_NOTIFICATION_REGISTRAR_H_ diff --git a/chrome/common/notification_service.cc b/chrome/common/notification_service.cc new file mode 100644 index 0000000..e127ccf --- /dev/null +++ b/chrome/common/notification_service.cc @@ -0,0 +1,152 @@ +// Copyright (c) 2006-2008 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 "chrome/common/notification_service.h" + +#include "base/lazy_instance.h" +#include "base/thread_local.h" + +static base::LazyInstance<base::ThreadLocalPointer<NotificationService> > + lazy_tls_ptr(base::LINKER_INITIALIZED); + +// static +NotificationService* NotificationService::current() { + return lazy_tls_ptr.Pointer()->Get(); +} + +// static +bool NotificationService::HasKey(const NotificationSourceMap& map, + const NotificationSource& source) { + return map.find(source.map_key()) != map.end(); +} + +NotificationService::NotificationService() { + DCHECK(current() == NULL); +#ifndef NDEBUG + memset(observer_counts_, 0, sizeof(observer_counts_)); +#endif + + lazy_tls_ptr.Pointer()->Set(this); +} + +void NotificationService::AddObserver(NotificationObserver* observer, + NotificationType type, + const NotificationSource& source) { + DCHECK(type.value < NotificationType::NOTIFICATION_TYPE_COUNT); + + // We have gotten some crashes where the observer pointer is NULL. The problem + // is that this happens when we actually execute a notification, so have no + // way of knowing who the bad observer was. We want to know when this happens + // in release mode so we know what code to blame the crash on (since this is + // guaranteed to crash later). + CHECK(observer); + + NotificationObserverList* observer_list; + if (HasKey(observers_[type.value], source)) { + observer_list = observers_[type.value][source.map_key()]; + } else { + observer_list = new NotificationObserverList; + observers_[type.value][source.map_key()] = observer_list; + } + + observer_list->AddObserver(observer); +#ifndef NDEBUG + ++observer_counts_[type.value]; +#endif +} + +void NotificationService::RemoveObserver(NotificationObserver* observer, + NotificationType type, + const NotificationSource& source) { + DCHECK(type.value < NotificationType::NOTIFICATION_TYPE_COUNT); + + // This is a very serious bug. An object is most likely being deleted on + // the wrong thread, and as a result another thread's NotificationService + // has its deleted pointer in its map. A garbge object will be called in the + // future. + // NOTE: when this check shows crashes, use ChromeThread::DeleteOnIOThread or + // other variants as the trait on the object. + CHECK(HasKey(observers_[type.value], source)); + + NotificationObserverList* observer_list = + observers_[type.value][source.map_key()]; + if (observer_list) { + observer_list->RemoveObserver(observer); +#ifndef NDEBUG + --observer_counts_[type.value]; +#endif + } + + // TODO(jhughes): Remove observer list from map if empty? +} + +void NotificationService::Notify(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + DCHECK(type.value > NotificationType::ALL) << + "Allowed for observing, but not posting."; + DCHECK(type.value < NotificationType::NOTIFICATION_TYPE_COUNT); + + // There's no particular reason for the order in which the different + // classes of observers get notified here. + + // Notify observers of all types and all sources + if (HasKey(observers_[NotificationType::ALL], AllSources()) && + source != AllSources()) { + FOR_EACH_OBSERVER(NotificationObserver, + *observers_[NotificationType::ALL][AllSources().map_key()], + Observe(type, source, details)); + } + + // Notify observers of all types and the given source + if (HasKey(observers_[NotificationType::ALL], source)) { + FOR_EACH_OBSERVER(NotificationObserver, + *observers_[NotificationType::ALL][source.map_key()], + Observe(type, source, details)); + } + + // Notify observers of the given type and all sources + if (HasKey(observers_[type.value], AllSources()) && + source != AllSources()) { + FOR_EACH_OBSERVER(NotificationObserver, + *observers_[type.value][AllSources().map_key()], + Observe(type, source, details)); + } + + // Notify observers of the given type and the given source + if (HasKey(observers_[type.value], source)) { + FOR_EACH_OBSERVER(NotificationObserver, + *observers_[type.value][source.map_key()], + Observe(type, source, details)); + } +} + + +NotificationService::~NotificationService() { + lazy_tls_ptr.Pointer()->Set(NULL); + +#ifndef NDEBUG + for (int i = 0; i < NotificationType::NOTIFICATION_TYPE_COUNT; i++) { + if (observer_counts_[i] > 0) { + // This may not be completely fixable -- see + // http://code.google.com/p/chromium/issues/detail?id=11010 . + // But any new leaks should be fixed. + LOG(INFO) << observer_counts_[i] << " notification observer(s) leaked" + << " of notification type " << i; + } + } +#endif + + for (int i = 0; i < NotificationType::NOTIFICATION_TYPE_COUNT; i++) { + NotificationSourceMap omap = observers_[i]; + for (NotificationSourceMap::iterator it = omap.begin(); + it != omap.end(); ++it) { + delete it->second; + } + } +} + +NotificationObserver::NotificationObserver() {} + +NotificationObserver::~NotificationObserver() {} diff --git a/chrome/common/notification_service.h b/chrome/common/notification_service.h new file mode 100644 index 0000000..fefc09c --- /dev/null +++ b/chrome/common/notification_service.h @@ -0,0 +1,108 @@ +// Copyright (c) 2006-2008 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 describes a central switchboard for notifications that might +// happen in various parts of the application, and allows users to register +// observers for various classes of events that they're interested in. + +#ifndef CHROME_COMMON_NOTIFICATION_SERVICE_H_ +#define CHROME_COMMON_NOTIFICATION_SERVICE_H_ + +#include <map> + +#include "base/observer_list.h" +#include "chrome/common/notification_details.h" +#include "chrome/common/notification_observer.h" +#include "chrome/common/notification_source.h" +#include "chrome/common/notification_type.h" + +class NotificationObserver; + +class NotificationService { + public: + // Returns the NotificationService object for the current thread, or NULL if + // none. + static NotificationService* current(); + + // Normally instantiated when the thread is created. Not all threads have + // a NotificationService. Only one instance should be created per thread. + NotificationService(); + ~NotificationService(); + + // Synchronously posts a notification to all interested observers. + // Source is a reference to a NotificationSource object representing + // the object originating the notification (can be + // NotificationService::AllSources(), in which case + // only observers interested in all sources will be notified). + // Details is a reference to an object containing additional data about + // the notification. If no additional data is needed, NoDetails() is used. + // There is no particular order in which the observers will be notified. + void Notify(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + // Returns a NotificationSource that represents all notification sources + // (for the purpose of registering an observer for events from all sources). + static Source<void> AllSources() { return Source<void>(NULL); } + + // Returns a NotificationDetails object that represents a lack of details + // associated with a notification. (This is effectively a null pointer.) + static Details<void> NoDetails() { return Details<void>(NULL); } + + private: + friend class NotificationRegistrar; + + typedef ObserverList<NotificationObserver> NotificationObserverList; + typedef std::map<uintptr_t, NotificationObserverList*> NotificationSourceMap; + + // Convenience function to determine whether a source has a + // NotificationObserverList in the given map; + static bool HasKey(const NotificationSourceMap& map, + const NotificationSource& source); + + // NOTE: Rather than using this directly, you should use a + // NotificationRegistrar. + // + // Registers a NotificationObserver to be called whenever a matching + // notification is posted. Observer is a pointer to an object subclassing + // NotificationObserver to be notified when an event matching the other two + // parameters is posted to this service. Type is the type of events to + // be notified about (or NOTIFY_ALL to receive events of all types). + // Source is a NotificationSource object (created using + // "Source<classname>(pointer)"), if this observer only wants to + // receive events from that object, or NotificationService::AllSources() + // to receive events from all sources. + // + // A given observer can be registered only once for each combination of + // type and source. If the same object is registered more than once, + // it must be removed for each of those combinations of type and source later. + // + // The caller retains ownership of the object pointed to by observer. + void AddObserver(NotificationObserver* observer, + NotificationType type, const NotificationSource& source); + + // NOTE: Rather than using this directly, you should use a + // NotificationRegistrar. + // + // Removes the object pointed to by observer from receiving notifications + // that match type and source. If no object matching the parameters is + // currently registered, this method is a no-op. + void RemoveObserver(NotificationObserver* observer, + NotificationType type, const NotificationSource& source); + + // Keeps track of the observers for each type of notification. + // Until we get a prohibitively large number of notification types, + // a simple array is probably the fastest way to dispatch. + NotificationSourceMap observers_[NotificationType::NOTIFICATION_TYPE_COUNT]; + +#ifndef NDEBUG + // Used to check to see that AddObserver and RemoveObserver calls are + // balanced. + int observer_counts_[NotificationType::NOTIFICATION_TYPE_COUNT]; +#endif + + DISALLOW_COPY_AND_ASSIGN(NotificationService); +}; + +#endif // CHROME_COMMON_NOTIFICATION_SERVICE_H_ diff --git a/chrome/common/notification_service_unittest.cc b/chrome/common/notification_service_unittest.cc new file mode 100644 index 0000000..d65f6e5 --- /dev/null +++ b/chrome/common/notification_service_unittest.cc @@ -0,0 +1,163 @@ +// Copyright (c) 2006-2008 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 "chrome/common/notification_registrar.h" +#include "chrome/common/notification_service.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +// Bogus class to act as a NotificationSource for the messages. +class TestSource {}; + +class TestObserver : public NotificationObserver { +public: + TestObserver() : notification_count_(0) {} + + int notification_count() { return notification_count_; } + + void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + ++notification_count_; + } + +private: + int notification_count_; +}; + +} // namespace + + +class NotificationServiceTest : public testing::Test { + protected: + NotificationRegistrar registrar_; +}; + +TEST_F(NotificationServiceTest, Basic) { + TestSource test_source; + TestSource other_source; + + // Check the equality operators defined for NotificationSource + EXPECT_TRUE( + Source<TestSource>(&test_source) == Source<TestSource>(&test_source)); + EXPECT_TRUE( + Source<TestSource>(&test_source) != Source<TestSource>(&other_source)); + + TestObserver all_types_all_sources; + TestObserver idle_all_sources; + TestObserver all_types_test_source; + TestObserver idle_test_source; + + // Make sure it doesn't freak out when there are no observers. + NotificationService* service = NotificationService::current(); + service->Notify(NotificationType::IDLE, + Source<TestSource>(&test_source), + NotificationService::NoDetails()); + + registrar_.Add(&all_types_all_sources, NotificationType::ALL, + NotificationService::AllSources()); + registrar_.Add(&idle_all_sources, NotificationType::IDLE, + NotificationService::AllSources()); + registrar_.Add(&all_types_test_source, NotificationType::ALL, + Source<TestSource>(&test_source)); + registrar_.Add(&idle_test_source, NotificationType::IDLE, + Source<TestSource>(&test_source)); + + EXPECT_EQ(0, all_types_all_sources.notification_count()); + EXPECT_EQ(0, idle_all_sources.notification_count()); + EXPECT_EQ(0, all_types_test_source.notification_count()); + EXPECT_EQ(0, idle_test_source.notification_count()); + + service->Notify(NotificationType::IDLE, + Source<TestSource>(&test_source), + NotificationService::NoDetails()); + + EXPECT_EQ(1, all_types_all_sources.notification_count()); + EXPECT_EQ(1, idle_all_sources.notification_count()); + EXPECT_EQ(1, all_types_test_source.notification_count()); + EXPECT_EQ(1, idle_test_source.notification_count()); + + service->Notify(NotificationType::BUSY, + Source<TestSource>(&test_source), + NotificationService::NoDetails()); + + EXPECT_EQ(2, all_types_all_sources.notification_count()); + EXPECT_EQ(1, idle_all_sources.notification_count()); + EXPECT_EQ(2, all_types_test_source.notification_count()); + EXPECT_EQ(1, idle_test_source.notification_count()); + + service->Notify(NotificationType::IDLE, + Source<TestSource>(&other_source), + NotificationService::NoDetails()); + + EXPECT_EQ(3, all_types_all_sources.notification_count()); + EXPECT_EQ(2, idle_all_sources.notification_count()); + EXPECT_EQ(2, all_types_test_source.notification_count()); + EXPECT_EQ(1, idle_test_source.notification_count()); + + service->Notify(NotificationType::BUSY, + Source<TestSource>(&other_source), + NotificationService::NoDetails()); + + EXPECT_EQ(4, all_types_all_sources.notification_count()); + EXPECT_EQ(2, idle_all_sources.notification_count()); + EXPECT_EQ(2, all_types_test_source.notification_count()); + EXPECT_EQ(1, idle_test_source.notification_count()); + + // Try send with NULL source. + service->Notify(NotificationType::IDLE, + NotificationService::AllSources(), + NotificationService::NoDetails()); + + EXPECT_EQ(5, all_types_all_sources.notification_count()); + EXPECT_EQ(3, idle_all_sources.notification_count()); + EXPECT_EQ(2, all_types_test_source.notification_count()); + EXPECT_EQ(1, idle_test_source.notification_count()); + + registrar_.RemoveAll(); + + service->Notify(NotificationType::IDLE, + Source<TestSource>(&test_source), + NotificationService::NoDetails()); + + EXPECT_EQ(5, all_types_all_sources.notification_count()); + EXPECT_EQ(3, idle_all_sources.notification_count()); + EXPECT_EQ(2, all_types_test_source.notification_count()); + EXPECT_EQ(1, idle_test_source.notification_count()); +} + +TEST_F(NotificationServiceTest, MultipleRegistration) { + TestSource test_source; + + TestObserver idle_test_source; + + NotificationService* service = NotificationService::current(); + + registrar_.Add(&idle_test_source, NotificationType::IDLE, + Source<TestSource>(&test_source)); + registrar_.Add(&idle_test_source, NotificationType::ALL, + Source<TestSource>(&test_source)); + + service->Notify(NotificationType::IDLE, + Source<TestSource>(&test_source), + NotificationService::NoDetails()); + EXPECT_EQ(2, idle_test_source.notification_count()); + + registrar_.Remove(&idle_test_source, NotificationType::IDLE, + Source<TestSource>(&test_source)); + + service->Notify(NotificationType::IDLE, + Source<TestSource>(&test_source), + NotificationService::NoDetails()); + EXPECT_EQ(3, idle_test_source.notification_count()); + + registrar_.Remove(&idle_test_source, NotificationType::ALL, + Source<TestSource>(&test_source)); + + service->Notify(NotificationType::IDLE, + Source<TestSource>(&test_source), + NotificationService::NoDetails()); + EXPECT_EQ(3, idle_test_source.notification_count()); +} diff --git a/chrome/common/notification_source.cc b/chrome/common/notification_source.cc new file mode 100644 index 0000000..e0f5ca0 --- /dev/null +++ b/chrome/common/notification_source.cc @@ -0,0 +1,17 @@ +// Copyright (c) 2010 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 "chrome/common/notification_source.h" + +NotificationSource::NotificationSource(const NotificationSource& other) + : ptr_(other.ptr_) { +} + +NotificationSource::NotificationSource(const void* ptr) : ptr_(ptr) { +} + +NotificationSource::~NotificationSource() { +} + + diff --git a/chrome/common/notification_source.h b/chrome/common/notification_source.h new file mode 100644 index 0000000..1813c2e --- /dev/null +++ b/chrome/common/notification_source.h @@ -0,0 +1,54 @@ +// Copyright (c) 2006-2008 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 defines the type used to provide sources for NotificationService +// notifications. + +#ifndef CHROME_COMMON_NOTIFICATION_SOURCE_H__ +#define CHROME_COMMON_NOTIFICATION_SOURCE_H__ + +#include "base/basictypes.h" + +// Do not declare a NotificationSource directly--use either +// "Source<sourceclassname>(sourceclasspointer)" or +// NotificationService::AllSources(). +class NotificationSource { + public: + NotificationSource(const NotificationSource& other); + ~NotificationSource(); + + // NotificationSource can be used as the index for a map; this method + // returns the pointer to the current source as an identifier, for use as a + // map index. + uintptr_t map_key() const { return reinterpret_cast<uintptr_t>(ptr_); } + + bool operator!=(const NotificationSource& other) const { + return ptr_ != other.ptr_; + } + bool operator==(const NotificationSource& other) const { + return ptr_ == other.ptr_; + } + + protected: + explicit NotificationSource(const void* ptr); + + // Declaring this const allows Source<T> to be used with both T = Foo and + // T = const Foo. + const void* ptr_; +}; + +template <class T> +class Source : public NotificationSource { + public: + // TODO(erg): Our code hard relies on implicit conversion + Source(T* ptr) : NotificationSource(ptr) {} // NOLINT + Source(const NotificationSource& other) // NOLINT + : NotificationSource(other) {} + + T* operator->() const { return ptr(); } + // The casts here allow this to compile with both T = Foo and T = const Foo. + T* ptr() const { return static_cast<T*>(const_cast<void*>(ptr_)); } +}; + +#endif // CHROME_COMMON_NOTIFICATION_SOURCE_H__ diff --git a/chrome/common/notification_type.h b/chrome/common/notification_type.h new file mode 100644 index 0000000..9f75bb4 --- /dev/null +++ b/chrome/common/notification_type.h @@ -0,0 +1,1114 @@ +// Copyright (c) 2010 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 CHROME_COMMON_NOTIFICATION_TYPE_H_ +#define CHROME_COMMON_NOTIFICATION_TYPE_H_ + +// This file describes various types used to describe and filter notifications +// that pass through the NotificationService. +// +// It is written as an enum inside a class so that it can be forward declared. +// You're not allowed to forward declare an enum, and we want to forward +// declare this since it's required by NotificationObserver which is included +// by a lot of header files. +// +// Since this class encapsulates an integral value, it should be passed by +// value. +class NotificationType { + public: + enum Type { + // General ----------------------------------------------------------------- + + // Special signal value to represent an interest in all notifications. + // Not valid when posting a notification. + ALL = 0, + + // The app is done processing user actions, now is a good time to do + // some background work. + IDLE, + + // Means that the app has just started doing something in response to a + // user action, and that background processes shouldn't run if avoidable. + BUSY, + + // This is sent when the user does a gesture resulting in a noteworthy + // action taking place. This is typically used for logging. The source is + // the profile, and the details is a wstring identifying the action. + USER_ACTION, + + // NavigationController ---------------------------------------------------- + + // A new pending navigation has been created. Pending entries are created + // when the user requests the navigation. We don't know if it will actually + // happen until it does (at this point, it will be "committed." Note that + // renderer- initiated navigations such as link clicks will never be + // pending. + // + // This notification is called after the pending entry is created, but + // before we actually try to navigate. The source will be the + // NavigationController that owns the pending entry, and there are no + // details. + NAV_ENTRY_PENDING, + + // A new non-pending navigation entry has been created. This will + // correspond to one NavigationController entry being created (in the case + // of new navigations) or renavigated to (for back/forward navigations). + // + // The source will be the navigation controller doing the commit. The + // details will be NavigationController::LoadCommittedDetails. + NAV_ENTRY_COMMITTED, + + // Indicates that the NavigationController given in the Source has + // decreased its back/forward list count by removing entries from either + // the front or back of its list. This is usually the result of going back + // and then doing a new navigation, meaning all the "forward" items are + // deleted. + // + // This normally happens as a result of a new navigation. It will be + // followed by a NAV_ENTRY_COMMITTED message for the new page that + // caused the pruning. It could also be a result of removing an item from + // the list to fix up after interstitials. + // + // The details are NavigationController::PrunedDetails. + NAV_LIST_PRUNED, + + // Indicates that a NavigationEntry has changed. The source will be the + // NavigationController that owns the NavigationEntry. The details will be + // a NavigationController::EntryChangedDetails struct. + // + // This will NOT be sent on navigation, interested parties should also + // listen for NAV_ENTRY_COMMITTED to handle that case. This will be + // sent when the entry is updated outside of navigation (like when a new + // title comes). + NAV_ENTRY_CHANGED, + + // Other load-related (not from NavigationController) ---------------------- + + // A content load is starting. The source will be a + // Source<NavigationController> corresponding to the tab in which the load + // is occurring. No details are expected for this notification. + LOAD_START, + + // A content load has stopped. The source will be a + // Source<NavigationController> corresponding to the tab in which the load + // is occurring. Details in the form of a LoadNotificationDetails object + // are optional. + LOAD_STOP, + + // A frame is staring a provisional load. The source is a + // Source<NavigationController> corresponding to the tab in which the load + // occurs. Details is a bool specifying if the load occurs in the main + // frame (or a sub-frame if false). + FRAME_PROVISIONAL_LOAD_START, + + // Content was loaded from an in-memory cache. The source will be a + // Source<NavigationController> corresponding to the tab in which the load + // occurred. Details in the form of a LoadFromMemoryCacheDetails object + // are provided. + LOAD_FROM_MEMORY_CACHE, + + // A provisional content load has failed with an error. The source will be + // a Source<NavigationController> corresponding to the tab in which the + // load occurred. Details in the form of a ProvisionalLoadDetails object + // are provided. + FAIL_PROVISIONAL_LOAD_WITH_ERROR, + + // A response has been received for a resource request. The source will be + // a Source<NavigationController> corresponding to the tab in which the + // request was issued. Details in the form of a ResourceRequestDetails + // object are provided. + RESOURCE_RESPONSE_STARTED, + + // A redirect was received while requesting a resource. The source will be + // a Source<NavigationController> corresponding to the tab in which the + // request was issued. Details in the form of a ResourceRedirectDetails + // are provided. + RESOURCE_RECEIVED_REDIRECT, + + // SSL --------------------------------------------------------------------- + + // Updating the SSL security indicators (the lock icon and such) proceeds + // in two phases: + // + // 1) The internal SSL state for a host or tab changes. When this happens, + // the SSLManager broadcasts an SSL_INTERNAL_STATE_CHANGED notification. + // + // 2) The SSLManager for each tab receives this notification and might or + // might not update the navigation entry for its tab, depending on + // whether the change in state affects that tab. If the SSLManager does + // change the navigation entry, then the SSLManager broadcasts an + // SSL_VISIBLE_STATE_CHANGED notification to the user interface can + // redraw properly. + + // The SSL state of a page has changed in some visible way. For example, + // if an insecure resource is loaded on a secure page. Note that a + // toplevel load commit will also update the SSL state (since the + // NavigationEntry is new) and this message won't always be sent in that + // case. Listen to this notification if you need to refresh SSL-related UI + // elements. + // + // There is no source or details. + SSL_VISIBLE_STATE_CHANGED, + + // The SSL state of the browser has changed in some internal way. For + // example, the user might have explicitly allowed some broken certificate + // or a secure origin might have included some insecure content. Listen to + // this notifiation if you need to keep track of our internal SSL state. + // + // The source will be the navigation controller associated with the state + // change. There are no details. + SSL_INTERNAL_STATE_CHANGED, + + // Lets resource handlers and other interested observers know when the + // message filter is being deleted and can no longer be used. This will + // also get sent if the renderer crashes (and in that case, it'll be sent + // twice). + RESOURCE_MESSAGE_FILTER_SHUTDOWN, + + // Lets interested observers know when a WorkerProcessHost is being deleted + // and can no longer be used. + WORKER_PROCESS_HOST_SHUTDOWN, + + // Views ------------------------------------------------------------------- + + // Notification that a view was removed from a view hierarchy. The source + // is the view, the details is the parent view. + VIEW_REMOVED, + + // Browser-window ---------------------------------------------------------- + + // This message is sent after a window has been opened. The source is a + // Source<Browser> containing the affected Browser. No details are + // expected. + BROWSER_OPENED, + + // This message is sent soon after BROWSER_OPENED, and indicates that + // the Browser's |window_| is now non-NULL. The source is a Source<Browser> + // containing the affected Browser. No details are expected. + BROWSER_WINDOW_READY, + + // This message is sent when a browser is closing. The source is a + // Source<Browser> containing the affected Browser. Details is a boolean + // that if true indicates that the application will be closed as a result of + // this browser window closure (i.e. this was the last opened browser + // window on win/linux). This is sent prior to BROWSER_CLOSED, and may be + // sent more than once for a particular browser. + BROWSER_CLOSING, + + // This message is sent after a window has been closed. The source is a + // Source<Browser> containing the affected Browser. Details is a boolean + // that if true indicates that the last browser window has closed - this + // does not indicate that the application is exiting (observers should + // listen for APP_TERMINATING if they want to detect when the application + // will shut down). Note that the boolean pointed to by details is only + // valid for the duration of this call. + BROWSER_CLOSED, + + // This message is sent when the last window considered to be an + // "application window" has been closed. Dependent/dialog/utility windows + // can use this as a way to know that they should also close. No source or + // details are passed. + ALL_APPWINDOWS_CLOSED, + +#if defined(OS_MACOSX) + // This message is sent when the application is made active (Mac OS X only + // at present). No source or details are passed. + APP_ACTIVATED, +#endif + + // This message is sent when the application is terminating (the last + // browser window has shutdown as part of an explicit user-initiated exit, + // or the user closed the last browser window on Windows/Linux and there are + // no BackgroundContents keeping the browser running). No source or details + // are passed. + APP_TERMINATING, + +#if defined(OS_MACOSX) + // This notification is sent when the app has no key window, such as when + // all windows are closed but the app is still active. No source or details + // are provided. + NO_KEY_WINDOW, +#endif + + // This is sent when the user has chosen to exit the app, but before any + // browsers have closed. This is only sent if the user chooses the exit menu + // item, not if Chrome exists by some other means (such as the user closing + // the last window). The source and details are unspecified. + APP_EXITING, + + // Indicates that a top window has been closed. The source is the HWND + // that was closed, no details are expected. + WINDOW_CLOSED, + + // Indicates that a devtools window is closing. The source is the Profile* + // and the details is the inspected RenderViewHost*. + DEVTOOLS_WINDOW_CLOSING, + + // Sent when an info bubble has been created but not yet shown. The source + // is the InfoBubble. + INFO_BUBBLE_CREATED, + + // Sent when the language (English, French...) for a page has been detected. + // The details Details<std::string> contain the ISO 639-1 language code and + // the source is Source<TabContents>. + TAB_LANGUAGE_DETERMINED, + + // Sent when a page has been translated. The source is the tab for that page + // (Source<TabContents>) and the details are the language the page was + // originally in and the language it was translated to + // (std::pair<std::string, std::string>). + PAGE_TRANSLATED, + + // Sent after the renderer returns a snapshot of tab contents. + // The source (Source<RenderViewHost>) is the RenderViewHost for which the + // snapshot was generated and the details (Details<const SkBitmap>) is the + // actual snapshot. + TAB_SNAPSHOT_TAKEN, + + // Send after the code is run in specified tab. + TAB_CODE_EXECUTED, + + // The user has changed the browser theme. + BROWSER_THEME_CHANGED, + + // Sent when the renderer returns focus to the browser, as part of focus + // traversal. The source is the browser, there are no details. + FOCUS_RETURNED_TO_BROWSER, + + // Application-modal dialogs ----------------------------------------------- + + // Sent after an application-modal dialog has been shown. The source + // is the dialog. + APP_MODAL_DIALOG_SHOWN, + + // Sent after an application-modal dialog has been closed. The source + // is the dialog. + APP_MODAL_DIALOG_CLOSED, + + // Tabs -------------------------------------------------------------------- + + // Sent when a tab is added to a TabContentsDelegate. The source is the + // TabContentsDelegate and the details is the TabContents. + TAB_ADDED, + + // This notification is sent after a tab has been appended to the + // tab_strip. The source is a Source<NavigationController> with a pointer + // to controller for the added tab. There are no details. + TAB_PARENTED, + + // This message is sent before a tab has been closed. The source is a + // Source<NavigationController> with a pointer to the controller for the + // closed tab. No details are expected. + // + // See also TAB_CLOSED. + TAB_CLOSING, + + // Notification that a tab has been closed. The source is the + // NavigationController with no details. + TAB_CLOSED, + + // This notification is sent when a render view host has connected to a + // renderer process. The source is a Source<TabContents> with a pointer to + // the TabContents. A TAB_CONTENTS_DISCONNECTED notification is + // guaranteed before the source pointer becomes junk. No details are + // expected. + TAB_CONTENTS_CONNECTED, + + // This notification is sent when a TabContents swaps its render view host + // with another one, possibly changing processes. The source is a + // Source<TabContents> with a pointer to the TabContents. A + // TAB_CONTENTS_DISCONNECTED notification is guaranteed before the + // source pointer becomes junk. No details are expected. + TAB_CONTENTS_SWAPPED, + + // This message is sent after a TabContents is disconnected from the + // renderer process. The source is a Source<TabContents> with a pointer to + // the TabContents (the pointer is usable). No details are expected. + TAB_CONTENTS_DISCONNECTED, + + // This notification is sent after TabContents' title is updated. The source + // is a Source<TabContents> with a pointer to the TabContents. No details + // are expected. + TAB_CONTENTS_TITLE_UPDATED, + + // This message is sent when a new InfoBar has been added to a TabContents. + // The source is a Source<TabContents> with a pointer to the TabContents + // the InfoBar was added to. The details is a Details<InfoBarDelegate> with + // a pointer to an object implementing the InfoBarDelegate interface for + // the InfoBar that was added. + TAB_CONTENTS_INFOBAR_ADDED, + + // This message is sent when an InfoBar is about to be removed from a + // TabContents. The source is a Source<TabContents> with a pointer to the + // TabContents the InfoBar was removed from. The details is a + // Details<InfoBarDelegate> with a pointer to an object implementing the + // InfoBarDelegate interface for the InfoBar that was removed. + TAB_CONTENTS_INFOBAR_REMOVED, + + // This message is sent when an InfoBar is replacing another infobar in a + // TabContents. The source is a Source<TabContents> with a pointer to the + // TabContents the InfoBar was removed from. The details is a + // Details<std::pair<InfoBarDelegate*, InfoBarDelegate*> > with a pointer + // to the old and new InfoBarDelegates, respectively. + TAB_CONTENTS_INFOBAR_REPLACED, + + // This is sent when an externally hosted tab is created. The details + // contain the ExternalTabContainer that contains the tab + EXTERNAL_TAB_CREATED, + + // This is sent when an externally hosted tab is closed. No details are + // expected. + EXTERNAL_TAB_CLOSED, + + // Indicates that the new page tab has finished loading. This is used for + // performance testing to see how fast we can load it after startup, and is + // only called once for the lifetime of the browser. The source is unused. + // Details is an integer: the number of milliseconds elapsed between + // starting and finishing all painting. + INITIAL_NEW_TAB_UI_LOAD, + + // Used to fire notifications about how long various events took to + // complete. E.g., this is used to get more fine grained timings from the + // new tab page. Details is a MetricEventDurationDetails. + METRIC_EVENT_DURATION, + + // This notification is sent when a TabContents is being hidden, e.g. due + // to switching away from this tab. The source is a Source<TabContents>. + TAB_CONTENTS_HIDDEN, + + // This notification is sent when a TabContents is being destroyed. Any + // object holding a reference to a TabContents can listen to that + // notification to properly reset the reference. The source is a + // Source<TabContents>. + TAB_CONTENTS_DESTROYED, + + // This notification is sent when TabContents::SetAppExtension is invoked. + // The source is the TabContents SetAppExtension was invoked on. + TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED, + + // A RenderViewHost was created for a TabContents. The source is the + // associated TabContents, and the details is the RenderViewHost + // pointer. + RENDER_VIEW_HOST_CREATED_FOR_TAB, + + // Stuff inside the tabs --------------------------------------------------- + + // This message is sent after a constrained window has been closed. The + // source is a Source<ConstrainedWindow> with a pointer to the closed child + // window. (The pointer isn't usable, except for identification.) No + // details are expected. + CWINDOW_CLOSED, + + // Indicates that a RenderProcessHost was created and its handle is now + // available. The source will be the RenderProcessHost that corresponds to + // the process. + RENDERER_PROCESS_CREATED, + + // Indicates that a RenderProcessHost is destructing. The source will be the + // RenderProcessHost that corresponds to the process. + RENDERER_PROCESS_TERMINATED, + + // Indicates that a render process was closed (meaning it exited, but the + // RenderProcessHost might be reused). The source will be the corresponding + // RenderProcessHost. The details will be a RendererClosedDetails struct. + // This may get sent along with RENDERER_PROCESS_TERMINATED. + RENDERER_PROCESS_CLOSED, + + // Indicates that a render process has become unresponsive for a period of + // time. The source will be the RenderWidgetHost that corresponds to the + // hung view, and no details are expected. + RENDERER_PROCESS_HANG, + + // This is sent to notify that the RenderViewHost displayed in a + // TabContents has changed. Source is the TabContents for which the change + // happened, details is the previous RenderViewHost (can be NULL when the + // first RenderViewHost is set). + RENDER_VIEW_HOST_CHANGED, + + // Indicates that the render view host has received a new accessibility tree + // from the render view. The source is the RenderViewHost, the details + // are not used. + RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED, + + // This is sent when a RenderWidgetHost is being destroyed. The source is + // the RenderWidgetHost, the details are not used. + RENDER_WIDGET_HOST_DESTROYED, + + // Sent from ~RenderViewHost. The source is the TabContents. + RENDER_VIEW_HOST_DELETED, + + // Sent from RenderViewHost::ClosePage. The hosted RenderView has + // processed the onbeforeunload handler and is about to be sent a + // ViewMsg_ClosePage message to complete the tear-down process. The source + // is the RenderViewHost sending the message, and no details are provided. + // Note: This message is not sent in response to RenderView closure + // initiated by window.close(). + RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW, + + // Indicates a RenderWidgetHost has been hidden or restored. The source is + // the RWH whose visibility changed, the details is a bool set to true if + // the new state is "visible." + RENDER_WIDGET_VISIBILITY_CHANGED, + + // Notification from TabContents that we have received a response from the + // renderer in response to a dom automation controller action. + DOM_OPERATION_RESPONSE, + + // Sent when the bookmark bubble hides. The source is the profile, the + // details unused. + BOOKMARK_BUBBLE_HIDDEN, + + // This notification is sent when the result of a find-in-page search is + // available with the browser process. The source is a Source<TabContents> + // with a pointer to the TabContents. Details encompass a + // FindNotificationDetail object that tells whether the match was found or + // not found. + FIND_RESULT_AVAILABLE, + + // This is sent when the users preference for when the bookmark bar should + // be shown changes. The source is the profile, and the details are + // NoDetails. + BOOKMARK_BAR_VISIBILITY_PREF_CHANGED, + + // This is sent when the user's preference (for when the extension shelf + // should be shown) changes. The source is the profile, and the details are + // NoDetails. + EXTENSION_SHELF_VISIBILITY_PREF_CHANGED, + + // Sent just before the installation confirm dialog is shown. The source + // is the ExtensionInstallUI, the details are NoDetails. + EXTENSION_WILL_SHOW_CONFIRM_DIALOG, + + // Used to monitor web cache usage by notifying whenever the + // CacheManagerHost observes new UsageStats. The source will be the + // RenderProcessHost that corresponds to the new statistics. Details are a + // UsageStats object sent by the renderer, and should be copied - ptr not + // guaranteed to be valid after the notification. + WEB_CACHE_STATS_OBSERVED, + + // The focused element inside a page has changed. The source is the render + // view host for the page, there are no details. + FOCUS_CHANGED_IN_PAGE, + + // BackgroundContents ------------------------------------------------------ + + // A new background contents was opened by script. The source is the parent + // profile and the details are BackgroundContentsOpenedDetails. + BACKGROUND_CONTENTS_OPENED, + + // The background contents navigated to a new location. The source is the + // parent Profile, and the details are the BackgroundContents that was + // navigated. + BACKGROUND_CONTENTS_NAVIGATED, + + // The background contents were closed by someone invoking window.close() + // or the parent application was uninstalled. + // The source is the parent profile, and the details are the + // BackgroundContents. + BACKGROUND_CONTENTS_CLOSED, + + // The background contents is being deleted. The source is the + // parent Profile, and the details are the BackgroundContents being deleted. + BACKGROUND_CONTENTS_DELETED, + + // Child Processes --------------------------------------------------------- + + // This notification is sent when a child process host has connected to a + // child process. There is no usable source, since it is sent from an + // ephemeral task; register for AllSources() to receive this notification. + // The details are in a Details<ChildProcessInfo>. + CHILD_PROCESS_HOST_CONNECTED, + + // This message is sent after a ChildProcessHost is disconnected from the + // child process. There is no usable source, since it is sent from an + // ephemeral task; register for AllSources() to receive this notification. + // The details are in a Details<ChildProcessInfo>. + CHILD_PROCESS_HOST_DISCONNECTED, + + // This message is sent when a child process disappears unexpectedly. + // There is no usable source, since it is sent from an ephemeral task; + // register for AllSources() to receive this notification. The details are + // in a Details<ChildProcessInfo>. + CHILD_PROCESS_CRASHED, + + // This message indicates that an instance of a particular child was + // created in a page. (If one page contains several regions rendered by + // the same child, this notification will occur once for each region + // during the page load.) + // + // There is no usable source, since it is sent from an ephemeral task; + // register for AllSources() to receive this notification. The details are + // in a Details<ChildProcessInfo>. + CHILD_INSTANCE_CREATED, + + // This is sent when network interception is disabled for a plugin, or the + // plugin is unloaded. This should only be sent/received on the browser IO + // thread or the plugin thread. The source is the plugin that is disabling + // interception. No details are expected. + CHROME_PLUGIN_UNLOADED, + + // This is sent when a login prompt is shown. The source is the + // Source<NavigationController> for the tab in which the prompt is shown. + // Details are a LoginNotificationDetails which provide the LoginHandler + // that should be given authentication. + AUTH_NEEDED, + + // This is sent when authentication credentials have been supplied (either + // by the user or by an automation service), but before we've actually + // received another response from the server. The source is the + // Source<NavigationController> for the tab in which the prompt was shown. + // Details are an AuthSuppliedLoginNotificationDetails which provide the + // LoginHandler that should be given authentication as well as the supplied + // username and password. + AUTH_SUPPLIED, + + // This is sent when an authentication request has been dismissed without + // supplying credentials (either by the user or by an automation service). + // The source is the Source<NavigationController> for the tab in which the + // prompt was shown. Details are a LoginNotificationDetails which provide + // the LoginHandler that should be cancelled. + AUTH_CANCELLED, + + // Saved Pages ------------------------------------------------------------- + + // Sent when a SavePackage finishes successfully. The source is the + // SavePackage, and Details are a GURL containing address of downloaded + // page. + SAVE_PACKAGE_SUCCESSFULLY_FINISHED, + + // History ----------------------------------------------------------------- + + // Sent when a history service is created on the main thread. This is sent + // after history is created, but before it has finished loading. Use + // HISTORY_LOADED is you need to know when loading has completed. + // The source is the profile that the history service belongs to, and the + // details is the pointer to the newly created HistoryService object. + HISTORY_CREATED, + + // Sent when a history service has finished loading. The source is the + // profile that the history service belongs to, and the details is the + // HistoryService. + HISTORY_LOADED, + + // Sent when a URL that has been typed has been added or modified. This is + // used by the in-memory URL database (used by autocomplete) to track + // changes to the main history system. + // + // The source is the profile owning the history service that changed, and + // the details is history::URLsModifiedDetails that lists the modified or + // added URLs. + HISTORY_TYPED_URLS_MODIFIED, + + // Sent when the user visits a URL. + // + // The source is the profile owning the history service that changed, and + // the details is history::URLVisitedDetails. + HISTORY_URL_VISITED, + + // Sent when one or more URLs are deleted. + // + // The source is the profile owning the history service that changed, and + // the details is history::URLsDeletedDetails that lists the deleted URLs. + HISTORY_URLS_DELETED, + + // Sent by history when the favicon of a URL changes. The source is the + // profile, and the details is history::FavIconChangeDetails (see + // history_notifications.h). + FAVICON_CHANGED, + + // Sent by history if there is a problem reading the profile. The details + // is an int that's one of the message IDs in the string table. The active + // browser window should notify the user of this error. + PROFILE_ERROR, + + // Sent before a Profile is destroyed. The details are + // none and the source is a Profile*. + PROFILE_DESTROYED, + + // Thumbnails--------------------------------------------------------------- + + // Sent by the ThumbnailGenerator whenever a render widget host + // updates its backing store. The source is the + // ThumbnailGenerator, and the details are the RenderWidgetHost + // that notified the ThumbnailGenerator that its backing store was + // updated. + THUMBNAIL_GENERATOR_SNAPSHOT_CHANGED, + + // Bookmarks --------------------------------------------------------------- + + // Sent when the starred state of a URL changes. A URL is starred if there + // is at least one bookmark for it. The source is a Profile and the details + // is history::URLsStarredDetails that contains the list of URLs and + // whether they were starred or unstarred. + URLS_STARRED, + + // Sent when the bookmark bar model finishes loading. This source is the + // Profile, and the details aren't used. + BOOKMARK_MODEL_LOADED, + + // Sent when SpellCheckHost has been reloaded. The source is the profile, + // the details are NoDetails. + SPELLCHECK_HOST_REINITIALIZED, + + // Sent when a new word has been added to the custom dictionary. The source + // is the SpellCheckHost, the details are NoDetails. + SPELLCHECK_WORD_ADDED, + + // Sent by the profile when the automatic spell correction setting has been + // toggled. It exists as a notification rather than just letting interested + // parties listen for the pref change because some objects may outlive the + // profile. Source is profile, details is NoDetails. + SPELLCHECK_AUTOSPELL_TOGGLED, + + // Sent when the bookmark bubble is shown for a particular URL. The source + // is the profile, the details the URL. + BOOKMARK_BUBBLE_SHOWN, + + // Non-history storage services -------------------------------------------- + + // Notification that the TemplateURLModel has finished loading from the + // database. The source is the TemplateURLModel, and the details are + // NoDetails. + TEMPLATE_URL_MODEL_LOADED, + + // Notification triggered when a web application has been installed or + // uninstalled. Any application view should reload its data. The source is + // the profile. No details are provided. + WEB_APP_INSTALL_CHANGED, + + // This is sent to a pref observer when a pref is changed. The source is the + // PrefService and the details a std::wstring of the changed path. + PREF_CHANGED, + + // Sent when a default request context has been created, so calling + // Profile::GetDefaultRequestContext() will not return NULL. This is sent + // on the thread where Profile::GetRequestContext() is first called, which + // should be the UI thread. + DEFAULT_REQUEST_CONTEXT_AVAILABLE, + + // Autocomplete ------------------------------------------------------------ + + // Sent by the autocomplete controller at least once per query, each time + // new matches are available, subject to rate-limiting/coalescing to reduce + // the number of updates. The details hold the AutocompleteResult that + // observers should use if they want to see the updated matches. + AUTOCOMPLETE_CONTROLLER_RESULT_UPDATED, + + // Sent by the autocomplete controller immediately after synchronous matches + // become available, and thereafter at the same time that + // AUTOCOMPLETE_CONTROLLER_RESULT_UPDATED is sent. The details hold the + // AutocompleteResult that observers should use if they want to see the + // up-to-date matches. + AUTOCOMPLETE_CONTROLLER_DEFAULT_MATCH_UPDATED, + + // This is sent when an item of the Omnibox popup is selected. The source + // is the profile. + OMNIBOX_OPENED_URL, + + // Sent by the autocomplete edit when it is destroyed. + AUTOCOMPLETE_EDIT_DESTROYED, + + // Sent when the main Google URL has been updated. Some services cache + // this value and need to update themselves when it changes. See + // google_util::GetGoogleURLAndUpdateIfNecessary(). + GOOGLE_URL_UPDATED, + + // Printing ---------------------------------------------------------------- + + // Notification from PrintJob that an event occured. It can be that a page + // finished printing or that the print job failed. Details is + // PrintJob::EventDetails. + PRINT_JOB_EVENT, + + // Shutdown ---------------------------------------------------------------- + + // Sent on the browser IO thread when an URLRequestContext is released by + // its owning Profile. The source is a pointer to the URLRequestContext. + URL_REQUEST_CONTEXT_RELEASED, + + // Sent when WM_ENDSESSION has been received, after the browsers have been + // closed but before browser process has been shutdown. The source/details + // are all source and no details. + SESSION_END, + + // Personalization --------------------------------------------------------- + + PERSONALIZATION, + PERSONALIZATION_CREATED, + + // User Scripts ------------------------------------------------------------ + + // Sent when there are new user scripts available. The details are a + // pointer to SharedMemory containing the new scripts. + USER_SCRIPTS_UPDATED, + + // User Style Sheet -------------------------------------------------------- + + // Sent when the user style sheet has changed. + USER_STYLE_SHEET_UPDATED, + + // Extensions -------------------------------------------------------------- + + // Sent when the known installed extensions have all been loaded. In + // testing scenarios this can happen multiple times if extensions are + // unloaded and reloaded. The source is a Profile. + EXTENSIONS_READY, + + // Sent when a new extension is loaded. The details are an Extension, and + // the source is a Profile. + EXTENSION_LOADED, + + // Sent when attempting to load a new extension, but they are disabled. The + // details are an Extension*, and the source is a Profile*. + EXTENSION_UPDATE_DISABLED, + + // Sent when an extension is about to be installed so we can (in the case of + // themes) alert the user with a loading dialog. The source is the download + // manager and the details are the download url. + EXTENSION_READY_FOR_INSTALL, + + // Sent when an extension install turns out to not be a theme. + NO_THEME_DETECTED, + + // Sent when a new theme is installed. The details are an Extension, and the + // source is a Profile. + THEME_INSTALLED, + + // Sent when new extensions are installed. The details are an Extension, and + // the source is a Profile. + EXTENSION_INSTALLED, + + // An error occured during extension install. The details are a string with + // details about why the install failed. + EXTENSION_INSTALL_ERROR, + + // Sent when an extension is unloaded. This happens when an extension is + // uninstalled or disabled. The details are an Extension, and the source is + // a Profile. + // + // Note that when this notification is sent, ExtensionsService has already + // removed the extension from its internal state. + EXTENSION_UNLOADED, + + // Same as above, but for a disabled extension. + EXTENSION_UNLOADED_DISABLED, + + // Sent when an extension has updated its user scripts. The details are an + // Extension, and the source is a Profile. + EXTENSION_USER_SCRIPTS_UPDATED, + + // Sent after a new ExtensionFunctionDispatcher is created. The details are + // an ExtensionFunctionDispatcher* and the source is a Profile*. This is + // similar in timing to EXTENSION_HOST_CREATED, but also fires when an + // extension view which is hosted in TabContents* is created. + EXTENSION_FUNCTION_DISPATCHER_CREATED, + + // Sent before an ExtensionHost is destroyed. The details are + // an ExtensionFunctionDispatcher* and the source is a Profile*. This is + // similar in timing to EXTENSION_HOST_DESTROYED, but also fires when an + // extension view which is hosted in TabContents* is destroyed. + EXTENSION_FUNCTION_DISPATCHER_DESTROYED, + + // Sent after a new ExtensionHost is created. The details are + // an ExtensionHost* and the source is an ExtensionProcessManager*. + EXTENSION_HOST_CREATED, + + // Sent before an ExtensionHost is destroyed. The details are + // an ExtensionHost* and the source is a Profile*. + EXTENSION_HOST_DESTROYED, + + // Sent by an ExtensionHost when it finished its initial page load. + // The details are an ExtensionHost* and the source is a Profile*. + EXTENSION_HOST_DID_STOP_LOADING, + + // Sent by an ExtensionHost when its render view requests closing through + // window.close(). The details are an ExtensionHost* and the source is a + // Profile*. + EXTENSION_HOST_VIEW_SHOULD_CLOSE, + + // Sent after an extension render process is created and fully functional. + // The details are an ExtensionHost*. + EXTENSION_PROCESS_CREATED, + + // Sent when extension render process ends (whether it crashes or closes). + // The details are an ExtensionHost* and the source is a Profile*. Not sent + // during browser shutdown. + EXTENSION_PROCESS_TERMINATED, + + // Sent when the contents or order of toolstrips in the shelf model change. + EXTENSION_SHELF_MODEL_CHANGED, + + // Sent when a background page is ready so other components can load. + EXTENSION_BACKGROUND_PAGE_READY, + + // Sent when a pop-up extension view is ready, so that notification may + // be sent to pending callbacks. Note that this notification is sent + // after all onload callbacks have been invoked in the main frame. + // The details is the ExtensionHost* hosted within the popup, and the source + // is a Profile*. + EXTENSION_POPUP_VIEW_READY, + + // Sent when a browser action's state has changed. The source is the + // ExtensionAction* that changed. There are no details. + EXTENSION_BROWSER_ACTION_UPDATED, + + // Sent when the count of page actions has changed. Note that some of them + // may not apply to the current page. The source is a LocationBar*. There + // are no details. + EXTENSION_PAGE_ACTION_COUNT_CHANGED, + + // Sent when a page action's visibility has changed. The source is the + // ExtensionAction* that changed. The details are a TabContents*. + EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED, + + // Sent by an extension to notify the browser about the results of a unit + // test. + EXTENSION_TEST_PASSED, + EXTENSION_TEST_FAILED, + + // Sent when an bookmarks extensions API function was successfully invoked. + // The source is the id of the extension that invoked the function, and the + // details are a pointer to the const BookmarksFunction in question. + EXTENSION_BOOKMARKS_API_INVOKED, + + // Sent when an omnibox extension has sent back omnibox suggestions. The + // source is the profile, and the details are an ExtensionOmniboxSuggestions + // object. + EXTENSION_OMNIBOX_SUGGESTIONS_READY, + + // Sent when the user accepts the input in an extension omnibox keyword + // session. The source is the profile. + EXTENSION_OMNIBOX_INPUT_ENTERED, + + // Debugging --------------------------------------------------------------- + + // TODO(mpcomplete): Sent to diagnose a bug. Remove when fixed. + // http://code.google.com/p/chromium/issues/detail?id=21201 + EXTENSION_PORT_DELETED_DEBUG, + + // Desktop Notifications --------------------------------------------------- + + // This notification is sent when a balloon is connected to a renderer + // process to render the balloon contents. The source is a + // Source<BalloonHost> with a pointer to the the balloon. A + // NOTIFY_BALLOON_DISCONNECTED is guaranteed before the source pointer + // becomes junk. No details expected. + NOTIFY_BALLOON_CONNECTED, + + // This message is sent after a balloon is disconnected from the renderer + // process. The source is a Source<BalloonHost> with a pointer to the + // balloon host (the pointer is usable). No details are expected. + NOTIFY_BALLOON_DISCONNECTED, + + // Web Database Service ---------------------------------------------------- + + // This notification is sent whenever autofill entries are + // changed. The detail of this notification is a list of changes + // represented by a vector of AutofillChange. Each change + // includes a change type (add, update, or remove) as well as the + // key of the entry that was affected. + AUTOFILL_ENTRIES_CHANGED, + + // Sent when an AutoFillProfile has been added/removed/updated in the + // WebDatabase. The detail is an AutofillProfileChange. + AUTOFILL_PROFILE_CHANGED, + + // Sent when an Autofill CreditCard has been added/removed/updated in the + // WebDatabase. The detail is an AutofillCreditCardChange. + AUTOFILL_CREDIT_CARD_CHANGED, + + // This notification is sent whenever the web database service has finished + // loading the web database. No details are expected. + WEB_DATABASE_LOADED, + + // Purge Memory ------------------------------------------------------------ + + // Sent on the IO thread when the system should try to reduce the amount of + // memory in use, no source or details are passed. See memory_purger.h .cc. + PURGE_MEMORY, + + // Upgrade notifications --------------------------------------------------- + + // Sent when Chrome detects that it has been upgraded behind the scenes. + // NOTE: The detection mechanism is asynchronous, so this event may arrive + // quite some time after the upgrade actually happened. No details are + // expected. + UPGRADE_DETECTED, + + // Sent when Chrome believes an update has been installed and available for + // long enough with the user shutting down to let it take effect. See + // upgrade_detector.cc for details on how long it waits. No details are + // expected. + UPGRADE_RECOMMENDED, + + // Accessibility Notifications --------------------------------------------- + + // Notification that a window in the browser UI (not the web content) + // was opened, for propagating to an accessibility extension. + // Details will be an AccessibilityWindowInfo. + ACCESSIBILITY_WINDOW_OPENED, + + // Notification that a window in the browser UI was closed. + // Details will be an AccessibilityWindowInfo. + ACCESSIBILITY_WINDOW_CLOSED, + + // Notification that a control in the browser UI was focused. + // Details will be an AccessibilityControlInfo. + ACCESSIBILITY_CONTROL_FOCUSED, + + // Notification that a control in the browser UI had its action taken, + // like pressing a button or toggling a checkbox. + // Details will be an AccessibilityControlInfo. + ACCESSIBILITY_CONTROL_ACTION, + + // Notification that text box in the browser UI had text change. + // Details will be an AccessibilityControlInfo. + ACCESSIBILITY_TEXT_CHANGED, + + // Notification that a pop-down menu was opened, for propagating + // to an accessibility extension. + // Details will be an AccessibilityMenuInfo. + ACCESSIBILITY_MENU_OPENED, + + // Notification that a pop-down menu was closed, for propagating + // to an accessibility extension. + // Details will be an AccessibilityMenuInfo. + ACCESSIBILITY_MENU_CLOSED, + + // Content Settings -------------------------------------------------------- + + // Sent when content settings change. The source is a HostContentSettings + // object, the details are ContentSettingsNotificationsDetails. + CONTENT_SETTINGS_CHANGED, + + // Sent when the collect cookies dialog is shown. The source is a + // TabSpecificContentSettings object, there are no details. + COLLECTED_COOKIES_SHOWN, + + // Sync -------------------------------------------------------------------- + + // Sent when the sync backend has been paused. + SYNC_PAUSED, + + // Sent when the sync backend has been resumed. + SYNC_RESUMED, + + // The sync service has started the configuration process. + SYNC_CONFIGURE_START, + + // The sync service is finished the configuration process. + SYNC_CONFIGURE_DONE, + + // The session service has been saved. This notification type is only sent + // if there were new SessionService commands to save, and not for no-op save + // operations. + SESSION_SERVICE_SAVED, + + // The syncer requires a passphrase to decrypt sensitive updates. This + // notification is sent when the first sensitive data type is setup by the + // user as well as anytime any the passphrase is changed in another synced + // client. + SYNC_PASSPHRASE_REQUIRED, + + // Sent when the passphrase provided by the user is accepted. After this + // notification is sent, updates to sensitive nodes are encrypted using the + // accepted passphrase. + SYNC_PASSPHRASE_ACCEPTED, + + // Cookies ----------------------------------------------------------------- + + // Sent when a cookie changes. The source is a Profile object, the details + // are a ChromeCookieDetails object. + COOKIE_CHANGED, + + // Misc -------------------------------------------------------------------- + +#if defined(OS_CHROMEOS) + // Sent when a chromium os user logs in. + LOGIN_USER_CHANGED, + + // Sent when user image is updated. + LOGIN_USER_IMAGE_CHANGED, + + // Sent when a chromium os user attempts to log in. The source is + // all and the details are AuthenticationNotificationDetails. + LOGIN_AUTHENTICATION, + + // Sent when a panel state changed. + PANEL_STATE_CHANGED, + + // Sent when the wizard's content view is destroyed. The source and details + // are not used. + WIZARD_CONTENT_VIEW_DESTROYED, + + // Sent when the screen lock state has changed. The source is + // ScreenLocker and the details is a bool specifing that the + // screen is locked. When details is a false, the source object + // is being deleted, so the receiver shouldn't use the screen locker + // object. + SCREEN_LOCK_STATE_CHANGED, + + // Sent when the network state has changed on UI thread. + // The source is AllSources and the details is NetworkStateDetails defined + // in chrome/browser/chromeos/network_state_notifier.h. + // TODO(oshima): Port this to all platforms. + NETWORK_STATE_CHANGED, +#endif + + // Sent before the repost form warning is brought up. + // The source is a NavigationController. + REPOST_WARNING_SHOWN, + +#if defined(TOOLKIT_VIEWS) + // Sent when a bookmark's context menu is shown. Used to notify + // tests that the context menu has been created and shown. + BOOKMARK_CONTEXT_MENU_SHOWN, +#endif + + // Sent when the zoom level changes. The source is the profile, details the + // host as a std::string (see HostZoomMap::GetZoomLevel for details on the + // host as it not always just the host). + ZOOM_LEVEL_CHANGED, + + // Sent when the tab's closeable state has changed due to increase/decrease + // in number of tabs in browser or increase/decrease in number of browsers. + // Details<bool> contain the closeable flag while source is AllSources. + // This is only sent from ChromeOS's TabCloseableStateWatcher. + TAB_CLOSEABLE_STATE_CHANGED, + + // Password Store ---------------------------------------------------------- + // This notification is sent whenenever login entries stored in the password + // store are changed. The detail of this notification is a list of changes + // represented by a vector of PasswordStoreChange. Each change includes a + // change type (ADD, UPDATE, or REMOVE) as well as the + // |webkit_glue::PasswordForm|s that were affected. + LOGINS_CHANGED, + + // Count (must be last) ---------------------------------------------------- + // Used to determine the number of notification types. Not valid as + // a type parameter when registering for or posting notifications. + NOTIFICATION_TYPE_COUNT + }; + + // TODO(erg): Our notification system relies on implicit conversion. + NotificationType(Type v) : value(v) {} // NOLINT + + bool operator==(NotificationType t) const { return value == t.value; } + bool operator!=(NotificationType t) const { return value != t.value; } + + // Comparison to explicit enum values. + bool operator==(Type v) const { return value == v; } + bool operator!=(Type v) const { return value != v; } + + Type value; +}; + +inline bool operator==(NotificationType::Type a, NotificationType b) { + return a == b.value; +} +inline bool operator!=(NotificationType::Type a, NotificationType b) { + return a != b.value; +} + +#endif // CHROME_COMMON_NOTIFICATION_TYPE_H_ diff --git a/chrome/common/owned_widget_gtk.cc b/chrome/common/owned_widget_gtk.cc new file mode 100644 index 0000000..f9b8bef --- /dev/null +++ b/chrome/common/owned_widget_gtk.cc @@ -0,0 +1,38 @@ +// Copyright (c) 2009 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 "chrome/common/owned_widget_gtk.h" + +#include <gtk/gtk.h> + +#include "base/logging.h" + +OwnedWidgetGtk::~OwnedWidgetGtk() { + DCHECK(!widget_) << "You must explicitly call OwnerWidgetGtk::Destroy()."; +} + +void OwnedWidgetGtk::Own(GtkWidget* widget) { + DCHECK(!widget_); + // We want to make sure that Own() was called properly, right after the + // widget was created. There should be a floating reference. + DCHECK(g_object_is_floating(widget)); + + // Sink the floating reference, we should now own this reference. + g_object_ref_sink(widget); + widget_ = widget; +} + +void OwnedWidgetGtk::Destroy() { + if (!widget_) + return; + + GtkWidget* widget = widget_; + widget_ = NULL; + gtk_widget_destroy(widget); + + DCHECK(!g_object_is_floating(widget)); + // NOTE: Assumes some implementation details about glib internals. + DCHECK_EQ(G_OBJECT(widget)->ref_count, 1U); + g_object_unref(widget); +} diff --git a/chrome/common/owned_widget_gtk.h b/chrome/common/owned_widget_gtk.h new file mode 100644 index 0000000..72fadd5 --- /dev/null +++ b/chrome/common/owned_widget_gtk.h @@ -0,0 +1,89 @@ +// Copyright (c) 2009 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 class assists you in dealing with a specific situation when managing +// ownership between a C++ object and a GTK widget. It is common to have a +// C++ object which encapsulates a GtkWidget, and that widget is exposed from +// the object for use outside of the class. In this situation, you commonly +// want the GtkWidget's lifetime to match its C++ object's lifetime. Using an +// OwnedWigetGtk will take ownership over the initial reference of the +// GtkWidget, so that it is "owned" by the C++ object. Example usage: +// +// class FooViewGtk() { +// public: +// FooViewGtk() { } +// ~FooViewGtk() { widget_.Destroy(); } +// void Init() { vbox_.Own(gtk_vbox_new()); } +// GtkWidget* widget() { return vbox_.get() }; // Host my widget! +// private: +// OwnedWidgetGtk vbox_; +// }; +// +// This design will ensure that the widget stays alive from the call to Own() +// until the call to Destroy(). +// +// - Details of the problem and OwnedWidgetGtk's solution: +// In order to make passing ownership more convenient for newly created +// widgets, GTK has a concept of a "floating" reference. All GtkObjects (and +// thus GtkWidgets) inherit from GInitiallyUnowned. When they are created, the +// object starts with a reference count of 1, but has its floating flag set. +// When it is put into a container for the first time, that container will +// "sink" the floating reference, and the count will still be 1. Now the +// container owns the widget, and if we remove the widget from the container, +// the widget is destroyed. This style of ownership often causes problems when +// you have an object encapsulating the widget. If we just use a raw +// GtkObject* with no specific ownership management, we push the widget's +// ownership onto the user of the class. Now the C++ object can't depend on +// the widget being valid, since it doesn't manage its lifetime. If the widget +// was removed from a container, removing its only reference, it would be +// destroyed (from the C++ object's perspective) unexpectantly destroyed. The +// solution is fairly simple, make sure that the C++ object owns the widget, +// and thus it is also responsible for destroying it. This boils down to: +// GtkWidget* widget = gtk_widget_new(); +// g_object_ref_sink(widget); // Claim the initial floating reference. +// ... +// gtk_destroy_widget(widget); // Ask all code to destroy their references. +// g_object_unref(widget); // Destroy the initial reference we had claimed. + +#ifndef CHROME_COMMON_OWNED_WIDGET_GTK_H_ +#define CHROME_COMMON_OWNED_WIDGET_GTK_H_ + +#include "base/basictypes.h" + +typedef struct _GtkWidget GtkWidget; + +class OwnedWidgetGtk { + public: + // Create an instance that isn't managing any ownership. + OwnedWidgetGtk() : widget_(NULL) { } + // Create an instance that owns |widget|. + explicit OwnedWidgetGtk(GtkWidget* widget) : widget_(NULL) { Own(widget); } + + ~OwnedWidgetGtk(); + + // Return the currently owned widget, or NULL if no widget is owned. + GtkWidget* get() const { return widget_; } + GtkWidget* operator->() const { return widget_; } + + // Takes ownership of a widget, by taking the initial floating reference of + // the GtkWidget. It is expected that Own() is called right after the widget + // has been created, and before any other references to the widget might have + // been added. It is valid to never call Own(), in which case Destroy() will + // do nothing. If Own() has been called, you must explicitly call Destroy(). + void Own(GtkWidget* widget); + + // You must call Destroy() after you have called Own(). Calling Destroy() + // will call gtk_widget_destroy(), and drop our reference to the widget. + // After a call to Destroy(), you may call Own() again. NOTE: It is expected + // that after gtk_widget_destroy we will be holding the only reference left + // on the object. We assert this in debug mode to help catch any leaks. + void Destroy(); + + private: + GtkWidget* widget_; + + DISALLOW_COPY_AND_ASSIGN(OwnedWidgetGtk); +}; + +#endif // CHROME_COMMON_OWNED_WIDGET_GTK_H_ diff --git a/chrome/common/page_transition_types.cc b/chrome/common/page_transition_types.cc new file mode 100644 index 0000000..bf686f9 --- /dev/null +++ b/chrome/common/page_transition_types.cc @@ -0,0 +1,36 @@ +// Copyright (c) 2010 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 "chrome/common/page_transition_types.h" + +#include "base/logging.h" + +// static +PageTransition::Type PageTransition::FromInt(int32 type) { + if (!ValidType(type)) { + NOTREACHED() << "Invalid transition type " << type; + + // Return a safe default so we don't have corrupt data in release mode. + return LINK; + } + return static_cast<Type>(type); +} + +// static +const char* PageTransition::CoreTransitionString(Type type) { + switch (type & PageTransition::CORE_MASK) { + case 0: return "link"; + case 1: return "typed"; + case 2: return "auto_bookmark"; + case 3: return "auto_subframe"; + case 4: return "manual_subframe"; + case 5: return "generated"; + case 6: return "start_page"; + case 7: return "form_submit"; + case 8: return "reload"; + case 9: return "keyword"; + case 10: return "keyword_generated"; + } + return NULL; +} diff --git a/chrome/common/page_transition_types.h b/chrome/common/page_transition_types.h new file mode 100644 index 0000000..592fc29 --- /dev/null +++ b/chrome/common/page_transition_types.h @@ -0,0 +1,161 @@ +// Copyright (c) 2010 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 CHROME_COMMON_PAGE_TRANSITION_TYPES_H__ +#define CHROME_COMMON_PAGE_TRANSITION_TYPES_H__ + +#include "base/basictypes.h" + +// This class is for scoping only. +class PageTransition { + public: + // Types of transitions between pages. These are stored in the history + // database to separate visits, and are reported by the renderer for page + // navigations. + // + // WARNING: don't change these numbers. They are written directly into the + // history database, so future versions will need the same values to match + // the enums. + // + // A type is made of a core value and a set of qualifiers. A type has one + // core value and 0 or or more qualifiers. + enum { + // User got to this page by clicking a link on another page. + LINK = 0, + + // User got this page by typing the URL in the URL bar. This should not be + // used for cases where the user selected a choice that didn't look at all + // like a URL; see GENERATED below. + // + // We also use this for other "explicit" navigation actions. + TYPED = 1, + + // User got to this page through a suggestion in the UI, for example, + // through the destinations page. + AUTO_BOOKMARK = 2, + + // This is a subframe navigation. This is any content that is automatically + // loaded in a non-toplevel frame. For example, if a page consists of + // several frames containing ads, those ad URLs will have this transition + // type. The user may not even realize the content in these pages is a + // separate frame, so may not care about the URL (see MANUAL below). + AUTO_SUBFRAME = 3, + + // For subframe navigations that are explicitly requested by the user and + // generate new navigation entries in the back/forward list. These are + // probably more important than frames that were automatically loaded in + // the background because the user probably cares about the fact that this + // link was loaded. + MANUAL_SUBFRAME = 4, + + // User got to this page by typing in the URL bar and selecting an entry + // that did not look like a URL. For example, a match might have the URL + // of a Google search result page, but appear like "Search Google for ...". + // These are not quite the same as TYPED navigations because the user + // didn't type or see the destination URL. + // See also KEYWORD. + GENERATED = 5, + + // The page was specified in the command line or is the start page. + START_PAGE = 6, + + // The user filled out values in a form and submitted it. NOTE that in + // some situations submitting a form does not result in this transition + // type. This can happen if the form uses script to submit the contents. + FORM_SUBMIT = 7, + + // The user "reloaded" the page, either by hitting the reload button or by + // hitting enter in the address bar. NOTE: This is distinct from the + // concept of whether a particular load uses "reload semantics" (i.e. + // bypasses cached data). For this reason, lots of code needs to pass + // around the concept of whether a load should be treated as a "reload" + // separately from their tracking of this transition type, which is mainly + // used for proper scoring for consumers who care about how frequently a + // user typed/visited a particular URL. + // + // SessionRestore and undo tab close use this transition type too. + RELOAD = 8, + + // The url was generated from a replaceable keyword other than the default + // search provider. If the user types a keyword (which also applies to + // tab-to-search) in the omnibox this qualifier is applied to the transition + // type of the generated url. TemplateURLModel then may generate an + // additional visit with a transition type of KEYWORD_GENERATED against the + // url 'http://' + keyword. For example, if you do a tab-to-search against + // wikipedia the generated url has a transition qualifer of KEYWORD, and + // TemplateURLModel generates a visit for 'wikipedia.org' with a transition + // type of KEYWORD_GENERATED. + KEYWORD = 9, + + // Corresponds to a visit generated for a keyword. See description of + // KEYWORD for more details. + KEYWORD_GENERATED = 10, + + // ADDING NEW CORE VALUE? Be sure to update the LAST_CORE and CORE_MASK + // values below. Also update CoreTransitionString(). + LAST_CORE = KEYWORD_GENERATED, + CORE_MASK = 0xFF, + + // Qualifiers + // Any of the core values above can be augmented by one or more qualifiers. + // These qualifiers further define the transition. + + // The beginning of a navigation chain. + CHAIN_START = 0x10000000, + + // The last transition in a redirect chain. + CHAIN_END = 0x20000000, + + // Redirects caused by JavaScript or a meta refresh tag on the page. + CLIENT_REDIRECT = 0x40000000, + + // Redirects sent from the server by HTTP headers. It might be nice to + // break this out into 2 types in the future, permanent or temporary, if we + // can get that information from WebKit. + SERVER_REDIRECT = 0x80000000, + + // Used to test whether a transition involves a redirect. + IS_REDIRECT_MASK = 0xC0000000, + + // General mask defining the bits used for the qualifiers. + QUALIFIER_MASK = 0xFFFFFF00 + }; + + // The type used for the bitfield. + typedef unsigned int Type; + + static bool ValidType(int32 type) { + Type t = StripQualifier(static_cast<Type>(type)); + return (t <= LAST_CORE); + } + + static Type FromInt(int32 type); + + // Returns true if the given transition is a top-level frame transition, or + // false if the transition was for a subframe. + static bool IsMainFrame(Type type) { + int32 t = StripQualifier(type); + return (t != AUTO_SUBFRAME && t != MANUAL_SUBFRAME); + } + + // Returns whether a transition involves a redirection + static bool IsRedirect(Type type) { + return (type & IS_REDIRECT_MASK) != 0; + } + + // Simplifies the provided transition by removing any qualifier + static Type StripQualifier(Type type) { + return static_cast<Type>(type & ~QUALIFIER_MASK); + } + + // Return the qualifier + static int32 GetQualifier(Type type) { + return type & QUALIFIER_MASK; + } + + // Return a string version of the core type values. + static const char* CoreTransitionString(Type type); +}; + +#endif // CHROME_COMMON_PAGE_TRANSITION_TYPES_H__ diff --git a/chrome/common/page_zoom.h b/chrome/common/page_zoom.h new file mode 100644 index 0000000..fa2f5bb --- /dev/null +++ b/chrome/common/page_zoom.h @@ -0,0 +1,22 @@ +// Copyright (c) 2009 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 CHROME_COMMON_PAGE_ZOOM_H_ +#define CHROME_COMMON_PAGE_ZOOM_H_ + +class PageZoom { + public: + // This enum is the parameter to various text/page zoom commands so we know + // what the specific zoom command is. + enum Function { + ZOOM_OUT = -1, + RESET = 0, + ZOOM_IN = 1, + }; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(PageZoom); +}; + +#endif // CHROME_COMMON_PAGE_ZOOM_H_ diff --git a/chrome/common/pepper_plugin_registry.cc b/chrome/common/pepper_plugin_registry.cc new file mode 100644 index 0000000..2ed484e --- /dev/null +++ b/chrome/common/pepper_plugin_registry.cc @@ -0,0 +1,163 @@ +// Copyright (c) 2010 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 "chrome/common/pepper_plugin_registry.h" + +#include "base/command_line.h" +#include "base/file_util.h" +#include "base/path_service.h" +#include "base/string_util.h" +#include "base/utf_string_conversions.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/chrome_switches.h" +#include "remoting/client/plugin/pepper_entrypoints.h" + +// static +PepperPluginRegistry* PepperPluginRegistry::GetInstance() { + static PepperPluginRegistry registry; + return ®istry; +} + +// static +void PepperPluginRegistry::GetList(std::vector<PepperPluginInfo>* plugins) { + InternalPluginInfoList internal_plugin_info; + GetInternalPluginInfo(&internal_plugin_info); + for (InternalPluginInfoList::const_iterator it = + internal_plugin_info.begin(); + it != internal_plugin_info.end(); + ++it) { + plugins->push_back(*it); + } + + GetPluginInfoFromSwitch(plugins); + GetExtraPlugins(plugins); +} + +// static +void PepperPluginRegistry::GetPluginInfoFromSwitch( + std::vector<PepperPluginInfo>* plugins) { + const std::wstring& value = CommandLine::ForCurrentProcess()->GetSwitchValue( + switches::kRegisterPepperPlugins); + if (value.empty()) + return; + + // FORMAT: + // command-line = <plugin-entry> + *( LWS + "," + LWS + <plugin-entry> ) + // plugin-entry = <file-path> + ["#" + <name> + ["#" + <description>]] + + // *1( LWS + ";" + LWS + <mime-type> ) + + std::vector<std::wstring> modules; + SplitString(value, ',', &modules); + for (size_t i = 0; i < modules.size(); ++i) { + std::vector<std::wstring> parts; + SplitString(modules[i], ';', &parts); + if (parts.size() < 2) { + DLOG(ERROR) << "Required mime-type not found"; + continue; + } + + std::vector<std::wstring> name_parts; + SplitString(parts[0], '#', &name_parts); + + PepperPluginInfo plugin; + plugin.path = FilePath::FromWStringHack(name_parts[0]); + if (name_parts.size() > 1) + plugin.name = WideToUTF8(name_parts[1]); + if (name_parts.size() > 2) + plugin.type_descriptions = WideToUTF8(name_parts[2]); + for (size_t j = 1; j < parts.size(); ++j) + plugin.mime_types.push_back(WideToASCII(parts[j])); + + plugins->push_back(plugin); + } +} + +// static +void PepperPluginRegistry::GetExtraPlugins( + std::vector<PepperPluginInfo>* plugins) { + FilePath path; + if (PathService::Get(chrome::FILE_PDF_PLUGIN, &path) && + file_util::PathExists(path)) { + PepperPluginInfo pdf; + pdf.path = path; + pdf.name = "Chrome PDF Viewer"; + pdf.mime_types.push_back("application/pdf"); + pdf.file_extensions = "pdf"; + pdf.type_descriptions = "Portable Document Format"; + plugins->push_back(pdf); + } +} + +// static +void PepperPluginRegistry::GetInternalPluginInfo( + InternalPluginInfoList* plugin_info) { + // Currently, to centralize the internal plugin registration logic, we + // hardcode the list of plugins, mimetypes, and registration information + // in this function. This is gross, but because the GetList() function is + // called from both the renderer and browser the other option is to force a + // special register function for each plugin to be called by both + // RendererMain() and BrowserMain(). This seemed like the better tradeoff. + // + // TODO(ajwong): Think up a better way to maintain the plugin registration + // information. Pehraps by construction of a singly linked list of + // plugin initializers that is built with static initializers? + +#if defined(ENABLE_REMOTING) + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableChromoting)) { + InternalPluginInfo info; + // Add the chromoting plugin. + info.path = + FilePath(FILE_PATH_LITERAL("internal-chromoting")); + info.mime_types.push_back("pepper-application/x-chromoting"); + info.entry_points.get_interface = remoting::PPP_GetInterface; + info.entry_points.initialize_module = remoting::PPP_InitializeModule; + info.entry_points.shutdown_module = remoting::PPP_ShutdownModule; + + plugin_info->push_back(info); + } +#endif +} + +pepper::PluginModule* PepperPluginRegistry::GetModule( + const FilePath& path) const { + ModuleMap::const_iterator it = modules_.find(path); + if (it == modules_.end()) + return NULL; + return it->second; +} + +PepperPluginRegistry::PepperPluginRegistry() { + InternalPluginInfoList internal_plugin_info; + GetInternalPluginInfo(&internal_plugin_info); + // Register modules for these suckers. + for (InternalPluginInfoList::const_iterator it = + internal_plugin_info.begin(); + it != internal_plugin_info.end(); + ++it) { + const FilePath& path = it->path; + ModuleHandle module = + pepper::PluginModule::CreateInternalModule(it->entry_points); + if (!module) { + DLOG(ERROR) << "Failed to load pepper module: " << path.value(); + continue; + } + modules_[path] = module; + } + + // Add the modules specified on the command line last so that they can + // override the internal plugins. + std::vector<PepperPluginInfo> plugins; + GetPluginInfoFromSwitch(&plugins); + GetExtraPlugins(&plugins); + for (size_t i = 0; i < plugins.size(); ++i) { + const FilePath& path = plugins[i].path; + ModuleHandle module = pepper::PluginModule::CreateModule(path); + if (!module) { + DLOG(ERROR) << "Failed to load pepper module: " << path.value(); + continue; + } + modules_[path] = module; + } +} diff --git a/chrome/common/pepper_plugin_registry.h b/chrome/common/pepper_plugin_registry.h new file mode 100644 index 0000000..a728381 --- /dev/null +++ b/chrome/common/pepper_plugin_registry.h @@ -0,0 +1,52 @@ +// Copyright (c) 2010 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 CHROME_COMMON_PEPPER_PLUGIN_REGISTRY_H_ +#define CHROME_COMMON_PEPPER_PLUGIN_REGISTRY_H_ + +#include <string> +#include <map> +#include <vector> + +#include "webkit/glue/plugins/pepper_plugin_module.h" + +struct PepperPluginInfo { + FilePath path; // Internal plugins are of the form "internal-[name]". + std::vector<std::string> mime_types; + std::string name; + std::string description; + std::string file_extensions; + std::string type_descriptions; +}; + +// This class holds references to all of the known pepper plugin modules. +class PepperPluginRegistry { + public: + static PepperPluginRegistry* GetInstance(); + + // Returns the list of known pepper plugins. This method is static so that + // it can be used by the browser process, which has no need to load the + // pepper plugin modules. + static void GetList(std::vector<PepperPluginInfo>* plugins); + + pepper::PluginModule* GetModule(const FilePath& path) const; + + private: + static void GetPluginInfoFromSwitch(std::vector<PepperPluginInfo>* plugins); + static void GetExtraPlugins(std::vector<PepperPluginInfo>* plugins); + + struct InternalPluginInfo : public PepperPluginInfo { + pepper::PluginModule::EntryPoints entry_points; + }; + typedef std::vector<InternalPluginInfo> InternalPluginInfoList; + static void GetInternalPluginInfo(InternalPluginInfoList* plugin_info); + + PepperPluginRegistry(); + + typedef scoped_refptr<pepper::PluginModule> ModuleHandle; + typedef std::map<FilePath, ModuleHandle> ModuleMap; + ModuleMap modules_; +}; + +#endif // CHROME_COMMON_PEPPER_PLUGIN_REGISTRY_H_ diff --git a/chrome/common/plugin_carbon_interpose_constants_mac.cc b/chrome/common/plugin_carbon_interpose_constants_mac.cc new file mode 100644 index 0000000..d7f6f91 --- /dev/null +++ b/chrome/common/plugin_carbon_interpose_constants_mac.cc @@ -0,0 +1,17 @@ +// Copyright (c) 2009 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. + +#if !defined(__LP64__) + +#include "chrome/common/plugin_carbon_interpose_constants_mac.h" + +namespace plugin_interpose_strings { + +const char kDYLDInsertLibrariesKey[] = "DYLD_INSERT_LIBRARIES"; +const char kInterposeLibraryPath[] = + "@executable_path/libplugin_carbon_interpose.dylib"; + +} // namespace plugin_interpose_strings + +#endif // !__LP64__ diff --git a/chrome/common/plugin_carbon_interpose_constants_mac.h b/chrome/common/plugin_carbon_interpose_constants_mac.h new file mode 100644 index 0000000..321dd84 --- /dev/null +++ b/chrome/common/plugin_carbon_interpose_constants_mac.h @@ -0,0 +1,20 @@ +// Copyright (c) 2009 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 CHROME_COMMON_PLUGIN_CARBON_INTERPOSE_CONSTANTS_MAC_H_ +#define CHROME_COMMON_PLUGIN_CARBON_INTERPOSE_CONSTANTS_MAC_H_ + +#if !defined(__LP64__) + +// Strings used in setting up Carbon interposing for the plugin process. +namespace plugin_interpose_strings { + +extern const char kDYLDInsertLibrariesKey[]; +extern const char kInterposeLibraryPath[]; + +} // namespace plugin_interpose_strings + +#endif // !__LP64__ + +#endif // CHROME_BROWSER_PLUGIN_CARBON_INTERPOSE_CONSTANTS_MAC_H_ diff --git a/chrome/common/plugin_group.cc b/chrome/common/plugin_group.cc new file mode 100644 index 0000000..5df39b3 --- /dev/null +++ b/chrome/common/plugin_group.cc @@ -0,0 +1,343 @@ +// Copyright (c) 2010 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 "chrome/common/plugin_group.h" + +#include "base/string_util.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "base/version.h" +#include "webkit/glue/plugins/plugin_list.h" + +#if defined(OS_MACOSX) +// Plugin Groups for Mac. +// Plugins are listed here as soon as vulnerabilities and solutions +// (new versions) are published. +// TODO(panayiotis): Track Java as soon as it's supported on Chrome Mac. +// TODO(panayiotis): Get the Real Player version on Mac, somehow. +static const PluginGroupDefinition kGroupDefinitions[] = { + { "Quicktime", "QuickTime Plug-in", "", "", "7.6.6", + "http://www.apple.com/quicktime/download/" }, + { "Flash", "Shockwave Flash", "", "", "10.1.53", + "http://get.adobe.com/flashplayer/" }, + { "Silverlight 3", "Silverlight", "0", "4", "3.0.50106.0", + "http://go.microsoft.com/fwlink/?LinkID=185927" }, + { "Silverlight 4", "Silverlight", "4", "5", "", + "http://go.microsoft.com/fwlink/?LinkID=185927" }, + { "Flip4Mac", "Flip4Mac", "", "", "2.2.1", + "http://www.telestream.net/flip4mac-wmv/overview.htm" }, + { "Shockwave", "Shockwave for Director", "", "", "11.5.7.609", + "http://www.adobe.com/shockwave/download/" } +}; + +#elif defined(OS_WIN) +// TODO(panayiotis): We should group "RealJukebox NS Plugin" with the rest of +// the RealPlayer files. +static const PluginGroupDefinition kGroupDefinitions[] = { + { "Quicktime", "QuickTime Plug-in", "", "", "7.6.6", + "http://www.apple.com/quicktime/download/" }, + { "Java 6", "Java", "", "6", "6.0.200", + "http://www.java.com/" }, + { "Adobe Reader 9", "Adobe Acrobat", "9", "10", "9.3.3", + "http://get.adobe.com/reader/" }, + { "Adobe Reader 8", "Adobe Acrobat", "0", "9", "8.2.3", + "http://get.adobe.com/reader/" }, + { "Flash", "Shockwave Flash", "", "", "10.1.53", + "http://get.adobe.com/flashplayer/" }, + { "Silverlight 3", "Silverlight", "0", "4", "3.0.50106.0", + "http://go.microsoft.com/fwlink/?LinkID=185927" }, + { "Silverlight 4", "Silverlight", "4", "5", "", + "http://go.microsoft.com/fwlink/?LinkID=185927" }, + { "Shockwave", "Shockwave for Director", "", "", "11.5.7.609", + "http://www.adobe.com/shockwave/download/" }, + { "DivX Player", "DivX Web Player", "", "", "1.4.3.4", + "http://download.divx.com/divx/autoupdate/player/DivXWebPlayerInstaller.exe" }, + // These are here for grouping, no vulnerabilies known. + { "Windows Media Player", "Windows Media Player", "", "", "", "" }, + { "Microsoft Office", "Microsoft Office", "", "", "", "" }, + // TODO(panayiotis): The vulnerable versions are + // (v >= 6.0.12.1040 && v <= 6.0.12.1663) + // || v == 6.0.12.1698 || v == 6.0.12.1741 + { "RealPlayer", "RealPlayer", "", "", "", + "http://www.adobe.com/shockwave/download/" }, +}; + +#else +static const PluginGroupDefinition kGroupDefinitions[] = {}; +#endif + +/*static*/ +std::set<string16>* PluginGroup::policy_disabled_puglins_; + +/*static*/ +const PluginGroupDefinition* PluginGroup::GetPluginGroupDefinitions() { + return kGroupDefinitions; +} + +/*static*/ +size_t PluginGroup::GetPluginGroupDefinitionsSize() { + // TODO(viettrungluu): |arraysize()| doesn't work with zero-size arrays. + return ARRAYSIZE_UNSAFE(kGroupDefinitions); +} + +/*static*/ +void PluginGroup::SetPolicyDisabledPluginSet(const std::set<string16>& set) { + if (!policy_disabled_puglins_) { + policy_disabled_puglins_ = new std::set<string16>(); + *policy_disabled_puglins_ = set; + } +} + +/*static*/ +bool PluginGroup::IsPluginNameDisabledByPolicy(const string16& plugin_name) { + return policy_disabled_puglins_ && + policy_disabled_puglins_->find(plugin_name) != + policy_disabled_puglins_->end(); +} + +/*static*/ +bool PluginGroup::IsPluginPathDisabledByPolicy(const FilePath& plugin_path) { + std::vector<WebPluginInfo> plugins; + NPAPI::PluginList::Singleton()->GetPlugins(false, &plugins); + for (std::vector<WebPluginInfo>::const_iterator it = plugins.begin(); + it != plugins.end(); + ++it) { + if (FilePath::CompareEqualIgnoreCase(it->path.value(), + plugin_path.value()) && IsPluginNameDisabledByPolicy(it->name)) { + return true; + } + } + return false; +} + +PluginGroup::PluginGroup(const string16& group_name, + const string16& name_matcher, + const std::string& version_range_low, + const std::string& version_range_high, + const std::string& min_version, + const std::string& update_url) { + group_name_ = group_name; + name_matcher_ = name_matcher; + version_range_low_str_ = version_range_low; + if (!version_range_low.empty()) { + version_range_low_.reset( + Version::GetVersionFromString(version_range_low)); + } + version_range_high_str_ = version_range_high; + if (!version_range_high.empty()) { + version_range_high_.reset( + Version::GetVersionFromString(version_range_high)); + } + min_version_str_ = min_version; + if (!min_version.empty()) { + min_version_.reset(Version::GetVersionFromString(min_version)); + } + update_url_ = update_url; + enabled_ = false; + max_version_.reset(Version::GetVersionFromString("0")); +} + +PluginGroup* PluginGroup::FromPluginGroupDefinition( + const PluginGroupDefinition& definition) { + return new PluginGroup(ASCIIToUTF16(definition.name), + ASCIIToUTF16(definition.name_matcher), + definition.version_matcher_low, + definition.version_matcher_high, + definition.min_version, + definition.update_url); +} + +PluginGroup* PluginGroup::FromWebPluginInfo(const WebPluginInfo& wpi) { + // Create a matcher from the name of this plugin. + return new PluginGroup(wpi.name, wpi.name, + "", "", "", ""); +} + +PluginGroup* PluginGroup::FindHardcodedPluginGroup(const WebPluginInfo& info) { + static std::vector<linked_ptr<PluginGroup> >* hardcoded_plugin_groups = NULL; + if (!hardcoded_plugin_groups) { + std::vector<linked_ptr<PluginGroup> >* groups = + new std::vector<linked_ptr<PluginGroup> >(); + const PluginGroupDefinition* definitions = GetPluginGroupDefinitions(); + for (size_t i = 0; i < GetPluginGroupDefinitionsSize(); ++i) { + PluginGroup* definition_group = PluginGroup::FromPluginGroupDefinition( + definitions[i]); + groups->push_back(linked_ptr<PluginGroup>(definition_group)); + } + hardcoded_plugin_groups = groups; + } + + // See if this plugin matches any of the hardcoded groups. + PluginGroup* hardcoded_group = FindGroupMatchingPlugin( + *hardcoded_plugin_groups, info); + if (hardcoded_group) { + // Make a copy. + return hardcoded_group->Copy(); + } else { + // Not found in our hardcoded list, create a new one. + return PluginGroup::FromWebPluginInfo(info); + } +} + +PluginGroup* PluginGroup::FindGroupMatchingPlugin( + std::vector<linked_ptr<PluginGroup> >& plugin_groups, + const WebPluginInfo& plugin) { + for (std::vector<linked_ptr<PluginGroup> >::iterator it = + plugin_groups.begin(); + it != plugin_groups.end(); + ++it) { + if ((*it)->Match(plugin)) { + return it->get(); + } + } + return NULL; +} + +bool PluginGroup::Match(const WebPluginInfo& plugin) const { + if (name_matcher_.empty()) { + return false; + } + + // Look for the name matcher anywhere in the plugin name. + if (plugin.name.find(name_matcher_) == string16::npos) { + return false; + } + + if (version_range_low_.get() == NULL || + version_range_high_.get() == NULL) { + return true; + } + + // There's a version range, we must be in it. + scoped_ptr<Version> plugin_version( + Version::GetVersionFromString(UTF16ToWide(plugin.version))); + if (plugin_version.get() == NULL) { + // No version could be extracted, assume we don't match the range. + return false; + } + + // We match if we are in the range: [low, high) + return (version_range_low_->CompareTo(*plugin_version) <= 0 && + version_range_high_->CompareTo(*plugin_version) > 0); +} + +void PluginGroup::AddPlugin(const WebPluginInfo& plugin, int position) { + web_plugin_infos_.push_back(plugin); + // The position of this plugin relative to the global list of plugins. + web_plugin_positions_.push_back(position); + description_ = plugin.desc; + + // A group is enabled if any of the files are enabled. + if (plugin.enabled) { + enabled_ = true; + } + + // update max_version_. Remove spaces and ')' from the version string, + // Replace any instances of 'r', ',' or '(' with a dot. + std::wstring version = UTF16ToWide(plugin.version); + RemoveChars(version, L") ", &version); + std::replace(version.begin(), version.end(), 'r', '.'); + std::replace(version.begin(), version.end(), ',', '.'); + std::replace(version.begin(), version.end(), '(', '.'); + + scoped_ptr<Version> plugin_version( + Version::GetVersionFromString(version)); + if (plugin_version.get() != NULL) { + if (plugin_version->CompareTo(*(max_version_)) > 0) { + max_version_.reset(plugin_version.release()); + } + } +} + +DictionaryValue* PluginGroup::GetSummary() const { + DictionaryValue* result = new DictionaryValue(); + result->SetStringFromUTF16(L"name", group_name_); + result->SetBoolean(L"enabled", enabled_); + return result; +} + +DictionaryValue* PluginGroup::GetDataForUI() const { + DictionaryValue* result = new DictionaryValue(); + result->SetStringFromUTF16(L"name", group_name_); + result->SetStringFromUTF16(L"description", description_); + result->SetString(L"version", max_version_->GetString()); + result->SetString(L"update_url", update_url_); + result->SetBoolean(L"critical", IsVulnerable()); + + bool group_disabled_by_policy = IsPluginNameDisabledByPolicy(group_name_); + if (group_disabled_by_policy) { + result->SetString(L"enabledMode", L"disabledByPolicy"); + } else { + result->SetString(L"enabledMode", + enabled_ ? L"enabled" : L"disabledByUser"); + } + + ListValue* plugin_files = new ListValue(); + for (size_t i = 0; i < web_plugin_infos_.size(); ++i) { + const WebPluginInfo& web_plugin = web_plugin_infos_[i]; + int priority = web_plugin_positions_[i]; + DictionaryValue* plugin_file = new DictionaryValue(); + plugin_file->SetStringFromUTF16(L"name", web_plugin.name); + plugin_file->SetStringFromUTF16(L"description", web_plugin.desc); + plugin_file->SetString(L"path", web_plugin.path.value()); + plugin_file->SetStringFromUTF16(L"version", web_plugin.version); + bool plugin_disabled_by_policy = group_disabled_by_policy || + IsPluginNameDisabledByPolicy(web_plugin.name); + if (plugin_disabled_by_policy) { + result->SetString(L"enabledMode", L"disabledByPolicy"); + } else { + result->SetString(L"enabledMode", + web_plugin.enabled ? L"enabled" : L"disabledByUser"); + } + plugin_file->SetInteger(L"priority", priority); + + ListValue* mime_types = new ListValue(); + for (std::vector<WebPluginMimeType>::const_iterator type_it = + web_plugin.mime_types.begin(); + type_it != web_plugin.mime_types.end(); + ++type_it) { + DictionaryValue* mime_type = new DictionaryValue(); + mime_type->SetString(L"mimeType", type_it->mime_type); + mime_type->SetStringFromUTF16(L"description", type_it->description); + + ListValue* file_extensions = new ListValue(); + for (std::vector<std::string>::const_iterator ext_it = + type_it->file_extensions.begin(); + ext_it != type_it->file_extensions.end(); + ++ext_it) { + file_extensions->Append(new StringValue(*ext_it)); + } + mime_type->Set(L"fileExtensions", file_extensions); + + mime_types->Append(mime_type); + } + plugin_file->Set(L"mimeTypes", mime_types); + + plugin_files->Append(plugin_file); + } + result->Set(L"plugin_files", plugin_files); + + return result; +} + +// Returns true if the latest version of this plugin group is vulnerable. +bool PluginGroup::IsVulnerable() const { + if (min_version_.get() == NULL || max_version_->GetString() == "0") { + return false; + } + return max_version_->CompareTo(*min_version_) < 0; +} + +void PluginGroup::Enable(bool enable) { + for (std::vector<WebPluginInfo>::const_iterator it = + web_plugin_infos_.begin(); + it != web_plugin_infos_.end(); ++it) { + if (enable && !IsPluginNameDisabledByPolicy(it->name)) { + NPAPI::PluginList::Singleton()->EnablePlugin(FilePath(it->path)); + } else { + NPAPI::PluginList::Singleton()->DisablePlugin(FilePath(it->path)); + } + } +} + diff --git a/chrome/common/plugin_group.h b/chrome/common/plugin_group.h new file mode 100644 index 0000000..f9f6ce3 --- /dev/null +++ b/chrome/common/plugin_group.h @@ -0,0 +1,129 @@ +// Copyright (c) 2010 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 CHROME_COMMON_PLUGIN_GROUP_H_ +#define CHROME_COMMON_PLUGIN_GROUP_H_ + +#include <set> +#include <vector> + +#include "base/linked_ptr.h" +#include "base/scoped_ptr.h" +#include "base/string16.h" +#include "base/version.h" +#include "webkit/glue/plugins/webplugininfo.h" + +class DictionaryValue; + +// Hard-coded definitions of plugin groups. +struct PluginGroupDefinition { + const char* name; // Name of this group. + const char* name_matcher; // Substring matcher for the plugin name. + const char* version_matcher_low; // Matchers for the plugin version. + const char* version_matcher_high; + const char* min_version; // Minimum secure version. + const char* update_url; // Location of latest secure version. +}; + + +// A PluginGroup contains at least one WebPluginInfo. +// In addition, it knows if the plugin is critically vulnerable. +class PluginGroup { + public: + // Creates a PluginGroup from a PluginGroupDefinition. + static PluginGroup* FromPluginGroupDefinition( + const PluginGroupDefinition& definition); + + // Creates a PluginGroup from a WebPluginInfo -- when no hard-coded + // definition is found. + static PluginGroup* FromWebPluginInfo(const WebPluginInfo& wpi); + + // Find a plugin group matching |info| in the list of hardcoded plugins. + static PluginGroup* FindHardcodedPluginGroup(const WebPluginInfo& info); + + // Configures the set of plugin names that are disabled by policy. + static void SetPolicyDisabledPluginSet(const std::set<string16>& set); + + // Tests to see if a plugin is on the blacklist using its name as + // the lookup key. + static bool IsPluginNameDisabledByPolicy(const string16& plugin_name); + + // Tests to see if a plugin is on the blacklist using its path as + // the lookup key. + static bool IsPluginPathDisabledByPolicy(const FilePath& plugin_path); + + // Find the PluginGroup matching a Plugin in a list of plugin groups. Returns + // NULL if no matching PluginGroup is found. + static PluginGroup* FindGroupMatchingPlugin( + std::vector<linked_ptr<PluginGroup> >& plugin_groups, + const WebPluginInfo& plugin); + + // Creates a copy of this plugin group. + PluginGroup* Copy() { + return new PluginGroup(group_name_, name_matcher_, version_range_low_str_, + version_range_high_str_, min_version_str_, + update_url_); + } + + // Returns true if the given plugin matches this group. + bool Match(const WebPluginInfo& plugin) const; + + // Adds the given plugin to this group. Provide the position of the + // plugin as given by PluginList so we can display its priority. + void AddPlugin(const WebPluginInfo& plugin, int position); + + // Enables/disables this group. This enables/disables all plugins in the + // group. + void Enable(bool enable); + + // Returns this group's name + const string16 GetGroupName() const { return group_name_; } + + // Returns a DictionaryValue with data to display in the UI. + DictionaryValue* GetDataForUI() const; + + // Returns a DictionaryValue with data to save in the preferences. + DictionaryValue* GetSummary() const; + + // Returns the update URL. + std::string GetUpdateURL() const { return update_url_; } + + // Returns true if the latest plugin in this group has known + // security problems. + bool IsVulnerable() const; + + private: + FRIEND_TEST_ALL_PREFIXES(PluginGroupTest, PluginGroupDefinition); + + static const PluginGroupDefinition* GetPluginGroupDefinitions(); + static size_t GetPluginGroupDefinitionsSize(); + + PluginGroup(const string16& group_name, + const string16& name_matcher, + const std::string& version_range_low, + const std::string& version_range_high, + const std::string& min_version, + const std::string& update_url); + + static std::set<string16>* policy_disabled_puglins_; + + string16 group_name_; + string16 name_matcher_; + std::string version_range_low_str_; + std::string version_range_high_str_; + scoped_ptr<Version> version_range_low_; + scoped_ptr<Version> version_range_high_; + string16 description_; + std::string update_url_; + bool enabled_; + std::string min_version_str_; + scoped_ptr<Version> min_version_; + scoped_ptr<Version> max_version_; + std::vector<WebPluginInfo> web_plugin_infos_; + std::vector<int> web_plugin_positions_; + + DISALLOW_COPY_AND_ASSIGN(PluginGroup); +}; + +#endif // CHROME_COMMON_PLUGIN_GROUP_H_ diff --git a/chrome/common/plugin_group_unittest.cc b/chrome/common/plugin_group_unittest.cc new file mode 100644 index 0000000..7def7c6 --- /dev/null +++ b/chrome/common/plugin_group_unittest.cc @@ -0,0 +1,113 @@ +// Copyright (c) 2010 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 "chrome/common/plugin_group.h" + +#include <string> +#include <vector> + +#include "base/scoped_ptr.h" +#include "base/string_util.h" +#include "base/values.h" +#include "base/version.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "webkit/glue/plugins/webplugininfo.h" + +static const PluginGroupDefinition kPluginDef = { + "MyPlugin", "MyPlugin", "", "", "3.0.44", "http://latest/" }; +static const PluginGroupDefinition kPluginDef3 = { + "MyPlugin 3", "MyPlugin", "0", "4", "3.0.44", "http://latest" }; +static const PluginGroupDefinition kPluginDef4 = { + "MyPlugin 4", "MyPlugin", "4", "5", "4.0.44", "http://latest" }; +static const PluginGroupDefinition kPluginDefNotVulnerable = { + "MyPlugin", "MyPlugin", "", "", "", "http://latest" }; + +// name, path, version, desc, mime_types, enabled. +static WebPluginInfo kPlugin2043 = { + ASCIIToUTF16("MyPlugin"), FilePath(), ASCIIToUTF16("2.0.43"), string16(), + std::vector<WebPluginMimeType>(), true }; +static WebPluginInfo kPlugin3043 = { + ASCIIToUTF16("MyPlugin"), FilePath(), ASCIIToUTF16("3.0.43"), string16(), + std::vector<WebPluginMimeType>(), true }; +static WebPluginInfo kPlugin3044 = { + ASCIIToUTF16("MyPlugin"), FilePath(), ASCIIToUTF16("3.0.44"), string16(), + std::vector<WebPluginMimeType>(), true }; +static WebPluginInfo kPlugin3045 = { + ASCIIToUTF16("MyPlugin"), FilePath(), ASCIIToUTF16("3.0.45"), string16(), + std::vector<WebPluginMimeType>(), true }; +static WebPluginInfo kPlugin4043 = { + ASCIIToUTF16("MyPlugin"), FilePath(), ASCIIToUTF16("4.0.43"), string16(), + std::vector<WebPluginMimeType>(), true }; + +class PluginGroupTest : public testing::Test { +}; + +TEST(PluginGroupTest, PluginGroupMatch) { + scoped_ptr<PluginGroup> group(PluginGroup::FromPluginGroupDefinition( + kPluginDef3)); + EXPECT_TRUE(group->Match(kPlugin3045)); + group->AddPlugin(kPlugin3045, 0); + EXPECT_FALSE(group->IsVulnerable()); +} + +TEST(PluginGroupTest, PluginGroupMatchMultipleFiles) { + scoped_ptr<PluginGroup> group(PluginGroup::FromPluginGroupDefinition( + kPluginDef3)); + EXPECT_TRUE(group->Match(kPlugin3043)); + group->AddPlugin(kPlugin3043, 0); + EXPECT_TRUE(group->IsVulnerable()); + + EXPECT_TRUE(group->Match(kPlugin3045)); + group->AddPlugin(kPlugin3045, 1); + EXPECT_FALSE(group->IsVulnerable()); +} + +TEST(PluginGroupTest, PluginGroupMatchCorrectVersion) { + scoped_ptr<PluginGroup> group(PluginGroup::FromPluginGroupDefinition( + kPluginDef3)); + EXPECT_TRUE(group->Match(kPlugin2043)); + EXPECT_TRUE(group->Match(kPlugin3043)); + EXPECT_FALSE(group->Match(kPlugin4043)); + + group.reset(PluginGroup::FromPluginGroupDefinition(kPluginDef4)); + EXPECT_FALSE(group->Match(kPlugin2043)); + EXPECT_FALSE(group->Match(kPlugin3043)); + EXPECT_TRUE(group->Match(kPlugin4043)); +} + +TEST(PluginGroupTest, PluginGroupDefinition) { + const PluginGroupDefinition* definitions = + PluginGroup::GetPluginGroupDefinitions(); + for (size_t i = 0; i < PluginGroup::GetPluginGroupDefinitionsSize(); ++i) { + scoped_ptr<PluginGroup> def_group( + PluginGroup::FromPluginGroupDefinition(definitions[i])); + ASSERT_TRUE(def_group.get() != NULL); + EXPECT_FALSE(def_group->Match(kPlugin2043)); + } +} + +TEST(PluginGroupTest, VersionExtraction) { + // Some real-world plugin versions (spaces, commata, parentheses, 'r', oh my) + const char* versions[][2] = { + { "7.6.6 (1671)", "7.6.6.1671" }, // Quicktime + { "2, 0, 0, 254", "2.0.0.254" }, // DivX + { "3, 0, 0, 0", "3.0.0.0" }, // Picasa + { "1, 0, 0, 1", "1.0.0.1" }, // Earth + { "10,0,45,2", "10.0.45.2" }, // Flash + { "11.5.7r609", "11.5.7.609"} // Shockwave + }; + + for (size_t i = 0; i < arraysize(versions); i++) { + const WebPluginInfo plugin = { + ASCIIToUTF16("Blah Plugin"), FilePath(), ASCIIToUTF16(versions[i][0]), + string16(),std::vector<WebPluginMimeType>(), true }; + scoped_ptr<PluginGroup> group(PluginGroup::FromWebPluginInfo(plugin)); + EXPECT_TRUE(group->Match(plugin)); + group->AddPlugin(plugin, 0); + scoped_ptr<DictionaryValue> data(group->GetDataForUI()); + std::string version; + data->GetString(L"version", &version); + EXPECT_EQ(versions[i][1], version); + } +} diff --git a/chrome/common/plugin_messages.h b/chrome/common/plugin_messages.h new file mode 100644 index 0000000..82116d8 --- /dev/null +++ b/chrome/common/plugin_messages.h @@ -0,0 +1,433 @@ +// Copyright (c) 2009 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. + +// Defines messages between the browser and plugin process, as well as between +// the renderer and plugin process. +// +// See render_message* for information about the multi-pass include of headers. + +#ifndef CHROME_COMMON_PLUGIN_MESSAGES_H_ +#define CHROME_COMMON_PLUGIN_MESSAGES_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "chrome/common/common_param_traits.h" +#include "chrome/common/webkit_param_traits.h" +#include "gfx/native_widget_types.h" +#include "gfx/rect.h" +#include "googleurl/src/gurl.h" +#include "ipc/ipc_message_utils.h" +#include "third_party/npapi/bindings/npapi.h" +#include "third_party/WebKit/WebKit/chromium/public/WebBindings.h" +#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h" +#include "webkit/glue/npruntime_util.h" + +// Name prefix of the event handle when a message box is displayed. +#define kMessageBoxEventPrefix L"message_box_active" + +// Structures for messages that have too many parameters to be put in a +// predefined IPC message. + +struct PluginMsg_Init_Params { + gfx::NativeViewId containing_window; + GURL url; + GURL page_url; + std::vector<std::string> arg_names; + std::vector<std::string> arg_values; + bool load_manually; + int host_render_view_routing_id; +#if defined(OS_MACOSX) + gfx::Rect containing_window_frame; + gfx::Rect containing_content_frame; + bool containing_window_has_focus; +#endif +}; + +struct PluginHostMsg_URLRequest_Params { + std::string url; + std::string method; + std::string target; + std::vector<char> buffer; + int notify_id; + bool popups_allowed; +}; + +struct PluginMsg_DidReceiveResponseParams { + unsigned long id; + std::string mime_type; + std::string headers; + uint32 expected_length; + uint32 last_modified; + bool request_is_seekable; +}; + +struct NPIdentifier_Param { + NPIdentifier identifier; +}; + +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_ParamEnum type; + bool bool_value; + int int_value; + double double_value; + std::string string_value; + int npobject_routing_id; +}; + +struct PluginMsg_UpdateGeometry_Param { + gfx::Rect window_rect; + gfx::Rect clip_rect; + TransportDIB::Handle windowless_buffer; + TransportDIB::Handle background_buffer; + bool transparent; + +#if defined(OS_MACOSX) + // This field contains a key that the plug-in process is expected to return + // to the renderer in its ACK message, unless the value is -1, in which case + // no ACK message is required. Other than the special -1 value, the values + // used in ack_key are opaque to the plug-in process. + int ack_key; +#endif +}; + + +namespace IPC { + +// Traits for PluginMsg_Init_Params structure to pack/unpack. +template <> +struct ParamTraits<PluginMsg_Init_Params> { + typedef PluginMsg_Init_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.containing_window); + WriteParam(m, p.url); + WriteParam(m, p.page_url); + DCHECK(p.arg_names.size() == p.arg_values.size()); + WriteParam(m, p.arg_names); + WriteParam(m, p.arg_values); + WriteParam(m, p.load_manually); + WriteParam(m, p.host_render_view_routing_id); +#if defined(OS_MACOSX) + WriteParam(m, p.containing_window_frame); + WriteParam(m, p.containing_content_frame); + WriteParam(m, p.containing_window_has_focus); +#endif + } + static bool Read(const Message* m, void** iter, param_type* p) { + return ReadParam(m, iter, &p->containing_window) && + ReadParam(m, iter, &p->url) && + ReadParam(m, iter, &p->page_url) && + ReadParam(m, iter, &p->arg_names) && + ReadParam(m, iter, &p->arg_values) && + ReadParam(m, iter, &p->load_manually) && + ReadParam(m, iter, &p->host_render_view_routing_id) +#if defined(OS_MACOSX) + && + ReadParam(m, iter, &p->containing_window_frame) && + ReadParam(m, iter, &p->containing_content_frame) && + ReadParam(m, iter, &p->containing_window_has_focus) +#endif + ; + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.containing_window, l); + l->append(L", "); + LogParam(p.url, l); + l->append(L", "); + LogParam(p.page_url, l); + l->append(L", "); + LogParam(p.arg_names, l); + l->append(L", "); + LogParam(p.arg_values, l); + l->append(L", "); + LogParam(p.load_manually, l); + l->append(L", "); + LogParam(p.host_render_view_routing_id, l); +#if defined(OS_MACOSX) + l->append(L", "); + LogParam(p.containing_window_frame, l); + l->append(L", "); + LogParam(p.containing_content_frame, l); + l->append(L", "); + LogParam(p.containing_window_has_focus, l); +#endif + l->append(L")"); + } +}; + +template <> +struct ParamTraits<PluginHostMsg_URLRequest_Params> { + typedef PluginHostMsg_URLRequest_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.url); + WriteParam(m, p.method); + WriteParam(m, p.target); + WriteParam(m, p.buffer); + WriteParam(m, p.notify_id); + WriteParam(m, p.popups_allowed); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->url) && + ReadParam(m, iter, &p->method) && + ReadParam(m, iter, &p->target) && + ReadParam(m, iter, &p->buffer) && + ReadParam(m, iter, &p->notify_id) && + ReadParam(m, iter, &p->popups_allowed); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.url, l); + l->append(L", "); + LogParam(p.method, l); + l->append(L", "); + LogParam(p.target, l); + l->append(L", "); + LogParam(p.buffer, l); + l->append(L", "); + LogParam(p.notify_id, l); + l->append(L", "); + LogParam(p.popups_allowed, l); + l->append(L")"); + } +}; + +template <> +struct ParamTraits<PluginMsg_DidReceiveResponseParams> { + typedef PluginMsg_DidReceiveResponseParams param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.id); + WriteParam(m, p.mime_type); + WriteParam(m, p.headers); + WriteParam(m, p.expected_length); + WriteParam(m, p.last_modified); + WriteParam(m, p.request_is_seekable); + } + static bool Read(const Message* m, void** iter, param_type* r) { + return + ReadParam(m, iter, &r->id) && + ReadParam(m, iter, &r->mime_type) && + ReadParam(m, iter, &r->headers) && + ReadParam(m, iter, &r->expected_length) && + ReadParam(m, iter, &r->last_modified) && + ReadParam(m, iter, &r->request_is_seekable); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.id, l); + l->append(L", "); + LogParam(p.mime_type, l); + l->append(L", "); + LogParam(p.headers, l); + l->append(L", "); + LogParam(p.expected_length, l); + l->append(L", "); + LogParam(p.last_modified, l); + l->append(L", "); + LogParam(p.request_is_seekable, l); + l->append(L")"); + } +}; + +typedef const WebKit::WebInputEvent* WebInputEventPointer; +template <> +struct ParamTraits<WebInputEventPointer> { + typedef WebInputEventPointer param_type; + static void Write(Message* m, const param_type& p) { + m->WriteData(reinterpret_cast<const char*>(p), p->size); + } + // Note: upon read, the event has the lifetime of the message. + static bool Read(const Message* m, void** iter, param_type* r) { + const char* data; + int data_length; + if (!m->ReadData(iter, &data, &data_length)) { + NOTREACHED(); + return false; + } + if (data_length < static_cast<int>(sizeof(WebKit::WebInputEvent))) { + NOTREACHED(); + return false; + } + param_type event = reinterpret_cast<param_type>(data); + // Check that the data size matches that of the event (we check the latter + // in the delegate). + if (data_length != static_cast<int>(event->size)) { + NOTREACHED(); + return false; + } + *r = event; + return true; + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p->size, l); + l->append(L", "); + LogParam(p->type, l); + l->append(L", "); + LogParam(p->timeStampSeconds, l); + l->append(L")"); + } +}; + +template <> +struct ParamTraits<NPIdentifier_Param> { + typedef NPIdentifier_Param param_type; + static void Write(Message* m, const param_type& p) { + webkit_glue::SerializeNPIdentifier(p.identifier, m); + } + static bool Read(const Message* m, void** iter, param_type* r) { + return webkit_glue::DeserializeNPIdentifier(*m, iter, &r->identifier); + } + static void Log(const param_type& p, std::wstring* l) { + if (WebKit::WebBindings::identifierIsString(p.identifier)) { + NPUTF8* str = WebKit::WebBindings::utf8FromIdentifier(p.identifier); + l->append(UTF8ToWide(str)); + NPN_MemFree(str); + } else { + l->append(IntToWString( + WebKit::WebBindings::intFromIdentifier(p.identifier))); + } + } +}; + +template <> +struct ParamTraits<NPVariant_Param> { + typedef NPVariant_Param param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, static_cast<int>(p.type)); + if (p.type == NPVARIANT_PARAM_BOOL) { + WriteParam(m, p.bool_value); + } else if (p.type == NPVARIANT_PARAM_INT) { + WriteParam(m, p.int_value); + } else if (p.type == NPVARIANT_PARAM_DOUBLE) { + WriteParam(m, p.double_value); + } else if (p.type == NPVARIANT_PARAM_STRING) { + WriteParam(m, p.string_value); + } else if (p.type == NPVARIANT_PARAM_SENDER_OBJECT_ROUTING_ID || + p.type == 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 == NPVARIANT_PARAM_VOID || p.type == NPVARIANT_PARAM_NULL); + } + } + static bool Read(const Message* m, void** iter, param_type* r) { + int type; + if (!ReadParam(m, iter, &type)) + return false; + + bool result = false; + r->type = static_cast<NPVariant_ParamEnum>(type); + if (r->type == NPVARIANT_PARAM_BOOL) { + result = ReadParam(m, iter, &r->bool_value); + } else if (r->type == NPVARIANT_PARAM_INT) { + result = ReadParam(m, iter, &r->int_value); + } else if (r->type == NPVARIANT_PARAM_DOUBLE) { + result = ReadParam(m, iter, &r->double_value); + } else if (r->type == NPVARIANT_PARAM_STRING) { + result = ReadParam(m, iter, &r->string_value); + } else if (r->type == NPVARIANT_PARAM_SENDER_OBJECT_ROUTING_ID || + r->type == NPVARIANT_PARAM_RECEIVER_OBJECT_ROUTING_ID) { + result = ReadParam(m, iter, &r->npobject_routing_id); + } else if ((r->type == NPVARIANT_PARAM_VOID) || + (r->type == NPVARIANT_PARAM_NULL)) { + result = true; + } else { + NOTREACHED(); + } + + return result; + } + static void Log(const param_type& p, std::wstring* l) { + if (p.type == NPVARIANT_PARAM_BOOL) { + LogParam(p.bool_value, l); + } else if (p.type == NPVARIANT_PARAM_INT) { + LogParam(p.int_value, l); + } else if (p.type == NPVARIANT_PARAM_DOUBLE) { + LogParam(p.double_value, l); + } else if (p.type == NPVARIANT_PARAM_STRING) { + LogParam(p.string_value, l); + } else if (p.type == NPVARIANT_PARAM_SENDER_OBJECT_ROUTING_ID || + p.type == NPVARIANT_PARAM_RECEIVER_OBJECT_ROUTING_ID) { + LogParam(p.npobject_routing_id, l); + } + } +}; + +// For windowless plugins, windowless_buffer +// contains a buffer that the plugin draws into. background_buffer is used +// for transparent windowless plugins, and holds the background of the plugin +// rectangle. +template <> +struct ParamTraits<PluginMsg_UpdateGeometry_Param> { + typedef PluginMsg_UpdateGeometry_Param param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.window_rect); + WriteParam(m, p.clip_rect); + WriteParam(m, p.windowless_buffer); + WriteParam(m, p.background_buffer); + WriteParam(m, p.transparent); +#if defined(OS_MACOSX) + WriteParam(m, p.ack_key); +#endif + } + static bool Read(const Message* m, void** iter, param_type* r) { + return + ReadParam(m, iter, &r->window_rect) && + ReadParam(m, iter, &r->clip_rect) && + ReadParam(m, iter, &r->windowless_buffer) && + ReadParam(m, iter, &r->background_buffer) && + ReadParam(m, iter, &r->transparent) +#if defined(OS_MACOSX) + && + ReadParam(m, iter, &r->ack_key) +#endif + ; + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.window_rect, l); + l->append(L", "); + LogParam(p.clip_rect, l); + l->append(L", "); + LogParam(p.windowless_buffer, l); + l->append(L", "); + LogParam(p.background_buffer, l); + l->append(L", "); + LogParam(p.transparent, l); +#if defined(OS_MACOSX) + l->append(L", "); + LogParam(p.ack_key, l); +#endif + l->append(L")"); + } +}; + +} // namespace IPC + + +#define MESSAGES_INTERNAL_FILE "chrome/common/plugin_messages_internal.h" +#include "ipc/ipc_message_macros.h" + +#endif // CHROME_COMMON_PLUGIN_MESSAGES_H_ diff --git a/chrome/common/plugin_messages_internal.h b/chrome/common/plugin_messages_internal.h new file mode 100644 index 0000000..29388a4 --- /dev/null +++ b/chrome/common/plugin_messages_internal.h @@ -0,0 +1,514 @@ +// Copyright (c) 2009 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/shared_memory.h" +#include "build/build_config.h" +#include "gfx/native_widget_types.h" +#include "ipc/ipc_message_macros.h" +#include "webkit/glue/webcursor.h" + +#if defined(OS_POSIX) +#include "base/file_descriptor_posix.h" +#endif + +//----------------------------------------------------------------------------- +// PluginProcess messages +// These are messages sent from the browser to the plugin process. +IPC_BEGIN_MESSAGES(PluginProcess) + // Tells the plugin process to create a new channel for communication with a + // given renderer. The channel name is returned in a + // PluginProcessHostMsg_ChannelCreated message. The renderer ID is passed so + // that the plugin process reuses an existing channel to that process if it + // exists. This ID is a unique opaque identifier generated by the browser + // process. + IPC_MESSAGE_CONTROL2(PluginProcessMsg_CreateChannel, + int /* renderer_id */, + bool /* off_the_record */) + + // Allows a chrome plugin loaded in the browser process to send arbitrary + // data to an instance of the same plugin loaded in a plugin process. + IPC_MESSAGE_CONTROL1(PluginProcessMsg_PluginMessage, + std::vector<uint8> /* opaque data */) + + // Tells the plugin process to notify every connected renderer of the pending + // shutdown, so we don't mistake it for a crash. + IPC_MESSAGE_CONTROL0(PluginProcessMsg_NotifyRenderersOfPendingShutdown) + + // The following messages are used by all child processes, even though they + // are listed under PluginProcess. It seems overkill to define ChildProcess. + // Tells the child process it should stop. + IPC_MESSAGE_CONTROL0(PluginProcessMsg_AskBeforeShutdown) + + // Sent in response to PluginProcessHostMsg_ShutdownRequest to tell the child + // process that it's safe to shutdown. + IPC_MESSAGE_CONTROL0(PluginProcessMsg_Shutdown) + +#if defined(IPC_MESSAGE_LOG_ENABLED) + // Tell the child process to begin or end IPC message logging. + // Like above, this is used by all ChildProcesses. + IPC_MESSAGE_CONTROL1(PluginProcessMsg_SetIPCLoggingEnabled, + bool /* on or off */) +#endif + +IPC_END_MESSAGES(PluginProcess) + + +//----------------------------------------------------------------------------- +// PluginProcessHost messages +// These are messages sent from the plugin process to the browser process. +IPC_BEGIN_MESSAGES(PluginProcessHost) + // Response to a PluginProcessMsg_CreateChannel message. + IPC_MESSAGE_CONTROL1(PluginProcessHostMsg_ChannelCreated, + IPC::ChannelHandle /* channel_handle */) + + IPC_SYNC_MESSAGE_CONTROL0_1(PluginProcessHostMsg_GetPluginFinderUrl, + std::string /* plugin finder URL */) + + IPC_MESSAGE_CONTROL0(PluginProcessHostMsg_ShutdownRequest) + + // Allows a chrome plugin loaded in a plugin process to send arbitrary + // data to an instance of the same plugin loaded in the browser process. + IPC_MESSAGE_CONTROL1(PluginProcessHostMsg_PluginMessage, + std::vector<uint8> /* opaque data */) + + // Allows a chrome plugin loaded in a plugin process to send arbitrary + // data to an instance of the same plugin loaded in the browser process. + IPC_SYNC_MESSAGE_CONTROL1_1(PluginProcessHostMsg_PluginSyncMessage, + std::vector<uint8> /* opaque data */, + std::vector<uint8> /* opaque data response */) + + // Used to get cookies for the given URL. The request_context is a + // CPBrowsingContext, but is passed as int32 to avoid compilation errors. + IPC_SYNC_MESSAGE_CONTROL2_1(PluginProcessHostMsg_GetCookies, + int32 /* request_context */, + GURL /* url */, + std::string /* cookies */) + + // Used by the plugin process to verify that its renderer |renderer_id| has + // permission to access the given |files|. + IPC_SYNC_MESSAGE_CONTROL2_1(PluginProcessHostMsg_AccessFiles, + int /* renderer_id */, + std::vector<std::string> /* files */, + bool /* allowed */) + + // Get the list of proxies to use for |url|, as a semicolon delimited list + // of "<TYPE> <HOST>:<PORT>" | "DIRECT". See also ViewHostMsg_ResolveProxy + // which does the same thing. + IPC_SYNC_MESSAGE_CONTROL1_2(PluginProcessHostMsg_ResolveProxy, + GURL /* url */, + int /* network error */, + std::string /* proxy list */) + +#if defined(OS_WIN) + // Creates a child window of the given parent window on the UI thread. + IPC_SYNC_MESSAGE_CONTROL1_1(PluginProcessHostMsg_CreateWindow, + HWND /* parent */, + HWND /* child */) + + // Destroys the given window's parent on the UI thread. + IPC_MESSAGE_CONTROL2(PluginProcessHostMsg_PluginWindowDestroyed, + HWND /* window */, + HWND /* parent */) + + IPC_MESSAGE_ROUTED3(PluginProcessHostMsg_DownloadUrl, + std::string /* URL */, + int /* process id */, + HWND /* caller window */) +#endif + +#if defined(USE_X11) + // On X11, the mapping between NativeViewId and X window ids + // is known only to the browser. This message lets the plugin process + // ask about a NativeViewId that was provided by the renderer. + // It will get 0 back if it's a bogus input. + IPC_SYNC_MESSAGE_CONTROL1_1(PluginProcessHostMsg_MapNativeViewId, + gfx::NativeViewId /* input: native view id */, + gfx::PluginWindowHandle /* output: X window id */) +#endif + +#if defined(OS_MACOSX) + // On Mac OS X, we need the browser to keep track of plugin windows so + // that it can add and remove them from stacking groups, hide and show the + // menu bar, etc. We pass the window rect for convenience so that the + // browser can easily tell if the window is fullscreen. + + // Notifies the browser that the plugin has selected a window (i.e., brought + // it to the front and wants it to have keyboard focus). + IPC_MESSAGE_CONTROL3(PluginProcessHostMsg_PluginSelectWindow, + uint32 /* window ID */, + gfx::Rect /* window rect */, + bool /* modal */) + + // Notifies the browser that the plugin has shown a window. + IPC_MESSAGE_CONTROL3(PluginProcessHostMsg_PluginShowWindow, + uint32 /* window ID */, + gfx::Rect /* window rect */, + bool /* modal */) + + // Notifies the browser that the plugin has hidden a window. + IPC_MESSAGE_CONTROL2(PluginProcessHostMsg_PluginHideWindow, + uint32 /* window ID */, + gfx::Rect /* window rect */) + + // Notifies the browser that a plugin instance has requested a cursor + // visibility change. + IPC_MESSAGE_CONTROL1(PluginProcessHostMsg_PluginSetCursorVisibility, + bool /* cursor visibility */) +#endif + +IPC_END_MESSAGES(PluginProcessHost) + + +//----------------------------------------------------------------------------- +// Plugin messages +// These are messages sent from the renderer process to the plugin process. +IPC_BEGIN_MESSAGES(Plugin) + // 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_1(PluginMsg_Init, + PluginMsg_Init_Params, + 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_2(PluginMsg_Print, + base::SharedMemoryHandle /* shared_memory*/, + uint32 /* size */) + + IPC_SYNC_MESSAGE_ROUTED0_1(PluginMsg_GetPluginScriptableObject, + int /* route_id */) + + 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*/) + +#if defined(OS_MACOSX) + IPC_MESSAGE_ROUTED1(PluginMsg_SetWindowFocus, + bool /* has_focus */) + + IPC_MESSAGE_ROUTED1(PluginMsg_SetContentAreaFocus, + 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 */) +#endif + + IPC_SYNC_MESSAGE_ROUTED2_0(PluginMsg_WillSendRequest, + unsigned long /* id */, + GURL /* url */) + + 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_ROUTED0(PluginMsg_InstallMissingPlugin) + + 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_SYNC_MESSAGE_ROUTED0_1(PluginMsg_CreateCommandBuffer, + int /* route_id */) + + IPC_MESSAGE_ROUTED0(PluginMsg_DestroyCommandBuffer) + + IPC_MESSAGE_CONTROL1(PluginMsg_SignalModalDialogEvent, + gfx::NativeViewId /* containing_window */) + + IPC_MESSAGE_CONTROL1(PluginMsg_ResetModalDialogEvent, + gfx::NativeViewId /* containing_window */) + +#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 + +IPC_END_MESSAGES(Plugin) + + +//----------------------------------------------------------------------------- +// PluginHost messages +// These are messages sent from the plugin process to the renderer process. +// They all map to the corresponding WebPlugin methods. +IPC_BEGIN_MESSAGES(PluginHost) + // 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_ROUTED1_0(PluginHostMsg_SetWindowlessPumpEvent, + HANDLE /* modal_loop_pump_messages_event */) +#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_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 */) + + // Asks the browser to show a modal HTML dialog. The dialog is passed the + // given arguments as a JSON string, and returns its result as a JSON string + // through json_retval. + IPC_SYNC_MESSAGE_ROUTED4_1(PluginHostMsg_ShowModalHTMLDialog, + GURL /* url */, + int /* width */, + int /* height */, + std::string /* json_arguments */, + std::string /* json_retval */) + + IPC_SYNC_MESSAGE_ROUTED2_2(PluginHostMsg_GetDragData, + NPVariant_Param /* event */, + bool /* add_data */, + std::vector<NPVariant_Param> /* result_values */, + bool /* result_success */) + + IPC_SYNC_MESSAGE_ROUTED2_1(PluginHostMsg_SetDropEffect, + NPVariant_Param /* event */, + int /* effect */, + bool /* result_success */) + + IPC_MESSAGE_ROUTED1(PluginHostMsg_MissingPluginStatus, + int /* status */) + + IPC_SYNC_MESSAGE_ROUTED0_1(PluginHostMsg_GetCPBrowsingContext, + uint32 /* context */) + + 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_UpdateGeometry_ACK, + int /* ack_key */) + + // This message, used in Mac OS X 10.5 and earlier, is sent from the plug-in + // process to the renderer process to indicate that the plug-in allocated a + // new TransportDIB that holds the GPU's rendered image. This information is + // then forwarded to the browser process via a similar message. + IPC_MESSAGE_ROUTED4(PluginHostMsg_AcceleratedSurfaceSetTransportDIB, + gfx::PluginWindowHandle /* window */, + int32 /* width */, + int32 /* height */, + TransportDIB::Handle /* handle to the TransportDIB */) + + // Synthesize a fake window handle for the plug-in to identify the instance + // to the browser, allowing mapping to a surface for hardware accelleration + // of plug-in content. The browser generates the handle which is then set on + // the plug-in. |opaque| indicates whether the content should be treated as + // opaque. + IPC_MESSAGE_ROUTED1(PluginHostMsg_BindFakePluginWindowHandle, + bool /* opaque */) + + // This message, used only on 10.6 and later, is sent from the plug-in process + // to the renderer process to indicate that the plugin allocated a new + // IOSurface object of the given width and height. This information is then + // forwarded on to the browser process. + // + // NOTE: the original intent was to pass a mach port as the IOSurface + // identifier but it looks like that will be a lot of work. For now we pass an + // ID from IOSurfaceGetID. + IPC_MESSAGE_ROUTED4(PluginHostMsg_AcceleratedSurfaceSetIOSurface, + gfx::PluginWindowHandle /* window */, + int32 /* width */, + int32 /* height */, + uint64 /* identifier for IOSurface */) + + + // On the Mac, shared memory can't be allocated in the sandbox, so + // the TransportDIB used by the plug-in for rendering has to be allocated + // and managed by the browser. This is a synchronous message, use with care. + IPC_SYNC_MESSAGE_ROUTED1_1(PluginHostMsg_AllocTransportDIB, + size_t /* requested memory size */, + TransportDIB::Handle /* output: DIB handle */) + + // Since the browser keeps handles to the allocated transport DIBs, this + // message is sent to tell the browser that it may release them when the + // renderer is finished with them. + IPC_MESSAGE_ROUTED1(PluginHostMsg_FreeTransportDIB, + TransportDIB::Id /* DIB id */) + + // This message notifies the renderer process (and from there the + // browser process) that the plug-in swapped the buffers associated + // with the given "window", which should cause the browser to redraw + // the various plug-ins' contents. + IPC_MESSAGE_ROUTED1(PluginHostMsg_AcceleratedSurfaceBuffersSwapped, + gfx::PluginWindowHandle /* window */) +#endif + +IPC_END_MESSAGES(PluginHost) + +//----------------------------------------------------------------------------- +// 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_BEGIN_MESSAGES(NPObject) + IPC_SYNC_MESSAGE_ROUTED0_0(NPObjectMsg_Release) + + IPC_SYNC_MESSAGE_ROUTED1_1(NPObjectMsg_HasMethod, + NPIdentifier_Param /* name */, + bool /* result */) + + IPC_SYNC_MESSAGE_ROUTED3_2(NPObjectMsg_Invoke, + bool /* is_default */, + NPIdentifier_Param /* method */, + std::vector<NPVariant_Param> /* args */, + NPVariant_Param /* result_param */, + bool /* result */) + + IPC_SYNC_MESSAGE_ROUTED1_1(NPObjectMsg_HasProperty, + NPIdentifier_Param /* name */, + bool /* result */) + + IPC_SYNC_MESSAGE_ROUTED1_2(NPObjectMsg_GetProperty, + NPIdentifier_Param /* name */, + NPVariant_Param /* property */, + bool /* result */) + + IPC_SYNC_MESSAGE_ROUTED2_1(NPObjectMsg_SetProperty, + NPIdentifier_Param /* name */, + NPVariant_Param /* property */, + bool /* result */) + + IPC_SYNC_MESSAGE_ROUTED1_1(NPObjectMsg_RemoveProperty, + NPIdentifier_Param /* name */, + bool /* result */) + + IPC_SYNC_MESSAGE_ROUTED0_0(NPObjectMsg_Invalidate) + + IPC_SYNC_MESSAGE_ROUTED0_2(NPObjectMsg_Enumeration, + std::vector<NPIdentifier_Param> /* value */, + bool /* result */) + + IPC_SYNC_MESSAGE_ROUTED1_2(NPObjectMsg_Construct, + std::vector<NPVariant_Param> /* args */, + NPVariant_Param /* result_param */, + bool /* result */) + + IPC_SYNC_MESSAGE_ROUTED2_2(NPObjectMsg_Evaluate, + std::string /* script */, + bool /* popups_allowed */, + NPVariant_Param /* result_param */, + bool /* result */) + +IPC_END_MESSAGES(NPObject) diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc new file mode 100644 index 0000000..e04994f --- /dev/null +++ b/chrome/common/pref_names.cc @@ -0,0 +1,945 @@ +// Copyright (c) 2010 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 "chrome/common/pref_names.h" + +namespace prefs { + +// *************** PROFILE PREFS *************** +// These are attached to the user profile + +// A boolean specifying whether the New Tab page is the home page or not. +const wchar_t kHomePageIsNewTabPage[] = L"homepage_is_newtabpage"; + +// This is the URL of the page to load when opening new tabs. +const wchar_t kHomePage[] = L"homepage"; + +// Used to determine if the last session exited cleanly. Set to false when +// first opened, and to true when closing. On startup if the value is false, +// it means the profile didn't exit cleanly. +const wchar_t kSessionExitedCleanly[] = L"profile.exited_cleanly"; + +// An integer pref. Holds one of several values: +// 0: (or empty) don't do anything special on startup. +// 1: restore the last session. +// 2: this was used to indicate a specific session should be restored. It is +// no longer used, but saved to avoid conflict with old preferences. +// 3: unused, previously indicated the user wants to restore a saved session. +// 4: restore the URLs defined in kURLsToRestoreOnStartup. +const wchar_t kRestoreOnStartup[] = L"session.restore_on_startup"; + +// The URLs to restore on startup or when the home button is pressed. The URLs +// are only restored on startup if kRestoreOnStartup is 4. +const wchar_t kURLsToRestoreOnStartup[] = + L"session.urls_to_restore_on_startup"; + +// The application locale. +const wchar_t kApplicationLocale[] = L"intl.app_locale"; + +// The default character encoding to assume for a web page in the +// absence of MIME charset specification +const wchar_t kDefaultCharset[] = L"intl.charset_default"; + +// The value to use for Accept-Languages HTTP header when making an HTTP +// request. +const wchar_t kAcceptLanguages[] = L"intl.accept_languages"; + +// The value to use for showing locale-dependent encoding list for different +// locale, it's initialized from the corresponding string resource that is +// stored in non-translatable part of the resource bundle. +const wchar_t kStaticEncodings[] = L"intl.static_encodings"; + +// OBSOLETE. The list of hostnames for which we whitelist popups (rather than +// blocking). +const wchar_t kPopupWhitelistedHosts[] = L"profile.popup_whitelisted_sites"; + +// WebKit preferences. +// A boolean flag to indicate whether WebKit standard font family is +// serif or sans-serif. We don't have a UI for setting standard family. +// Instead, we use this pref to map either serif or sans_serif to WebKit +// standard font family. At the moment, we don't have a UI for this +// flag, either. +const wchar_t kWebKitStandardFontIsSerif[] = + L"webkit.webprefs.standard_font_is_serif"; +const wchar_t kWebKitFixedFontFamily[] = L"webkit.webprefs.fixed_font_family"; +const wchar_t kWebKitSerifFontFamily[] = L"webkit.webprefs.serif_font_family"; +const wchar_t kWebKitSansSerifFontFamily[] = + L"webkit.webprefs.sansserif_font_family"; +const wchar_t kWebKitCursiveFontFamily[] = + L"webkit.webprefs.cursive_font_family"; +const wchar_t kWebKitFantasyFontFamily[] = + L"webkit.webprefs.fantasy_font_family"; +const wchar_t kWebKitDefaultFontSize[] = L"webkit.webprefs.default_font_size"; +const wchar_t kWebKitDefaultFixedFontSize[] = + L"webkit.webprefs.default_fixed_font_size"; +const wchar_t kWebKitMinimumFontSize[] = L"webkit.webprefs.minimum_font_size"; +const wchar_t kWebKitMinimumLogicalFontSize[] = + L"webkit.webprefs.minimum_logical_font_size"; +const wchar_t kWebKitJavascriptEnabled[] = + L"webkit.webprefs.javascript_enabled"; +const wchar_t kWebKitWebSecurityEnabled[] = + L"webkit.webprefs.web_security_enabled"; +const wchar_t kWebKitJavascriptCanOpenWindowsAutomatically[] = + L"webkit.webprefs.javascript_can_open_windows_automatically"; +const wchar_t kWebKitLoadsImagesAutomatically[] = + L"webkit.webprefs.loads_images_automatically"; +const wchar_t kWebKitPluginsEnabled[] = L"webkit.webprefs.plugins_enabled"; +const wchar_t kWebKitDomPasteEnabled[] = L"webkit.webprefs.dom_paste_enabled"; +const wchar_t kWebKitShrinksStandaloneImagesToFit[] = + L"webkit.webprefs.shrinks_standalone_images_to_fit"; +const wchar_t kWebKitInspectorSettings[] = + L"webkit.webprefs.inspector_settings"; +const wchar_t kWebKitUsesUniversalDetector[] = + L"webkit.webprefs.uses_universal_detector"; +const wchar_t kWebKitTextAreasAreResizable[] = + L"webkit.webprefs.text_areas_are_resizable"; +const wchar_t kWebKitJavaEnabled[] = + L"webkit.webprefs.java_enabled"; +const wchar_t kWebkitTabsToLinks[] = L"webkit.webprefs.tabs_to_links"; + +// Boolean which specifies whether the bookmark bar is visible on all tabs. +const wchar_t kShowBookmarkBar[] = L"bookmark_bar.show_on_all_tabs"; + +// Boolean that is true if the password manager is on (will record new +// passwords and fill in known passwords). +const wchar_t kPasswordManagerEnabled[] = L"profile.password_manager_enabled"; + +// OBSOLETE. Boolean that is true if the form AutoFill is on (will record +// values entered in text inputs in forms and shows them in a popup when user +// type in a text input with the same name later on). This has been superseded +// by kAutoFillEnabled. +const wchar_t kFormAutofillEnabled[] = L"profile.form_autofill_enabled"; + +// Boolean that is true when SafeBrowsing is enabled. +const wchar_t kSafeBrowsingEnabled[] = L"safebrowsing.enabled"; + +// Boolean that is true when Suggest support is enabled. +const wchar_t kSearchSuggestEnabled[] = L"search.suggest_enabled"; + +// OBSOLETE. Enum that specifies whether to enforce a third-party cookie +// blocking policy. This has been superseded by kDefaultContentSettings + +// kBlockThirdPartyCookies. +// 0 - allow all cookies. +// 1 - block third-party cookies +// 2 - block all cookies +const wchar_t kCookieBehavior[] = L"security.cookie_behavior"; + +// The URL (as understood by TemplateURLRef) the default search provider uses +// for searches. +const wchar_t kDefaultSearchProviderSearchURL[] = + L"default_search_provider.search_url"; + +// The URL (as understood by TemplateURLRef) the default search provider uses +// for suggestions. +const wchar_t kDefaultSearchProviderSuggestURL[] = + L"default_search_provider.suggest_url"; + +// The name of the default search provider. +const wchar_t kDefaultSearchProviderName[] = L"default_search_provider.name"; + +// The id of the default search provider. +const wchar_t kDefaultSearchProviderID[] = L"default_search_provider.id"; + +// The prepopulate id of the default search provider. +const wchar_t kDefaultSearchProviderPrepopulateID[] = + L"default_search_provider.prepopulate_id"; + +// The dictionary key used when the default search providers are given +// in the preferences file. Normally they are copied from the master +// preferences file. +const wchar_t kSearchProviderOverrides[] = + L"search_provider_overrides"; +// The format version for the dictionary above. +const wchar_t kSearchProviderOverridesVersion[] = + L"search_provider_overrides_version"; + +// Boolean which specifies whether we should ask the user if we should download +// a file (true) or just download it automatically. +const wchar_t kPromptForDownload[] = L"download.prompt_for_download"; + +// A boolean pref set to true if we're using Link Doctor error pages. +const wchar_t kAlternateErrorPagesEnabled[] = L"alternate_error_pages.enabled"; + +// A boolean pref set to true if DNS pre-fetching is being done in browser. +const wchar_t kDnsPrefetchingEnabled[] = L"dns_prefetching.enabled"; + +// An adaptively identified list of domain names to be pre-fetched during the +// next startup, based on what was actually needed during this startup. +const wchar_t kDnsStartupPrefetchList[] = L"StartupDNSPrefetchList"; + +// A list of host names used to fetch web pages, and their commonly used +// sub-resource hostnames (and expected latency benefits from pre-resolving, or +// preconnecting to, such sub-resource hostnames). +// This list is adaptively grown and pruned. +const wchar_t kDnsHostReferralList[] = L"HostReferralList"; + +// Is the cookie prompt expanded? +const wchar_t kCookiePromptExpanded[] = L"cookieprompt.expanded"; + +#if defined(USE_NSS) +// Prefs for SSLConfigServicePref. Currently, these are only present on +// and used by NSS-using OSes. +const wchar_t kCertRevocationCheckingEnabled[] = L"ssl.rev_checking.enabled"; +const wchar_t kSSL2Enabled[] = L"ssl.ssl2.enabled"; +const wchar_t kSSL3Enabled[] = L"ssl.ssl3.enabled"; +const wchar_t kTLS1Enabled[] = L"ssl.tls1.enabled"; +#endif + +#if defined(OS_CHROMEOS) +// A boolean pref set to true if TapToClick is being done in browser. +const wchar_t kTapToClickEnabled[] = L"settings.touchpad.enable_tap_to_click"; + +// A boolean pref set to true if VertEdgeScroll is being done in browser. +const wchar_t kVertEdgeScrollEnabled[] = + L"settings.touchpad.enable_vert_edge_scroll"; + +// A integer pref for the touchpad speed factor. +const wchar_t kTouchpadSpeedFactor[] = L"settings.touchpad.speed_factor"; + +// A integer pref for the touchpad sensitivity. +const wchar_t kTouchpadSensitivity[] = L"settings.touchpad.sensitivity"; + +// A string pref set to the current input method. +const wchar_t kLanguageCurrentInputMethod[] = + L"settings.language.current_input_method"; + +// A string pref set to the previous input method. +const wchar_t kLanguagePreviousInputMethod[] = + L"settings.language.previous_input_method"; + +// A string pref (comma-separated list) set to the "next engine in menu" +// hot-key lists. +const wchar_t kLanguageHotkeyNextEngineInMenu[] = + L"settings.language.hotkey_next_engine_in_menu"; + +// A string pref (comma-separated list) set to the "previous engine" +// hot-key lists. +const wchar_t kLanguageHotkeyPreviousEngine[] = + L"settings.language.hotkey_previous_engine"; + +// A string pref (comma-separated list) set to the preferred language IDs +// (ex. "en-US,fr,ko"). +const wchar_t kLanguagePreferredLanguages[] = + L"settings.language.preferred_languages"; + +// A string pref (comma-separated list) set to the preloaded (active) input +// method IDs (ex. "pinyin,mozc"). +const wchar_t kLanguagePreloadEngines[] = L"settings.language.preload_engines"; + +// Boolean prefs for ibus-chewing Chinese input method. +const wchar_t kLanguageChewingAutoShiftCur[] = + L"settings.language.chewing_auto_shift_cur"; +const wchar_t kLanguageChewingAddPhraseDirection[] = + L"settings.language.chewing_add_phrase_direction"; +const wchar_t kLanguageChewingEasySymbolInput[] = + L"settings.language.chewing_easy_symbol_input"; +const wchar_t kLanguageChewingEscCleanAllBuf[] = + L"settings.language.chewing_esc_clean_all_buf"; +const wchar_t kLanguageChewingForceLowercaseEnglish[] = + L"settings.language.chewing_force_lowercase_english"; +const wchar_t kLanguageChewingPlainZhuyin[] = + L"settings.language.chewing_plain_zhuyin"; +const wchar_t kLanguageChewingPhraseChoiceRearward[] = + L"settings.language.chewing_phrase_choice_rearward"; +const wchar_t kLanguageChewingSpaceAsSelection[] = + L"settings.language.chewing_space_as_selection"; + +// Integer prefs for ibus-chewing Chinese input method. +const wchar_t kLanguageChewingMaxChiSymbolLen[] = + L"settings.language.chewing_max_chi_symbol_len"; +const wchar_t kLanguageChewingCandPerPage[] = + L"settings.language.chewing_cand_per_page"; + +// String prefs for ibus-chewing Chinese input method. +const wchar_t kLanguageChewingKeyboardType[] = + L"settings.language.chewing_keyboard_type"; +const wchar_t kLanguageChewingSelKeys[] = + L"settings.language.chewing_sel_keys"; + +const wchar_t kLanguageChewingHsuSelKeyType[] = + L"settings.language.chewing_hsu_sel_key_type"; + +// A string pref which determines the keyboard layout for Hangul input method. +const wchar_t kLanguageHangulKeyboard[] = L"settings.language.hangul_keyboard"; +const wchar_t kLanguageHangulHanjaKeys[] = + L"settings.language.hangul_hanja_keys"; + +// A boolean prefs for ibus-pinyin Chinese input method. +const wchar_t kLanguagePinyinCorrectPinyin[] = + L"settings.language.pinyin_correct_pinyin"; +const wchar_t kLanguagePinyinFuzzyPinyin[] = + L"settings.language.pinyin_fuzzy_pinyin"; +const wchar_t kLanguagePinyinShiftSelectCandidate[] = + L"settings.language.pinyin_shift_select_candidate"; +const wchar_t kLanguagePinyinMinusEqualPage[] = + L"settings.language.pinyin_minus_equal_page"; +const wchar_t kLanguagePinyinCommaPeriodPage[] = + L"settings.language.pinyin_comma_period_page"; +const wchar_t kLanguagePinyinAutoCommit[] = + L"settings.language.pinyin_auto_commit"; +const wchar_t kLanguagePinyinDoublePinyin[] = + L"settings.language.pinyin_double_pinyin"; +const wchar_t kLanguagePinyinInitChinese[] = + L"settings.language.pinyin_init_chinese"; +const wchar_t kLanguagePinyinInitFull[] = + L"settings.language.pinyin_init_full"; +const wchar_t kLanguagePinyinInitFullPunct[] = + L"settings.language.pinyin_init_full_punct"; +const wchar_t kLanguagePinyinInitSimplifiedChinese[] = + L"settings.language.pinyin_init_simplified_chinese"; +const wchar_t kLanguagePinyinTradCandidate[] = + L"settings.language.pinyin_trad_candidate"; + +// A integer prefs for ibus-pinyin Chinese input method. +const wchar_t kLanguagePinyinDoublePinyinSchema[] = + L"settings.language.pinyin_double_pinyin_schema"; +const wchar_t kLanguagePinyinLookupTablePageSize[] = + L"settings.language.pinyin_lookup_table_page_size"; + +// A string prefs for ibus-mozc Japanese input method. +// ibus-mozc converts the string values to protobuf enum values defined in +// third_party/ibus-mozc/files/src/session/config.proto. +const wchar_t kLanguageMozcPreeditMethod[] = + L"settings.language.mozc_preedit_method"; +const wchar_t kLanguageMozcSessionKeymap[] = + L"settings.language.mozc_sessoin_keymap"; +const wchar_t kLanguageMozcPunctuationMethod[] = + L"settings.language.mozc_punctuation_method"; +const wchar_t kLanguageMozcSymbolMethod[] = + L"settings.language.mozc_symbol_method"; +const wchar_t kLanguageMozcSpaceCharacterForm[] = + L"settings.language.mozc_space_character_form"; +const wchar_t kLanguageMozcHistoryLearningLevel[] = + L"settings.language.mozc_history_learning_level"; +const wchar_t kLanguageMozcSelectionShortcut[] = + L"settings.language.mozc_selection_shortcut"; +const wchar_t kLanguageMozcShiftKeyModeSwitch[] = + L"settings.language.mozc_shift_key_mode_switch"; +const wchar_t kLanguageMozcNumpadCharacterForm[] = + L"settings.language.mozc_numpad_character_form"; +const wchar_t kLanguageMozcIncognitoMode[] = + L"settings.language.mozc_incognito_mode"; +const wchar_t kLanguageMozcUseAutoImeTurnOff[] = + L"settings.language.mozc_use_auto_ime_turn_off"; +const wchar_t kLanguageMozcUseDateConversion[] = + L"settings.language.mozc_use_date_conversion"; +const wchar_t kLanguageMozcUseSingleKanjiConversion[] = + L"settings.language.mozc_use_single_kanji_conversion"; +const wchar_t kLanguageMozcUseSymbolConversion[] = + L"settings.language.mozc_use_symbol_conversion"; +const wchar_t kLanguageMozcUseNumberConversion[] = + L"settings.language.mozc_use_number_conversion"; +const wchar_t kLanguageMozcUseHistorySuggest[] = + L"settings.language.mozc_use_history_suggest"; +const wchar_t kLanguageMozcUseDictionarySuggest[] = + L"settings.language.mozc_use_dictionary_suggest"; +const wchar_t kLanguageMozcSuggestionsSize[] = + L"settings.language.mozc_suggestions_size"; + +// A boolean pref which determines whether accessibility is enabled. +const wchar_t kAccessibilityEnabled[] = L"settings.accessibility"; + +// A boolean pref which turns on Advanced Filesystem +// (USB support, SD card, etc). +const wchar_t kLabsAdvancedFilesystemEnabled[] = + L"settings.labs.advanced_filesystem"; + +// A boolean pref which turns on the mediaplayer. +const wchar_t kLabsMediaplayerEnabled[] = L"settings.labs.mediaplayer"; + +#endif // defined(OS_CHROMEOS) + +// The disabled messages in IPC logging. +const wchar_t kIpcDisabledMessages[] = L"ipc_log_disabled_messages"; + +// A boolean pref set to true if a Home button to open the Home pages should be +// visible on the toolbar. +const wchar_t kShowHomeButton[] = L"browser.show_home_button"; + +// A boolean pref set to true if the Page and Options menu buttons should be +// visible on the toolbar. This is only used for Mac where the default is to +// have these menu in the main menubar, not as buttons on the toolbar. +const wchar_t kShowPageOptionsButtons[] = L"browser.show_page_options_buttons"; + +// A string value which saves short list of recently user selected encodings +// separated with comma punctuation mark. +const wchar_t kRecentlySelectedEncoding[] = + L"profile.recently_selected_encodings"; + +// Clear Browsing Data dialog preferences. +const wchar_t kDeleteBrowsingHistory[] = L"browser.clear_data.browsing_history"; +const wchar_t kDeleteDownloadHistory[] = + L"browser.clear_data.download_history"; +const wchar_t kDeleteCache[] = L"browser.clear_data.cache"; +const wchar_t kDeleteCookies[] = L"browser.clear_data.cookies"; +const wchar_t kDeletePasswords[] = L"browser.clear_data.passwords"; +const wchar_t kDeleteFormData[] = L"browser.clear_data.form_data"; +const wchar_t kDeleteTimePeriod[] = L"browser.clear_data.time_period"; + +// Boolean pref to define the default values for using spellchecker. +const wchar_t kEnableSpellCheck[] = L"browser.enable_spellchecking"; + +// Boolean pref to define the default values for using auto spell correct. +const wchar_t kEnableAutoSpellCorrect[] = L"browser.enable_autospellcorrect"; + +// String pref to define the default values for print overlays. +const wchar_t kPrintingPageHeaderLeft[] = L"printing.page.header.left"; +const wchar_t kPrintingPageHeaderCenter[] = L"printing.page.header.center"; +const wchar_t kPrintingPageHeaderRight[] = L"printing.page.header.right"; +const wchar_t kPrintingPageFooterLeft[] = L"printing.page.footer.left"; +const wchar_t kPrintingPageFooterCenter[] = L"printing.page.footer.center"; +const wchar_t kPrintingPageFooterRight[] = L"printing.page.footer.right"; +#if defined(TOOLKIT_USES_GTK) +// GTK specific preference on whether we should match the system GTK theme. +const wchar_t kUsesSystemTheme[] = L"extensions.theme.use_system"; +#endif +const wchar_t kCurrentThemePackFilename[] = L"extensions.theme.pack"; +const wchar_t kCurrentThemeID[] = L"extensions.theme.id"; +const wchar_t kCurrentThemeImages[] = L"extensions.theme.images"; +const wchar_t kCurrentThemeColors[] = L"extensions.theme.colors"; +const wchar_t kCurrentThemeTints[] = L"extensions.theme.tints"; +const wchar_t kCurrentThemeDisplayProperties[] = + L"extensions.theme.properties"; + +// Boolean pref which persists whether the extensions_ui is in developer mode +// (showing developer packing tools and extensions details) +const wchar_t kExtensionsUIDeveloperMode[] = L"extensions.ui.developer_mode"; + +// Integer pref that tracks the number of browser actions visible in the browser +// actions toolbar. +const wchar_t kExtensionToolbarSize[] = L"extensions.toolbarsize"; + +// Pref containing the directory for internal plugins as written to the plugins +// list (below). +const wchar_t kPluginsLastInternalDirectory[] = + L"plugins.last_internal_directory"; + +// List pref containing information (dictionaries) on plugins. +const wchar_t kPluginsPluginsList[] = L"plugins.plugins_list"; + +// List pref containing names of plugins that are disabled by policy. +const wchar_t kPluginsPluginsBlacklist[] = L"plugins.plugins_blacklist"; + +// When first shipped, the pdf plugin will be disabled by default. When we +// enable it by default, we'll want to do so only once. +const wchar_t kPluginsEnabledInternalPDF[] = L"plugins.enabled_internal_pdf"; + +// Boolean that indicates whether we should check if we are the default browser +// on start-up. +const wchar_t kCheckDefaultBrowser[] = L"browser.check_default_browser"; + +#if defined(OS_MACOSX) +// Boolean that indicates whether the application should show the info bar +// asking the user to set up automatic updates when Keystone promotion is +// required. +const wchar_t kShowUpdatePromotionInfoBar[] = + L"browser.show_update_promotion_info_bar"; +#endif + +// Boolean that is false if we should show window manager decorations. If +// true, we draw a custom chrome frame (thicker title bar and blue border). +const wchar_t kUseCustomChromeFrame[] = L"browser.custom_chrome_frame"; + +// Boolean that indicates whether the infobar explaining that search can be +// done directly from the omnibox should be shown. +const wchar_t kShowOmniboxSearchHint[] = L"browser.show_omnibox_search_hint"; + +// Int which specifies how many times left to show a promotional message on the +// NTP. This value decrements each time the NTP is shown for the first time +// in a session. +const wchar_t kNTPPromoViewsRemaining[] = L"browser.ntp.promo_remaining"; + +// The list of origins which are allowed|denied to show desktop notifications. +const wchar_t kDesktopNotificationDefaultContentSetting[] = + L"profile.notifications_default_content_setting"; +const wchar_t kDesktopNotificationAllowedOrigins[] = + L"profile.notification_allowed_sites"; +const wchar_t kDesktopNotificationDeniedOrigins[] = + L"profile.notification_denied_sites"; + +// Dictionary of content settings applied to all hosts by default. +const wchar_t kDefaultContentSettings[] = L"profile.default_content_settings"; + +// OBSOLETE. Dictionary that maps hostnames to content related settings. +// Default settings will be applied to hosts not in this pref. +const wchar_t kPerHostContentSettings[] = L"profile.per_host_content_settings"; + +// Version of the pattern format used to define content settings. +const wchar_t kContentSettingsVersion[] = + L"profile.content_settings.pref_version"; + +// Patterns for mapping hostnames to content related settings. Default settings +// will be applied to hosts that don't match any of the patterns. Replaces +// kPerHostContentSettings. The pattern format used is defined by +// kContentSettingsVersion. +const wchar_t kContentSettingsPatterns[] = + L"profile.content_settings.patterns"; + +// Boolean that is true if we should unconditionally block third-party cookies, +// regardless of other content settings. +const wchar_t kBlockThirdPartyCookies[] = L"profile.block_third_party_cookies"; + +// Boolean that is true when all locally stored site data (e.g. cookies, local +// storage, etc..) should be deleted on exit. +const wchar_t kClearSiteDataOnExit[] = L"profile.clear_site_data_on_exit"; + +// Dictionary that maps hostnames to zoom levels. Hosts not in this pref will +// be displayed at the default zoom level. +const wchar_t kPerHostZoomLevels[] = L"profile.per_host_zoom_levels"; + +// Boolean that is true if AutoFill is enabled and allowed to save profile data. +const wchar_t kAutoFillEnabled[] = L"autofill.enabled"; + +// Boolean that is true when auxiliary AutoFill profiles are enabled. +// Currently applies to Address Book "me" card on Mac. False on Win and Linux. +const wchar_t kAutoFillAuxiliaryProfilesEnabled[] = + L"autofill.auxiliary_profiles_enabled"; + +// Position and size of the AutoFill dialog. +const wchar_t kAutoFillDialogPlacement[] = L"autofill.dialog_placement"; + +// Double that indicates positive (for matched forms) upload rate. +const wchar_t kAutoFillPositiveUploadRate[] = L"autofill.positive_upload_rate"; + +// Double that indicates negative (for not matched forms) upload rate. +const wchar_t kAutoFillNegativeUploadRate[] = L"autofill.negative_upload_rate"; + +// Boolean that is true when the tabstrip is to be laid out vertically down the +// side of the browser window. +const wchar_t kUseVerticalTabs[] = L"tabs.use_vertical_tabs"; + +// Boolean that is true when the translate feature is enabled. +const wchar_t kEnableTranslate[] = L"translate.enabled"; + +const wchar_t kPinnedTabs[] = L"pinned_tabs"; + +// Integer containing the default Geolocation content setting. +const wchar_t kGeolocationDefaultContentSetting[] = + L"geolocation.default_content_setting"; + +// Dictionary that maps [frame, toplevel] to their Geolocation content setting. +const wchar_t kGeolocationContentSettings[] = L"geolocation.content_settings"; + +// *************** LOCAL STATE *************** +// These are attached to the machine/installation + +// The metrics client GUID and session ID. +const wchar_t kMetricsClientID[] = L"user_experience_metrics.client_id"; +const wchar_t kMetricsSessionID[] = L"user_experience_metrics.session_id"; + +// Date/time when the current metrics profile ID was created +// (which hopefully corresponds to first run). +const wchar_t kMetricsClientIDTimestamp[] = + L"user_experience_metrics.client_id_timestamp"; + +// Boolean that specifies whether or not crash reporting and metrics reporting +// are sent over the network for analysis. +const wchar_t kMetricsReportingEnabled[] = + L"user_experience_metrics.reporting_enabled"; + +// Array of strings that are each UMA logs that were supposed to be sent in the +// first minute of a browser session. These logs include things like crash count +// info, etc. +const wchar_t kMetricsInitialLogs[] = + L"user_experience_metrics.initial_logs"; + +// Array of strings that are each UMA logs that were not sent because the +// browser terminated before these accumulated metrics could be sent. These +// logs typically include histograms and memory reports, as well as ongoing +// user activities. +const wchar_t kMetricsOngoingLogs[] = + L"user_experience_metrics.ongoing_logs"; + +// Where profile specific metrics are placed. +const wchar_t kProfileMetrics[] = L"user_experience_metrics.profiles"; + +// The metrics for a profile are stored as dictionary values under the +// path kProfileMetrics. The individual metrics are placed under the path +// kProfileMetrics.kProfilePrefix<hashed-profile-id>. +const wchar_t kProfilePrefix[] = L"profile-"; + +// True if the previous run of the program exited cleanly. +const wchar_t kStabilityExitedCleanly[] = + L"user_experience_metrics.stability.exited_cleanly"; + +// Version string of previous run, which is used to assure that stability +// metrics reported under current version reflect stability of the same version. +const wchar_t kStabilityStatsVersion[] = + L"user_experience_metrics.stability.stats_version"; + +// Build time, in seconds since an epoch, which is used to assure that stability +// metrics reported reflect stability of the same build. +const wchar_t kStabilityStatsBuildTime[] = + L"user_experience_metrics.stability.stats_buildtime"; + +// False if we received a session end and either we crashed during processing +// the session end or ran out of time and windows terminated us. +const wchar_t kStabilitySessionEndCompleted[] = + L"user_experience_metrics.stability.session_end_completed"; + +// Number of times the application was launched since last report. +const wchar_t kStabilityLaunchCount[] = + L"user_experience_metrics.stability.launch_count"; + +// Number of times the application exited uncleanly since the last report. +const wchar_t kStabilityCrashCount[] = + L"user_experience_metrics.stability.crash_count"; + +// Number of times the session end did not complete. +const wchar_t kStabilityIncompleteSessionEndCount[] = + L"user_experience_metrics.stability.incomplete_session_end_count"; + +// Number of times a page load event occurred since the last report. +const wchar_t kStabilityPageLoadCount[] = + L"user_experience_metrics.stability.page_load_count"; + +// Number of times a renderer process crashed since the last report. +const wchar_t kStabilityRendererCrashCount[] = + L"user_experience_metrics.stability.renderer_crash_count"; + +// Number of times an extension renderer process crashed since the last report. +const wchar_t kStabilityExtensionRendererCrashCount[] = + L"user_experience_metrics.stability.extension_renderer_crash_count"; + +// Time when the app was last launched, in seconds since the epoch. +const wchar_t kStabilityLaunchTimeSec[] = + L"user_experience_metrics.stability.launch_time_sec"; + +// Time when the app was last known to be running, in seconds since +// the epoch. +const wchar_t kStabilityLastTimestampSec[] = + L"user_experience_metrics.stability.last_timestamp_sec"; + +// This is the location of a list of dictionaries of plugin stability stats. +const wchar_t kStabilityPluginStats[] = + L"user_experience_metrics.stability.plugin_stats2"; + +// Number of times the renderer has become non-responsive since the last +// report. +const wchar_t kStabilityRendererHangCount[] = + L"user_experience_metrics.stability.renderer_hang_count"; + +// Total number of child process crashes (other than renderer / extension +// renderer ones, and plugin children, which are counted separately) since the +// last report. +const wchar_t kStabilityChildProcessCrashCount[] = + L"user_experience_metrics.stability.child_process_crash_count"; + +// Number of times the browser has been able to register crash reporting. +const wchar_t kStabilityBreakpadRegistrationSuccess[] = + L"user_experience_metrics.stability.breakpad_registration_ok"; + +// Number of times the browser has failed to register crash reporting. +const wchar_t kStabilityBreakpadRegistrationFail[] = + L"user_experience_metrics.stability.breakpad_registration_fail"; + +// Number of times the browser has been run under a debugger. +const wchar_t kStabilityDebuggerPresent[] = + L"user_experience_metrics.stability.debugger_present"; + +// Number of times the browser has not been run under a debugger. +const wchar_t kStabilityDebuggerNotPresent[] = + L"user_experience_metrics.stability.debugger_not_present"; + +// The keys below are used for the dictionaries in the +// kStabilityPluginStats list. +const wchar_t kStabilityPluginName[] = L"name"; +const wchar_t kStabilityPluginLaunches[] = L"launches"; +const wchar_t kStabilityPluginInstances[] = L"instances"; +const wchar_t kStabilityPluginCrashes[] = L"crashes"; + +// The keys below are strictly increasing counters over the lifetime of +// a chrome installation. They are (optionally) sent up to the uninstall +// survey in the event of uninstallation. +const wchar_t kUninstallMetricsPageLoadCount[] = + L"uninstall_metrics.page_load_count"; +const wchar_t kUninstallLaunchCount[] = L"uninstall_metrics.launch_count"; +const wchar_t kUninstallMetricsInstallDate[] = + L"uninstall_metrics.installation_date2"; +const wchar_t kUninstallMetricsUptimeSec[] = L"uninstall_metrics.uptime_sec"; +const wchar_t kUninstallLastLaunchTimeSec[] = + L"uninstall_metrics.last_launch_time_sec"; +const wchar_t kUninstallLastObservedRunTimeSec[] = + L"uninstall_metrics.last_observed_running_time_sec"; + +// A collection of position, size, and other data relating to the browser +// window to restore on startup. +const wchar_t kBrowserWindowPlacement[] = L"browser.window_placement"; + +// A collection of position, size, and other data relating to the task +// manager window to restore on startup. +const wchar_t kTaskManagerWindowPlacement[] = L"task_manager.window_placement"; + +// A collection of position, size, and other data relating to the page info +// window to restore on startup. +const wchar_t kPageInfoWindowPlacement[] = L"page_info.window_placement"; + +// A collection of position, size, and other data relating to the keyword +// editor window to restore on startup. +const wchar_t kKeywordEditorWindowPlacement[] = + L"keyword_editor.window_placement"; + +// A collection of position, size, and other data relating to the preferences +// window to restore on startup. +const wchar_t kPreferencesWindowPlacement[] = L"preferences.window_placement"; + +// An integer specifying the total number of bytes to be used by the +// renderer's in-memory cache of objects. +const wchar_t kMemoryCacheSize[] = L"renderer.memory_cache.size"; + +// String which specifies where to download files to by default. +const wchar_t kDownloadDefaultDirectory[] = L"download.default_directory"; + +// Boolean that records if the download directory was changed by an +// upgrade a unsafe location to a safe location. +const wchar_t kDownloadDirUpgraded[] = L"download.directory_upgrade"; + +// String which specifies where to save html files to by default. +const wchar_t kSaveFileDefaultDirectory[] = L"savefile.default_directory"; + +// String which specifies the last directory that was chosen for uploading +// or opening a file. +extern const wchar_t kSelectFileLastDirectory[] = L"selectfile.last_directory"; + +// Extensions which should be opened upon completion. +const wchar_t kDownloadExtensionsToOpen[] = L"download.extensions_to_open"; + +// Integer which specifies the frequency in milliseconds for detecting whether +// plugin windows are hung. +const wchar_t kHungPluginDetectFrequency[] = + L"browser.hung_plugin_detect_freq"; + +// Integer which specifies the timeout value to be used for SendMessageTimeout +// to detect a hung plugin window. +const wchar_t kPluginMessageResponseTimeout[] = + L"browser.plugin_message_response_timeout"; + +// String which represents the dictionary name for our spell-checker. +const wchar_t kSpellCheckDictionary[] = L"spellcheck.dictionary"; + +// Dictionary of schemes used by the external protocol handler. +// The value is true if the scheme must be ignored. +const wchar_t kExcludedSchemes[] = L"protocol_handler.excluded_schemes"; + +// Keys used for MAC handling of SafeBrowsing requests. +const wchar_t kSafeBrowsingClientKey[] = L"safe_browsing.client_key"; +const wchar_t kSafeBrowsingWrappedKey[] = L"safe_browsing.wrapped_key"; + +// Integer that specifies the index of the tab the user was on when they +// last visited the options window. +const wchar_t kOptionsWindowLastTabIndex[] = L"options_window.last_tab_index"; + +// Integer that specifies the index of the tab the user was on when they +// last visited the content settings window. +const wchar_t kContentSettingsWindowLastTabIndex[] = + L"content_settings_window.last_tab_index"; + +// Integer that specifies the index of the tab the user was on when they +// last visited the Certificate Manager window. +const wchar_t kCertificateManagerWindowLastTabIndex[] = + L"certificate_manager_window.last_tab_index"; + +// The mere fact that this pref is registered signals that we should show the +// First Run Search Information bubble when the first browser window appears. +// This preference is only registered by the first-run procedure. +const wchar_t kShouldShowFirstRunBubble[] = L"show-first-run-bubble"; + +// The mere fact that this pref is registered signals that we should show the +// smaller OEM First Run Search Information bubble when the first +// browser window appears. +// This preference is only registered by the first-run procedure. +const wchar_t kShouldUseOEMFirstRunBubble[] = L"show-OEM-first-run-bubble"; + +// The mere fact that this pref is registered signals that we should show the +// minimal First Run omnibox information bubble when the first +// browser window appears. +// This preference is only registered by the first-run procedure. +const wchar_t kShouldUseMinimalFirstRunBubble[] = + L"show-minimal-first-run-bubble"; + +// Signal that we should show the welcome page when we launch Chrome. +const wchar_t kShouldShowWelcomePage[] = L"show-welcome-page"; + +// String containing the last known Google URL. We re-detect this on startup in +// most cases, and use it to send traffic to the correct Google host or with the +// correct Google domain/country code for whatever location the user is in. +const wchar_t kLastKnownGoogleURL[] = L"browser.last_known_google_url"; + +// String containing the last known intranet redirect URL, if any. See +// intranet_redirect_detector.h for more information. +const wchar_t kLastKnownIntranetRedirectOrigin[] = L""; + +// Integer containing the system Country ID the first time we checked the +// template URL prepopulate data. This is used to avoid adding a whole bunch of +// new search engine choices if prepopulation runs when the user's Country ID +// differs from their previous Country ID. This pref does not exist until +// prepopulation has been run at least once. +const wchar_t kCountryIDAtInstall[] = L"countryid_at_install"; +// OBSOLETE. Same as above, but uses the Windows-specific GeoID value instead. +// Updated if found to the above key. +const wchar_t kGeoIDAtInstall[] = L"geoid_at_install"; + +// An enum value of how the browser was shut down (see browser_shutdown.h). +const wchar_t kShutdownType[] = L"shutdown.type"; +// Number of processes that were open when the user shut down. +const wchar_t kShutdownNumProcesses[] = L"shutdown.num_processes"; +// Number of processes that were shut down using the slow path. +const wchar_t kShutdownNumProcessesSlow[] = L"shutdown.num_processes_slow"; + +// Whether to restart the current Chrome session automatically as the last thing +// before shutting everything down. +const wchar_t kRestartLastSessionOnShutdown[] = + L"restart.last.session.on.shutdown"; + +// Number of bookmarks/folders on the bookmark bar/other bookmark folder. +const wchar_t kNumBookmarksOnBookmarkBar[] = + L"user_experience_metrics.num_bookmarks_on_bookmark_bar"; +const wchar_t kNumFoldersOnBookmarkBar[] = + L"user_experience_metrics.num_folders_on_bookmark_bar"; +const wchar_t kNumBookmarksInOtherBookmarkFolder[] = + L"user_experience_metrics.num_bookmarks_in_other_bookmark_folder"; +const wchar_t kNumFoldersInOtherBookmarkFolder[] = + L"user_experience_metrics.num_folders_in_other_bookmark_folder"; + +// Number of keywords. +const wchar_t kNumKeywords[] = L"user_experience_metrics.num_keywords"; + +// Placeholder preference for disabling voice / video chat if it is ever added. +// Currently, this does not change any behavior. +const wchar_t kDisableVideoAndChat[] = L"disable_video_chat"; + +// Whether Extensions are enabled. +const wchar_t kDisableExtensions[] = L"extensions.disabled"; + +// Boolean which specifies whether the Extension Shelf is visible on all tabs. +const wchar_t kShowExtensionShelf[] = L"extensions.shelf.show_on_all_tabs"; + +// Integer boolean representing the width (in pixels) of the container for +// browser actions. +const wchar_t kBrowserActionContainerWidth[] = + L"extensions.browseractions.container.width"; + +// Time of the last, and next scheduled, extensions auto-update checks. +const wchar_t kLastExtensionsUpdateCheck[] = + L"extensions.autoupdate.last_check"; +const wchar_t kNextExtensionsUpdateCheck[] = + L"extensions.autoupdate.next_check"; +// Version number of last blacklist check +const wchar_t kExtensionBlacklistUpdateVersion[] = + L"extensions.blacklistupdate.version"; + +// New Tab Page URLs that should not be shown as most visited thumbnails. +const wchar_t kNTPMostVisitedURLsBlacklist[] = L"ntp.most_visited_blacklist"; + +// The URLs that have been pinned to the Most Visited section of the New Tab +// Page. +const wchar_t kNTPMostVisitedPinnedURLs[] = L"ntp.pinned_urls"; + +// Data downloaded from resource pages (JSON, RSS) to be displayed in the +// recommendations portion of the NTP. +const wchar_t kNTPTipsCache[] = L"ntp.tips_cache"; + +// Last time of update of tips_cache. +const wchar_t kNTPTipsCacheUpdate[] = L"ntp.tips_cache_update"; + +// Last server used to fill tips_cache. +const wchar_t kNTPTipsServer[] = L"ntp.tips_server"; + +// Which sections should be visible on the new tab page +// 1 - Show the most visited sites in a grid +// 2 - Show the most visited sites as a list +// 4 - Show the recent section +// 8 - Show tips +// 16 - show sync status +const wchar_t kNTPShownSections[] = L"ntp.shown_sections"; + +// This pref is used for migrating the prefs for the NTP +const wchar_t kNTPPrefVersion[] = L"ntp.pref_version"; + +// A boolean specifying whether dev tools window should be opened docked. +const wchar_t kDevToolsOpenDocked[] = L"devtools.open_docked"; + +// Integer location of the split bar in the browser view. +const wchar_t kDevToolsSplitLocation[] = L"devtools.split_location"; + +// 64-bit integer serialization of the base::Time when the last sync occurred. +const wchar_t kSyncLastSyncedTime[] = L"sync.last_synced_time"; + +// Boolean specifying whether the user finished setting up sync. +const wchar_t kSyncHasSetupCompleted[] = L"sync.has_setup_completed"; + +// Boolean specifying whether to automatically sync all data types (including +// future ones, as they're added). If this is true, the following preferences +// (kSyncBookmarks, kSyncPasswords, etc.) can all be ignored. +const wchar_t kKeepEverythingSynced[] = L"sync.keep_everything_synced"; + +// Booleans specifying whether the user has selected to sync the following +// datatypes. +const wchar_t kSyncBookmarks[] = L"sync.bookmarks"; +const wchar_t kSyncPasswords[] = L"sync.passwords"; +const wchar_t kSyncPreferences[] = L"sync.preferences"; +const wchar_t kSyncAutofill[] = L"sync.autofill"; +const wchar_t kSyncThemes[] = L"sync.themes"; +const wchar_t kSyncTypedUrls[] = L"sync.typed_urls"; +const wchar_t kSyncExtensions[] = L"sync.extensions"; + +// Boolean used by enterprise configuration management in order to lock down +// sync. +const wchar_t kSyncManaged[] = L"sync.managed"; + +// Create web application shortcut dialog preferences. +const wchar_t kWebAppCreateOnDesktop[] = L"browser.web_app.create_on_desktop"; +const wchar_t kWebAppCreateInAppsMenu[] = + L"browser.web_app.create_in_apps_menu"; +const wchar_t kWebAppCreateInQuickLaunchBar[] = + L"browser.web_app.create_in_quick_launch_bar"; + +// Dictionary that maps Geolocation network provider server URLs to +// corresponding access token. +const wchar_t kGeolocationAccessToken[] = L"geolocation.access_token"; + +// Whether PasswordForms have been migrated from the WedDataService to the +// LoginDatabase. +const wchar_t kLoginDatabaseMigrated[] = L"login_database.migrated"; + +// The root URL of the cloud print service. +const wchar_t kCloudPrintServiceURL[] = L"cloud_print.service_url"; + +// The list of BackgroundContents that should be loaded when the browser +// launches. +const wchar_t kRegisteredBackgroundContents[] = + L"background_contents.registered"; + +// *************** SERVICE PREFS *************** +// These are attached to the service process. + +// The unique id for this instance of the cloud print proxy. +const wchar_t kCloudPrintProxyId[] = L"cloud_print.proxy_id"; +// The GAIA auth token for Cloud Print +const wchar_t kCloudPrintAuthToken[] = L"cloud_print.auth_token"; +// The GAIA auth token used by Cloud Print to authenticate with the XMPP server +// This should eventually go away because the above token should work for both. +const wchar_t kCloudPrintXMPPAuthToken[] = L"cloud_print.xmpp_auth_token"; +// The email address of the account used to authenticate with the Cloud Print +// server. +extern const wchar_t kCloudPrintEmail[] = L"cloud_print.email"; +// Settings specific to underlying print system. +extern const wchar_t kCloudPrintPrintSystemSettings[] = + L"cloud_print.print_system_settings"; + +// Boolean to disable proxy altogether. If true, other proxy +// preferences are ignored. +const wchar_t kNoProxyServer[] = L"proxy.disabled"; +// Boolean specifying if proxy should be auto-detected. +const wchar_t kProxyAutoDetect[] = L"proxy.auto_detect"; +// String specifying the proxy server. For a specification of the expected +// syntax see net::ProxyConfig::ProxyRules::ParseFromString(). +const wchar_t kProxyServer[] = L"proxy.server"; +// URL to the proxy .pac file. +const wchar_t kProxyPacUrl[] = L"proxy.pac_url"; +// String containing proxy bypass rules. For a specification of the +// expected syntax see net::ProxyBypassRules::ParseFromString(). +const wchar_t kProxyBypassList[] = L"proxy.bypass_list"; + +} // namespace prefs diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h new file mode 100644 index 0000000..9897ec0 --- /dev/null +++ b/chrome/common/pref_names.h @@ -0,0 +1,353 @@ +// Copyright (c) 2010 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. + +// Constants for the names of various preferences, for easier changing. + +#ifndef CHROME_COMMON_PREF_NAMES_H_ +#define CHROME_COMMON_PREF_NAMES_H_ + +#include "build/build_config.h" + +namespace prefs { + +// Profile prefs +extern const wchar_t kHomePageIsNewTabPage[]; +extern const wchar_t kHomePage[]; +extern const wchar_t kSessionExitedCleanly[]; +extern const wchar_t kRestoreOnStartup[]; +extern const wchar_t kURLsToRestoreOnStartup[]; +extern const wchar_t kApplicationLocale[]; +extern const wchar_t kDefaultCharset[]; +extern const wchar_t kAcceptLanguages[]; +extern const wchar_t kStaticEncodings[]; +extern const wchar_t kPopupWhitelistedHosts[]; +extern const wchar_t kShowBookmarkBar[]; +extern const wchar_t kWebKitStandardFontIsSerif[]; +extern const wchar_t kWebKitFixedFontFamily[]; +extern const wchar_t kWebKitSerifFontFamily[]; +extern const wchar_t kWebKitSansSerifFontFamily[]; +extern const wchar_t kWebKitCursiveFontFamily[]; +extern const wchar_t kWebKitFantasyFontFamily[]; +extern const wchar_t kWebKitDefaultFontSize[]; +extern const wchar_t kWebKitDefaultFixedFontSize[]; +extern const wchar_t kWebKitMinimumFontSize[]; +extern const wchar_t kWebKitMinimumLogicalFontSize[]; +extern const wchar_t kWebKitJavascriptEnabled[]; +extern const wchar_t kWebKitWebSecurityEnabled[]; +extern const wchar_t kWebKitJavascriptCanOpenWindowsAutomatically[]; +extern const wchar_t kWebKitLoadsImagesAutomatically[]; +extern const wchar_t kWebKitPluginsEnabled[]; +extern const wchar_t kWebKitDomPasteEnabled[]; +extern const wchar_t kWebKitShrinksStandaloneImagesToFit[]; +extern const wchar_t kWebKitInspectorSettings[]; +extern const wchar_t kWebKitUsesUniversalDetector[]; +extern const wchar_t kWebKitTextAreasAreResizable[]; +extern const wchar_t kWebKitJavaEnabled[]; +extern const wchar_t kWebkitTabsToLinks[]; +extern const wchar_t kPasswordManagerEnabled[]; +extern const wchar_t kFormAutofillEnabled[]; // OBSOLETE +extern const wchar_t kSafeBrowsingEnabled[]; +extern const wchar_t kSearchSuggestEnabled[]; +extern const wchar_t kCookieBehavior[]; // OBSOLETE +extern const wchar_t kDefaultSearchProviderSearchURL[]; +extern const wchar_t kDefaultSearchProviderSuggestURL[]; +extern const wchar_t kDefaultSearchProviderName[]; +extern const wchar_t kDefaultSearchProviderID[]; +extern const wchar_t kDefaultSearchProviderPrepopulateID[]; +extern const wchar_t kSearchProviderOverrides[]; +extern const wchar_t kSearchProviderOverridesVersion[]; +extern const wchar_t kPromptForDownload[]; +extern const wchar_t kAlternateErrorPagesEnabled[]; +extern const wchar_t kDnsPrefetchingEnabled[]; +extern const wchar_t kDnsStartupPrefetchList[]; +extern const wchar_t kDnsHostReferralList[]; +extern const wchar_t kCookiePromptExpanded[]; +#if defined(USE_NSS) +extern const wchar_t kCertRevocationCheckingEnabled[]; +extern const wchar_t kSSL2Enabled[]; +extern const wchar_t kSSL3Enabled[]; +extern const wchar_t kTLS1Enabled[]; +#endif +#if defined(OS_CHROMEOS) +extern const wchar_t kTapToClickEnabled[]; +extern const wchar_t kVertEdgeScrollEnabled[]; +extern const wchar_t kTouchpadSpeedFactor[]; +extern const wchar_t kTouchpadSensitivity[]; +extern const wchar_t kLanguageCurrentInputMethod[]; +extern const wchar_t kLanguagePreviousInputMethod[]; +extern const wchar_t kLanguageHotkeyNextEngineInMenu[]; +extern const wchar_t kLanguageHotkeyPreviousEngine[]; +extern const wchar_t kLanguagePreferredLanguages[]; +extern const wchar_t kLanguagePreloadEngines[]; +extern const wchar_t kLanguageChewingAutoShiftCur[]; +extern const wchar_t kLanguageChewingAddPhraseDirection[]; +extern const wchar_t kLanguageChewingEasySymbolInput[]; +extern const wchar_t kLanguageChewingEscCleanAllBuf[]; +extern const wchar_t kLanguageChewingForceLowercaseEnglish[]; +extern const wchar_t kLanguageChewingPlainZhuyin[]; +extern const wchar_t kLanguageChewingPhraseChoiceRearward[]; +extern const wchar_t kLanguageChewingSpaceAsSelection[]; +extern const wchar_t kLanguageChewingMaxChiSymbolLen[]; +extern const wchar_t kLanguageChewingCandPerPage[]; +extern const wchar_t kLanguageChewingKeyboardType[]; +extern const wchar_t kLanguageChewingSelKeys[]; +extern const wchar_t kLanguageChewingHsuSelKeyType[]; +extern const wchar_t kLanguageHangulKeyboard[]; +extern const wchar_t kLanguageHangulHanjaKeys[]; +extern const wchar_t kLanguagePinyinCorrectPinyin[]; +extern const wchar_t kLanguagePinyinFuzzyPinyin[]; +extern const wchar_t kLanguagePinyinLookupTablePageSize[]; +extern const wchar_t kLanguagePinyinShiftSelectCandidate[]; +extern const wchar_t kLanguagePinyinMinusEqualPage[]; +extern const wchar_t kLanguagePinyinCommaPeriodPage[]; +extern const wchar_t kLanguagePinyinAutoCommit[]; +extern const wchar_t kLanguagePinyinDoublePinyin[]; +extern const wchar_t kLanguagePinyinDoublePinyinSchema[]; +extern const wchar_t kLanguagePinyinInitChinese[]; +extern const wchar_t kLanguagePinyinInitFull[]; +extern const wchar_t kLanguagePinyinInitFullPunct[]; +extern const wchar_t kLanguagePinyinInitSimplifiedChinese[]; +extern const wchar_t kLanguagePinyinTradCandidate[]; +extern const wchar_t kLanguageMozcPreeditMethod[]; +extern const wchar_t kLanguageMozcSessionKeymap[]; +extern const wchar_t kLanguageMozcPunctuationMethod[]; +extern const wchar_t kLanguageMozcSymbolMethod[]; +extern const wchar_t kLanguageMozcSpaceCharacterForm[]; +extern const wchar_t kLanguageMozcHistoryLearningLevel[]; +extern const wchar_t kLanguageMozcSelectionShortcut[]; +extern const wchar_t kLanguageMozcShiftKeyModeSwitch[]; +extern const wchar_t kLanguageMozcNumpadCharacterForm[]; +extern const wchar_t kLanguageMozcIncognitoMode[]; +extern const wchar_t kLanguageMozcUseAutoImeTurnOff[]; +extern const wchar_t kLanguageMozcUseDateConversion[]; +extern const wchar_t kLanguageMozcUseSingleKanjiConversion[]; +extern const wchar_t kLanguageMozcUseSymbolConversion[]; +extern const wchar_t kLanguageMozcUseNumberConversion[]; +extern const wchar_t kLanguageMozcUseHistorySuggest[]; +extern const wchar_t kLanguageMozcUseDictionarySuggest[]; +extern const wchar_t kLanguageMozcSuggestionsSize[]; +extern const wchar_t kAccessibilityEnabled[]; +extern const wchar_t kLabsAdvancedFilesystemEnabled[]; +extern const wchar_t kLabsMediaplayerEnabled[]; +#endif +extern const wchar_t kIpcDisabledMessages[]; +extern const wchar_t kShowHomeButton[]; +extern const wchar_t kShowPageOptionsButtons[]; +extern const wchar_t kRecentlySelectedEncoding[]; +extern const wchar_t kDeleteBrowsingHistory[]; +extern const wchar_t kDeleteDownloadHistory[]; +extern const wchar_t kDeleteCache[]; +extern const wchar_t kDeleteCookies[]; +extern const wchar_t kDeletePasswords[]; +extern const wchar_t kDeleteFormData[]; +extern const wchar_t kEnableSpellCheck[]; +extern const wchar_t kEnableAutoSpellCorrect[]; +extern const wchar_t kDeleteTimePeriod[]; +extern const wchar_t kPrintingPageHeaderLeft[]; +extern const wchar_t kPrintingPageHeaderCenter[]; +extern const wchar_t kPrintingPageHeaderRight[]; +extern const wchar_t kPrintingPageFooterLeft[]; +extern const wchar_t kPrintingPageFooterCenter[]; +extern const wchar_t kPrintingPageFooterRight[]; +#if defined(TOOLKIT_USES_GTK) +extern const wchar_t kUsesSystemTheme[]; +#endif +extern const wchar_t kCurrentThemePackFilename[]; +extern const wchar_t kCurrentThemeID[]; +extern const wchar_t kCurrentThemeImages[]; +extern const wchar_t kCurrentThemeColors[]; +extern const wchar_t kCurrentThemeTints[]; +extern const wchar_t kCurrentThemeDisplayProperties[]; +extern const wchar_t kExtensionsUIDeveloperMode[]; +extern const wchar_t kExtensionToolbarSize[]; +extern const wchar_t kPluginsLastInternalDirectory[]; +extern const wchar_t kPluginsPluginsList[]; +extern const wchar_t kPluginsPluginsBlacklist[]; +extern const wchar_t kPluginsEnabledInternalPDF[]; +extern const wchar_t kCheckDefaultBrowser[]; +#if defined(OS_MACOSX) +extern const wchar_t kShowUpdatePromotionInfoBar[]; +#endif +extern const wchar_t kUseCustomChromeFrame[]; +extern const wchar_t kShowOmniboxSearchHint[]; +extern const wchar_t kNTPPromoViewsRemaining[]; +extern const wchar_t kDesktopNotificationDefaultContentSetting[]; +extern const wchar_t kDesktopNotificationAllowedOrigins[]; +extern const wchar_t kDesktopNotificationDeniedOrigins[]; +extern const wchar_t kDefaultContentSettings[]; +extern const wchar_t kPerHostContentSettings[]; // OBSOLETE +extern const wchar_t kContentSettingsVersion[]; +extern const wchar_t kContentSettingsPatterns[]; +extern const wchar_t kBlockThirdPartyCookies[]; +extern const wchar_t kClearSiteDataOnExit[]; +extern const wchar_t kPerHostZoomLevels[]; +extern const wchar_t kAutoFillEnabled[]; +extern const wchar_t kAutoFillAuxiliaryProfilesEnabled[]; +extern const wchar_t kAutoFillDialogPlacement[]; +extern const wchar_t kAutoFillPositiveUploadRate[]; +extern const wchar_t kAutoFillNegativeUploadRate[]; + +extern const wchar_t kUseVerticalTabs[]; +extern const wchar_t kEnableTranslate[]; +extern const wchar_t kPinnedTabs[]; + +// Local state +extern const wchar_t kMetricsClientID[]; +extern const wchar_t kMetricsSessionID[]; +extern const wchar_t kMetricsClientIDTimestamp[]; +extern const wchar_t kMetricsReportingEnabled[]; +extern const wchar_t kMetricsInitialLogs[]; +extern const wchar_t kMetricsOngoingLogs[]; + +extern const wchar_t kProfileMetrics[]; +extern const wchar_t kProfilePrefix[]; + +extern const wchar_t kStabilityExitedCleanly[]; +extern const wchar_t kStabilityStatsVersion[]; +extern const wchar_t kStabilityStatsBuildTime[]; +extern const wchar_t kStabilitySessionEndCompleted[]; +extern const wchar_t kStabilityLaunchCount[]; +extern const wchar_t kStabilityCrashCount[]; +extern const wchar_t kStabilityIncompleteSessionEndCount[]; +extern const wchar_t kStabilityPageLoadCount[]; +extern const wchar_t kStabilityRendererCrashCount[]; +extern const wchar_t kStabilityExtensionRendererCrashCount[]; +extern const wchar_t kStabilityLaunchTimeSec[]; +extern const wchar_t kStabilityLastTimestampSec[]; +extern const wchar_t kStabilityRendererHangCount[]; +extern const wchar_t kStabilityChildProcessCrashCount[]; + +extern const wchar_t kStabilityBreakpadRegistrationSuccess[]; +extern const wchar_t kStabilityBreakpadRegistrationFail[]; +extern const wchar_t kStabilityDebuggerPresent[]; +extern const wchar_t kStabilityDebuggerNotPresent[]; + +extern const wchar_t kStabilityPluginStats[]; +extern const wchar_t kStabilityPluginName[]; +extern const wchar_t kStabilityPluginLaunches[]; +extern const wchar_t kStabilityPluginInstances[]; +extern const wchar_t kStabilityPluginCrashes[]; + +extern const wchar_t kUninstallMetricsPageLoadCount[]; +extern const wchar_t kUninstallLaunchCount[]; + +extern const wchar_t kUninstallMetricsInstallDate[]; +extern const wchar_t kUninstallMetricsUptimeSec[]; +extern const wchar_t kUninstallLastLaunchTimeSec[]; +extern const wchar_t kUninstallLastObservedRunTimeSec[]; + +extern const wchar_t kBrowserWindowPlacement[]; +extern const wchar_t kTaskManagerWindowPlacement[]; +extern const wchar_t kPageInfoWindowPlacement[]; +extern const wchar_t kKeywordEditorWindowPlacement[]; +extern const wchar_t kPreferencesWindowPlacement[]; +extern const wchar_t kMemoryCacheSize[]; + +extern const wchar_t kDownloadDefaultDirectory[]; +extern const wchar_t kDownloadExtensionsToOpen[]; +extern const wchar_t kDownloadDirUpgraded[]; + +extern const wchar_t kSaveFileDefaultDirectory[]; + +extern const wchar_t kSelectFileLastDirectory[]; + +extern const wchar_t kHungPluginDetectFrequency[]; +extern const wchar_t kPluginMessageResponseTimeout[]; + +extern const wchar_t kSpellCheckDictionary[]; + +extern const wchar_t kExcludedSchemes[]; + +extern const wchar_t kSafeBrowsingClientKey[]; +extern const wchar_t kSafeBrowsingWrappedKey[]; + +extern const wchar_t kOptionsWindowLastTabIndex[]; +extern const wchar_t kContentSettingsWindowLastTabIndex[]; +extern const wchar_t kCertificateManagerWindowLastTabIndex[]; +extern const wchar_t kShouldShowFirstRunBubble[]; +extern const wchar_t kShouldUseOEMFirstRunBubble[]; +extern const wchar_t kShouldUseMinimalFirstRunBubble[]; +extern const wchar_t kShouldShowWelcomePage[]; + +extern const wchar_t kLastKnownGoogleURL[]; +extern const wchar_t kLastKnownIntranetRedirectOrigin[]; + +extern const wchar_t kCountryIDAtInstall[]; +extern const wchar_t kGeoIDAtInstall[]; // OBSOLETE + +extern const wchar_t kShutdownType[]; +extern const wchar_t kShutdownNumProcesses[]; +extern const wchar_t kShutdownNumProcessesSlow[]; + +extern const wchar_t kRestartLastSessionOnShutdown[]; + +extern const wchar_t kNumBookmarksOnBookmarkBar[]; +extern const wchar_t kNumFoldersOnBookmarkBar[]; +extern const wchar_t kNumBookmarksInOtherBookmarkFolder[]; +extern const wchar_t kNumFoldersInOtherBookmarkFolder[]; + +extern const wchar_t kNumKeywords[]; + +extern const wchar_t kDisableVideoAndChat[]; + +extern const wchar_t kDisableExtensions[]; +extern const wchar_t kShowExtensionShelf[]; +extern const wchar_t kBrowserActionContainerWidth[]; + +extern const wchar_t kLastExtensionsUpdateCheck[]; +extern const wchar_t kNextExtensionsUpdateCheck[]; + +extern const wchar_t kExtensionBlacklistUpdateVersion[]; + +extern const wchar_t kNTPMostVisitedURLsBlacklist[]; +extern const wchar_t kNTPMostVisitedPinnedURLs[]; +extern const wchar_t kNTPTipsCache[]; +extern const wchar_t kNTPTipsCacheUpdate[]; +extern const wchar_t kNTPTipsServer[]; +extern const wchar_t kNTPShownSections[]; +extern const wchar_t kNTPPrefVersion[]; + +extern const wchar_t kDevToolsOpenDocked[]; +extern const wchar_t kDevToolsSplitLocation[]; + +extern const wchar_t kSyncLastSyncedTime[]; +extern const wchar_t kSyncHasSetupCompleted[]; +extern const wchar_t kKeepEverythingSynced[]; +extern const wchar_t kSyncBookmarks[]; +extern const wchar_t kSyncPasswords[]; +extern const wchar_t kSyncPreferences[]; +extern const wchar_t kSyncAutofill[]; +extern const wchar_t kSyncThemes[]; +extern const wchar_t kSyncTypedUrls[]; +extern const wchar_t kSyncExtensions[]; +extern const wchar_t kSyncManaged[]; + +extern const wchar_t kWebAppCreateOnDesktop[]; +extern const wchar_t kWebAppCreateInAppsMenu[]; +extern const wchar_t kWebAppCreateInQuickLaunchBar[]; + +extern const wchar_t kGeolocationAccessToken[]; +extern const wchar_t kGeolocationDefaultContentSetting[]; +extern const wchar_t kGeolocationContentSettings[]; + +extern const wchar_t kLoginDatabaseMigrated[]; + +extern const wchar_t kCloudPrintServiceURL[]; +extern const wchar_t kCloudPrintProxyId[]; +extern const wchar_t kCloudPrintAuthToken[]; +extern const wchar_t kCloudPrintXMPPAuthToken[]; +extern const wchar_t kCloudPrintEmail[]; +extern const wchar_t kCloudPrintPrintSystemSettings[]; + +extern const wchar_t kNoProxyServer[]; +extern const wchar_t kProxyAutoDetect[]; +extern const wchar_t kProxyServer[]; +extern const wchar_t kProxyPacUrl[]; +extern const wchar_t kProxyBypassList[]; + +extern const wchar_t kRegisteredBackgroundContents[]; + +} // namespace prefs + +#endif // CHROME_COMMON_PREF_NAMES_H_ diff --git a/chrome/common/pref_store.h b/chrome/common/pref_store.h new file mode 100644 index 0000000..959c412 --- /dev/null +++ b/chrome/common/pref_store.h @@ -0,0 +1,49 @@ +// Copyright (c) 2010 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 CHROME_COMMON_PREF_STORE_H_ +#define CHROME_COMMON_PREF_STORE_H_ + +class DictionaryValue; + +// This is an abstract interface for reading and writing from/to a persistent +// preference store, used by |PrefService|. An implementation using a JSON file +// can be found in |JsonPrefStore|, while an implementation without any backing +// store (currently used for testing) can be found in |DummyPrefStore|. +class PrefStore { + public: + // Unique integer code for each type of error so we can report them + // distinctly in a histogram. + // NOTE: Don't change the order here as it will change the server's meaning + // of the histogram. + enum PrefReadError { + PREF_READ_ERROR_NONE = 0, + PREF_READ_ERROR_JSON_PARSE, + PREF_READ_ERROR_JSON_TYPE, + PREF_READ_ERROR_ACCESS_DENIED, + PREF_READ_ERROR_FILE_OTHER, + PREF_READ_ERROR_FILE_LOCKED, + PREF_READ_ERROR_NO_FILE, + PREF_READ_ERROR_JSON_REPEAT, + PREF_READ_ERROR_OTHER + }; + + virtual ~PrefStore() { } + + // Whether the store is in a pseudo-read-only mode where changes are not + // actually persisted to disk. This happens in some cases when there are + // read errors during startup. + virtual bool ReadOnly() { return true; } + + virtual DictionaryValue* prefs() = 0; + + virtual PrefReadError ReadPrefs() = 0; + + virtual bool WritePrefs() { return true; } + + virtual void ScheduleWritePrefs() { } +}; + +#endif // CHROME_COMMON_PREF_STORE_H_ + diff --git a/chrome/common/process_watcher.h b/chrome/common/process_watcher.h new file mode 100644 index 0000000..f764c4f --- /dev/null +++ b/chrome/common/process_watcher.h @@ -0,0 +1,44 @@ +// Copyright (c) 2006-2008 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 CHROME_COMMON_PROCESS_WATCHER_H_ +#define CHROME_COMMON_PROCESS_WATCHER_H_ + +#include "build/build_config.h" + +#include "base/basictypes.h" +#include "base/process_util.h" + +class ProcessWatcher { + public: + // This method ensures that the specified process eventually terminates, and + // then it closes the given process handle. + // + // It assumes that the process has already been signalled to exit, and it + // begins by waiting a small amount of time for it to exit. If the process + // does not appear to have exited, then this function starts to become + // aggressive about ensuring that the process terminates. + // + // On Linux this method does not block the calling thread. + // On OS X this method may block for up to 2 seconds. + // + // NOTE: The process handle must have been opened with the PROCESS_TERMINATE + // and SYNCHRONIZE permissions. + // + static void EnsureProcessTerminated(base::ProcessHandle process_handle); + +#if defined(OS_POSIX) && !defined(OS_MACOSX) + // The nicer version of EnsureProcessTerminated() that is patient and will + // wait for |process_handle| to finish and then reap it. + static void EnsureProcessGetsReaped(base::ProcessHandle process_handle); +#endif + + private: + // Do not instantiate this class. + ProcessWatcher(); + + DISALLOW_COPY_AND_ASSIGN(ProcessWatcher); +}; + +#endif // CHROME_COMMON_PROCESS_WATCHER_H_ diff --git a/chrome/common/process_watcher_mac.cc b/chrome/common/process_watcher_mac.cc new file mode 100644 index 0000000..2702fa7 --- /dev/null +++ b/chrome/common/process_watcher_mac.cc @@ -0,0 +1,170 @@ +// Copyright (c) 2009 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 "chrome/common/process_watcher.h" + +#include <errno.h> +#include <signal.h> +#include <sys/event.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include "base/eintr_wrapper.h" +#include "base/file_util.h" +#include "base/time.h" + +namespace { + +const int kWaitBeforeKillSeconds = 2; + +// Reap |child| process. This call blocks until completion. +void BlockingReap(pid_t child) { + const pid_t result = HANDLE_EINTR(waitpid(child, NULL, 0)); + if (result == -1) { + PLOG(ERROR) << "waitpid(" << child << ", NULL, 0)"; + } +} + +// Waits for |timeout| seconds for the given |child| to exit and reap it. If +// the child doesn't exit within the time specified, kills it. +// +// This function takes two approaches: first, it tries to use kqueue to +// observe when the process exits. kevent can monitor a kqueue with a +// timeout, so this method is preferred to wait for a specified period of +// time. Once the kqueue indicates the process has exited, waitpid will reap +// the exited child. If the kqueue doesn't provide an exit event notification, +// before the timeout expires, or if the kqueue fails or misbehaves, the +// process will be mercilessly killed and reaped. +// +// A child process passed to this function may be in one of several states: +// running, terminated and not yet reaped, and (apparently, and unfortunately) +// terminated and already reaped. Normally, a process will at least have been +// asked to exit before this function is called, but this is not required. +// If a process is terminating and unreaped, there may be a window between the +// time that kqueue will no longer recognize it and when it becomes an actual +// zombie that a non-blocking (WNOHANG) waitpid can reap. This condition is +// detected when kqueue indicates that the process is not running and a +// non-blocking waitpid fails to reap the process but indicates that it is +// still running. In this event, a blocking attempt to reap the process +// collects the known-dying child, preventing zombies from congregating. +// +// In the event that the kqueue misbehaves entirely, as it might under a +// EMFILE condition ("too many open files", or out of file descriptors), this +// function will forcibly kill and reap the child without delay. This +// eliminates another potential zombie vector. (If you're out of file +// descriptors, you're probably deep into something else, but that doesn't +// mean that zombies be allowed to kick you while you're down.) +// +// The fact that this function seemingly can be called to wait on a child +// that's not only already terminated but already reaped is a bit of a +// problem: a reaped child's pid can be reclaimed and may refer to a distinct +// process in that case. The fact that this function can seemingly be called +// to wait on a process that's not even a child is also a problem: kqueue will +// work in that case, but waitpid won't, and killing a non-child might not be +// the best approach. +void WaitForChildToDie(pid_t child, int timeout) { + DCHECK(child > 0); + DCHECK(timeout > 0); + + // DON'T ADD ANY EARLY RETURNS TO THIS FUNCTION without ensuring that + // |child| has been reaped. Specifically, even if a kqueue, kevent, or other + // call fails, this function should fall back to the last resort of trying + // to kill and reap the process. Not observing this rule will resurrect + // zombies. + + int result; + + int kq = HANDLE_EINTR(kqueue()); + if (kq == -1) { + PLOG(ERROR) << "kqueue()"; + } else { + file_util::ScopedFD auto_close_kq(&kq); + + struct kevent change = {0}; + EV_SET(&change, child, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL); + result = HANDLE_EINTR(kevent(kq, &change, 1, NULL, 0, NULL)); + + if (result == -1) { + if (errno != ESRCH) { + PLOG(ERROR) << "kevent (setup " << child << ")"; + } else { + // At this point, one of the following has occurred: + // 1. The process has died but has not yet been reaped. + // 2. The process has died and has already been reaped. + // 3. The process is in the process of dying. It's no longer + // kqueueable, but it may not be waitable yet either. Mark calls + // this case the "zombie death race". + + result = HANDLE_EINTR(waitpid(child, NULL, WNOHANG)); + + if (result != 0) { + // A positive result indicates case 1. waitpid succeeded and reaped + // the child. A result of -1 indicates case 2. The child has already + // been reaped. In both of these cases, no further action is + // necessary. + return; + } + + // |result| is 0, indicating case 3. The process will be waitable in + // short order. Fall back out of the kqueue code to kill it (for good + // measure) and reap it. + } + } else { + // Keep track of the elapsed time to be able to restart kevent if it's + // interrupted. + base::TimeDelta remaining_delta = base::TimeDelta::FromSeconds(timeout); + base::Time deadline = base::Time::Now() + remaining_delta; + result = -1; + struct kevent event = {0}; + while (remaining_delta.InMilliseconds() > 0) { + const struct timespec remaining_timespec = remaining_delta.ToTimeSpec(); + result = kevent(kq, NULL, 0, &event, 1, &remaining_timespec); + if (result == -1 && errno == EINTR) { + remaining_delta = deadline - base::Time::Now(); + result = 0; + } else { + break; + } + } + + if (result == -1) { + PLOG(ERROR) << "kevent (wait " << child << ")"; + } else if (result > 1) { + LOG(ERROR) << "kevent (wait " << child << "): unexpected result " + << result; + } else if (result == 1) { + if ((event.fflags & NOTE_EXIT) && + (event.ident == static_cast<uintptr_t>(child))) { + // The process is dead or dying. This won't block for long, if at + // all. + BlockingReap(child); + return; + } else { + LOG(ERROR) << "kevent (wait " << child + << "): unexpected event: fflags=" << event.fflags + << ", ident=" << event.ident; + } + } + } + } + + // The child is still alive, or is very freshly dead. Be sure by sending it + // a signal. This is safe even if it's freshly dead, because it will be a + // zombie (or on the way to zombiedom) and kill will return 0 even if the + // signal is not delivered to a live process. + result = kill(child, SIGKILL); + if (result == -1) { + PLOG(ERROR) << "kill(" << child << ", SIGKILL)"; + } else { + // The child is definitely on the way out now. BlockingReap won't need to + // wait for long, if at all. + BlockingReap(child); + } +} + +} // namespace + +void ProcessWatcher::EnsureProcessTerminated(base::ProcessHandle process) { + WaitForChildToDie(process, kWaitBeforeKillSeconds); +} diff --git a/chrome/common/process_watcher_posix.cc b/chrome/common/process_watcher_posix.cc new file mode 100644 index 0000000..4b13c32 --- /dev/null +++ b/chrome/common/process_watcher_posix.cc @@ -0,0 +1,105 @@ +// Copyright (c) 2009 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 "chrome/common/process_watcher.h" + +#include <errno.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include "base/eintr_wrapper.h" +#include "base/logging.h" +#include "base/platform_thread.h" + +// Return true if the given child is dead. This will also reap the process. +// Doesn't block. +static bool IsChildDead(pid_t child) { + const pid_t result = HANDLE_EINTR(waitpid(child, NULL, WNOHANG)); + if (result == -1) { + PLOG(ERROR) << "waitpid(" << child << ")"; + NOTREACHED(); + } else if (result > 0) { + // The child has died. + return true; + } + + return false; +} + +// A thread class which waits for the given child to exit and reaps it. +// If the child doesn't exit within a couple of seconds, kill it. +class BackgroundReaper : public PlatformThread::Delegate { + public: + explicit BackgroundReaper(pid_t child, unsigned timeout) + : child_(child), + timeout_(timeout) { + } + + void ThreadMain() { + WaitForChildToDie(); + delete this; + } + + void WaitForChildToDie() { + // Wait forever case. + if (timeout_ == 0) { + pid_t r = HANDLE_EINTR(waitpid(child_, NULL, 0)); + if (r != child_) { + PLOG(ERROR) << "While waiting for " << child_ + << " to terminate, we got the following result: " << r; + } + return; + } + + // There's no good way to wait for a specific child to exit in a timed + // fashion. (No kqueue on Linux), so we just loop and sleep. + + // Wait for 2 * timeout_ 500 milliseconds intervals. + for (unsigned i = 0; i < 2 * timeout_; ++i) { + PlatformThread::Sleep(500); // 0.5 seconds + if (IsChildDead(child_)) + return; + } + + if (kill(child_, SIGKILL) == 0) { + // SIGKILL is uncatchable. Since the signal was delivered, we can + // just wait for the process to die now in a blocking manner. + if (HANDLE_EINTR(waitpid(child_, NULL, 0)) < 0) + PLOG(WARNING) << "waitpid"; + } else { + LOG(ERROR) << "While waiting for " << child_ << " to terminate we" + << " failed to deliver a SIGKILL signal (" << errno << ")."; + } + } + + private: + const pid_t child_; + // Number of seconds to wait, if 0 then wait forever and do not attempt to + // kill |child_|. + const unsigned timeout_; + + DISALLOW_COPY_AND_ASSIGN(BackgroundReaper); +}; + +// static +void ProcessWatcher::EnsureProcessTerminated(base::ProcessHandle process) { + // If the child is already dead, then there's nothing to do. + if (IsChildDead(process)) + return; + + const unsigned timeout = 2; // seconds + BackgroundReaper* reaper = new BackgroundReaper(process, timeout); + PlatformThread::CreateNonJoinable(0, reaper); +} + +// static +void ProcessWatcher::EnsureProcessGetsReaped(base::ProcessHandle process) { + // If the child is already dead, then there's nothing to do. + if (IsChildDead(process)) + return; + + BackgroundReaper* reaper = new BackgroundReaper(process, 0); + PlatformThread::CreateNonJoinable(0, reaper); +} diff --git a/chrome/common/process_watcher_unittest.cc b/chrome/common/process_watcher_unittest.cc new file mode 100644 index 0000000..af4aaa2 --- /dev/null +++ b/chrome/common/process_watcher_unittest.cc @@ -0,0 +1,64 @@ +// Copyright (c) 2009 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 "chrome/common/process_watcher.h" + +#if defined(OS_POSIX) +#include <sys/wait.h> + +#include "base/eintr_wrapper.h" +#include "base/multiprocess_test.h" +#include "base/process_util.h" +#include "testing/gtest/include/gtest/gtest.h" + +class ProcessWatcherTest : public MultiProcessTest { +}; + +namespace { + +bool IsProcessDead(base::ProcessHandle child) { + // waitpid() will actually reap the process which is exactly NOT what we + // want to test for. The good thing is that if it can't find the process + // we'll get a nice value for errno which we can test for. + const pid_t result = HANDLE_EINTR(waitpid(child, NULL, WNOHANG)); + return result == -1 && errno == ECHILD; +} + +} // namespace + +TEST_F(ProcessWatcherTest, DelayedTermination) { + base::ProcessHandle child_process = + SpawnChild(L"process_watcher_test_never_die"); + ProcessWatcher::EnsureProcessTerminated(child_process); + base::WaitForSingleProcess(child_process, 5000); + + // Check that process was really killed. + EXPECT_TRUE(IsProcessDead(child_process)); + base::CloseProcessHandle(child_process); +} + +MULTIPROCESS_TEST_MAIN(process_watcher_test_never_die) { + while (1) { + sleep(500); + } + return 0; +} + +TEST_F(ProcessWatcherTest, ImmediateTermination) { + base::ProcessHandle child_process = + SpawnChild(L"process_watcher_test_die_immediately"); + // Give it time to die. + sleep(2); + ProcessWatcher::EnsureProcessTerminated(child_process); + + // Check that process was really killed. + EXPECT_TRUE(IsProcessDead(child_process)); + base::CloseProcessHandle(child_process); +} + +MULTIPROCESS_TEST_MAIN(process_watcher_test_die_immediately) { + return 0; +} + +#endif // OS_POSIX diff --git a/chrome/common/process_watcher_win.cc b/chrome/common/process_watcher_win.cc new file mode 100644 index 0000000..ed99780 --- /dev/null +++ b/chrome/common/process_watcher_win.cc @@ -0,0 +1,95 @@ +// Copyright (c) 2010 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 "chrome/common/process_watcher.h" + +#include "base/scoped_ptr.h" +#include "base/env_var.h" +#include "base/message_loop.h" +#include "base/object_watcher.h" +#include "chrome/common/env_vars.h" +#include "chrome/common/result_codes.h" + +// Maximum amount of time (in milliseconds) to wait for the process to exit. +static const int kWaitInterval = 2000; + +namespace { + +class TimerExpiredTask : public Task, public base::ObjectWatcher::Delegate { + public: + explicit TimerExpiredTask(base::ProcessHandle process) : process_(process) { + watcher_.StartWatching(process_, this); + } + + virtual ~TimerExpiredTask() { + if (process_) { + KillProcess(); + DCHECK(!process_) << "Make sure to close the handle."; + } + } + + // Task --------------------------------------------------------------------- + + virtual void Run() { + if (process_) + KillProcess(); + } + + // MessageLoop::Watcher ----------------------------------------------------- + + virtual void OnObjectSignaled(HANDLE object) { + // When we're called from KillProcess, the ObjectWatcher may still be + // watching. the process handle, so make sure it has stopped. + watcher_.StopWatching(); + + CloseHandle(process_); + process_ = NULL; + } + + private: + void KillProcess() { + scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create()); + if (env->HasEnv(env_vars::kHeadless)) { + // If running the distributed tests, give the renderer a little time + // to figure out that the channel is shutdown and unwind. + if (WaitForSingleObject(process_, kWaitInterval) == WAIT_OBJECT_0) { + OnObjectSignaled(process_); + return; + } + } + + // OK, time to get frisky. We don't actually care when the process + // terminates. We just care that it eventually terminates, and that's what + // TerminateProcess should do for us. Don't check for the result code since + // it fails quite often. This should be investigated eventually. + base::KillProcess(process_, ResultCodes::HUNG, false); + + // Now, just cleanup as if the process exited normally. + OnObjectSignaled(process_); + } + + // The process that we are watching. + base::ProcessHandle process_; + + base::ObjectWatcher watcher_; + + DISALLOW_COPY_AND_ASSIGN(TimerExpiredTask); +}; + +} // namespace + +// static +void ProcessWatcher::EnsureProcessTerminated(base::ProcessHandle process) { + DCHECK(process != GetCurrentProcess()); + + // If already signaled, then we are done! + if (WaitForSingleObject(process, 0) == WAIT_OBJECT_0) { + CloseHandle(process); + return; + } + + MessageLoop::current()->PostDelayedTask(FROM_HERE, + new TimerExpiredTask(process), + kWaitInterval); +} diff --git a/chrome/common/property_bag.cc b/chrome/common/property_bag.cc new file mode 100644 index 0000000..dc25961 --- /dev/null +++ b/chrome/common/property_bag.cc @@ -0,0 +1,55 @@ +// Copyright (c) 2006-2008 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 "chrome/common/property_bag.h" + +PropertyBag::PropertyBag() { +} + +PropertyBag::PropertyBag(const PropertyBag& other) { + operator=(other); +} + +PropertyBag::~PropertyBag() { +} + +PropertyBag& PropertyBag::operator=(const PropertyBag& other) { + props_.clear(); + + // We need to make copies of each property using the virtual copy() method. + for (PropertyMap::const_iterator i = other.props_.begin(); + i != other.props_.end(); ++i) + props_[i->first] = linked_ptr<Prop>(i->second->copy()); + return *this; +} + +void PropertyBag::SetProperty(PropID id, Prop* prop) { + props_[id] = linked_ptr<Prop>(prop); +} + +PropertyBag::Prop* PropertyBag::GetProperty(PropID id) { + PropertyMap::const_iterator found = props_.find(id); + if (found == props_.end()) + return NULL; + return found->second.get(); +} + +const PropertyBag::Prop* PropertyBag::GetProperty(PropID id) const { + PropertyMap::const_iterator found = props_.find(id); + if (found == props_.end()) + return NULL; + return found->second.get(); +} + +void PropertyBag::DeleteProperty(PropID id) { + PropertyMap::iterator found = props_.find(id); + if (found == props_.end()) + return; // Not found, nothing to do. + props_.erase(found); +} + +PropertyAccessorBase::PropertyAccessorBase() { + static PropertyBag::PropID next_id = 1; + prop_id_ = next_id++; +} diff --git a/chrome/common/property_bag.h b/chrome/common/property_bag.h new file mode 100644 index 0000000..778d0b9 --- /dev/null +++ b/chrome/common/property_bag.h @@ -0,0 +1,173 @@ +// Copyright (c) 2006-2008 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 CHROME_COMMON_PROPERTY_BAG_H_ +#define CHROME_COMMON_PROPERTY_BAG_H_ + +#include <map> + +#include "base/basictypes.h" +#include "base/linked_ptr.h" + +class PropertyAccessorBase; + +// A property bag holds a generalized list of arbitrary metadata called +// properties. Each property is a class type derived from PropertyBag::Prop +// that can bet set and retrieved. +// +// The property bag is not read or written directly. Instead, callers go +// through a PropertyAccessor. The Accessor generates the unique IDs that +// identify different properties. The Accessor is templatized to also provide +// typesafety to the callers. +// +// Example: +// // Note: you don't want to use Singleton for your Accessor if you're using +// // a simple type like int or string as the data, since it will enforce that +// // there is only one singleton for that type, which will conflict. If +// // you're putting in some struct that's unique to you, go ahead. +// PropertyAccessor<int>* my_accessor() const { +// static PropertyAccessor<int>* accessor = NULL; +// if (!accessor) accessor = new PropertyAccessor<int>; +// return accessor; +// } +// +// void doit(SomeObjectThatImplementsPropertyBag* object) { +// PropertyAccessor<int>* accessor = my_accessor(); +// int* property = accessor.GetProperty(object); +// if (property) +// ... use property ... +// +// accessor.SetProperty(object, 22); +// } +class PropertyBag { + public: + // The type that uniquely identifies a property type. + typedef int PropID; + enum { NULL_PROP_ID = -1 }; // Invalid property ID. + + // Properties are all derived from this class. They must be deletable and + // copyable + class Prop { + public: + virtual ~Prop() {} + + // Copies the property and returns a pointer to the new one. The caller is + // responsible for managing the lifetime. + virtual Prop* copy() = 0; + }; + + PropertyBag(); + PropertyBag(const PropertyBag& other); + virtual ~PropertyBag(); + + PropertyBag& operator=(const PropertyBag& other); + + private: + friend class PropertyAccessorBase; + + typedef std::map<PropID, linked_ptr<Prop> > PropertyMap; + + // Used by the PropertyAccessor to set the property with the given ID. + // Ownership of the given pointer will be transferred to us. Any existing + // property matching the given ID will be deleted. + void SetProperty(PropID id, Prop* prop); + + // Used by the PropertyAccessor to retrieve the property with the given ID. + // The returned pointer will be NULL if there is no match. Ownership of the + // pointer will stay with the property bag. + Prop* GetProperty(PropID id); + const Prop* GetProperty(PropID id) const; + + // Deletes the property with the given ID from the bag if it exists. + void DeleteProperty(PropID id); + + PropertyMap props_; + + // Copy and assign is explicitly allowed for this class. +}; + +// PropertyAccessorBase ------------------------------------------------------- + +// Manages getting the unique IDs to identify a property. Callers should use +// PropertyAccessor below instead. +class PropertyAccessorBase { + public: + PropertyAccessorBase(); + virtual ~PropertyAccessorBase() {} + + // Removes our property, if any, from the given property bag. + void DeleteProperty(PropertyBag* bag) { + bag->DeleteProperty(prop_id_); + } + + protected: + void SetPropertyInternal(PropertyBag* bag, PropertyBag::Prop* prop) { + bag->SetProperty(prop_id_, prop); + } + PropertyBag::Prop* GetPropertyInternal(PropertyBag* bag) { + return bag->GetProperty(prop_id_); + } + const PropertyBag::Prop* GetPropertyInternal(const PropertyBag* bag) const { + return bag->GetProperty(prop_id_); + } + + private: + // Identifier for this property. + PropertyBag::PropID prop_id_; + + DISALLOW_COPY_AND_ASSIGN(PropertyAccessorBase); +}; + +// PropertyAccessor ----------------------------------------------------------- + +// Provides typesafe accessor functions for a property bag, and manages the +// unique identifiers for properties via the PropertyAccessorBase. +template<class T> +class PropertyAccessor : public PropertyAccessorBase { + public: + PropertyAccessor() : PropertyAccessorBase() {} + virtual ~PropertyAccessor() {} + + // Makes a copy of the |prop| object for storage. + void SetProperty(PropertyBag* bag, const T& prop) { + SetPropertyInternal(bag, new Container(prop)); + } + + // Returns our property in the given bag or NULL if there is no match. The + // returned pointer's ownership will stay with the property bag. + T* GetProperty(PropertyBag* bag) { + PropertyBag::Prop* prop = GetPropertyInternal(bag); + if (!prop) + return NULL; + return static_cast<Container*>(prop)->get(); + } + const T* GetProperty(const PropertyBag* bag) const { + const PropertyBag::Prop* prop = GetPropertyInternal(bag); + if (!prop) + return NULL; + return static_cast<const Container*>(prop)->get(); + } + + // See also DeleteProperty on thn PropertyAccessorBase. + + private: + class Container : public PropertyBag::Prop { + public: + explicit Container(const T& data) : data_(data) {} + + T* get() { return &data_; } + const T* get() const { return &data_; } + + private: + virtual Prop* copy() { + return new Container(data_); + } + + T data_; + }; + + DISALLOW_COPY_AND_ASSIGN(PropertyAccessor); +}; + +#endif // CHROME_COMMON_PROPERTY_BAG_H_ diff --git a/chrome/common/property_bag_unittest.cc b/chrome/common/property_bag_unittest.cc new file mode 100644 index 0000000..f63bbc2 --- /dev/null +++ b/chrome/common/property_bag_unittest.cc @@ -0,0 +1,62 @@ +// Copyright (c) 2009 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 "chrome/common/property_bag.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(PropertyBagTest, AddQueryRemove) { + PropertyBag bag; + PropertyAccessor<int> adaptor; + + // Should be no match initially. + EXPECT_TRUE(adaptor.GetProperty(&bag) == NULL); + + // Add the value and make sure we get it back. + const int kFirstValue = 1; + adaptor.SetProperty(&bag, kFirstValue); + ASSERT_TRUE(adaptor.GetProperty(&bag)); + EXPECT_EQ(kFirstValue, *adaptor.GetProperty(&bag)); + + // Set it to a new value. + const int kSecondValue = 2; + adaptor.SetProperty(&bag, kSecondValue); + ASSERT_TRUE(adaptor.GetProperty(&bag)); + EXPECT_EQ(kSecondValue, *adaptor.GetProperty(&bag)); + + // Remove the value and make sure it's gone. + adaptor.DeleteProperty(&bag); + EXPECT_TRUE(adaptor.GetProperty(&bag) == NULL); +} + +TEST(PropertyBagTest, Copy) { + PropertyAccessor<int> adaptor1; + PropertyAccessor<double> adaptor2; + + // Create a bag with property type 1 in it. + PropertyBag copy; + adaptor1.SetProperty(©, 22); + + const int kType1Value = 10; + const double kType2Value = 2.7; + { + // Create a bag with property types 1 and 2 in it. + PropertyBag initial; + adaptor1.SetProperty(&initial, kType1Value); + adaptor2.SetProperty(&initial, kType2Value); + + // Assign to the original. + copy = initial; + } + + // Verify the copy got the two properties. + ASSERT_TRUE(adaptor1.GetProperty(©)); + ASSERT_TRUE(adaptor2.GetProperty(©)); + EXPECT_EQ(kType1Value, *adaptor1.GetProperty(©)); + EXPECT_EQ(kType2Value, *adaptor2.GetProperty(©)); + + // Clear it out, neither property should be left. + copy = PropertyBag(); + EXPECT_TRUE(adaptor1.GetProperty(©) == NULL); + EXPECT_TRUE(adaptor2.GetProperty(©) == NULL); +} diff --git a/chrome/common/ref_counted_util.h b/chrome/common/ref_counted_util.h new file mode 100644 index 0000000..b04580e --- /dev/null +++ b/chrome/common/ref_counted_util.h @@ -0,0 +1,26 @@ +// Copyright (c) 2006-2008 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 CHROME_COMMON_REF_COUNTED_UTIL_H__ +#define CHROME_COMMON_REF_COUNTED_UTIL_H__ + +#include "base/ref_counted.h" +#include <vector> + +// RefCountedVector is just a vector wrapped up with +// RefCountedThreadSafe. +template<class T> +class RefCountedVector + : public base::RefCountedThreadSafe<RefCountedVector<T> > { + public: + RefCountedVector() {} + explicit RefCountedVector(const std::vector<T>& initializer) + : data(initializer) {} + + std::vector<T> data; + + DISALLOW_COPY_AND_ASSIGN(RefCountedVector<T>); +}; + +#endif // CHROME_COMMON_REF_COUNTED_UTIL_H__ diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h new file mode 100644 index 0000000..e1ec6b3 --- /dev/null +++ b/chrome/common/render_messages.h @@ -0,0 +1,3214 @@ +// Copyright (c) 2010 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 CHROME_COMMON_RENDER_MESSAGES_H_ +#define CHROME_COMMON_RENDER_MESSAGES_H_ + +#include <map> +#include <string> +#include <vector> + +#include "app/clipboard/clipboard.h" +#include "app/surface/transport_dib.h" +#include "base/basictypes.h" +#include "base/platform_file.h" +#include "base/ref_counted.h" +#include "base/shared_memory.h" +#include "base/string16.h" +#include "chrome/common/common_param_traits.h" +#include "chrome/common/css_colors.h" +#include "chrome/common/dom_storage_common.h" +#include "chrome/common/edit_command.h" +#include "chrome/common/extensions/extension_extent.h" +#include "chrome/common/extensions/url_pattern.h" +#include "chrome/common/font_descriptor_mac.h" +#include "chrome/common/indexed_db_key.h" +#include "chrome/common/navigation_gesture.h" +#include "chrome/common/page_transition_types.h" +#include "chrome/common/renderer_preferences.h" +#include "chrome/common/resource_response.h" +#include "chrome/common/translate_errors.h" +#include "chrome/common/view_types.h" +#include "chrome/common/serialized_script_value.h" +#include "chrome/common/webkit_param_traits.h" +#include "chrome/common/window_container_type.h" +#include "gfx/native_widget_types.h" +#include "googleurl/src/gurl.h" +#include "ipc/ipc_message_utils.h" +#include "ipc/ipc_platform_file.h" +#include "media/audio/audio_io.h" +#include "net/base/upload_data.h" +#include "net/http/http_response_headers.h" +#include "third_party/WebKit/WebKit/chromium/public/WebStorageArea.h" +#include "third_party/WebKit/WebKit/chromium/public/WebTextDirection.h" +#include "webkit/appcache/appcache_interfaces.h" +#include "webkit/glue/context_menu.h" +#include "webkit/glue/form_data.h" +#include "webkit/glue/form_field.h" +#include "webkit/glue/password_form.h" +#include "webkit/glue/password_form_dom_manager.h" +#include "webkit/glue/plugins/webplugin.h" +#include "webkit/glue/plugins/webplugininfo.h" +#include "webkit/glue/resource_loader_bridge.h" +#include "webkit/glue/webaccessibility.h" +#include "webkit/glue/webcookie.h" +#include "webkit/glue/webdropdata.h" +#include "webkit/glue/webmenuitem.h" +#include "webkit/glue/webpreferences.h" + +namespace base { +class Time; +} + +class SkBitmap; + +// Parameters structure for ViewMsg_Navigate, which has too many data +// parameters to be reasonably put in a predefined IPC message. +struct ViewMsg_Navigate_Params { + enum NavigationType { + // Reload the page. + RELOAD, + + // Reload the page, ignoring any cache entries. + RELOAD_IGNORING_CACHE, + + // The navigation is the result of session restore and should honor the + // page's cache policy while restoring form state. This is set to true if + // restoring a tab/session from the previous session and the previous + // session did not crash. If this is not set and the page was restored then + // the page's cache policy is ignored and we load from the cache. + RESTORE, + + // Navigation type not categorized by the other types. + NORMAL + }; + + // The page_id for this navigation, or -1 if it is a new navigation. Back, + // Forward, and Reload navigations should have a valid page_id. If the load + // succeeds, then this page_id will be reflected in the resultant + // ViewHostMsg_FrameNavigate message. + int32 page_id; + + // If page_id is -1, then pending_history_list_offset will also be -1. + // Otherwise, it contains the offset into the history list corresponding to + // the current navigation. + int pending_history_list_offset; + + // Informs the RenderView of where its current page contents reside in + // session history and the total size of the session history list. + int current_history_list_offset; + int current_history_list_length; + + // The URL to load. + GURL url; + + // The URL to send in the "Referer" header field. Can be empty if there is + // no referrer. + GURL referrer; + + // The type of transition. + PageTransition::Type transition; + + // Opaque history state (received by ViewHostMsg_UpdateState). + std::string state; + + // Type of navigation. + NavigationType navigation_type; + + // The time the request was created + base::Time request_time; +}; + +// Current status of the audio output stream in the browser process. Browser +// sends information about the current playback state and error to the +// renderer process using this type. +struct ViewMsg_AudioStreamState_Params { + enum State { + kPlaying, + kPaused, + kError + }; + + // Carries the current playback state. + State state; +}; + +// The user has completed a find-in-page; this type defines what actions the +// renderer should take next. +struct ViewMsg_StopFinding_Params { + enum Action { + kClearSelection, + kKeepSelection, + kActivateSelection + }; + + // The action that should be taken when the find is completed. + Action action; +}; + +// The install state of the search provider (not installed, installed, default). +struct ViewHostMsg_GetSearchProviderInstallState_Params { + enum State { + // Equates to an access denied error. + DENIED = -1, + + // DON'T CHANGE THE VALUES BELOW. + // All of the following values are manidated by the + // spec for window.external.IsSearchProviderInstalled. + + // The search provider is not installed. + NOT_INSTALLED = 0, + + // The search provider is in the user's set but is not + INSTALLED_BUT_NOT_DEFAULT = 1, + + // The search provider is set as the user's default. + INSTALLED_AS_DEFAULT = 2 + }; + State state; + + ViewHostMsg_GetSearchProviderInstallState_Params() + : state(DENIED) { + } + + explicit ViewHostMsg_GetSearchProviderInstallState_Params(State s) + : state(s) { + } + + static ViewHostMsg_GetSearchProviderInstallState_Params Denied() { + return ViewHostMsg_GetSearchProviderInstallState_Params(DENIED); + } + + static ViewHostMsg_GetSearchProviderInstallState_Params NotInstalled() { + return ViewHostMsg_GetSearchProviderInstallState_Params(NOT_INSTALLED); + } + + static ViewHostMsg_GetSearchProviderInstallState_Params + InstallButNotDefault() { + return ViewHostMsg_GetSearchProviderInstallState_Params( + INSTALLED_BUT_NOT_DEFAULT); + } + + static ViewHostMsg_GetSearchProviderInstallState_Params InstalledAsDefault() { + return ViewHostMsg_GetSearchProviderInstallState_Params( + INSTALLED_AS_DEFAULT); + } +}; + + +// Parameters structure for ViewHostMsg_FrameNavigate, which has too many data +// parameters to be reasonably put in a predefined IPC message. +struct ViewHostMsg_FrameNavigate_Params { + // Page ID of this navigation. The renderer creates a new unique page ID + // anytime a new session history entry is created. This means you'll get new + // page IDs for user actions, and the old page IDs will be reloaded when + // iframes are loaded automatically. + int32 page_id; + + // URL of the page being loaded. + GURL url; + + // URL of the referrer of this load. WebKit generates this based on the + // source of the event that caused the load. + GURL referrer; + + // The type of transition. + PageTransition::Type transition; + + // Lists the redirects that occurred on the way to the current page. This + // vector has the same format as reported by the WebDataSource in the glue, + // with the current page being the last one in the list (so even when + // there's no redirect, there will be one entry in the list. + std::vector<GURL> redirects; + + // Set to false if we want to update the session history but not update + // the browser history. E.g., on unreachable urls. + bool should_update_history; + + // See SearchableFormData for a description of these. + GURL searchable_form_url; + std::string searchable_form_encoding; + + // See password_form.h. + webkit_glue::PasswordForm password_form; + + // Information regarding the security of the connection (empty if the + // connection was not secure). + std::string security_info; + + // The gesture that initiated this navigation. + NavigationGesture gesture; + + // Contents MIME type of main frame. + std::string contents_mime_type; + + // True if this was a post request. + bool is_post; + + // Whether the content of the frame was replaced with some alternate content + // (this can happen if the resource was insecure). + bool is_content_filtered; + + // The status code of the HTTP request. + int http_status_code; +}; + +// Values that may be OR'd together to form the 'flags' parameter of a +// ViewHostMsg_UpdateRect_Params structure. +struct ViewHostMsg_UpdateRect_Flags { + enum { + IS_RESIZE_ACK = 1 << 0, + IS_RESTORE_ACK = 1 << 1, + IS_REPAINT_ACK = 1 << 2, + }; + static bool is_resize_ack(int flags) { + return (flags & IS_RESIZE_ACK) != 0; + } + static bool is_restore_ack(int flags) { + return (flags & IS_RESTORE_ACK) != 0; + } + static bool is_repaint_ack(int flags) { + return (flags & IS_REPAINT_ACK) != 0; + } +}; + +struct ViewHostMsg_UpdateRect_Params { + // The bitmap to be painted into the view at the locations specified by + // update_rects. + TransportDIB::Id bitmap; + + // The position and size of the bitmap. + gfx::Rect bitmap_rect; + + // The scroll offset. Only one of these can be non-zero, and if they are + // both zero, then it means there is no scrolling and the scroll_rect is + // ignored. + int dx; + int dy; + + // The rectangular region to scroll. + gfx::Rect scroll_rect; + + // The regions of the bitmap (in view coords) that contain updated pixels. + // In the case of scrolling, this includes the scroll damage rect. + std::vector<gfx::Rect> copy_rects; + + // The size of the RenderView when this message was generated. This is + // included so the host knows how large the view is from the perspective of + // the renderer process. This is necessary in case a resize operation is in + // progress. + gfx::Size view_size; + + // New window locations for plugin child windows. + std::vector<webkit_glue::WebPluginGeometry> plugin_window_moves; + + // The following describes the various bits that may be set in flags: + // + // ViewHostMsg_UpdateRect_Flags::IS_RESIZE_ACK + // Indicates that this is a response to a ViewMsg_Resize message. + // + // ViewHostMsg_UpdateRect_Flags::IS_RESTORE_ACK + // Indicates that this is a response to a ViewMsg_WasRestored message. + // + // ViewHostMsg_UpdateRect_Flags::IS_REPAINT_ACK + // Indicates that this is a response to a ViewMsg_Repaint message. + // + // If flags is zero, then this message corresponds to an unsoliticed paint + // request by the render view. Any of the above bits may be set in flags, + // which would indicate that this paint message is an ACK for multiple + // request messages. + int flags; +}; + +// Information on closing a tab. This is used both for ViewMsg_ClosePage, and +// the corresponding ViewHostMsg_ClosePage_ACK. +struct ViewMsg_ClosePage_Params { + // The identifier of the RenderProcessHost for the currently closing view. + // + // These first two parameters are technically redundant since they are + // needed only when processing the ACK message, and the processor + // theoretically knows both the process and route ID. However, this is + // difficult to figure out with our current implementation, so this + // information is duplicate here. + int closing_process_id; + + // The route identifier for the currently closing RenderView. + int closing_route_id; + + // True when this close is for the first (closing) tab of a cross-site + // transition where we switch processes. False indicates the close is for the + // entire tab. + // + // When true, the new_* variables below must be filled in. Otherwise they must + // both be -1. + bool for_cross_site_transition; + + // The identifier of the RenderProcessHost for the new view attempting to + // replace the closing one above. This must be valid when + // for_cross_site_transition is set, and must be -1 otherwise. + int new_render_process_host_id; + + // The identifier of the *request* the new view made that is causing the + // cross-site transition. This is *not* a route_id, but the request that we + // will resume once the ACK from the closing view has been received. This + // must be valid when for_cross_site_transition is set, and must be -1 + // otherwise. + int new_request_id; +}; + +// Parameters for a resource request. +struct ViewHostMsg_Resource_Request { + // The request method: GET, POST, etc. + std::string method; + + // The requested URL. + GURL url; + + // Usually the URL of the document in the top-level window, which may be + // checked by the third-party cookie blocking policy. Leaving it empty may + // lead to undesired cookie blocking. Third-party cookie blocking can be + // bypassed by setting first_party_for_cookies = url, but this should ideally + // only be done if there really is no way to determine the correct value. + GURL first_party_for_cookies; + + // The referrer to use (may be empty). + GURL referrer; + + // The origin of the frame that is associated with this request. This is used + // to update our insecure content state. + std::string frame_origin; + + // The origin of the main frame (top-level frame) that is associated with this + // request. This is used to update our insecure content state. + std::string main_frame_origin; + + // Additional HTTP request headers. + std::string headers; + + // URLRequest load flags (0 by default). + int load_flags; + + // Unique ID of process that originated this request. For normal renderer + // requests, this will be the ID of the renderer. For plugin requests routed + // through the renderer, this will be the plugin's ID. + int origin_child_id; + + // What this resource load is for (main frame, sub-frame, sub-resource, + // object). + ResourceType::Type resource_type; + + // Used by plugin->browser requests to get the correct URLRequestContext. + uint32 request_context; + + // Indicates which frame (or worker context) the request is being loaded into, + // or kNoHostId. + int appcache_host_id; + + // Optional upload data (may be null). + scoped_refptr<net::UploadData> upload_data; + + // The following two members are specified if the request is initiated by + // a plugin like Gears. + + // Contains the id of the host renderer. + int host_renderer_id; + + // Contains the id of the host render view. + int host_render_view_id; +}; + +// Parameters for a render request. +struct ViewMsg_Print_Params { + // Physical size of the page, including non-printable margins, + // in pixels according to dpi. + gfx::Size page_size; + + // In pixels according to dpi_x and dpi_y. + gfx::Size printable_size; + + // The y-offset of the printable area, in pixels according to dpi. + int margin_top; + + // The x-offset of the printable area, in pixels according to dpi. + int margin_left; + + // Specifies dots per inch. + double dpi; + + // Minimum shrink factor. See PrintSettings::min_shrink for more information. + double min_shrink; + + // Maximum shrink factor. See PrintSettings::max_shrink for more information. + double max_shrink; + + // Desired apparent dpi on paper. + int desired_dpi; + + // Cookie for the document to ensure correctness. + int document_cookie; + + // Should only print currently selected text. + bool selection_only; + + // Warning: do not compare document_cookie. + bool Equals(const ViewMsg_Print_Params& rhs) const { + return page_size == rhs.page_size && + printable_size == rhs.printable_size && + margin_top == rhs.margin_top && + margin_left == rhs.margin_left && + dpi == rhs.dpi && + min_shrink == rhs.min_shrink && + max_shrink == rhs.max_shrink && + desired_dpi == rhs.desired_dpi && + selection_only == rhs.selection_only; + } + + // Checking if the current params is empty. Just initialized after a memset. + bool IsEmpty() const { + return !document_cookie && !desired_dpi && !max_shrink && !min_shrink && + !dpi && printable_size.IsEmpty() && !selection_only && + page_size.IsEmpty() && !margin_top && !margin_left; + } +}; + +struct ViewMsg_PrintPage_Params { + // Parameters to render the page as a printed page. It must always be the same + // value for all the document. + ViewMsg_Print_Params params; + + // The page number is the indicator of the square that should be rendered + // according to the layout specified in ViewMsg_Print_Params. + int page_number; +}; + +struct ViewMsg_PrintPages_Params { + // Parameters to render the page as a printed page. It must always be the same + // value for all the document. + ViewMsg_Print_Params params; + + // If empty, this means a request to render all the printed pages. + std::vector<int> pages; +}; + +// Parameters to describe a rendered page. +struct ViewHostMsg_DidPrintPage_Params { + // A shared memory handle to the EMF data. This data can be quite large so a + // memory map needs to be used. + base::SharedMemoryHandle metafile_data_handle; + + // Size of the metafile data. + uint32 data_size; + + // Cookie for the document to ensure correctness. + int document_cookie; + + // Page number. + int page_number; + + // Shrink factor used to render this page. + double actual_shrink; + + // The size of the page the page author specified. + gfx::Size page_size; + + // The printable area the page author specified. + gfx::Rect content_area; + + // True if the page has visible overlays. + bool has_visible_overlays; +}; + +// Parameters for creating an audio output stream. +struct ViewHostMsg_Audio_CreateStream_Params { + // Format request for the stream. + AudioManager::Format format; + + // Number of channels. + int channels; + + // Sampling rate (frequency) of the output stream. + int sample_rate; + + // Number of bits per sample; + int bits_per_sample; + + // Number of bytes per packet. Determines the maximum number of bytes + // transported for each audio packet request. + // A value of 0 means that the audio packet size is selected automatically + // by the browser process. + uint32 packet_size; +}; + +// This message is used for supporting popup menus on Mac OS X using native +// Cocoa controls. The renderer sends us this message which we use to populate +// the popup menu. +struct ViewHostMsg_ShowPopup_Params { + // Position on the screen. + gfx::Rect bounds; + + // The height of each item in the menu. + int item_height; + + // The size of the font to use for those items. + double item_font_size; + + // The currently selected (displayed) item in the menu. + int selected_item; + + // The entire list of items in the popup menu. + std::vector<WebMenuItem> popup_items; + + // Whether items should be right-aligned. + bool right_aligned; +}; + +// Parameters for the IPC message ViewHostMsg_ScriptedPrint +struct ViewHostMsg_ScriptedPrint_Params { + int routing_id; + gfx::NativeViewId host_window_id; + int cookie; + int expected_pages_count; + bool has_selection; + bool use_overlays; +}; + +// Signals a storage event. +struct ViewMsg_DOMStorageEvent_Params { + // The key that generated the storage event. Null if clear() was called. + NullableString16 key_; + + // The old value of this key. Null on clear() or if it didn't have a value. + NullableString16 old_value_; + + // The new value of this key. Null on removeItem() or clear(). + NullableString16 new_value_; + + // The origin this is associated with. + string16 origin_; + + // The URL of the page that caused the storage event. + GURL url_; + + // The storage type of this event. + DOMStorageType storage_type_; +}; + +// Used to open an indexed database. +struct ViewHostMsg_IndexedDatabaseOpen_Params { + // The routing ID of the view initiating the open. + int32 routing_id_; + + // The response should have this id. + int32 response_id_; + + // The origin doing the initiating. + string16 origin_; + + // The name of the database. + string16 name_; + + // The description of the database. + string16 description_; +}; + +// Used to create an object store. +struct ViewHostMsg_IDBDatabaseCreateObjectStore_Params { + // The response should have this id. + int32 response_id_; + + // The name of the object store. + string16 name_; + + // The keyPath of the object store. + NullableString16 key_path_; + + // Whether the object store created should have a key generator. + bool auto_increment_; + + // The database the object store belongs to. + int32 idb_database_id_; +}; + +// Used to create an index. +struct ViewHostMsg_IDBObjectStoreCreateIndex_Params { + // The response should have this id. + int32 response_id_; + + // The name of the index. + string16 name_; + + // The keyPath of the index. + NullableString16 key_path_; + + // Whether the index created has unique keys. + bool unique_; + + // The object store the index belongs to. + int32 idb_object_store_id_; +}; + +// Allows an extension to execute code in a tab. +struct ViewMsg_ExecuteCode_Params { + ViewMsg_ExecuteCode_Params() {} + ViewMsg_ExecuteCode_Params(int request_id, const std::string& extension_id, + const std::vector<URLPattern>& host_permissions, + bool is_javascript, const std::string& code, + bool all_frames) + : request_id(request_id), extension_id(extension_id), + host_permissions(host_permissions), is_javascript(is_javascript), + code(code), all_frames(all_frames) { + } + + // The extension API request id, for responding. + int request_id; + + // The ID of the requesting extension. To know which isolated world to + // execute the code inside of. + std::string extension_id; + + // The host permissions of the requesting extension. So that we can check them + // right before injecting, to avoid any race conditions. + std::vector<URLPattern> host_permissions; + + // Whether the code is JavaScript or CSS. + bool is_javascript; + + // String of code to execute. + std::string code; + + // Whether to inject into all frames, or only the root frame. + bool all_frames; +}; + +// Parameters for the message that creates a worker thread. +struct ViewHostMsg_CreateWorker_Params { + // URL for the worker script. + GURL url; + + // True if this is a SharedWorker, false if it is a dedicated Worker. + bool is_shared; + + // Name for a SharedWorker, otherwise empty string. + string16 name; + + // The ID of the parent document (unique within parent renderer). + unsigned long long document_id; + + // RenderView routing id used to send messages back to the parent. + int render_view_route_id; + + // The route ID to associate with the worker. If MSG_ROUTING_NONE is passed, + // a new unique ID is created and assigned to the worker. + int route_id; + + // The ID of the parent's appcache host, only valid for dedicated workers. + int parent_appcache_host_id; + + // The ID of the appcache the main shared worker script resource was loaded + // from, only valid for shared workers. + int64 script_resource_appcache_id; +}; + +// Parameters for the message that creates a desktop notification. +struct ViewHostMsg_ShowNotification_Params { + // URL which is the origin that created this notification. + GURL origin; + + // True if this is HTML + bool is_html; + + // URL which contains the HTML contents (if is_html is true), otherwise empty. + GURL contents_url; + + // Contents of the notification if is_html is false. + GURL icon_url; + string16 title; + string16 body; + + // Directionality of the notification. + WebKit::WebTextDirection direction; + + // ReplaceID if this notification should replace an existing one; may be + // empty if no replacement is called for. + string16 replace_id; + + // Notification ID for sending events back for this notification. + int notification_id; +}; + +// Creates a new view via a control message since the view doesn't yet exist. +struct ViewMsg_New_Params { + // The parent window's id. + gfx::NativeViewId parent_window; + + // Renderer-wide preferences. + RendererPreferences renderer_preferences; + + // Preferences for this view. + WebPreferences web_preferences; + + // The ID of the view to be created. + int32 view_id; + + // The session storage namespace ID this view should use. + int64 session_storage_namespace_id; + + // The name of the frame associated with this view (or empty if none). + string16 frame_name; +}; + +struct ViewHostMsg_CreateWindow_Params { + // Routing ID of the view initiating the open. + int opener_id; + + // True if this open request came in the context of a user gesture. + bool user_gesture; + + // Type of window requested. + WindowContainerType window_container_type; + + // The session storage namespace ID this view should use. + int64 session_storage_namespace_id; + + // The name of the resulting frame that should be created (empty if none + // has been specified). + string16 frame_name; +}; + +struct ViewHostMsg_RunFileChooser_Params { + enum Mode { + // Requires that the file exists before allowing the user to pick it. + Open, + + // Like Open, but allows picking multiple files to open. + OpenMultiple, + + // Allows picking a nonexistent file, and prompts to overwrite if the file + // already exists. + Save, + }; + + Mode mode; + + // Title to be used for the dialog. This may be empty for the default title, + // which will be either "Open" or "Save" depending on the mode. + string16 title; + + // Default file name to select in the dialog. + FilePath default_file_name; +}; + +struct ViewMsg_ExtensionExtentInfo { + std::string extension_id; + ExtensionExtent web_extent; + ExtensionExtent browse_extent; +}; + +struct ViewMsg_ExtensionExtentsUpdated_Params { + // Describes the installed extension apps and the URLs they cover. + std::vector<ViewMsg_ExtensionExtentInfo> extension_apps; +}; + +// Values that may be OR'd together to form the 'flags' parameter of the +// ViewMsg_EnablePreferredSizeChangedMode message. +enum ViewHostMsg_EnablePreferredSizeChangedMode_Flags { + kPreferredSizeNothing, + kPreferredSizeWidth = 1 << 0, + // Requesting the height currently requires a polling loop in render_view.cc. + kPreferredSizeHeightThisIsSlow = 1 << 1, +}; + +namespace IPC { + +template <> +struct ParamTraits<ResourceType::Type> { + typedef ResourceType::Type param_type; + static void Write(Message* m, const param_type& p) { + m->WriteInt(p); + } + static bool Read(const Message* m, void** iter, param_type* p) { + int type; + if (!m->ReadInt(iter, &type) || !ResourceType::ValidType(type)) + return false; + *p = ResourceType::FromInt(type); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + std::wstring type; + switch (p) { + case ResourceType::MAIN_FRAME: + type = L"MAIN_FRAME"; + break; + case ResourceType::SUB_FRAME: + type = L"SUB_FRAME"; + break; + case ResourceType::SUB_RESOURCE: + type = L"SUB_RESOURCE"; + break; + case ResourceType::OBJECT: + type = L"OBJECT"; + break; + case ResourceType::MEDIA: + type = L"MEDIA"; + break; + default: + type = L"UNKNOWN"; + break; + } + + LogParam(type, l); + } +}; + +// Traits for ViewMsg_Navigate_Params structure to pack/unpack. +template <> +struct ParamTraits<ViewMsg_Navigate_Params> { + typedef ViewMsg_Navigate_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.page_id); + WriteParam(m, p.pending_history_list_offset); + WriteParam(m, p.current_history_list_offset); + WriteParam(m, p.current_history_list_length); + WriteParam(m, p.url); + WriteParam(m, p.referrer); + WriteParam(m, p.transition); + WriteParam(m, p.state); + WriteParam(m, p.navigation_type); + WriteParam(m, p.request_time); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->page_id) && + ReadParam(m, iter, &p->pending_history_list_offset) && + ReadParam(m, iter, &p->current_history_list_offset) && + ReadParam(m, iter, &p->current_history_list_length) && + ReadParam(m, iter, &p->url) && + ReadParam(m, iter, &p->referrer) && + ReadParam(m, iter, &p->transition) && + ReadParam(m, iter, &p->state) && + ReadParam(m, iter, &p->navigation_type) && + ReadParam(m, iter, &p->request_time); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.page_id, l); + l->append(L", "); + LogParam(p.url, l); + l->append(L", "); + LogParam(p.transition, l); + l->append(L", "); + LogParam(p.state, l); + l->append(L", "); + LogParam(p.navigation_type, l); + l->append(L", "); + LogParam(p.request_time, l); + l->append(L")"); + } +}; + +template<> +struct ParamTraits<ViewMsg_Navigate_Params::NavigationType> { + typedef ViewMsg_Navigate_Params::NavigationType param_type; + static void Write(Message* m, const param_type& p) { + m->WriteInt(p); + } + static bool Read(const Message* m, void** iter, param_type* p) { + int type; + if (!m->ReadInt(iter, &type)) + return false; + *p = static_cast<ViewMsg_Navigate_Params::NavigationType>(type); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + std::wstring event; + switch (p) { + case ViewMsg_Navigate_Params::RELOAD: + event = L"NavigationType_RELOAD"; + break; + + case ViewMsg_Navigate_Params::RELOAD_IGNORING_CACHE: + event = L"NavigationType_RELOAD_IGNORING_CACHE"; + break; + + case ViewMsg_Navigate_Params::RESTORE: + event = L"NavigationType_RESTORE"; + break; + + case ViewMsg_Navigate_Params::NORMAL: + event = L"NavigationType_NORMAL"; + break; + + default: + event = L"NavigationType_UNKNOWN"; + break; + } + LogParam(event, l); + } +}; + +// Traits for FormField_Params structure to pack/unpack. +template <> +struct ParamTraits<webkit_glue::FormField> { + typedef webkit_glue::FormField param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.label()); + WriteParam(m, p.name()); + WriteParam(m, p.value()); + WriteParam(m, p.form_control_type()); + WriteParam(m, p.size()); + WriteParam(m, p.option_strings()); + } + static bool Read(const Message* m, void** iter, param_type* p) { + string16 label, name, value, form_control_type; + int size = 0; + std::vector<string16> options; + bool result = ReadParam(m, iter, &label); + result = result && ReadParam(m, iter, &name); + result = result && ReadParam(m, iter, &value); + result = result && ReadParam(m, iter, &form_control_type); + result = result && ReadParam(m, iter, &size); + result = result && ReadParam(m, iter, &options); + if (!result) + return false; + + p->set_label(label); + p->set_name(name); + p->set_value(value); + p->set_form_control_type(form_control_type); + p->set_size(size); + p->set_option_strings(options); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<FormField>"); + } +}; + +// Traits for FontDescriptor structure to pack/unpack. +template <> +struct ParamTraits<FontDescriptor> { + typedef FontDescriptor param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.font_name); + WriteParam(m, p.font_point_size); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return( + ReadParam(m, iter, &p->font_name) && + ReadParam(m, iter, &p->font_point_size)); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<FontDescriptor>"); + } +}; + +// Traits for ViewHostMsg_GetSearchProviderInstallState_Params structure to +// pack/unpack. +template <> +struct ParamTraits<ViewHostMsg_GetSearchProviderInstallState_Params> { + typedef ViewHostMsg_GetSearchProviderInstallState_Params param_type; + static void Write(Message* m, const param_type& p) { + m->WriteInt(p.state); + } + static bool Read(const Message* m, void** iter, param_type* p) { + int type; + if (!m->ReadInt(iter, &type)) + return false; + p->state = static_cast<param_type::State>(type); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + std::wstring state; + switch (p.state) { + case ViewHostMsg_GetSearchProviderInstallState_Params::DENIED: + state = L"ViewHostMsg_GetSearchProviderInstallState_Params::DENIED"; + break; + case ViewHostMsg_GetSearchProviderInstallState_Params::NOT_INSTALLED: + state = + L"ViewHostMsg_GetSearchProviderInstallState_Params::NOT_INSTALLED"; + break; + case ViewHostMsg_GetSearchProviderInstallState_Params:: + INSTALLED_BUT_NOT_DEFAULT: + state = L"ViewHostMsg_GetSearchProviderInstallState_Params::" + L"INSTALLED_BUT_NOT_DEFAULT"; + break; + case ViewHostMsg_GetSearchProviderInstallState_Params:: + INSTALLED_AS_DEFAULT: + state = L"ViewHostMsg_GetSearchProviderInstallState_Params::" + L"INSTALLED_AS_DEFAULT"; + break; + default: + state = L"UNKNOWN"; + break; + } + LogParam(state, l); + } +}; + +// Traits for ViewHostMsg_FrameNavigate_Params structure to pack/unpack. +template <> +struct ParamTraits<ViewHostMsg_FrameNavigate_Params> { + typedef ViewHostMsg_FrameNavigate_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.page_id); + WriteParam(m, p.url); + WriteParam(m, p.referrer); + WriteParam(m, p.transition); + WriteParam(m, p.redirects); + WriteParam(m, p.should_update_history); + WriteParam(m, p.searchable_form_url); + WriteParam(m, p.searchable_form_encoding); + WriteParam(m, p.password_form); + WriteParam(m, p.security_info); + WriteParam(m, p.gesture); + WriteParam(m, p.contents_mime_type); + WriteParam(m, p.is_post); + WriteParam(m, p.is_content_filtered); + WriteParam(m, p.http_status_code); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->page_id) && + ReadParam(m, iter, &p->url) && + ReadParam(m, iter, &p->referrer) && + ReadParam(m, iter, &p->transition) && + ReadParam(m, iter, &p->redirects) && + ReadParam(m, iter, &p->should_update_history) && + ReadParam(m, iter, &p->searchable_form_url) && + ReadParam(m, iter, &p->searchable_form_encoding) && + ReadParam(m, iter, &p->password_form) && + ReadParam(m, iter, &p->security_info) && + ReadParam(m, iter, &p->gesture) && + ReadParam(m, iter, &p->contents_mime_type) && + ReadParam(m, iter, &p->is_post) && + ReadParam(m, iter, &p->is_content_filtered) && + ReadParam(m, iter, &p->http_status_code); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.page_id, l); + l->append(L", "); + LogParam(p.url, l); + l->append(L", "); + LogParam(p.referrer, l); + l->append(L", "); + LogParam(p.transition, l); + l->append(L", "); + LogParam(p.redirects, l); + l->append(L", "); + LogParam(p.should_update_history, l); + l->append(L", "); + LogParam(p.searchable_form_url, l); + l->append(L", "); + LogParam(p.searchable_form_encoding, l); + l->append(L", "); + LogParam(p.password_form, l); + l->append(L", "); + LogParam(p.security_info, l); + l->append(L", "); + LogParam(p.gesture, l); + l->append(L", "); + LogParam(p.contents_mime_type, l); + l->append(L", "); + LogParam(p.is_post, l); + l->append(L", "); + LogParam(p.is_content_filtered, l); + l->append(L", "); + LogParam(p.http_status_code, l); + l->append(L")"); + } +}; + +template <> +struct ParamTraits<ContextMenuParams> { + typedef ContextMenuParams param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.media_type); + WriteParam(m, p.x); + WriteParam(m, p.y); + WriteParam(m, p.link_url); + WriteParam(m, p.unfiltered_link_url); + WriteParam(m, p.src_url); + WriteParam(m, p.is_image_blocked); + WriteParam(m, p.page_url); + WriteParam(m, p.frame_url); + WriteParam(m, p.media_flags); + WriteParam(m, p.selection_text); + WriteParam(m, p.misspelled_word); + WriteParam(m, p.dictionary_suggestions); + WriteParam(m, p.spellcheck_enabled); + WriteParam(m, p.is_editable); +#if defined(OS_MACOSX) + WriteParam(m, p.writing_direction_default); + WriteParam(m, p.writing_direction_left_to_right); + WriteParam(m, p.writing_direction_right_to_left); +#endif // OS_MACOSX + WriteParam(m, p.edit_flags); + WriteParam(m, p.security_info); + WriteParam(m, p.frame_charset); + WriteParam(m, p.custom_items); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->media_type) && + ReadParam(m, iter, &p->x) && + ReadParam(m, iter, &p->y) && + ReadParam(m, iter, &p->link_url) && + ReadParam(m, iter, &p->unfiltered_link_url) && + ReadParam(m, iter, &p->src_url) && + ReadParam(m, iter, &p->is_image_blocked) && + ReadParam(m, iter, &p->page_url) && + ReadParam(m, iter, &p->frame_url) && + ReadParam(m, iter, &p->media_flags) && + ReadParam(m, iter, &p->selection_text) && + ReadParam(m, iter, &p->misspelled_word) && + ReadParam(m, iter, &p->dictionary_suggestions) && + ReadParam(m, iter, &p->spellcheck_enabled) && + ReadParam(m, iter, &p->is_editable) && +#if defined(OS_MACOSX) + ReadParam(m, iter, &p->writing_direction_default) && + ReadParam(m, iter, &p->writing_direction_left_to_right) && + ReadParam(m, iter, &p->writing_direction_right_to_left) && +#endif // OS_MACOSX + ReadParam(m, iter, &p->edit_flags) && + ReadParam(m, iter, &p->security_info) && + ReadParam(m, iter, &p->frame_charset) && + ReadParam(m, iter, &p->custom_items); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<ContextMenuParams>"); + } +}; + +// Traits for ViewHostMsg_UpdateRect_Params structure to pack/unpack. +template <> +struct ParamTraits<ViewHostMsg_UpdateRect_Params> { + typedef ViewHostMsg_UpdateRect_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.bitmap); + WriteParam(m, p.bitmap_rect); + WriteParam(m, p.dx); + WriteParam(m, p.dy); + WriteParam(m, p.scroll_rect); + WriteParam(m, p.copy_rects); + WriteParam(m, p.view_size); + WriteParam(m, p.plugin_window_moves); + WriteParam(m, p.flags); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->bitmap) && + ReadParam(m, iter, &p->bitmap_rect) && + ReadParam(m, iter, &p->dx) && + ReadParam(m, iter, &p->dy) && + ReadParam(m, iter, &p->scroll_rect) && + ReadParam(m, iter, &p->copy_rects) && + ReadParam(m, iter, &p->view_size) && + ReadParam(m, iter, &p->plugin_window_moves) && + ReadParam(m, iter, &p->flags); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.bitmap, l); + l->append(L", "); + LogParam(p.bitmap_rect, l); + l->append(L", "); + LogParam(p.dx, l); + l->append(L", "); + LogParam(p.dy, l); + l->append(L", "); + LogParam(p.scroll_rect, l); + l->append(L", "); + LogParam(p.copy_rects, l); + l->append(L", "); + LogParam(p.view_size, l); + l->append(L", "); + LogParam(p.plugin_window_moves, l); + l->append(L", "); + LogParam(p.flags, l); + l->append(L")"); + } +}; + +template <> +struct ParamTraits<webkit_glue::WebPluginGeometry> { + typedef webkit_glue::WebPluginGeometry param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.window); + WriteParam(m, p.window_rect); + WriteParam(m, p.clip_rect); + WriteParam(m, p.cutout_rects); + WriteParam(m, p.rects_valid); + WriteParam(m, p.visible); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->window) && + ReadParam(m, iter, &p->window_rect) && + ReadParam(m, iter, &p->clip_rect) && + ReadParam(m, iter, &p->cutout_rects) && + ReadParam(m, iter, &p->rects_valid) && + ReadParam(m, iter, &p->visible); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.window, l); + l->append(L", "); + LogParam(p.window_rect, l); + l->append(L", "); + LogParam(p.clip_rect, l); + l->append(L", "); + LogParam(p.cutout_rects, l); + l->append(L", "); + LogParam(p.rects_valid, l); + l->append(L", "); + LogParam(p.visible, l); + l->append(L")"); + } +}; + +// Traits for ViewMsg_GetPlugins_Reply structure to pack/unpack. +template <> +struct ParamTraits<WebPluginMimeType> { + typedef WebPluginMimeType param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.mime_type); + WriteParam(m, p.file_extensions); + WriteParam(m, p.description); + } + static bool Read(const Message* m, void** iter, param_type* r) { + return + ReadParam(m, iter, &r->mime_type) && + ReadParam(m, iter, &r->file_extensions) && + ReadParam(m, iter, &r->description); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.mime_type, l); + l->append(L", "); + LogParam(p.file_extensions, l); + l->append(L", "); + LogParam(p.description, l); + l->append(L")"); + } +}; + + +template <> +struct ParamTraits<WebPluginInfo> { + typedef WebPluginInfo param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.name); + WriteParam(m, p.path); + WriteParam(m, p.version); + WriteParam(m, p.desc); + WriteParam(m, p.mime_types); + } + static bool Read(const Message* m, void** iter, param_type* r) { + return + ReadParam(m, iter, &r->name) && + ReadParam(m, iter, &r->path) && + ReadParam(m, iter, &r->version) && + ReadParam(m, iter, &r->desc) && + ReadParam(m, iter, &r->mime_types); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.name, l); + l->append(L", "); + l->append(L", "); + LogParam(p.path, l); + l->append(L", "); + LogParam(p.version, l); + l->append(L", "); + LogParam(p.desc, l); + l->append(L", "); + LogParam(p.mime_types, l); + l->append(L")"); + } +}; + +// Traits for webkit_glue::PasswordFormDomManager::FillData. +template <> +struct ParamTraits<webkit_glue::PasswordFormFillData> { + typedef webkit_glue::PasswordFormFillData param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.basic_data); + WriteParam(m, p.additional_logins); + WriteParam(m, p.wait_for_username); + } + static bool Read(const Message* m, void** iter, param_type* r) { + return + ReadParam(m, iter, &r->basic_data) && + ReadParam(m, iter, &r->additional_logins) && + ReadParam(m, iter, &r->wait_for_username); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<PasswordFormFillData>"); + } +}; + +template<> +struct ParamTraits<NavigationGesture> { + typedef NavigationGesture param_type; + static void Write(Message* m, const param_type& p) { + m->WriteInt(p); + } + static bool Read(const Message* m, void** iter, param_type* p) { + int type; + if (!m->ReadInt(iter, &type)) + return false; + *p = static_cast<NavigationGesture>(type); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + std::wstring event; + switch (p) { + case NavigationGestureUser: + event = L"GESTURE_USER"; + break; + case NavigationGestureAuto: + event = L"GESTURE_AUTO"; + break; + default: + event = L"GESTURE_UNKNOWN"; + break; + } + LogParam(event, l); + } +}; + +// Traits for ViewMsg_Close_Params. +template <> +struct ParamTraits<ViewMsg_ClosePage_Params> { + typedef ViewMsg_ClosePage_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.closing_process_id); + WriteParam(m, p.closing_route_id); + WriteParam(m, p.for_cross_site_transition); + WriteParam(m, p.new_render_process_host_id); + WriteParam(m, p.new_request_id); + } + + static bool Read(const Message* m, void** iter, param_type* r) { + return ReadParam(m, iter, &r->closing_process_id) && + ReadParam(m, iter, &r->closing_route_id) && + ReadParam(m, iter, &r->for_cross_site_transition) && + ReadParam(m, iter, &r->new_render_process_host_id) && + ReadParam(m, iter, &r->new_request_id); + } + + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.closing_process_id, l); + l->append(L", "); + LogParam(p.closing_route_id, l); + l->append(L", "); + LogParam(p.for_cross_site_transition, l); + l->append(L", "); + LogParam(p.new_render_process_host_id, l); + l->append(L", "); + LogParam(p.new_request_id, l); + l->append(L")"); + } +}; + +// Traits for ViewHostMsg_Resource_Request +template <> +struct ParamTraits<ViewHostMsg_Resource_Request> { + typedef ViewHostMsg_Resource_Request param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.method); + WriteParam(m, p.url); + WriteParam(m, p.first_party_for_cookies); + WriteParam(m, p.referrer); + WriteParam(m, p.frame_origin); + WriteParam(m, p.main_frame_origin); + WriteParam(m, p.headers); + WriteParam(m, p.load_flags); + WriteParam(m, p.origin_child_id); + WriteParam(m, p.resource_type); + WriteParam(m, p.request_context); + WriteParam(m, p.appcache_host_id); + WriteParam(m, p.upload_data); + WriteParam(m, p.host_renderer_id); + WriteParam(m, p.host_render_view_id); + } + static bool Read(const Message* m, void** iter, param_type* r) { + return + ReadParam(m, iter, &r->method) && + ReadParam(m, iter, &r->url) && + ReadParam(m, iter, &r->first_party_for_cookies) && + ReadParam(m, iter, &r->referrer) && + ReadParam(m, iter, &r->frame_origin) && + ReadParam(m, iter, &r->main_frame_origin) && + ReadParam(m, iter, &r->headers) && + ReadParam(m, iter, &r->load_flags) && + ReadParam(m, iter, &r->origin_child_id) && + ReadParam(m, iter, &r->resource_type) && + ReadParam(m, iter, &r->request_context) && + ReadParam(m, iter, &r->appcache_host_id) && + ReadParam(m, iter, &r->upload_data) && + ReadParam(m, iter, &r->host_renderer_id) && + ReadParam(m, iter, &r->host_render_view_id); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.method, l); + l->append(L", "); + LogParam(p.url, l); + l->append(L", "); + LogParam(p.referrer, l); + l->append(L", "); + LogParam(p.frame_origin, l); + l->append(L", "); + LogParam(p.main_frame_origin, l); + l->append(L", "); + LogParam(p.load_flags, l); + l->append(L", "); + LogParam(p.origin_child_id, l); + l->append(L", "); + LogParam(p.resource_type, l); + l->append(L", "); + LogParam(p.request_context, l); + l->append(L", "); + LogParam(p.appcache_host_id, l); + l->append(L", "); + LogParam(p.host_renderer_id, l); + l->append(L", "); + LogParam(p.host_render_view_id, l); + l->append(L")"); + } +}; + +template <> +struct ParamTraits<scoped_refptr<net::HttpResponseHeaders> > { + typedef scoped_refptr<net::HttpResponseHeaders> param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.get() != NULL); + if (p) { + // Do not disclose Set-Cookie headers over IPC. + p->Persist(m, net::HttpResponseHeaders::PERSIST_SANS_COOKIES); + } + } + static bool Read(const Message* m, void** iter, param_type* r) { + bool has_object; + if (!ReadParam(m, iter, &has_object)) + return false; + if (has_object) + *r = new net::HttpResponseHeaders(*m, iter); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<HttpResponseHeaders>"); + } +}; + +// Traits for webkit_glue::ResourceLoaderBridge::LoadTimingInfo +template <> +struct ParamTraits<webkit_glue::ResourceLoaderBridge::LoadTimingInfo> { + typedef webkit_glue::ResourceLoaderBridge::LoadTimingInfo param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.base_time.is_null()); + if (p.base_time.is_null()) + return; + WriteParam(m, p.base_time); + WriteParam(m, p.proxy_start); + WriteParam(m, p.proxy_end); + WriteParam(m, p.dns_start); + WriteParam(m, p.dns_end); + WriteParam(m, p.connect_start); + WriteParam(m, p.connect_end); + WriteParam(m, p.ssl_start); + WriteParam(m, p.ssl_end); + WriteParam(m, p.send_start); + WriteParam(m, p.send_end); + WriteParam(m, p.receive_headers_start); + WriteParam(m, p.receive_headers_end); + } + static bool Read(const Message* m, void** iter, param_type* r) { + bool is_null; + if (!ReadParam(m, iter, &is_null)) + return false; + if (is_null) + return true; + + return + ReadParam(m, iter, &r->base_time) && + ReadParam(m, iter, &r->proxy_start) && + ReadParam(m, iter, &r->proxy_end) && + ReadParam(m, iter, &r->dns_start) && + ReadParam(m, iter, &r->dns_end) && + ReadParam(m, iter, &r->connect_start) && + ReadParam(m, iter, &r->connect_end) && + ReadParam(m, iter, &r->ssl_start) && + ReadParam(m, iter, &r->ssl_end) && + ReadParam(m, iter, &r->send_start) && + ReadParam(m, iter, &r->send_end) && + ReadParam(m, iter, &r->receive_headers_start) && + ReadParam(m, iter, &r->receive_headers_end); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.base_time, l); + l->append(L", "); + LogParam(p.proxy_start, l); + l->append(L", "); + LogParam(p.proxy_end, l); + l->append(L", "); + LogParam(p.dns_start, l); + l->append(L", "); + LogParam(p.dns_end, l); + l->append(L", "); + LogParam(p.connect_start, l); + l->append(L", "); + LogParam(p.connect_end, l); + l->append(L", "); + LogParam(p.ssl_start, l); + l->append(L", "); + LogParam(p.ssl_end, l); + l->append(L", "); + LogParam(p.send_start, l); + l->append(L", "); + LogParam(p.send_end, l); + l->append(L", "); + LogParam(p.receive_headers_start, l); + l->append(L", "); + LogParam(p.receive_headers_end, l); + l->append(L")"); + } +}; + +// Traits for webkit_glue::ResourceLoaderBridge::ResponseInfo +template <> +struct ParamTraits<webkit_glue::ResourceLoaderBridge::ResponseInfo> { + typedef webkit_glue::ResourceLoaderBridge::ResponseInfo param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.request_time); + WriteParam(m, p.response_time); + WriteParam(m, p.headers); + WriteParam(m, p.mime_type); + WriteParam(m, p.charset); + WriteParam(m, p.security_info); + WriteParam(m, p.content_length); + WriteParam(m, p.appcache_id); + WriteParam(m, p.appcache_manifest_url); + WriteParam(m, p.connection_id); + WriteParam(m, p.connection_reused); + WriteParam(m, p.load_timing); + WriteParam(m, p.was_fetched_via_spdy); + WriteParam(m, p.was_npn_negotiated); + WriteParam(m, p.was_alternate_protocol_available); + WriteParam(m, p.was_fetched_via_proxy); + } + static bool Read(const Message* m, void** iter, param_type* r) { + return + ReadParam(m, iter, &r->request_time) && + ReadParam(m, iter, &r->response_time) && + ReadParam(m, iter, &r->headers) && + ReadParam(m, iter, &r->mime_type) && + ReadParam(m, iter, &r->charset) && + ReadParam(m, iter, &r->security_info) && + ReadParam(m, iter, &r->content_length) && + ReadParam(m, iter, &r->appcache_id) && + ReadParam(m, iter, &r->appcache_manifest_url) && + ReadParam(m, iter, &r->connection_id) && + ReadParam(m, iter, &r->connection_reused) && + ReadParam(m, iter, &r->load_timing) && + ReadParam(m, iter, &r->was_fetched_via_spdy) && + ReadParam(m, iter, &r->was_npn_negotiated) && + ReadParam(m, iter, &r->was_alternate_protocol_available) && + ReadParam(m, iter, &r->was_fetched_via_proxy); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.request_time, l); + l->append(L", "); + LogParam(p.response_time, l); + l->append(L", "); + LogParam(p.headers, l); + l->append(L", "); + LogParam(p.mime_type, l); + l->append(L", "); + LogParam(p.charset, l); + l->append(L", "); + LogParam(p.security_info, l); + l->append(L", "); + LogParam(p.content_length, l); + l->append(L", "); + LogParam(p.appcache_id, l); + l->append(L", "); + LogParam(p.appcache_manifest_url, l); + l->append(L", "); + LogParam(p.connection_id, l); + l->append(L", "); + LogParam(p.connection_reused, l); + l->append(L", "); + LogParam(p.load_timing, l); + l->append(L", "); + LogParam(p.was_fetched_via_spdy, l); + l->append(L", "); + LogParam(p.was_npn_negotiated, l); + l->append(L", "); + LogParam(p.was_alternate_protocol_available, l); + l->append(L", "); + LogParam(p.was_fetched_via_proxy, l); + l->append(L")"); + } +}; + +template <> +struct ParamTraits<ResourceResponseHead> { + typedef ResourceResponseHead param_type; + static void Write(Message* m, const param_type& p) { + ParamTraits<webkit_glue::ResourceLoaderBridge::ResponseInfo>::Write(m, p); + WriteParam(m, p.status); + WriteParam(m, p.replace_extension_localization_templates); + } + static bool Read(const Message* m, void** iter, param_type* r) { + return ParamTraits<webkit_glue::ResourceLoaderBridge::ResponseInfo>::Read( + m, iter, r) && + ReadParam(m, iter, &r->status) && + ReadParam(m, iter, &r->replace_extension_localization_templates); + } + static void Log(const param_type& p, std::wstring* l) { + // log more? + ParamTraits<webkit_glue::ResourceLoaderBridge::ResponseInfo>::Log(p, l); + } +}; + +template <> +struct ParamTraits<SyncLoadResult> { + typedef SyncLoadResult param_type; + static void Write(Message* m, const param_type& p) { + ParamTraits<ResourceResponseHead>::Write(m, p); + WriteParam(m, p.final_url); + WriteParam(m, p.data); + } + static bool Read(const Message* m, void** iter, param_type* r) { + return + ParamTraits<ResourceResponseHead>::Read(m, iter, r) && + ReadParam(m, iter, &r->final_url) && + ReadParam(m, iter, &r->data); + } + static void Log(const param_type& p, std::wstring* l) { + // log more? + ParamTraits<webkit_glue::ResourceLoaderBridge::ResponseInfo>::Log(p, l); + } +}; + +template <> +struct ParamTraits<SerializedScriptValue> { + typedef SerializedScriptValue param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.is_null()); + WriteParam(m, p.is_invalid()); + WriteParam(m, p.data()); + } + static bool Read(const Message* m, void** iter, param_type* r) { + bool is_null; + bool is_invalid; + string16 data; + bool ok = + ReadParam(m, iter, &is_null) && + ReadParam(m, iter, &is_invalid) && + ReadParam(m, iter, &data); + if (!ok) + return false; + r->set_is_null(is_null); + r->set_is_invalid(is_invalid); + r->set_data(data); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<SerializedScriptValue>("); + LogParam(p.is_null(), l); + l->append(L", "); + LogParam(p.is_invalid(), l); + l->append(L", "); + LogParam(p.data(), l); + l->append(L")"); + } +}; + +template <> +struct ParamTraits<IndexedDBKey> { + typedef IndexedDBKey param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, int(p.type())); + // TODO(jorlow): Technically, we only need to pack the type being used. + WriteParam(m, p.string()); + WriteParam(m, p.number()); + } + static bool Read(const Message* m, void** iter, param_type* r) { + int type; + string16 string; + int32 number; + bool ok = + ReadParam(m, iter, &type) && + ReadParam(m, iter, &string) && + ReadParam(m, iter, &number); + if (!ok) + return false; + switch (type) { + case WebKit::WebIDBKey::NullType: + r->SetNull(); + return true; + case WebKit::WebIDBKey::StringType: + r->Set(string); + return true; + case WebKit::WebIDBKey::NumberType: + r->Set(number); + return true; + case WebKit::WebIDBKey::InvalidType: + r->SetInvalid(); + return true; + } + NOTREACHED(); + return false; + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<IndexedDBKey>("); + LogParam(int(p.type()), l); + l->append(L", "); + LogParam(p.string(), l); + l->append(L", "); + LogParam(p.number(), l); + l->append(L")"); + } +}; + +// Traits for FormData structure to pack/unpack. +template <> +struct ParamTraits<webkit_glue::FormData> { + typedef webkit_glue::FormData param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.name); + WriteParam(m, p.method); + WriteParam(m, p.origin); + WriteParam(m, p.action); + WriteParam(m, p.fields); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->name) && + ReadParam(m, iter, &p->method) && + ReadParam(m, iter, &p->origin) && + ReadParam(m, iter, &p->action) && + ReadParam(m, iter, &p->fields); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<FormData>"); + } +}; + +// Traits for ViewMsg_Print_Params +template <> +struct ParamTraits<ViewMsg_Print_Params> { + typedef ViewMsg_Print_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.page_size); + WriteParam(m, p.printable_size); + WriteParam(m, p.margin_top); + WriteParam(m, p.margin_left); + WriteParam(m, p.dpi); + WriteParam(m, p.min_shrink); + WriteParam(m, p.max_shrink); + WriteParam(m, p.desired_dpi); + WriteParam(m, p.document_cookie); + WriteParam(m, p.selection_only); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return ReadParam(m, iter, &p->page_size) && + ReadParam(m, iter, &p->printable_size) && + ReadParam(m, iter, &p->margin_top) && + ReadParam(m, iter, &p->margin_left) && + ReadParam(m, iter, &p->dpi) && + ReadParam(m, iter, &p->min_shrink) && + ReadParam(m, iter, &p->max_shrink) && + ReadParam(m, iter, &p->desired_dpi) && + ReadParam(m, iter, &p->document_cookie) && + ReadParam(m, iter, &p->selection_only); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<ViewMsg_Print_Params>"); + } +}; + +// Traits for ViewMsg_PrintPage_Params +template <> +struct ParamTraits<ViewMsg_PrintPage_Params> { + typedef ViewMsg_PrintPage_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.params); + WriteParam(m, p.page_number); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return ReadParam(m, iter, &p->params) && + ReadParam(m, iter, &p->page_number); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<ViewMsg_PrintPage_Params>"); + } +}; + +// Traits for ViewMsg_PrintPages_Params +template <> +struct ParamTraits<ViewMsg_PrintPages_Params> { + typedef ViewMsg_PrintPages_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.params); + WriteParam(m, p.pages); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return ReadParam(m, iter, &p->params) && + ReadParam(m, iter, &p->pages); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<ViewMsg_PrintPages_Params>"); + } +}; + +// Traits for ViewHostMsg_DidPrintPage_Params +template <> +struct ParamTraits<ViewHostMsg_DidPrintPage_Params> { + typedef ViewHostMsg_DidPrintPage_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.metafile_data_handle); + WriteParam(m, p.data_size); + WriteParam(m, p.document_cookie); + WriteParam(m, p.page_number); + WriteParam(m, p.actual_shrink); + WriteParam(m, p.page_size); + WriteParam(m, p.content_area); + WriteParam(m, p.has_visible_overlays); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return ReadParam(m, iter, &p->metafile_data_handle) && + ReadParam(m, iter, &p->data_size) && + ReadParam(m, iter, &p->document_cookie) && + ReadParam(m, iter, &p->page_number) && + ReadParam(m, iter, &p->actual_shrink) && + ReadParam(m, iter, &p->page_size) && + ReadParam(m, iter, &p->content_area) && + ReadParam(m, iter, &p->has_visible_overlays); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<ViewHostMsg_DidPrintPage_Params>"); + } +}; + +// Traits for reading/writing CSS Colors +template <> +struct ParamTraits<CSSColors::CSSColorName> { + typedef CSSColors::CSSColorName param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, static_cast<int>(p)); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return ReadParam(m, iter, reinterpret_cast<int*>(p)); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<CSSColorName>"); + } +}; + + +// Traits for RendererPreferences structure to pack/unpack. +template <> +struct ParamTraits<RendererPreferences> { + typedef RendererPreferences param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.can_accept_load_drops); + WriteParam(m, p.should_antialias_text); + WriteParam(m, static_cast<int>(p.hinting)); + WriteParam(m, static_cast<int>(p.subpixel_rendering)); + WriteParam(m, p.focus_ring_color); + WriteParam(m, p.thumb_active_color); + WriteParam(m, p.thumb_inactive_color); + WriteParam(m, p.track_color); + WriteParam(m, p.active_selection_bg_color); + WriteParam(m, p.active_selection_fg_color); + WriteParam(m, p.inactive_selection_bg_color); + WriteParam(m, p.inactive_selection_fg_color); + WriteParam(m, p.browser_handles_top_level_requests); + WriteParam(m, p.caret_blink_interval); + } + static bool Read(const Message* m, void** iter, param_type* p) { + if (!ReadParam(m, iter, &p->can_accept_load_drops)) + return false; + if (!ReadParam(m, iter, &p->should_antialias_text)) + return false; + + int hinting = 0; + if (!ReadParam(m, iter, &hinting)) + return false; + p->hinting = static_cast<RendererPreferencesHintingEnum>(hinting); + + int subpixel_rendering = 0; + if (!ReadParam(m, iter, &subpixel_rendering)) + return false; + p->subpixel_rendering = + static_cast<RendererPreferencesSubpixelRenderingEnum>( + subpixel_rendering); + + int focus_ring_color; + if (!ReadParam(m, iter, &focus_ring_color)) + return false; + p->focus_ring_color = focus_ring_color; + + int thumb_active_color, thumb_inactive_color, track_color; + int active_selection_bg_color, active_selection_fg_color; + int inactive_selection_bg_color, inactive_selection_fg_color; + if (!ReadParam(m, iter, &thumb_active_color) || + !ReadParam(m, iter, &thumb_inactive_color) || + !ReadParam(m, iter, &track_color) || + !ReadParam(m, iter, &active_selection_bg_color) || + !ReadParam(m, iter, &active_selection_fg_color) || + !ReadParam(m, iter, &inactive_selection_bg_color) || + !ReadParam(m, iter, &inactive_selection_fg_color)) + return false; + p->thumb_active_color = thumb_active_color; + p->thumb_inactive_color = thumb_inactive_color; + p->track_color = track_color; + p->active_selection_bg_color = active_selection_bg_color; + p->active_selection_fg_color = active_selection_fg_color; + p->inactive_selection_bg_color = inactive_selection_bg_color; + p->inactive_selection_fg_color = inactive_selection_fg_color; + + if (!ReadParam(m, iter, &p->browser_handles_top_level_requests)) + return false; + + if (!ReadParam(m, iter, &p->caret_blink_interval)) + return false; + + return true; + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<RendererPreferences>"); + } +}; + +// Traits for WebPreferences structure to pack/unpack. +template <> +struct ParamTraits<WebPreferences> { + typedef WebPreferences param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.standard_font_family); + WriteParam(m, p.fixed_font_family); + WriteParam(m, p.serif_font_family); + WriteParam(m, p.sans_serif_font_family); + WriteParam(m, p.cursive_font_family); + WriteParam(m, p.fantasy_font_family); + WriteParam(m, p.default_font_size); + WriteParam(m, p.default_fixed_font_size); + WriteParam(m, p.minimum_font_size); + WriteParam(m, p.minimum_logical_font_size); + WriteParam(m, p.default_encoding); + WriteParam(m, p.javascript_enabled); + WriteParam(m, p.web_security_enabled); + WriteParam(m, p.javascript_can_open_windows_automatically); + WriteParam(m, p.loads_images_automatically); + WriteParam(m, p.plugins_enabled); + WriteParam(m, p.dom_paste_enabled); + WriteParam(m, p.developer_extras_enabled); + WriteParam(m, p.inspector_settings); + WriteParam(m, p.site_specific_quirks_enabled); + WriteParam(m, p.shrinks_standalone_images_to_fit); + WriteParam(m, p.uses_universal_detector); + WriteParam(m, p.text_areas_are_resizable); + WriteParam(m, p.java_enabled); + WriteParam(m, p.allow_scripts_to_close_windows); + WriteParam(m, p.uses_page_cache); + WriteParam(m, p.remote_fonts_enabled); + WriteParam(m, p.javascript_can_access_clipboard); + WriteParam(m, p.xss_auditor_enabled); + WriteParam(m, p.local_storage_enabled); + WriteParam(m, p.databases_enabled); + WriteParam(m, p.application_cache_enabled); + WriteParam(m, p.tabs_to_links); + WriteParam(m, p.user_style_sheet_enabled); + WriteParam(m, p.user_style_sheet_location); + WriteParam(m, p.author_and_user_styles_enabled); + WriteParam(m, p.allow_universal_access_from_file_urls); + WriteParam(m, p.allow_file_access_from_file_urls); + WriteParam(m, p.experimental_webgl_enabled); + WriteParam(m, p.show_composited_layer_borders); + WriteParam(m, p.accelerated_compositing_enabled); + WriteParam(m, p.memory_info_enabled); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->standard_font_family) && + ReadParam(m, iter, &p->fixed_font_family) && + ReadParam(m, iter, &p->serif_font_family) && + ReadParam(m, iter, &p->sans_serif_font_family) && + ReadParam(m, iter, &p->cursive_font_family) && + ReadParam(m, iter, &p->fantasy_font_family) && + ReadParam(m, iter, &p->default_font_size) && + ReadParam(m, iter, &p->default_fixed_font_size) && + ReadParam(m, iter, &p->minimum_font_size) && + ReadParam(m, iter, &p->minimum_logical_font_size) && + ReadParam(m, iter, &p->default_encoding) && + ReadParam(m, iter, &p->javascript_enabled) && + ReadParam(m, iter, &p->web_security_enabled) && + ReadParam(m, iter, &p->javascript_can_open_windows_automatically) && + ReadParam(m, iter, &p->loads_images_automatically) && + ReadParam(m, iter, &p->plugins_enabled) && + ReadParam(m, iter, &p->dom_paste_enabled) && + ReadParam(m, iter, &p->developer_extras_enabled) && + ReadParam(m, iter, &p->inspector_settings) && + ReadParam(m, iter, &p->site_specific_quirks_enabled) && + ReadParam(m, iter, &p->shrinks_standalone_images_to_fit) && + ReadParam(m, iter, &p->uses_universal_detector) && + ReadParam(m, iter, &p->text_areas_are_resizable) && + ReadParam(m, iter, &p->java_enabled) && + ReadParam(m, iter, &p->allow_scripts_to_close_windows) && + ReadParam(m, iter, &p->uses_page_cache) && + ReadParam(m, iter, &p->remote_fonts_enabled) && + ReadParam(m, iter, &p->javascript_can_access_clipboard) && + ReadParam(m, iter, &p->xss_auditor_enabled) && + ReadParam(m, iter, &p->local_storage_enabled) && + ReadParam(m, iter, &p->databases_enabled) && + ReadParam(m, iter, &p->application_cache_enabled) && + ReadParam(m, iter, &p->tabs_to_links) && + ReadParam(m, iter, &p->user_style_sheet_enabled) && + ReadParam(m, iter, &p->user_style_sheet_location) && + ReadParam(m, iter, &p->author_and_user_styles_enabled) && + ReadParam(m, iter, &p->allow_universal_access_from_file_urls) && + ReadParam(m, iter, &p->allow_file_access_from_file_urls) && + ReadParam(m, iter, &p->experimental_webgl_enabled) && + ReadParam(m, iter, &p->show_composited_layer_borders) && + ReadParam(m, iter, &p->accelerated_compositing_enabled) && + ReadParam(m, iter, &p->memory_info_enabled); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<WebPreferences>"); + } +}; + +// Traits for WebDropData +template <> +struct ParamTraits<WebDropData> { + typedef WebDropData param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.identity); + WriteParam(m, p.url); + WriteParam(m, p.url_title); + WriteParam(m, p.download_metadata); + WriteParam(m, p.file_extension); + WriteParam(m, p.filenames); + WriteParam(m, p.plain_text); + WriteParam(m, p.text_html); + WriteParam(m, p.html_base_url); + WriteParam(m, p.file_description_filename); + WriteParam(m, p.file_contents); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->identity) && + ReadParam(m, iter, &p->url) && + ReadParam(m, iter, &p->url_title) && + ReadParam(m, iter, &p->download_metadata) && + ReadParam(m, iter, &p->file_extension) && + ReadParam(m, iter, &p->filenames) && + ReadParam(m, iter, &p->plain_text) && + ReadParam(m, iter, &p->text_html) && + ReadParam(m, iter, &p->html_base_url) && + ReadParam(m, iter, &p->file_description_filename) && + ReadParam(m, iter, &p->file_contents); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<WebDropData>"); + } +}; + +// Traits for AudioManager::Format. +template <> +struct ParamTraits<AudioManager::Format> { + typedef AudioManager::Format param_type; + static void Write(Message* m, const param_type& p) { + m->WriteInt(p); + } + static bool Read(const Message* m, void** iter, param_type* p) { + int type; + if (!m->ReadInt(iter, &type)) + return false; + *p = static_cast<AudioManager::Format>(type); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + std::wstring format; + switch (p) { + case AudioManager::AUDIO_PCM_LINEAR: + format = L"AUDIO_PCM_LINEAR"; + break; + case AudioManager::AUDIO_PCM_LOW_LATENCY: + format = L"AUDIO_PCM_LOW_LATENCY"; + break; + case AudioManager::AUDIO_MOCK: + format = L"AUDIO_MOCK"; + break; + default: + format = L"AUDIO_LAST_FORMAT"; + break; + } + LogParam(format, l); + } +}; + +// Traits for ViewHostMsg_Audio_CreateStream_Params. +template <> +struct ParamTraits<ViewHostMsg_Audio_CreateStream_Params> { + typedef ViewHostMsg_Audio_CreateStream_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.format); + WriteParam(m, p.channels); + WriteParam(m, p.sample_rate); + WriteParam(m, p.bits_per_sample); + WriteParam(m, p.packet_size); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->format) && + ReadParam(m, iter, &p->channels) && + ReadParam(m, iter, &p->sample_rate) && + ReadParam(m, iter, &p->bits_per_sample) && + ReadParam(m, iter, &p->packet_size); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<ViewHostMsg_Audio_CreateStream_Params>("); + LogParam(p.format, l); + l->append(L", "); + LogParam(p.channels, l); + l->append(L", "); + LogParam(p.sample_rate, l); + l->append(L", "); + LogParam(p.bits_per_sample, l); + l->append(L", "); + LogParam(p.packet_size, l); + l->append(L")"); + } +}; + + +#if defined(OS_POSIX) + +// TODO(port): this shouldn't exist. However, the plugin stuff is really using +// HWNDS (NativeView), and making Windows calls based on them. I've not figured +// out the deal with plugins yet. +template <> +struct ParamTraits<gfx::NativeView> { + typedef gfx::NativeView param_type; + static void Write(Message* m, const param_type& p) { + NOTIMPLEMENTED(); + } + + static bool Read(const Message* m, void** iter, param_type* p) { + NOTIMPLEMENTED(); + *p = NULL; + return true; + } + + static void Log(const param_type& p, std::wstring* l) { + l->append(StringPrintf(L"<gfx::NativeView>")); + } +}; + +#endif // defined(OS_POSIX) + +template <> +struct ParamTraits<ViewMsg_AudioStreamState_Params> { + typedef ViewMsg_AudioStreamState_Params param_type; + static void Write(Message* m, const param_type& p) { + m->WriteInt(p.state); + } + static bool Read(const Message* m, void** iter, param_type* p) { + int type; + if (!m->ReadInt(iter, &type)) + return false; + p->state = static_cast<ViewMsg_AudioStreamState_Params::State>(type); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + std::wstring state; + switch (p.state) { + case ViewMsg_AudioStreamState_Params::kPlaying: + state = L"ViewMsg_AudioStreamState_Params::kPlaying"; + break; + case ViewMsg_AudioStreamState_Params::kPaused: + state = L"ViewMsg_AudioStreamState_Params::kPaused"; + break; + case ViewMsg_AudioStreamState_Params::kError: + state = L"ViewMsg_AudioStreamState_Params::kError"; + break; + default: + state = L"UNKNOWN"; + break; + } + LogParam(state, l); + } +}; + +template <> +struct ParamTraits<ViewMsg_StopFinding_Params> { + typedef ViewMsg_StopFinding_Params param_type; + static void Write(Message* m, const param_type& p) { + m->WriteInt(p.action); + } + static bool Read(const Message* m, void** iter, param_type* p) { + int type; + if (!m->ReadInt(iter, &type)) + return false; + p->action = static_cast<ViewMsg_StopFinding_Params::Action>(type); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + std::wstring action; + switch (p.action) { + case ViewMsg_StopFinding_Params::kClearSelection: + action = L"ViewMsg_StopFinding_Params::kClearSelection"; + break; + case ViewMsg_StopFinding_Params::kKeepSelection: + action = L"ViewMsg_StopFinding_Params::kKeepSelection"; + break; + case ViewMsg_StopFinding_Params::kActivateSelection: + action = L"ViewMsg_StopFinding_Params::kActivateSelection"; + break; + default: + action = L"UNKNOWN"; + break; + } + LogParam(action, l); + } +}; + +template <> +struct ParamTraits<appcache::Status> { + typedef appcache::Status param_type; + static void Write(Message* m, const param_type& p) { + m->WriteInt(static_cast<int>(p)); + } + static bool Read(const Message* m, void** iter, param_type* p) { + int type; + if (!m->ReadInt(iter, &type)) + return false; + *p = static_cast<param_type>(type); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + std::wstring state; + switch (p) { + case appcache::UNCACHED: + state = L"UNCACHED"; + break; + case appcache::IDLE: + state = L"IDLE"; + break; + case appcache::CHECKING: + state = L"CHECKING"; + break; + case appcache::DOWNLOADING: + state = L"DOWNLOADING"; + break; + case appcache::UPDATE_READY: + state = L"UPDATE_READY"; + break; + case appcache::OBSOLETE: + state = L"OBSOLETE"; + break; + default: + state = L"InvalidStatusValue"; + break; + } + + LogParam(state, l); + } +}; + +template <> +struct ParamTraits<appcache::EventID> { + typedef appcache::EventID param_type; + static void Write(Message* m, const param_type& p) { + m->WriteInt(static_cast<int>(p)); + } + static bool Read(const Message* m, void** iter, param_type* p) { + int type; + if (!m->ReadInt(iter, &type)) + return false; + *p = static_cast<param_type>(type); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + std::wstring state; + switch (p) { + case appcache::CHECKING_EVENT: + state = L"CHECKING_EVENT"; + break; + case appcache::ERROR_EVENT: + state = L"ERROR_EVENT"; + break; + case appcache::NO_UPDATE_EVENT: + state = L"NO_UPDATE_EVENT"; + break; + case appcache::DOWNLOADING_EVENT: + state = L"DOWNLOADING_EVENT"; + break; + case appcache::PROGRESS_EVENT: + state = L"PROGRESS_EVENT"; + break; + case appcache::UPDATE_READY_EVENT: + state = L"UPDATE_READY_EVENT"; + break; + case appcache::CACHED_EVENT: + state = L"CACHED_EVENT"; + break; + case appcache::OBSOLETE_EVENT: + state = L"OBSOLETE_EVENT"; + break; + default: + state = L"InvalidEventValue"; + break; + } + + LogParam(state, l); + } +}; + +template<> +struct ParamTraits<WebMenuItem::Type> { + typedef WebMenuItem::Type param_type; + static void Write(Message* m, const param_type& p) { + m->WriteInt(p); + } + static bool Read(const Message* m, void** iter, param_type* p) { + int type; + if (!m->ReadInt(iter, &type)) + return false; + *p = static_cast<WebMenuItem::Type>(type); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + std::wstring type; + switch (p) { + case WebMenuItem::OPTION: + type = L"OPTION"; + break; + case WebMenuItem::GROUP: + type = L"GROUP"; + break; + case WebMenuItem::SEPARATOR: + type = L"SEPARATOR"; + break; + default: + type = L"UNKNOWN"; + break; + } + LogParam(type, l); + } +}; + +template<> +struct ParamTraits<WebMenuItem> { + typedef WebMenuItem param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.label); + WriteParam(m, p.type); + WriteParam(m, p.enabled); + WriteParam(m, p.checked); + WriteParam(m, p.action); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->label) && + ReadParam(m, iter, &p->type) && + ReadParam(m, iter, &p->enabled) && + ReadParam(m, iter, &p->checked) && + ReadParam(m, iter, &p->action); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.label, l); + l->append(L", "); + LogParam(p.type, l); + l->append(L", "); + LogParam(p.enabled, l); + l->append(L", "); + LogParam(p.checked, l); + l->append(L", "); + LogParam(p.action, l); + l->append(L")"); + } +}; + +// Traits for ViewHostMsg_ShowPopup_Params. +template <> +struct ParamTraits<ViewHostMsg_ShowPopup_Params> { + typedef ViewHostMsg_ShowPopup_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.bounds); + WriteParam(m, p.item_height); + WriteParam(m, p.item_font_size); + WriteParam(m, p.selected_item); + WriteParam(m, p.popup_items); + WriteParam(m, p.right_aligned); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->bounds) && + ReadParam(m, iter, &p->item_height) && + ReadParam(m, iter, &p->item_font_size) && + ReadParam(m, iter, &p->selected_item) && + ReadParam(m, iter, &p->popup_items) && + ReadParam(m, iter, &p->right_aligned); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.bounds, l); + l->append(L", "); + LogParam(p.item_height, l); + l->append(L", "); + LogParam(p.item_font_size, l); + l->append(L", "); + LogParam(p.selected_item, l); + l->append(L", "); + LogParam(p.popup_items, l); + l->append(L", "); + LogParam(p.right_aligned, l); + l->append(L")"); + } +}; + +// Traits for ViewHostMsg_ScriptedPrint_Params. +template <> +struct ParamTraits<ViewHostMsg_ScriptedPrint_Params> { + typedef ViewHostMsg_ScriptedPrint_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.routing_id); + WriteParam(m, p.host_window_id); + WriteParam(m, p.cookie); + WriteParam(m, p.expected_pages_count); + WriteParam(m, p.has_selection); + WriteParam(m, p.use_overlays); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->routing_id) && + ReadParam(m, iter, &p->host_window_id) && + ReadParam(m, iter, &p->cookie) && + ReadParam(m, iter, &p->expected_pages_count) && + ReadParam(m, iter, &p->has_selection) && + ReadParam(m, iter, &p->use_overlays); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.routing_id, l); + l->append(L", "); + LogParam(p.host_window_id, l); + l->append(L", "); + LogParam(p.cookie, l); + l->append(L", "); + LogParam(p.expected_pages_count, l); + l->append(L", "); + LogParam(p.has_selection, l); + l->append(L","); + LogParam(p.use_overlays, l); + l->append(L")"); + } +}; + +template <> +struct SimilarTypeTraits<ViewType::Type> { + typedef int Type; +}; + +// Traits for URLPattern. +template <> +struct ParamTraits<URLPattern> { + typedef URLPattern param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.valid_schemes()); + WriteParam(m, p.GetAsString()); + } + static bool Read(const Message* m, void** iter, param_type* p) { + int valid_schemes; + std::string spec; + if (!ReadParam(m, iter, &valid_schemes) || + !ReadParam(m, iter, &spec)) + return false; + + p->set_valid_schemes(valid_schemes); + return p->Parse(spec); + } + static void Log(const param_type& p, std::wstring* l) { + LogParam(p.GetAsString(), l); + } +}; + +template <> +struct ParamTraits<Clipboard::Buffer> { + typedef Clipboard::Buffer param_type; + static void Write(Message* m, const param_type& p) { + m->WriteInt(p); + } + static bool Read(const Message* m, void** iter, param_type* p) { + int buffer; + if (!m->ReadInt(iter, &buffer) || !Clipboard::IsValidBuffer(buffer)) + return false; + *p = Clipboard::FromInt(buffer); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + std::wstring type; + switch (p) { + case Clipboard::BUFFER_STANDARD: + type = L"BUFFER_STANDARD"; + break; +#if defined(USE_X11) + case Clipboard::BUFFER_SELECTION: + type = L"BUFFER_SELECTION"; + break; +#endif + case Clipboard::BUFFER_DRAG: + type = L"BUFFER_DRAG"; + break; + default: + type = L"UNKNOWN"; + break; + } + + LogParam(type, l); + } +}; + +// Traits for EditCommand structure. +template <> +struct ParamTraits<EditCommand> { + typedef EditCommand param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.name); + WriteParam(m, p.value); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return ReadParam(m, iter, &p->name) && ReadParam(m, iter, &p->value); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.name, l); + l->append(L":"); + LogParam(p.value, l); + l->append(L")"); + } +}; + +// Traits for DOMStorageType enum. +template <> +struct ParamTraits<DOMStorageType> { + typedef DOMStorageType param_type; + static void Write(Message* m, const param_type& p) { + m->WriteInt(p); + } + static bool Read(const Message* m, void** iter, param_type* p) { + int type; + if (!m->ReadInt(iter, &type)) + return false; + *p = static_cast<param_type>(type); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + std::wstring control; + switch (p) { + case DOM_STORAGE_LOCAL: + control = L"DOM_STORAGE_LOCAL"; + break; + case DOM_STORAGE_SESSION: + control = L"DOM_STORAGE_SESSION"; + break; + default: + NOTIMPLEMENTED(); + control = L"UNKNOWN"; + break; + } + LogParam(control, l); + } +}; + +// Traits for WebKit::WebStorageArea::Result enum. +template <> +struct ParamTraits<WebKit::WebStorageArea::Result> { + typedef WebKit::WebStorageArea::Result param_type; + static void Write(Message* m, const param_type& p) { + m->WriteInt(p); + } + static bool Read(const Message* m, void** iter, param_type* p) { + int type; + if (!m->ReadInt(iter, &type)) + return false; + *p = static_cast<param_type>(type); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + std::wstring control; + switch (p) { + case WebKit::WebStorageArea::ResultOK: + control = L"WebKit::WebStorageArea::ResultOK"; + break; + case WebKit::WebStorageArea::ResultBlockedByQuota: + control = L"WebKit::WebStorageArea::ResultBlockedByQuota"; + break; + case WebKit::WebStorageArea::ResultBlockedByPolicy: + control = L"WebKit::WebStorageArea::ResultBlockedByPolicy"; + break; + default: + NOTIMPLEMENTED(); + control = L"UNKNOWN"; + break; + } + LogParam(control, l); + } +}; + +// Traits for ViewMsg_DOMStorageEvent_Params. +template <> +struct ParamTraits<ViewMsg_DOMStorageEvent_Params> { + typedef ViewMsg_DOMStorageEvent_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.key_); + WriteParam(m, p.old_value_); + WriteParam(m, p.new_value_); + WriteParam(m, p.origin_); + WriteParam(m, p.url_); + WriteParam(m, p.storage_type_); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->key_) && + ReadParam(m, iter, &p->old_value_) && + ReadParam(m, iter, &p->new_value_) && + ReadParam(m, iter, &p->origin_) && + ReadParam(m, iter, &p->url_) && + ReadParam(m, iter, &p->storage_type_); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.key_, l); + l->append(L", "); + LogParam(p.old_value_, l); + l->append(L", "); + LogParam(p.new_value_, l); + l->append(L", "); + LogParam(p.origin_, l); + l->append(L", "); + LogParam(p.url_, l); + l->append(L", "); + LogParam(p.storage_type_, l); + l->append(L")"); + } +}; + +// Traits for ViewHostMsg_IndexedDatabaseOpen_Params. +template <> +struct ParamTraits<ViewHostMsg_IndexedDatabaseOpen_Params> { + typedef ViewHostMsg_IndexedDatabaseOpen_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.routing_id_); + WriteParam(m, p.response_id_); + WriteParam(m, p.origin_); + WriteParam(m, p.name_); + WriteParam(m, p.description_); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->routing_id_) && + ReadParam(m, iter, &p->response_id_) && + ReadParam(m, iter, &p->origin_) && + ReadParam(m, iter, &p->name_) && + ReadParam(m, iter, &p->description_); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.routing_id_, l); + l->append(L", "); + LogParam(p.response_id_, l); + l->append(L", "); + LogParam(p.origin_, l); + l->append(L", "); + LogParam(p.name_, l); + l->append(L", "); + LogParam(p.description_, l); + l->append(L")"); + } +}; + +// Traits for ViewHostMsg_IDBDatabaseCreateObjectStore_Params. +template <> +struct ParamTraits<ViewHostMsg_IDBDatabaseCreateObjectStore_Params> { + typedef ViewHostMsg_IDBDatabaseCreateObjectStore_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.response_id_); + WriteParam(m, p.name_); + WriteParam(m, p.key_path_); + WriteParam(m, p.auto_increment_); + WriteParam(m, p.idb_database_id_); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->response_id_) && + ReadParam(m, iter, &p->name_) && + ReadParam(m, iter, &p->key_path_) && + ReadParam(m, iter, &p->auto_increment_) && + ReadParam(m, iter, &p->idb_database_id_); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.response_id_, l); + l->append(L", "); + LogParam(p.name_, l); + l->append(L", "); + LogParam(p.key_path_, l); + l->append(L", "); + LogParam(p.auto_increment_, l); + l->append(L", "); + LogParam(p.idb_database_id_, l); + l->append(L")"); + } +}; + +// Traits for ViewHostMsg_IDBObjectStoreCreateIndex_Params. +template <> +struct ParamTraits<ViewHostMsg_IDBObjectStoreCreateIndex_Params> { + typedef ViewHostMsg_IDBObjectStoreCreateIndex_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.response_id_); + WriteParam(m, p.name_); + WriteParam(m, p.key_path_); + WriteParam(m, p.unique_); + WriteParam(m, p.idb_object_store_id_); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->response_id_) && + ReadParam(m, iter, &p->name_) && + ReadParam(m, iter, &p->key_path_) && + ReadParam(m, iter, &p->unique_) && + ReadParam(m, iter, &p->idb_object_store_id_); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.response_id_, l); + l->append(L", "); + LogParam(p.name_, l); + l->append(L", "); + LogParam(p.key_path_, l); + l->append(L", "); + LogParam(p.unique_, l); + l->append(L", "); + LogParam(p.idb_object_store_id_, l); + l->append(L")"); + } +}; + +// Traits for ViewHostMsg_CreateWorker_Params +template <> +struct ParamTraits<ViewHostMsg_CreateWorker_Params> { + typedef ViewHostMsg_CreateWorker_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.url); + WriteParam(m, p.is_shared); + WriteParam(m, p.name); + WriteParam(m, p.document_id); + WriteParam(m, p.render_view_route_id); + WriteParam(m, p.route_id); + WriteParam(m, p.parent_appcache_host_id); + WriteParam(m, p.script_resource_appcache_id); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->url) && + ReadParam(m, iter, &p->is_shared) && + ReadParam(m, iter, &p->name) && + ReadParam(m, iter, &p->document_id) && + ReadParam(m, iter, &p->render_view_route_id) && + ReadParam(m, iter, &p->route_id) && + ReadParam(m, iter, &p->parent_appcache_host_id) && + ReadParam(m, iter, &p->script_resource_appcache_id); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.url, l); + l->append(L", "); + LogParam(p.is_shared, l); + l->append(L", "); + LogParam(p.name, l); + l->append(L", "); + LogParam(p.document_id, l); + l->append(L", "); + LogParam(p.render_view_route_id, l); + l->append(L","); + LogParam(p.route_id, l); + l->append(L", "); + LogParam(p.parent_appcache_host_id, l); + l->append(L","); + LogParam(p.script_resource_appcache_id, l); + l->append(L")"); + } +}; + +// Traits for ShowNotification_Params +template <> +struct ParamTraits<ViewHostMsg_ShowNotification_Params> { + typedef ViewHostMsg_ShowNotification_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.origin); + WriteParam(m, p.is_html); + WriteParam(m, p.contents_url); + WriteParam(m, p.icon_url); + WriteParam(m, p.title); + WriteParam(m, p.body); + WriteParam(m, p.direction); + WriteParam(m, p.replace_id); + WriteParam(m, p.notification_id); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->origin) && + ReadParam(m, iter, &p->is_html) && + ReadParam(m, iter, &p->contents_url) && + ReadParam(m, iter, &p->icon_url) && + ReadParam(m, iter, &p->title) && + ReadParam(m, iter, &p->body) && + ReadParam(m, iter, &p->direction) && + ReadParam(m, iter, &p->replace_id) && + ReadParam(m, iter, &p->notification_id); + } + static void Log(const param_type &p, std::wstring* l) { + l->append(L"("); + LogParam(p.origin, l); + l->append(L", "); + LogParam(p.is_html, l); + l->append(L", "); + LogParam(p.contents_url, l); + l->append(L", "); + LogParam(p.icon_url, l); + l->append(L", "); + LogParam(p.title, l); + l->append(L","); + LogParam(p.body, l); + l->append(L","); + LogParam(p.direction, l); + l->append(L","); + LogParam(p.replace_id, l); + l->append(L","); + LogParam(p.notification_id, l); + l->append(L")"); + } +}; + +// Traits for WebCookie +template <> +struct ParamTraits<webkit_glue::WebCookie> { + typedef webkit_glue::WebCookie param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.name); + WriteParam(m, p.value); + WriteParam(m, p.domain); + WriteParam(m, p.path); + WriteParam(m, p.expires); + WriteParam(m, p.http_only); + WriteParam(m, p.secure); + WriteParam(m, p.session); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->name) && + ReadParam(m, iter, &p->value) && + ReadParam(m, iter, &p->domain) && + ReadParam(m, iter, &p->path) && + ReadParam(m, iter, &p->expires) && + ReadParam(m, iter, &p->http_only) && + ReadParam(m, iter, &p->secure) && + ReadParam(m, iter, &p->session); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<WebCookie>"); + } +}; + +template<> +struct ParamTraits<ViewMsg_ExecuteCode_Params> { + typedef ViewMsg_ExecuteCode_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.request_id); + WriteParam(m, p.extension_id); + WriteParam(m, p.host_permissions); + WriteParam(m, p.is_javascript); + WriteParam(m, p.code); + WriteParam(m, p.all_frames); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->request_id) && + ReadParam(m, iter, &p->extension_id) && + ReadParam(m, iter, &p->host_permissions) && + ReadParam(m, iter, &p->is_javascript) && + ReadParam(m, iter, &p->code) && + ReadParam(m, iter, &p->all_frames); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<ViewMsg_ExecuteCode_Params>"); + } +}; + +template<> +struct ParamTraits<ViewMsg_New_Params> { + typedef ViewMsg_New_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.parent_window); + WriteParam(m, p.renderer_preferences); + WriteParam(m, p.web_preferences); + WriteParam(m, p.view_id); + WriteParam(m, p.session_storage_namespace_id); + WriteParam(m, p.frame_name); + } + + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->parent_window) && + ReadParam(m, iter, &p->renderer_preferences) && + ReadParam(m, iter, &p->web_preferences) && + ReadParam(m, iter, &p->view_id) && + ReadParam(m, iter, &p->session_storage_namespace_id) && + ReadParam(m, iter, &p->frame_name); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.parent_window, l); + l->append(L", "); + LogParam(p.renderer_preferences, l); + l->append(L", "); + LogParam(p.web_preferences, l); + l->append(L", "); + LogParam(p.view_id, l); + l->append(L", "); + LogParam(p.session_storage_namespace_id, l); + l->append(L", "); + LogParam(p.frame_name, l); + l->append(L")"); + } +}; + +template <> +struct SimilarTypeTraits<TranslateErrors::Type> { + typedef int Type; +}; + +template<> +struct ParamTraits<ViewHostMsg_RunFileChooser_Params> { + typedef ViewHostMsg_RunFileChooser_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, static_cast<int>(p.mode)); + WriteParam(m, p.title); + WriteParam(m, p.default_file_name); + } + static bool Read(const Message* m, void** iter, param_type* p) { + int mode; + if (!ReadParam(m, iter, &mode)) + return false; + if (mode != param_type::Open && + mode != param_type::OpenMultiple && + mode != param_type::Save) + return false; + p->mode = static_cast<param_type::Mode>(mode); + return + ReadParam(m, iter, &p->title) && + ReadParam(m, iter, &p->default_file_name); + }; + static void Log(const param_type& p, std::wstring* l) { + switch (p.mode) { + case param_type::Open: + l->append(L"(Open, "); + break; + case param_type::OpenMultiple: + l->append(L"(OpenMultiple, "); + break; + case param_type::Save: + l->append(L"(Save, "); + break; + default: + l->append(L"(UNKNOWN, "); + } + LogParam(p.title, l); + l->append(L", "); + LogParam(p.default_file_name, l); + } +}; + +template<> +struct ParamTraits<ViewHostMsg_CreateWindow_Params> { + typedef ViewHostMsg_CreateWindow_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.opener_id); + WriteParam(m, p.user_gesture); + WriteParam(m, p.window_container_type); + WriteParam(m, p.session_storage_namespace_id); + WriteParam(m, p.frame_name); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->opener_id) && + ReadParam(m, iter, &p->user_gesture) && + ReadParam(m, iter, &p->window_container_type) && + ReadParam(m, iter, &p->session_storage_namespace_id) && + ReadParam(m, iter, &p->frame_name); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.opener_id, l); + l->append(L", "); + LogParam(p.user_gesture, l); + l->append(L", "); + LogParam(p.window_container_type, l); + l->append(L", "); + LogParam(p.session_storage_namespace_id, l); + l->append(L", "); + LogParam(p.frame_name, l); + l->append(L")"); + } +}; + +template <> +struct ParamTraits<ExtensionExtent> { + typedef ExtensionExtent param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.patterns()); + } + static bool Read(const Message* m, void** iter, param_type* p) { + std::vector<URLPattern> patterns; + bool success = + ReadParam(m, iter, &patterns); + if (!success) + return false; + + for (size_t i = 0; i < patterns.size(); ++i) + p->AddPattern(patterns[i]); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + LogParam(p.patterns(), l); + } +}; + +template <> +struct ParamTraits<ViewMsg_ExtensionExtentInfo> { + typedef ViewMsg_ExtensionExtentInfo param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.extension_id); + WriteParam(m, p.web_extent); + WriteParam(m, p.browse_extent); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return ReadParam(m, iter, &p->extension_id) && + ReadParam(m, iter, &p->web_extent) && + ReadParam(m, iter, &p->browse_extent); + } + static void Log(const param_type& p, std::wstring* l) { + LogParam(p.extension_id, l); + } +}; + +template <> +struct ParamTraits<ViewMsg_ExtensionExtentsUpdated_Params> { + typedef ViewMsg_ExtensionExtentsUpdated_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.extension_apps); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return ReadParam(m, iter, &p->extension_apps); + } + static void Log(const param_type& p, std::wstring* l) { + LogParam(p.extension_apps, l); + } +}; + +template <> +struct ParamTraits<WindowContainerType> { + typedef WindowContainerType param_type; + static void Write(Message* m, const param_type& p) { + int val = static_cast<int>(p); + WriteParam(m, val); + } + static bool Read(const Message* m, void** iter, param_type* p) { + int val = 0; + if (!ReadParam(m, iter, &val) || + val < WINDOW_CONTAINER_TYPE_NORMAL || + val >= WINDOW_CONTAINER_TYPE_MAX_VALUE) + return false; + *p = static_cast<param_type>(val); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + LogParam(p, l); + } +}; + +template <> +struct ParamTraits<webkit_glue::WebAccessibility> { + typedef webkit_glue::WebAccessibility param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.id); + WriteParam(m, p.name); + WriteParam(m, p.value); + WriteParam(m, static_cast<int>(p.role)); + WriteParam(m, static_cast<int>(p.state)); + WriteParam(m, p.location); + WriteParam(m, p.attributes); + WriteParam(m, p.children); + } + static bool Read(const Message* m, void** iter, param_type* p) { + bool ret = ReadParam(m, iter, &p->id); + ret = ret && ReadParam(m, iter, &p->name); + ret = ret && ReadParam(m, iter, &p->value); + int role = -1; + ret = ret && ReadParam(m, iter, &role); + if (role >= webkit_glue::WebAccessibility::ROLE_NONE && + role < webkit_glue::WebAccessibility::NUM_ROLES) { + p->role = static_cast<webkit_glue::WebAccessibility::Role>(role); + } else { + p->role = webkit_glue::WebAccessibility::ROLE_NONE; + } + int state = 0; + ret = ret && ReadParam(m, iter, &state); + p->state = static_cast<webkit_glue::WebAccessibility::State>(state); + ret = ret && ReadParam(m, iter, &p->location); + ret = ret && ReadParam(m, iter, &p->attributes); + ret = ret && ReadParam(m, iter, &p->children); + return ret; + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.id, l); + l->append(L", "); + LogParam(p.name, l); + l->append(L", "); + LogParam(p.value, l); + l->append(L", "); + LogParam(static_cast<int>(p.role), l); + l->append(L", "); + LogParam(static_cast<int>(p.state), l); + l->append(L", "); + LogParam(p.location, l); + l->append(L", "); + LogParam(p.attributes, l); + l->append(L", "); + LogParam(p.children, l); + l->append(L")"); + } +}; + +} // namespace IPC + +#define MESSAGES_INTERNAL_FILE "chrome/common/render_messages_internal.h" +#include "ipc/ipc_message_macros.h" + +#endif // CHROME_COMMON_RENDER_MESSAGES_H_ diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h new file mode 100644 index 0000000..2cedec8 --- /dev/null +++ b/chrome/common/render_messages_internal.h @@ -0,0 +1,2529 @@ +// Copyright (c) 2010 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 header is meant to be included in multiple passes, hence no traditional +// header guard. +// See ipc_message_macros.h for explanation of the macros and passes. + +#include <map> +#include <string> +#include <vector> + +#include "build/build_config.h" + +#include "base/file_path.h" +#include "base/nullable_string16.h" +#include "base/platform_file.h" +#include "base/sync_socket.h" +#include "base/time.h" +#include "base/values.h" +#include "chrome/common/content_settings.h" +#include "chrome/common/extensions/update_manifest.h" +#include "chrome/common/geoposition.h" +#include "chrome/common/nacl_types.h" +#include "chrome/common/notification_type.h" +#include "chrome/common/page_zoom.h" +#include "chrome/common/thumbnail_score.h" +#include "chrome/common/translate_errors.h" +#include "chrome/common/window_container_type.h" +#include "gfx/rect.h" +#include "ipc/ipc_channel_handle.h" +#include "ipc/ipc_message.h" +#include "ipc/ipc_message_macros.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "webkit/glue/dom_operations.h" +#include "webkit/glue/form_field.h" +#include "webkit/glue/webcursor.h" + +#if defined(OS_POSIX) +#include "base/file_descriptor_posix.h" +#endif + +#if defined(OS_MACOSX) +#include "chrome/common/font_descriptor_mac.h" +#endif + +// TODO(mpcomplete): rename ViewMsg and ViewHostMsg to something that makes +// more sense with our current design. + +// IPC_MESSAGE macros choke on extra , in the std::map, when expanding. We need +// to typedef it to avoid that. +// Substitution map for l10n messages. +typedef std::map<std::string, std::string> SubstitutionMap; + +//----------------------------------------------------------------------------- +// RenderView messages +// These are messages sent from the browser to the renderer process. + +IPC_BEGIN_MESSAGES(View) + // Used typically when recovering from a crash. The new rendering process + // sets its global "next page id" counter to the given value. + IPC_MESSAGE_CONTROL1(ViewMsg_SetNextPageID, + int32 /* next_page_id */) + + // Sends System Colors corresponding to a set of CSS color keywords + // down the pipe. + // This message must be sent to the renderer immediately on launch + // before creating any new views. + // The message can also be sent during a renderer's lifetime if system colors + // are updated. + // TODO(jeremy): Possibly change IPC format once we have this all hooked up. + IPC_MESSAGE_ROUTED1(ViewMsg_SetCSSColors, + std::vector<CSSColors::CSSColorMapping>) + + // Tells the renderer to create a new view. + // This message is slightly different, the view it takes (via + // ViewMsg_New_Params) is the view to create, the message itself is sent as a + // non-view control message. + IPC_MESSAGE_CONTROL1(ViewMsg_New, + ViewMsg_New_Params) + + // Tells the renderer to set its maximum cache size to the supplied value + IPC_MESSAGE_CONTROL3(ViewMsg_SetCacheCapacities, + size_t /* min_dead_capacity */, + size_t /* max_dead_capacity */, + size_t /* capacity */) + + // Reply in response to ViewHostMsg_ShowView or ViewHostMsg_ShowWidget. + // similar to the new command, but used when the renderer created a view + // first, and we need to update it + IPC_MESSAGE_ROUTED1(ViewMsg_CreatingNew_ACK, + gfx::NativeViewId /* parent_hwnd */) + + // Sends updated preferences to the renderer. + IPC_MESSAGE_ROUTED1(ViewMsg_SetRendererPrefs, + RendererPreferences) + + // Tells the renderer to perform the given action on the media player + // located at the given point. + IPC_MESSAGE_ROUTED2(ViewMsg_MediaPlayerActionAt, + gfx::Point, /* location */ + WebKit::WebMediaPlayerAction) + + // Tells the render view to close. + IPC_MESSAGE_ROUTED0(ViewMsg_Close) + + // Tells the render view to change its size. A ViewHostMsg_PaintRect message + // is generated in response provided new_size is not empty and not equal to + // the view's current size. The generated ViewHostMsg_PaintRect message will + // have the IS_RESIZE_ACK flag set. It also receives the resizer rect so that + // we don't have to fetch it every time WebKit asks for it. + IPC_MESSAGE_ROUTED2(ViewMsg_Resize, + gfx::Size /* new_size */, + gfx::Rect /* resizer_rect */) + + // Sent to inform the view that it was hidden. This allows it to reduce its + // resource utilization. + IPC_MESSAGE_ROUTED0(ViewMsg_WasHidden) + + // Tells the render view that it is no longer hidden (see WasHidden), and the + // render view is expected to respond with a full repaint if needs_repainting + // is true. In that case, the generated ViewHostMsg_PaintRect message will + // have the IS_RESTORE_ACK flag set. If needs_repainting is false, then this + // message does not trigger a message in response. + IPC_MESSAGE_ROUTED1(ViewMsg_WasRestored, + bool /* needs_repainting */) + + // Tells the render view to capture a thumbnail image of the page. The + // render view responds with a ViewHostMsg_Thumbnail. + IPC_MESSAGE_ROUTED0(ViewMsg_CaptureThumbnail) + + // Tells the render view to capture a thumbnail image of the page. The + // render view responds with a ViewHostMsg_Snapshot. + IPC_MESSAGE_ROUTED0(ViewMsg_CaptureSnapshot) + + // Tells the render view to switch the CSS to print media type, renders every + // requested pages and switch back the CSS to display media type. + IPC_MESSAGE_ROUTED0(ViewMsg_PrintPages) + + // Tells the render view that printing is done so it can clean up. + IPC_MESSAGE_ROUTED2(ViewMsg_PrintingDone, + int /* document_cookie */, + bool /* success */) + + // Tells the renderer to dump as much memory as it can, perhaps because we + // have memory pressure or the renderer is (or will be) paged out. This + // should only result in purging objects we can recalculate, e.g. caches or + // JS garbage, not in purging irreplaceable objects. + IPC_MESSAGE_CONTROL0(ViewMsg_PurgeMemory) + + // Sent to render the view into the supplied transport DIB, resize + // the web widget to match the |page_size|, scale it by the + // appropriate scale to make it fit the |desired_size|, and return + // it. In response to this message, the host generates a + // ViewHostMsg_PaintAtSize_ACK message. Note that the DIB *must* be + // the right size to receive an RGBA image at the |desired_size|. + // |tag| is sent along with ViewHostMsg_PaintAtSize_ACK unmodified to + // identify the PaintAtSize message the ACK belongs to. + IPC_MESSAGE_ROUTED4(ViewMsg_PaintAtSize, + TransportDIB::Handle /* dib_handle */, + int /* tag */, + gfx::Size /* page_size */, + gfx::Size /* desired_size */) + + // Tells the render view that a ViewHostMsg_UpdateRect message was processed. + // This signals the render view that it can send another UpdateRect message. + IPC_MESSAGE_ROUTED0(ViewMsg_UpdateRect_ACK) + + // Replies to creating and updating videos. + IPC_MESSAGE_ROUTED1(ViewMsg_CreateVideo_ACK, + int32 /* video_id */) + IPC_MESSAGE_ROUTED1(ViewMsg_UpdateVideo_ACK, + int32 /* video_id */) + + // Message payload includes: + // 1. A blob that should be cast to WebInputEvent + // 2. An optional boolean value indicating if a RawKeyDown event is associated + // to a keyboard shortcut of the browser. + IPC_MESSAGE_ROUTED0(ViewMsg_HandleInputEvent) + + // This message notifies the renderer that the next key event is bound to one + // or more pre-defined edit commands. If the next key event is not handled + // by webkit, the specified edit commands shall be executed against current + // focused frame. + // Parameters + // * edit_commands (see chrome/common/edit_command_types.h) + // Contains one or more edit commands. + // See third_party/WebKit/WebCore/editing/EditorCommand.cpp for detailed + // definition of webkit edit commands. + // + // This message must be sent just before sending a key event. + IPC_MESSAGE_ROUTED1(ViewMsg_SetEditCommandsForNextKeyEvent, + EditCommands /* edit_commands */) + + // Message payload is the name/value of a WebCore edit command to execute. + IPC_MESSAGE_ROUTED2(ViewMsg_ExecuteEditCommand, + std::string, /* name */ + std::string /* value */) + + IPC_MESSAGE_ROUTED0(ViewMsg_MouseCaptureLost) + + // TODO(darin): figure out how this meshes with RestoreFocus + IPC_MESSAGE_ROUTED1(ViewMsg_SetFocus, bool /* enable */) + + // Tells the renderer to focus the first (last if reverse is true) focusable + // node. + IPC_MESSAGE_ROUTED1(ViewMsg_SetInitialFocus, bool /* reverse */) + + // Tells the renderer to perform the specified navigation, interrupting any + // existing navigation. + IPC_MESSAGE_ROUTED1(ViewMsg_Navigate, ViewMsg_Navigate_Params) + + IPC_MESSAGE_ROUTED0(ViewMsg_Stop) + + // Tells the renderer to reload the current focused frame + IPC_MESSAGE_ROUTED0(ViewMsg_ReloadFrame) + + // This message notifies the renderer that the user has closed the FindInPage + // window (and what action to take regarding the selection). + IPC_MESSAGE_ROUTED1(ViewMsg_StopFinding, + ViewMsg_StopFinding_Params /* action */) + + // These messages are typically generated from context menus and request the + // renderer to apply the specified operation to the current selection. + IPC_MESSAGE_ROUTED0(ViewMsg_Undo) + IPC_MESSAGE_ROUTED0(ViewMsg_Redo) + IPC_MESSAGE_ROUTED0(ViewMsg_Cut) + IPC_MESSAGE_ROUTED0(ViewMsg_Copy) +#if defined(OS_MACOSX) + IPC_MESSAGE_ROUTED0(ViewMsg_CopyToFindPboard) +#endif + IPC_MESSAGE_ROUTED0(ViewMsg_Paste) + // Replaces the selected region or a word around the cursor with the + // specified string. + IPC_MESSAGE_ROUTED1(ViewMsg_Replace, string16) + IPC_MESSAGE_ROUTED0(ViewMsg_ToggleSpellCheck) + IPC_MESSAGE_ROUTED0(ViewMsg_Delete) + IPC_MESSAGE_ROUTED0(ViewMsg_SelectAll) + IPC_MESSAGE_ROUTED1(ViewMsg_ToggleSpellPanel, bool) + + // This message tells the renderer to advance to the next misspelling. It is + // sent when the user clicks the "Find Next" button on the spelling panel. + IPC_MESSAGE_ROUTED0(ViewMsg_AdvanceToNextMisspelling) + + // Copies the image at location x, y to the clipboard (if there indeed is an + // image at that location). + IPC_MESSAGE_ROUTED2(ViewMsg_CopyImageAt, + int /* x */, + int /* y */) + + // History system notification that the visited link database has been + // replaced. It has one SharedMemoryHandle argument consisting of the table + // handle. This handle is valid in the context of the renderer + IPC_MESSAGE_CONTROL1(ViewMsg_VisitedLink_NewTable, base::SharedMemoryHandle) + + // History system notification that a link has been added and the link + // coloring state for the given hash must be re-calculated. + IPC_MESSAGE_CONTROL1(ViewMsg_VisitedLink_Add, std::vector<uint64>) + + // History system notification that one or more history items have been + // deleted, which at this point means that all link coloring state must be + // re-calculated. + IPC_MESSAGE_CONTROL0(ViewMsg_VisitedLink_Reset) + + // Notification that the user scripts have been updated. It has one + // SharedMemoryHandle argument consisting of the pickled script data. This + // handle is valid in the context of the renderer. + IPC_MESSAGE_CONTROL1(ViewMsg_UserScripts_UpdatedScripts, + base::SharedMemoryHandle) + + // Sent when the user wants to search for a word on the page (find in page). + IPC_MESSAGE_ROUTED3(ViewMsg_Find, + int /* request_id */, + string16 /* search_text */, + WebKit::WebFindOptions) + + // Send from the renderer to the browser to return the script running result. + IPC_MESSAGE_ROUTED2(ViewMsg_ExecuteCodeFinished, + int, /* request id */ + bool /* whether the script ran successfully */) + + // Sent when the headers are available for a resource request. + IPC_MESSAGE_ROUTED2(ViewMsg_Resource_ReceivedResponse, + int /* request_id */, + ResourceResponseHead) + + // Sent when cached metadata from a resource request is ready. + IPC_MESSAGE_ROUTED2(ViewMsg_Resource_ReceivedCachedMetadata, + int /* request_id */, + std::vector<char> /* data */) + + // Sent as download progress is being made, size of the resource may be + // unknown, in that case |size| is -1. + IPC_MESSAGE_ROUTED3(ViewMsg_Resource_DownloadProgress, + int /* request_id */, + int64 /* position */, + int64 /* size */) + + // Sent as upload progress is being made. + IPC_MESSAGE_ROUTED3(ViewMsg_Resource_UploadProgress, + int /* request_id */, + int64 /* position */, + int64 /* size */) + + // Sent when the request has been redirected. The receiver is expected to + // respond with either a FollowRedirect message (if the redirect is to be + // followed) or a CancelRequest message (if it should not be followed). + IPC_MESSAGE_ROUTED3(ViewMsg_Resource_ReceivedRedirect, + int /* request_id */, + GURL /* new_url */, + ResourceResponseHead) + + // Sent when some data from a resource request is ready. The handle should + // already be mapped into the process that receives this message. + IPC_MESSAGE_ROUTED3(ViewMsg_Resource_DataReceived, + int /* request_id */, + base::SharedMemoryHandle /* data */, + int /* data_len */) + + // Sent when the request has been completed. + IPC_MESSAGE_ROUTED3(ViewMsg_Resource_RequestComplete, + int /* request_id */, + URLRequestStatus /* status */, + std::string /* security info */) + + // Sent when user prompting is required before a ViewHostMsg_GetCookies + // message can complete. This message indicates that the renderer should + // pump messages while waiting for cookies. + IPC_MESSAGE_CONTROL0(ViewMsg_SignalCookiePromptEvent) + + // Request for the renderer to evaluate an xpath to a frame and execute a + // javascript: url in that frame's context. The message is completely + // asynchronous and no corresponding response message is sent back. + // + // frame_xpath contains the modified xpath notation to identify an inner + // subframe (starting from the root frame). It is a concatenation of + // number of smaller xpaths delimited by '\n'. Each chunk in the string can + // be evaluated to a frame in its parent-frame's context. + // + // Example: /html/body/iframe/\n/html/body/div/iframe/\n/frameset/frame[0] + // can be broken into 3 xpaths + // /html/body/iframe evaluates to an iframe within the root frame + // /html/body/div/iframe evaluates to an iframe within the level-1 iframe + // /frameset/frame[0] evaluates to first frame within the level-2 iframe + // + // jscript_url is the string containing the javascript: url to be executed + // in the target frame's context. The string should start with "javascript:" + // and continue with a valid JS text. + IPC_MESSAGE_ROUTED2(ViewMsg_ScriptEvalRequest, + std::wstring, /* frame_xpath */ + std::wstring /* jscript_url */) + + // Request for the renderer to evaluate an xpath to a frame and insert css + // into that frame's document. See ViewMsg_ScriptEvalRequest for details on + // allowed xpath expressions. + IPC_MESSAGE_ROUTED3(ViewMsg_CSSInsertRequest, + std::wstring, /* frame_xpath */ + std::string, /* css string */ + std::string /* element id */) + + // Log a message to the console of the target frame + IPC_MESSAGE_ROUTED3(ViewMsg_AddMessageToConsole, + string16 /* frame_xpath */, + string16 /* message */, + WebKit::WebConsoleMessage::Level /* message_level */) + + // RenderViewHostDelegate::RenderViewCreated method sends this message to a + // new renderer to notify it that it will host developer tools UI and should + // set up all neccessary bindings and create DevToolsClient instance that + // will handle communication with inspected page DevToolsAgent. + IPC_MESSAGE_ROUTED0(ViewMsg_SetupDevToolsClient) + + // Change the zoom level for the current main frame. If the level actually + // changes, a ViewHostMsg_DidZoomURL message will be sent back to the browser + // telling it what url got zoomed and what its current zoom level is. + IPC_MESSAGE_ROUTED1(ViewMsg_Zoom, + PageZoom::Function /* function */) + + // Set the zoom level for a particular url that the renderer is in the + // process of loading. This will be stored, to be used if the load commits + // and ignored otherwise. + IPC_MESSAGE_ROUTED2(ViewMsg_SetZoomLevelForLoadingURL, + GURL /* url */, + int /* zoom_level */) + + // Set the zoom level for a particular url, so all render views + // displaying this url can update their zoom levels to match. + IPC_MESSAGE_CONTROL2(ViewMsg_SetZoomLevelForCurrentURL, + GURL /* url */, + int /* zoom_level */) + + // Set the content settings for a particular url that the renderer is in the + // process of loading. This will be stored, to be used if the load commits + // and ignored otherwise. + IPC_MESSAGE_ROUTED2(ViewMsg_SetContentSettingsForLoadingURL, + GURL /* url */, + ContentSettings /* content_settings */) + + // Set the content settings for a particular url, so all render views + // displaying this host url update their content settings to match. + IPC_MESSAGE_CONTROL2(ViewMsg_SetContentSettingsForCurrentURL, + GURL /* url */, + ContentSettings /* content_settings */) + + // Change encoding of page in the renderer. + IPC_MESSAGE_ROUTED1(ViewMsg_SetPageEncoding, + std::string /*new encoding name*/) + + // Reset encoding of page in the renderer back to default. + IPC_MESSAGE_ROUTED0(ViewMsg_ResetPageEncodingToDefault) + + // Requests the renderer to reserve a range of page ids. + IPC_MESSAGE_ROUTED1(ViewMsg_ReservePageIDRange, + int /* size_of_range */) + + // Fill a form with data and optionally submit it + IPC_MESSAGE_ROUTED1(ViewMsg_FormFill, + webkit_glue::FormData /* form */) + + // Fill a password form and prepare field autocomplete for multiple + // matching logins. + IPC_MESSAGE_ROUTED1(ViewMsg_FillPasswordForm, + webkit_glue::PasswordFormFillData) + + // D&d drop target messages. + IPC_MESSAGE_ROUTED4(ViewMsg_DragTargetDragEnter, + WebDropData /* drop_data */, + gfx::Point /* client_pt */, + gfx::Point /* screen_pt */, + WebKit::WebDragOperationsMask /* ops_allowed */) + IPC_MESSAGE_ROUTED3(ViewMsg_DragTargetDragOver, + gfx::Point /* client_pt */, + gfx::Point /* screen_pt */, + WebKit::WebDragOperationsMask /* ops_allowed */) + IPC_MESSAGE_ROUTED0(ViewMsg_DragTargetDragLeave) + IPC_MESSAGE_ROUTED2(ViewMsg_DragTargetDrop, + gfx::Point /* client_pt */, + gfx::Point /* screen_pt */) + + // Notifies the renderer of updates in mouse position of an in-progress + // drag. if |ended| is true, then the user has ended the drag operation. + IPC_MESSAGE_ROUTED4(ViewMsg_DragSourceEndedOrMoved, + gfx::Point /* client_pt */, + gfx::Point /* screen_pt */, + bool /* ended */, + WebKit::WebDragOperation /* drag_operation */) + + // Notifies the renderer that the system DoDragDrop call has ended. + IPC_MESSAGE_ROUTED0(ViewMsg_DragSourceSystemDragEnded) + + // Used to tell a render view whether it should expose various bindings + // that allow JS content extended privileges. See BindingsPolicy for valid + // flag values. + IPC_MESSAGE_ROUTED1(ViewMsg_AllowBindings, + int /* enabled_bindings_flags */) + + // Tell the renderer to add a property to the DOMUI binding object. This + // only works if we allowed DOMUI bindings. + IPC_MESSAGE_ROUTED2(ViewMsg_SetDOMUIProperty, + std::string /* property_name */, + std::string /* property_value_json */) + + // This message starts/stop monitoring the input method status of the focused + // edit control of a renderer process. + // Parameters + // * is_active (bool) + // Indicates if an input method is active in the browser process. + // The possible actions when a renderer process receives this message are + // listed below: + // Value Action + // true Start sending IPC message ViewHostMsg_ImeUpdateTextInputState + // to notify the input method status of the focused edit control. + // false Stop sending IPC message ViewHostMsg_ImeUpdateTextInputState. + IPC_MESSAGE_ROUTED1(ViewMsg_SetInputMethodActive, + bool /* is_active */) + + // This message sends a string being composed with an input method. + IPC_MESSAGE_ROUTED4( + ViewMsg_ImeSetComposition, + string16, /* text */ + std::vector<WebKit::WebCompositionUnderline>, /* underlines */ + int, /* selectiont_start */ + int /* selection_end */) + + // This message confirms an ongoing composition. + IPC_MESSAGE_ROUTED0(ViewMsg_ImeConfirmComposition) + + // This passes a set of webkit preferences down to the renderer. + IPC_MESSAGE_ROUTED1(ViewMsg_UpdateWebPreferences, WebPreferences) + + // Used to notify the render-view that the browser has received a reply for + // the Find operation and is interested in receiving the next one. This is + // used to prevent the renderer from spamming the browser process with + // results. + IPC_MESSAGE_ROUTED0(ViewMsg_FindReplyACK) + + // Used to notify the render-view that we have received a target URL. Used + // to prevent target URLs spamming the browser. + IPC_MESSAGE_ROUTED0(ViewMsg_UpdateTargetURL_ACK) + + // Sets the alternate error page URL (link doctor) for the renderer process. + IPC_MESSAGE_ROUTED1(ViewMsg_SetAltErrorPageURL, GURL) + + // Install the first missing pluign. + IPC_MESSAGE_ROUTED0(ViewMsg_InstallMissingPlugin) + + // Tells the renderer to empty its plugin list cache, optional reloading + // pages containing plugins. + IPC_MESSAGE_CONTROL1(ViewMsg_PurgePluginListCache, + bool /* reload_pages */) + + IPC_MESSAGE_ROUTED1(ViewMsg_RunFileChooserResponse, + std::vector<FilePath> /* selected files */) + + // Used to instruct the RenderView to go into "view source" mode. + IPC_MESSAGE_ROUTED0(ViewMsg_EnableViewSourceMode) + + // Get all savable resource links from current webpage, include main + // frame and sub-frame. + IPC_MESSAGE_ROUTED1(ViewMsg_GetAllSavableResourceLinksForCurrentPage, + GURL /* url of page which is needed to save */) + + // Get html data by serializing all frames of current page with lists + // which contain all resource links that have local copy. + IPC_MESSAGE_ROUTED3(ViewMsg_GetSerializedHtmlDataForCurrentPageWithLocalLinks, + std::vector<GURL> /* urls that have local copy */, + std::vector<FilePath> /* paths of local copy */, + FilePath /* local directory path */) + + // Requests application info for the page. The renderer responds back with + // ViewHostMsg_DidGetApplicationInfo. + IPC_MESSAGE_ROUTED1(ViewMsg_GetApplicationInfo, int32 /*page_id*/) + + // Requests the renderer to download the specified favicon image encode it as + // PNG and send the PNG data back ala ViewHostMsg_DidDownloadFavIcon. + IPC_MESSAGE_ROUTED3(ViewMsg_DownloadFavIcon, + int /* identifier for the request */, + GURL /* URL of the image */, + int /* Size of the image. Normally 0, but set if you have + a preferred image size to request, such as when + downloading the favicon */) + + // When a renderer sends a ViewHostMsg_Focus to the browser process, + // the browser has the option of sending a ViewMsg_CantFocus back to + // the renderer. + IPC_MESSAGE_ROUTED0(ViewMsg_CantFocus) + + // Instructs the renderer to invoke the frame's shouldClose method, which + // runs the onbeforeunload event handler. Expects the result to be returned + // via ViewHostMsg_ShouldClose. + IPC_MESSAGE_ROUTED0(ViewMsg_ShouldClose) + + // Instructs the renderer to close the current page, including running the + // onunload event handler. See the struct in render_messages.h for more. + // + // Expects a ClosePage_ACK message when finished, where the parameters are + // echoed back. + IPC_MESSAGE_ROUTED1(ViewMsg_ClosePage, + ViewMsg_ClosePage_Params) + + // Asks the renderer to send back stats on the WebCore cache broken down by + // resource types. + IPC_MESSAGE_CONTROL0(ViewMsg_GetCacheResourceStats) + + // Asks the renderer to send back Histograms. + IPC_MESSAGE_CONTROL1(ViewMsg_GetRendererHistograms, + int /* sequence number of Renderer Histograms. */) + +#if defined(USE_TCMALLOC) + // Asks the renderer to send back tcmalloc stats. + IPC_MESSAGE_CONTROL0(ViewMsg_GetRendererTcmalloc) +#endif + + // Asks the renderer to send back V8 heap stats. + IPC_MESSAGE_CONTROL0(ViewMsg_GetV8HeapStats) + + // Notifies the renderer about ui theme changes + IPC_MESSAGE_ROUTED0(ViewMsg_ThemeChanged) + + // Notifies the renderer that a paint is to be generated for the rectangle + // passed in. + IPC_MESSAGE_ROUTED1(ViewMsg_Repaint, + gfx::Size /* The view size to be repainted */) + + // Posts a message to the renderer. + IPC_MESSAGE_ROUTED3(ViewMsg_HandleMessageFromExternalHost, + std::string /* The message */, + std::string /* The origin */, + std::string /* The target*/) + + // Sent to the renderer when a popup window should no longer count against + // the current popup count (either because it's not a popup or because it was + // a generated by a user action or because a constrained popup got turned + // into a full window). + IPC_MESSAGE_ROUTED0(ViewMsg_DisassociateFromPopupCount) + + // The browser sends this to a renderer process in response to a + // ViewHostMsg_EstablishGpuChannel message. + IPC_MESSAGE_CONTROL1(ViewMsg_GpuChannelEstablished, + IPC::ChannelHandle /* handle to channel */) + + // Notifies the renderer of the appcache that has been selected for a + // a particular host. This is sent in reply to AppCacheMsg_SelectCache. + IPC_MESSAGE_CONTROL3(AppCacheMsg_CacheSelected, + int /* host_id */, + int64 /* appcache_id */, + appcache::Status) + + // Notifies the renderer of an AppCache status change. + IPC_MESSAGE_CONTROL2(AppCacheMsg_StatusChanged, + std::vector<int> /* host_ids */, + appcache::Status) + + // Notifies the renderer of an AppCache event other than the + // progress event which has a seperate message. + IPC_MESSAGE_CONTROL2(AppCacheMsg_EventRaised, + std::vector<int> /* host_ids */, + appcache::EventID) + + // Notifies the renderer of an AppCache progress event. + IPC_MESSAGE_CONTROL4(AppCacheMsg_ProgressEventRaised, + std::vector<int> /* host_ids */, + GURL /* url being processed */, + int /* total */, + int /* complete */) + + // Notifies the renderer of an AppCache error event. + IPC_MESSAGE_CONTROL2(AppCacheMsg_ErrorEventRaised, + std::vector<int> /* host_ids */, + std::string /* error_message */) + + // Notifies the renderer of an AppCache logging message. + IPC_MESSAGE_CONTROL3(AppCacheMsg_LogMessage, + int /* host_id */, + int /* log_level */, + std::string /* message */) + + // Notifies the renderer of the fact that AppCache access was blocked. + IPC_MESSAGE_CONTROL2(AppCacheMsg_ContentBlocked, + int /* host_id */, + GURL /* manifest_url */) + + // Reply to the ViewHostMsg_QueryFormFieldAutoFill message with the + // AutoFill suggestions. + IPC_MESSAGE_ROUTED4(ViewMsg_AutoFillSuggestionsReturned, + int /* id of the request message */, + std::vector<string16> /* names */, + std::vector<string16> /* labels */, + std::vector<int> /* unique_ids */) + + // Reply to the ViewHostMsg_FillAutoFillFormData message with the + // AutoFill form data. + IPC_MESSAGE_ROUTED2(ViewMsg_AutoFillFormDataFilled, + int /* id of the request message */, + webkit_glue::FormData /* form data */) + + // Sent by the Browser process to alert a window about whether a it should + // allow a scripted window.close(). The renderer assumes every new window is a + // blocked popup until notified otherwise. + IPC_MESSAGE_ROUTED1(ViewMsg_AllowScriptToClose, + bool /* script_can_close */) + + // Sent by AudioRendererHost to renderer to request an audio packet. + IPC_MESSAGE_ROUTED3(ViewMsg_RequestAudioPacket, + int /* stream id */, + uint32 /* bytes in buffer */, + int64 /* message timestamp */) + + // Tell the renderer process that the audio stream has been created, renderer + // process would be given a ShareMemoryHandle that it should write to from + // then on. + IPC_MESSAGE_ROUTED3(ViewMsg_NotifyAudioStreamCreated, + int /* stream id */, + base::SharedMemoryHandle /* handle */, + uint32 /* length */) + + // Tell the renderer process that a low latency audio stream has been created, + // renderer process would be given a SyncSocket that it should write to from + // then on. +#if defined(OS_WIN) + IPC_MESSAGE_ROUTED4(ViewMsg_NotifyLowLatencyAudioStreamCreated, + int /* stream id */, + base::SharedMemoryHandle /* handle */, + base::SyncSocket::Handle /* socket handle */, + uint32 /* length */) +#else + IPC_MESSAGE_ROUTED4(ViewMsg_NotifyLowLatencyAudioStreamCreated, + int /* stream id */, + base::SharedMemoryHandle /* handle */, + base::FileDescriptor /* socket handle */, + uint32 /* length */) +#endif + + // Notification message sent from AudioRendererHost to renderer for state + // update after the renderer has requested a Create/Start/Close. + IPC_MESSAGE_ROUTED2(ViewMsg_NotifyAudioStreamStateChanged, + int /* stream id */, + ViewMsg_AudioStreamState_Params /* new state */) + + IPC_MESSAGE_ROUTED2(ViewMsg_NotifyAudioStreamVolume, + int /* stream id */, + double /* volume */) + + // Notification that a move or resize renderer's containing window has + // started. + IPC_MESSAGE_ROUTED0(ViewMsg_MoveOrResizeStarted) + + // The browser sends this message in response to all extension api calls. + IPC_MESSAGE_ROUTED4(ViewMsg_ExtensionResponse, + int /* request_id */, + bool /* success */, + std::string /* response */, + std::string /* error */) + + // This message is optionally routed. If used as a control message, it + // will call a javascript function in every registered context in the + // target process. If routed, it will be restricted to the contexts that + // are part of the target RenderView. + // |args| is a list of primitive Value types that are passed to the function. + IPC_MESSAGE_ROUTED4(ViewMsg_ExtensionMessageInvoke, + std::string /* function_name */, + ListValue /* args */, + bool /* requires incognito access */, + GURL /* event URL */) + + // Tell the renderer process all known extension function names. + IPC_MESSAGE_CONTROL1(ViewMsg_Extension_SetFunctionNames, + std::vector<std::string>) + + // Tell the renderer process which permissions the given extension has. See + // Extension::Permissions for which elements correspond to which permissions. + IPC_MESSAGE_CONTROL2(ViewMsg_Extension_SetAPIPermissions, + std::string /* extension_id */, + std::vector<std::string> /* permissions */) + + // Tell the renderer process which host permissions the given extension has. + IPC_MESSAGE_CONTROL2( + ViewMsg_Extension_SetHostPermissions, + GURL /* source extension's origin */, + std::vector<URLPattern> /* URLPatterns the extension can access */) + + // Tell the renderer process that the given extension is enabled or disabled + // for incognito mode. + IPC_MESSAGE_CONTROL2(ViewMsg_Extension_ExtensionSetIncognitoEnabled, + std::string /* extension_id */, + bool /* enabled */) + + // Tell the renderer process all known page action ids for a particular + // extension. + IPC_MESSAGE_CONTROL2(ViewMsg_Extension_UpdatePageActions, + std::string /* extension_id */, + std::vector<std::string> /* page_action_ids */) + + // Changes the text direction of the currently selected input field (if any). + IPC_MESSAGE_ROUTED1(ViewMsg_SetTextDirection, + WebKit::WebTextDirection /* direction */) + + // Tells the renderer to clear the focused node (if any). + IPC_MESSAGE_ROUTED0(ViewMsg_ClearFocusedNode) + + // Make the RenderView transparent and render it onto a custom background. The + // background will be tiled in both directions if it is not large enough. + IPC_MESSAGE_ROUTED1(ViewMsg_SetBackground, + SkBitmap /* background */) + + // Reply to ViewHostMsg_RequestMove, ViewHostMsg_ShowView, and + // ViewHostMsg_ShowWidget to inform the renderer that the browser has + // processed the move. The browser may have ignored the move, but it finished + // processing. This is used because the renderer keeps a temporary cache of + // the widget position while these asynchronous operations are in progress. + IPC_MESSAGE_ROUTED0(ViewMsg_Move_ACK) + + // Used to instruct the RenderView to send back updates to the preferred size. + IPC_MESSAGE_ROUTED1(ViewMsg_EnablePreferredSizeChangedMode, int /*flags*/) + + // Used to tell the renderer not to add scrollbars with height and + // width below a threshold. + IPC_MESSAGE_ROUTED1(ViewMsg_DisableScrollbarsForSmallWindows, + gfx::Size /* disable_scrollbar_size_limit */) + + // Used to inform the renderer that the browser has displayed its + // requested notification. + IPC_MESSAGE_ROUTED1(ViewMsg_PostDisplayToNotificationObject, + int /* notification_id */) + + // Used to inform the renderer that the browser has encountered an error + // trying to display a notification. + IPC_MESSAGE_ROUTED2(ViewMsg_PostErrorToNotificationObject, + int /* notification_id */, + string16 /* message */) + + // Informs the renderer that the one if its notifications has closed. + IPC_MESSAGE_ROUTED2(ViewMsg_PostCloseToNotificationObject, + int /* notification_id */, + bool /* by_user */) + + // Informs the renderer that the one if its notifications has closed. + IPC_MESSAGE_ROUTED1(ViewMsg_PermissionRequestDone, + int /* request_id */) + + // Activate/deactivate the RenderView (i.e., set its controls' tint + // accordingly, etc.). + IPC_MESSAGE_ROUTED1(ViewMsg_SetActive, + bool /* active */) + +#if defined(OS_MACOSX) + // Let the RenderView know its window has changed visibility. + IPC_MESSAGE_ROUTED1(ViewMsg_SetWindowVisibility, + bool /* visibile */) + + // Let the RenderView know its window's frame has changed. + IPC_MESSAGE_ROUTED2(ViewMsg_WindowFrameChanged, + gfx::Rect /* window frame */, + gfx::Rect /* content view frame */) +#endif + + // Response message to ViewHostMsg_CreateShared/DedicatedWorker. + // Sent when the worker has started. + IPC_MESSAGE_ROUTED0(ViewMsg_WorkerCreated) + + // Tell the renderer which browser window it's being attached to. + IPC_MESSAGE_ROUTED1(ViewMsg_UpdateBrowserWindowId, + int /* id of browser window */) + + // Tell the renderer which type this view is. + IPC_MESSAGE_ROUTED1(ViewMsg_NotifyRenderViewType, + ViewType::Type /* view_type */) + + // Notification that renderer should run some JavaScript code. + IPC_MESSAGE_ROUTED1(ViewMsg_ExecuteCode, + ViewMsg_ExecuteCode_Params) + + // Notifies the child process of the new database size + IPC_MESSAGE_CONTROL4(ViewMsg_DatabaseUpdateSize, + string16 /* the origin */, + string16 /* the database name */, + int64 /* the new database size */, + int64 /* space available to origin */) + + // Asks the child process to close a database immediately + IPC_MESSAGE_CONTROL2(ViewMsg_DatabaseCloseImmediately, + string16 /* the origin */, + string16 /* the database name */) + + // Storage events are broadcast to renderer processes. + IPC_MESSAGE_CONTROL1(ViewMsg_DOMStorageEvent, + ViewMsg_DOMStorageEvent_Params) + + // IDBCallback message handlers. + IPC_MESSAGE_CONTROL1(ViewMsg_IDBCallbacksSuccessNull, + int32 /* response_id */) + IPC_MESSAGE_CONTROL2(ViewMsg_IDBCallbacksSuccessIDBDatabase, + int32 /* response_id */, + int32 /* idb_database_id */) + IPC_MESSAGE_CONTROL2(ViewMsg_IDBCallbacksSuccessIndexedDBKey, + int32 /* response_id */, + IndexedDBKey /* indexed_db_key */) + IPC_MESSAGE_CONTROL2(ViewMsg_IDBCallbacksSuccessIDBObjectStore, + int32 /* response_id */, + int32 /* idb_object_store_id */) + IPC_MESSAGE_CONTROL2(ViewMsg_IDBCallbacksSuccessIDBIndex, + int32 /* response_id */, + int32 /* idb_index_id */) + IPC_MESSAGE_CONTROL2(ViewMsg_IDBCallbacksSuccessSerializedScriptValue, + int32 /* response_id */, + SerializedScriptValue /* serialized_script_value */) + IPC_MESSAGE_CONTROL3(ViewMsg_IDBCallbacksError, + int32 /* response_id */, + int /* code */, + string16 /* message */) + +#if defined(IPC_MESSAGE_LOG_ENABLED) + // Tell the renderer process to begin or end IPC message logging. + IPC_MESSAGE_CONTROL1(ViewMsg_SetIPCLoggingEnabled, + bool /* on or off */) +#endif + + // Socket Stream messages: + // These are messages from the browser to the SocketStreamHandle on + // a renderer. + + // A |socket_id| is assigned by ViewHostMsg_SocketStream_Connect. + // The Socket Stream is connected. The SocketStreamHandle should keep track + // of how much it has pending (how much it has requested to be sent) and + // shouldn't go over |max_pending_send_allowed| bytes. + IPC_MESSAGE_CONTROL2(ViewMsg_SocketStream_Connected, + int /* socket_id */, + int /* max_pending_send_allowed */) + + // |data| is received on the Socket Stream. + IPC_MESSAGE_CONTROL2(ViewMsg_SocketStream_ReceivedData, + int /* socket_id */, + std::vector<char> /* data */) + + // |amount_sent| bytes of data requested by + // ViewHostMsg_SocketStream_SendData has been sent on the Socket Stream. + IPC_MESSAGE_CONTROL2(ViewMsg_SocketStream_SentData, + int /* socket_id */, + int /* amount_sent */) + + // The Socket Stream is closed. + IPC_MESSAGE_CONTROL1(ViewMsg_SocketStream_Closed, + int /* socket_id */) + + // SpellChecker messages. + + // Passes some initialization params to the renderer's spellchecker. This can + // be called directly after startup or in (async) response to a + // RequestDictionary ViewHost message. + IPC_MESSAGE_CONTROL4(ViewMsg_SpellChecker_Init, + IPC::PlatformFileForTransit /* bdict_file */, + std::vector<std::string> /* custom_dict_words */, + std::string /* language */, + bool /* auto spell correct */) + + // A word has been added to the custom dictionary; update the local custom + // word list. + IPC_MESSAGE_CONTROL1(ViewMsg_SpellChecker_WordAdded, + std::string /* word */) + + // Toggle the auto spell correct functionality. + IPC_MESSAGE_CONTROL1(ViewMsg_SpellChecker_EnableAutoSpellCorrect, + bool /* enable */) + + // Executes custom context menu action that was provided from WebKit. + IPC_MESSAGE_ROUTED1(ViewMsg_CustomContextMenuAction, + unsigned /* action */) + + // Tells the renderer to translate the page contents from one language to + // another. + IPC_MESSAGE_ROUTED4(ViewMsg_TranslatePage, + int /* page id */, + std::string, /* the script injected in the page */ + std::string, /* BCP 47/RFC 5646 language code the page + is in */ + std::string /* BCP 47/RFC 5646 language code to translate + to */) + + // Tells the renderer to revert the text of translated page to its original + // contents. + IPC_MESSAGE_ROUTED1(ViewMsg_RevertTranslation, + int /* page id */) + + // Reply in response to ViewHostMsg_Geolocation_RequestPermission. + IPC_MESSAGE_ROUTED2(ViewMsg_Geolocation_PermissionSet, + int /* bridge_id */, + bool /* is_allowed */) + + // Sent after ViewHostMsg_Geolocation_StartUpdating iff the user has granted + // permission and we have a position available or an error occurs (such as + // permission denied, position unavailable, etc.) + IPC_MESSAGE_ROUTED1(ViewMsg_Geolocation_PositionUpdated, + Geoposition /* geoposition */) + + // Sent on process startup to indicate whether this process is running in + // incognito mode. + IPC_MESSAGE_CONTROL1(ViewMsg_SetIsIncognitoProcess, + bool /* is_incognito_processs */) + + // Notification that the list of extensions with web extents has been updated. + IPC_MESSAGE_CONTROL1(ViewMsg_ExtensionExtentsUpdated, + ViewMsg_ExtensionExtentsUpdated_Params) + + // Request a tree of Accessibility data from the render process. + IPC_MESSAGE_ROUTED0(ViewMsg_GetAccessibilityTree) + + // Relay a request from assistive technology to set focus to a given node. + IPC_MESSAGE_ROUTED1(ViewMsg_SetAccessibilityFocus, + int /* object id */) + + // Relay a request from assistive technology to perform the default action + // on a given node. + IPC_MESSAGE_ROUTED1(ViewMsg_AccessibilityDoDefaultAction, + int /* object id */) + +IPC_END_MESSAGES(View) + + +//----------------------------------------------------------------------------- +// TabContents messages +// These are messages sent from the renderer to the browser process. + +IPC_BEGIN_MESSAGES(ViewHost) + // Sent by the renderer when it is creating a new window. The browser creates + // a tab for it and responds with a ViewMsg_CreatingNew_ACK. If route_id is + // MSG_ROUTING_NONE, the view couldn't be created. + IPC_SYNC_MESSAGE_CONTROL1_2(ViewHostMsg_CreateWindow, + ViewHostMsg_CreateWindow_Params, + int /* route_id */, + int64 /* cloned_session_storage_namespace_id */) + + // Similar to ViewHostMsg_CreateWindow, except used for sub-widgets, like + // <select> dropdowns. This message is sent to the TabContents that + // contains the widget being created. + IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_CreateWidget, + int /* opener_id */, + WebKit::WebPopupType /* popup type */, + int /* route_id */) + + // These two messages are sent to the parent RenderViewHost to display the + // page/widget that was created by CreateWindow/CreateWidget. routing_id + // refers to the id that was returned from the Create message above. + // The initial_position parameter is a rectangle in screen coordinates. + // + // FUTURE: there will probably be flags here to control if the result is + // in a new window. + IPC_MESSAGE_ROUTED4(ViewHostMsg_ShowView, + int /* route_id */, + WindowOpenDisposition /* disposition */, + gfx::Rect /* initial_pos */, + bool /* opened_by_user_gesture */) + + IPC_MESSAGE_ROUTED2(ViewHostMsg_ShowWidget, + int /* route_id */, + gfx::Rect /* initial_pos */) + + // Message to show a popup menu using native cocoa controls (Mac only). + IPC_MESSAGE_ROUTED1(ViewHostMsg_ShowPopup, + ViewHostMsg_ShowPopup_Params) + + // This message is sent after ViewHostMsg_ShowView to cause the RenderView + // to run in a modal fashion until it is closed. + IPC_SYNC_MESSAGE_ROUTED0_0(ViewHostMsg_RunModal) + + IPC_MESSAGE_CONTROL1(ViewHostMsg_UpdatedCacheStats, + WebKit::WebCache::UsageStats /* stats */) + + // Indicates the renderer is ready in response to a ViewMsg_New or + // a ViewMsg_CreatingNew_ACK. + IPC_MESSAGE_ROUTED0(ViewHostMsg_RenderViewReady) + + // Indicates the renderer process is gone. This actually is sent by the + // browser process to itself, but keeps the interface cleaner. + IPC_MESSAGE_ROUTED0(ViewHostMsg_RenderViewGone) + + // Sent by the renderer process to request that the browser close the view. + // This corresponds to the window.close() API, and the browser may ignore + // this message. Otherwise, the browser will generates a ViewMsg_Close + // message to close the view. + IPC_MESSAGE_ROUTED0(ViewHostMsg_Close) + + // Sent by the renderer process to request that the browser move the view. + // This corresponds to the window.resizeTo() and window.moveTo() APIs, and + // the browser may ignore this message. + IPC_MESSAGE_ROUTED1(ViewHostMsg_RequestMove, + gfx::Rect /* position */) + + // Notifies the browser that a frame in the view has changed. This message + // has a lot of parameters and is packed/unpacked by functions defined in + // render_messages.h. + IPC_MESSAGE_ROUTED1(ViewHostMsg_FrameNavigate, + ViewHostMsg_FrameNavigate_Params) + + // Notifies the browser that we have session history information. + // page_id: unique ID that allows us to distinguish between history entries. + IPC_MESSAGE_ROUTED2(ViewHostMsg_UpdateState, + int32 /* page_id */, + std::string /* state */) + + // Notifies the browser that a document has been loaded in a frame. + IPC_MESSAGE_ROUTED0(ViewHostMsg_DocumentLoadedInFrame) + + // Changes the title for the page in the UI when the page is navigated or the + // title changes. + // TODO(darin): use a UTF-8 string to reduce data size + IPC_MESSAGE_ROUTED2(ViewHostMsg_UpdateTitle, int32, std::wstring) + + // Changes the icon url for the page in the UI. + IPC_MESSAGE_ROUTED2(ViewHostMsg_UpdateIconURL, int32, GURL) + + // Change the encoding name of the page in UI when the page has detected + // proper encoding name. + IPC_MESSAGE_ROUTED1(ViewHostMsg_UpdateEncoding, + std::string /* new encoding name */) + + // Notifies the browser that we want to show a destination url for a potential + // action (e.g. when the user is hovering over a link). + IPC_MESSAGE_ROUTED2(ViewHostMsg_UpdateTargetURL, int32, GURL) + + // Sent when the renderer starts loading the page. This corresponds to + // WebKit's notion of the throbber starting. Note that sometimes you may get + // duplicates of these during a single load. + IPC_MESSAGE_ROUTED0(ViewHostMsg_DidStartLoading) + + // Sent when the renderer is done loading a page. This corresponds to WebKit's + // noption of the throbber stopping. + IPC_MESSAGE_ROUTED0(ViewHostMsg_DidStopLoading) + + // Sent when the document element is available for the toplevel frame. This + // happens after the page starts loading, but before all resources are + // finished. + IPC_MESSAGE_ROUTED0(ViewHostMsg_DocumentAvailableInMainFrame) + + // Sent when after the onload handler has been invoked for the document + // in the toplevel frame. + IPC_MESSAGE_ROUTED0(ViewHostMsg_DocumentOnLoadCompletedInMainFrame) + + // Sent when the renderer loads a resource from its memory cache. + // The security info is non empty if the resource was originally loaded over + // a secure connection. + // Note: May only be sent once per URL per frame per committed load. + IPC_MESSAGE_ROUTED4(ViewHostMsg_DidLoadResourceFromMemoryCache, + GURL /* url */, + std::string /* frame_origin */, + std::string /* main_frame_origin */, + std::string /* security info */) + + // Sent when the renderer displays insecure content in a secure page. + IPC_MESSAGE_ROUTED0(ViewHostMsg_DidDisplayInsecureContent) + + // Sent when the renderer runs insecure content in a secure origin. + IPC_MESSAGE_ROUTED1(ViewHostMsg_DidRunInsecureContent, + std::string /* security_origin */) + + // Sent when the renderer starts a provisional load for a frame. + IPC_MESSAGE_ROUTED2(ViewHostMsg_DidStartProvisionalLoadForFrame, + bool /* true if it is the main frame */, + GURL /* url */) + + // Sent when the renderer fails a provisional load with an error. + IPC_MESSAGE_ROUTED4(ViewHostMsg_DidFailProvisionalLoadWithError, + bool /* true if it is the main frame */, + int /* error_code */, + GURL /* url */, + bool /* true if the failure is the result of + navigating to a POST again and we're going to + show the POST interstitial */ ) + + // Tells the render view that a ViewHostMsg_PaintAtSize message was + // processed, and the DIB is ready for use. |tag| has the same value that + // the tag sent along with ViewMsg_PaintAtSize. + IPC_MESSAGE_ROUTED2(ViewHostMsg_PaintAtSize_ACK, + int /* tag */, + gfx::Size /* size */) + + // Sent to update part of the view. In response to this message, the host + // generates a ViewMsg_UpdateRect_ACK message. + IPC_MESSAGE_ROUTED1(ViewHostMsg_UpdateRect, + ViewHostMsg_UpdateRect_Params) + + // Sent to create, update and destroy video layers. + IPC_MESSAGE_ROUTED1(ViewHostMsg_CreateVideo, + gfx::Size /* size */) + IPC_MESSAGE_ROUTED2(ViewHostMsg_UpdateVideo, + TransportDIB::Id /* bitmap */, + gfx::Rect /* bitmap_rect */) + IPC_MESSAGE_ROUTED0(ViewHostMsg_DestroyVideo) + + // Sent by the renderer when GPU compositing is enabled or disabled to notify + // the browser whether or not is should do paiting. + IPC_MESSAGE_ROUTED1(ViewHostMsg_GpuRenderingActivated, + bool /* true if the GPU process renders to window */) + + // Acknowledges receipt of a ViewMsg_HandleInputEvent message. + // Payload is a WebInputEvent::Type which is the type of the event, followed + // by an optional WebInputEvent which is provided only if the event was not + // processed. + IPC_MESSAGE_ROUTED0(ViewHostMsg_HandleInputEvent_ACK) + + IPC_MESSAGE_ROUTED0(ViewHostMsg_Focus) + IPC_MESSAGE_ROUTED0(ViewHostMsg_Blur) + IPC_MESSAGE_ROUTED0(ViewHostMsg_FocusedNodeChanged) + + // Returns the window location of the given window. + // TODO(shess): Provide a mapping from reply_msg->routing_id() to + // HWND so that we can eliminate the NativeViewId parameter. + IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_GetWindowRect, + gfx::NativeViewId /* window */, + gfx::Rect /* Out: Window location */) + + IPC_MESSAGE_ROUTED1(ViewHostMsg_SetCursor, WebCursor) + // Result of string search in the page. + // Response to ViewMsg_Find with the results of the requested find-in-page + // search, the number of matches found and the selection rect (in screen + // coordinates) for the string found. If |final_update| is false, it signals + // that this is not the last Find_Reply message - more will be sent as the + // scoping effort continues. + IPC_MESSAGE_ROUTED5(ViewHostMsg_Find_Reply, + int /* request_id */, + int /* number of matches */, + gfx::Rect /* selection_rect */, + int /* active_match_ordinal */, + bool /* final_update */) + + // Makes a resource request via the browser. + IPC_MESSAGE_ROUTED2(ViewHostMsg_RequestResource, + int /* request_id */, + ViewHostMsg_Resource_Request) + + // Cancels a resource request with the ID given as the parameter. + IPC_MESSAGE_ROUTED1(ViewHostMsg_CancelRequest, + int /* request_id */) + + // Follows a redirect that occured for the resource request with the ID given + // as the parameter. + IPC_MESSAGE_ROUTED3(ViewHostMsg_FollowRedirect, + int /* request_id */, + bool /* has_new_first_party_for_cookies */, + GURL /* new_first_party_for_cookies */) + + // Makes a synchronous resource request via the browser. + IPC_SYNC_MESSAGE_ROUTED2_1(ViewHostMsg_SyncLoad, + int /* request_id */, + ViewHostMsg_Resource_Request, + SyncLoadResult) + + // Used to set a cookie. The cookie is set asynchronously, but will be + // available to a subsequent ViewHostMsg_GetCookies request. + IPC_MESSAGE_ROUTED3(ViewHostMsg_SetCookie, + GURL /* url */, + GURL /* first_party_for_cookies */, + std::string /* cookie */) + + // Used to get cookies for the given URL. This may be blocked by a user + // prompt to validate a previous SetCookie message. + IPC_SYNC_MESSAGE_ROUTED2_1(ViewHostMsg_GetCookies, + GURL /* url */, + GURL /* first_party_for_cookies */, + std::string /* cookies */) + + // Used to get raw cookie information for the given URL. This may be blocked + // by a user prompt to validate a previous SetCookie message. + IPC_SYNC_MESSAGE_ROUTED2_1(ViewHostMsg_GetRawCookies, + GURL /* url */, + GURL /* first_party_for_cookies */, + std::vector<webkit_glue::WebCookie> + /* raw_cookies */) + + // Used to delete cookie for the given URL and name + IPC_SYNC_MESSAGE_CONTROL2_0(ViewHostMsg_DeleteCookie, + GURL /* url */, + std::string /* cookie_name */) + + // Used to get raw cookie information for the given URL + IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_GetCookiesEnabled, + GURL /* url */, + GURL /* first_party_for_cookies */, + bool /* enabled */) + + // Used to get the list of plugins + IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_GetPlugins, + bool /* refresh*/, + std::vector<WebPluginInfo> /* plugins */) + + // Returns a path to a plugin for the given url and mime type. If there's + // no plugin, an empty string is returned. + IPC_SYNC_MESSAGE_CONTROL3_2(ViewHostMsg_GetPluginPath, + GURL /* url */, + GURL /* policy_url */, + std::string /* mime_type */, + FilePath /* filename */, + std::string /* actual mime type for url */) + + // Requests spellcheck for a word. + IPC_SYNC_MESSAGE_ROUTED2_2(ViewHostMsg_SpellCheck, + string16 /* word to check */, + int /* document tag*/, + int /* misspell location */, + int /* misspell length */) + + // Asks the browser for a unique document tag. + IPC_SYNC_MESSAGE_ROUTED0_1(ViewHostMsg_GetDocumentTag, + int /* the tag */) + + + // This message tells the spellchecker that a document, identified by an int + // tag, has been closed and all of the ignored words for that document can be + // forgotten. + IPC_MESSAGE_ROUTED1(ViewHostMsg_DocumentWithTagClosed, + int /* the tag */) + + // Tells the browser to display or not display the SpellingPanel + IPC_MESSAGE_ROUTED1(ViewHostMsg_ShowSpellingPanel, + bool /* if true, then show it, otherwise hide it*/) + + // Tells the browser to update the spelling panel with the given word. + IPC_MESSAGE_ROUTED1(ViewHostMsg_UpdateSpellingPanelWithMisspelledWord, + string16 /* the word to update the panel with */) + + // Tells the browser that content in the current page was blocked due to the + // user's content settings. + IPC_MESSAGE_ROUTED1(ViewHostMsg_ContentBlocked, + ContentSettingsType /* type of blocked content */) + + // Tells the browser that a specific Appcache manifest in the current page + // was accessed. + IPC_MESSAGE_ROUTED2(ViewHostMsg_AppCacheAccessed, + GURL /* manifest url */, + bool /* blocked by policy */) + + // Tells the browser that a specific Web database in the current page was + // accessed. + IPC_MESSAGE_ROUTED5(ViewHostMsg_WebDatabaseAccessed, + GURL /* origin url */, + string16 /* database name */, + string16 /* database display name */, + unsigned long /* estimated size */, + bool /* blocked by policy */) + + // Initiates a download based on user actions like 'ALT+click'. + IPC_MESSAGE_ROUTED2(ViewHostMsg_DownloadUrl, + GURL /* url */, + GURL /* referrer */) + + // Used to go to the session history entry at the given offset (ie, -1 will + // return the "back" item). + IPC_MESSAGE_ROUTED1(ViewHostMsg_GoToEntryAtOffset, + int /* offset (from current) of history item to get */) + + IPC_SYNC_MESSAGE_ROUTED4_2(ViewHostMsg_RunJavaScriptMessage, + std::wstring /* in - alert message */, + std::wstring /* in - default prompt */, + GURL /* in - originating page URL */, + int /* in - dialog flags */, + bool /* out - success */, + std::wstring /* out - prompt field */) + + // Provides the contents for the given page that was loaded recently. + IPC_MESSAGE_ROUTED5(ViewHostMsg_PageContents, + GURL /* URL of the page */, + int32 /* page id */, + string16 /* page contents */, + std::string /* page ISO639_1 language code */, + bool /* whether the page can be translated */) + + // Used to get the extension message bundle. + IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_GetExtensionMessageBundle, + std::string /* extension id */, + SubstitutionMap /* message bundle */) + + // Specifies the URL as the first parameter (a wstring) and thumbnail as + // binary data as the second parameter. + IPC_MESSAGE_ROUTED3(ViewHostMsg_Thumbnail, + GURL /* url */, + ThumbnailScore /* score */, + SkBitmap /* bitmap */) + + // Send a snapshot of the tab contents to the render host. + IPC_MESSAGE_ROUTED1(ViewHostMsg_Snapshot, + SkBitmap /* bitmap */) + + // Notification that the url for the favicon of a site has been determined. + IPC_MESSAGE_ROUTED2(ViewHostMsg_UpdateFavIconURL, + int32 /* page_id */, + GURL /* url of the favicon */) + + // Used to tell the parent that the user right clicked on an area of the + // content area, and a context menu should be shown for it. The params + // object contains information about the node(s) that were selected when the + // user right clicked. + IPC_MESSAGE_ROUTED1(ViewHostMsg_ContextMenu, ContextMenuParams) + + // Requests that the given URL be opened in the specified manner. + IPC_MESSAGE_ROUTED3(ViewHostMsg_OpenURL, + GURL /* url */, + GURL /* referrer */, + WindowOpenDisposition /* disposition */) + + // Notifies that the preferred size of the content changed. + IPC_MESSAGE_ROUTED1(ViewHostMsg_DidContentsPreferredSizeChange, + gfx::Size /* pref_size */) + + // Following message is used to communicate the values received by the + // callback binding the JS to Cpp. + // An instance of browser that has an automation host listening to it can + // have a javascript send a native value (string, number, boolean) to the + // listener in Cpp. (DomAutomationController) + IPC_MESSAGE_ROUTED2(ViewHostMsg_DomOperationResponse, + std::string /* json_string */, + int /* automation_id */) + + // A message from HTML-based UI. When (trusted) Javascript calls + // send(message, args), this message is sent to the browser. + IPC_MESSAGE_ROUTED3(ViewHostMsg_DOMUISend, + GURL /* source_url */, + std::string /* message */, + std::string /* args (as a JSON string) */) + + // A message for an external host. + IPC_MESSAGE_ROUTED3(ViewHostMsg_ForwardMessageToExternalHost, + std::string /* message */, + std::string /* origin */, + std::string /* target */) + + // A renderer sends this to the browser process when it wants to + // create a plugin. The browser will create the plugin process if + // necessary, and will return a handle to the channel on success. + // On error an empty string is returned. + IPC_SYNC_MESSAGE_CONTROL3_2(ViewHostMsg_OpenChannelToPlugin, + GURL /* url */, + std::string /* mime_type */, + std::wstring /* locale */, + IPC::ChannelHandle /* handle to channel */, + WebPluginInfo /* info */) + + // A renderer sends this to the browser process when it wants to + // create connect to the GPU. The browser will create the GPU process if + // necessary, and will return a handle to the channel via + // a GpuChannelEstablished message. + IPC_MESSAGE_CONTROL0(ViewHostMsg_EstablishGpuChannel) + + // A renderer sends this to the browser process to provide a synchronization + // point for GPU operations, in particular to make sure the GPU channel has + // been established. + IPC_SYNC_MESSAGE_CONTROL0_0(ViewHostMsg_SynchronizeGpu) + + // A renderer sends this to the browser process when it wants to start + // a new instance of the Native Client process. The browser will launch + // the process and return a handle to an IMC channel. + IPC_SYNC_MESSAGE_CONTROL2_3(ViewHostMsg_LaunchNaCl, + std::wstring /* url for the NaCl module */, + int /* channel number */, + nacl::FileDescriptor /* imc channel handle */, + base::ProcessHandle /* NaCl process handle */, + base::ProcessId /* NaCl process id */) + +#if defined(USE_X11) + // A renderer sends this when it needs a browser-side widget for + // hosting a windowed plugin. id is the XID of the plugin window, for which + // the container is created. + IPC_SYNC_MESSAGE_ROUTED1_0(ViewHostMsg_CreatePluginContainer, + gfx::PluginWindowHandle /* id */) + + // Destroy a plugin container previously created using CreatePluginContainer. + // id is the XID of the plugin window corresponding to the container that is + // to be destroyed. + IPC_SYNC_MESSAGE_ROUTED1_0(ViewHostMsg_DestroyPluginContainer, + gfx::PluginWindowHandle /* id */) +#endif + + // Clipboard IPC messages + + // This message is used when the object list does not contain a bitmap. + IPC_MESSAGE_CONTROL1(ViewHostMsg_ClipboardWriteObjectsAsync, + Clipboard::ObjectMap /* objects */) + // This message is used when the object list contains a bitmap. + // It is synchronized so that the renderer knows when it is safe to + // free the shared memory used to transfer the bitmap. + IPC_SYNC_MESSAGE_CONTROL2_0(ViewHostMsg_ClipboardWriteObjectsSync, + Clipboard::ObjectMap /* objects */, + base::SharedMemoryHandle /* bitmap handle */) + IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_ClipboardIsFormatAvailable, + std::string /* format */, + Clipboard::Buffer /* buffer */, + bool /* result */) + IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_ClipboardReadText, + Clipboard::Buffer /* buffer */, + string16 /* result */) + IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_ClipboardReadAsciiText, + Clipboard::Buffer /* buffer */, + std::string /* result */) + IPC_SYNC_MESSAGE_CONTROL1_2(ViewHostMsg_ClipboardReadHTML, + Clipboard::Buffer /* buffer */, + string16 /* markup */, + GURL /* url */) + + IPC_SYNC_MESSAGE_CONTROL1_3(ViewHostMsg_ClipboardReadAvailableTypes, + Clipboard::Buffer /* buffer */, + bool /* result */, + std::vector<string16> /* types */, + bool /* contains filenames */) + IPC_SYNC_MESSAGE_CONTROL2_3(ViewHostMsg_ClipboardReadData, + Clipboard::Buffer /* buffer */, + string16 /* type */, + bool /* succeeded */, + string16 /* data */, + string16 /* metadata */) + IPC_SYNC_MESSAGE_CONTROL1_2(ViewHostMsg_ClipboardReadFilenames, + Clipboard::Buffer /* buffer */, + bool /* result */, + std::vector<string16> /* filenames */) + +#if defined(OS_MACOSX) + IPC_MESSAGE_CONTROL1(ViewHostMsg_ClipboardFindPboardWriteStringAsync, + string16 /* text */) + + // Request that the browser load a font into shared memory for us. + IPC_SYNC_MESSAGE_CONTROL1_2(ViewHostMsg_LoadFont, + FontDescriptor /* font to load */, + uint32 /* buffer size */, + base::SharedMemoryHandle /* font data */) +#endif + +#if defined(OS_WIN) + // Request that the given font be loaded by the browser so it's cached by the + // OS. Please see ChildProcessHost::PreCacheFont for details. + IPC_SYNC_MESSAGE_CONTROL1_0(ViewHostMsg_PreCacheFont, + LOGFONT /* font data */) +#endif // defined(OS_WIN) + + // Returns WebScreenInfo corresponding to the view. + // TODO(shess): Provide a mapping from reply_msg->routing_id() to + // HWND so that we can eliminate the NativeViewId parameter. + IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_GetScreenInfo, + gfx::NativeViewId /* view */, + WebKit::WebScreenInfo /* results */) + + // Send the tooltip text for the current mouse position to the browser. + IPC_MESSAGE_ROUTED2(ViewHostMsg_SetTooltipText, + std::wstring /* tooltip text string */, + WebKit::WebTextDirection /* text direction hint */) + + // Notification that the text selection has changed. + IPC_MESSAGE_ROUTED1(ViewHostMsg_SelectionChanged, + std::string /* currently selected text */) + + // Asks the browser to display the file chooser. The result is returned in a + // ViewHost_RunFileChooserResponse message. + IPC_MESSAGE_ROUTED1(ViewHostMsg_RunFileChooser, + ViewHostMsg_RunFileChooser_Params) + + // Notification that forms have been seen that are candidates for + // filling/submitting by the AutoFillManager. + IPC_MESSAGE_ROUTED1(ViewHostMsg_FormsSeen, + std::vector<webkit_glue::FormData> /* forms */) + + // Notification that password forms have been seen that are candidates for + // filling/submitting by the password manager. + IPC_MESSAGE_ROUTED1(ViewHostMsg_PasswordFormsFound, + std::vector<webkit_glue::PasswordForm> /* forms */) + + // Notification that initial layout has occurred and the following password + // forms are visible on the page (e.g. not set to display:none.) + IPC_MESSAGE_ROUTED1(ViewHostMsg_PasswordFormsVisible, + std::vector<webkit_glue::PasswordForm> /* forms */) + + // Notification that a form has been submitted. The user hit the button. + IPC_MESSAGE_ROUTED1(ViewHostMsg_FormSubmitted, + webkit_glue::FormData /* form */) + + // Used to tell the parent the user started dragging in the content area. The + // WebDropData struct contains contextual information about the pieces of the + // page the user dragged. The parent uses this notification to initiate a + // drag session at the OS level. + IPC_MESSAGE_ROUTED4(ViewHostMsg_StartDragging, + WebDropData /* drop_data */, + WebKit::WebDragOperationsMask /* ops_allowed */, + SkBitmap /* image */, + gfx::Point /* image_offset */) + + // The page wants to update the mouse cursor during a drag & drop operation. + // |is_drop_target| is true if the mouse is over a valid drop target. + IPC_MESSAGE_ROUTED1(ViewHostMsg_UpdateDragCursor, + WebKit::WebDragOperation /* drag_operation */) + + // Tells the browser to move the focus to the next (previous if reverse is + // true) focusable element. + IPC_MESSAGE_ROUTED1(ViewHostMsg_TakeFocus, bool /* reverse */) + + // Notification that the page has an OpenSearch description document + // associated with it. + IPC_MESSAGE_ROUTED3(ViewHostMsg_PageHasOSDD, + int32 /* page_id */, + GURL /* url of OS description document */, + bool /* autodetected */) + + // Find out if the given url's security origin is installed as a search + // provider. + IPC_SYNC_MESSAGE_ROUTED1_1( + ViewHostMsg_GetSearchProviderInstallState, + GURL, + ViewHostMsg_GetSearchProviderInstallState_Params /* install */) + + // Required for updating text input state. + IPC_MESSAGE_ROUTED2(ViewHostMsg_ImeUpdateTextInputState, + WebKit::WebTextInputType, /* text_input_type */ + gfx::Rect /* caret_rect */) + + // Required for cancelling an ongoing input method composition. + IPC_MESSAGE_ROUTED0(ViewHostMsg_ImeCancelComposition) + + // Tells the browser that the renderer is done calculating the number of + // rendered pages according to the specified settings. + IPC_MESSAGE_ROUTED2(ViewHostMsg_DidGetPrintedPagesCount, + int /* rendered document cookie */, + int /* number of rendered pages */) + + // Sends back to the browser the rendered "printed page" that was requested by + // a ViewMsg_PrintPage message or from scripted printing. The memory handle in + // this message is already valid in the browser process. + IPC_MESSAGE_ROUTED1(ViewHostMsg_DidPrintPage, + ViewHostMsg_DidPrintPage_Params /* page content */) + + // The renderer wants to know the default print settings. + IPC_SYNC_MESSAGE_ROUTED0_1(ViewHostMsg_GetDefaultPrintSettings, + ViewMsg_Print_Params /* default_settings */) + +#if defined(OS_WIN) || defined(OS_MACOSX) + // It's the renderer that controls the printing process when it is generated + // by javascript. This step is about showing UI to the user to select the + // final print settings. The output parameter is the same as + // ViewMsg_PrintPages which is executed implicitly. + IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_ScriptedPrint, + ViewHostMsg_ScriptedPrint_Params, + ViewMsg_PrintPages_Params + /* settings chosen by the user*/) +#endif // defined(OS_WIN) || defined(OS_MACOSX) + + // WebKit and JavaScript error messages to log to the console + // or debugger UI. + IPC_MESSAGE_ROUTED3(ViewHostMsg_AddMessageToConsole, + std::wstring, /* msg */ + int32, /* line number */ + std::wstring /* source id */) + + // Stores new inspector setting in the profile. + IPC_MESSAGE_ROUTED2(ViewHostMsg_UpdateInspectorSetting, + std::string, /* key */ + std::string /* value */) + + // Wraps an IPC message that's destined to the DevToolsClient on + // DevToolsAgent->browser hop. + IPC_MESSAGE_ROUTED1(ViewHostMsg_ForwardToDevToolsClient, + IPC::Message /* one of DevToolsClientMsg_XXX types */) + + // Wraps an IPC message that's destined to the DevToolsAgent on + // DevToolsClient->browser hop. + IPC_MESSAGE_ROUTED1(ViewHostMsg_ForwardToDevToolsAgent, + IPC::Message /* one of DevToolsAgentMsg_XXX types */) + + // Activates (brings to the front) corresponding dev tools window. + IPC_MESSAGE_ROUTED0(ViewHostMsg_ActivateDevToolsWindow) + + // Closes dev tools window that is inspecting current render_view_host. + IPC_MESSAGE_ROUTED0(ViewHostMsg_CloseDevToolsWindow) + + // Attaches dev tools window that is inspecting current render_view_host. + IPC_MESSAGE_ROUTED0(ViewHostMsg_RequestDockDevToolsWindow) + + // Detaches dev tools window that is inspecting current render_view_host. + IPC_MESSAGE_ROUTED0(ViewHostMsg_RequestUndockDevToolsWindow) + + // Updates runtime features store in devtools manager in order to support + // cross-navigation instrumentation. + IPC_MESSAGE_ROUTED2(ViewHostMsg_DevToolsRuntimeFeatureStateChanged, + std::string /* feature */, + bool /* enabled */) + + // Send back a string to be recorded by UserMetrics. + IPC_MESSAGE_ROUTED1(ViewHostMsg_UserMetricsRecordAction, + std::string /* action */) + + // Send back histograms as vector of pickled-histogram strings. + IPC_MESSAGE_CONTROL2(ViewHostMsg_RendererHistograms, + int, /* sequence number of Renderer Histograms. */ + std::vector<std::string>) + +#if defined USE_TCMALLOC + // Send back tcmalloc stats output. + IPC_MESSAGE_CONTROL2(ViewHostMsg_RendererTcmalloc, + int /* pid */, + std::string /* tcmalloc debug output */) +#endif + + // Sends back stats about the V8 heap. + IPC_MESSAGE_CONTROL2(ViewHostMsg_V8HeapStats, + int /* size of heap (allocated from the OS) */, + int /* bytes in use */) + + // Request for a DNS prefetch of the names in the array. + // NameList is typedef'ed std::vector<std::string> + IPC_MESSAGE_CONTROL1(ViewHostMsg_DnsPrefetch, + std::vector<std::string> /* hostnames */) + + // Notifies when default plugin updates status of the missing plugin. + IPC_MESSAGE_ROUTED1(ViewHostMsg_MissingPluginStatus, + int /* status */) + + // Sent by the renderer process to indicate that a plugin instance has + // crashed. + IPC_MESSAGE_ROUTED1(ViewHostMsg_CrashedPlugin, + FilePath /* plugin_path */) + + // Displays a JavaScript out-of-memory message in the infobar. + IPC_MESSAGE_ROUTED0(ViewHostMsg_JSOutOfMemory) + + // Displays a box to confirm that the user wants to navigate away from the + // page. Replies true if yes, false otherwise, the reply string is ignored, + // but is included so that we can use OnJavaScriptMessageBoxClosed. + IPC_SYNC_MESSAGE_ROUTED2_2(ViewHostMsg_RunBeforeUnloadConfirm, + GURL, /* in - originating frame URL */ + std::wstring /* in - alert message */, + bool /* out - success */, + std::wstring /* out - This is ignored.*/) + + IPC_MESSAGE_ROUTED3(ViewHostMsg_SendCurrentPageAllSavableResourceLinks, + std::vector<GURL> /* all savable resource links */, + std::vector<GURL> /* all referrers of resource links */, + std::vector<GURL> /* all frame links */) + + IPC_MESSAGE_ROUTED3(ViewHostMsg_SendSerializedHtmlData, + GURL /* frame's url */, + std::string /* data buffer */, + int32 /* complete status */) + + IPC_SYNC_MESSAGE_ROUTED4_1(ViewHostMsg_ShowModalHTMLDialog, + GURL /* url */, + int /* width */, + int /* height */, + std::string /* json_arguments */, + std::string /* json_retval */) + + IPC_MESSAGE_ROUTED2(ViewHostMsg_DidGetApplicationInfo, + int32 /* page_id */, + webkit_glue::WebApplicationInfo) + + // Provides the result from running OnMsgShouldClose. |proceed| matches the + // return value of the the frame's shouldClose method (which includes the + // onbeforeunload handler): true if the user decided to proceed with leaving + // the page. + IPC_MESSAGE_ROUTED1(ViewHostMsg_ShouldClose_ACK, + bool /* proceed */) + + // Indicates that the current page has been closed, after a ClosePage + // message. The parameters are just echoed from the ClosePage request. + IPC_MESSAGE_ROUTED1(ViewHostMsg_ClosePage_ACK, + ViewMsg_ClosePage_Params) + + IPC_MESSAGE_ROUTED4(ViewHostMsg_DidDownloadFavIcon, + int /* Identifier of the request */, + GURL /* URL of the image */, + bool /* true if there was a network error */, + SkBitmap /* image_data */) + + // Sent to query MIME information. + IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_GetMimeTypeFromExtension, + FilePath::StringType /* extension */, + std::string /* mime_type */) + IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_GetMimeTypeFromFile, + FilePath /* file_path */, + std::string /* mime_type */) + IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_GetPreferredExtensionForMimeType, + std::string /* mime_type */, + FilePath::StringType /* extension */) + + // Get the CPBrowsingContext associated with the renderer sending this + // message. + IPC_SYNC_MESSAGE_CONTROL0_1(ViewHostMsg_GetCPBrowsingContext, + uint32 /* context */) + + // Sent when the renderer process is done processing a DataReceived + // message. + IPC_MESSAGE_ROUTED1(ViewHostMsg_DataReceived_ACK, + int /* request_id */) + + // Sent when a provisional load on the main frame redirects. + IPC_MESSAGE_ROUTED3(ViewHostMsg_DidRedirectProvisionalLoad, + int /* page_id */, + GURL /* last url */, + GURL /* url redirected to */) + + // Sent by the renderer process to acknowledge receipt of a + // DownloadProgress message. + IPC_MESSAGE_ROUTED1(ViewHostMsg_DownloadProgress_ACK, + int /* request_id */) + + // Sent by the renderer process to acknowledge receipt of a + // UploadProgress message. + IPC_MESSAGE_ROUTED1(ViewHostMsg_UploadProgress_ACK, + int /* request_id */) + + // Sent when the renderer changes the zoom level for a particular url, so the + // browser can update its records. + IPC_MESSAGE_CONTROL2(ViewHostMsg_DidZoomURL, + GURL /* url */, + int /* zoom_level */) + +#if defined(OS_WIN) + // Duplicates a shared memory handle from the renderer to the browser. Then + // the renderer can flush the handle. + IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_DuplicateSection, + base::SharedMemoryHandle /* renderer handle */, + base::SharedMemoryHandle /* browser handle */) +#endif + +#if defined(USE_X11) + // Asks the browser to create a temporary file for the renderer to fill + // in resulting NativeMetafile in printing. + IPC_SYNC_MESSAGE_CONTROL0_2(ViewHostMsg_AllocateTempFileForPrinting, + base::FileDescriptor /* temp file fd */, + int /* fd in browser*/) + IPC_MESSAGE_CONTROL1(ViewHostMsg_TempFileForPrintingWritten, + int /* fd in browser */) +#endif + +#if defined(OS_MACOSX) + // Asks the browser to create a block of shared memory for the renderer to + // pass NativeMetafile data to the browser. + IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_AllocatePDFTransport, + uint32 /* buffer size */, + base::SharedMemoryHandle /* browser handle */) +#endif + +#if defined(OS_POSIX) + // Asks the browser to create a block of shared memory for the renderer to + // fill in and pass back to the browser. + IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_AllocateSharedMemoryBuffer, + uint32 /* buffer size */, + base::SharedMemoryHandle /* browser handle */) +#endif + + // Provide the browser process with information about the WebCore resource + // cache. + IPC_MESSAGE_CONTROL1(ViewHostMsg_ResourceTypeStats, + WebKit::WebCache::ResourceTypeStats) + + // Notify the browser that this render process can or can't be suddenly + // terminated. + IPC_MESSAGE_CONTROL1(ViewHostMsg_SuddenTerminationChanged, + bool /* enabled */) + + // Returns the window location of the window this widget is embeded. + // TODO(shess): Provide a mapping from reply_msg->routing_id() to + // HWND so that we can eliminate the NativeViewId parameter. + IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_GetRootWindowRect, + gfx::NativeViewId /* window */, + gfx::Rect /* Out: Window location */) + + // Informs the browser of a new appcache host. + IPC_MESSAGE_CONTROL1(AppCacheMsg_RegisterHost, + int /* host_id */) + + // Informs the browser of an appcache host being destroyed. + IPC_MESSAGE_CONTROL1(AppCacheMsg_UnregisterHost, + int /* host_id */) + + // Initiates the cache selection algorithm for the given host. + // This is sent prior to any subresource loads. An AppCacheMsg_CacheSelected + // message will be sent in response. + // 'host_id' indentifies a specific document or worker + // 'document_url' the url of the main resource + // 'appcache_document_was_loaded_from' the id of the appcache the main + // resource was loaded from or kNoCacheId + // 'opt_manifest_url' the manifest url specified in the <html> tag if any + IPC_MESSAGE_CONTROL4(AppCacheMsg_SelectCache, + int /* host_id */, + GURL /* document_url */, + int64 /* appcache_document_was_loaded_from */, + GURL /* opt_manifest_url */) + + // Initiates worker specific cache selection algorithm for the given host. + IPC_MESSAGE_CONTROL3(AppCacheMsg_SelectCacheForWorker, + int /* host_id */, + int /* parent_process_id */, + int /* parent_host_id */) + IPC_MESSAGE_CONTROL2(AppCacheMsg_SelectCacheForSharedWorker, + int /* host_id */, + int64 /* appcache_id */) + + // Informs the browser of a 'foreign' entry in an appcache. + IPC_MESSAGE_CONTROL3(AppCacheMsg_MarkAsForeignEntry, + int /* host_id */, + GURL /* document_url */, + int64 /* appcache_document_was_loaded_from */) + + // Returns the status of the appcache associated with host_id. + IPC_SYNC_MESSAGE_CONTROL1_1(AppCacheMsg_GetStatus, + int /* host_id */, + appcache::Status) + + // Initiates an update of the appcache associated with host_id. + IPC_SYNC_MESSAGE_CONTROL1_1(AppCacheMsg_StartUpdate, + int /* host_id */, + bool /* success */) + + // Swaps a new pending appcache, if there is one, into use for host_id. + IPC_SYNC_MESSAGE_CONTROL1_1(AppCacheMsg_SwapCache, + int /* host_id */, + bool /* success */) + + // Returns the resizer box location in the window this widget is embedded. + // Important for Mac OS X, but not Win or Linux. + IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_GetRootWindowResizerRect, + gfx::NativeViewId /* window */, + gfx::Rect /* Out: Window location */) + + // Queries the browser for AutoFill suggestions for a form input field. + IPC_MESSAGE_ROUTED3(ViewHostMsg_QueryFormFieldAutoFill, + int /* id of this message */, + bool /* form_autofilled */, + webkit_glue::FormField /* the form field */) + + // Instructs the browser to fill in the values for a form using AutoFill + // profile data. + IPC_MESSAGE_ROUTED5(ViewHostMsg_FillAutoFillFormData, + int /* id of this message */, + webkit_glue::FormData /* the form */, + string16 /* profile name */, + string16 /* profile label */, + int /* profile unique ID */) + + // Instructs the browser to remove the specified Autocomplete entry from the + // database. + IPC_MESSAGE_ROUTED2(ViewHostMsg_RemoveAutocompleteEntry, + string16 /* field name */, + string16 /* value */) + + // Instructs the browser to show the AutoFill dialog. + IPC_MESSAGE_ROUTED0(ViewHostMsg_ShowAutoFillDialog) + + // Get the list of proxies to use for |url|, as a semicolon delimited list + // of "<TYPE> <HOST>:<PORT>" | "DIRECT". See also + // PluginProcessHostMsg_ResolveProxy which does the same thing. + IPC_SYNC_MESSAGE_CONTROL1_2(ViewHostMsg_ResolveProxy, + GURL /* url */, + int /* network error */, + std::string /* proxy list */) + + // Request that got sent to browser for creating an audio output stream + IPC_MESSAGE_ROUTED3(ViewHostMsg_CreateAudioStream, + int /* stream_id */, + ViewHostMsg_Audio_CreateStream_Params, + bool /* low-latency */) + + // Tell the browser the audio buffer prepared for stream + // (render_view_id, stream_id) is filled and is ready to be consumed. + IPC_MESSAGE_ROUTED2(ViewHostMsg_NotifyAudioPacketReady, + int /* stream_id */, + uint32 /* packet size */) + + // Start buffering and play the audio stream specified by + // (render_view_id, stream_id). + IPC_MESSAGE_ROUTED1(ViewHostMsg_PlayAudioStream, + int /* stream_id */) + + // Pause the audio stream specified by (render_view_id, stream_id). + IPC_MESSAGE_ROUTED1(ViewHostMsg_PauseAudioStream, + int /* stream_id */) + + // Discard all buffered audio data for the specified audio stream. + IPC_MESSAGE_ROUTED1(ViewHostMsg_FlushAudioStream, + int /* stream_id */) + + // Close an audio stream specified by (render_view_id, stream_id). + IPC_MESSAGE_ROUTED1(ViewHostMsg_CloseAudioStream, + int /* stream_id */) + + // Get audio volume of the stream specified by (render_view_id, stream_id). + IPC_MESSAGE_ROUTED1(ViewHostMsg_GetAudioVolume, + int /* stream_id */) + + // Set audio volume of the stream specified by (render_view_id, stream_id). + // TODO(hclam): change this to vector if we have channel numbers other than 2. + IPC_MESSAGE_ROUTED2(ViewHostMsg_SetAudioVolume, + int /* stream_id */, + double /* volume */) + + // A renderer sends this message when an extension process starts an API + // request. The browser will always respond with a ViewMsg_ExtensionResponse. + IPC_MESSAGE_ROUTED5(ViewHostMsg_ExtensionRequest, + std::string /* name */, + ListValue /* arguments */, + GURL /* source_url */, + int /* callback id */, + bool /* has_callback */) + + // Notify the browser that this renderer added a listener to an event. + IPC_MESSAGE_CONTROL1(ViewHostMsg_ExtensionAddListener, + std::string /* name */) + + // Notify the browser that this renderer removed a listener from an event. + IPC_MESSAGE_CONTROL1(ViewHostMsg_ExtensionRemoveListener, + std::string /* name */) + +#if defined(OS_MACOSX) + // On OSX, we cannot allocated shared memory from within the sandbox, so + // this call exists for the renderer to ask the browser to allocate memory + // on its behalf. We return a file descriptor to the POSIX shared memory. + // If the |cache_in_browser| flag is |true|, then a copy of the shmem is kept + // by the browser, and it is the caller's repsonsibility to send a + // ViewHostMsg_FreeTransportDIB message in order to release the cached shmem. + // In all cases, the caller is responsible for deleting the resulting + // TransportDIB. + IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_AllocTransportDIB, + size_t, /* bytes requested */ + bool, /* cache in the browser */ + TransportDIB::Handle /* DIB */) + + // Since the browser keeps handles to the allocated transport DIBs, this + // message is sent to tell the browser that it may release them when the + // renderer is finished with them. + IPC_MESSAGE_CONTROL1(ViewHostMsg_FreeTransportDIB, + TransportDIB::Id /* DIB id */) + + //--------------------------------------------------------------------------- + // Messages related to the GPU plugin on Mac OS X 10.6 and later + + // This is sent from the renderer to the browser to allocate a fake + // PluginWindowHandle on the browser side which is used to identify + // the plugin to the browser later when backing store is allocated + // or reallocated. |opaque| indicates whether the plugin's output is + // considered to be opaque, as opposed to translucent. + IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_AllocateFakePluginWindowHandle, + bool /* opaque */, + gfx::PluginWindowHandle /* id */) + + // Destroys a fake window handle previously allocated using + // AllocateFakePluginWindowHandle. + IPC_MESSAGE_ROUTED1(ViewHostMsg_DestroyFakePluginWindowHandle, + gfx::PluginWindowHandle /* id */) + + // This message, used on Mac OS X 10.5 and earlier (no IOSurface support), + // is sent from the renderer to the browser on behalf of the plug-in + // to indicate that a new backing store was allocated for that plug-in + // instance. + IPC_MESSAGE_ROUTED4(ViewHostMsg_AcceleratedSurfaceSetTransportDIB, + gfx::PluginWindowHandle /* window */, + int32 /* width */, + int32 /* height */, + TransportDIB::Handle /* handle for the DIB */) + + // This message, used on Mac OS X 10.6 and later (where IOSurface is + // supported), is sent from the renderer to the browser on behalf of the + // plug-in to indicate that a new backing store was allocated for that + // plug-in instance. + // + // NOTE: the original intent was to pass a mach port as the IOSurface + // identifier but it looks like that will be a lot of work. For now we pass an + // ID from IOSurfaceGetID. + IPC_MESSAGE_ROUTED4(ViewHostMsg_AcceleratedSurfaceSetIOSurface, + gfx::PluginWindowHandle /* window */, + int32 /* width */, + int32 /* height */, + uint64 /* identifier for IOSurface */) + + // This message notifies the browser process that the plug-in + // swapped the buffers associated with the given "window", which + // should cause the browser to redraw the various plug-ins' + // contents. + IPC_MESSAGE_ROUTED1(ViewHostMsg_AcceleratedSurfaceBuffersSwapped, + gfx::PluginWindowHandle /* window */) +#endif + + // A renderer sends this to the browser process when it wants to create a + // worker. The browser will create the worker process if necessary, and + // will return the route id on success. On error returns MSG_ROUTING_NONE. + IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_CreateWorker, + ViewHostMsg_CreateWorker_Params, + int /* route_id */) + + // This message is sent to the browser to see if an instance of this shared + // worker already exists. If so, it returns exists == true. If a + // non-empty name is passed, also validates that the url matches the url of + // the existing worker. If a matching worker is found, the passed-in + // document_id is associated with that worker, to ensure that the worker + // stays alive until the document is detached. + // The route_id returned can be used to forward messages to the worker via + // ForwardToWorker if it exists, otherwise it should be passed in to any + // future call to CreateWorker to avoid creating duplicate workers. + IPC_SYNC_MESSAGE_CONTROL1_3(ViewHostMsg_LookupSharedWorker, + ViewHostMsg_CreateWorker_Params, + bool /* exists */, + int /* route_id */, + bool /* url_mismatch */) + + // A renderer sends this to the browser process when a document has been + // detached. The browser will use this to constrain the lifecycle of worker + // processes (SharedWorkers are shut down when their last associated document + // is detached). + IPC_MESSAGE_CONTROL1(ViewHostMsg_DocumentDetached, + unsigned long long /* document_id */) + + // A message sent to the browser on behalf of a renderer which wants to show + // a desktop notification. + IPC_MESSAGE_ROUTED1(ViewHostMsg_ShowDesktopNotification, + ViewHostMsg_ShowNotification_Params) + IPC_MESSAGE_ROUTED1(ViewHostMsg_CancelDesktopNotification, + int /* notification_id */ ) + IPC_MESSAGE_ROUTED2(ViewHostMsg_RequestNotificationPermission, + GURL /* origin */, + int /* callback_context */) + IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_CheckNotificationPermission, + GURL /* source page */, + int /* permission_result */) + + // Sent if the worker object has sent a ViewHostMsg_CreateDedicatedWorker + // message and not received a ViewMsg_WorkerCreated reply, but in the + // mean time it's destroyed. This tells the browser to not create the queued + // worker. + IPC_MESSAGE_CONTROL1(ViewHostMsg_CancelCreateDedicatedWorker, + int /* route_id */) + + // Wraps an IPC message that's destined to the worker on the renderer->browser + // hop. + IPC_MESSAGE_CONTROL1(ViewHostMsg_ForwardToWorker, + IPC::Message /* message */) + + // Open a channel to all listening contexts owned by the extension with + // the given ID. This always returns a valid port ID which can be used for + // sending messages. If an error occurred, the opener will be notified + // asynchronously. + IPC_SYNC_MESSAGE_CONTROL4_1(ViewHostMsg_OpenChannelToExtension, + int /* routing_id */, + std::string /* source_extension_id */, + std::string /* target_extension_id */, + std::string /* channel_name */, + int /* port_id */) + + // Get a port handle to the given tab. The handle can be used for sending + // messages to the extension. + IPC_SYNC_MESSAGE_CONTROL4_1(ViewHostMsg_OpenChannelToTab, + int /* routing_id */, + int /* tab_id */, + std::string /* extension_id */, + std::string /* channel_name */, + int /* port_id */) + + // Send a message to an extension process. The handle is the value returned + // by ViewHostMsg_OpenChannelTo*. + IPC_MESSAGE_ROUTED2(ViewHostMsg_ExtensionPostMessage, + int /* port_id */, + std::string /* message */) + + // Send a message to an extension process. The handle is the value returned + // by ViewHostMsg_OpenChannelTo*. + IPC_MESSAGE_CONTROL1(ViewHostMsg_ExtensionCloseChannel, + int /* port_id */) + + // Sent as a result of a focus change in the renderer (if accessibility is + // enabled), to notify the browser side that its accessibility focus needs to + // change as well. Takes the id of the accessibility object that now has + // focus. + IPC_MESSAGE_ROUTED1(ViewHostMsg_AccessibilityFocusChange, + int /* accessibility object id */) + + // Send as a result of a state change in the renderer (if accessibility is + // enabled), to notify the browser side. Takes the id of the accessibility + // object that had a state change + IPC_MESSAGE_ROUTED1(ViewHostMsg_AccessibilityObjectStateChange, + int /* accessibility object id */) + + // Message sent from the renderer to the browser to request that the browser + // close all sockets. Used for debugging/testing. + IPC_MESSAGE_CONTROL0(ViewHostMsg_CloseCurrentConnections) + + // Message sent from the renderer to the browser to request that the browser + // enable or disable the cache. Used for debugging/testing. + IPC_MESSAGE_CONTROL1(ViewHostMsg_SetCacheMode, + bool /* enabled */) + + // Message sent from the renderer to the browser to request that the browser + // clear the cache. Used for debugging/testing. + IPC_SYNC_MESSAGE_CONTROL0_1(ViewHostMsg_ClearCache, + int /* result */) + + // Message sent from the renderer to the browser to request that the browser + // cache |data| associated with |url|. + IPC_MESSAGE_CONTROL3(ViewHostMsg_DidGenerateCacheableMetadata, + GURL /* url */, + double /* expected_response_time */, + std::vector<char> /* data */) + + // Get the storage area id for a particular origin within a namespace. + IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_DOMStorageStorageAreaId, + int64 /* namespace_id */, + string16 /* origin */, + int64 /* storage_area_id */) + + // Get the length of a storage area. + IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_DOMStorageLength, + int64 /* storage_area_id */, + unsigned /* length */) + + // Get a the ith key within a storage area. + IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_DOMStorageKey, + int64 /* storage_area_id */, + unsigned /* index */, + NullableString16 /* key */) + + // Get a value based on a key from a storage area. + IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_DOMStorageGetItem, + int64 /* storage_area_id */, + string16 /* key */, + NullableString16 /* value */) + + // Set a value that's associated with a key in a storage area. + IPC_SYNC_MESSAGE_ROUTED4_2(ViewHostMsg_DOMStorageSetItem, + int64 /* storage_area_id */, + string16 /* key */, + string16 /* value */, + GURL /* url */, + WebKit::WebStorageArea::Result /* result */, + NullableString16 /* old_value */) + + // Remove the value associated with a key in a storage area. + IPC_SYNC_MESSAGE_CONTROL3_1(ViewHostMsg_DOMStorageRemoveItem, + int64 /* storage_area_id */, + string16 /* key */, + GURL /* url */, + NullableString16 /* old_value */) + + // Clear the storage area. + IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_DOMStorageClear, + int64 /* storage_area_id */, + GURL /* url */, + bool /* something_cleared */) + + // WebIndexedDatabase::open() message. + IPC_MESSAGE_CONTROL1(ViewHostMsg_IndexedDatabaseOpen, + ViewHostMsg_IndexedDatabaseOpen_Params) + + // WebIDBDatabase::name() message. + IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_IDBDatabaseName, + int32, /* idb_database_id */ + string16 /* name */) + + // WebIDBDatabase::description() message. + IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_IDBDatabaseDescription, + int32, /* idb_database_id */ + string16 /* description */) + + // WebIDBDatabase::version() message. + IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_IDBDatabaseVersion, + int32, /* idb_database_id */ + string16 /* vesion */) + + // WebIDBDatabase::objectStores() message. + IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_IDBDatabaseObjectStores, + int32, /* idb_database_id */ + std::vector<string16> /* objectStores */) + + // WebIDBDatabase::createObjectStore() message. + IPC_MESSAGE_CONTROL1(ViewHostMsg_IDBDatabaseCreateObjectStore, + ViewHostMsg_IDBDatabaseCreateObjectStore_Params) + + // WebIDBDatabase::objectStore() message. + IPC_SYNC_MESSAGE_CONTROL3_2(ViewHostMsg_IDBDatabaseObjectStore, + int32, /* idb_database_id */ + string16, /* name */ + int32, /* mode */ + bool, /* success */ + int32 /* idb_object_store_id */) + + // WebIDBDatabase::removeObjectStore() message. + IPC_MESSAGE_CONTROL3(ViewHostMsg_IDBDatabaseRemoveObjectStore, + int32, /* idb_database_id */ + int32, /* response_id */ + string16 /* name */) + + // WebIDBDatabase::~WebIDBDatabase() message. + IPC_MESSAGE_CONTROL1(ViewHostMsg_IDBDatabaseDestroyed, + int32 /* idb_database_id */) + + // WebIDBIndex::name() message. + IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_IDBIndexName, + int32, /* idb_index_id */ + string16 /* name */) + + // WebIDBIndex::keyPath() message. + IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_IDBIndexKeyPath, + int32, /* idb_index_id */ + NullableString16 /* key_path */) + + // WebIDBIndex::unique() message. + IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_IDBIndexUnique, + int32, /* idb_unique_id */ + bool /* unique */) + + // WebIDBIndex::~WebIDBIndex() message. + IPC_MESSAGE_CONTROL1(ViewHostMsg_IDBIndexDestroyed, + int32 /* idb_index_id */) + + // WebIDBObjectStore::name() message. + IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_IDBObjectStoreName, + int32, /* idb_object_store_id */ + string16 /* name */) + + // WebIDBObjectStore::keyPath() message. + IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_IDBObjectStoreKeyPath, + int32, /* idb_object_store_id */ + NullableString16 /* keyPath */) + + // WebIDBObjectStore::indexNames() message. + IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_IDBObjectStoreIndexNames, + int32, /* idb_object_store_id */ + std::vector<string16> /* index_names */) + + // WebIDBObjectStore::get() message. + IPC_MESSAGE_CONTROL3(ViewHostMsg_IDBObjectStoreGet, + int32, /* idb_object_store_id */ + int32, /* response_id */ + IndexedDBKey /* key */) + + // WebIDBObjectStore::put() message. + IPC_MESSAGE_CONTROL5(ViewHostMsg_IDBObjectStorePut, + int32, /* idb_object_store_id */ + int32, /* response_id */ + SerializedScriptValue, /* serialized_value */ + IndexedDBKey, /* key */ + bool /* add_only */) + + // WebIDBObjectStore::remove() message. + IPC_MESSAGE_CONTROL3(ViewHostMsg_IDBObjectStoreRemove, + int32, /* idb_object_store_id */ + int32, /* response_id */ + IndexedDBKey /* key */) + + // WebIDBObjectStore::createIndex() message. + IPC_MESSAGE_CONTROL1(ViewHostMsg_IDBObjectStoreCreateIndex, + ViewHostMsg_IDBObjectStoreCreateIndex_Params) + + // WebIDBObjectStore::index() message. + IPC_SYNC_MESSAGE_CONTROL2_2(ViewHostMsg_IDBObjectStoreIndex, + int32, /* idb_object_store_id */ + string16, /* name */ + bool, /* success */ + int32 /* idb_index_id */) + + // WebIDBObjectStore::removeIndex() message. + IPC_MESSAGE_CONTROL3(ViewHostMsg_IDBObjectStoreRemoveIndex, + int32, /* idb_object_store_id */ + int32, /* response_id */ + string16 /* name */) + + // WebIDBObjectStore::~WebIDBObjectStore() message. + IPC_MESSAGE_CONTROL1(ViewHostMsg_IDBObjectStoreDestroyed, + int32 /* idb_object_store_id */) + + // Get file size in bytes. Set result to -1 if failed to get the file size. + IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_GetFileSize, + FilePath /* path */, + int64 /* result */) + + // Get file modification time in seconds. Set result to 0 if failed to get the + // file modification time. + IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_GetFileModificationTime, + FilePath /* path */, + base::Time /* result */) + + // Open the file. + IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_OpenFile, + FilePath /* path */, + int /* mode */, + IPC::PlatformFileForTransit /* result */) + + // Sent by the renderer process to acknowledge receipt of a + // ViewMsg_CSSInsertRequest message and css has been inserted into the frame. + IPC_MESSAGE_ROUTED0(ViewHostMsg_OnCSSInserted) + + // Sent by the renderer process to check whether access to web databases is + // granted by content settings. This may block and trigger a cookie prompt. + IPC_SYNC_MESSAGE_ROUTED4_1(ViewHostMsg_AllowDatabase, + std::string /* origin_url */, + string16 /* database name */, + string16 /* database display name */, + unsigned long /* estimated size */, + bool /* result */) + + // Asks the browser process to open a DB file with the given name. + IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_DatabaseOpenFile, + string16 /* vfs file name */, + int /* desired flags */, + IPC::PlatformFileForTransit /* file_handle */) + + // Asks the browser process to delete a DB file + IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_DatabaseDeleteFile, + string16 /* vfs file name */, + bool /* whether or not to sync the directory */, + int /* SQLite error code */) + + // Asks the browser process to return the attributes of a DB file + IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_DatabaseGetFileAttributes, + string16 /* vfs file name */, + int32 /* the attributes for the given DB file */) + + // Asks the browser process to return the size of a DB file + IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_DatabaseGetFileSize, + string16 /* vfs file name */, + int64 /* the size of the given DB file */) + + // Notifies the browser process that a new database has been opened + IPC_MESSAGE_CONTROL4(ViewHostMsg_DatabaseOpened, + string16 /* origin identifier */, + string16 /* database name */, + string16 /* database description */, + int64 /* estimated size */) + + // Notifies the browser process that a database might have been modified + IPC_MESSAGE_CONTROL2(ViewHostMsg_DatabaseModified, + string16 /* origin identifier */, + string16 /* database name */) + + // Notifies the browser process that a database is about to close + IPC_MESSAGE_CONTROL2(ViewHostMsg_DatabaseClosed, + string16 /* origin identifier */, + string16 /* database name */) + + // Notifies the browser of the language (ISO 639_1 code language, such as fr, + // en, zh...) of the current page. + IPC_MESSAGE_ROUTED1(ViewHostMsg_PageLanguageDetermined, + std::string /* the language */) + + // Notifies the browser that a page has been translated. + IPC_MESSAGE_ROUTED4(ViewHostMsg_PageTranslated, + int, /* page id */ + std::string /* the original language */, + std::string /* the translated language */, + TranslateErrors::Type /* the error type if available */) + + //--------------------------------------------------------------------------- + // Socket Stream messages: + // These are messages from the SocketStreamHandle to the browser. + + // Open new Socket Stream for the |socket_url| identified by |socket_id| + // in the renderer process. + // The browser starts connecting asynchronously. + // Once Socket Stream connection is established, the browser will send + // ViewMsg_SocketStream_Connected back. + IPC_MESSAGE_CONTROL2(ViewHostMsg_SocketStream_Connect, + GURL /* socket_url */, + int /* socket_id */) + + // Request to send data on the Socket Stream. + // SocketStreamHandle can send data at most |max_pending_send_allowed| bytes, + // which is given by ViewMsg_SocketStream_Connected at any time. + // The number of pending bytes can be tracked by size of |data| sent + // and |amount_sent| parameter of ViewMsg_SocketStream_DataSent. + // That is, the following constraints is applied: + // (accumulated total of |data|) - (accumulated total of |amount_sent|) + // <= |max_pending_send_allowed| + // If the SocketStreamHandle ever tries to exceed the + // |max_pending_send_allowed|, the connection will be closed. + IPC_MESSAGE_CONTROL2(ViewHostMsg_SocketStream_SendData, + int /* socket_id */, + std::vector<char> /* data */) + + // Request to close the Socket Stream. + // The browser will send ViewMsg_SocketStream_Closed back when the Socket + // Stream is completely closed. + IPC_MESSAGE_CONTROL1(ViewHostMsg_SocketStream_Close, + int /* socket_id */) + + //--------------------------------------------------------------------------- + // Request for cryptographic operation messages: + // These are messages from the renderer to the browser to perform a + // cryptographic operation. + + // Asks the browser process to generate a keypair for grabbing a client + // certificate from a CA (<keygen> tag), and returns the signed public + // key and challenge string. + IPC_SYNC_MESSAGE_CONTROL3_1(ViewHostMsg_Keygen, + uint32 /* key size index */, + std::string /* challenge string */, + GURL /* URL of requestor */, + std::string /* signed public key and challenge */) + + // The renderer has tried to spell check a word, but couldn't because no + // dictionary was available to load. Request that the browser find an + // appropriate dictionary and return it. + IPC_MESSAGE_CONTROL0(ViewHostMsg_SpellChecker_RequestDictionary) + + IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_SpellChecker_PlatformCheckSpelling, + string16 /* word */, + int /* document tag */, + bool /* correct */) + + IPC_SYNC_MESSAGE_CONTROL1_1( + ViewHostMsg_SpellChecker_PlatformFillSuggestionList, + string16 /* word */, + std::vector<string16> /* suggestions */) + + //--------------------------------------------------------------------------- + // Geolocation services messages + + // A GeolocationServiceBridgeImpl in the renderer process has been created. + // This is used to lazily initialize the host dispatchers and related + // Geolocation infrastructure in the browser process. + IPC_MESSAGE_CONTROL1(ViewHostMsg_Geolocation_RegisterDispatcher, + int /* render_view_id */) + + // A GeolocationServiceBridgeImpl has been destroyed. + // This is used to let the Geolocation infrastructure do its cleanup. + IPC_MESSAGE_CONTROL1(ViewHostMsg_Geolocation_UnregisterDispatcher, + int /* render_view_id */) + + // The |render_view_id| and |bridge_id| representing |host| is requesting + // permission to access geolocation position. + // This will be replied by ViewMsg_Geolocation_PermissionSet. + IPC_MESSAGE_CONTROL3(ViewHostMsg_Geolocation_RequestPermission, + int /* render_view_id */, + int /* bridge_id */, + GURL /* GURL of the frame requesting geolocation */) + + // The |render_view_id| and |bridge_id| representing |GURL| is cancelling its + // previous permission request to access geolocation position. + IPC_MESSAGE_CONTROL3(ViewHostMsg_Geolocation_CancelPermissionRequest, + int /* render_view_id */, + int /* bridge_id */, + GURL /* GURL of the frame */) + + // The |render_view_id| and |bridge_id| requests Geolocation service to start + // updating. + // This is an asynchronous call, and the browser process may eventually reply + // with the updated geoposition, or an error (access denied, location + // unavailable, etc.) + IPC_MESSAGE_CONTROL4(ViewHostMsg_Geolocation_StartUpdating, + int /* render_view_id */, + int /* bridge_id */, + GURL /* GURL of the frame requesting geolocation */, + bool /* enable_high_accuracy */) + + // The |render_view_id| and |bridge_id| requests Geolocation service to stop + // updating. + // Note that the geolocation service may continue to fetch geolocation data + // for other origins. + IPC_MESSAGE_CONTROL2(ViewHostMsg_Geolocation_StopUpdating, + int /* render_view_id */, + int /* bridge_id */) + + // The |render_view_id| and |bridge_id| requests Geolocation service to + // suspend. + // Note that the geolocation service may continue to fetch geolocation data + // for other origins. + IPC_MESSAGE_CONTROL2(ViewHostMsg_Geolocation_Suspend, + int /* render_view_id */, + int /* bridge_id */) + + // The |render_view_id| and |bridge_id| requests Geolocation service to + // resume. + IPC_MESSAGE_CONTROL2(ViewHostMsg_Geolocation_Resume, + int /* render_view_id */, + int /* bridge_id */) + + // Send the tree of accessibility data to the browser, where it's cached + // in order to respond to OS accessibility queries immediately. + IPC_MESSAGE_ROUTED1(ViewHostMsg_AccessibilityTree, + webkit_glue::WebAccessibility) + +IPC_END_MESSAGES(ViewHost) diff --git a/chrome/common/render_messages_unittest.cc b/chrome/common/render_messages_unittest.cc new file mode 100644 index 0000000..30b1446 --- /dev/null +++ b/chrome/common/render_messages_unittest.cc @@ -0,0 +1,92 @@ +// Copyright (c) 2010 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/scoped_ptr.h" +#include "base/string16.h" +#include "base/values.h" +#include "chrome/common/render_messages.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(RenderMessagesUnittest, WebAccessibility) { + // Test a simple case. + webkit_glue::WebAccessibility input; + input.id = 123; + input.name = ASCIIToUTF16("name"); + input.value = ASCIIToUTF16("value"); + string16 help = ASCIIToUTF16("help"); + input.attributes[webkit_glue::WebAccessibility::ATTR_HELP] = help; + input.role = webkit_glue::WebAccessibility::ROLE_CHECKBOX; + input.state = + (1 << webkit_glue::WebAccessibility::STATE_CHECKED) | + (1 << webkit_glue::WebAccessibility::STATE_FOCUSED); + input.location = WebKit::WebRect(11, 22, 333, 444); + + IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); + IPC::WriteParam(&msg, input); + + webkit_glue::WebAccessibility output; + void* iter = NULL; + EXPECT_TRUE(IPC::ReadParam(&msg, &iter, &output)); + EXPECT_EQ(input.id, output.id); + EXPECT_EQ(input.name, output.name); + EXPECT_EQ(input.value, output.value); + EXPECT_EQ(static_cast<size_t>(1), input.attributes.size()); + EXPECT_EQ(help, input.attributes[webkit_glue::WebAccessibility::ATTR_HELP]); + EXPECT_EQ(input.role, output.role); + EXPECT_EQ(input.state, output.state); + EXPECT_EQ(input.location, output.location); + EXPECT_EQ(input.children.size(), output.children.size()); + + // Test a corrupt case. + IPC::Message bad_msg(1, 2, IPC::Message::PRIORITY_NORMAL); + bad_msg.WriteInt(99); + iter = NULL; + EXPECT_FALSE(IPC::ReadParam(&bad_msg, &iter, &output)); + + // Test a recursive case. + webkit_glue::WebAccessibility outer; + outer.id = 1000; + outer.name = ASCIIToUTF16("outer_name"); + outer.role = webkit_glue::WebAccessibility::ROLE_GROUP; + outer.state = 0; + outer.location = WebKit::WebRect(0, 0, 1000, 1000); + webkit_glue::WebAccessibility inner1; + inner1.id = 1001; + inner1.name = ASCIIToUTF16("inner1_name"); + inner1.role = webkit_glue::WebAccessibility::ROLE_RADIO_BUTTON; + inner1.state = + (1 << webkit_glue::WebAccessibility::STATE_CHECKED) | + (1 << webkit_glue::WebAccessibility::STATE_FOCUSED); + inner1.location = WebKit::WebRect(10, 10, 900, 400); + outer.children.push_back(inner1); + webkit_glue::WebAccessibility inner2; + inner2.id = 1002; + inner2.name = ASCIIToUTF16("inner2_name"); + inner2.role = webkit_glue::WebAccessibility::ROLE_RADIO_BUTTON; + inner2.state = (1 << webkit_glue::WebAccessibility::STATE_CHECKED); + inner2.location = WebKit::WebRect(10, 500, 900, 400); + outer.children.push_back(inner2); + + IPC::Message msg2(1, 2, IPC::Message::PRIORITY_NORMAL); + IPC::WriteParam(&msg2, outer); + + void* iter2 = NULL; + EXPECT_TRUE(IPC::ReadParam(&msg2, &iter2, &output)); + EXPECT_EQ(outer.id, output.id); + EXPECT_EQ(outer.name, output.name); + EXPECT_EQ(outer.role, output.role); + EXPECT_EQ(outer.state, output.state); + EXPECT_EQ(outer.location, output.location); + EXPECT_EQ(outer.children.size(), output.children.size()); + EXPECT_EQ(inner1.id, output.children[0].id); + EXPECT_EQ(inner1.name, output.children[0].name); + EXPECT_EQ(inner1.role, output.children[0].role); + EXPECT_EQ(inner1.state, output.children[0].state); + EXPECT_EQ(inner1.location, output.children[0].location); + EXPECT_EQ(inner2.id, output.children[1].id); + EXPECT_EQ(inner2.name, output.children[1].name); + EXPECT_EQ(inner2.role, output.children[1].role); + EXPECT_EQ(inner2.state, output.children[1].state); + EXPECT_EQ(inner2.location, output.children[1].location); +} diff --git a/chrome/common/renderer_preferences.h b/chrome/common/renderer_preferences.h new file mode 100644 index 0000000..7a55b17 --- /dev/null +++ b/chrome/common/renderer_preferences.h @@ -0,0 +1,93 @@ +// Copyright (c) 2006-2008 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 struct for managing browser's settings that apply to the renderer or its +// webview. These differ from WebPreferences since they apply to Chromium's +// glue layer rather than applying to just WebKit. +// +// Adding new values to this class probably involves updating +// common/render_messages.h, browser/browser.cc, etc. + +#ifndef CHROME_COMMON_RENDERER_PREFERENCES_H_ +#define CHROME_COMMON_RENDERER_PREFERENCES_H_ + +#include "third_party/skia/include/core/SkColor.h" + +enum RendererPreferencesHintingEnum { + RENDERER_PREFERENCES_HINTING_SYSTEM_DEFAULT = 0, + RENDERER_PREFERENCES_HINTING_NONE, + RENDERER_PREFERENCES_HINTING_SLIGHT, + RENDERER_PREFERENCES_HINTING_MEDIUM, + RENDERER_PREFERENCES_HINTING_FULL, +}; + +enum RendererPreferencesSubpixelRenderingEnum { + RENDERER_PREFERENCES_SUBPIXEL_RENDERING_SYSTEM_DEFAULT = 0, + RENDERER_PREFERENCES_SUBPIXEL_RENDERING_NONE, + RENDERER_PREFERENCES_SUBPIXEL_RENDERING_RGB, + RENDERER_PREFERENCES_SUBPIXEL_RENDERING_BGR, + RENDERER_PREFERENCES_SUBPIXEL_RENDERING_VRGB, + RENDERER_PREFERENCES_SUBPIXEL_RENDERING_VBGR, +}; + +struct RendererPreferences { + // Whether the renderer's current browser context accept drops from the OS + // that result in navigations away from the current page. + bool can_accept_load_drops; + + // Whether text should be antialiased. + // Currently only used by Linux. + bool should_antialias_text; + + // The level of hinting to use when rendering text. + // Currently only used by Linux. + RendererPreferencesHintingEnum hinting; + + // The type of subpixel rendering to use for text. + // Currently only used by Linux. + RendererPreferencesSubpixelRenderingEnum subpixel_rendering; + + // The color of the focus ring. Currently only used on Linux. + SkColor focus_ring_color; + + // The color of different parts of the scrollbar. Currently only used on + // Linux. + SkColor thumb_active_color; + SkColor thumb_inactive_color; + SkColor track_color; + + // The colors used in selection text. Currently only used on Linux. + SkColor active_selection_bg_color; + SkColor active_selection_fg_color; + SkColor inactive_selection_bg_color; + SkColor inactive_selection_fg_color; + + // Browser wants a look at all top level requests + bool browser_handles_top_level_requests; + + // Cursor blink rate in seconds. + // Currently only changed from default on Linux. Uses |gtk-cursor-blink| + // from GtkSettings. + double caret_blink_interval; + + RendererPreferences() + : can_accept_load_drops(true), + should_antialias_text(true), + hinting(RENDERER_PREFERENCES_HINTING_SYSTEM_DEFAULT), + subpixel_rendering( + RENDERER_PREFERENCES_SUBPIXEL_RENDERING_SYSTEM_DEFAULT), + focus_ring_color(0), + thumb_active_color(0), + thumb_inactive_color(0), + track_color(0), + active_selection_bg_color(0), + active_selection_fg_color(0), + inactive_selection_bg_color(0), + inactive_selection_fg_color(0), + browser_handles_top_level_requests(false), + caret_blink_interval(0) { + } +}; + +#endif // CHROME_COMMON_RENDERER_PREFERENCES_H_ diff --git a/chrome/common/resource_dispatcher.cc b/chrome/common/resource_dispatcher.cc new file mode 100644 index 0000000..ace6169 --- /dev/null +++ b/chrome/common/resource_dispatcher.cc @@ -0,0 +1,628 @@ +// Copyright (c) 2010 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. + +// See http://dev.chromium.org/developers/design-documents/multi-process-resource-loading + +#include "chrome/common/resource_dispatcher.h" + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/file_path.h" +#include "base/message_loop.h" +#include "base/shared_memory.h" +#include "base/string_util.h" +#include "chrome/common/extensions/extension_localization_peer.h" +#include "chrome/common/render_messages.h" +#include "chrome/common/security_filter_peer.h" +#include "net/base/net_errors.h" +#include "net/base/net_util.h" +#include "webkit/glue/resource_type.h" +#include "webkit/glue/webkit_glue.h" + +// Uncomment to enable logging of request traffic +// #define LOG_RESOURCE_REQUESTS + +#ifdef LOG_RESOURCE_REQUESTS +# define RESOURCE_LOG(stuff) LOG(INFO) << stuff +#else +# define RESOURCE_LOG(stuff) +#endif + +// Each resource request is assigned an ID scoped to this process. +static int MakeRequestID() { + // NOTE: The resource_dispatcher_host also needs probably unique + // request_ids, so they count down from -2 (-1 is a special we're + // screwed value), while the renderer process counts up. + static int next_request_id = 0; + return next_request_id++; +} + +// ResourceLoaderBridge implementation ---------------------------------------- + +namespace webkit_glue { + +class IPCResourceLoaderBridge : public ResourceLoaderBridge { + public: + IPCResourceLoaderBridge(ResourceDispatcher* dispatcher, + const webkit_glue::ResourceLoaderBridge::RequestInfo& request_info, + int host_renderer_id, + int host_render_view_id); + virtual ~IPCResourceLoaderBridge(); + + // ResourceLoaderBridge + virtual void AppendDataToUpload(const char* data, int data_len); + virtual void AppendFileRangeToUpload( + const FilePath& path, + uint64 offset, + uint64 length, + const base::Time& expected_modification_time); + virtual void SetUploadIdentifier(int64 identifier); + virtual bool Start(Peer* peer); + virtual void Cancel(); + virtual void SetDefersLoading(bool value); + virtual void SyncLoad(SyncLoadResponse* response); + +#ifdef LOG_RESOURCE_REQUESTS + const std::string& url() const { return url_; } +#endif + + private: + ResourceLoaderBridge::Peer* peer_; + + // The resource dispatcher for this loader. The bridge doesn't own it, but + // it's guaranteed to outlive the bridge. + ResourceDispatcher* dispatcher_; + + // The request to send, created on initialization for modification and + // appending data. + ViewHostMsg_Resource_Request request_; + + // ID for the request, valid once Start()ed, -1 if not valid yet. + int request_id_; + + // The routing id used when sending IPC messages. + int routing_id_; + +#ifdef LOG_RESOURCE_REQUESTS + // indicates the URL of this resource request for help debugging + std::string url_; +#endif + + // The following two members are specified if the request is initiated by + // a plugin like Gears. + + // Contains the id of the host renderer. + int host_renderer_id_; + + // Contains the id of the host render view. + int host_render_view_id_; +}; + +IPCResourceLoaderBridge::IPCResourceLoaderBridge( + ResourceDispatcher* dispatcher, + const webkit_glue::ResourceLoaderBridge::RequestInfo& request_info, + int host_renderer_id, + int host_render_view_id) + : peer_(NULL), + dispatcher_(dispatcher), + request_id_(-1), + routing_id_(request_info.routing_id), + host_renderer_id_(host_renderer_id), + host_render_view_id_(host_render_view_id) { + DCHECK(dispatcher_) << "no resource dispatcher"; + request_.method = request_info.method; + request_.url = request_info.url; + request_.first_party_for_cookies = request_info.first_party_for_cookies; + request_.referrer = request_info.referrer; + request_.frame_origin = request_info.frame_origin; + request_.main_frame_origin = request_info.main_frame_origin; + request_.headers = request_info.headers; + request_.load_flags = request_info.load_flags; + request_.origin_child_id = request_info.requestor_pid; + request_.resource_type = request_info.request_type; + request_.request_context = request_info.request_context; + request_.appcache_host_id = request_info.appcache_host_id; + request_.host_renderer_id = host_renderer_id_; + request_.host_render_view_id = host_render_view_id_; + +#ifdef LOG_RESOURCE_REQUESTS + url_ = url.possibly_invalid_spec(); +#endif +} + +IPCResourceLoaderBridge::~IPCResourceLoaderBridge() { + // we remove our hook for the resource dispatcher only when going away, since + // it doesn't keep track of whether we've force terminated the request + if (request_id_ >= 0) { + // this operation may fail, as the dispatcher will have preemptively + // removed us when the renderer sends the ReceivedAllData message. + dispatcher_->RemovePendingRequest(request_id_); + } +} + +void IPCResourceLoaderBridge::AppendDataToUpload(const char* data, + int data_len) { + DCHECK(request_id_ == -1) << "request already started"; + + // don't bother appending empty data segments + if (data_len == 0) + return; + + if (!request_.upload_data) + request_.upload_data = new net::UploadData(); + request_.upload_data->AppendBytes(data, data_len); +} + +void IPCResourceLoaderBridge::AppendFileRangeToUpload( + const FilePath& path, uint64 offset, uint64 length, + const base::Time& expected_modification_time) { + DCHECK(request_id_ == -1) << "request already started"; + + if (!request_.upload_data) + request_.upload_data = new net::UploadData(); + request_.upload_data->AppendFileRange(path, offset, length, + expected_modification_time); +} + +void IPCResourceLoaderBridge::SetUploadIdentifier(int64 identifier) { + DCHECK(request_id_ == -1) << "request already started"; + + if (!request_.upload_data) + request_.upload_data = new net::UploadData(); + request_.upload_data->set_identifier(identifier); +} + +// Writes a footer on the message and sends it +bool IPCResourceLoaderBridge::Start(Peer* peer) { + if (request_id_ != -1) { + NOTREACHED() << "Starting a request twice"; + return false; + } + + RESOURCE_LOG("Starting request for " << url_); + + peer_ = peer; + + // generate the request ID, and append it to the message + request_id_ = dispatcher_->AddPendingRequest( + peer_, request_.resource_type, request_.url); + + return dispatcher_->message_sender()->Send( + new ViewHostMsg_RequestResource(routing_id_, request_id_, request_)); +} + +void IPCResourceLoaderBridge::Cancel() { + if (request_id_ < 0) { + NOTREACHED() << "Trying to cancel an unstarted request"; + return; + } + + RESOURCE_LOG("Canceling request for " << url_); + + dispatcher_->CancelPendingRequest(routing_id_, request_id_); + + // We can't remove the request ID from the resource dispatcher because more + // data might be pending. Sending the cancel message may cause more data + // to be flushed, and will then cause a complete message to be sent. +} + +void IPCResourceLoaderBridge::SetDefersLoading(bool value) { + if (request_id_ < 0) { + NOTREACHED() << "Trying to (un)defer an unstarted request"; + return; + } + + dispatcher_->SetDefersLoading(request_id_, value); +} + +void IPCResourceLoaderBridge::SyncLoad(SyncLoadResponse* response) { + if (request_id_ != -1) { + NOTREACHED() << "Starting a request twice"; + response->status.set_status(URLRequestStatus::FAILED); + return; + } + + RESOURCE_LOG("Making sync request for " << url_); + + request_id_ = MakeRequestID(); + + SyncLoadResult result; + IPC::SyncMessage* msg = new ViewHostMsg_SyncLoad(routing_id_, request_id_, + request_, &result); + // NOTE: This may pump events (see RenderThread::Send). + if (!dispatcher_->message_sender()->Send(msg)) { + response->status.set_status(URLRequestStatus::FAILED); + return; + } + + response->status = result.status; + response->url = result.final_url; + response->headers = result.headers; + response->mime_type = result.mime_type; + response->charset = result.charset; + response->data.swap(result.data); +} + +} // namespace webkit_glue + +// ResourceDispatcher --------------------------------------------------------- + +ResourceDispatcher::ResourceDispatcher(IPC::Message::Sender* sender) + : message_sender_(sender), + ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { +} + +ResourceDispatcher::~ResourceDispatcher() { +} + +// ResourceDispatcher implementation ------------------------------------------ + +bool ResourceDispatcher::OnMessageReceived(const IPC::Message& message) { + if (!IsResourceDispatcherMessage(message)) { + return false; + } + + int request_id; + + void* iter = NULL; + if (!message.ReadInt(&iter, &request_id)) { + NOTREACHED() << "malformed resource message"; + return true; + } + + PendingRequestList::iterator it = pending_requests_.find(request_id); + if (it == pending_requests_.end()) { + // This might happen for kill()ed requests on the webkit end, so perhaps it + // shouldn't be a warning... + DLOG(WARNING) << "Got response for a nonexistent or finished request"; + // Release resources in the message if it is a data message. + ReleaseResourcesInDataMessage(message); + return true; + } + + PendingRequestInfo& request_info = it->second; + if (request_info.is_deferred) { + request_info.deferred_message_queue.push_back(new IPC::Message(message)); + return true; + } + // Make sure any deferred messages are dispatched before we dispatch more. + if (!request_info.deferred_message_queue.empty()) { + FlushDeferredMessages(request_id); + // The request could have been deferred now. If yes then the current + // message has to be queued up. The request_info instance should remain + // valid here as there are pending messages for it. + DCHECK(pending_requests_.find(request_id) != pending_requests_.end()); + if (request_info.is_deferred) { + request_info.deferred_message_queue.push_back(new IPC::Message(message)); + return true; + } + } + + DispatchMessage(message); + return true; +} + +void ResourceDispatcher::OnUploadProgress( + const IPC::Message& message, int request_id, int64 position, int64 size) { + PendingRequestList::iterator it = pending_requests_.find(request_id); + if (it == pending_requests_.end()) { + // this might happen for kill()ed requests on the webkit end, so perhaps + // it shouldn't be a warning... + DLOG(WARNING) << "Got upload progress for a nonexistent or " + "finished request"; + return; + } + + PendingRequestInfo& request_info = it->second; + + RESOURCE_LOG("Dispatching upload progress for " << + request_info.peer->GetURLForDebugging().possibly_invalid_spec()); + request_info.peer->OnUploadProgress(position, size); + + // Acknowledge receipt + message_sender()->Send( + new ViewHostMsg_UploadProgress_ACK(message.routing_id(), request_id)); +} + +void ResourceDispatcher::OnReceivedResponse( + int request_id, const ResourceResponseHead& response_head) { + PendingRequestList::iterator it = pending_requests_.find(request_id); + if (it == pending_requests_.end()) { + // This might happen for kill()ed requests on the webkit end, so perhaps it + // shouldn't be a warning... + DLOG(WARNING) << "Got response for a nonexistent or finished request"; + return; + } + + PendingRequestInfo& request_info = it->second; + if (response_head.replace_extension_localization_templates) { + webkit_glue::ResourceLoaderBridge::Peer* new_peer = + ExtensionLocalizationPeer::CreateExtensionLocalizationPeer( + request_info.peer, message_sender(), response_head.mime_type, + request_info.url); + if (new_peer) + request_info.peer = new_peer; + } + + RESOURCE_LOG("Dispatching response for " << + request_info.peer->GetURLForDebugging().possibly_invalid_spec()); + request_info.peer->OnReceivedResponse(response_head, false); +} + +void ResourceDispatcher::OnReceivedCachedMetadata( + int request_id, const std::vector<char>& data) { + PendingRequestList::iterator it = pending_requests_.find(request_id); + if (it == pending_requests_.end()) { + // this might happen for kill()ed requests on the webkit end, so perhaps + // it shouldn't be a warning... + DLOG(WARNING) << "Got metadata for a nonexistent or finished request"; + return; + } + + if (data.size()) { + PendingRequestInfo& request_info = it->second; + RESOURCE_LOG("Dispatching " << data.size() << " metadata bytes for " << + request_info.peer->GetURLForDebugging().possibly_invalid_spec()); + request_info.peer->OnReceivedCachedMetadata(&data.front(), data.size()); + } +} + +void ResourceDispatcher::OnReceivedData(const IPC::Message& message, + int request_id, + base::SharedMemoryHandle shm_handle, + int data_len) { + // Acknowledge the reception of this data. + message_sender()->Send( + new ViewHostMsg_DataReceived_ACK(message.routing_id(), request_id)); + + const bool shm_valid = base::SharedMemory::IsHandleValid(shm_handle); + DCHECK((shm_valid && data_len > 0) || (!shm_valid && !data_len)); + base::SharedMemory shared_mem(shm_handle, true); // read only + + PendingRequestList::iterator it = pending_requests_.find(request_id); + if (it == pending_requests_.end()) { + // this might happen for kill()ed requests on the webkit end, so perhaps + // it shouldn't be a warning... + DLOG(WARNING) << "Got data for a nonexistent or finished request"; + return; + } + + PendingRequestInfo& request_info = it->second; + + if (data_len > 0 && shared_mem.Map(data_len)) { + RESOURCE_LOG("Dispatching " << data_len << " bytes for " << + request_info.peer->GetURLForDebugging().possibly_invalid_spec()); + const char* data = static_cast<char*>(shared_mem.memory()); + request_info.peer->OnReceivedData(data, data_len); + } +} + +void ResourceDispatcher::OnReceivedRedirect( + const IPC::Message& message, + int request_id, + const GURL& new_url, + const webkit_glue::ResourceLoaderBridge::ResponseInfo& info) { + PendingRequestList::iterator it = pending_requests_.find(request_id); + if (it == pending_requests_.end()) { + // this might happen for kill()ed requests on the webkit end, so perhaps + // it shouldn't be a warning... + DLOG(WARNING) << "Got data for a nonexistent or finished request"; + return; + } + + PendingRequestInfo& request_info = it->second; + + RESOURCE_LOG("Dispatching redirect for " << + request_info.peer->GetURLForDebugging().possibly_invalid_spec()); + + bool has_new_first_party_for_cookies = false; + GURL new_first_party_for_cookies; + if (request_info.peer->OnReceivedRedirect(new_url, info, + &has_new_first_party_for_cookies, + &new_first_party_for_cookies)) { + message_sender()->Send( + new ViewHostMsg_FollowRedirect(message.routing_id(), request_id, + has_new_first_party_for_cookies, + new_first_party_for_cookies)); + } else { + CancelPendingRequest(message.routing_id(), request_id); + } +} + +void ResourceDispatcher::OnRequestComplete(int request_id, + const URLRequestStatus& status, + const std::string& security_info) { + PendingRequestList::iterator it = pending_requests_.find(request_id); + if (it == pending_requests_.end()) { + // this might happen for kill()ed requests on the webkit end, so perhaps + // it shouldn't be a warning... + DLOG(WARNING) << "Got 'complete' for a nonexistent or finished request"; + return; + } + + PendingRequestInfo& request_info = it->second; + webkit_glue::ResourceLoaderBridge::Peer* peer = request_info.peer; + + RESOURCE_LOG("Dispatching complete for " << + request_info.peer->GetURLForDebugging().possibly_invalid_spec()); + + if (status.status() == URLRequestStatus::CANCELED && + status.os_error() != net::ERR_ABORTED) { + // Resource canceled with a specific error are filtered. + SecurityFilterPeer* new_peer = + SecurityFilterPeer::CreateSecurityFilterPeerForDeniedRequest( + request_info.resource_type, + request_info.peer, + status.os_error()); + if (new_peer) { + request_info.peer = new_peer; + peer = new_peer; + } + } + + // The request ID will be removed from our pending list in the destructor. + // Normally, dispatching this message causes the reference-counted request to + // die immediately. + peer->OnCompletedRequest(status, security_info); + + webkit_glue::NotifyCacheStats(); +} + +int ResourceDispatcher::AddPendingRequest( + webkit_glue::ResourceLoaderBridge::Peer* callback, + ResourceType::Type resource_type, + const GURL& request_url) { + // Compute a unique request_id for this renderer process. + int id = MakeRequestID(); + pending_requests_[id] = + PendingRequestInfo(callback, resource_type, request_url); + return id; +} + +bool ResourceDispatcher::RemovePendingRequest(int request_id) { + PendingRequestList::iterator it = pending_requests_.find(request_id); + if (it == pending_requests_.end()) + return false; + + PendingRequestInfo& request_info = it->second; + ReleaseResourcesInMessageQueue(&request_info.deferred_message_queue); + pending_requests_.erase(it); + + return true; +} + +void ResourceDispatcher::CancelPendingRequest(int routing_id, + int request_id) { + PendingRequestList::iterator it = pending_requests_.find(request_id); + if (it == pending_requests_.end()) { + DLOG(WARNING) << "unknown request"; + return; + } + + PendingRequestInfo& request_info = it->second; + ReleaseResourcesInMessageQueue(&request_info.deferred_message_queue); + pending_requests_.erase(it); + + message_sender()->Send( + new ViewHostMsg_CancelRequest(routing_id, request_id)); +} + +void ResourceDispatcher::SetDefersLoading(int request_id, bool value) { + PendingRequestList::iterator it = pending_requests_.find(request_id); + if (it == pending_requests_.end()) { + DLOG(ERROR) << "unknown request"; + return; + } + PendingRequestInfo& request_info = it->second; + if (value) { + request_info.is_deferred = value; + } else if (request_info.is_deferred) { + request_info.is_deferred = false; + MessageLoop::current()->PostTask(FROM_HERE, + method_factory_.NewRunnableMethod( + &ResourceDispatcher::FlushDeferredMessages, request_id)); + } +} + +void ResourceDispatcher::DispatchMessage(const IPC::Message& message) { + IPC_BEGIN_MESSAGE_MAP(ResourceDispatcher, message) + IPC_MESSAGE_HANDLER(ViewMsg_Resource_UploadProgress, OnUploadProgress) + IPC_MESSAGE_HANDLER(ViewMsg_Resource_ReceivedResponse, OnReceivedResponse) + IPC_MESSAGE_HANDLER( + ViewMsg_Resource_ReceivedCachedMetadata, OnReceivedCachedMetadata) + IPC_MESSAGE_HANDLER(ViewMsg_Resource_ReceivedRedirect, OnReceivedRedirect) + IPC_MESSAGE_HANDLER(ViewMsg_Resource_DataReceived, OnReceivedData) + IPC_MESSAGE_HANDLER(ViewMsg_Resource_RequestComplete, OnRequestComplete) + IPC_END_MESSAGE_MAP() +} + +void ResourceDispatcher::FlushDeferredMessages(int request_id) { + PendingRequestList::iterator it = pending_requests_.find(request_id); + if (it == pending_requests_.end()) // The request could have become invalid. + return; + PendingRequestInfo& request_info = it->second; + if (request_info.is_deferred) + return; + // Because message handlers could result in request_info being destroyed, + // we need to work with a stack reference to the deferred queue. + MessageQueue q; + q.swap(request_info.deferred_message_queue); + while (!q.empty()) { + IPC::Message* m = q.front(); + q.pop_front(); + DispatchMessage(*m); + delete m; + // If this request is deferred in the context of the above message, then + // we should honor the same and stop dispatching further messages. + // We need to find the request again in the list as it may have completed + // by now and the request_info instance above may be invalid. + PendingRequestList::iterator index = pending_requests_.find(request_id); + if (index != pending_requests_.end()) { + PendingRequestInfo& pending_request = index->second; + if (pending_request.is_deferred) { + pending_request.deferred_message_queue.swap(q); + return; + } + } + } +} + +webkit_glue::ResourceLoaderBridge* ResourceDispatcher::CreateBridge( + const webkit_glue::ResourceLoaderBridge::RequestInfo& request_info, + int host_renderer_id, + int host_render_view_id) { + return new webkit_glue::IPCResourceLoaderBridge(this, request_info, + host_renderer_id, + host_render_view_id); +} + +bool ResourceDispatcher::IsResourceDispatcherMessage( + const IPC::Message& message) { + switch (message.type()) { + case ViewMsg_Resource_UploadProgress::ID: + case ViewMsg_Resource_ReceivedResponse::ID: + case ViewMsg_Resource_ReceivedCachedMetadata::ID: + case ViewMsg_Resource_ReceivedRedirect::ID: + case ViewMsg_Resource_DataReceived::ID: + case ViewMsg_Resource_RequestComplete::ID: + return true; + + default: + break; + } + + return false; +} + +// static +void ResourceDispatcher::ReleaseResourcesInDataMessage( + const IPC::Message& message) { + void* iter = NULL; + int request_id; + if (!message.ReadInt(&iter, &request_id)) { + NOTREACHED() << "malformed resource message"; + return; + } + + // If the message contains a shared memory handle, we should close the + // handle or there will be a memory leak. + if (message.type() == ViewMsg_Resource_DataReceived::ID) { + base::SharedMemoryHandle shm_handle; + if (IPC::ParamTraits<base::SharedMemoryHandle>::Read(&message, + &iter, + &shm_handle)) { + base::SharedMemory::CloseHandle(shm_handle); + } + } +} + +// static +void ResourceDispatcher::ReleaseResourcesInMessageQueue(MessageQueue* queue) { + while (!queue->empty()) { + IPC::Message* message = queue->front(); + ReleaseResourcesInDataMessage(*message); + queue->pop_front(); + delete message; + } +} diff --git a/chrome/common/resource_dispatcher.h b/chrome/common/resource_dispatcher.h new file mode 100644 index 0000000..c98b11a --- /dev/null +++ b/chrome/common/resource_dispatcher.h @@ -0,0 +1,138 @@ +// Copyright (c) 2010 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. + +// See http://dev.chromium.org/developers/design-documents/multi-process-resource-loading + +#ifndef CHROME_COMMON_RESOURCE_DISPATCHER_H__ +#define CHROME_COMMON_RESOURCE_DISPATCHER_H__ + +#include <deque> +#include <string> + +#include "base/hash_tables.h" +#include "base/shared_memory.h" +#include "base/task.h" +#include "ipc/ipc_channel.h" +#include "webkit/glue/resource_loader_bridge.h" + +struct ResourceResponseHead; + +// This class serves as a communication interface between the +// ResourceDispatcherHost in the browser process and the ResourceLoaderBridge in +// the child process. It can be used from any child process. +class ResourceDispatcher { + public: + explicit ResourceDispatcher(IPC::Message::Sender* sender); + ~ResourceDispatcher(); + + // Called to possibly handle the incoming IPC message. Returns true if + // handled, else false. + bool OnMessageReceived(const IPC::Message& message); + + // Creates a ResourceLoaderBridge for this type of dispatcher, this is so + // this can be tested regardless of the ResourceLoaderBridge::Create + // implementation. + webkit_glue::ResourceLoaderBridge* CreateBridge( + const webkit_glue::ResourceLoaderBridge::RequestInfo& request_info, + int host_renderer_id, + int host_render_view_id); + + // Adds a request from the pending_requests_ list, returning the new + // requests' ID + int AddPendingRequest(webkit_glue::ResourceLoaderBridge::Peer* callback, + ResourceType::Type resource_type, + const GURL& request_url); + + // Removes a request from the pending_requests_ list, returning true if the + // request was found and removed. + bool RemovePendingRequest(int request_id); + + // Cancels a request in the pending_requests_ list. + void CancelPendingRequest(int routing_id, int request_id); + + IPC::Message::Sender* message_sender() const { + return message_sender_; + } + + // Toggles the is_deferred attribute for the specified request. + void SetDefersLoading(int request_id, bool value); + + private: + friend class ResourceDispatcherTest; + + typedef std::deque<IPC::Message*> MessageQueue; + struct PendingRequestInfo { + PendingRequestInfo() { } + PendingRequestInfo(webkit_glue::ResourceLoaderBridge::Peer* peer, + ResourceType::Type resource_type, + const GURL& request_url) + : peer(peer), + resource_type(resource_type), + is_deferred(false), + url(request_url) { + } + ~PendingRequestInfo() { } + webkit_glue::ResourceLoaderBridge::Peer* peer; + ResourceType::Type resource_type; + MessageQueue deferred_message_queue; + bool is_deferred; + GURL url; + }; + typedef base::hash_map<int, PendingRequestInfo> PendingRequestList; + + // Message response handlers, called by the message handler for this process. + void OnUploadProgress( + const IPC::Message& message, + int request_id, + int64 position, + int64 size); + void OnReceivedResponse(int request_id, const ResourceResponseHead&); + void OnReceivedCachedMetadata(int request_id, const std::vector<char>& data); + void OnReceivedRedirect( + const IPC::Message& message, + int request_id, + const GURL& new_url, + const webkit_glue::ResourceLoaderBridge::ResponseInfo& info); + void OnReceivedData( + const IPC::Message& message, + int request_id, + base::SharedMemoryHandle data, + int data_len); + void OnRequestComplete( + int request_id, + const URLRequestStatus& status, + const std::string& security_info); + + // Dispatch the message to one of the message response handlers. + void DispatchMessage(const IPC::Message& message); + + // Dispatch any deferred messages for the given request, provided it is not + // again in the deferred state. + void FlushDeferredMessages(int request_id); + + // Returns true if the message passed in is a resource related message. + static bool IsResourceDispatcherMessage(const IPC::Message& message); + + // ViewHostMsg_Resource_DataReceived is not POD, it has a shared memory + // handle in it that we should cleanup it up nicely. This method accepts any + // message and determine whether the message is + // ViewHostMsg_Resource_DataReceived and clean up the shared memory handle. + static void ReleaseResourcesInDataMessage(const IPC::Message& message); + + // Iterate through a message queue and clean up the messages by calling + // ReleaseResourcesInDataMessage and removing them from the queue. Intended + // for use on deferred message queues that are no longer needed. + static void ReleaseResourcesInMessageQueue(MessageQueue* queue); + + IPC::Message::Sender* message_sender_; + + // All pending requests issued to the host + PendingRequestList pending_requests_; + + ScopedRunnableMethodFactory<ResourceDispatcher> method_factory_; + + DISALLOW_COPY_AND_ASSIGN(ResourceDispatcher); +}; + +#endif // CHROME_COMMON_RESOURCE_DISPATCHER_H__ diff --git a/chrome/common/resource_dispatcher_dummy.cc b/chrome/common/resource_dispatcher_dummy.cc new file mode 100644 index 0000000..f047b34 --- /dev/null +++ b/chrome/common/resource_dispatcher_dummy.cc @@ -0,0 +1,35 @@ +// Copyright (c) 2006-2008 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. + +// See http://dev.chromium.org/developers/design-documents/multi-process-resource-loading + +#include "chrome/common/resource_dispatcher.h" + +#include "base/compiler_specific.h" + +// ResourceDispatcher --------------------------------------------------------- + +ResourceDispatcher::ResourceDispatcher(IPC::Message::Sender* sender) + : message_sender_(sender), + ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { +} + +ResourceDispatcher::~ResourceDispatcher() { +} + +// ResourceDispatcher implementation ------------------------------------------ + +bool ResourceDispatcher::OnMessageReceived(const IPC::Message& message) { + return false; +} + +webkit_glue::ResourceLoaderBridge* ResourceDispatcher::CreateBridge( + const webkit_glue::ResourceLoaderBridge::RequestInfo& request_info, + int host_renderer_id, + int host_render_view_id) { + // This function is used only by plugin and renderer code, so it should + // never be called in a 64-bit Windows process. + NOTREACHED(); + return NULL; +} diff --git a/chrome/common/resource_dispatcher_unittest.cc b/chrome/common/resource_dispatcher_unittest.cc new file mode 100644 index 0000000..323a6e4 --- /dev/null +++ b/chrome/common/resource_dispatcher_unittest.cc @@ -0,0 +1,325 @@ +// Copyright (c) 2010 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 <string> +#include <vector> + +#include "base/message_loop.h" +#include "base/process.h" +#include "base/process_util.h" +#include "base/scoped_ptr.h" +#include "chrome/common/render_messages.h" +#include "chrome/common/resource_dispatcher.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "webkit/appcache/appcache_interfaces.h" + +using webkit_glue::ResourceLoaderBridge; + +static const char test_page_url[] = "http://www.google.com/"; +static const char test_page_headers[] = + "HTTP/1.1 200 OK\nContent-Type:text/html\n\n"; +static const char test_page_mime_type[] = "text/html"; +static const char test_page_charset[] = ""; +static const char test_page_contents[] = + "<html><head><title>Google</title></head><body><h1>Google</h1></body></html>"; +static const uint32 test_page_contents_len = arraysize(test_page_contents) - 1; + +// Listens for request response data and stores it so that it can be compared +// to the reference data. +class TestRequestCallback : public ResourceLoaderBridge::Peer { + public: + TestRequestCallback() : complete_(false) { + } + + virtual bool OnReceivedRedirect( + const GURL& new_url, + const ResourceLoaderBridge::ResponseInfo& info, + bool* has_new_first_party_for_cookies, + GURL* new_first_party_for_cookies) { + *has_new_first_party_for_cookies = false; + return true; + } + + virtual void OnReceivedResponse( + const ResourceLoaderBridge::ResponseInfo& info, + bool content_filtered) { + } + + virtual void OnReceivedData(const char* data, int len) { + EXPECT_FALSE(complete_); + data_.append(data, len); + } + + virtual void OnUploadProgress(uint64 position, uint64 size) { + } + + virtual void OnCompletedRequest(const URLRequestStatus& status, + const std::string& security_info) { + EXPECT_FALSE(complete_); + complete_ = true; + } + + virtual GURL GetURLForDebugging() const { + return GURL(); + } + + const std::string& data() const { + return data_; + } + bool complete() const { + return complete_; + } + + private: + bool complete_; + std::string data_; +}; + + +// Sets up the message sender override for the unit test +class ResourceDispatcherTest : public testing::Test, + public IPC::Message::Sender { + public: + // Emulates IPC send operations (IPC::Message::Sender) by adding + // pending messages to the queue. + virtual bool Send(IPC::Message* msg) { + message_queue_.push_back(IPC::Message(*msg)); + delete msg; + return true; + } + + // Emulates the browser process and processes the pending IPC messages, + // returning the hardcoded file contents. + void ProcessMessages() { + while (!message_queue_.empty()) { + int request_id; + ViewHostMsg_Resource_Request request; + ASSERT_TRUE(ViewHostMsg_RequestResource::Read( + &message_queue_[0], &request_id, &request)); + + // check values + EXPECT_EQ(test_page_url, request.url.spec()); + + // received response message + ResourceResponseHead response; + std::string raw_headers(test_page_headers); + std::replace(raw_headers.begin(), raw_headers.end(), '\n', '\0'); + response.headers = new net::HttpResponseHeaders(raw_headers); + response.mime_type = test_page_mime_type; + response.charset = test_page_charset; + dispatcher_->OnReceivedResponse(request_id, response); + + // received data message with the test contents + base::SharedMemory shared_mem; + EXPECT_TRUE(shared_mem.Create(std::wstring(), + false, false, test_page_contents_len)); + EXPECT_TRUE(shared_mem.Map(test_page_contents_len)); + char* put_data_here = static_cast<char*>(shared_mem.memory()); + memcpy(put_data_here, test_page_contents, test_page_contents_len); + base::SharedMemoryHandle dup_handle; + EXPECT_TRUE(shared_mem.GiveToProcess( + base::Process::Current().handle(), &dup_handle)); + dispatcher_->OnReceivedData( + message_queue_[0], request_id, dup_handle, test_page_contents_len); + + message_queue_.erase(message_queue_.begin()); + + // read the ack message. + Tuple1<int> request_ack; + ASSERT_TRUE(ViewHostMsg_DataReceived_ACK::Read( + &message_queue_[0], &request_ack)); + + ASSERT_EQ(request_ack.a, request_id); + + message_queue_.erase(message_queue_.begin()); + } + } + + protected: + // testing::Test + virtual void SetUp() { + dispatcher_.reset(new ResourceDispatcher(this)); + } + virtual void TearDown() { + dispatcher_.reset(); + } + + ResourceLoaderBridge* CreateBridge() { + webkit_glue::ResourceLoaderBridge::RequestInfo request_info; + request_info.method = "GET"; + request_info.url = GURL(test_page_url); + request_info.first_party_for_cookies = GURL(test_page_url); + request_info.referrer = GURL(); + request_info.frame_origin = "null"; + request_info.main_frame_origin = "null"; + request_info.headers = std::string(); + request_info.load_flags = 0; + request_info.requestor_pid = 0; + request_info.request_type = ResourceType::SUB_RESOURCE; + request_info.appcache_host_id = appcache::kNoHostId; + request_info.routing_id = 0; + + return dispatcher_->CreateBridge(request_info, -1, -1); + } + + std::vector<IPC::Message> message_queue_; + static scoped_ptr<ResourceDispatcher> dispatcher_; +}; + +/*static*/ +scoped_ptr<ResourceDispatcher> ResourceDispatcherTest::dispatcher_; + +// Does a simple request and tests that the correct data is received. +TEST_F(ResourceDispatcherTest, RoundTrip) { + TestRequestCallback callback; + ResourceLoaderBridge* bridge = CreateBridge(); + + bridge->Start(&callback); + + ProcessMessages(); + + // FIXME(brettw) when the request complete messages are actually handledo + // and dispatched, uncomment this. + //EXPECT_TRUE(callback.complete()); + //EXPECT_STREQ(test_page_contents, callback.data().c_str()); + + delete bridge; +} + +// Tests that the request IDs are straight when there are multiple requests. +TEST_F(ResourceDispatcherTest, MultipleRequests) { + // FIXME +} + +// Tests that the cancel method prevents other messages from being received +TEST_F(ResourceDispatcherTest, Cancel) { + // FIXME +} + +TEST_F(ResourceDispatcherTest, Cookies) { + // FIXME +} + +TEST_F(ResourceDispatcherTest, SerializedPostData) { + // FIXME +} + +// This class provides functionality to validate whether the ResourceDispatcher +// object honors the deferred loading contract correctly, i.e. if deferred +// loading is enabled it should queue up any responses received. If deferred +// loading is enabled/disabled in the context of a dispatched message, other +// queued messages should not be dispatched until deferred load is turned off. +class DeferredResourceLoadingTest : public ResourceDispatcherTest, + public ResourceLoaderBridge::Peer { + public: + DeferredResourceLoadingTest() + : defer_loading_(false) { + } + + virtual bool Send(IPC::Message* msg) { + delete msg; + return true; + } + + void InitMessages() { + set_defer_loading(true); + + ResourceResponseHead response_head; + response_head.status.set_status(URLRequestStatus::SUCCESS); + + IPC::Message* response_message = + new ViewMsg_Resource_ReceivedResponse(0, 0, response_head); + + dispatcher_->OnMessageReceived(*response_message); + + delete response_message; + + // Duplicate the shared memory handle so both the test and the callee can + // close their copy. + base::SharedMemoryHandle duplicated_handle; + EXPECT_TRUE(shared_handle_.ShareToProcess(base::GetCurrentProcessHandle(), + &duplicated_handle)); + + response_message = + new ViewMsg_Resource_DataReceived(0, 0, duplicated_handle, 100); + + dispatcher_->OnMessageReceived(*response_message); + + delete response_message; + + set_defer_loading(false); + } + + // ResourceLoaderBridge::Peer methods. + virtual void OnReceivedResponse( + const ResourceLoaderBridge::ResponseInfo& info, + bool content_filtered) { + EXPECT_EQ(defer_loading_, false); + set_defer_loading(true); + } + + virtual bool OnReceivedRedirect( + const GURL& new_url, + const ResourceLoaderBridge::ResponseInfo& info, + bool* has_new_first_party_for_cookies, + GURL* new_first_party_for_cookies) { + *has_new_first_party_for_cookies = false; + return true; + } + + virtual void OnReceivedData(const char* data, int len) { + EXPECT_EQ(defer_loading_, false); + set_defer_loading(false); + } + + virtual void OnUploadProgress(uint64 position, uint64 size) { + } + + virtual void OnCompletedRequest(const URLRequestStatus& status, + const std::string& security_info) { + } + + virtual GURL GetURLForDebugging() const { + return GURL(); + } + + protected: + virtual void SetUp() { + EXPECT_EQ(true, shared_handle_.Create(L"DeferredResourceLoaderTest", false, + false, 100)); + ResourceDispatcherTest::SetUp(); + } + + virtual void TearDown() { + shared_handle_.Close(); + ResourceDispatcherTest::TearDown(); + } + + private: + void set_defer_loading(bool defer) { + defer_loading_ = defer; + dispatcher_->SetDefersLoading(0, defer); + } + + bool defer_loading() const { + return defer_loading_; + } + + bool defer_loading_; + base::SharedMemory shared_handle_; +}; + +TEST_F(DeferredResourceLoadingTest, DeferredLoadTest) { + MessageLoop message_loop(MessageLoop::TYPE_IO); + + ResourceLoaderBridge* bridge = CreateBridge(); + + bridge->Start(this); + InitMessages(); + + // Dispatch deferred messages. + message_loop.RunAllPending(); + delete bridge; +} + diff --git a/chrome/common/resource_response.h b/chrome/common/resource_response.h new file mode 100644 index 0000000..1c9b766 --- /dev/null +++ b/chrome/common/resource_response.h @@ -0,0 +1,50 @@ +// Copyright (c) 2010 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. + +// See http://dev.chromium.org/developers/design-documents/multi-process-resource-loading + +#ifndef CHROME_COMMON_RESOURCE_RESPONSE_H_ +#define CHROME_COMMON_RESOURCE_RESPONSE_H_ + +#include <string> + +#include "base/ref_counted.h" +#include "googleurl/src/gurl.h" +#include "net/url_request/url_request_status.h" +#include "webkit/glue/resource_loader_bridge.h" + +// Parameters for a resource response header. +struct ResourceResponseHead + : webkit_glue::ResourceLoaderBridge::ResponseInfo { + ResourceResponseHead() : replace_extension_localization_templates(false) {} + + // The response status. + URLRequestStatus status; + + // Whether we should apply a filter to this resource that replaces + // localization templates with the appropriate localized strings. This is set + // for CSS resources used by extensions. + bool replace_extension_localization_templates; +}; + +// Parameters for a synchronous resource response. +struct SyncLoadResult : ResourceResponseHead { + // The final URL after any redirects. + GURL final_url; + + // The response data. + std::string data; +}; + +// Simple wrapper that refcounts ResourceResponseHead. +struct ResourceResponse : public base::RefCounted<ResourceResponse> { + ResourceResponseHead response_head; + + private: + friend class base::RefCounted<ResourceResponse>; + + ~ResourceResponse() {} +}; + +#endif // CHROME_COMMON_RESOURCE_RESPONSE_H_ diff --git a/chrome/common/result_codes.h b/chrome/common/result_codes.h new file mode 100644 index 0000000..6ca19b8 --- /dev/null +++ b/chrome/common/result_codes.h @@ -0,0 +1,63 @@ +// Copyright (c) 2010 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 CHROME_COMMON_RESULT_CODES_H_ +#define CHROME_COMMON_RESULT_CODES_H_ + +#include "base/process_util.h" + +// This file consolidates all the return codes for the browser and renderer +// process. The return code is the value that: +// a) is returned by main() or winmain(), or +// b) specified in the call for ExitProcess() or TerminateProcess(), or +// c) the exception value that causes a process to terminate. +// +// It is advisable to not use negative numbers because the Windows API returns +// it as an unsigned long and the exception values have high numbers. For +// example EXCEPTION_ACCESS_VIOLATION value is 0xC0000005. + +class ResultCodes { + public: + enum ExitCode { + NORMAL_EXIT = base::PROCESS_END_NORMAL_TERMINATION, + TASKMAN_KILL = base::PROCESS_END_KILLED_BY_USER, + HUNG = base::PROCESS_END_PROCESS_WAS_HUNG, + INVALID_CMDLINE_URL, // An invalid command line url was given. + SBOX_INIT_FAILED, // The sandbox could not be initialized. + GOOGLE_UPDATE_INIT_FAILED, // The Google Update client stub init failed. + GOOGLE_UPDATE_LAUNCH_FAILED,// Google Update could not launch chrome DLL. + BAD_PROCESS_TYPE, // The process is of an unknown type. + MISSING_PATH, // An critical chrome path is missing. + MISSING_DATA, // A critical chrome file is missing. + SHELL_INTEGRATION_FAILED, // Failed to make Chrome default browser. + MACHINE_LEVEL_INSTALL_EXISTS, // Machine level install exists + UNINSTALL_DELETE_FILE_ERROR,// Error while deleting shortcuts. + UNINSTALL_CHROME_ALIVE, // Uninstall detected another chrome instance. + UNINSTALL_NO_SURVEY, // Do not launch survey after uninstall. + UNINSTALL_USER_CANCEL, // The user changed her mind. + UNINSTALL_DELETE_PROFILE, // Delete profile as well during uninstall. + UNSUPPORTED_PARAM, // Command line parameter is not supported. + KILLED_BAD_MESSAGE, // A bad message caused the process termination. + IMPORTER_CANCEL, // The user canceled the browser import. + IMPORTER_HUNG, // Browser import hung and was killed. + RESPAWN_FAILED, // Trying to restart the browser we crashed. + + NORMAL_EXIT_EXP1, // The EXP1, EXP2, EXP3, EXP4 are generic codes + NORMAL_EXIT_EXP2, // used to communicate some simple outcome back + NORMAL_EXIT_EXP3, // to the process that launched us. This is + NORMAL_EXIT_EXP4, // used for experiments and the actual meaning + // depends on the experiment. + + NORMAL_EXIT_CANCEL, // For experiments this return code means that + // the user canceled causes the did_run "dr" + // signal to be reset so this chrome run does + // not count as active chrome usage. + + PROFILE_IN_USE, // The profile was in use on another host. + + EXIT_LAST_CODE // Last return code (keep it last). + }; +}; + +#endif // CHROME_COMMON_RESULT_CODES_H_ diff --git a/chrome/common/sandbox_init_wrapper.h b/chrome/common/sandbox_init_wrapper.h new file mode 100644 index 0000000..d1652d2 --- /dev/null +++ b/chrome/common/sandbox_init_wrapper.h @@ -0,0 +1,68 @@ +// Copyright (c) 2009 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 CHROME_COMMON_SANDBOX_INIT_WRAPPER_H_ +#define CHROME_COMMON_SANDBOX_INIT_WRAPPER_H_ + +// Wraps the sandbox initialization and platform variables to consolodate +// the code and reduce the number of platform ifdefs elsewhere. The POSIX +// version of this wrapper is basically empty. + +#include "build/build_config.h" + +#include <string> + +#include "base/basictypes.h" +#if defined(OS_WIN) +#include "sandbox/src/sandbox.h" +#endif + +class CommandLine; + +#if defined(OS_WIN) + +class SandboxInitWrapper { + public: + SandboxInitWrapper() : broker_services_(), target_services_() { } + // SetServices() needs to be called before InitializeSandbox() on Win32 with + // the info received from the chrome exe main. + void SetServices(sandbox::SandboxInterfaceInfo* sandbox_info); + sandbox::BrokerServices* BrokerServices() const { return broker_services_; } + sandbox::TargetServices* TargetServices() const { return target_services_; } + + // Initialize the sandbox for renderer and plug-in processes, depending on + // the command line flags. The browser process is not sandboxed. + // Returns true if the sandbox was initialized succesfully, false if an error + // occurred. If process_type isn't one that needs sandboxing true is always + // returned. + bool InitializeSandbox(const CommandLine& parsed_command_line, + const std::string& process_type); + private: + sandbox::BrokerServices* broker_services_; + sandbox::TargetServices* target_services_; + + DISALLOW_COPY_AND_ASSIGN(SandboxInitWrapper); +}; + +#elif defined(OS_POSIX) + +class SandboxInitWrapper { + public: + SandboxInitWrapper() { } + + // Initialize the sandbox for renderer and plug-in processes, depending on + // the command line flags. The browser process is not sandboxed. + // Returns true if the sandbox was initialized succesfully, false if an error + // occurred. If process_type isn't one that needs sandboxing true is always + // returned. + bool InitializeSandbox(const CommandLine& parsed_command_line, + const std::string& process_type); + + private: + DISALLOW_COPY_AND_ASSIGN(SandboxInitWrapper); +}; + +#endif + +#endif // CHROME_COMMON_SANDBOX_INIT_WRAPPER_H_ diff --git a/chrome/common/sandbox_init_wrapper_linux.cc b/chrome/common/sandbox_init_wrapper_linux.cc new file mode 100644 index 0000000..daf02d3 --- /dev/null +++ b/chrome/common/sandbox_init_wrapper_linux.cc @@ -0,0 +1,14 @@ +// Copyright (c) 2009 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 "chrome/common/sandbox_init_wrapper.h" + +#include "base/command_line.h" +#include "chrome/common/chrome_switches.h" + +bool SandboxInitWrapper::InitializeSandbox(const CommandLine& command_line, + const std::string& process_type) { + // TODO(port): Does Linux need to do anything here? + return true; +} diff --git a/chrome/common/sandbox_init_wrapper_mac.cc b/chrome/common/sandbox_init_wrapper_mac.cc new file mode 100644 index 0000000..998fe64 --- /dev/null +++ b/chrome/common/sandbox_init_wrapper_mac.cc @@ -0,0 +1,77 @@ +// Copyright (c) 2009 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 "chrome/common/sandbox_init_wrapper.h" + +#include "base/command_line.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/sandbox_mac.h" + +bool SandboxInitWrapper::InitializeSandbox(const CommandLine& command_line, + const std::string& process_type) { + if (command_line.HasSwitch(switches::kNoSandbox)) + return true; + + sandbox::SandboxProcessType sandbox_process_type; + FilePath allowed_dir; // Empty by default. + + if (process_type.empty()) { + // Browser process isn't sandboxed. + return true; + } else if (process_type == switches::kRendererProcess) { + if (command_line.HasSwitch(switches::kEnableExperimentalWebGL) && + command_line.HasSwitch(switches::kInProcessWebGL)) { + // TODO(kbr): this check seems to be necessary only on this + // platform because the sandbox is initialized later. Remove + // this once this flag is removed. + return true; + } else if (command_line.HasSwitch(switches::kInternalNaCl)) { + // Renderer process sandbox. If --internal_nacl is present then use the + // version of the renderer sandbox which allows Native Client to use Unix + // sockets. + // TODO(msneck): Remove the use of Unix sockets from Native Client and + // then get rid of the SANDBOX_TYPE_NACL_PLUGIN enum. + // See http://code.google.com/p/nativeclient/issues/detail?id=344 + sandbox_process_type = sandbox::SANDBOX_TYPE_NACL_PLUGIN; + } else { + sandbox_process_type = sandbox::SANDBOX_TYPE_RENDERER; + } + } else if (process_type == switches::kExtensionProcess) { + // Extension processes are just renderers [they use RenderMain()] with a + // different set of command line flags. + // If we ever get here it means something has changed in regards + // to the extension process mechanics and we should probably reexamine + // how we sandbox extension processes since they are no longer identical + // to renderers. + NOTREACHED(); + return true; + } else if (process_type == switches::kUtilityProcess) { + // Utility process sandbox. + sandbox_process_type = sandbox::SANDBOX_TYPE_UTILITY; + allowed_dir = FilePath::FromWStringHack( + command_line.GetSwitchValue(switches::kUtilityProcessAllowedDir)); + } else if (process_type == switches::kWorkerProcess) { + // Worker process sandbox. + sandbox_process_type = sandbox::SANDBOX_TYPE_WORKER; + } else if (process_type == switches::kNaClLoaderProcess) { + // Native Client sel_ldr (user untrusted code) sandbox. + sandbox_process_type = sandbox::SANDBOX_TYPE_NACL_LOADER; + } else if ((process_type == switches::kPluginProcess) || + (process_type == switches::kProfileImportProcess) || + (process_type == switches::kGpuProcess) || + (process_type == switches::kServiceProcess)) { + return true; + } else { + // Failsafe: If you hit an unreached here, is your new process type in need + // of sandboxing? + NOTREACHED(); + return true; + } + + // Warm up APIs before turning on the sandbox. + sandbox::SandboxWarmup(); + + // Actually sandbox the process. + return sandbox::EnableSandbox(sandbox_process_type, allowed_dir); +} diff --git a/chrome/common/sandbox_init_wrapper_win.cc b/chrome/common/sandbox_init_wrapper_win.cc new file mode 100644 index 0000000..5d4399a --- /dev/null +++ b/chrome/common/sandbox_init_wrapper_win.cc @@ -0,0 +1,33 @@ +// Copyright (c) 2009 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 "chrome/common/sandbox_init_wrapper.h" + +#include "base/command_line.h" +#include "chrome/common/chrome_switches.h" + +void SandboxInitWrapper::SetServices(sandbox::SandboxInterfaceInfo* info) { + if (info) { + broker_services_ = info->broker_services; + target_services_ = info->target_services; + } +} + +bool SandboxInitWrapper::InitializeSandbox(const CommandLine& command_line, + const std::string& process_type) { + if (command_line.HasSwitch(switches::kNoSandbox)) + return true; + if ((process_type == switches::kRendererProcess) || + (process_type == switches::kExtensionProcess) || + (process_type == switches::kWorkerProcess) || + (process_type == switches::kNaClLoaderProcess) || + (process_type == switches::kUtilityProcess) || + (process_type == switches::kPluginProcess && + command_line.HasSwitch(switches::kSafePlugins))) { + if (!target_services_) + return false; + target_services_->Init(); + } + return true; +} diff --git a/chrome/common/sandbox_mac.h b/chrome/common/sandbox_mac.h new file mode 100644 index 0000000..249eaa3 --- /dev/null +++ b/chrome/common/sandbox_mac.h @@ -0,0 +1,60 @@ +// Copyright (c) 2009 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 CHROME_COMMON_SANDBOX_MAC_H_ +#define CHROME_COMMON_SANDBOX_MAC_H_ + +#include "base/file_path.h" + +namespace sandbox { + +enum SandboxProcessType { + + SANDBOX_TYPE_FIRST_TYPE, // Placeholder to ease iteration. + + SANDBOX_TYPE_RENDERER = SANDBOX_TYPE_FIRST_TYPE, + + // The worker processes uses the most restrictive sandbox which has almost + // *everything* locked down. Only a couple of /System/Library/ paths and + // some other very basic operations (e.g., reading metadata to allow + // following symlinks) are permitted. + SANDBOX_TYPE_WORKER, + + // Utility process is as restrictive as the worker process except full access + // is allowed to one configurable directory. + SANDBOX_TYPE_UTILITY, + + // Native Client sandboxes. The plugin contains trusted code and the + // loader contains the user's untrusted code. + SANDBOX_TYPE_NACL_PLUGIN, + SANDBOX_TYPE_NACL_LOADER, + + SANDBOX_AFTER_TYPE_LAST_TYPE, // Placeholder to ease iteration. +}; + +// Warm up System APIs that empirically need to be accessed before the Sandbox +// is turned on. +void SandboxWarmup(); + +// Turns on the OS X sandbox for this process. +// |sandbox_type| - type of Sandbox to use. +// |allowed_dir| - directory to allow access to, currently the only sandbox +// profile that supports this is SANDBOX_TYPE_UTILITY . +// +// |allowed_dir| must be a "simple" string since it's placed as is in a regex +// i.e. it must not contain quotation characters, escaping or any characters +// that might have special meaning when blindly substituted into a regular +// expression - crbug.com/26492 . +// Returns true on success, false if an error occurred enabling the sandbox. +bool EnableSandbox(SandboxProcessType sandbox_type, + const FilePath& allowed_dir); + +// Convert provided path into a "canonical" path matching what the Sandbox +// expects i.e. one without symlinks. +// This path is not necessarily unique e.g. in the face of hardlinks. +void GetCanonicalSandboxPath(FilePath* path); + +} // namespace sandbox + +#endif // CHROME_COMMON_SANDBOX_MAC_H_ diff --git a/chrome/common/sandbox_mac.mm b/chrome/common/sandbox_mac.mm new file mode 100644 index 0000000..3d2985c --- /dev/null +++ b/chrome/common/sandbox_mac.mm @@ -0,0 +1,434 @@ +// Copyright (c) 2009 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 "chrome/common/sandbox_mac.h" + +#include "base/debug_util.h" + +#import <Cocoa/Cocoa.h> +extern "C" { +#include <sandbox.h> +} +#include <sys/param.h> + +#include "base/basictypes.h" +#include "base/command_line.h" +#include "base/file_util.h" +#include "base/mac_util.h" +#include "base/rand_util_c.h" +#include "base/scoped_cftyperef.h" +#include "base/scoped_nsautorelease_pool.h" +#include "base/string16.h" +#include "base/sys_info.h" +#include "base/sys_string_conversions.h" +#include "base/utf_string_conversions.h" +#include "chrome/common/chrome_switches.h" +#include "unicode/uchar.h" + +namespace { + +// Try to escape |c| as a "SingleEscapeCharacter" (\n, etc). If successful, +// returns true and appends the escape sequence to |dst|. +bool EscapeSingleChar(char c, std::string* dst) { + const char *append = NULL; + switch (c) { + case '\b': + append = "\\b"; + break; + case '\f': + append = "\\f"; + break; + case '\n': + append = "\\n"; + break; + case '\r': + append = "\\r"; + break; + case '\t': + append = "\\t"; + break; + case '\\': + append = "\\\\"; + break; + case '"': + append = "\\\""; + break; + } + + if (!append) { + return false; + } + + dst->append(append); + return true; +} + +} // namespace + +namespace sandbox { + +// Escape |str_utf8| for use in a plain string variable in a sandbox +// configuraton file. On return |dst| is set to the utf-8 encoded quoted +// output. +// Returns: true on success, false otherwise. +bool QuotePlainString(const std::string& str_utf8, std::string* dst) { + dst->clear(); + + const char* src = str_utf8.c_str(); + int32_t length = str_utf8.length(); + int32_t position = 0; + while (position < length) { + UChar32 c; + U8_NEXT(src, position, length, c); // Macro increments |position|. + DCHECK_GE(c, 0); + if (c < 0) + return false; + + if (c < 128) { // EscapeSingleChar only handles ASCII. + char as_char = static_cast<char>(c); + if (EscapeSingleChar(as_char, dst)) { + continue; + } + } + + if (c < 32 || c > 126) { + // Any characters that aren't printable ASCII get the \u treatment. + unsigned int as_uint = static_cast<unsigned int>(c); + StringAppendF(dst, "\\u%04X", as_uint); + continue; + } + + // If we got here we know that the character in question is strictly + // in the ASCII range so there's no need to do any kind of encoding + // conversion. + dst->push_back(static_cast<char>(c)); + } + return true; +} + +// Escape |str_utf8| for use in a regex literal in a sandbox +// configuraton file. On return |dst| is set to the utf-8 encoded quoted +// output. +// +// The implementation of this function is based on empirical testing of the +// OS X sandbox on 10.5.8 & 10.6.2 which is undocumented and subject to change. +// +// Note: If str_utf8 contains any characters < 32 || >125 then the function +// fails and false is returned. +// +// Returns: true on success, false otherwise. +bool QuoteStringForRegex(const std::string& str_utf8, std::string* dst) { + // Characters with special meanings in sandbox profile syntax. + const char regex_special_chars[] = { + '\\', + + // Metacharacters + '^', + '.', + '[', + ']', + '$', + '(', + ')', + '|', + + // Quantifiers + '*', + '+', + '?', + '{', + '}', + }; + + // Anchor regex at start of path. + dst->assign("^"); + + const char* src = str_utf8.c_str(); + int32_t length = str_utf8.length(); + int32_t position = 0; + while (position < length) { + UChar32 c; + U8_NEXT(src, position, length, c); // Macro increments |position|. + DCHECK_GE(c, 0); + if (c < 0) + return false; + + // The Mac sandbox regex parser only handles printable ASCII characters. + // 33 >= c <= 126 + if (c < 32 || c > 125) { + return false; + } + + for (size_t i = 0; i < arraysize(regex_special_chars); ++i) { + if (c == regex_special_chars[i]) { + dst->push_back('\\'); + break; + } + } + + dst->push_back(static_cast<char>(c)); + } + + // Make sure last element of path is interpreted as a directory. Leaving this + // off would allow access to files if they start with the same name as the + // directory. + dst->append("(/|$)"); + + return true; +} + +// Warm up System APIs that empirically need to be accessed before the Sandbox +// is turned on. +// This method is layed out in blocks, each one containing a separate function +// that needs to be warmed up. The OS version on which we found the need to +// enable the function is also noted. +// This function is tested on the following OS versions: +// 10.5.6, 10.6.0 +void SandboxWarmup() { + base::ScopedNSAutoreleasePool scoped_pool; + + { // CGColorSpaceCreateWithName(), CGBitmapContextCreate() - 10.5.6 + scoped_cftyperef<CGColorSpaceRef> rgb_colorspace( + CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB)); + + // Allocate a 1x1 image. + char data[4]; + scoped_cftyperef<CGContextRef> context( + CGBitmapContextCreate(data, 1, 1, 8, 1 * 4, + rgb_colorspace, + kCGImageAlphaPremultipliedFirst | + kCGBitmapByteOrder32Host)); + + // Load in the color profiles we'll need (as a side effect). + (void) mac_util::GetSRGBColorSpace(); + (void) mac_util::GetSystemColorSpace(); + + // CGColorSpaceCreateSystemDefaultCMYK - 10.6 + scoped_cftyperef<CGColorSpaceRef> cmyk_colorspace( + CGColorSpaceCreateWithName(kCGColorSpaceGenericCMYK)); + } + + { // [-NSColor colorUsingColorSpaceName] - 10.5.6 + NSColor* color = [NSColor controlTextColor]; + [color colorUsingColorSpaceName:NSCalibratedRGBColorSpace]; + } + + { // localtime() - 10.5.6 + time_t tv = {0}; + localtime(&tv); + } + + { // Gestalt() tries to read /System/Library/CoreServices/SystemVersion.plist + // on 10.5.6 + int32 tmp; + base::SysInfo::OperatingSystemVersionNumbers(&tmp, &tmp, &tmp); + } + + { // CGImageSourceGetStatus() - 10.6 + // Create a png with just enough data to get everything warmed up... + char png_header[] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}; + NSData* data = [NSData dataWithBytes:png_header + length:arraysize(png_header)]; + scoped_cftyperef<CGImageSourceRef> img( + CGImageSourceCreateWithData((CFDataRef)data, + NULL)); + CGImageSourceGetStatus(img); + } + + { // Native Client access to /dev/random. + GetUrandomFD(); + } +} + +// Turns on the OS X sandbox for this process. +bool EnableSandbox(SandboxProcessType sandbox_type, + const FilePath& allowed_dir) { + // Sanity - currently only SANDBOX_TYPE_UTILITY supports a directory being + // passed in. + if (sandbox_type != SANDBOX_TYPE_UTILITY) { + DCHECK(allowed_dir.empty()) + << "Only SANDBOX_TYPE_UTILITY allows a custom directory parameter."; + } + // We use a custom sandbox definition file to lock things down as + // tightly as possible. + // TODO(jeremy): Look at using include syntax to unify common parts of sandbox + // definition files. + NSString* sandbox_config_filename = nil; + bool allow_nacl_lines = false; + switch (sandbox_type) { + case SANDBOX_TYPE_RENDERER: + sandbox_config_filename = @"renderer"; + break; + case SANDBOX_TYPE_WORKER: + sandbox_config_filename = @"worker"; + break; + case SANDBOX_TYPE_UTILITY: + sandbox_config_filename = @"utility"; + break; + case SANDBOX_TYPE_NACL_PLUGIN: + // The Native Client plugin is a standard renderer sandbox with some + // additional lines to support use of Unix sockets. + // TODO(msneck): Remove the use of Unix sockets from Native Client and + // then remove the associated rules from chrome/renderer/renderer.sb. + // See http://code.google.com/p/nativeclient/issues/detail?id=344 + sandbox_config_filename = @"renderer"; + allow_nacl_lines = true; + break; + case SANDBOX_TYPE_NACL_LOADER: + // The Native Client loader is used for safeguarding the user's + // untrusted code within Native Client. + // TODO(msneck): Remove the use of Unix sockets from Native Client and + // then decide on an appropriate sandbox type for the untrusted code. + // This might simply mean removing the Unix socket rules from + // chrome/browser/nacl_loader.sb or it might mean sharing the + // sandbox configuration with SANDBOX_TYPE_WORKER. + // See http://code.google.com/p/nativeclient/issues/detail?id=344 + sandbox_config_filename = @"nacl_loader"; + break; + default: + NOTREACHED(); + return false; + } + + // Read in the sandbox profile and the common prefix file. + NSString* common_sandbox_prefix_path = + [mac_util::MainAppBundle() pathForResource:@"common" + ofType:@"sb"]; + NSString* common_sandbox_prefix_data = + [NSString stringWithContentsOfFile:common_sandbox_prefix_path + encoding:NSUTF8StringEncoding + error:NULL]; + + if (!common_sandbox_prefix_data) { + LOG(FATAL) << "Failed to find the sandbox profile on disk " + << [common_sandbox_prefix_path fileSystemRepresentation]; + return false; + } + + NSString* sandbox_profile_path = + [mac_util::MainAppBundle() pathForResource:sandbox_config_filename + ofType:@"sb"]; + NSString* sandbox_data = + [NSString stringWithContentsOfFile:sandbox_profile_path + encoding:NSUTF8StringEncoding + error:NULL]; + + if (!sandbox_data) { + LOG(FATAL) << "Failed to find the sandbox profile on disk " + << [sandbox_profile_path fileSystemRepresentation]; + return false; + } + + // Prefix sandbox_data with common_sandbox_prefix_data. + sandbox_data = + [common_sandbox_prefix_data stringByAppendingString:sandbox_data]; + + // Enable verbose logging if enabled on the command line. + // (see renderer.sb for details). + const CommandLine *command_line = CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch(switches::kEnableSandboxLogging)) { + sandbox_data = [sandbox_data + stringByReplacingOccurrencesOfString:@";ENABLE_LOGGING" + withString:@""]; + } + + // Enable Native Client lines if they are allowed. + if (allow_nacl_lines) { + sandbox_data = [sandbox_data + stringByReplacingOccurrencesOfString:@";NACL" + withString:@""]; + } + + if (!allowed_dir.empty()) { + // The sandbox only understands "real" paths. This resolving step is + // needed so the caller doesn't need to worry about things like /var + // being a link to /private/var (like in the paths CreateNewTempDirectory() + // returns). + FilePath allowed_dir_canonical(allowed_dir); + GetCanonicalSandboxPath(&allowed_dir_canonical); + + std::string allowed_dir_escaped; + if (!QuoteStringForRegex(allowed_dir_canonical.value(), + &allowed_dir_escaped)) { + LOG(FATAL) << "Regex string quoting failed " << allowed_dir.value(); + return false; + } + NSString* allowed_dir_escaped_ns = base::SysUTF8ToNSString( + allowed_dir_escaped.c_str()); + sandbox_data = [sandbox_data + stringByReplacingOccurrencesOfString:@";ENABLE_DIRECTORY_ACCESS" + withString:@""]; + sandbox_data = [sandbox_data + stringByReplacingOccurrencesOfString:@"DIR_TO_ALLOW_ACCESS" + withString:allowed_dir_escaped_ns]; + + } + + int32 major_version, minor_version, bugfix_version; + base::SysInfo::OperatingSystemVersionNumbers(&major_version, + &minor_version, &bugfix_version); + + if (major_version > 10 || (major_version == 10 && minor_version >= 6)) { + // 10.6-only Sandbox rules. + sandbox_data = [sandbox_data + stringByReplacingOccurrencesOfString:@";10.6_ONLY" + withString:@""]; + // Splice the path of the user's home directory into the sandbox profile + // (see renderer.sb for details). + // This code is in the 10.6-only block because the sandbox syntax we use + // for this "subdir" is only supported on 10.6. + // If we ever need this on pre-10.6 OSs then we'll have to rethink the + // surrounding sandbox syntax. + std::string home_dir = base::SysNSStringToUTF8(NSHomeDirectory()); + + FilePath home_dir_canonical(home_dir); + GetCanonicalSandboxPath(&home_dir_canonical); + + std::string home_dir_escaped; + if (!QuotePlainString(home_dir_canonical.value(), &home_dir_escaped)) { + LOG(FATAL) << "Sandbox string quoting failed"; + return false; + } + NSString* home_dir_escaped_ns = base::SysUTF8ToNSString(home_dir_escaped); + sandbox_data = [sandbox_data + stringByReplacingOccurrencesOfString:@"USER_HOMEDIR" + withString:home_dir_escaped_ns]; + } else if (major_version == 10 && minor_version < 6) { + // Sandbox rules only for versions before 10.6. + sandbox_data = [sandbox_data + stringByReplacingOccurrencesOfString:@";BEFORE_10.6" + withString:@""]; + } + + char* error_buff = NULL; + int error = sandbox_init([sandbox_data UTF8String], 0, &error_buff); + bool success = (error == 0 && error_buff == NULL); + LOG_IF(FATAL, !success) << "Failed to initialize sandbox: " + << error + << " " + << error_buff; + sandbox_free_error(error_buff); + return success; +} + +void GetCanonicalSandboxPath(FilePath* path) { + int fd = HANDLE_EINTR(open(path->value().c_str(), O_RDONLY)); + if (fd < 0) { + PLOG(FATAL) << "GetCanonicalSandboxPath() failed for: " + << path->value(); + return; + } + file_util::ScopedFD file_closer(&fd); + + FilePath::CharType canonical_path[MAXPATHLEN]; + if (HANDLE_EINTR(fcntl(fd, F_GETPATH, canonical_path)) != 0) { + PLOG(FATAL) << "GetCanonicalSandboxPath() failed for: " + << path->value(); + return; + } + + *path = FilePath(canonical_path); +} + +} // namespace sandbox diff --git a/chrome/common/sandbox_mac_diraccess_unittest.mm b/chrome/common/sandbox_mac_diraccess_unittest.mm new file mode 100644 index 0000000..f356453 --- /dev/null +++ b/chrome/common/sandbox_mac_diraccess_unittest.mm @@ -0,0 +1,250 @@ +// Copyright (c) 2009 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. + +#import <Cocoa/Cocoa.h> +#include <dirent.h> + +extern "C" { +#include <sandbox.h> +} + +#include "base/file_util.h" +#include "base/file_path.h" +#include "base/multiprocess_test.h" +#include "base/sys_string_conversions.h" +#include "base/utf_string_conversions.h" +#include "chrome/common/sandbox_mac.h" +#include "testing/gtest/include/gtest/gtest.h" + +// Tests to exercise directory-access-related restrictions of Mac sandbox. + +namespace sandbox { + +bool QuotePlainString(const std::string& str_utf8, std::string* dst); +bool QuoteStringForRegex(const std::string& str_utf8, std::string* dst); + +} // namespace sandbox + +namespace { + +static const char* kSandboxAccessPathKey = "sandbox_dir"; + +class MacDirAccessSandboxTest : public MultiProcessTest { + public: + bool CheckSandbox(std::string directory_to_try) { + setenv(kSandboxAccessPathKey, directory_to_try.c_str(), 1); + base::ProcessHandle child_process = SpawnChild(L"mac_sandbox_path_access"); + int code = -1; + if (!base::WaitForExitCode(child_process, &code)) { + LOG(WARNING) << "base::WaitForExitCode failed"; + return false; + } + return code == 0; + } +}; + +TEST_F(MacDirAccessSandboxTest, StringEscape) { + using sandbox::QuotePlainString; + + const struct string_escape_test_data { + const char* to_escape; + const char* escaped; + } string_escape_cases[] = { + {"", ""}, + {"\b\f\n\r\t\\\"", "\\b\\f\\n\\r\\t\\\\\\\""}, + {"/'", "/'"}, + {"sandwich", "sandwich"}, + {"(sandwich)", "(sandwich)"}, + {"^\u2135.\u2136$", "^\\u2135.\\u2136$"}, + }; + + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(string_escape_cases); ++i) { + std::string out; + std::string in(string_escape_cases[i].to_escape); + EXPECT_TRUE(QuotePlainString(in, &out)); + EXPECT_EQ(string_escape_cases[i].escaped, out); + } +} + +TEST_F(MacDirAccessSandboxTest, RegexEscape) { + using sandbox::QuoteStringForRegex; + + const std::string kSandboxEscapeSuffix("(/|$)"); + const struct regex_test_data { + const wchar_t *to_escape; + const char* escaped; + } regex_cases[] = { + {L"", ""}, + {L"/'", "/'"}, // / & ' characters don't need escaping. + {L"sandwich", "sandwich"}, + {L"(sandwich)", "\\(sandwich\\)"}, + }; + + // Check that all characters whose values are smaller than 32 [1F] are + // rejected by the regex escaping code. + { + std::string out; + char fail_string[] = {31, 0}; + char ok_string[] = {32, 0}; + EXPECT_FALSE(QuoteStringForRegex(fail_string, &out)); + EXPECT_TRUE(QuoteStringForRegex(ok_string, &out)); + } + + // Check that all characters whose values are larger than 126 [7E] are + // rejected by the regex escaping code. + { + std::string out; + EXPECT_TRUE(QuoteStringForRegex("}", &out)); // } == 0x7D == 125 + EXPECT_FALSE(QuoteStringForRegex("~", &out)); // ~ == 0x7E == 126 + EXPECT_FALSE(QuoteStringForRegex(WideToUTF8(L"^\u2135.\u2136$"), &out)); + } + + { + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(regex_cases); ++i) { + std::string out; + std::string in = WideToUTF8(regex_cases[i].to_escape); + EXPECT_TRUE(QuoteStringForRegex(in, &out)); + std::string expected("^"); + expected.append(regex_cases[i].escaped); + expected.append(kSandboxEscapeSuffix); + EXPECT_EQ(expected, out); + } + } + + { + std::string in_utf8("\\^.$|()[]*+?{}"); + std::string expected; + expected.push_back('^'); + for (size_t i = 0; i < in_utf8.length(); ++i) { + expected.push_back('\\'); + expected.push_back(in_utf8[i]); + } + expected.append(kSandboxEscapeSuffix); + + std::string out; + EXPECT_TRUE(QuoteStringForRegex(in_utf8, &out)); + EXPECT_EQ(expected, out); + + } +} + +// A class to handle auto-deleting a directory. +class ScopedDirectoryDelete { + public: + inline void operator()(FilePath* x) const { + if (x) { + file_util::Delete(*x, true); + } + } +}; + +typedef scoped_ptr_malloc<FilePath, ScopedDirectoryDelete> ScopedDirectory; + +TEST_F(MacDirAccessSandboxTest, SandboxAccess) { + FilePath tmp_dir; + ASSERT_TRUE(file_util::CreateNewTempDirectory("", &tmp_dir)); + // This step is important on OS X since the sandbox only understands "real" + // paths and the paths CreateNewTempDirectory() returns are empirically in + // /var which is a symlink to /private/var . + sandbox::GetCanonicalSandboxPath(&tmp_dir); + ScopedDirectory cleanup(&tmp_dir); + + const char* sandbox_dir_cases[] = { + "simple_dir_name", + "^hello++ $", // Regex. + "\\^.$|()[]*+?{}", // All regex characters. + }; + + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(sandbox_dir_cases); ++i) { + const char* sandbox_dir_name = sandbox_dir_cases[i]; + FilePath sandbox_dir = tmp_dir.Append(sandbox_dir_name); + ASSERT_TRUE(file_util::CreateDirectory(sandbox_dir)); + ScopedDirectory cleanup_sandbox(&sandbox_dir); + EXPECT_TRUE(CheckSandbox(sandbox_dir.value())); + } +} + +MULTIPROCESS_TEST_MAIN(mac_sandbox_path_access) { + char *sandbox_allowed_dir = getenv(kSandboxAccessPathKey); + if (!sandbox_allowed_dir) + return -1; + + // Build up a sandbox profile that only allows access to DIR_TO_ALLOW_ACCESS. + NSString *sandbox_profile = + @"(version 1)" \ + "(deny default)" \ + "(allow signal (target self))" \ + "(allow sysctl-read)" \ + "(allow file-read-metadata)" \ + "(allow file-read* file-write* (regex #\"DIR_TO_ALLOW_ACCESS\"))"; + + std::string allowed_dir(sandbox_allowed_dir); + std::string allowed_dir_escaped; + if (!sandbox::QuoteStringForRegex(allowed_dir, &allowed_dir_escaped)) { + LOG(ERROR) << "Regex string quoting failed " << allowed_dir; + return -1; + } + NSString* allowed_dir_escaped_ns = base::SysUTF8ToNSString( + allowed_dir_escaped.c_str()); + sandbox_profile = [sandbox_profile + stringByReplacingOccurrencesOfString:@"DIR_TO_ALLOW_ACCESS" + withString:allowed_dir_escaped_ns]; + // Enable Sandbox. + char* error_buff = NULL; + int error = sandbox_init([sandbox_profile UTF8String], 0, &error_buff); + if (error == -1) { + LOG(ERROR) << "Failed to Initialize Sandbox: " << error_buff; + return -1; + } + sandbox_free_error(error_buff); + + // Test Sandbox. + + // We should be able to list the contents of the sandboxed directory. + DIR *file_list = NULL; + file_list = opendir(sandbox_allowed_dir); + if (!file_list) { + PLOG(ERROR) << "Sandbox overly restrictive: call to opendir(" + << sandbox_allowed_dir + << ") failed"; + return -1; + } + closedir(file_list); + + // Test restrictions on accessing files. + FilePath allowed_dir_path(sandbox_allowed_dir); + FilePath allowed_file = allowed_dir_path.Append("ok_to_write"); + FilePath denied_file1 = allowed_dir_path.DirName().Append("cant_access"); + + // Try to write a file who's name has the same prefix as the directory we + // allow access to. + FilePath basename = allowed_dir_path.BaseName(); + std::string tricky_filename = basename.value() + "123"; + FilePath denied_file2 = allowed_dir_path.DirName().Append(tricky_filename); + + if (open(allowed_file.value().c_str(), O_WRONLY | O_CREAT) <= 0) { + PLOG(ERROR) << "Sandbox overly restrictive: failed to write (" + << allowed_file.value() + << ")"; + return -1; + } + + if (open(denied_file1.value().c_str(), O_WRONLY | O_CREAT) > 0) { + PLOG(ERROR) << "Sandbox breach: was able to write (" + << denied_file1.value() + << ")"; + return -1; + } + + if (open(denied_file2.value().c_str(), O_WRONLY | O_CREAT) > 0) { + PLOG(ERROR) << "Sandbox breach: was able to write (" + << denied_file2.value() + << ")"; + return -1; + } + + return 0; +} + +} // namespace diff --git a/chrome/common/sandbox_mac_fontloading_unittest.mm b/chrome/common/sandbox_mac_fontloading_unittest.mm new file mode 100644 index 0000000..a20d263 --- /dev/null +++ b/chrome/common/sandbox_mac_fontloading_unittest.mm @@ -0,0 +1,183 @@ +// Copyright (c) 2010 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. + +#import <Cocoa/Cocoa.h> + +#include "base/file_util.h" +#include "base/logging.h" +#include "base/scoped_cftyperef.h" +#include "base/scoped_ptr.h" +#include "base/shared_memory.h" +#include "chrome/common/font_loader_mac.h" +#include "chrome/common/sandbox_mac_unittest_helper.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +using sandboxtest::MacSandboxTest; + +bool CGFontFromFontContainer(ATSFontContainerRef container, CGFontRef* out) { + // Count the number of fonts that were loaded. + ItemCount fontCount = 0; + OSStatus err = ATSFontFindFromContainer(container, kATSOptionFlagsDefault, 0, + NULL, &fontCount); + + if (err != noErr || fontCount < 1) { + return false; + } + + // Load font from container. + ATSFontRef font_ref_ats = 0; + ATSFontFindFromContainer(container, kATSOptionFlagsDefault, 1, + &font_ref_ats, NULL); + + if (!font_ref_ats) { + return false; + } + + // Convert to cgFont. + CGFontRef font_ref_cg = CGFontCreateWithPlatformFont(&font_ref_ats); + + if (!font_ref_cg) { + return false; + } + + *out = font_ref_cg; + return true; +} + +class ScopedFontContainer { + public: + explicit ScopedFontContainer(ATSFontContainerRef ref) + : container_ref(ref) {} + + ~ScopedFontContainer() { + ATSFontDeactivate(container_ref, NULL, kATSOptionFlagsDefault); + } + + ATSFontContainerRef container_ref; +}; + +class FontLoadingTestCase : public sandboxtest::MacSandboxTestCase { + public: + FontLoadingTestCase() : font_data_length_(-1) {} + virtual bool BeforeSandboxInit(); + virtual bool SandboxedTest(); + private: + scoped_ptr<base::SharedMemory> font_shmem_; + size_t font_data_length_; +}; +REGISTER_SANDBOX_TEST_CASE(FontLoadingTestCase); + + +// Load raw font data into shared memory object. +bool FontLoadingTestCase::BeforeSandboxInit() { + std::string font_data; + if (!file_util::ReadFileToString(FilePath(test_data_.c_str()), &font_data)) { + LOG(ERROR) << "Failed to read font data from file (" << test_data_ << ")"; + return false; + } + + font_data_length_ = font_data.length(); + if (font_data_length_ <= 0) { + LOG(ERROR) << "No font data: " << font_data_length_; + return false; + } + + font_shmem_.reset(new base::SharedMemory); + if (!font_shmem_.get()) { + LOG(ERROR) << "Failed to create shared memory object."; + return false; + } + + if (!font_shmem_->Create(L"", false, false, font_data_length_)) { + LOG(ERROR) << "SharedMemory::Create failed"; + return false; + } + + if (!font_shmem_->Map(font_data_length_)) { + LOG(ERROR) << "SharedMemory::Map failed"; + return false; + } + + memcpy(font_shmem_->memory(), font_data.c_str(), font_data_length_); + if (!font_shmem_->Unmap()) { + LOG(ERROR) << "SharedMemory::Unmap failed"; + return false; + } + return true; +} + +bool FontLoadingTestCase::SandboxedTest() { + base::SharedMemoryHandle shmem_handle; + if (!font_shmem_->ShareToProcess(NULL, &shmem_handle)) { + LOG(ERROR) << "SharedMemory::ShareToProcess failed"; + return false; + } + + ATSFontContainerRef font_container; + if (!FontLoader::ATSFontContainerFromBuffer(shmem_handle, font_data_length_, + &font_container)) { + LOG(ERROR) << "Call to CreateCGFontFromBuffer() failed"; + return false; + } + + // Unload the font container when done. + ScopedFontContainer scoped_unloader(font_container); + + CGFontRef font_ref; + if (!CGFontFromFontContainer(font_container, &font_ref)) { + LOG(ERROR) << "CGFontFromFontContainer failed"; + return false; + } + + if (!font_ref) { + LOG(ERROR) << "Got NULL CGFontRef"; + return false; + } + scoped_cftyperef<CGFontRef> cgfont; + cgfont.reset(font_ref); + + const NSFont* nsfont = reinterpret_cast<const NSFont*>( + CTFontCreateWithGraphicsFont(cgfont.get(), 16.0, + NULL, NULL)); + if (!nsfont) { + LOG(ERROR) << "CTFontCreateWithGraphicsFont() failed"; + return false; + } + + // Do something with the font to make sure it's loaded. + CGFloat cap_height = [nsfont capHeight]; + + if (cap_height <= 0.0) { + LOG(ERROR) << "Got bad value for [NSFont capHeight] " << cap_height; + return false; + } + + return true; +} + +TEST_F(MacSandboxTest, FontLoadingTest) { + FilePath temp_file_path; + FILE* temp_file = file_util::CreateAndOpenTemporaryFile(&temp_file_path); + ASSERT_TRUE(temp_file); + file_util::ScopedFILE temp_file_closer(temp_file); + + base::SharedMemory font_data; + uint32 font_data_size; + NSFont* srcFont = [NSFont fontWithName:@"Geeza Pro" size:16.0]; + EXPECT_TRUE(FontLoader::LoadFontIntoBuffer(srcFont, + &font_data, &font_data_size)); + EXPECT_GT(font_data_size, 0U); + + file_util::WriteFileDescriptor(fileno(temp_file), + static_cast<const char *>(font_data.memory()), font_data_size); + + ASSERT_TRUE(RunTestInSandbox(sandbox::SANDBOX_TYPE_RENDERER, + "FontLoadingTestCase", temp_file_path.value().c_str())); + temp_file_closer.reset(); + ASSERT_TRUE(file_util::Delete(temp_file_path, false)); +} + +} // namespace diff --git a/chrome/common/sandbox_mac_system_access_unittest.mm b/chrome/common/sandbox_mac_system_access_unittest.mm new file mode 100644 index 0000000..382aa2c --- /dev/null +++ b/chrome/common/sandbox_mac_system_access_unittest.mm @@ -0,0 +1,96 @@ +// Copyright (c) 2010 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. + +#import <Cocoa/Cocoa.h> + +#include "base/logging.h" +#include "base/sys_string_conversions.h" +#include "chrome/common/sandbox_mac.h" +#include "chrome/common/sandbox_mac_unittest_helper.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +using sandboxtest::MacSandboxTest; + +//--------------------- Clipboard Sandboxing ---------------------- +// Test case for checking sandboxing of clipboard access. +class MacSandboxedClipboardTestCase : public sandboxtest::MacSandboxTestCase { + public: + MacSandboxedClipboardTestCase(); + virtual ~MacSandboxedClipboardTestCase(); + + virtual bool SandboxedTest(); + + virtual void SetTestData(const char* test_data); + private: + NSString* clipboard_name_; +}; + +REGISTER_SANDBOX_TEST_CASE(MacSandboxedClipboardTestCase); + +MacSandboxedClipboardTestCase::MacSandboxedClipboardTestCase() : + clipboard_name_(nil) {} + +MacSandboxedClipboardTestCase::~MacSandboxedClipboardTestCase() { + [clipboard_name_ release]; +} + +bool MacSandboxedClipboardTestCase::SandboxedTest() { + // Shouldn't be able to open the pasteboard in the sandbox. + + if ([clipboard_name_ length] == 0) { + LOG(ERROR) << "Clipboard name is empty"; + return false; + } + + NSPasteboard* pb = [NSPasteboard pasteboardWithName:clipboard_name_]; + if (pb != nil) { + LOG(ERROR) << "Was able to access named clipboard"; + return false; + } + + pb = [NSPasteboard generalPasteboard]; + if (pb != nil) { + LOG(ERROR) << "Was able to access system clipboard"; + return false; + } + + return true; +} + +void MacSandboxedClipboardTestCase::SetTestData(const char* test_data) { + clipboard_name_ = [base::SysUTF8ToNSString(test_data) retain]; +} + +TEST_F(MacSandboxTest, ClipboardAccess) { + NSPasteboard* pb = [NSPasteboard pasteboardWithUniqueName]; + EXPECT_EQ([[pb types] count], 0U); + + std::string pasteboard_name = base::SysNSStringToUTF8([pb name]); + EXPECT_TRUE(RunTestInAllSandboxTypes("MacSandboxedClipboardTestCase", + pasteboard_name.c_str())); + + // After executing the test, the clipboard should still be empty. + EXPECT_EQ([[pb types] count], 0U); +} + +//--------------------- File Access Sandboxing ---------------------- +// Test case for checking sandboxing of filesystem apis. +class MacSandboxedFileAccessTestCase : public sandboxtest::MacSandboxTestCase { + public: + virtual bool SandboxedTest(); +}; + +REGISTER_SANDBOX_TEST_CASE(MacSandboxedFileAccessTestCase); + +bool MacSandboxedFileAccessTestCase::SandboxedTest() { + return open("/etc/passwd", O_RDONLY) == -1; +} + +TEST_F(MacSandboxTest, FileAccess) { + EXPECT_TRUE(RunTestInAllSandboxTypes("MacSandboxedFileAccessTestCase", NULL)); +} + +} // namespace diff --git a/chrome/common/sandbox_mac_unittest_helper.h b/chrome/common/sandbox_mac_unittest_helper.h new file mode 100644 index 0000000..3e24009 --- /dev/null +++ b/chrome/common/sandbox_mac_unittest_helper.h @@ -0,0 +1,114 @@ +// Copyright (c) 2010 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 CHROME_COMMON_SANDBOX_MAC_UNITTEST_RUNNER_H_ +#define CHROME_COMMON_SANDBOX_MAC_UNITTEST_RUNNER_H_ + +#include "base/multiprocess_test.h" +#include "chrome/common/sandbox_mac.h" + +namespace sandboxtest { + +// Helpers for writing unit tests that runs in the context of the Mac sandbox. +// +// How to write a sandboxed test: +// 1. Create a class that inherits from MacSandboxTestCase and overrides +// it's functions to run code before or after the sandbox is initialised in a +// subprocess. +// 2. Register the class you just created with the REGISTER_SANDBOX_TEST_CASE() +// macro. +// 3. Write a test [using TEST_F()] that inherits from MacSandboxTest and call +// one of it's helper functions to launch the test. +// +// Example: +// class TestCaseThatRunsInSandboxedSubprocess : +// public sandboxtest::MacSandboxTestCase { +// public: +// virtual bool SandboxedTest() { +// .. test code that runs in sandbox goes here .. +// return true; // always succeed. +// } +// }; +// +// // Register the test case you just created. +// REGISTER_SANDBOX_TEST_CASE(TestCaseThatRunsInSandboxedSubprocess); +// +// TEST_F(MacSandboxTest, ATest) { +// EXPECT_TRUE(RunTestInAllSandboxTypes( +// "TestCaseThatRunsInSandboxedSubprocess", +// NULL)); +// } + +// Base test type with helper functions to spawn a subprocess that exercises +// a given test in the sandbox. +class MacSandboxTest : public MultiProcessTest { + public: + // Runs a test specified by |test_name| in a sandbox of the type specified + // by |sandbox_type|. |test_data| is a custom string that a test can pass + // to the child process runing in the sandbox. + // Returns true if the test passes, false if either of the functions in + // the corresponding MacSandboxTestCase return false. + bool RunTestInSandbox(sandbox::SandboxProcessType sandbox_type, + const char* test_name, + const char* test_data); + + // Runs the test specified by |test_name| in all the different sandbox types, + // one by one. + // Returns true if the test passes, false if either of the functions in + // the corresponding MacSandboxTestCase return false in any of the spawned + // processes. + bool RunTestInAllSandboxTypes(const char* test_name, + const char* test_data); +}; + +// Class to ease writing test cases that run inside the OS X sandbox. +// This class is instantiated in a subprocess, and allows you to run test code +// at various stages of execution. +// Note that you must register the subclass you create with the +// REGISTER_SANDBOX_TEST_CASE so it's visible to the test driver. +class MacSandboxTestCase { + public: + // Code that runs in the sandboxed subprocess before the sandbox is + // initialized. + // Returning false from this function will cause the entire test case to fail. + virtual bool BeforeSandboxInit() { return true; }; + + // Code that runs in the sandboxed subprocess when the sandbox has been + // enabled. + // Returning false from this function will cause the entire test case to fail. + virtual bool SandboxedTest() = 0; + + // The data that's passed in the |user_data| parameter of + // RunTest[s]InSandbox() is passed to this function. + virtual void SetTestData(const char* test_data) { test_data_ = test_data; } + + protected: + std::string test_data_; +}; + +// Plumbing to support the REGISTER_SANDBOX_TEST_CASE macro. +namespace internal { + +// Register a test case with a given name. +void AddSandboxTestCase(const char* test_name, MacSandboxTestCase* test_class); + +// Construction of this class causes a new entry to be placed in a global +// map. +template <class T> struct RegisterSandboxTest { + RegisterSandboxTest(const char* test_name) { + AddSandboxTestCase(test_name, new T); + } +}; + +#define REGISTER_SANDBOX_TEST_CASE(class_name) \ + namespace { \ + sandboxtest::internal::RegisterSandboxTest<class_name> \ + register_test##class_name(#class_name); \ + } // namespace + +} // namespace internal + +} // namespace sandboxtest + +#endif // CHROME_COMMON_SANDBOX_MAC_UNITTEST_RUNNER_H_ diff --git a/chrome/common/sandbox_mac_unittest_helper.mm b/chrome/common/sandbox_mac_unittest_helper.mm new file mode 100644 index 0000000..a14370f --- /dev/null +++ b/chrome/common/sandbox_mac_unittest_helper.mm @@ -0,0 +1,153 @@ +// Copyright (c) 2010 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 "chrome/common/sandbox_mac_unittest_helper.h" + +extern "C" { +#include <sandbox.h> +} + +#include "base/scoped_ptr.h" +#include "chrome/common/sandbox_mac.h" + +namespace { + +const char* kSandboxTypeKey = "CHROMIUM_SANDBOX_SANDBOX_TYPE"; +const char* kSandboxTestNameKey = "CHROMIUM_SANDBOX_TEST_NAME"; +const char* kTestDataKey = "CHROMIUM_SANDBOX_USER_DATA"; + +} // namespace + +namespace sandboxtest { + +// Support infrastructure for REGISTER_SANDBOX_TEST_CASE macro. +namespace internal { + +typedef std::map<std::string,MacSandboxTestCase*> SandboxTestMap; + +// A function that returns a common map from string -> test case class. +SandboxTestMap& GetSandboxTestMap() { + static SandboxTestMap test_map; + return test_map; +} + +void AddSandboxTestCase(const char* test_name, MacSandboxTestCase* test_class) { + SandboxTestMap& test_map = GetSandboxTestMap(); + if (test_map.find(test_name) != test_map.end()) { + LOG(ERROR) << "Trying to register duplicate test" << test_name; + NOTREACHED(); + } + test_map[test_name] = test_class; +} + +} // namespace internal + +bool MacSandboxTest:: RunTestInAllSandboxTypes(const char* test_name, + const char* test_data) { + // Go through all the sandbox types, and run the test case in each of them + // if one fails, abort. + for(int i = static_cast<int>(sandbox::SANDBOX_TYPE_FIRST_TYPE); + i < sandbox::SANDBOX_AFTER_TYPE_LAST_TYPE; + ++i) { + if (!RunTestInSandbox(static_cast<sandbox::SandboxProcessType>(i), + test_name, test_data)) { + LOG(ERROR) << "Sandboxed test (" << test_name << ")" << + "Failed in sandbox type " << i << + "user data: (" << test_data << ")"; + return false; + } + } + return true; +} + +bool MacSandboxTest::RunTestInSandbox(sandbox::SandboxProcessType sandbox_type, + const char* test_name, + const char* test_data) { + std::stringstream s; + s << static_cast<int>(static_cast<int>(sandbox_type)); + setenv(kSandboxTypeKey, s.str().c_str(), 1); + setenv(kSandboxTestNameKey, test_name, 1); + if (test_data) + setenv(kTestDataKey, test_data, 1); + + base::ProcessHandle child_process = SpawnChild(L"mac_sandbox_test_runner"); + int code = -1; + if (!base::WaitForExitCode(child_process, &code)) { + LOG(WARNING) << "base::WaitForExitCode failed"; + return false; + } + return code == 0; +} + +// Given a test name specified by |name| return that test case. +// If no test case is found for the given name, return NULL. +MacSandboxTestCase *SandboxTestForName(const char* name) { + using internal::SandboxTestMap; + using internal::GetSandboxTestMap; + + SandboxTestMap all_tests = GetSandboxTestMap(); + + SandboxTestMap::iterator it = all_tests.find(name); + if (it == all_tests.end()) { + LOG(ERROR) << "Couldn't find sandbox test case(" << name << ")"; + return NULL; + } + + return it->second; +} + +} // namespace sandboxtest + +namespace { + +// Main function for driver process that enables the sandbox and runs test +// code. +MULTIPROCESS_TEST_MAIN(mac_sandbox_test_runner) { + // Extract parameters. + char* sandbox_type_str = getenv(kSandboxTypeKey); + if (!sandbox_type_str) { + LOG(ERROR) << "Sandbox type not specified"; + return -1; + } + sandbox::SandboxProcessType sandbox_type = + static_cast<sandbox::SandboxProcessType>(atoi(sandbox_type_str)); + char* sandbox_test_name = getenv(kSandboxTestNameKey); + if (!sandbox_test_name) { + LOG(ERROR) << "Sandbox test name not specified"; + return -1; + } + + const char* test_data = getenv(kTestDataKey); + + // Find Test Function to run; + scoped_ptr<sandboxtest::MacSandboxTestCase> + test_case(sandboxtest::SandboxTestForName(sandbox_test_name)); + if (!test_case.get()) { + LOG(ERROR) << "Invalid sandbox test name (" << sandbox_test_name << ")"; + return -1; + } + test_case->SetTestData(test_data); + + // Run Test. + if (!test_case->BeforeSandboxInit()) { + LOG(ERROR) << sandbox_test_name << "Failed test before sandbox init"; + return -1; + } + + sandbox::SandboxWarmup(); + + if (!sandbox::EnableSandbox(sandbox_type, FilePath())) { + LOG(ERROR) << "Failed to initialize sandbox " << sandbox_type; + return -1; + } + + if (!test_case->SandboxedTest()) { + LOG(ERROR) << sandbox_test_name << "Failed sandboxed test"; + return -1; + } + + return 0; +} + +} // namespace diff --git a/chrome/common/sandbox_methods_linux.h b/chrome/common/sandbox_methods_linux.h new file mode 100644 index 0000000..254ba62 --- /dev/null +++ b/chrome/common/sandbox_methods_linux.h @@ -0,0 +1,24 @@ +// Copyright (c) 2009 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 CHROME_COMMON_SANDBOX_METHODS_LINUX_H_ +#define CHROME_COMMON_SANDBOX_METHODS_LINUX_H_ + +// This is a list of sandbox IPC methods which the renderer may send to the +// sandbox host. See http://code.google.com/p/chromium/LinuxSandboxIPC +// This isn't the full list, values < 32 are reserved for methods called from +// Skia. +class LinuxSandbox { + public: + enum Methods { + METHOD_GET_FONT_FAMILY_FOR_CHARS = 32, + METHOD_LOCALTIME = 33, + METHOD_GET_CHILD_WITH_INODE = 34, + METHOD_GET_STYLE_FOR_STRIKE = 35, + METHOD_MAKE_SHARED_MEMORY_SEGMENT = 36, + METHOD_MATCH_WITH_FALLBACK = 37, + }; +}; + +#endif // CHROME_COMMON_SANDBOX_METHODS_LINUX_H_ diff --git a/chrome/common/sandbox_policy.cc b/chrome/common/sandbox_policy.cc new file mode 100644 index 0000000..aa5249f --- /dev/null +++ b/chrome/common/sandbox_policy.cc @@ -0,0 +1,503 @@ +// Copyright (c) 2010 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 "chrome/common/sandbox_policy.h" + +#include <string> + +#include "app/win_util.h" +#include "base/command_line.h" +#include "base/debug_util.h" +#include "base/file_util.h" +#include "base/logging.h" +#include "base/path_service.h" +#include "base/process_util.h" +#include "base/registry.h" +#include "base/string_util.h" +#include "base/win_util.h" +#include "chrome/common/child_process_info.h" +#include "chrome/common/chrome_constants.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/debug_flags.h" +#include "sandbox/src/sandbox.h" + +static sandbox::BrokerServices* g_broker_services = NULL; + +namespace { + +// The DLLs listed here are known (or under strong suspicion) of causing crashes +// when they are loaded in the renderer. +const wchar_t* const kTroublesomeDlls[] = { + L"adialhk.dll", // Kaspersky Internet Security. + L"acpiz.dll", // Unknown. + L"avgrsstx.dll", // AVG 8. + L"btkeyind.dll", // Widcomm Bluetooth. + L"cmcsyshk.dll", // CMC Internet Security. + L"dockshellhook.dll", // Stardock Objectdock. + L"GoogleDesktopNetwork3.DLL", // Google Desktop Search v5. + L"fwhook.dll", // PC Tools Firewall Plus. + L"hookprocesscreation.dll", // Blumentals Program protector. + L"hookterminateapis.dll", // Blumentals and Cyberprinter. + L"hookprintapis.dll", // Cyberprinter. + L"imon.dll", // NOD32 Antivirus. + L"ioloHL.dll", // Iolo (System Mechanic). + L"kloehk.dll", // Kaspersky Internet Security. + L"lawenforcer.dll", // Spyware-Browser AntiSpyware (Spybro). + L"libdivx.dll", // DivX. + L"lvprcinj01.dll", // Logitech QuickCam. + L"madchook.dll", // Madshi (generic hooking library). + L"mdnsnsp.dll", // Bonjour. + L"moonsysh.dll", // Moon Secure Antivirus. + L"npdivx32.dll", // DivX. + L"npggNT.des", // GameGuard 2008. + L"npggNT.dll", // GameGuard (older). + L"oawatch.dll", // Online Armor. + L"pavhook.dll", // Panda Internet Security. + L"pavshook.dll", // Panda Antivirus. + L"pctavhook.dll", // PC Tools Antivirus. + L"pctgmhk.dll", // PC Tools Spyware Doctor. + L"prntrack.dll", // Pharos Systems. + L"radhslib.dll", // Radiant Naomi Internet Filter. + L"radprlib.dll", // Radiant Naomi Internet Filter. + L"rlhook.dll", // Trustware Bufferzone. + L"r3hook.dll", // Kaspersky Internet Security. + L"sahook.dll", // McAfee Site Advisor. + L"sbrige.dll", // Unknown. + L"sc2hook.dll", // Supercopier 2. + L"sguard.dll", // Iolo (System Guard). + L"smum32.dll", // Spyware Doctor version 6. + L"smumhook.dll", // Spyware Doctor version 5. + L"ssldivx.dll", // DivX. + L"syncor11.dll", // SynthCore Midi interface. + L"systools.dll", // Panda Antivirus. + L"tfwah.dll", // Threatfire (PC tools). + L"wblind.dll", // Stardock Object desktop. + L"wbhelp.dll", // Stardock Object desktop. + L"winstylerthemehelper.dll" // Tuneup utilities 2006. +}; + +enum PluginPolicyCategory { + PLUGIN_GROUP_TRUSTED, + PLUGIN_GROUP_UNTRUSTED, +}; + +// Returns the policy category for the plugin dll. +PluginPolicyCategory GetPolicyCategoryForPlugin( + const std::wstring& dll, + const std::wstring& list) { + std::wstring filename = FilePath(dll).BaseName().value(); + std::wstring plugin_dll = StringToLowerASCII(filename); + std::wstring trusted_plugins = StringToLowerASCII(list); + + size_t pos = 0; + size_t end_item = 0; + while (end_item != std::wstring::npos) { + end_item = list.find(L",", pos); + + size_t size_item = (end_item == std::wstring::npos) ? end_item : + end_item - pos; + std::wstring item = list.substr(pos, size_item); + if (!item.empty() && item == plugin_dll) + return PLUGIN_GROUP_TRUSTED; + + pos = end_item + 1; + } + + return PLUGIN_GROUP_UNTRUSTED; +} + +// Adds the policy rules for the path and path\ with the semantic |access|. +// If |children| is set to true, we need to add the wildcard rules to also +// apply the rule to the subfiles and subfolders. +bool AddDirectory(int path, const wchar_t* sub_dir, bool children, + sandbox::TargetPolicy::Semantics access, + sandbox::TargetPolicy* policy) { + std::wstring directory; + if (!PathService::Get(path, &directory)) + return false; + + if (sub_dir) { + file_util::AppendToPath(&directory, sub_dir); + file_util::AbsolutePath(&directory); + } + + sandbox::ResultCode result; + result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, access, + directory.c_str()); + if (result != sandbox::SBOX_ALL_OK) + return false; + + if (children) + file_util::AppendToPath(&directory, L"*"); + else + // Add the version of the path that ends with a separator. + file_util::AppendToPath(&directory, L""); + + result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, access, + directory.c_str()); + if (result != sandbox::SBOX_ALL_OK) + return false; + + return true; +} + +// Adds the policy rules for the path and path\* with the semantic |access|. +// We need to add the wildcard rules to also apply the rule to the subkeys. +bool AddKeyAndSubkeys(std::wstring key, + sandbox::TargetPolicy::Semantics access, + sandbox::TargetPolicy* policy) { + sandbox::ResultCode result; + result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY, access, + key.c_str()); + if (result != sandbox::SBOX_ALL_OK) + return false; + + key += L"\\*"; + result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY, access, + key.c_str()); + if (result != sandbox::SBOX_ALL_OK) + return false; + + return true; +} + +// Adds policy rules for unloaded the known dlls that cause chrome to crash. +// Eviction of injected DLLs is done by the sandbox so that the injected module +// does not get a chance to execute any code. +void AddDllEvictionPolicy(sandbox::TargetPolicy* policy) { + for (int ix = 0; ix != arraysize(kTroublesomeDlls); ++ix) { + // To minimize the list we only add an unload policy if the dll is also + // loaded in this process. All the injected dlls of interest do this. + if (::GetModuleHandleW(kTroublesomeDlls[ix])) { + LOG(INFO) << "dll to unload found: " << kTroublesomeDlls[ix]; + policy->AddDllToUnload(kTroublesomeDlls[ix]); + } + } +} + +// Adds the generic policy rules to a sandbox TargetPolicy. +bool AddGenericPolicy(sandbox::TargetPolicy* policy) { + sandbox::ResultCode result; + + // Add the policy for the pipes + result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, + sandbox::TargetPolicy::FILES_ALLOW_ANY, + L"\\??\\pipe\\chrome.*"); + if (result != sandbox::SBOX_ALL_OK) + return false; + + result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_NAMED_PIPES, + sandbox::TargetPolicy::NAMEDPIPES_ALLOW_ANY, + L"\\\\.\\pipe\\chrome.nacl.*"); + if (result != sandbox::SBOX_ALL_OK) + return false; + + // Add the policy for debug message only in debug +#ifndef NDEBUG + std::wstring debug_message; + if (!PathService::Get(chrome::DIR_APP, &debug_message)) + return false; + if (!win_util::ConvertToLongPath(debug_message, &debug_message)) + return false; + file_util::AppendToPath(&debug_message, L"debug_message.exe"); + result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_PROCESS, + sandbox::TargetPolicy::PROCESS_MIN_EXEC, + debug_message.c_str()); + if (result != sandbox::SBOX_ALL_OK) + return false; +#endif // NDEBUG + + return true; +} + +// Creates a sandbox without any restriction. +bool ApplyPolicyForTrustedPlugin(sandbox::TargetPolicy* policy) { + policy->SetJobLevel(sandbox::JOB_UNPROTECTED, 0); + policy->SetTokenLevel(sandbox::USER_UNPROTECTED, sandbox::USER_UNPROTECTED); + return true; +} + +// Creates a sandbox with the plugin running in a restricted environment. +// Only the "Users" and "Everyone" groups are enabled in the token. The User SID +// is disabled. +bool ApplyPolicyForUntrustedPlugin(sandbox::TargetPolicy* policy) { + policy->SetJobLevel(sandbox::JOB_UNPROTECTED, 0); + + sandbox::TokenLevel initial_token = sandbox::USER_UNPROTECTED; + if (win_util::GetWinVersion() > win_util::WINVERSION_XP) { + // On 2003/Vista the initial token has to be restricted if the main token + // is restricted. + initial_token = sandbox::USER_RESTRICTED_SAME_ACCESS; + } + policy->SetTokenLevel(initial_token, sandbox::USER_LIMITED); + policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW); + + if (!AddDirectory(base::DIR_TEMP, NULL, true, + sandbox::TargetPolicy::FILES_ALLOW_ANY, policy)) + return false; + + if (!AddDirectory(base::DIR_IE_INTERNET_CACHE, NULL, true, + sandbox::TargetPolicy::FILES_ALLOW_ANY, policy)) + return false; + + if (!AddDirectory(base::DIR_APP_DATA, NULL, true, + sandbox::TargetPolicy::FILES_ALLOW_READONLY, + policy)) + return false; + + if (!AddDirectory(base::DIR_PROFILE, NULL, false, /*not recursive*/ + sandbox::TargetPolicy::FILES_ALLOW_READONLY, + policy)) + return false; + + if (!AddDirectory(base::DIR_APP_DATA, L"Adobe", true, + sandbox::TargetPolicy::FILES_ALLOW_ANY, + policy)) + return false; + + if (!AddDirectory(base::DIR_APP_DATA, L"Macromedia", true, + sandbox::TargetPolicy::FILES_ALLOW_ANY, + policy)) + return false; + + if (!AddDirectory(base::DIR_LOCAL_APP_DATA, NULL, true, + sandbox::TargetPolicy::FILES_ALLOW_READONLY, + policy)) + return false; + + if (!AddKeyAndSubkeys(L"HKEY_CURRENT_USER\\SOFTWARE\\ADOBE", + sandbox::TargetPolicy::REG_ALLOW_ANY, + policy)) + return false; + + if (!AddKeyAndSubkeys(L"HKEY_CURRENT_USER\\SOFTWARE\\MACROMEDIA", + sandbox::TargetPolicy::REG_ALLOW_ANY, + policy)) + return false; + + if (win_util::GetWinVersion() >= win_util::WINVERSION_VISTA) { + if (!AddKeyAndSubkeys(L"HKEY_CURRENT_USER\\SOFTWARE\\AppDataLow", + sandbox::TargetPolicy::REG_ALLOW_ANY, + policy)) + return false; + + if (!AddDirectory(base::DIR_LOCAL_APP_DATA_LOW, NULL, true, + sandbox::TargetPolicy::FILES_ALLOW_ANY, + policy)) + return false; + + // DIR_APP_DATA is AppData\Roaming, but Adobe needs to do a directory + // listing in AppData directly, so we add a non-recursive policy for + // AppData itself. + if (!AddDirectory(base::DIR_APP_DATA, L"..", false, + sandbox::TargetPolicy::FILES_ALLOW_READONLY, + policy)) + return false; + } + + return true; +} + +// Adds the custom policy rules for a given plugin. |trusted_plugins| contains +// the comma separate list of plugin dll names that should not be sandboxed. +bool AddPolicyForPlugin(const CommandLine* cmd_line, + sandbox::TargetPolicy* policy) { + std::wstring plugin_dll = cmd_line-> + GetSwitchValue(switches::kPluginPath); + std::wstring trusted_plugins = CommandLine::ForCurrentProcess()-> + GetSwitchValue(switches::kTrustedPlugins); + // Add the policy for the pipes. + sandbox::ResultCode result = sandbox::SBOX_ALL_OK; + result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_NAMED_PIPES, + sandbox::TargetPolicy::NAMEDPIPES_ALLOW_ANY, + L"\\\\.\\pipe\\chrome.*"); + if (result != sandbox::SBOX_ALL_OK) { + NOTREACHED(); + return false; + } + + PluginPolicyCategory policy_category = + GetPolicyCategoryForPlugin(plugin_dll, trusted_plugins); + + switch (policy_category) { + case PLUGIN_GROUP_TRUSTED: + return ApplyPolicyForTrustedPlugin(policy); + case PLUGIN_GROUP_UNTRUSTED: + return ApplyPolicyForUntrustedPlugin(policy); + default: + NOTREACHED(); + break; + } + + return false; +} + +void AddPolicyForRenderer(sandbox::TargetPolicy* policy, + bool* on_sandbox_desktop) { + policy->SetJobLevel(sandbox::JOB_LOCKDOWN, 0); + + sandbox::TokenLevel initial_token = sandbox::USER_UNPROTECTED; + if (win_util::GetWinVersion() > win_util::WINVERSION_XP) { + // On 2003/Vista the initial token has to be restricted if the main + // token is restricted. + initial_token = sandbox::USER_RESTRICTED_SAME_ACCESS; + } + + policy->SetTokenLevel(initial_token, sandbox::USER_LOCKDOWN); + policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW); + + bool use_winsta = !CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableAltWinstation); + + if (sandbox::SBOX_ALL_OK == policy->SetAlternateDesktop(use_winsta)) { + *on_sandbox_desktop = true; + } else { + *on_sandbox_desktop = false; + DLOG(WARNING) << "Failed to apply desktop security to the renderer"; + } + + AddDllEvictionPolicy(policy); +} + +} // namespace + +namespace sandbox { + +void InitBrokerServices(sandbox::BrokerServices* broker_services) { + // TODO(abarth): DCHECK(CalledOnValidThread()); + // See <http://b/1287166>. + CHECK(broker_services); + CHECK(!g_broker_services); + broker_services->Init(); + g_broker_services = broker_services; +} + +base::ProcessHandle StartProcessWithAccess(CommandLine* cmd_line, + const FilePath& exposed_dir) { + base::ProcessHandle process = 0; + const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); + ChildProcessInfo::ProcessType type; + std::string type_str = cmd_line->GetSwitchValueASCII(switches::kProcessType); + if (type_str == switches::kRendererProcess) { + type = ChildProcessInfo::RENDER_PROCESS; + } else if (type_str == switches::kExtensionProcess) { + // Extensions are just renderers with another name. + type = ChildProcessInfo::RENDER_PROCESS; + } else if (type_str == switches::kPluginProcess) { + type = ChildProcessInfo::PLUGIN_PROCESS; + } else if (type_str == switches::kWorkerProcess) { + type = ChildProcessInfo::WORKER_PROCESS; + } else if (type_str == switches::kNaClLoaderProcess) { + type = ChildProcessInfo::NACL_LOADER_PROCESS; + } else if (type_str == switches::kUtilityProcess) { + type = ChildProcessInfo::UTILITY_PROCESS; + } else if (type_str == switches::kNaClBrokerProcess) { + type = ChildProcessInfo::NACL_BROKER_PROCESS; + } else if (type_str == switches::kGpuProcess) { + type = ChildProcessInfo::GPU_PROCESS; + } else { + NOTREACHED(); + return 0; + } + + bool in_sandbox = + (type != ChildProcessInfo::NACL_BROKER_PROCESS) && + !browser_command_line.HasSwitch(switches::kNoSandbox) && + (type != ChildProcessInfo::PLUGIN_PROCESS || + browser_command_line.HasSwitch(switches::kSafePlugins)) && + (type != ChildProcessInfo::GPU_PROCESS); +#if !defined (GOOGLE_CHROME_BUILD) + if (browser_command_line.HasSwitch(switches::kInProcessPlugins)) { + // In process plugins won't work if the sandbox is enabled. + in_sandbox = false; + } +#endif + if (browser_command_line.HasSwitch(switches::kEnableExperimentalWebGL) && + browser_command_line.HasSwitch(switches::kInProcessWebGL)) { + // In process WebGL won't work if the sandbox is enabled. + in_sandbox = false; + } + + // Propagate the Chrome Frame flag to sandboxed processes if present. + if (browser_command_line.HasSwitch(switches::kChromeFrame)) { + if (!cmd_line->HasSwitch(switches::kChromeFrame)) { + cmd_line->AppendSwitch(switches::kChromeFrame); + } + } + + bool child_needs_help = + DebugFlags::ProcessDebugFlags(cmd_line, type, in_sandbox); + + // Prefetch hints on windows: + // Using a different prefetch profile per process type will allow Windows + // to create separate pretetch settings for browser, renderer etc. + cmd_line->AppendLooseValue(StringPrintf(L"/prefetch:%d", type)); + + if (!in_sandbox) { + base::LaunchApp(*cmd_line, false, false, &process); + return process; + } + + sandbox::ResultCode result; + PROCESS_INFORMATION target = {0}; + sandbox::TargetPolicy* policy = g_broker_services->CreatePolicy(); + + bool on_sandbox_desktop = false; + if (type == ChildProcessInfo::PLUGIN_PROCESS) { + if (!AddPolicyForPlugin(cmd_line, policy)) + return 0; + } else { + AddPolicyForRenderer(policy, &on_sandbox_desktop); + + if (type_str != switches::kRendererProcess) { + // Hack for Google Desktop crash. Trick GD into not injecting its DLL into + // this subprocess. See + // http://code.google.com/p/chromium/issues/detail?id=25580 + cmd_line->AppendSwitchWithValue("ignored", " --type=renderer "); + } + } + + if (!exposed_dir.empty()) { + result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, + sandbox::TargetPolicy::FILES_ALLOW_ANY, + exposed_dir.ToWStringHack().c_str()); + if (result != sandbox::SBOX_ALL_OK) + return 0; + + FilePath exposed_files = exposed_dir.AppendASCII("*"); + result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, + sandbox::TargetPolicy::FILES_ALLOW_ANY, + exposed_files.ToWStringHack().c_str()); + if (result != sandbox::SBOX_ALL_OK) + return 0; + } + + if (!AddGenericPolicy(policy)) { + NOTREACHED(); + return 0; + } + + result = g_broker_services->SpawnTarget( + cmd_line->program().c_str(), + cmd_line->command_line_string().c_str(), + policy, &target); + policy->Release(); + + if (sandbox::SBOX_ALL_OK != result) + return 0; + + ResumeThread(target.hThread); + CloseHandle(target.hThread); + process = target.hProcess; + + // Help the process a little. It can't start the debugger by itself if + // the process is in a sandbox. + if (child_needs_help) + DebugUtil::SpawnDebuggerOnProcess(target.dwProcessId); + + return process; +} + +} // namespace sandbox diff --git a/chrome/common/sandbox_policy.h b/chrome/common/sandbox_policy.h new file mode 100644 index 0000000..46ab7bf --- /dev/null +++ b/chrome/common/sandbox_policy.h @@ -0,0 +1,26 @@ +// Copyright (c) 2006-2008 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 CHROME_COMMON_SANDBOX_POLICY_H_ +#define CHROME_COMMON_SANDBOX_POLICY_H_ + +#include "base/process.h" +#include "base/file_path.h" + +class CommandLine; + +namespace sandbox { + +class BrokerServices; + +void InitBrokerServices(sandbox::BrokerServices* broker_services); + +// Starts a sandboxed process with the given directory unsandboxed +// and returns a handle to it. +base::ProcessHandle StartProcessWithAccess(CommandLine* cmd_line, + const FilePath& exposed_dir); + +} // namespace sandbox + +#endif // CHROME_COMMON_SANDBOX_POLICY_H_ diff --git a/chrome/common/security_filter_peer.cc b/chrome/common/security_filter_peer.cc new file mode 100644 index 0000000..6448d20 --- /dev/null +++ b/chrome/common/security_filter_peer.cc @@ -0,0 +1,210 @@ +// Copyright (c) 2010 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 "chrome/common/security_filter_peer.h" + +#include "app/l10n_util.h" +#include "grit/generated_resources.h" +#include "net/base/net_errors.h" +#include "net/http/http_response_headers.h" + +SecurityFilterPeer::SecurityFilterPeer( + webkit_glue::ResourceLoaderBridge* resource_loader_bridge, + webkit_glue::ResourceLoaderBridge::Peer* peer) + : original_peer_(peer), + resource_loader_bridge_(resource_loader_bridge) { +} + +SecurityFilterPeer::~SecurityFilterPeer() { +} + +// static +SecurityFilterPeer* + SecurityFilterPeer::CreateSecurityFilterPeerForDeniedRequest( + ResourceType::Type resource_type, + webkit_glue::ResourceLoaderBridge::Peer* peer, + int os_error) { + // Create a filter for SSL and CERT errors. + switch (os_error) { + case net::ERR_SSL_PROTOCOL_ERROR: + case net::ERR_CERT_COMMON_NAME_INVALID: + case net::ERR_CERT_DATE_INVALID: + case net::ERR_CERT_AUTHORITY_INVALID: + case net::ERR_CERT_CONTAINS_ERRORS: + case net::ERR_CERT_NO_REVOCATION_MECHANISM: + case net::ERR_CERT_UNABLE_TO_CHECK_REVOCATION: + case net::ERR_CERT_REVOKED: + case net::ERR_CERT_INVALID: + case net::ERR_CERT_WEAK_SIGNATURE_ALGORITHM: + case net::ERR_INSECURE_RESPONSE: + if (ResourceType::IsFrame(resource_type)) + return CreateSecurityFilterPeerForFrame(peer, os_error); + // Any other content is entirely filtered-out. + return new ReplaceContentPeer(NULL, peer, std::string(), std::string()); + default: + // For other errors, we use our normal error handling. + return NULL; + } +} + +// static +SecurityFilterPeer* SecurityFilterPeer::CreateSecurityFilterPeerForFrame( + webkit_glue::ResourceLoaderBridge::Peer* peer, int os_error) { + // TODO(jcampan): use a different message when getting a phishing/malware + // error. + std::string html = StringPrintf( + "<html><meta charset='UTF-8'>" + "<body style='background-color:#990000;color:white;'>" + "%s</body></html>", + l10n_util::GetStringUTF8(IDS_UNSAFE_FRAME_MESSAGE).c_str()); + return new ReplaceContentPeer(NULL, peer, "text/html", html); +} + +void SecurityFilterPeer::OnUploadProgress(uint64 position, uint64 size) { + original_peer_->OnUploadProgress(position, size); +} + +bool SecurityFilterPeer::OnReceivedRedirect( + const GURL& new_url, + const webkit_glue::ResourceLoaderBridge::ResponseInfo& info, + bool* has_new_first_party_for_cookies, + GURL* new_first_party_for_cookies) { + NOTREACHED(); + return false; +} + +void SecurityFilterPeer::OnReceivedResponse( + const webkit_glue::ResourceLoaderBridge::ResponseInfo& info, + bool content_filtered) { + NOTREACHED(); +} + +void SecurityFilterPeer::OnReceivedData(const char* data, int len) { + NOTREACHED(); +} + +void SecurityFilterPeer::OnCompletedRequest(const URLRequestStatus& status, + const std::string& security_info) { + NOTREACHED(); +} + +GURL SecurityFilterPeer::GetURLForDebugging() const { + return original_peer_->GetURLForDebugging(); +} + +// static +void ProcessResponseInfo( + const webkit_glue::ResourceLoaderBridge::ResponseInfo& info_in, + webkit_glue::ResourceLoaderBridge::ResponseInfo* info_out, + const std::string& mime_type) { + DCHECK(info_out); + *info_out = info_in; + info_out->mime_type = mime_type; + // Let's create our own HTTP headers. + std::string raw_headers; + raw_headers.append("HTTP/1.1 200 OK"); + raw_headers.push_back('\0'); + // Don't cache the data we are serving, it is not the real data for that URL + // (if the filtered resource were to make it into the WebCore cache, then the + // same URL loaded in a safe scenario would still return the filtered + // resource). + raw_headers.append("cache-control: no-cache"); + raw_headers.push_back('\0'); + if (!mime_type.empty()) { + raw_headers.append("content-type: "); + raw_headers.append(mime_type); + raw_headers.push_back('\0'); + } + raw_headers.push_back('\0'); + net::HttpResponseHeaders* new_headers = + new net::HttpResponseHeaders(raw_headers); + info_out->headers = new_headers; +} + +//////////////////////////////////////////////////////////////////////////////// +// BufferedPeer + +BufferedPeer::BufferedPeer( + webkit_glue::ResourceLoaderBridge* resource_loader_bridge, + webkit_glue::ResourceLoaderBridge::Peer* peer, + const std::string& mime_type) + : SecurityFilterPeer(resource_loader_bridge, peer), + mime_type_(mime_type) { +} + +BufferedPeer::~BufferedPeer() { +} + +void BufferedPeer::OnReceivedResponse( + const webkit_glue::ResourceLoaderBridge::ResponseInfo& info, + bool response_filtered) { + ProcessResponseInfo(info, &response_info_, mime_type_); +} + +void BufferedPeer::OnReceivedData(const char* data, int len) { + data_.append(data, len); +} + +void BufferedPeer::OnCompletedRequest(const URLRequestStatus& status, + const std::string& security_info) { + // Make sure we delete ourselves at the end of this call. + scoped_ptr<BufferedPeer> this_deleter(this); + + // Give sub-classes a chance at altering the data. + if (status.status() != URLRequestStatus::SUCCESS || !DataReady()) { + // Pretend we failed to load the resource. + original_peer_->OnReceivedResponse(response_info_, true); + URLRequestStatus status(URLRequestStatus::CANCELED, net::ERR_ABORTED); + original_peer_->OnCompletedRequest(status, security_info); + return; + } + + original_peer_->OnReceivedResponse(response_info_, true); + if (!data_.empty()) + original_peer_->OnReceivedData(data_.data(), + static_cast<int>(data_.size())); + original_peer_->OnCompletedRequest(status, security_info); +} + +//////////////////////////////////////////////////////////////////////////////// +// ReplaceContentPeer + +ReplaceContentPeer::ReplaceContentPeer( + webkit_glue::ResourceLoaderBridge* resource_loader_bridge, + webkit_glue::ResourceLoaderBridge::Peer* peer, + const std::string& mime_type, + const std::string& data) + : SecurityFilterPeer(resource_loader_bridge, peer), + mime_type_(mime_type), + data_(data) { +} + +ReplaceContentPeer::~ReplaceContentPeer() { +} + +void ReplaceContentPeer::OnReceivedResponse( + const webkit_glue::ResourceLoaderBridge::ResponseInfo& info, + bool content_filtered) { + // Ignore this, we'll serve some alternate content in OnCompletedRequest. +} + +void ReplaceContentPeer::OnReceivedData(const char* data, int len) { + // Ignore this, we'll serve some alternate content in OnCompletedRequest. +} + +void ReplaceContentPeer::OnCompletedRequest(const URLRequestStatus& status, + const std::string& security_info) { + webkit_glue::ResourceLoaderBridge::ResponseInfo info; + ProcessResponseInfo(info, &info, mime_type_); + info.security_info = security_info; + info.content_length = static_cast<int>(data_.size()); + original_peer_->OnReceivedResponse(info, true); + if (!data_.empty()) + original_peer_->OnReceivedData(data_.data(), + static_cast<int>(data_.size())); + original_peer_->OnCompletedRequest(URLRequestStatus(), security_info); + + // The request processing is complete, we must delete ourselves. + delete this; +} diff --git a/chrome/common/security_filter_peer.h b/chrome/common/security_filter_peer.h new file mode 100644 index 0000000..4a44be3 --- /dev/null +++ b/chrome/common/security_filter_peer.h @@ -0,0 +1,122 @@ +// Copyright (c) 2010 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 CHROME_COMMON_SECURITY_FILTER_PEER_H__ +#define CHROME_COMMON_SECURITY_FILTER_PEER_H__ + +#include "webkit/glue/resource_loader_bridge.h" + +// The SecurityFilterPeer is a proxy to a +// webkit_glue::ResourceLoaderBridge::Peer instance. It is used to pre-process +// unsafe resources (such as mixed-content resource). +// Call the factory method CreateSecurityFilterPeer() to obtain an instance of +// SecurityFilterPeer based on the original Peer. +// NOTE: subclasses should insure they delete themselves at the end of the +// OnReceiveComplete call. +class SecurityFilterPeer : public webkit_glue::ResourceLoaderBridge::Peer { + public: + virtual ~SecurityFilterPeer(); + + static SecurityFilterPeer* CreateSecurityFilterPeerForDeniedRequest( + ResourceType::Type resource_type, + webkit_glue::ResourceLoaderBridge::Peer* peer, + int os_error); + + static SecurityFilterPeer* CreateSecurityFilterPeerForFrame( + webkit_glue::ResourceLoaderBridge::Peer* peer, + int os_error); + + // ResourceLoaderBridge::Peer methods. + virtual void OnUploadProgress(uint64 position, uint64 size); + virtual bool OnReceivedRedirect( + const GURL& new_url, + const webkit_glue::ResourceLoaderBridge::ResponseInfo& info, + bool* has_new_first_party_for_cookies, + GURL* new_first_party_for_cookies); + virtual void OnReceivedResponse( + const webkit_glue::ResourceLoaderBridge::ResponseInfo& info, + bool content_filtered); + virtual void OnReceivedData(const char* data, int len); + virtual void OnCompletedRequest(const URLRequestStatus& status, + const std::string& security_info); + virtual GURL GetURLForDebugging() const; + + protected: + SecurityFilterPeer(webkit_glue::ResourceLoaderBridge* resource_loader_bridge, + webkit_glue::ResourceLoaderBridge::Peer* peer); + + webkit_glue::ResourceLoaderBridge::Peer* original_peer_; + webkit_glue::ResourceLoaderBridge* resource_loader_bridge_; + + private: + DISALLOW_COPY_AND_ASSIGN(SecurityFilterPeer); +}; + +// The BufferedPeer reads all the data of the request into an internal buffer. +// Subclasses should implement DataReady() to process the data as necessary. +class BufferedPeer : public SecurityFilterPeer { + public: + BufferedPeer(webkit_glue::ResourceLoaderBridge* resource_loader_bridge, + webkit_glue::ResourceLoaderBridge::Peer* peer, + const std::string& mime_type); + virtual ~BufferedPeer(); + + // ResourceLoaderBridge::Peer Implementation. + virtual void OnReceivedResponse( + const webkit_glue::ResourceLoaderBridge::ResponseInfo& info, + bool content_filtered); + virtual void OnReceivedData(const char* data, int len); + virtual void OnCompletedRequest(const URLRequestStatus& status, + const std::string& security_info); + + protected: + // Invoked when the entire request has been processed before the data is sent + // to the original peer, giving an opportunity to subclasses to process the + // data in data_. If this method returns true, the data is fed to the + // original peer, if it returns false, an error is sent instead. + virtual bool DataReady() = 0; + + webkit_glue::ResourceLoaderBridge::ResponseInfo response_info_; + std::string data_; + + private: + std::string mime_type_; + + DISALLOW_COPY_AND_ASSIGN(BufferedPeer); +}; + +// The ReplaceContentPeer cancels the request and serves the provided data as +// content instead. +// TODO(jcampan): we do not as of now cancel the request, as we do not have +// access to the resource_loader_bridge in the SecurityFilterPeer factory +// method. For now the resource is still being fetched, but ignored, as once +// we have provided the replacement content, the associated pending request +// in ResourceDispatcher is removed and further OnReceived* notifications are +// ignored. +class ReplaceContentPeer : public SecurityFilterPeer { + public: + ReplaceContentPeer(webkit_glue::ResourceLoaderBridge* resource_loader_bridge, + webkit_glue::ResourceLoaderBridge::Peer* peer, + const std::string& mime_type, + const std::string& data); + virtual ~ReplaceContentPeer(); + + // ResourceLoaderBridge::Peer Implementation. + virtual void OnReceivedResponse( + const webkit_glue::ResourceLoaderBridge::ResponseInfo& info, + bool content_filtered); + void OnReceivedData(const char* data, int len); + void OnCompletedRequest(const URLRequestStatus& status, + const std::string& security_info); + + private: + webkit_glue::ResourceLoaderBridge::ResponseInfo response_info_; + std::string mime_type_; + std::string data_; + + DISALLOW_COPY_AND_ASSIGN(ReplaceContentPeer); +}; + +#endif // CHROME_COMMON_SECURITY_FILTER_PEER_H__ diff --git a/chrome/common/serialized_script_value.cc b/chrome/common/serialized_script_value.cc new file mode 100644 index 0000000..095f4e6 --- /dev/null +++ b/chrome/common/serialized_script_value.cc @@ -0,0 +1,37 @@ +// Copyright (c) 2010 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 "chrome/common/serialized_script_value.h" + +#include "third_party/WebKit/WebKit/chromium/public/WebString.h" + +using WebKit::WebSerializedScriptValue; + +SerializedScriptValue::SerializedScriptValue() + : is_null_(true), + is_invalid_(false) { +} + +SerializedScriptValue::SerializedScriptValue( + bool is_null, bool is_invalid, const string16& data) + : is_null_(is_null), + is_invalid_(is_invalid), + data_(data) { +} + +SerializedScriptValue::SerializedScriptValue( + const WebSerializedScriptValue& value) + : is_null_(value.isNull()), + is_invalid_(value.isNull() ? false : value.toString().isNull()), + data_(value.isNull() ? string16() + : static_cast<string16>(value.toString())) { +} + +SerializedScriptValue::operator WebSerializedScriptValue() const { + if (is_null_) + return WebSerializedScriptValue(); + if (is_invalid_) + return WebSerializedScriptValue::createInvalid(); + return WebSerializedScriptValue::fromString(data_); +} diff --git a/chrome/common/serialized_script_value.h b/chrome/common/serialized_script_value.h new file mode 100644 index 0000000..e464134 --- /dev/null +++ b/chrome/common/serialized_script_value.h @@ -0,0 +1,34 @@ +// Copyright (c) 2010 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 CHROME_COMMON_SERIALIZED_SCRIPT_VALUE_H_ +#define CHROME_COMMON_SERIALIZED_SCRIPT_VALUE_H_ + +#include "base/string16.h" +#include "third_party/WebKit/WebKit/chromium/public/WebSerializedScriptValue.h" + +class SerializedScriptValue { + public: + SerializedScriptValue(); + SerializedScriptValue(bool is_null, bool is_invalid, const string16& data); + explicit SerializedScriptValue(const WebKit::WebSerializedScriptValue& value); + + void set_is_null(bool is_null) { is_null_ = is_null; } + bool is_null() const { return is_null_; } + + void set_is_invalid(bool is_invalid) { is_invalid_ = is_invalid; } + bool is_invalid() const { return is_invalid_; } + + void set_data(const string16& data) { data_ = data; } + const string16& data() const { return data_; } + + operator WebKit::WebSerializedScriptValue() const; + + private: + bool is_null_; // Is this null? If so, none of the other properties are valid. + bool is_invalid_; // Is data_ valid? + string16 data_; // The wire string format of the serialized script value. +}; + +#endif // CHROME_COMMON_SERIALIZED_SCRIPT_VALUE_H_ diff --git a/chrome/common/socket_stream_dispatcher.cc b/chrome/common/socket_stream_dispatcher.cc new file mode 100644 index 0000000..97aed21 --- /dev/null +++ b/chrome/common/socket_stream_dispatcher.cc @@ -0,0 +1,215 @@ +// Copyright (c) 2009 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 "chrome/common/socket_stream_dispatcher.h" + +#include <vector> + +#include "base/id_map.h" +#include "base/ref_counted.h" +#include "chrome/common/child_thread.h" +#include "chrome/common/render_messages.h" +#include "chrome/common/net/socket_stream.h" +#include "googleurl/src/gurl.h" +#include "webkit/glue/websocketstreamhandle_bridge.h" +#include "webkit/glue/websocketstreamhandle_delegate.h" + +// IPCWebSocketStreamHandleBridge is owned by each SocketStreamHandle. +// It communicates with the main browser process via SocketStreamDispatcher. +class IPCWebSocketStreamHandleBridge + : public webkit_glue::WebSocketStreamHandleBridge { + public: + IPCWebSocketStreamHandleBridge( + ChildThread* child_thread, + WebKit::WebSocketStreamHandle* handle, + webkit_glue::WebSocketStreamHandleDelegate* delegate) + : socket_id_(chrome_common_net::kNoSocketId), + child_thread_(child_thread), + handle_(handle), + delegate_(delegate) {} + + // Returns the handle having given id or NULL if there is no such handle. + static IPCWebSocketStreamHandleBridge* FromSocketId(int id); + + // webkit_glue::WebSocketStreamHandleBridge methods. + virtual void Connect(const GURL& url); + virtual bool Send(const std::vector<char>& data); + virtual void Close(); + + // Called by SocketStreamDispatcher. + void OnConnected(int max_amount_send_allowed); + void OnSentData(int amount_sent); + void OnReceivedData(const std::vector<char>& data); + void OnClosed(); + + private: + virtual ~IPCWebSocketStreamHandleBridge(); + + void DoConnect(const GURL& url); + int socket_id_; + + ChildThread* child_thread_; + WebKit::WebSocketStreamHandle* handle_; + webkit_glue::WebSocketStreamHandleDelegate* delegate_; + + static IDMap<IPCWebSocketStreamHandleBridge> all_bridges; +}; + +IDMap<IPCWebSocketStreamHandleBridge> +IPCWebSocketStreamHandleBridge::all_bridges; + +/* static */ +IPCWebSocketStreamHandleBridge* IPCWebSocketStreamHandleBridge::FromSocketId( + int id) { + return all_bridges.Lookup(id); +} + +IPCWebSocketStreamHandleBridge::~IPCWebSocketStreamHandleBridge() { + DLOG(INFO) << "IPCWebSocketStreamHandleBridge destructor socket_id=" + << socket_id_; + if (socket_id_ != chrome_common_net::kNoSocketId) { + child_thread_->Send(new ViewHostMsg_Close(socket_id_)); + socket_id_ = chrome_common_net::kNoSocketId; + } +} + +void IPCWebSocketStreamHandleBridge::Connect(const GURL& url) { + DCHECK(child_thread_); + DLOG(INFO) << "Connect url=" << url; + child_thread_->message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(this, &IPCWebSocketStreamHandleBridge::DoConnect, + url)); +} + +bool IPCWebSocketStreamHandleBridge::Send( + const std::vector<char>& data) { + DLOG(INFO) << "Send data.size=" << data.size(); + if (child_thread_->Send( + new ViewHostMsg_SocketStream_SendData(socket_id_, data))) { + if (delegate_) + delegate_->WillSendData(handle_, &data[0], data.size()); + return true; + } + return false; +} + +void IPCWebSocketStreamHandleBridge::Close() { + DLOG(INFO) << "Close socket_id" << socket_id_; + child_thread_->Send(new ViewHostMsg_SocketStream_Close(socket_id_)); +} + +void IPCWebSocketStreamHandleBridge::OnConnected(int max_pending_send_allowed) { + DLOG(INFO) << "IPCWebSocketStreamHandleBridge::OnConnected socket_id=" + << socket_id_; + if (delegate_) + delegate_->DidOpenStream(handle_, max_pending_send_allowed); +} + +void IPCWebSocketStreamHandleBridge::OnSentData(int amount_sent) { + if (delegate_) + delegate_->DidSendData(handle_, amount_sent); +} + +void IPCWebSocketStreamHandleBridge::OnReceivedData( + const std::vector<char>& data) { + if (delegate_) + delegate_->DidReceiveData(handle_, &data[0], data.size()); +} + +void IPCWebSocketStreamHandleBridge::OnClosed() { + DLOG(INFO) << "IPCWebSocketStreamHandleBridge::OnClosed"; + if (socket_id_ != chrome_common_net::kNoSocketId) { + all_bridges.Remove(socket_id_); + socket_id_ = chrome_common_net::kNoSocketId; + } + if (delegate_) { + delegate_->DidClose(handle_); + } + delegate_ = NULL; + Release(); +} + +void IPCWebSocketStreamHandleBridge::DoConnect(const GURL& url) { + DCHECK(child_thread_); + DCHECK_EQ(socket_id_, chrome_common_net::kNoSocketId); + if (delegate_) + delegate_->WillOpenStream(handle_, url); + + socket_id_ = all_bridges.Add(this); + DCHECK_NE(socket_id_, chrome_common_net::kNoSocketId); + if (child_thread_->Send( + new ViewHostMsg_SocketStream_Connect(url, socket_id_))) { + DLOG(INFO) << "Connect socket_id=" << socket_id_; + AddRef(); // Released in OnClosed(). + // TODO(ukai): timeout to OnConnected. + } else { + LOG(ERROR) << "IPC SocketStream_Connect failed."; + OnClosed(); + } +} + +SocketStreamDispatcher::SocketStreamDispatcher() { +} + +/* static */ +webkit_glue::WebSocketStreamHandleBridge* +SocketStreamDispatcher::CreateBridge( + WebKit::WebSocketStreamHandle* handle, + webkit_glue::WebSocketStreamHandleDelegate* delegate) { + return new IPCWebSocketStreamHandleBridge( + ChildThread::current(), handle, delegate); +} + +bool SocketStreamDispatcher::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(SocketStreamDispatcher, msg) + IPC_MESSAGE_HANDLER(ViewMsg_SocketStream_Connected, OnConnected) + IPC_MESSAGE_HANDLER(ViewMsg_SocketStream_SentData, OnSentData) + IPC_MESSAGE_HANDLER(ViewMsg_SocketStream_ReceivedData, OnReceivedData) + IPC_MESSAGE_HANDLER(ViewMsg_SocketStream_Closed, OnClosed) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void SocketStreamDispatcher::OnConnected(int socket_id, + int max_pending_send_allowed) { + DLOG(INFO) << "SocketStreamDispatcher::OnConnected socket_id=" << socket_id + << " max_pending_send_allowed=" << max_pending_send_allowed; + IPCWebSocketStreamHandleBridge* bridge = + IPCWebSocketStreamHandleBridge::FromSocketId(socket_id); + if (bridge) + bridge->OnConnected(max_pending_send_allowed); + else + DLOG(ERROR) << "No SocketStreamHandleBridge for socket_id=" << socket_id; +} + +void SocketStreamDispatcher::OnSentData(int socket_id, int amount_sent) { + IPCWebSocketStreamHandleBridge* bridge = + IPCWebSocketStreamHandleBridge::FromSocketId(socket_id); + if (bridge) + bridge->OnSentData(amount_sent); + else + DLOG(ERROR) << "No SocketStreamHandleBridge for socket_id=" << socket_id; +} + +void SocketStreamDispatcher::OnReceivedData( + int socket_id, const std::vector<char>& data) { + IPCWebSocketStreamHandleBridge* bridge = + IPCWebSocketStreamHandleBridge::FromSocketId(socket_id); + if (bridge) + bridge->OnReceivedData(data); + else + DLOG(ERROR) << "No SocketStreamHandleBridge for socket_id=" << socket_id; +} + +void SocketStreamDispatcher::OnClosed(int socket_id) { + IPCWebSocketStreamHandleBridge* bridge = + IPCWebSocketStreamHandleBridge::FromSocketId(socket_id); + if (bridge) + bridge->OnClosed(); + else + DLOG(ERROR) << "No SocketStreamHandleBridge for socket_id=" << socket_id; +} diff --git a/chrome/common/socket_stream_dispatcher.h b/chrome/common/socket_stream_dispatcher.h new file mode 100644 index 0000000..8e3bbe4 --- /dev/null +++ b/chrome/common/socket_stream_dispatcher.h @@ -0,0 +1,38 @@ +// Copyright (c) 2009 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 CHROME_COMMON_SOCKET_STREAM_DISPATCHER_H_ +#define CHROME_COMMON_SOCKET_STREAM_DISPATCHER_H_ + +#include <vector> + +#include "base/basictypes.h" +#include "ipc/ipc_channel.h" +#include "ipc/ipc_message.h" +#include "webkit/glue/websocketstreamhandle_bridge.h" + +// Dispatches socket stream related messages sent to a child process from the +// main browser process. There is one instance per child process. Messages +// are dispatched on the main child thread. The RenderThread class +// creates an instance of SocketStreamDispatcher and delegates calls to it. +class SocketStreamDispatcher { + public: + SocketStreamDispatcher(); + ~SocketStreamDispatcher() {} + + static webkit_glue::WebSocketStreamHandleBridge* CreateBridge( + WebKit::WebSocketStreamHandle* handle, + webkit_glue::WebSocketStreamHandleDelegate* delegate); + bool OnMessageReceived(const IPC::Message& msg); + + private: + void OnConnected(int socket_id, int max_amount_send_allowed); + void OnSentData(int socket_id, int amount_sent); + void OnReceivedData(int socket_id, const std::vector<char>& data); + void OnClosed(int socket_id); + + DISALLOW_COPY_AND_ASSIGN(SocketStreamDispatcher); +}; + +#endif // CHROME_COMMON_SOCKET_STREAM_DISPATCHER_H_ diff --git a/chrome/common/socket_stream_dispatcher_dummy.cc b/chrome/common/socket_stream_dispatcher_dummy.cc new file mode 100644 index 0000000..ef49285 --- /dev/null +++ b/chrome/common/socket_stream_dispatcher_dummy.cc @@ -0,0 +1,18 @@ +// Copyright (c) 2006-2008 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 "chrome/common/socket_stream_dispatcher.h" + +#include "base/compiler_specific.h" + +// SocketStreamDispatcher ------------------------------------------------------ + +SocketStreamDispatcher::SocketStreamDispatcher() { +} + +// SocketStreamDispatcher implementation --------------------------------------- + +bool SocketStreamDispatcher::OnMessageReceived(const IPC::Message& message) { + return false; +} diff --git a/chrome/common/spellcheck_common.cc b/chrome/common/spellcheck_common.cc new file mode 100644 index 0000000..d1abfa5 --- /dev/null +++ b/chrome/common/spellcheck_common.cc @@ -0,0 +1,179 @@ +// Copyright (c) 2009 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 "chrome/common/spellcheck_common.h" + +#include "base/file_path.h" + +namespace SpellCheckCommon { + +static const struct { + // The language. + const char* language; + + // The corresponding language and region, used by the dictionaries. + const char* language_region; +} g_supported_spellchecker_languages[] = { + // Several languages are not to be included in the spellchecker list: + // th-TH, uk-UA + {"bg", "bg-BG"}, + {"ca", "ca-ES"}, + {"cs", "cs-CZ"}, + {"da", "da-DK"}, + {"de", "de-DE"}, + {"el", "el-GR"}, + {"en-AU", "en-AU"}, + {"en-GB", "en-GB"}, + {"en-US", "en-US"}, + {"es", "es-ES"}, + {"et", "et-EE"}, + {"fr", "fr-FR"}, + {"he", "he-IL"}, + {"hi", "hi-IN"}, + {"hr", "hr-HR"}, + {"hu", "hu-HU"}, + {"id", "id-ID"}, + {"it", "it-IT"}, + {"lt", "lt-LT"}, + {"lv", "lv-LV"}, + {"nb", "nb-NO"}, + {"nl", "nl-NL"}, + {"pl", "pl-PL"}, + {"pt-BR", "pt-BR"}, + {"pt-PT", "pt-PT"}, + {"ro", "ro-RO"}, + {"ru", "ru-RU"}, + {"sk", "sk-SK"}, + {"sl", "sl-SI"}, + {"sv", "sv-SE"}, + {"tr", "tr-TR"}, + {"vi", "vi-VN"}, +}; + +// This function returns the language-region version of language name. +// e.g. returns hi-IN for hi. +std::string GetSpellCheckLanguageRegion(const std::string& input_language) { + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(g_supported_spellchecker_languages); + ++i) { + if (g_supported_spellchecker_languages[i].language == input_language) { + return std::string( + g_supported_spellchecker_languages[i].language_region); + } + } + + return input_language; +} + +FilePath GetVersionedFileName(const std::string& input_language, + const FilePath& dict_dir) { + // The default dictionary version is 1-2. These versions have been augmented + // with additional words found by the translation team. + static const char kDefaultVersionString[] = "-1-2"; + + // The following dictionaries have either not been augmented with additional + // words (version 1-1) or have new words, as well as an upgraded dictionary + // as of Feb 2009 (version 1-3). + static const struct { + // The language input. + const char* language; + + // The corresponding version. + const char* version; + } special_version_string[] = { + {"en-AU", "-1-1"}, + {"en-GB", "-1-1"}, + {"es-ES", "-1-1"}, + {"nl-NL", "-1-1"}, + {"sv-SE", "-1-1"}, + {"he-IL", "-1-1"}, + {"el-GR", "-1-1"}, + {"hi-IN", "-1-1"}, + {"tr-TR", "-1-1"}, + {"et-EE", "-1-1"}, + {"fr-FR", "-2-0"}, // Hunspell fr(modern) 3.7 + Chromium delta. + {"lt-LT", "-1-3"}, + {"pl-PL", "-1-3"}, + {"hu-HU", "-2-0"}, + {"ro-RO", "-2-0"}, + {"ru-RU", "-2-0"}, + {"bg-BG", "-2-0"}, + }; + + // Generate the bdict file name using default version string or special + // version string, depending on the language. + std::string language = GetSpellCheckLanguageRegion(input_language); + std::string versioned_bdict_file_name(language + kDefaultVersionString + + ".bdic"); + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(special_version_string); ++i) { + if (language == special_version_string[i].language) { + versioned_bdict_file_name = + language + special_version_string[i].version + ".bdic"; + break; + } + } + + return dict_dir.AppendASCII(versioned_bdict_file_name); +} + +std::string GetCorrespondingSpellCheckLanguage(const std::string& language) { + // Look for exact match in the Spell Check language list. + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(g_supported_spellchecker_languages); + ++i) { + // First look for exact match in the language region of the list. + std::string spellcheck_language( + g_supported_spellchecker_languages[i].language); + if (spellcheck_language == language) + return language; + + // Next, look for exact match in the language_region part of the list. + std::string spellcheck_language_region( + g_supported_spellchecker_languages[i].language_region); + if (spellcheck_language_region == language) + return g_supported_spellchecker_languages[i].language; + } + + // Look for a match by comparing only language parts. All the 'en-RR' + // except for 'en-GB' exactly matched in the above loop, will match + // 'en-US'. This is not ideal because 'en-ZA', 'en-NZ' had + // better be matched with 'en-GB'. This does not handle cases like + // 'az-Latn-AZ' vs 'az-Arab-AZ', either, but we don't use 3-part + // locale ids with a script code in the middle, yet. + // TODO(jungshik): Add a better fallback. + std::string language_part(language, 0, language.find('-')); + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(g_supported_spellchecker_languages); + ++i) { + std::string spellcheck_language( + g_supported_spellchecker_languages[i].language_region); + if (spellcheck_language.substr(0, spellcheck_language.find('-')) == + language_part) { + return spellcheck_language; + } + } + + // No match found - return blank. + return std::string(); +} + + +void SpellCheckLanguages(std::vector<std::string>* languages) { + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(g_supported_spellchecker_languages); + ++i) { + languages->push_back(g_supported_spellchecker_languages[i].language); + } +} + + +std::string GetLanguageFromLanguageRegion(std::string input_language) { + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(g_supported_spellchecker_languages); + ++i) { + std::string language( + g_supported_spellchecker_languages[i].language_region); + if (language == input_language) + return std::string(g_supported_spellchecker_languages[i].language); + } + + return input_language; +} + +} // namespace SpellCheckCommon diff --git a/chrome/common/spellcheck_common.h b/chrome/common/spellcheck_common.h new file mode 100644 index 0000000..5c2569e --- /dev/null +++ b/chrome/common/spellcheck_common.h @@ -0,0 +1,36 @@ +// Copyright (c) 2009 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 CHROME_COMMON_SPELLCHECK_COMMON_H_ +#define CHROME_COMMON_SPELLCHECK_COMMON_H_ + +#include <string> +#include <vector> + +class FilePath; + +namespace SpellCheckCommon { + +// Max number of dictionary suggestions. +static const int kMaxSuggestions = 5; + +static const int kMaxAutoCorrectWordSize = 8; + +FilePath GetVersionedFileName(const std::string& input_language, + const FilePath& dict_dir); + +std::string GetCorrespondingSpellCheckLanguage(const std::string& language); + +// Get SpellChecker supported languages. +void SpellCheckLanguages(std::vector<std::string>* languages); + + +// This function returns ll (language code) from ll-RR where 'RR' (region +// code) is redundant. However, if the region code matters, it's preserved. +// That is, it returns 'hi' and 'en-GB' for 'hi-IN' and 'en-GB' respectively. +std::string GetLanguageFromLanguageRegion(std::string input_language); + +} // namespace SpellCheckCommon + +#endif // CHROME_COMMON_SPELLCHECK_COMMON_H_ diff --git a/chrome/common/sqlite_compiled_statement.cc b/chrome/common/sqlite_compiled_statement.cc new file mode 100644 index 0000000..f54182a --- /dev/null +++ b/chrome/common/sqlite_compiled_statement.cc @@ -0,0 +1,85 @@ +// Copyright (c) 2010 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 "chrome/common/sqlite_compiled_statement.h" + +#include "base/logging.h" +#include "base/stl_util-inl.h" +#include "chrome/common/sqlite_utils.h" +#include "third_party/sqlite/preprocessed/sqlite3.h" + +// SqliteStatementCache ------------------------------------------------------- + +SqliteStatementCache::~SqliteStatementCache() { + STLDeleteContainerPairSecondPointers(statements_.begin(), statements_.end()); + statements_.clear(); + db_ = NULL; +} + +void SqliteStatementCache::set_db(sqlite3* db) { + DCHECK(!db_) << "Setting the database twice"; + db_ = db; +} + +SQLStatement* SqliteStatementCache::InternalGetStatement(const char* func_name, + int func_number, + const char* sql) { + FuncID id; + id.name = func_name; + id.number = func_number; + + StatementMap::const_iterator found = statements_.find(id); + if (found != statements_.end()) + return found->second; + + if (!sql) + return NULL; // Don't create a new statement when we were not given SQL. + + // Create a new statement. + SQLStatement* statement = new SQLStatement(); + if (statement->prepare(db_, sql) != SQLITE_OK) { + const char* err_msg = sqlite3_errmsg(db_); + NOTREACHED() << "SQL preparation error for: " << err_msg; + return NULL; + } + + statements_[id] = statement; + return statement; +} + +bool SqliteStatementCache::FuncID::operator<(const FuncID& other) const { + // Compare numbers first since they are faster than strings and they are + // almost always unique. + if (number != other.number) + return number < other.number; + return name < other.name; +} + +// SqliteCompiledStatement ---------------------------------------------------- + +SqliteCompiledStatement::SqliteCompiledStatement(const char* func_name, + int func_number, + SqliteStatementCache& cache, + const char* sql) { + statement_ = cache.GetStatement(func_name, func_number, sql); +} + +SqliteCompiledStatement::~SqliteCompiledStatement() { + // Reset the statement so that subsequent callers don't get crap in it. + if (statement_) + statement_->reset(); +} + +SQLStatement& SqliteCompiledStatement::operator*() { + DCHECK(statement_) << "Should check is_valid() before using the statement."; + return *statement_; +} +SQLStatement* SqliteCompiledStatement::operator->() { + DCHECK(statement_) << "Should check is_valid() before using the statement."; + return statement_; +} +SQLStatement* SqliteCompiledStatement::statement() { + DCHECK(statement_) << "Should check is_valid() before using the statement."; + return statement_; +} diff --git a/chrome/common/sqlite_compiled_statement.h b/chrome/common/sqlite_compiled_statement.h new file mode 100644 index 0000000..01b7f1e --- /dev/null +++ b/chrome/common/sqlite_compiled_statement.h @@ -0,0 +1,135 @@ +// Copyright (c) 2006-2008 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 CHROME_COMMON_SQLITE_COMPILED_STATEMENT_H_ +#define CHROME_COMMON_SQLITE_COMPILED_STATEMENT_H_ + +#include <map> +#include <string> + +#include "base/basictypes.h" + +struct sqlite3; +class SQLStatement; + +// Stores a list of precompiled sql statements for a database. Each statement +// is given a unique name by the caller. +// +// Note: see comments on descructor. +class SqliteStatementCache { + public: + // You must call set_db before anything else if you use this constructor. + SqliteStatementCache() : db_(NULL) { + } + + explicit SqliteStatementCache(sqlite3* db) : db_(db) { + } + + // This object must be deleted before the sqlite connection it is associated + // with. Otherwise, sqlite seems to keep the file open because there are open + // statements. + ~SqliteStatementCache(); + + void set_db(sqlite3* db); + + // Creates or retrieves a cached SQL statement identified by the given + // (name, number) pair. + // + // The name and number can be anything the caller wants, but must uniquely + // identify the SQL. The caller must ensure that every call with the same + // number and name has the same SQL. + // + // In practice the number and name is supposed to be a file and line number. + // (See the SQLITE_UNIQUE_STATEMENT macro below.) Recommended practice is to + // use 0 for the function number if you are not using this scheme, and just + // use a name you like. + // + // On error, NULL is returned. Otherwise, the statement for the given SQL is + // returned. This pointer is cached and owned by this class. + // + // The caller should not cache this value since it may be used by others. + // The caller should reset the statement when it is complete so that + // subsequent callers do not get bound stuff. + SQLStatement* GetStatement(const char* func_name, + int func_number, + const char* sql) { + return InternalGetStatement(func_name, func_number, sql); + } + + // Returns the cached statement if it has already been created, or NULL if it + // has not. + SQLStatement* GetExistingStatement(const char* func_name, + int func_number) { + return InternalGetStatement(func_name, func_number, NULL); + } + + private: + // The key used for precompiled function lookup. + struct FuncID { + int number; + std::string name; + + // Used as a key in the map below, so we need this comparator. + bool operator<(const FuncID& other) const; + }; + + // Backend for GetStatement and GetExistingStatement. If sql is NULL, we will + // only look for an existing statement and return NULL if there is not a + // matching one. If it is non-NULL, we will create it if it doesn't exist. + SQLStatement* InternalGetStatement(const char* func_name, + int func_number, + const char* sql); + + sqlite3* db_; + + // This object owns the statement pointers, which it must manually free. + typedef std::map<FuncID, SQLStatement*> StatementMap; + StatementMap statements_; + + DISALLOW_COPY_AND_ASSIGN(SqliteStatementCache); +}; + +// Automatically creates or retrieves a statement from the given cache, and +// automatically resets the statement when it goes out of scope. +class SqliteCompiledStatement { + public: + // See SqliteStatementCache::GetStatement for a description of these args. + SqliteCompiledStatement(const char* func_name, + int func_number, + SqliteStatementCache& cache, + const char* sql); + ~SqliteCompiledStatement(); + + // Call to see if this statement is valid or not. Using this statement will + // segfault if it is not valid. + bool is_valid() const { return !!statement_; } + + // Allow accessing this object to be like accessing a statement for + // convenience. The caller must ensure the statement is_valid() before using + // these two functions. + SQLStatement& operator*(); + SQLStatement* operator->(); + SQLStatement* statement(); + + private: + // The sql statement if valid, NULL if not valid. This pointer is NOT owned + // by this class, it is owned by the statement cache object. + SQLStatement* statement_; + + DISALLOW_COPY_AND_ASSIGN(SqliteCompiledStatement); +}; + +// Creates a compiled statement that has a unique name based on the file and +// line number. Example: +// +// SQLITE_UNIQUE_STATEMENT(var_name, cache, "SELECT * FROM foo"); +// if (!var_name.is_valid()) +// return oops; +// var_name->bind_XXX( +// var_name->step(); +// ... +#define SQLITE_UNIQUE_STATEMENT(var_name, cache, sql) \ + SqliteCompiledStatement var_name(__FILE__, __LINE__, cache, sql) + +#endif // CHROME_COMMON_SQLITE_COMPILED_STATEMENT_H_ diff --git a/chrome/common/sqlite_utils.cc b/chrome/common/sqlite_utils.cc new file mode 100644 index 0000000..ed383be --- /dev/null +++ b/chrome/common/sqlite_utils.cc @@ -0,0 +1,508 @@ +// Copyright (c) 2010 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 "chrome/common/sqlite_utils.h" + +#include <list> + +#include "base/at_exit.h" +#include "base/file_path.h" +#include "base/lock.h" +#include "base/logging.h" +#include "base/singleton.h" +#include "base/stl_util-inl.h" +#include "base/string16.h" + +// The vanilla error handler implements the common fucntionality for all the +// error handlers. Specialized error handlers are expected to only override +// the Handler() function. +class VanillaSQLErrorHandler : public SQLErrorHandler { + public: + VanillaSQLErrorHandler() : error_(SQLITE_OK) { + } + virtual int GetLastError() const { + return error_; + } + protected: + int error_; +}; + +class DebugSQLErrorHandler: public VanillaSQLErrorHandler { + public: + virtual int HandleError(int error, sqlite3* db) { + error_ = error; + NOTREACHED() << "sqlite error " << error + << " db " << static_cast<void*>(db); + return error; + } +}; + +class ReleaseSQLErrorHandler : public VanillaSQLErrorHandler { + public: + virtual int HandleError(int error, sqlite3* db) { + error_ = error; + // Used to have a CHECK here. Got lots of crashes. + return error; + } +}; + +// The default error handler factory is also in charge of managing the +// lifetime of the error objects. This object is multi-thread safe. +class DefaultSQLErrorHandlerFactory : public SQLErrorHandlerFactory { + public: + ~DefaultSQLErrorHandlerFactory() { + STLDeleteContainerPointers(errors_.begin(), errors_.end()); + } + + virtual SQLErrorHandler* Make() { + SQLErrorHandler* handler; +#ifndef NDEBUG + handler = new DebugSQLErrorHandler; +#else + handler = new ReleaseSQLErrorHandler; +#endif // NDEBUG + AddHandler(handler); + return handler; + } + + private: + void AddHandler(SQLErrorHandler* handler) { + AutoLock lock(lock_); + errors_.push_back(handler); + } + + typedef std::list<SQLErrorHandler*> ErrorList; + ErrorList errors_; + Lock lock_; +}; + +SQLErrorHandlerFactory* GetErrorHandlerFactory() { + // TODO(cpu): Testing needs to override the error handler. + // Destruction of DefaultSQLErrorHandlerFactory handled by at_exit manager. + return Singleton<DefaultSQLErrorHandlerFactory>::get(); +} + +namespace sqlite_utils { + +int OpenSqliteDb(const FilePath& filepath, sqlite3** database) { +#if defined(OS_WIN) + // We want the default encoding to always be UTF-8, so we use the + // 8-bit version of open(). + return sqlite3_open(WideToUTF8(filepath.value()).c_str(), database); +#elif defined(OS_POSIX) + return sqlite3_open(filepath.value().c_str(), database); +#endif +} + +bool DoesSqliteTableExist(sqlite3* db, + const char* db_name, + const char* table_name) { + // sqlite doesn't allow binding parameters as table names, so we have to + // manually construct the sql + std::string sql("SELECT name FROM "); + if (db_name && db_name[0]) { + sql.append(db_name); + sql.push_back('.'); + } + sql.append("sqlite_master WHERE type='table' AND name=?"); + + SQLStatement statement; + if (statement.prepare(db, sql.c_str()) != SQLITE_OK) + return false; + + if (statement.bind_text(0, table_name) != SQLITE_OK) + return false; + + // we only care about if this matched a row, not the actual data + return sqlite3_step(statement.get()) == SQLITE_ROW; +} + +bool DoesSqliteColumnExist(sqlite3* db, + const char* database_name, + const char* table_name, + const char* column_name, + const char* column_type) { + SQLStatement s; + std::string sql; + sql.append("PRAGMA "); + if (database_name && database_name[0]) { + // optional database name specified + sql.append(database_name); + sql.push_back('.'); + } + sql.append("TABLE_INFO("); + sql.append(table_name); + sql.append(")"); + + if (s.prepare(db, sql.c_str()) != SQLITE_OK) + return false; + + while (s.step() == SQLITE_ROW) { + if (!s.column_string(1).compare(column_name)) { + if (column_type && column_type[0]) + return !s.column_string(2).compare(column_type); + return true; + } + } + return false; +} + +bool DoesSqliteTableHaveRow(sqlite3* db, const char* table_name) { + SQLStatement s; + std::string b; + b.append("SELECT * FROM "); + b.append(table_name); + + if (s.prepare(db, b.c_str()) != SQLITE_OK) + return false; + + return s.step() == SQLITE_ROW; +} + +} // namespace sqlite_utils + +SQLTransaction::SQLTransaction(sqlite3* db) : db_(db), began_(false) { +} + +SQLTransaction::~SQLTransaction() { + if (began_) { + Rollback(); + } +} + +int SQLTransaction::BeginCommand(const char* command) { + int rv = SQLITE_ERROR; + if (!began_ && db_) { + rv = sqlite3_exec(db_, command, NULL, NULL, NULL); + began_ = (rv == SQLITE_OK); + } + return rv; +} + +int SQLTransaction::EndCommand(const char* command) { + int rv = SQLITE_ERROR; + if (began_ && db_) { + rv = sqlite3_exec(db_, command, NULL, NULL, NULL); + began_ = (rv != SQLITE_OK); + } + return rv; +} + +SQLNestedTransactionSite::~SQLNestedTransactionSite() { + DCHECK(!top_transaction_); +} + +void SQLNestedTransactionSite::SetTopTransaction(SQLNestedTransaction* top) { + DCHECK(!top || !top_transaction_); + top_transaction_ = top; +} + +SQLNestedTransaction::SQLNestedTransaction(SQLNestedTransactionSite* site) + : SQLTransaction(site->GetSqlite3DB()), + needs_rollback_(false), + site_(site) { + DCHECK(site); + if (site->GetTopTransaction() == NULL) { + site->SetTopTransaction(this); + } +} + +SQLNestedTransaction::~SQLNestedTransaction() { + if (began_) { + Rollback(); + } + if (site_->GetTopTransaction() == this) { + site_->SetTopTransaction(NULL); + } +} + +int SQLNestedTransaction::BeginCommand(const char* command) { + DCHECK(db_); + DCHECK(site_ && site_->GetTopTransaction()); + if (!db_ || began_) { + return SQLITE_ERROR; + } + if (site_->GetTopTransaction() == this) { + int rv = sqlite3_exec(db_, command, NULL, NULL, NULL); + began_ = (rv == SQLITE_OK); + if (began_) { + site_->OnBegin(); + } + return rv; + } else { + if (site_->GetTopTransaction()->needs_rollback_) { + return SQLITE_ERROR; + } + began_ = true; + return SQLITE_OK; + } +} + +int SQLNestedTransaction::EndCommand(const char* command) { + DCHECK(db_); + DCHECK(site_ && site_->GetTopTransaction()); + if (!db_ || !began_) { + return SQLITE_ERROR; + } + if (site_->GetTopTransaction() == this) { + if (needs_rollback_) { + sqlite3_exec(db_, "ROLLBACK", NULL, NULL, NULL); + began_ = false; // reset so we don't try to rollback or call + // OnRollback() again + site_->OnRollback(); + return SQLITE_ERROR; + } else { + int rv = sqlite3_exec(db_, command, NULL, NULL, NULL); + began_ = (rv != SQLITE_OK); + if (strcmp(command, "ROLLBACK") == 0) { + began_ = false; // reset so we don't try to rollbck or call + // OnRollback() again + site_->OnRollback(); + } else { + DCHECK(strcmp(command, "COMMIT") == 0); + if (rv == SQLITE_OK) { + site_->OnCommit(); + } + } + return rv; + } + } else { + if (strcmp(command, "ROLLBACK") == 0) { + site_->GetTopTransaction()->needs_rollback_ = true; + } + began_ = false; + return SQLITE_OK; + } +} + +int SQLStatement::prepare(sqlite3* db, const char* sql, int sql_len) { + DCHECK(!stmt_); + int rv = sqlite3_prepare_v2(db, sql, sql_len, &stmt_, NULL); + if (rv != SQLITE_OK) { + SQLErrorHandler* error_handler = GetErrorHandlerFactory()->Make(); + return error_handler->HandleError(rv, db); + } + return rv; +} + +int SQLStatement::step() { + DCHECK(stmt_); + int status = sqlite3_step(stmt_); + if ((status == SQLITE_ROW) || (status == SQLITE_DONE)) + return status; + // We got a problem. + SQLErrorHandler* error_handler = GetErrorHandlerFactory()->Make(); + return error_handler->HandleError(status, db_handle()); +} + +int SQLStatement::reset() { + DCHECK(stmt_); + return sqlite3_reset(stmt_); +} + +sqlite_int64 SQLStatement::last_insert_rowid() { + DCHECK(stmt_); + return sqlite3_last_insert_rowid(db_handle()); +} + +int SQLStatement::changes() { + DCHECK(stmt_); + return sqlite3_changes(db_handle()); +} + +sqlite3* SQLStatement::db_handle() { + DCHECK(stmt_); + return sqlite3_db_handle(stmt_); +} + +int SQLStatement::bind_parameter_count() { + DCHECK(stmt_); + return sqlite3_bind_parameter_count(stmt_); +} + +int SQLStatement::bind_blob(int index, std::vector<unsigned char>* blob) { + if (blob) { + const void* value = blob->empty() ? NULL : &(*blob)[0]; + int len = static_cast<int>(blob->size()); + return bind_blob(index, value, len); + } else { + return bind_null(index); + } +} + +int SQLStatement::bind_blob(int index, const void* value, int value_len) { + return bind_blob(index, value, value_len, SQLITE_TRANSIENT); +} + +int SQLStatement::bind_blob(int index, const void* value, int value_len, + Function dtor) { + DCHECK(stmt_); + return sqlite3_bind_blob(stmt_, index + 1, value, value_len, dtor); +} + +int SQLStatement::bind_double(int index, double value) { + DCHECK(stmt_); + return sqlite3_bind_double(stmt_, index + 1, value); +} + +int SQLStatement::bind_bool(int index, bool value) { + DCHECK(stmt_); + return sqlite3_bind_int(stmt_, index + 1, value); +} + +int SQLStatement::bind_int(int index, int value) { + DCHECK(stmt_); + return sqlite3_bind_int(stmt_, index + 1, value); +} + +int SQLStatement::bind_int64(int index, sqlite_int64 value) { + DCHECK(stmt_); + return sqlite3_bind_int64(stmt_, index + 1, value); +} + +int SQLStatement::bind_null(int index) { + DCHECK(stmt_); + return sqlite3_bind_null(stmt_, index + 1); +} + +int SQLStatement::bind_text(int index, const char* value, int value_len, + Function dtor) { + DCHECK(stmt_); + return sqlite3_bind_text(stmt_, index + 1, value, value_len, dtor); +} + +int SQLStatement::bind_text16(int index, const char16* value, int value_len, + Function dtor) { + DCHECK(stmt_); + value_len *= sizeof(char16); + return sqlite3_bind_text16(stmt_, index + 1, value, value_len, dtor); +} + +int SQLStatement::bind_value(int index, const sqlite3_value* value) { + DCHECK(stmt_); + return sqlite3_bind_value(stmt_, index + 1, value); +} + +int SQLStatement::column_count() { + DCHECK(stmt_); + return sqlite3_column_count(stmt_); +} + +int SQLStatement::column_type(int index) { + DCHECK(stmt_); + return sqlite3_column_type(stmt_, index); +} + +const void* SQLStatement::column_blob(int index) { + DCHECK(stmt_); + return sqlite3_column_blob(stmt_, index); +} + +bool SQLStatement::column_blob_as_vector(int index, + std::vector<unsigned char>* blob) { + DCHECK(stmt_); + const void* p = column_blob(index); + size_t len = column_bytes(index); + blob->resize(len); + if (blob->size() != len) { + return false; + } + if (len > 0) + memcpy(&(blob->front()), p, len); + return true; +} + +bool SQLStatement::column_blob_as_string(int index, std::string* blob) { + DCHECK(stmt_); + const void* p = column_blob(index); + size_t len = column_bytes(index); + blob->resize(len); + if (blob->size() != len) { + return false; + } + blob->assign(reinterpret_cast<const char*>(p), len); + return true; +} + +int SQLStatement::column_bytes(int index) { + DCHECK(stmt_); + return sqlite3_column_bytes(stmt_, index); +} + +int SQLStatement::column_bytes16(int index) { + DCHECK(stmt_); + return sqlite3_column_bytes16(stmt_, index); +} + +double SQLStatement::column_double(int index) { + DCHECK(stmt_); + return sqlite3_column_double(stmt_, index); +} + +bool SQLStatement::column_bool(int index) { + DCHECK(stmt_); + return sqlite3_column_int(stmt_, index) ? true : false; +} + +int SQLStatement::column_int(int index) { + DCHECK(stmt_); + return sqlite3_column_int(stmt_, index); +} + +sqlite_int64 SQLStatement::column_int64(int index) { + DCHECK(stmt_); + return sqlite3_column_int64(stmt_, index); +} + +const char* SQLStatement::column_text(int index) { + DCHECK(stmt_); + return reinterpret_cast<const char*>(sqlite3_column_text(stmt_, index)); +} + +bool SQLStatement::column_string(int index, std::string* str) { + DCHECK(stmt_); + DCHECK(str); + const char* s = column_text(index); + str->assign(s ? s : std::string()); + return s != NULL; +} + +std::string SQLStatement::column_string(int index) { + std::string str; + column_string(index, &str); + return str; +} + +const char16* SQLStatement::column_text16(int index) { + DCHECK(stmt_); + return static_cast<const char16*>(sqlite3_column_text16(stmt_, index)); +} + +bool SQLStatement::column_string16(int index, string16* str) { + DCHECK(stmt_); + DCHECK(str); + const char* s = column_text(index); + str->assign(s ? UTF8ToUTF16(s) : string16()); + return (s != NULL); +} + +string16 SQLStatement::column_string16(int index) { + string16 str; + column_string16(index, &str); + return str; +} + +bool SQLStatement::column_wstring(int index, std::wstring* str) { + DCHECK(stmt_); + DCHECK(str); + const char* s = column_text(index); + str->assign(s ? UTF8ToWide(s) : std::wstring()); + return (s != NULL); +} + +std::wstring SQLStatement::column_wstring(int index) { + std::wstring wstr; + column_wstring(index, &wstr); + return wstr; +} diff --git a/chrome/common/sqlite_utils.h b/chrome/common/sqlite_utils.h new file mode 100644 index 0000000..f7351a2 --- /dev/null +++ b/chrome/common/sqlite_utils.h @@ -0,0 +1,399 @@ +// Copyright (c) 2010 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 CHROME_COMMON_SQLITE_UTILS_H_ +#define CHROME_COMMON_SQLITE_UTILS_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/scoped_ptr.h" +#include "base/string16.h" +#include "base/utf_string_conversions.h" +#include "third_party/sqlite/preprocessed/sqlite3.h" + +// forward declarations of classes defined here +class FilePath; +class SQLTransaction; +class SQLNestedTransaction; +class SQLNestedTransactionSite; +class scoped_sqlite3_stmt_ptr; +class SQLStatement; + +//------------------------------------------------------------------------------ +// Interface to be implemented by objects that can handle exceptional sqlite +// conditions. This way client code can focus on handling normal condtions. +//------------------------------------------------------------------------------ +class SQLErrorHandler { + public: + virtual ~SQLErrorHandler() {} + // Handle a sqlite error. |error| is the return code an of sqlite operation + // which is considered an error. This handler is free to try repair, notify + // someone or even break into the debugger depending on the situation. + virtual int HandleError(int error, sqlite3* db) = 0; + // Returns the last value of |error| passed to HandleError. + virtual int GetLastError() const = 0; +}; + +//------------------------------------------------------------------------------ +// The factory interface is used to create the different error handling +// strategies for debug, release and for diagnostic mode. +//------------------------------------------------------------------------------ +class SQLErrorHandlerFactory { + public: + virtual ~SQLErrorHandlerFactory() {} + virtual SQLErrorHandler* Make() = 0; +}; + +//------------------------------------------------------------------------------ +// A wrapper for sqlite transactions that rollsback when the wrapper +// goes out of scope if the caller has not already called Commit or Rollback. +// Note: the constructor does NOT Begin a transaction. +//------------------------------------------------------------------------------ +class SQLTransaction { + public: + explicit SQLTransaction(sqlite3* db); + virtual ~SQLTransaction(); + + int Begin() { + // By default, we BEGIN IMMEDIATE to establish file locks at the + // onset of a transaction. This avoids SQLITE_BUSY errors, without + // waiting for the busy timeout period, which can occur when BEGIN + // DEFERRED is used. + return BeginImmediate(); + } + + int BeginExclusive() { + return BeginCommand("BEGIN EXCLUSIVE"); + } + + int BeginImmediate() { + return BeginCommand("BEGIN IMMEDIATE"); + } + + int BeginDeferred() { + return BeginCommand("BEGIN DEFERRED"); + } + + int Commit() { + return EndCommand("COMMIT"); + } + + int Rollback() { + return EndCommand("ROLLBACK"); + } + + bool HasBegun() { + return began_; + } + + protected: + virtual int BeginCommand(const char* command); + virtual int EndCommand(const char* command); + + sqlite3* db_; + bool began_; + DISALLOW_COPY_AND_ASSIGN(SQLTransaction); +}; + + +//------------------------------------------------------------------------------ +// A class for use with SQLNestedTransaction. +//------------------------------------------------------------------------------ +class SQLNestedTransactionSite { + protected: + SQLNestedTransactionSite() : db_(NULL), top_transaction_(NULL) {} + virtual ~SQLNestedTransactionSite(); + + // The following virtual methods provide notification of true transaction + // boundaries as they are crossed by a top nested transaction. + // Intended to be overriden (See WebCacheDB) + // SQLNestedTransaction calls these after the underlying database + // operation has been performed. + + virtual void OnBegin() {} + virtual void OnCommit() {} + virtual void OnRollback() {} + + // Returns the sqlite3 database connection associated with this site + // Used by SQLNestedTransaction + sqlite3* GetSqlite3DB() { return db_; } + + // Returns the current top nested transaction associated with this site + // Used by SQLNestedTransaction + SQLNestedTransaction* GetTopTransaction() { + return top_transaction_; + } + + // Sets or clears the top nested transaction associated with this site + // Used by SQLNestedTransaction + void SetTopTransaction(SQLNestedTransaction* top); + + sqlite3* db_; + SQLNestedTransaction* top_transaction_; + friend class SQLNestedTransaction; +}; + +//------------------------------------------------------------------------------ +// SQLite does not support nested transactions. This class provides a gross +// approximation of nested transactions. +// +// Really there is only one transaction, the top transaction. +// +// A nested transaction commits with respect to the top transaction. +// That is, even though the nested transaction commits, the permanence of its +// effects depends on the top transaction committing. If the top +// transaction rollsback, the results of the nested transaction are backed out. +// If any nested transaction aborts, the top transaction ultimately rollsback +// as well. +// +// Note: If a nested transaction is open for a particular db connection, an +// attempt to open a non-nested transaction (class SQLTransaction) will fail. +// And vice versa. +// +// TODO(michaeln): demonstrate usage here +// TODO(michaeln): safegaurds to prevent mis-use +//------------------------------------------------------------------------------ +class SQLNestedTransaction : public SQLTransaction { + public: + explicit SQLNestedTransaction(SQLNestedTransactionSite* site); + virtual ~SQLNestedTransaction(); + + protected: + virtual int BeginCommand(const char* command); + virtual int EndCommand(const char* command); + + private: + bool needs_rollback_; + SQLNestedTransactionSite* site_; + DISALLOW_COPY_AND_ASSIGN(SQLNestedTransaction); +}; + +//------------------------------------------------------------------------------ +// A scoped sqlite statement that finalizes when it goes out of scope. +//------------------------------------------------------------------------------ +class scoped_sqlite3_stmt_ptr { + public: + ~scoped_sqlite3_stmt_ptr() { + finalize(); + } + + scoped_sqlite3_stmt_ptr() : stmt_(NULL) { + } + + explicit scoped_sqlite3_stmt_ptr(sqlite3_stmt* stmt) + : stmt_(stmt) { + } + + sqlite3_stmt* get() const { + return stmt_; + } + + void set(sqlite3_stmt* stmt) { + finalize(); + stmt_ = stmt; + } + + sqlite3_stmt* release() { + sqlite3_stmt* tmp = stmt_; + stmt_ = NULL; + return tmp; + } + + // It is not safe to call sqlite3_finalize twice on the same stmt. + // Sqlite3's sqlite3_finalize() function should not be called directly + // without calling the release method. If sqlite3_finalize() must be + // called directly, the following usage is advised: + // scoped_sqlite3_stmt_ptr stmt; + // ... do something with stmt ... + // sqlite3_finalize(stmt.release()); + int finalize() { + int err = sqlite3_finalize(stmt_); + stmt_ = NULL; + return err; + } + + protected: + sqlite3_stmt* stmt_; + + private: + DISALLOW_COPY_AND_ASSIGN(scoped_sqlite3_stmt_ptr); +}; + +//------------------------------------------------------------------------------ +// A scoped sqlite statement with convenient C++ wrappers for sqlite3 APIs. +//------------------------------------------------------------------------------ +class SQLStatement : public scoped_sqlite3_stmt_ptr { + public: + SQLStatement() {} + + int prepare(sqlite3* db, const char* sql) { + return prepare(db, sql, -1); + } + + int prepare(sqlite3* db, const char* sql, int sql_len); + + int step(); + int reset(); + sqlite_int64 last_insert_rowid(); + int changes(); + sqlite3* db_handle(); + + // + // Parameter binding helpers (NOTE: index is 0-based) + // + + int bind_parameter_count(); + + typedef void (*Function)(void*); + + int bind_blob(int index, std::vector<unsigned char>* blob); + int bind_blob(int index, const void* value, int value_len); + int bind_blob(int index, const void* value, int value_len, Function dtor); + int bind_double(int index, double value); + int bind_bool(int index, bool value); + int bind_int(int index, int value); + int bind_int64(int index, sqlite_int64 value); + int bind_null(int index); + + int bind_string(int index, const std::string& value) { + // don't use c_str so it doesn't have to fix up the null terminator + // (sqlite just uses the length) + return bind_text(index, value.data(), + static_cast<int>(value.length()), SQLITE_TRANSIENT); + } + + int bind_string16(int index, const string16& value) { + // don't use c_str so it doesn't have to fix up the null terminator + // (sqlite just uses the length) + std::string value_utf8(UTF16ToUTF8(value)); + return bind_text(index, value_utf8.data(), + static_cast<int>(value_utf8.length()), SQLITE_TRANSIENT); + } + + int bind_wstring(int index, const std::wstring& value) { + // don't use c_str so it doesn't have to fix up the null terminator + // (sqlite just uses the length) + std::string value_utf8(WideToUTF8(value)); + return bind_text(index, value_utf8.data(), + static_cast<int>(value_utf8.length()), SQLITE_TRANSIENT); + } + + int bind_text(int index, const char* value) { + return bind_text(index, value, -1, SQLITE_TRANSIENT); + } + + // value_len is number of characters or may be negative + // a for null-terminated value string + int bind_text(int index, const char* value, int value_len) { + return bind_text(index, value, value_len, SQLITE_TRANSIENT); + } + + // value_len is number of characters or may be negative + // a for null-terminated value string + int bind_text(int index, const char* value, int value_len, + Function dtor); + + int bind_text16(int index, const char16* value) { + return bind_text16(index, value, -1, SQLITE_TRANSIENT); + } + + // value_len is number of characters or may be negative + // a for null-terminated value string + int bind_text16(int index, const char16* value, int value_len) { + return bind_text16(index, value, value_len, SQLITE_TRANSIENT); + } + + // value_len is number of characters or may be negative + // a for null-terminated value string + int bind_text16(int index, const char16* value, int value_len, + Function dtor); + + int bind_value(int index, const sqlite3_value* value); + + // + // Column helpers (NOTE: index is 0-based) + // + + int column_count(); + int column_type(int index); + const void* column_blob(int index); + bool column_blob_as_vector(int index, std::vector<unsigned char>* blob); + bool column_blob_as_string(int index, std::string* blob); + int column_bytes(int index); + int column_bytes16(int index); + double column_double(int index); + bool column_bool(int index); + int column_int(int index); + sqlite_int64 column_int64(int index); + const char* column_text(int index); + bool column_string(int index, std::string* str); + std::string column_string(int index); + const char16* column_text16(int index); + bool column_string16(int index, string16* str); + string16 column_string16(int index); + bool column_wstring(int index, std::wstring* str); + std::wstring column_wstring(int index); + + private: + DISALLOW_COPY_AND_ASSIGN(SQLStatement); +}; + +namespace sqlite_utils { + +//------------------------------------------------------------------------------ +// A scoped sqlite database that closes when it goes out of scope. +//------------------------------------------------------------------------------ +class DBClose { + public: + inline void operator()(sqlite3* x) const { + sqlite3_close(x); + } +}; + +typedef scoped_ptr_malloc<sqlite3, DBClose> scoped_sqlite_db_ptr; + +// Opens the DB in the file pointed to by |filepath|. This method forces the +// database to be in UTF-8 mode on all platforms. See +// http://www.sqlite.org/capi3ref.html#sqlite3_open for an explanation of the +// return value. +int OpenSqliteDb(const FilePath& filepath, sqlite3** database); + +// Returns true if there is a table with the given name in the database. +// For the version where a database name is specified, it may be NULL or the +// empty string if no database name is necessary. +bool DoesSqliteTableExist(sqlite3* db, + const char* db_name, + const char* table_name); +inline bool DoesSqliteTableExist(sqlite3* db, const char* table_name) { + return DoesSqliteTableExist(db, NULL, table_name); +} + +// Test whether a table has a column matching the provided name and type. +// Returns true if the column exist and false otherwise. There are two +// versions, one that takes a database name, the other that doesn't. The +// database name can be NULL or empty if no name is desired. +// +// Column type is optional, it can be NULL or empty. If specified, we the +// function will check that the column is of the correct type (case-sensetive). +bool DoesSqliteColumnExist(sqlite3* db, + const char* datbase_name, + const char* table_name, + const char* column_name, + const char* column_type); +inline bool DoesSqliteColumnExist(sqlite3* db, + const char* table_name, + const char* column_name, + const char* column_type) { + return DoesSqliteColumnExist(db, NULL, table_name, column_name, column_type); +} + +// Test whether a table has one or more rows. Returns true if the table +// has one or more rows and false if the table is empty or doesn't exist. +bool DoesSqliteTableHaveRow(sqlite3* db, const char* table_name); + +} // namespace sqlite_utils + +#endif // CHROME_COMMON_SQLITE_UTILS_H_ diff --git a/chrome/common/task_queue.cc b/chrome/common/task_queue.cc new file mode 100644 index 0000000..0d5aabb --- /dev/null +++ b/chrome/common/task_queue.cc @@ -0,0 +1,46 @@ +// Copyright (c) 2006-2008 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 "chrome/common/task_queue.h" + +#include "base/stl_util-inl.h" + +TaskQueue::TaskQueue() { +} + +TaskQueue::~TaskQueue() { + // We own all the pointes in |queue_|. It is our job to delete them. + STLDeleteElements(&queue_); +} + +void TaskQueue::Run() { + // Nothing to run if our queue is empty. + if (queue_.empty()) + return; + + std::deque<Task*> ready; + queue_.swap(ready); + + // Run the tasks that are ready. + std::deque<Task*>::const_iterator task; + for (task = ready.begin(); task != ready.end(); ++task) { + // Run the task and then delete it. + (*task)->Run(); + delete (*task); + } +} + +void TaskQueue::Push(Task* task) { + // Add the task to the back of the queue. + queue_.push_back(task); +} + +void TaskQueue::Clear() { + // Delete all the elements in the queue and clear the dead pointers. + STLDeleteElements(&queue_); +} + +bool TaskQueue::Empty() const { + return queue_.empty(); +} diff --git a/chrome/common/task_queue.h b/chrome/common/task_queue.h new file mode 100644 index 0000000..9e1c817 --- /dev/null +++ b/chrome/common/task_queue.h @@ -0,0 +1,42 @@ +// Copyright (c) 2006-2008 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 CHROME_COMMON_TASK_QUEUE_H__ +#define CHROME_COMMON_TASK_QUEUE_H__ + +#include <deque> + +#include "base/task.h" + +// A TaskQueue is a queue of tasks waiting to be run. To run the tasks, call +// the Run method. A task queue is itself a Task so that it can be placed in a +// message loop or another task queue. +class TaskQueue : public Task { + public: + TaskQueue(); + ~TaskQueue(); + + // Run all the tasks in the queue. New tasks pushed onto the queue during + // a run will be run next time |Run| is called. + virtual void Run(); + + // Push the specified task onto the queue. When the queue is run, the tasks + // will be run in the order they are pushed. + // + // This method takes ownership of |task| and will delete task after it is run + // (or when the TaskQueue is destroyed, if we never got a chance to run it). + void Push(Task* task); + + // Remove all tasks from the queue. The tasks are deleted. + void Clear(); + + // Returns true if this queue contains no tasks. + bool Empty() const; + + private: + // The list of tasks we are waiting to run. + std::deque<Task*> queue_; +}; + +#endif // CHROME_COMMON_TASK_QUEUE_H__ diff --git a/chrome/common/thumbnail_score.cc b/chrome/common/thumbnail_score.cc new file mode 100644 index 0000000..dc7856d --- /dev/null +++ b/chrome/common/thumbnail_score.cc @@ -0,0 +1,118 @@ +// Copyright (c) 2009 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 "chrome/common/thumbnail_score.h" + +#include "base/logging.h" + +using base::Time; +using base::TimeDelta; + +const TimeDelta ThumbnailScore::kUpdateThumbnailTime = TimeDelta::FromDays(1); +const double ThumbnailScore::kThumbnailMaximumBoringness = 0.94; +const double ThumbnailScore::kThumbnailDegradePerHour = 0.01; + +// Calculates a numeric score from traits about where a snapshot was +// taken. We store the raw components in the database because I'm sure +// this will evolve and I don't want to break databases. +static int GetThumbnailType(bool good_clipping, bool at_top) { + if (good_clipping && at_top) { + return 0; + } else if (good_clipping && !at_top) { + return 1; + } else if (!good_clipping && at_top) { + return 2; + } else if (!good_clipping && !at_top) { + return 3; + } else { + NOTREACHED(); + return -1; + } +} + +ThumbnailScore::ThumbnailScore() + : boring_score(1.0), + good_clipping(false), + at_top(false), + time_at_snapshot(Time::Now()), + redirect_hops_from_dest(0) { +} + +ThumbnailScore::ThumbnailScore(double score, bool clipping, bool top) + : boring_score(score), + good_clipping(clipping), + at_top(top), + time_at_snapshot(Time::Now()), + redirect_hops_from_dest(0) { +} + +ThumbnailScore::ThumbnailScore(double score, bool clipping, bool top, + const Time& time) + : boring_score(score), + good_clipping(clipping), + at_top(top), + time_at_snapshot(time), + redirect_hops_from_dest(0) { +} + +ThumbnailScore::~ThumbnailScore() { +} + +bool ThumbnailScore::Equals(const ThumbnailScore& rhs) const { + // When testing equality we use ToTimeT() because that's the value + // stuck in the SQL database, so we need to test equivalence with + // that lower resolution. + return boring_score == rhs.boring_score && + good_clipping == rhs.good_clipping && + at_top == rhs.at_top && + time_at_snapshot.ToTimeT() == rhs.time_at_snapshot.ToTimeT() && + redirect_hops_from_dest == rhs.redirect_hops_from_dest; +} + +bool ShouldReplaceThumbnailWith(const ThumbnailScore& current, + const ThumbnailScore& replacement) { + int current_type = GetThumbnailType(current.good_clipping, current.at_top); + int replacement_type = GetThumbnailType(replacement.good_clipping, + replacement.at_top); + if (replacement_type < current_type) { + // If we have a better class of thumbnail, add it if it meets + // certain minimum boringness. + return replacement.boring_score < + ThumbnailScore::kThumbnailMaximumBoringness; + } else if (replacement_type == current_type) { + // It's much easier to do the scaling below when we're dealing with "higher + // is better." Then we can decrease the score by dividing by a fraction. + const double kThumbnailMinimumInterestingness = + 1.0 - ThumbnailScore::kThumbnailMaximumBoringness; + double current_interesting_score = 1.0 - current.boring_score; + double replacement_interesting_score = 1.0 - replacement.boring_score; + + // Degrade the score of each thumbnail to account for how many redirects + // they are away from the destination. 1/(x+1) gives a scaling factor of + // one for x = 0, and asymptotically approaches 0 for larger values of x. + current_interesting_score *= + 1.0 / (current.redirect_hops_from_dest + 1); + replacement_interesting_score *= + 1.0 / (replacement.redirect_hops_from_dest + 1); + + // Degrade the score and prefer the newer one based on how long apart the + // two thumbnails were taken. This means we'll eventually replace an old + // good one with a new worse one assuming enough time has passed. + TimeDelta time_between_thumbnails = + replacement.time_at_snapshot - current.time_at_snapshot; + current_interesting_score -= time_between_thumbnails.InHours() * + ThumbnailScore::kThumbnailDegradePerHour; + + if (current_interesting_score < kThumbnailMinimumInterestingness) + current_interesting_score = kThumbnailMinimumInterestingness; + if (replacement_interesting_score > current_interesting_score) + return true; + } + + // If the current thumbnail doesn't meet basic boringness + // requirements, but the replacement does, always replace the + // current one even if we're using a worse thumbnail type. + return current.boring_score >= ThumbnailScore::kThumbnailMaximumBoringness && + replacement.boring_score < ThumbnailScore::kThumbnailMaximumBoringness; +} diff --git a/chrome/common/thumbnail_score.h b/chrome/common/thumbnail_score.h new file mode 100644 index 0000000..c3a5a90 --- /dev/null +++ b/chrome/common/thumbnail_score.h @@ -0,0 +1,82 @@ +// Copyright (c) 2009 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 CHROME_COMMON_THUMBNAIL_SCORE_H_ +#define CHROME_COMMON_THUMBNAIL_SCORE_H_ + +#include "base/time.h" + +// A set of metadata about a Thumbnail. +struct ThumbnailScore { + // Initializes the ThumbnailScore to the absolute worst possible values + // except for time, which is set to Now(), and redirect_hops_from_dest which + // is set to 0. + ThumbnailScore(); + + // Builds a ThumbnailScore with the passed in values, and sets the + // thumbnail generation time to Now(). + ThumbnailScore(double score, bool clipping, bool top); + + // Builds a ThumbnailScore with the passed in values. + ThumbnailScore(double score, bool clipping, bool top, + const base::Time& time); + ~ThumbnailScore(); + + // Tests for equivalence between two ThumbnailScore objects. + bool Equals(const ThumbnailScore& rhs) const; + + // How "boring" a thumbnail is. The boring score is the 0,1 ranged + // percentage of pixels that are the most common luma. Higher boring + // scores indicate that a higher percentage of a bitmap are all the + // same brightness (most likely the same color). + double boring_score; + + // Whether the thumbnail was taken with height greater then + // width. In cases where we don't have |good_clipping|, the + // thumbnails are either clipped from the horizontal center of the + // window, or are otherwise weirdly stretched. + bool good_clipping; + + // Whether this thumbnail was taken while the renderer was + // displaying the top of the page. Most pages are more recognizable + // by their headers then by a set of random text half way down the + // page; i.e. most MediaWiki sites would be indistinguishable by + // thumbnails with |at_top| set to false. + bool at_top; + + // Record the time when a thumbnail was taken. This is used to make + // sure thumbnails are kept fresh. + base::Time time_at_snapshot; + + // The number of hops from the final destination page that this thumbnail was + // taken at. When a thumbnail is taken, this will always be the redirect + // destination (value of 0). + // + // For the most visited view, we'll sometimes get thumbnails for URLs in the + // middle of a redirect chain. In this case, the top sites component will set + // this value so the distance from the destination can be taken into account + // by the comparison function. + // + // If "http://google.com/" redirected to "http://www.google.com/", then + // a thumbnail for the first would have a redirect hop of 1, and the second + // would have a redirect hop of 0. + int redirect_hops_from_dest; + + // How bad a thumbnail needs to be before we completely ignore it. + static const double kThumbnailMaximumBoringness; + + // Time before we take a worse thumbnail (subject to + // kThumbnailMaximumBoringness) over what's currently in the database + // for freshness. + static const base::TimeDelta kUpdateThumbnailTime; + + // Penalty of how much more boring a thumbnail should be per hour. + static const double kThumbnailDegradePerHour; +}; + +// Checks whether we should replace one thumbnail with another. +bool ShouldReplaceThumbnailWith(const ThumbnailScore& current, + const ThumbnailScore& replacement); + +#endif // CHROME_COMMON_THUMBNAIL_SCORE_H_ diff --git a/chrome/common/thumbnail_score_unittest.cc b/chrome/common/thumbnail_score_unittest.cc new file mode 100644 index 0000000..14d79dd --- /dev/null +++ b/chrome/common/thumbnail_score_unittest.cc @@ -0,0 +1,54 @@ +// Copyright (c) 2009 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 "chrome/common/thumbnail_score.h" +#include "testing/gtest/include/gtest/gtest.h" + +// Tests that the different types of thumbnails are compared properly. +TEST(ThumbnailScoreTest, ShouldReplaceThumbnailWithType) { + base::Time now = base::Time::Now(); + + ThumbnailScore nothing_good(0.5, false, false, now); + ThumbnailScore not_at_top(0.5, false, true, now); + ThumbnailScore bad_clipping(0.5, true, false, now); + ThumbnailScore life_is_awesome(0.5, true, true, now); + + EXPECT_TRUE(ShouldReplaceThumbnailWith(nothing_good, not_at_top)); + EXPECT_TRUE(ShouldReplaceThumbnailWith(nothing_good, bad_clipping)); + EXPECT_TRUE(ShouldReplaceThumbnailWith(nothing_good, life_is_awesome)); + EXPECT_TRUE(ShouldReplaceThumbnailWith(not_at_top, bad_clipping)); + EXPECT_TRUE(ShouldReplaceThumbnailWith(not_at_top, life_is_awesome)); + EXPECT_TRUE(ShouldReplaceThumbnailWith(bad_clipping, life_is_awesome)); +} + +// Tests that we'll replace old thumbnails will crappier but newer ones. +TEST(ThumbnailScoreTest, ShouldReplaceThumbnailWithTime) { + // Use a really long time for the difference so we aren't sensitive to the + // degrading schedule. + base::Time now = base::Time::Now(); + base::Time last_year = now - base::TimeDelta::FromDays(365); + + ThumbnailScore oldie_but_goodie(0.1, true, true, last_year); + ThumbnailScore newie_but_crappie(0.9, true, true, now); + + EXPECT_TRUE(ShouldReplaceThumbnailWith(oldie_but_goodie, newie_but_crappie)); +} + +// Having many redirects should age the thumbnail. +TEST(ThumbnailScoreTest, RedirectCount) { + base::Time now = base::Time::Now(); + + ThumbnailScore no_redirects(0.5, true, true, now); + no_redirects.redirect_hops_from_dest = 0; + ThumbnailScore some_redirects(0.5, true, true, now); + some_redirects.redirect_hops_from_dest = 1; + + EXPECT_TRUE(ShouldReplaceThumbnailWith(some_redirects, no_redirects)); + + // This one has a lot of redirects but a better score. It should still be + // rejected. + ThumbnailScore lotsa_redirects(0.4, true, true, now); + lotsa_redirects.redirect_hops_from_dest = 4; + EXPECT_FALSE(ShouldReplaceThumbnailWith(no_redirects, lotsa_redirects)); +} diff --git a/chrome/common/time_format.cc b/chrome/common/time_format.cc new file mode 100644 index 0000000..4ca5187 --- /dev/null +++ b/chrome/common/time_format.cc @@ -0,0 +1,338 @@ +// Copyright (c) 2009 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 "chrome/common/time_format.h" + +#include <vector> + +#include "app/l10n_util.h" +#include "base/i18n/time_formatting.h" +#include "base/logging.h" +#include "base/scoped_ptr.h" +#include "base/singleton.h" +#include "base/stl_util-inl.h" +#include "base/time.h" +#include "base/utf_string_conversions.h" +#include "grit/generated_resources.h" +#include "unicode/datefmt.h" +#include "unicode/locid.h" +#include "unicode/plurfmt.h" +#include "unicode/plurrule.h" +#include "unicode/smpdtfmt.h" + +using base::Time; +using base::TimeDelta; + +namespace { + +static const char kFallbackFormatSuffixShort[] = "}"; +static const char kFallbackFormatSuffixLeft[] = " left}"; +static const char kFallbackFormatSuffixAgo[] = " ago}"; + +// Contains message IDs for various time units and pluralities. +struct MessageIDs { + // There are 4 different time units and 6 different pluralities. + int ids[4][6]; +}; + +// Message IDs for different time formats. +static const MessageIDs kTimeShortMessageIDs = { { + { + IDS_TIME_SECS_DEFAULT, IDS_TIME_SEC_SINGULAR, IDS_TIME_SECS_ZERO, + IDS_TIME_SECS_TWO, IDS_TIME_SECS_FEW, IDS_TIME_SECS_MANY + }, + { + IDS_TIME_MINS_DEFAULT, IDS_TIME_MIN_SINGULAR, IDS_TIME_MINS_ZERO, + IDS_TIME_MINS_TWO, IDS_TIME_MINS_FEW, IDS_TIME_MINS_MANY + }, + { + IDS_TIME_HOURS_DEFAULT, IDS_TIME_HOUR_SINGULAR, IDS_TIME_HOURS_ZERO, + IDS_TIME_HOURS_TWO, IDS_TIME_HOURS_FEW, IDS_TIME_HOURS_MANY + }, + { + IDS_TIME_DAYS_DEFAULT, IDS_TIME_DAY_SINGULAR, IDS_TIME_DAYS_ZERO, + IDS_TIME_DAYS_TWO, IDS_TIME_DAYS_FEW, IDS_TIME_DAYS_MANY + } +} }; + +static const MessageIDs kTimeRemainingMessageIDs = { { + { + IDS_TIME_REMAINING_SECS_DEFAULT, IDS_TIME_REMAINING_SEC_SINGULAR, + IDS_TIME_REMAINING_SECS_ZERO, IDS_TIME_REMAINING_SECS_TWO, + IDS_TIME_REMAINING_SECS_FEW, IDS_TIME_REMAINING_SECS_MANY + }, + { + IDS_TIME_REMAINING_MINS_DEFAULT, IDS_TIME_REMAINING_MIN_SINGULAR, + IDS_TIME_REMAINING_MINS_ZERO, IDS_TIME_REMAINING_MINS_TWO, + IDS_TIME_REMAINING_MINS_FEW, IDS_TIME_REMAINING_MINS_MANY + }, + { + IDS_TIME_REMAINING_HOURS_DEFAULT, IDS_TIME_REMAINING_HOUR_SINGULAR, + IDS_TIME_REMAINING_HOURS_ZERO, IDS_TIME_REMAINING_HOURS_TWO, + IDS_TIME_REMAINING_HOURS_FEW, IDS_TIME_REMAINING_HOURS_MANY + }, + { + IDS_TIME_REMAINING_DAYS_DEFAULT, IDS_TIME_REMAINING_DAY_SINGULAR, + IDS_TIME_REMAINING_DAYS_ZERO, IDS_TIME_REMAINING_DAYS_TWO, + IDS_TIME_REMAINING_DAYS_FEW, IDS_TIME_REMAINING_DAYS_MANY + } +} }; + +static const MessageIDs kTimeElapsedMessageIDs = { { + { + IDS_TIME_ELAPSED_SECS_DEFAULT, IDS_TIME_ELAPSED_SEC_SINGULAR, + IDS_TIME_ELAPSED_SECS_ZERO, IDS_TIME_ELAPSED_SECS_TWO, + IDS_TIME_ELAPSED_SECS_FEW, IDS_TIME_ELAPSED_SECS_MANY + }, + { + IDS_TIME_ELAPSED_MINS_DEFAULT, IDS_TIME_ELAPSED_MIN_SINGULAR, + IDS_TIME_ELAPSED_MINS_ZERO, IDS_TIME_ELAPSED_MINS_TWO, + IDS_TIME_ELAPSED_MINS_FEW, IDS_TIME_ELAPSED_MINS_MANY + }, + { + IDS_TIME_ELAPSED_HOURS_DEFAULT, IDS_TIME_ELAPSED_HOUR_SINGULAR, + IDS_TIME_ELAPSED_HOURS_ZERO, IDS_TIME_ELAPSED_HOURS_TWO, + IDS_TIME_ELAPSED_HOURS_FEW, IDS_TIME_ELAPSED_HOURS_MANY + }, + { + IDS_TIME_ELAPSED_DAYS_DEFAULT, IDS_TIME_ELAPSED_DAY_SINGULAR, + IDS_TIME_ELAPSED_DAYS_ZERO, IDS_TIME_ELAPSED_DAYS_TWO, + IDS_TIME_ELAPSED_DAYS_FEW, IDS_TIME_ELAPSED_DAYS_MANY + } +} }; + +// Different format types. +enum FormatType { + FORMAT_SHORT, + FORMAT_REMAINING, + FORMAT_ELAPSED, +}; + +} // namespace + +class TimeFormatter { + public: + const std::vector<icu::PluralFormat*>& formatter(FormatType format_type) { + switch (format_type) { + case FORMAT_SHORT: + return short_formatter_; + case FORMAT_REMAINING: + return time_left_formatter_; + case FORMAT_ELAPSED: + return time_elapsed_formatter_; + default: + NOTREACHED(); + return short_formatter_; + } + } + private: + static const MessageIDs& GetMessageIDs(FormatType format_type) { + switch (format_type) { + case FORMAT_SHORT: + return kTimeShortMessageIDs; + case FORMAT_REMAINING: + return kTimeRemainingMessageIDs; + case FORMAT_ELAPSED: + return kTimeElapsedMessageIDs; + default: + NOTREACHED(); + return kTimeShortMessageIDs; + } + } + + static const char* GetFallbackFormatSuffix(FormatType format_type) { + switch (format_type) { + case FORMAT_SHORT: + return kFallbackFormatSuffixShort; + case FORMAT_REMAINING: + return kFallbackFormatSuffixLeft; + case FORMAT_ELAPSED: + return kFallbackFormatSuffixAgo; + default: + NOTREACHED(); + return kFallbackFormatSuffixShort; + } + } + + TimeFormatter() { + BuildFormats(FORMAT_SHORT, &short_formatter_); + BuildFormats(FORMAT_REMAINING, &time_left_formatter_); + BuildFormats(FORMAT_ELAPSED, &time_elapsed_formatter_); + } + ~TimeFormatter() { + STLDeleteContainerPointers(short_formatter_.begin(), + short_formatter_.end()); + STLDeleteContainerPointers(time_left_formatter_.begin(), + time_left_formatter_.end()); + STLDeleteContainerPointers(time_elapsed_formatter_.begin(), + time_elapsed_formatter_.end()); + } + friend class Singleton<TimeFormatter>; + friend struct DefaultSingletonTraits<TimeFormatter>; + + std::vector<icu::PluralFormat*> short_formatter_; + std::vector<icu::PluralFormat*> time_left_formatter_; + std::vector<icu::PluralFormat*> time_elapsed_formatter_; + static void BuildFormats(FormatType format_type, + std::vector<icu::PluralFormat*>* time_formats); + static icu::PluralFormat* createFallbackFormat( + const icu::PluralRules& rules, int index, FormatType format_type); + + DISALLOW_COPY_AND_ASSIGN(TimeFormatter); +}; + +void TimeFormatter::BuildFormats( + FormatType format_type, std::vector<icu::PluralFormat*>* time_formats) { + static const icu::UnicodeString kKeywords[] = { + UNICODE_STRING_SIMPLE("other"), UNICODE_STRING_SIMPLE("one"), + UNICODE_STRING_SIMPLE("zero"), UNICODE_STRING_SIMPLE("two"), + UNICODE_STRING_SIMPLE("few"), UNICODE_STRING_SIMPLE("many") + }; + UErrorCode err = U_ZERO_ERROR; + scoped_ptr<icu::PluralRules> rules( + icu::PluralRules::forLocale(icu::Locale::getDefault(), err)); + if (U_FAILURE(err)) { + err = U_ZERO_ERROR; + icu::UnicodeString fallback_rules("one: n is 1", -1, US_INV); + rules.reset(icu::PluralRules::createRules(fallback_rules, err)); + DCHECK(U_SUCCESS(err)); + } + + const MessageIDs& message_ids = GetMessageIDs(format_type); + + for (int i = 0; i < 4; ++i) { + icu::UnicodeString pattern; + for (size_t j = 0; j < arraysize(kKeywords); ++j) { + int msg_id = message_ids.ids[i][j]; + std::string sub_pattern = WideToUTF8(l10n_util::GetString(msg_id)); + // NA means this keyword is not used in the current locale. + // Even if a translator translated for this keyword, we do not + // use it unless it's 'other' (j=0) or it's defined in the rules + // for the current locale. Special-casing of 'other' will be removed + // once ICU's isKeyword is fixed to return true for isKeyword('other'). + if (sub_pattern.compare("NA") != 0 && + (j == 0 || rules->isKeyword(kKeywords[j]))) { + pattern += kKeywords[j]; + pattern += UNICODE_STRING_SIMPLE("{"); + pattern += icu::UnicodeString(sub_pattern.c_str(), "UTF-8"); + pattern += UNICODE_STRING_SIMPLE("}"); + } + } + icu::PluralFormat* format = new icu::PluralFormat(*rules, pattern, err); + if (U_SUCCESS(err)) { + time_formats->push_back(format); + } else { + delete format; + time_formats->push_back(createFallbackFormat(*rules, i, format_type)); + // Reset it so that next ICU call can proceed. + err = U_ZERO_ERROR; + } + } +} + +// Create a hard-coded fallback plural format. This will never be called +// unless translators make a mistake. +icu::PluralFormat* TimeFormatter::createFallbackFormat( + const icu::PluralRules& rules, int index, FormatType format_type) { + static const icu::UnicodeString kUnits[4][2] = { + { UNICODE_STRING_SIMPLE("sec"), UNICODE_STRING_SIMPLE("secs") }, + { UNICODE_STRING_SIMPLE("min"), UNICODE_STRING_SIMPLE("mins") }, + { UNICODE_STRING_SIMPLE("hour"), UNICODE_STRING_SIMPLE("hours") }, + { UNICODE_STRING_SIMPLE("day"), UNICODE_STRING_SIMPLE("days") } + }; + icu::UnicodeString suffix(GetFallbackFormatSuffix(format_type), -1, US_INV); + icu::UnicodeString pattern; + if (rules.isKeyword(UNICODE_STRING_SIMPLE("one"))) { + pattern += UNICODE_STRING_SIMPLE("one{# ") + kUnits[index][0] + suffix; + } + pattern += UNICODE_STRING_SIMPLE(" other{# ") + kUnits[index][1] + suffix; + UErrorCode err = U_ZERO_ERROR; + icu::PluralFormat* format = new icu::PluralFormat(rules, pattern, err); + DCHECK(U_SUCCESS(err)); + return format; +} + +Singleton<TimeFormatter> time_formatter; + +static std::wstring FormatTimeImpl(const TimeDelta& delta, + FormatType format_type) { + if (delta.ToInternalValue() < 0) { + NOTREACHED() << "Negative duration"; + return std::wstring(); + } + + int number; + + const std::vector<icu::PluralFormat*>& formatters = + time_formatter->formatter(format_type); + + UErrorCode error = U_ZERO_ERROR; + icu::UnicodeString time_string; + // Less than a minute gets "X seconds left" + if (delta.ToInternalValue() < Time::kMicrosecondsPerMinute) { + number = static_cast<int>(delta.ToInternalValue() / + Time::kMicrosecondsPerSecond); + time_string = formatters[0]->format(number, error); + + // Less than 1 hour gets "X minutes left". + } else if (delta.ToInternalValue() < Time::kMicrosecondsPerHour) { + number = static_cast<int>(delta.ToInternalValue() / + Time::kMicrosecondsPerMinute); + time_string = formatters[1]->format(number, error); + + // Less than 1 day remaining gets "X hours left" + } else if (delta.ToInternalValue() < Time::kMicrosecondsPerDay) { + number = static_cast<int>(delta.ToInternalValue() / + Time::kMicrosecondsPerHour); + time_string = formatters[2]->format(number, error); + + // Anything bigger gets "X days left" + } else { + number = static_cast<int>(delta.ToInternalValue() / + Time::kMicrosecondsPerDay); + time_string = formatters[3]->format(number, error); + } + + // With the fallback added, this should never fail. + DCHECK(U_SUCCESS(error)); + int capacity = time_string.length() + 1; + string16 result_utf16; + time_string.extract(static_cast<UChar*>( + WriteInto(&result_utf16, capacity)), + capacity, error); + DCHECK(U_SUCCESS(error)); + return UTF16ToWide(result_utf16); +} + +// static +std::wstring TimeFormat::TimeElapsed(const TimeDelta& delta) { + return FormatTimeImpl(delta, FORMAT_ELAPSED); +} + +// static +std::wstring TimeFormat::TimeRemaining(const TimeDelta& delta) { + return FormatTimeImpl(delta, FORMAT_REMAINING); +} + +// static +std::wstring TimeFormat::TimeRemainingShort(const TimeDelta& delta) { + return FormatTimeImpl(delta, FORMAT_SHORT); +} + +// static +std::wstring TimeFormat::RelativeDate( + const Time& time, + const Time* optional_midnight_today) { + Time midnight_today = optional_midnight_today ? *optional_midnight_today : + Time::Now().LocalMidnight(); + + // Filter out "today" and "yesterday" + if (time >= midnight_today) + return l10n_util::GetString(IDS_PAST_TIME_TODAY); + else if (time >= midnight_today - + TimeDelta::FromMicroseconds(Time::kMicrosecondsPerDay)) + return l10n_util::GetString(IDS_PAST_TIME_YESTERDAY); + + return std::wstring(); +} diff --git a/chrome/common/time_format.h b/chrome/common/time_format.h new file mode 100644 index 0000000..c04ed62 --- /dev/null +++ b/chrome/common/time_format.h @@ -0,0 +1,52 @@ +// Copyright (c) 2006-2008 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 CHROME_COMMON_TIME_FORMAT_H__ +#define CHROME_COMMON_TIME_FORMAT_H__ + +// This file defines methods to format time values as strings. + +#include <string> + +#include "unicode/smpdtfmt.h" + +namespace base { +class Time; +class TimeDelta; +} + +class TimeFormat { + public: + // TimeElapsed, TimeRemaining and TimeRemainingShort functions: + // These functions return a localized string of approximate time duration. The + // conditions are simpler than PastTime since these functions are used for + // in-progress operations and users have different expectations of units. + + // Returns times in elapsed-format: "3 mins ago", "2 days ago". + static std::wstring TimeElapsed(const base::TimeDelta& delta); + + // Returns times in remaining-format: "3 mins left", "2 days left". + static std::wstring TimeRemaining(const base::TimeDelta& delta); + + // Returns times in short-format: "3 mins", "2 days". + static std::wstring TimeRemainingShort(const base::TimeDelta& delta); + + // For displaying a relative time in the past. This method returns either + // "Today", "Yesterday", or an empty string if it's older than that. + // + // TODO(brettw): This should be able to handle days in the future like + // "Tomorrow". + // TODO(tc): This should be able to do things like "Last week". This + // requires handling singluar/plural for all languages. + // + // The second parameter is optional, it is midnight of "Now" for relative day + // computations: Time::Now().LocalMidnight() + // If NULL, the current day's midnight will be retrieved, which can be + // slow. If many items are being processed, it is best to get the current + // time once at the beginning and pass it for each computation. + static std::wstring RelativeDate(const base::Time& time, + const base::Time* optional_midnight_today); +}; + +#endif // CHROME_COMMON_TIME_FORMAT_H__ diff --git a/chrome/common/time_format_unittest.cc b/chrome/common/time_format_unittest.cc new file mode 100644 index 0000000..d437859 --- /dev/null +++ b/chrome/common/time_format_unittest.cc @@ -0,0 +1,69 @@ +// Copyright (c) 2006-2008 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 <time.h> + +#include "app/l10n_util.h" +#include "base/basictypes.h" +#include "base/time.h" +#include "chrome/common/time_format.h" +#include "testing/gtest/include/gtest/gtest.h" + +using base::Time; +using base::TimeDelta; + +TEST(TimeFormat, RelativeDate) { + Time now = Time::Now(); + std::wstring today_str = TimeFormat::RelativeDate(now, NULL); + EXPECT_EQ(L"Today", today_str); + + Time yesterday = now - TimeDelta::FromDays(1); + std::wstring yesterday_str = TimeFormat::RelativeDate(yesterday, NULL); + EXPECT_EQ(L"Yesterday", yesterday_str); + + Time two_days_ago = now - TimeDelta::FromDays(2); + std::wstring two_days_ago_str = TimeFormat::RelativeDate(two_days_ago, NULL); + EXPECT_TRUE(two_days_ago_str.empty()); + + Time a_week_ago = now - TimeDelta::FromDays(7); + std::wstring a_week_ago_str = TimeFormat::RelativeDate(a_week_ago, NULL); + EXPECT_TRUE(a_week_ago_str.empty()); +} + +namespace { +void TestTimeFormats(const TimeDelta delta, const std::wstring& expected) { + std::wstring expected_left = expected + L" left"; + std::wstring expected_ago = expected + L" ago"; + EXPECT_EQ(expected, TimeFormat::TimeRemainingShort(delta)); + EXPECT_EQ(expected_left, TimeFormat::TimeRemaining(delta)); + EXPECT_EQ(expected_ago, TimeFormat::TimeElapsed(delta)); +} + +} // namespace + +TEST(TimeFormat, FormatTime) { + const TimeDelta one_day = TimeDelta::FromDays(1); + const TimeDelta three_days = TimeDelta::FromDays(3); + const TimeDelta one_hour = TimeDelta::FromHours(1); + const TimeDelta four_hours = TimeDelta::FromHours(4); + const TimeDelta one_min = TimeDelta::FromMinutes(1); + const TimeDelta three_mins = TimeDelta::FromMinutes(3); + const TimeDelta one_sec = TimeDelta::FromSeconds(1); + const TimeDelta five_secs = TimeDelta::FromSeconds(5); + const TimeDelta twohundred_millisecs = TimeDelta::FromMilliseconds(200); + + // TODO(jungshik) : These test only pass when the OS locale is 'en'. + // We need to add SetUp() and TearDown() to set the locale to 'en'. + TestTimeFormats(twohundred_millisecs, L"0 secs"); + TestTimeFormats(one_sec - twohundred_millisecs, L"0 secs"); + TestTimeFormats(one_sec + twohundred_millisecs, L"1 sec"); + TestTimeFormats(five_secs + twohundred_millisecs, L"5 secs"); + TestTimeFormats(one_min + five_secs, L"1 min"); + TestTimeFormats(three_mins + twohundred_millisecs, L"3 mins"); + TestTimeFormats(one_hour + five_secs, L"1 hour"); + TestTimeFormats(four_hours + five_secs, L"4 hours"); + TestTimeFormats(one_day + five_secs, L"1 day"); + TestTimeFormats(three_days, L"3 days"); + TestTimeFormats(three_days + four_hours, L"3 days"); +} diff --git a/chrome/common/translate_errors.h b/chrome/common/translate_errors.h new file mode 100644 index 0000000..1c6ea8a --- /dev/null +++ b/chrome/common/translate_errors.h @@ -0,0 +1,30 @@ +// Copyright (c) 2010 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 CHROME_COMMON_TRANSLATE_ERRORS_H_ +#define CHROME_COMMON_TRANSLATE_ERRORS_H_ + +// This file consolidates all the error types for translation of a page. + +class TranslateErrors { + public: + enum Type { + NONE = 0, + NETWORK, // No connectivity. + INITIALIZATION_ERROR, // The translation script failed to initialize. + UNKNOWN_LANGUAGE, // The page's language could not be detected. + UNSUPPORTED_LANGUAGE, // The server detected a language that the browser + // does not know. + IDENTICAL_LANGUAGES, // The original and target languages are the same. + TRANSLATION_ERROR, // An error was reported by the translation script + // during translation. + }; + + private: + TranslateErrors() {} + + DISALLOW_COPY_AND_ASSIGN(TranslateErrors); +}; + +#endif // CHROME_COMMON_TRANSLATE_ERRORS_H_ diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc new file mode 100644 index 0000000..a2a32bd --- /dev/null +++ b/chrome/common/url_constants.cc @@ -0,0 +1,134 @@ +// Copyright (c) 2010 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 <stdlib.h> + +#include "chrome/common/url_constants.h" +#include "googleurl/src/url_util.h" + +namespace chrome { + +const char kAboutScheme[] = "about"; +const char kChromeInternalScheme[] = "chrome-internal"; +const char kChromeUIScheme[] = "chrome"; +const char kDataScheme[] = "data"; +const char kExtensionScheme[] = "chrome-extension"; +const char kFileScheme[] = "file"; +const char kFtpScheme[] = "ftp"; +const char kGearsScheme[] = "gears"; +const char kHttpScheme[] = "http"; +const char kHttpsScheme[] = "https"; +const char kJavaScriptScheme[] = "javascript"; +const char kMailToScheme[] = "mailto"; +const char kMetadataScheme[] = "metadata"; +const char kUserScriptScheme[] = "chrome-user-script"; +const char kViewSourceScheme[] = "view-source"; + +#if defined(OS_CHROMEOS) +const char kCrosScheme[] = "cros"; +#endif + +const char kStandardSchemeSeparator[] = "://"; + +const char* kSavableSchemes[] = { + kHttpScheme, + kHttpsScheme, + kFileScheme, + kFtpScheme, + kExtensionScheme, + kChromeUIScheme, + NULL +}; + +const char kAboutAppCacheInternalsURL[] = "about:appcache-internals"; +const char kAboutBlankURL[] = "about:blank"; +const char kAboutCacheURL[] = "about:cache"; +const char kAboutCrashURL[] = "about:crash"; +const char kAboutCreditsURL[] = "about:credits"; +const char kAboutHangURL[] = "about:hang"; +const char kAboutMemoryURL[] = "about:memory"; +const char kAboutNetInternalsURL[] = "about:net-internals"; +const char kAboutPluginsURL[] = "about:plugins"; +const char kAboutShorthangURL[] = "about:shorthang"; +const char kAboutSystemURL[] = "about:system"; +const char kAboutTermsURL[] = "about:terms"; +const char kAboutAboutURL[] = "about:about"; +const char kAboutDNSURL[] = "about:dns"; +const char kAboutHistogramsURL[] = "about:histograms"; +const char kAboutVersionURL[] = "about:version"; + +// Use an obfuscated URL to make this nondiscoverable, we only want this +// to be used for testing. +const char kAboutBrowserCrash[] = "about:inducebrowsercrashforrealz"; + +const char kChromeUIAppLauncherURL[] = "chrome://newtab/#mode=app-launcher"; +const char kChromeUIBookmarksURL[] = "chrome://bookmarks/"; +const char kChromeUIDevToolsURL[] = "chrome://devtools/"; +const char kChromeUIDownloadsURL[] = "chrome://downloads/"; +const char kChromeUIExtensionsURL[] = "chrome://extensions/"; +const char kChromeUIFavIconURL[] = "chrome://favicon/"; +const char kChromeUIFileBrowseURL[] = "chrome://filebrowse/"; +const char kChromeUIHistoryURL[] = "chrome://history/"; +const char kChromeUIHistory2URL[] = "chrome://history2/"; +const char kChromeUIIPCURL[] = "chrome://about/ipc"; +const char kChromeUIMediaplayerURL[] = "chrome://mediaplayer/"; +const char kChromeUINewTabURL[] = "chrome://newtab"; +const char kChromeUIOptionsURL[] = "chrome://options/"; +const char kChromeUIPluginsURL[] = "chrome://plugins/"; +const char kChromeUIPrintURL[] = "chrome://print/"; +const char kChromeUIRegisterPageURL[] = "chrome://register/"; +const char kChromeUISlideshowURL[] = "chrome://slideshow/"; + +const char kChromeUIBookmarksHost[] = "bookmarks"; +const char kChromeUIDevToolsHost[] = "devtools"; +const char kChromeUIDialogHost[] = "dialog"; +const char kChromeUIDownloadsHost[] = "downloads"; +const char kChromeUIExtensionsHost[] = "extensions"; +const char kChromeUIFavIconHost[] = "favicon"; +const char kChromeUIFileBrowseHost[] = "filebrowse"; +const char kChromeUIHistoryHost[] = "history"; +const char kChromeUIHistory2Host[] = "history2"; +const char kChromeUIInspectorHost[] = "inspector"; +const char kChromeUIMediaplayerHost[] = "mediaplayer"; +const char kChromeUINetInternalsHost[] = "net-internals"; +const char kChromeUINewTabHost[] = "newtab"; +const char kChromeUIOptionsHost[] = "options"; +const char kChromeUIPluginsHost[] = "plugins"; +const char kChromeUIPrintHost[] = "print"; +const char kChromeUIRegisterPageHost[] = "register"; +const char kChromeUIRemotingHost[] = "remoting"; +const char kChromeUIResourcesHost[] = "resources"; +const char kChromeUISlideshowHost[] = "slideshow"; +const char kChromeUISyncResourcesHost[] = "syncresources"; +const char kChromeUIThemePath[] = "theme"; +const char kChromeUIThumbnailPath[] = "thumb"; + +const char kAppCacheViewInternalsURL[] = "chrome://appcache-internals/"; + +const char kCloudPrintResourcesURL[] = "chrome://cloudprintresources/"; +const char kCloudPrintResourcesHost[] = "cloudprintresources"; + +const char kNetworkViewInternalsURL[] = "chrome://net-internals/"; +const char kNetworkViewCacheURL[] = "chrome://view-http-cache/"; + +void RegisterChromeSchemes() { + // Don't need "chrome-internal" which was used in old versions of Chrome for + // the new tab page. + url_util::AddStandardScheme(kChromeUIScheme); + url_util::AddStandardScheme(kGearsScheme); + url_util::AddStandardScheme(kExtensionScheme); + url_util::AddStandardScheme(kMetadataScheme); +#if defined(OS_CHROMEOS) + url_util::AddStandardScheme(kCrosScheme); +#endif + + // Prevent future modification of the standard schemes list. This is to + // prevent accidental creation of data races in the program. AddStandardScheme + // isn't threadsafe so must be called when GURL isn't used on any other + // thread. This is really easy to mess up, so we say that all calls to + // AddStandardScheme in Chrome must be inside this function. + url_util::LockStandardSchemes(); +} + +} // namespace chrome diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h new file mode 100644 index 0000000..216ffb1 --- /dev/null +++ b/chrome/common/url_constants.h @@ -0,0 +1,118 @@ +// Copyright (c) 2010 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. + +// Contains constants for known URLs and portions thereof. + +#ifndef CHROME_COMMON_URL_CONSTANTS_H_ +#define CHROME_COMMON_URL_CONSTANTS_H_ + +namespace chrome { + +// Canonical schemes you can use as input to GURL.SchemeIs(). +extern const char kAboutScheme[]; +extern const char kChromeInternalScheme[]; +extern const char kChromeUIScheme[]; // The scheme used for DOMUIs. +extern const char kCrosScheme[]; // The scheme used for ChromeOS. +extern const char kDataScheme[]; +extern const char kExtensionScheme[]; +extern const char kFileScheme[]; +extern const char kFtpScheme[]; +extern const char kGearsScheme[]; +extern const char kHttpScheme[]; +extern const char kHttpsScheme[]; +extern const char kJavaScriptScheme[]; +extern const char kMailToScheme[]; +extern const char kMetadataScheme[]; +extern const char kUserScriptScheme[]; +extern const char kViewSourceScheme[]; + +// Used to separate a standard scheme and the hostname: "://". +extern const char kStandardSchemeSeparator[]; + +// Null terminated list of schemes that are savable. +extern const char* kSavableSchemes[]; + +// About URLs (including schemes). +extern const char kAboutAppCacheInternalsURL[]; +extern const char kAboutBlankURL[]; +extern const char kAboutBrowserCrash[]; +extern const char kAboutCacheURL[]; +extern const char kAboutNetInternalsURL[]; +extern const char kAboutCrashURL[]; +extern const char kAboutCreditsURL[]; +extern const char kAboutHangURL[]; +extern const char kAboutMemoryURL[]; +extern const char kAboutPluginsURL[]; +extern const char kAboutShorthangURL[]; +extern const char kAboutSystemURL[]; +extern const char kAboutTermsURL[]; +extern const char kAboutAboutURL[]; +extern const char kAboutDNSURL[]; +extern const char kAboutHistogramsURL[]; +extern const char kAboutVersionURL[]; + +// chrome: URLs (including schemes). Should be kept in sync with the +// components below. +extern const char kChromeUIAppLauncherURL[]; +extern const char kChromeUIBookmarksURL[]; +extern const char kChromeUIDevToolsURL[]; +extern const char kChromeUIDownloadsURL[]; +extern const char kChromeUIExtensionsURL[]; +extern const char kChromeUIFavIconURL[]; +extern const char kChromeUIFileBrowseURL[]; +extern const char kChromeUIHistoryURL[]; +extern const char kChromeUIHistory2URL[]; +extern const char kChromeUIIPCURL[]; +extern const char kChromeUIMediaplayerURL[]; +extern const char kChromeUINewTabURL[]; +extern const char kChromeUIOptionsURL[]; +extern const char kChromeUIPluginsURL[]; +extern const char kChromeUIPrintURL[]; +extern const char kChromeUIRegisterPageURL[]; +extern const char kChromeUISlideshowURL[]; + +// chrome components of URLs. Should be kept in sync with the full URLs +// above. +extern const char kChromeUIBookmarksHost[]; +extern const char kChromeUIDevToolsHost[]; +extern const char kChromeUIDialogHost[]; +extern const char kChromeUIDownloadsHost[]; +extern const char kChromeUIExtensionsHost[]; +extern const char kChromeUIFavIconHost[]; +extern const char kChromeUIFileBrowseHost[]; +extern const char kChromeUIHistoryHost[]; +extern const char kChromeUIHistory2Host[]; +extern const char kChromeUIInspectorHost[]; +extern const char kChromeUIMediaplayerHost[]; +extern const char kChromeUINetInternalsHost[]; +extern const char kChromeUINewTabHost[]; +extern const char kChromeUIOptionsHost[]; +extern const char kChromeUIPluginsHost[]; +extern const char kChromeUIPrintHost[]; +extern const char kChromeUIRegisterPageHost[]; +extern const char kChromeUIRemotingHost[]; +extern const char kChromeUIResourcesHost[]; +extern const char kChromeUISlideshowHost[]; +extern const char kChromeUISyncResourcesHost[]; +extern const char kChromeUIThumbnailPath[]; +extern const char kChromeUIThemePath[]; + +// AppCache related URL. +extern const char kAppCacheViewInternalsURL[]; + +// Cloud Print dialog URL components. +extern const char kCloudPrintResourcesURL[]; +extern const char kCloudPrintResourcesHost[]; + +// Network related URLs. +extern const char kNetworkViewCacheURL[]; +extern const char kNetworkViewInternalsURL[]; + +// Call near the beginning of startup to register Chrome's internal URLs that +// should be parsed as "standard" with the googleurl library. +void RegisterChromeSchemes(); + +} // namespace chrome + +#endif // CHROME_COMMON_URL_CONSTANTS_H_ diff --git a/chrome/common/utility_messages.h b/chrome/common/utility_messages.h new file mode 100644 index 0000000..867131f --- /dev/null +++ b/chrome/common/utility_messages.h @@ -0,0 +1,78 @@ +// Copyright (c) 2009 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 CHROME_COMMON_UTILITY_MESSAGES_H_ +#define CHROME_COMMON_UTILITY_MESSAGES_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/file_path.h" +#include "base/values.h" +#include "chrome/common/common_param_traits.h" +#include "chrome/common/extensions/update_manifest.h" +#include "ipc/ipc_message_utils.h" + +namespace IPC { + +// Traits for UpdateManifest::Result. +template <> +struct ParamTraits<UpdateManifest::Result> { + typedef UpdateManifest::Result param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.extension_id); + WriteParam(m, p.version); + WriteParam(m, p.browser_min_version); + WriteParam(m, p.package_hash); + WriteParam(m, p.crx_url); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return ReadParam(m, iter, &p->extension_id) && + ReadParam(m, iter, &p->version) && + ReadParam(m, iter, &p->browser_min_version) && + ReadParam(m, iter, &p->package_hash) && + ReadParam(m, iter, &p->crx_url); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.extension_id, l); + l->append(L", "); + LogParam(p.version, l); + l->append(L", "); + LogParam(p.browser_min_version, l); + l->append(L", "); + LogParam(p.package_hash, l); + l->append(L", "); + LogParam(p.crx_url, l); + l->append(L")"); + } +}; + +template<> +struct ParamTraits<UpdateManifest::Results> { + typedef UpdateManifest::Results param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.list); + WriteParam(m, p.daystart_elapsed_seconds); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return ReadParam(m, iter, &p->list) && + ReadParam(m, iter, &p->daystart_elapsed_seconds); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.list, l); + l->append(L", "); + LogParam(p.daystart_elapsed_seconds, l); + l->append(L")"); + } +}; + +} // namespace IPC + +#define MESSAGES_INTERNAL_FILE "chrome/common/utility_messages_internal.h" +#include "ipc/ipc_message_macros.h" + +#endif // CHROME_COMMON_UTILITY_MESSAGES_H_ diff --git a/chrome/common/utility_messages_internal.h b/chrome/common/utility_messages_internal.h new file mode 100644 index 0000000..9231501 --- /dev/null +++ b/chrome/common/utility_messages_internal.h @@ -0,0 +1,114 @@ +// Copyright (c) 2009 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 <string> +#include <vector> + +// This header is meant to be included in multiple passes, hence no traditional +// header guard. It is included by utility_messages_internal.h +// See ipc_message_macros.h for explanation of the macros and passes. + +// This file needs to be included again, even though we're actually included +// from it via utility_messages.h. +#include "ipc/ipc_message_macros.h" + +#include "base/platform_file.h" +#include "gfx/rect.h" +#include "printing/native_metafile.h" +#include "printing/page_range.h" +#include "third_party/skia/include/core/SkBitmap.h" + +//------------------------------------------------------------------------------ +// Utility process messages: +// These are messages from the browser to the utility process. +IPC_BEGIN_MESSAGES(Utility) + + // Tell the utility process to unpack the given extension file in its + // directory and verify that it is valid. + IPC_MESSAGE_CONTROL1(UtilityMsg_UnpackExtension, + FilePath /* extension_filename */) + + // Tell the utility process to parse the given JSON data and verify its + // validity. + IPC_MESSAGE_CONTROL1(UtilityMsg_UnpackWebResource, + std::string /* JSON data */) + + // Tell the utility process to parse the given xml document. + IPC_MESSAGE_CONTROL1(UtilityMsg_ParseUpdateManifest, + std::string /* xml document contents */) + + // Tell the utility process to decode the given image data. + IPC_MESSAGE_CONTROL1(UtilityMsg_DecodeImage, + std::vector<unsigned char>) // encoded image contents + + // Tell the utility process to render the given PDF into a metafile. + IPC_MESSAGE_CONTROL4(UtilityMsg_RenderPDFPagesToMetafile, + base::PlatformFile, // PDF file + gfx::Rect, // Render Area + int, // DPI + std::vector<printing::PageRange>) +IPC_END_MESSAGES(Utility) + +//------------------------------------------------------------------------------ +// Utility process host messages: +// These are messages from the utility process to the browser. +IPC_BEGIN_MESSAGES(UtilityHost) + + // Reply when the utility process is done unpacking an extension. |manifest| + // is the parsed manifest.json file. + // The unpacker should also have written out files containing the decoded + // images and message catalogs from the extension. See ExtensionUnpacker for + // details. + IPC_MESSAGE_CONTROL1(UtilityHostMsg_UnpackExtension_Succeeded, + DictionaryValue /* manifest */) + + // Reply when the utility process has failed while unpacking an extension. + // |error_message| is a user-displayable explanation of what went wrong. + IPC_MESSAGE_CONTROL1(UtilityHostMsg_UnpackExtension_Failed, + std::string /* error_message, if any */) + + // Reply when the utility process is done unpacking and parsing JSON data + // from a web resource. + IPC_MESSAGE_CONTROL1(UtilityHostMsg_UnpackWebResource_Succeeded, + DictionaryValue /* json data */) + + // Reply when the utility process has failed while unpacking and parsing a + // web resource. |error_message| is a user-readable explanation of what + // went wrong. + IPC_MESSAGE_CONTROL1(UtilityHostMsg_UnpackWebResource_Failed, + std::string /* error_message, if any */) + + // Reply when the utility process has succeeded in parsing an update manifest + // xml document. + IPC_MESSAGE_CONTROL1(UtilityHostMsg_ParseUpdateManifest_Succeeded, + UpdateManifest::Results /* updates */) + + // Reply when an error occured parsing the update manifest. |error_message| + // is a description of what went wrong suitable for logging. + IPC_MESSAGE_CONTROL1(UtilityHostMsg_ParseUpdateManifest_Failed, + std::string /* error_message, if any */) + + // Reply when the utility process has succeeded in decoding the image. + IPC_MESSAGE_CONTROL1(UtilityHostMsg_DecodeImage_Succeeded, + SkBitmap) // decoded image + + // Reply when an error occured decoding the image. + IPC_MESSAGE_CONTROL0(UtilityHostMsg_DecodeImage_Failed) + + // Reply when the utility process has succeeded in rendering the PDF. + IPC_MESSAGE_CONTROL2(UtilityHostMsg_RenderPDFPagesToMetafile_Succeeded, + printing::NativeMetafile, // Output metafile + int) // Highest rendered page number + + // Reply when an error occured rendering the PDF. + IPC_MESSAGE_CONTROL0(UtilityHostMsg_RenderPDFPagesToMetafile_Failed) + +#if defined(OS_WIN) + // Request that the given font be loaded by the host so it's cached by the + // OS. Please see ChildProcessHost::PreCacheFont for details. + IPC_SYNC_MESSAGE_CONTROL1_0(UtilityHostMsg_PreCacheFont, + LOGFONT /* font data */) +#endif // defined(OS_WIN) + +IPC_END_MESSAGES(UtilityHost) diff --git a/chrome/common/view_types.cc b/chrome/common/view_types.cc new file mode 100644 index 0000000..c32174b --- /dev/null +++ b/chrome/common/view_types.cc @@ -0,0 +1,14 @@ +// Copyright (c) 2010 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 "chrome/common/view_types.h" + +const char* ViewType::kTabContents = "TAB"; +const char* ViewType::kToolstrip = "TOOLSTRIP"; +const char* ViewType::kMole = "MOLE"; +const char* ViewType::kBackgroundPage = "BACKGROUND"; +const char* ViewType::kPopup = "POPUP"; +const char* ViewType::kInfobar = "INFOBAR"; +const char* ViewType::kNotification = "NOTIFICATION"; +const char* ViewType::kAll = "ALL"; diff --git a/chrome/common/view_types.h b/chrome/common/view_types.h new file mode 100644 index 0000000..697ebbd --- /dev/null +++ b/chrome/common/view_types.h @@ -0,0 +1,45 @@ +// Copyright (c) 2010 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 CHROME_COMMON_VIEW_TYPES_H_ +#define CHROME_COMMON_VIEW_TYPES_H_ + +#include "base/basictypes.h" + +// Indicates different types of views +class ViewType { + public: + enum Type { + INVALID, + BACKGROUND_CONTENTS, + TAB_CONTENTS, + EXTENSION_TOOLSTRIP, + EXTENSION_MOLE, + EXTENSION_BACKGROUND_PAGE, + EXTENSION_POPUP, + EXTENSION_INFOBAR, + DEV_TOOLS_UI, + INTERSTITIAL_PAGE, + NOTIFICATION, + }; + + // Constant strings corresponding to the Type enumeration values. Used + // when converting JS arguments. + static const char* kTabContents; + static const char* kToolstrip; + static const char* kMole; + static const char* kBackgroundPage; + static const char* kPopup; + static const char* kInfobar; + static const char* kNotification; + static const char* kAll; + + private: + // This class is for scoping only, so you shouldn't create an instance of it. + ViewType() {} + + DISALLOW_COPY_AND_ASSIGN(ViewType); +}; + +#endif // CHROME_COMMON_VIEW_TYPES_H_ diff --git a/chrome/common/visitedlink_common.cc b/chrome/common/visitedlink_common.cc new file mode 100644 index 0000000..2782311 --- /dev/null +++ b/chrome/common/visitedlink_common.cc @@ -0,0 +1,89 @@ +// Copyright (c) 2006-2008 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 "chrome/common/visitedlink_common.h" + +#include "base/logging.h" +#include "base/md5.h" + +const VisitedLinkCommon::Fingerprint VisitedLinkCommon::null_fingerprint_ = 0; +const VisitedLinkCommon::Hash VisitedLinkCommon::null_hash_ = -1; + +VisitedLinkCommon::VisitedLinkCommon() + : hash_table_(NULL), + table_length_(0) { +} + +VisitedLinkCommon::~VisitedLinkCommon() { +} + +// FIXME: this uses linear probing, it should be replaced with quadratic +// probing or something better. See VisitedLinkMaster::AddFingerprint +bool VisitedLinkCommon::IsVisited(const char* canonical_url, + size_t url_len) const { + if (url_len == 0) + return false; + if (!hash_table_ || table_length_ == 0) + return false; + return IsVisited(ComputeURLFingerprint(canonical_url, url_len)); +} + +bool VisitedLinkCommon::IsVisited(Fingerprint fingerprint) const { + // Go through the table until we find the item or an empty spot (meaning it + // wasn't found). This loop will terminate as long as the table isn't full, + // which should be enforced by AddFingerprint. + Hash first_hash = HashFingerprint(fingerprint); + Hash cur_hash = first_hash; + while (true) { + Fingerprint cur_fingerprint = FingerprintAt(cur_hash); + if (cur_fingerprint == null_fingerprint_) + return false; // End of probe sequence found. + if (cur_fingerprint == fingerprint) + return true; // Found a match. + + // This spot was taken, but not by the item we're looking for, search in + // the next position. + cur_hash++; + if (cur_hash == table_length_) + cur_hash = 0; + if (cur_hash == first_hash) { + // Wrapped around and didn't find an empty space, this means we're in an + // infinite loop because AddFingerprint didn't do its job resizing. + NOTREACHED(); + return false; + } + } +} + +// Uses the top 64 bits of the MD5 sum of the canonical URL as the fingerprint, +// this is as random as any other subset of the MD5SUM. +// +// FIXME: this uses the MD5SUM of the 16-bit character version. For systems +// where wchar_t is not 16 bits (Linux uses 32 bits, I think), this will not be +// compatable. We should define explicitly what should happen here across +// platforms, and convert if necessary (probably to UTF-16). + +// static +VisitedLinkCommon::Fingerprint VisitedLinkCommon::ComputeURLFingerprint( + const char* canonical_url, + size_t url_len, + const uint8 salt[LINK_SALT_LENGTH]) { + DCHECK(url_len > 0) << "Canonical URLs should not be empty"; + + MD5Context ctx; + MD5Init(&ctx); + MD5Update(&ctx, salt, sizeof(salt)); + MD5Update(&ctx, canonical_url, url_len * sizeof(char)); + + MD5Digest digest; + MD5Final(&digest, &ctx); + + // This is the same as "return *(Fingerprint*)&digest.a;" but if we do that + // direct cast the alignment could be wrong, and we can't access a 64-bit int + // on arbitrary alignment on some processors. This reinterpret_casts it + // down to a char array of the same size as fingerprint, and then does the + // bit cast, which amounts to a memcpy. This does not handle endian issues. + return bit_cast<Fingerprint, uint8[8]>( + *reinterpret_cast<uint8(*)[8]>(&digest.a)); +} diff --git a/chrome/common/visitedlink_common.h b/chrome/common/visitedlink_common.h new file mode 100644 index 0000000..0e79c04 --- /dev/null +++ b/chrome/common/visitedlink_common.h @@ -0,0 +1,137 @@ +// Copyright (c) 2006-2008 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 CHROME_COMMON_VISITEDLINK_COMMON_H__ +#define CHROME_COMMON_VISITEDLINK_COMMON_H__ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/logging.h" +#include "googleurl/src/gurl.h" + +// number of bytes in the salt +#define LINK_SALT_LENGTH 8 + +// A multiprocess-safe database of the visited links for the browser. There +// should be exactly one process that has write access (implemented by +// VisitedLinkMaster), while all other processes should be read-only +// (implemented by VisitedLinkSlave). These other processes add links by calling +// the writer process to add them for it. The writer may also notify the readers +// to replace their table when the table is resized. +// +// IPC is not implemented in these classes. This is done through callback +// functions supplied by the creator of these objects to allow more flexibility, +// especially for testing. +// +// This class defines the common base for these others. We implement accessors +// for looking things up in the hash table, and for computing hash values and +// fingerprints. Both the master and the slave inherit from this, and add their +// own code to set up and change these values as their design requires. The +// slave pretty much just sets up the shared memory and saves the pointer. The +// master does a lot of work to manage the table, reading and writing it to and +// from disk, and resizing it when it gets too full. +// +// To ask whether a page is in history, we compute a 64-bit fingerprint of the +// URL. This URL is hashed and we see if it is in the URL hashtable. If it is, +// we consider it visited. Otherwise, it is unvisited. Note that it is possible +// to get collisions, which is the penalty for not storing all URL strings in +// memory (which could get to be more than we want to have in memory). We use +// a salt value for the links on one computer so that an attacker can not +// manually create a link that causes a collision. +class VisitedLinkCommon { + public: + // A number that identifies the URL. + typedef uint64 Fingerprint; + typedef std::vector<Fingerprint> Fingerprints; + + // A hash value of a fingerprint + typedef int32 Hash; + + // A fingerprint or hash value that does not exist + static const Fingerprint null_fingerprint_; + static const Hash null_hash_; + + VisitedLinkCommon(); + virtual ~VisitedLinkCommon(); + + // Returns the fingerprint for the given URL. + Fingerprint ComputeURLFingerprint(const char* canonical_url, + size_t url_len) const { + return ComputeURLFingerprint(canonical_url, url_len, salt_); + } + + // Looks up the given key in the table. The fingerprint for the URL is + // computed if you call one with the string argument. Returns true if found. + // Does not modify the hastable. + bool IsVisited(const char* canonical_url, size_t url_len) const; + bool IsVisited(const GURL& url) const { + return IsVisited(url.spec().data(), url.spec().size()); + } + bool IsVisited(Fingerprint fingerprint) const; + +#ifdef UNIT_TEST + // Returns statistics about DB usage + void GetUsageStatistics(int32* table_size, + VisitedLinkCommon::Fingerprint** fingerprints) { + *table_size = table_length_; + *fingerprints = hash_table_; + } +#endif + + protected: + // This structure is at the beginning of the shared memory so that the slaves + // can get stats on the table + struct SharedHeader { + // see goes into table_length_ + uint32 length; + + // goes into salt_ + uint8 salt[LINK_SALT_LENGTH]; + }; + + // Returns the fingerprint at the given index into the URL table. This + // function should be called instead of accessing the table directly to + // contain endian issues. + Fingerprint FingerprintAt(int32 table_offset) const { + if (!hash_table_) + return null_fingerprint_; + return hash_table_[table_offset]; + } + + // Computes the fingerprint of the given canonical URL. It is static so the + // same algorithm can be re-used by the table rebuilder, so you will have to + // pass the salt as a parameter. See the non-static version above if you + // want to use the current class' salt. + static Fingerprint ComputeURLFingerprint(const char* canonical_url, + size_t url_len, + const uint8 salt[LINK_SALT_LENGTH]); + + // Computes the hash value of the given fingerprint, this is used as a lookup + // into the hashtable. + static Hash HashFingerprint(Fingerprint fingerprint, int32 table_length) { + if (table_length == 0) + return null_hash_; + return static_cast<Hash>(fingerprint % table_length); + } + // Uses the current hashtable. + Hash HashFingerprint(Fingerprint fingerprint) const { + return HashFingerprint(fingerprint, table_length_); + } + + // pointer to the first item + VisitedLinkCommon::Fingerprint* hash_table_; + + // the number of items in the hash table + int32 table_length_; + + // salt used for each URL when computing the fingerprint + uint8 salt_[LINK_SALT_LENGTH]; + + private: + DISALLOW_COPY_AND_ASSIGN(VisitedLinkCommon); +}; + +#endif // CHROME_COMMON_VISITEDLINK_COMMON_H_ diff --git a/chrome/common/web_database_observer_impl.cc b/chrome/common/web_database_observer_impl.cc new file mode 100644 index 0000000..8c008e4 --- /dev/null +++ b/chrome/common/web_database_observer_impl.cc @@ -0,0 +1,52 @@ +// Copyright (c) 2010 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 "chrome/common/web_database_observer_impl.h" + +#include "base/auto_reset.h" +#include "base/message_loop.h" +#include "base/string16.h" +#include "chrome/common/render_messages.h" +#include "third_party/WebKit/WebKit/chromium/public/WebDatabase.h" + +WebDatabaseObserverImpl::WebDatabaseObserverImpl( + IPC::Message::Sender* sender) + : sender_(sender), + waiting_for_dbs_to_close_(false) { +} + +void WebDatabaseObserverImpl::databaseOpened( + const WebKit::WebDatabase& database) { + string16 origin_identifier = database.securityOrigin().databaseIdentifier(); + string16 database_name = database.name(); + sender_->Send(new ViewHostMsg_DatabaseOpened( + origin_identifier, database_name, + database.displayName(), database.estimatedSize())); + database_connections_.AddConnection(origin_identifier, database_name); +} + +void WebDatabaseObserverImpl::databaseModified( + const WebKit::WebDatabase& database) { + sender_->Send(new ViewHostMsg_DatabaseModified( + database.securityOrigin().databaseIdentifier(), database.name())); +} + +void WebDatabaseObserverImpl::databaseClosed( + const WebKit::WebDatabase& database) { + string16 origin_identifier = database.securityOrigin().databaseIdentifier(); + string16 database_name = database.name(); + sender_->Send(new ViewHostMsg_DatabaseClosed( + origin_identifier, database_name)); + database_connections_.RemoveConnection(origin_identifier, database_name); + if (waiting_for_dbs_to_close_ && database_connections_.IsEmpty()) + MessageLoop::current()->Quit(); +} + +void WebDatabaseObserverImpl::WaitForAllDatabasesToClose() { + if (!database_connections_.IsEmpty()) { + AutoReset<bool> waiting_for_dbs_auto_reset(&waiting_for_dbs_to_close_, true); + MessageLoop::ScopedNestableTaskAllower nestable(MessageLoop::current()); + MessageLoop::current()->Run(); + } +} diff --git a/chrome/common/web_database_observer_impl.h b/chrome/common/web_database_observer_impl.h new file mode 100644 index 0000000..3f5e80b --- /dev/null +++ b/chrome/common/web_database_observer_impl.h @@ -0,0 +1,27 @@ +// Copyright (c) 2010 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 CHROME_COMMON_WEB_DATABASE_OBSERVER_IMPL_H_ +#define CHROME_COMMON_WEB_DATABASE_OBSERVER_IMPL_H_ + +#include "ipc/ipc_message.h" +#include "third_party/WebKit/WebKit/chromium/public/WebDatabaseObserver.h" +#include "webkit/database/database_connections.h" + +class WebDatabaseObserverImpl : public WebKit::WebDatabaseObserver { + public: + explicit WebDatabaseObserverImpl(IPC::Message::Sender* sender); + virtual void databaseOpened(const WebKit::WebDatabase& database); + virtual void databaseModified(const WebKit::WebDatabase& database); + virtual void databaseClosed(const WebKit::WebDatabase& database); + + void WaitForAllDatabasesToClose(); + + private: + IPC::Message::Sender* sender_; + bool waiting_for_dbs_to_close_; + webkit_database::DatabaseConnections database_connections_; +}; + +#endif // CHROME_COMMON_WEB_DATABASE_OBSERVER_IMPL_H_ diff --git a/chrome/common/web_resource/web_resource_unpacker.cc b/chrome/common/web_resource/web_resource_unpacker.cc new file mode 100644 index 0000000..bbb14cf --- /dev/null +++ b/chrome/common/web_resource/web_resource_unpacker.cc @@ -0,0 +1,38 @@ +// Copyright (c) 2009 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 "chrome/common/web_resource/web_resource_unpacker.h" + +#include "base/json/json_reader.h" +#include "base/values.h" + +const char* WebResourceUnpacker::kInvalidDataTypeError = + "Data from web resource server is missing or not valid JSON."; + +const char* WebResourceUnpacker::kUnexpectedJSONFormatError = + "Data from web resource server does not have expected format."; + +// TODO(mrc): Right now, this reads JSON data from the experimental popgadget +// server. Change so the format is based on a template, once we have +// decided on final server format. +bool WebResourceUnpacker::Run() { + scoped_ptr<Value> value; + if (!resource_data_.empty()) { + value.reset(base::JSONReader::Read(resource_data_, false)); + if (!value.get()) { + // Page information not properly read, or corrupted. + error_message_ = kInvalidDataTypeError; + return false; + } + if (!value->IsType(Value::TYPE_DICTIONARY)) { + error_message_ = kUnexpectedJSONFormatError; + return false; + } + parsed_json_.reset(static_cast<DictionaryValue*>(value.release())); + return true; + } + error_message_ = kInvalidDataTypeError; + return false; +} + diff --git a/chrome/common/web_resource/web_resource_unpacker.h b/chrome/common/web_resource/web_resource_unpacker.h new file mode 100644 index 0000000..f07c06f --- /dev/null +++ b/chrome/common/web_resource/web_resource_unpacker.h @@ -0,0 +1,57 @@ +// Copyright (c) 2009 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 class is called by the WebResourceService in a sandboxed process +// to unpack data retrieved from a web resource feed. Right now, it +// takes a string of data in JSON format, parses it, and hands it back +// to the WebResourceService as a list of items. In the future +// it will be set up to unpack and verify image data in addition to +// just parsing a JSON feed. + +#ifndef CHROME_COMMON_WEB_RESOURCE_WEB_RESOURCE_UNPACKER_H_ +#define CHROME_COMMON_WEB_RESOURCE_WEB_RESOURCE_UNPACKER_H_ + +#include <string> + +#include "base/file_path.h" +#include "base/scoped_ptr.h" + +class DictionaryValue; + +class WebResourceUnpacker { + public: + static const char* kInvalidDataTypeError; + static const char* kUnexpectedJSONFormatError; + + explicit WebResourceUnpacker(const std::string &resource_data) + : resource_data_(resource_data) {} + + // This does the actual parsing. In case of an error, error_message_ + // is set to an appropriate value. + bool Run(); + + // Returns the last error message set by Run(). + const std::string& error_message() { return error_message_; } + + // Gets data which has been parsed by Run(). + DictionaryValue* parsed_json() { + return parsed_json_.get(); + } + + private: + // Holds the string which is to be parsed. + std::string resource_data_; + + // Holds the result of JSON parsing of resource_data_. + scoped_ptr<DictionaryValue> parsed_json_; + + // Holds the last error message produced by Run(). + std::string error_message_; + + DISALLOW_COPY_AND_ASSIGN(WebResourceUnpacker); +}; + +#endif // CHROME_COMMON_WEB_RESOURCE_WEB_RESOURCE_UNPACKER_H_ + + diff --git a/chrome/common/webkit_param_traits.h b/chrome/common/webkit_param_traits.h new file mode 100644 index 0000000..e277e38 --- /dev/null +++ b/chrome/common/webkit_param_traits.h @@ -0,0 +1,442 @@ +// Copyright (c) 2010 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 contains ParamTraits templates to support serialization of WebKit +// data types over IPC. +// +// NOTE: IT IS IMPORTANT THAT ONLY POD (plain old data) TYPES ARE SERIALIZED. +// +// There are several reasons for this restrictions: +// +// o We don't want inclusion of this file to imply linking to WebKit code. +// +// o Many WebKit structures are not thread-safe. WebString, for example, +// contains a reference counted buffer, which does not use thread-safe +// reference counting. If we allowed serializing WebString, then we may run +// the risk of introducing subtle thread-safety bugs if people passed a +// WebString across threads via PostTask(NewRunnableMethod(...)). +// +// o The WebKit API has redundant types for strings, and we should avoid using +// those beyond code that interfaces with the WebKit API. + +#ifndef CHROME_COMMON_WEBKIT_PARAM_TRAITS_H_ +#define CHROME_COMMON_WEBKIT_PARAM_TRAITS_H_ + +#include "ipc/ipc_message_utils.h" +#include "third_party/WebKit/WebKit/chromium/public/WebCache.h" +#include "third_party/WebKit/WebKit/chromium/public/WebCompositionUnderline.h" +#include "third_party/WebKit/WebKit/chromium/public/WebConsoleMessage.h" +#include "third_party/WebKit/WebKit/chromium/public/WebContextMenuData.h" +#include "third_party/WebKit/WebKit/chromium/public/WebDragOperation.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFindOptions.h" +#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h" +#include "third_party/WebKit/WebKit/chromium/public/WebMediaPlayerAction.h" +#include "third_party/WebKit/WebKit/chromium/public/WebPopupType.h" +#include "third_party/WebKit/WebKit/chromium/public/WebScreenInfo.h" +#include "third_party/WebKit/WebKit/chromium/public/WebTextDirection.h" +#include "third_party/WebKit/WebKit/chromium/public/WebTextInputType.h" + +namespace IPC { + +template <> +struct ParamTraits<WebKit::WebRect> { + typedef WebKit::WebRect param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.x); + WriteParam(m, p.y); + WriteParam(m, p.width); + WriteParam(m, p.height); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->x) && + ReadParam(m, iter, &p->y) && + ReadParam(m, iter, &p->width) && + ReadParam(m, iter, &p->height); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.x, l); + l->append(L", "); + LogParam(p.y, l); + l->append(L", "); + LogParam(p.width, l); + l->append(L", "); + LogParam(p.height, l); + l->append(L")"); + } +}; + +template <> +struct ParamTraits<WebKit::WebScreenInfo> { + typedef WebKit::WebScreenInfo param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.depth); + WriteParam(m, p.depthPerComponent); + WriteParam(m, p.isMonochrome); + WriteParam(m, p.rect); + WriteParam(m, p.availableRect); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->depth) && + ReadParam(m, iter, &p->depthPerComponent) && + ReadParam(m, iter, &p->isMonochrome) && + ReadParam(m, iter, &p->rect) && + ReadParam(m, iter, &p->availableRect); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.depth, l); + l->append(L", "); + LogParam(p.depthPerComponent, l); + l->append(L", "); + LogParam(p.isMonochrome, l); + l->append(L", "); + LogParam(p.rect, l); + l->append(L", "); + LogParam(p.availableRect, l); + l->append(L")"); + } +}; + +template <> +struct ParamTraits<WebKit::WebConsoleMessage::Level> { + typedef WebKit::WebConsoleMessage::Level param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, static_cast<int>(p)); + } + static bool Read(const Message* m, void** iter, param_type* r) { + int value; + if (!ReadParam(m, iter, &value)) + return false; + *r = static_cast<param_type>(value); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + LogParam(static_cast<int>(p), l); + } +}; + +template <> +struct ParamTraits<WebKit::WebPopupType> { + typedef WebKit::WebPopupType param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, static_cast<int>(p)); + } + static bool Read(const Message* m, void** iter, param_type* r) { + int value; + if (!ReadParam(m, iter, &value)) + return false; + *r = static_cast<param_type>(value); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + LogParam(static_cast<int>(p), l); + } +}; + +template <> +struct ParamTraits<WebKit::WebFindOptions> { + typedef WebKit::WebFindOptions param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.forward); + WriteParam(m, p.matchCase); + WriteParam(m, p.findNext); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->forward) && + ReadParam(m, iter, &p->matchCase) && + ReadParam(m, iter, &p->findNext); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.forward, l); + l->append(L", "); + LogParam(p.matchCase, l); + l->append(L", "); + LogParam(p.findNext, l); + l->append(L")"); + } +}; + +template <> +struct ParamTraits<WebKit::WebInputEvent::Type> { + typedef WebKit::WebInputEvent::Type param_type; + static void Write(Message* m, const param_type& p) { + m->WriteInt(p); + } + static bool Read(const Message* m, void** iter, param_type* p) { + int type; + if (!m->ReadInt(iter, &type)) + return false; + *p = static_cast<WebKit::WebInputEvent::Type>(type); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + const wchar_t* type; + switch (p) { + case WebKit::WebInputEvent::MouseDown: + type = L"MouseDown"; + break; + case WebKit::WebInputEvent::MouseUp: + type = L"MouseUp"; + break; + case WebKit::WebInputEvent::MouseMove: + type = L"MouseMove"; + break; + case WebKit::WebInputEvent::MouseLeave: + type = L"MouseLeave"; + break; + case WebKit::WebInputEvent::MouseEnter: + type = L"MouseEnter"; + break; + case WebKit::WebInputEvent::MouseWheel: + type = L"MouseWheel"; + break; + case WebKit::WebInputEvent::RawKeyDown: + type = L"RawKeyDown"; + break; + case WebKit::WebInputEvent::KeyDown: + type = L"KeyDown"; + break; + case WebKit::WebInputEvent::KeyUp: + type = L"KeyUp"; + break; + default: + type = L"None"; + break; + } + LogParam(std::wstring(type), l); + } +}; + +template <> +struct ParamTraits<WebKit::WebCache::UsageStats> { + typedef WebKit::WebCache::UsageStats param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.minDeadCapacity); + WriteParam(m, p.maxDeadCapacity); + WriteParam(m, p.capacity); + WriteParam(m, p.liveSize); + WriteParam(m, p.deadSize); + } + static bool Read(const Message* m, void** iter, param_type* r) { + return + ReadParam(m, iter, &r->minDeadCapacity) && + ReadParam(m, iter, &r->maxDeadCapacity) && + ReadParam(m, iter, &r->capacity) && + ReadParam(m, iter, &r->liveSize) && + ReadParam(m, iter, &r->deadSize); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<WebCache::UsageStats>"); + } +}; + +template <> +struct ParamTraits<WebKit::WebCache::ResourceTypeStat> { + typedef WebKit::WebCache::ResourceTypeStat param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.count); + WriteParam(m, p.size); + WriteParam(m, p.liveSize); + WriteParam(m, p.decodedSize); + } + static bool Read(const Message* m, void** iter, param_type* r) { + bool result = + ReadParam(m, iter, &r->count) && + ReadParam(m, iter, &r->size) && + ReadParam(m, iter, &r->liveSize) && + ReadParam(m, iter, &r->decodedSize); + return result; + } + static void Log(const param_type& p, std::wstring* l) { + l->append(StringPrintf(L"%d %d %d %d", p.count, p.size, p.liveSize, + p.decodedSize)); + } +}; + +template <> +struct ParamTraits<WebKit::WebCache::ResourceTypeStats> { + typedef WebKit::WebCache::ResourceTypeStats param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.images); + WriteParam(m, p.cssStyleSheets); + WriteParam(m, p.scripts); + WriteParam(m, p.xslStyleSheets); + WriteParam(m, p.fonts); + } + static bool Read(const Message* m, void** iter, param_type* r) { + bool result = + ReadParam(m, iter, &r->images) && + ReadParam(m, iter, &r->cssStyleSheets) && + ReadParam(m, iter, &r->scripts) && + ReadParam(m, iter, &r->xslStyleSheets) && + ReadParam(m, iter, &r->fonts); + return result; + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<WebCoreStats>"); + LogParam(p.images, l); + LogParam(p.cssStyleSheets, l); + LogParam(p.scripts, l); + LogParam(p.xslStyleSheets, l); + LogParam(p.fonts, l); + l->append(L"</WebCoreStats>"); + } +}; + +template <> +struct ParamTraits<WebKit::WebTextDirection> { + typedef WebKit::WebTextDirection param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, static_cast<int>(p)); + } + static bool Read(const Message* m, void** iter, param_type* r) { + int value; + if (!ReadParam(m, iter, &value)) + return false; + *r = static_cast<param_type>(value); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + LogParam(static_cast<int>(p), l); + } +}; + +template <> +struct ParamTraits<WebKit::WebDragOperation> { + typedef WebKit::WebDragOperation param_type; + static void Write(Message* m, const param_type& p) { + m->WriteInt(p); + } + static bool Read(const Message* m, void** iter, param_type* r) { + int temp; + bool res = m->ReadInt(iter, &temp); + *r = static_cast<param_type>(temp); + return res; + } + static void Log(const param_type& p, std::wstring* l) { + l->append(StringPrintf(L"%d", p)); + } +}; + +template <> +struct ParamTraits<WebKit::WebMediaPlayerAction> { + typedef WebKit::WebMediaPlayerAction param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, static_cast<int>(p.type)); + WriteParam(m, p.enable); + } + static bool Read(const Message* m, void** iter, param_type* r) { + int temp; + if (!ReadParam(m, iter, &temp)) + return false; + r->type = static_cast<param_type::Type>(temp); + return ReadParam(m, iter, &r->enable); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + switch (p.type) { + case WebKit::WebMediaPlayerAction::Play: + l->append(L"Play"); + break; + case WebKit::WebMediaPlayerAction::Mute: + l->append(L"Mute"); + break; + case WebKit::WebMediaPlayerAction::Loop: + l->append(L"Loop"); + break; + default: + l->append(L"Unknown"); + break; + } + l->append(L", "); + LogParam(p.enable, l); + l->append(L")"); + } +}; + +template <> + struct ParamTraits<WebKit::WebContextMenuData::MediaType> { + typedef WebKit::WebContextMenuData::MediaType param_type; + static void Write(Message* m, const param_type& p) { + m->WriteInt(p); + } + static bool Read(const Message* m, void** iter, param_type* r) { + int temp; + bool res = m->ReadInt(iter, &temp); + *r = static_cast<param_type>(temp); + return res; + } +}; + +template <> +struct ParamTraits<WebKit::WebCompositionUnderline> { + typedef WebKit::WebCompositionUnderline param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.startOffset); + WriteParam(m, p.endOffset); + WriteParam(m, p.color); + WriteParam(m, p.thick); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->startOffset) && + ReadParam(m, iter, &p->endOffset) && + ReadParam(m, iter, &p->color) && + ReadParam(m, iter, &p->thick); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.startOffset, l); + l->append(L","); + LogParam(p.endOffset, l); + l->append(L":"); + LogParam(p.color, l); + l->append(L":"); + LogParam(p.thick, l); + l->append(L")"); + } +}; + +template <> +struct ParamTraits<WebKit::WebTextInputType> { + typedef WebKit::WebTextInputType param_type; + static void Write(Message* m, const param_type& p) { + m->WriteInt(p); + } + static bool Read(const Message* m, void** iter, param_type* p) { + int type; + if (!m->ReadInt(iter, &type)) + return false; + *p = static_cast<param_type>(type); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + std::wstring control; + switch (p) { + case WebKit::WebTextInputTypeNone: + control = L"WebKit::WebTextInputTypeNone"; + break; + case WebKit::WebTextInputTypeText: + control = L"WebKit::WebTextInputTypeText"; + break; + case WebKit::WebTextInputTypePassword: + control = L"WebKit::WebTextInputTypePassword"; + break; + default: + NOTIMPLEMENTED(); + control = L"UNKNOWN"; + break; + } + LogParam(control, l); + } +}; + +} // namespace IPC + +#endif // CHROME_COMMON_WEBKIT_PARAM_TRAITS_H_ diff --git a/chrome/common/webmessageportchannel_impl.cc b/chrome/common/webmessageportchannel_impl.cc new file mode 100644 index 0000000..24304fd --- /dev/null +++ b/chrome/common/webmessageportchannel_impl.cc @@ -0,0 +1,237 @@ +// Copyright (c) 2009 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 "chrome/common/webmessageportchannel_impl.h" + +#include "chrome/common/child_process.h" +#include "chrome/common/child_thread.h" +#include "chrome/common/worker_messages.h" +#include "third_party/WebKit/WebKit/chromium/public/WebString.h" +#include "third_party/WebKit/WebKit/chromium/public/WebMessagePortChannelClient.h" + +using WebKit::WebMessagePortChannel; +using WebKit::WebMessagePortChannelArray; +using WebKit::WebMessagePortChannelClient; +using WebKit::WebString; + +WebMessagePortChannelImpl::WebMessagePortChannelImpl() + : client_(NULL), + route_id_(MSG_ROUTING_NONE), + message_port_id_(MSG_ROUTING_NONE) { + AddRef(); + Init(); +} + +WebMessagePortChannelImpl::WebMessagePortChannelImpl( + int route_id, + int message_port_id) + : client_(NULL), + route_id_(route_id), + message_port_id_(message_port_id) { + AddRef(); + Init(); +} + +WebMessagePortChannelImpl::~WebMessagePortChannelImpl() { + // If we have any queued messages with attached ports, manually destroy them. + while (!message_queue_.empty()) { + const std::vector<WebMessagePortChannelImpl*>& channel_array = + message_queue_.front().ports; + for (size_t i = 0; i < channel_array.size(); i++) { + channel_array[i]->destroy(); + } + message_queue_.pop(); + } + + if (message_port_id_ != MSG_ROUTING_NONE) + Send(new WorkerProcessHostMsg_DestroyMessagePort(message_port_id_)); + + if (route_id_ != MSG_ROUTING_NONE) + ChildThread::current()->RemoveRoute(route_id_); +} + +void WebMessagePortChannelImpl::setClient(WebMessagePortChannelClient* client) { + // Must lock here since client_ is called on the main thread. + AutoLock auto_lock(lock_); + client_ = client; +} + +void WebMessagePortChannelImpl::destroy() { + setClient(NULL); + + // Release the object on the main thread, since the destructor might want to + // send an IPC, and that has to happen on the main thread. + ChildThread::current()->message_loop()->ReleaseSoon(FROM_HERE, this); +} + +void WebMessagePortChannelImpl::entangle(WebMessagePortChannel* channel) { + // The message port ids might not be set up yet, if this channel wasn't + // created on the main thread. So need to wait until we're on the main thread + // before getting the other message port id. + scoped_refptr<WebMessagePortChannelImpl> webchannel = + static_cast<WebMessagePortChannelImpl*>(channel); + Entangle(webchannel); +} + +void WebMessagePortChannelImpl::postMessage( + const WebString& message, + WebMessagePortChannelArray* channels) { + if (MessageLoop::current() != ChildThread::current()->message_loop()) { + ChildThread::current()->message_loop()->PostTask(FROM_HERE, + NewRunnableMethod(this, &WebMessagePortChannelImpl::postMessage, + message, channels)); + return; + } + + std::vector<int> message_port_ids(channels ? channels->size() : 0); + if (channels) { + // Extract the port IDs from the source array, then free it. + for (size_t i = 0; i < channels->size(); ++i) { + WebMessagePortChannelImpl* webchannel = + static_cast<WebMessagePortChannelImpl*>((*channels)[i]); + message_port_ids[i] = webchannel->message_port_id(); + webchannel->QueueMessages(); + DCHECK(message_port_ids[i] != MSG_ROUTING_NONE); + } + delete channels; + } + + IPC::Message* msg = new WorkerProcessHostMsg_PostMessage( + message_port_id_, message, message_port_ids); + Send(msg); +} + +bool WebMessagePortChannelImpl::tryGetMessage( + WebString* message, + WebMessagePortChannelArray& channels) { + AutoLock auto_lock(lock_); + if (message_queue_.empty()) + return false; + + *message = message_queue_.front().message; + const std::vector<WebMessagePortChannelImpl*>& channel_array = + message_queue_.front().ports; + WebMessagePortChannelArray result_ports(channel_array.size()); + for (size_t i = 0; i < channel_array.size(); i++) { + result_ports[i] = channel_array[i]; + } + + channels.swap(result_ports); + message_queue_.pop(); + return true; +} + +void WebMessagePortChannelImpl::Init() { + if (MessageLoop::current() != ChildThread::current()->message_loop()) { + ChildThread::current()->message_loop()->PostTask(FROM_HERE, + NewRunnableMethod(this, &WebMessagePortChannelImpl::Init)); + return; + } + + if (route_id_ == MSG_ROUTING_NONE) { + DCHECK(message_port_id_ == MSG_ROUTING_NONE); + Send(new WorkerProcessHostMsg_CreateMessagePort( + &route_id_, &message_port_id_)); + } + + ChildThread::current()->AddRoute(route_id_, this); +} + +void WebMessagePortChannelImpl::Entangle( + scoped_refptr<WebMessagePortChannelImpl> channel) { + if (MessageLoop::current() != ChildThread::current()->message_loop()) { + ChildThread::current()->message_loop()->PostTask(FROM_HERE, + NewRunnableMethod(this, &WebMessagePortChannelImpl::Entangle, channel)); + return; + } + + Send(new WorkerProcessHostMsg_Entangle( + message_port_id_, channel->message_port_id())); +} + +void WebMessagePortChannelImpl::QueueMessages() { + if (MessageLoop::current() != ChildThread::current()->message_loop()) { + ChildThread::current()->message_loop()->PostTask(FROM_HERE, + NewRunnableMethod(this, &WebMessagePortChannelImpl::QueueMessages)); + return; + } + // This message port is being sent elsewhere (perhaps to another process). + // The new endpoint needs to receive the queued messages, including ones that + // could still be in-flight. So we tell the browser to queue messages, and it + // sends us an ack, whose receipt we know means that no more messages are + // in-flight. We then send the queued messages to the browser, which prepends + // them to the ones it queued and it sends them to the new endpoint. + Send(new WorkerProcessHostMsg_QueueMessages(message_port_id_)); + + // The process could potentially go away while we're still waiting for + // in-flight messages. Ensure it stays alive. + ChildProcess::current()->AddRefProcess(); +} + +void WebMessagePortChannelImpl::Send(IPC::Message* message) { + if (MessageLoop::current() != ChildThread::current()->message_loop()) { + DCHECK(!message->is_sync()); + ChildThread::current()->message_loop()->PostTask(FROM_HERE, + NewRunnableMethod(this, &WebMessagePortChannelImpl::Send, message)); + return; + } + + ChildThread::current()->Send(message); +} + +void WebMessagePortChannelImpl::OnMessageReceived(const IPC::Message& message) { + IPC_BEGIN_MESSAGE_MAP(WebMessagePortChannelImpl, message) + IPC_MESSAGE_HANDLER(WorkerProcessMsg_Message, OnMessage) + IPC_MESSAGE_HANDLER(WorkerProcessMsg_MessagesQueued, OnMessagedQueued) + IPC_END_MESSAGE_MAP() +} + +void WebMessagePortChannelImpl::OnMessage( + const string16& message, + const std::vector<int>& sent_message_port_ids, + const std::vector<int>& new_routing_ids) { + AutoLock auto_lock(lock_); + Message msg; + msg.message = message; + if (!sent_message_port_ids.empty()) { + msg.ports.resize(sent_message_port_ids.size()); + for (size_t i = 0; i < sent_message_port_ids.size(); ++i) { + msg.ports[i] = new WebMessagePortChannelImpl( + new_routing_ids[i], sent_message_port_ids[i]); + } + } + + bool was_empty = message_queue_.empty(); + message_queue_.push(msg); + if (client_ && was_empty) + client_->messageAvailable(); +} + +void WebMessagePortChannelImpl::OnMessagedQueued() { + std::vector<QueuedMessage> queued_messages; + + { + AutoLock auto_lock(lock_); + queued_messages.reserve(message_queue_.size()); + while (!message_queue_.empty()) { + string16 message = message_queue_.front().message; + const std::vector<WebMessagePortChannelImpl*>& channel_array = + message_queue_.front().ports; + std::vector<int> port_ids(channel_array.size()); + for (size_t i = 0; i < channel_array.size(); ++i) { + port_ids[i] = channel_array[i]->message_port_id(); + } + queued_messages.push_back(std::make_pair(message, port_ids)); + message_queue_.pop(); + } + } + + Send(new WorkerProcessHostMsg_SendQueuedMessages( + message_port_id_, queued_messages)); + + message_port_id_ = MSG_ROUTING_NONE; + + Release(); + ChildProcess::current()->ReleaseProcess(); +} diff --git a/chrome/common/webmessageportchannel_impl.h b/chrome/common/webmessageportchannel_impl.h new file mode 100644 index 0000000..da52b9d --- /dev/null +++ b/chrome/common/webmessageportchannel_impl.h @@ -0,0 +1,74 @@ +// Copyright (c) 2009 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 CHROME_COMMON_WEBMESSAGEPORTCHANNEL_IMPL_H_ +#define CHROME_COMMON_WEBMESSAGEPORTCHANNEL_IMPL_H_ + +#include <queue> +#include <vector> + +#include "base/basictypes.h" +#include "base/lock.h" +#include "base/string16.h" +#include "base/ref_counted.h" +#include "ipc/ipc_channel.h" +#include "third_party/WebKit/WebKit/chromium/public/WebMessagePortChannel.h" + +// This is thread safe. +class WebMessagePortChannelImpl + : public WebKit::WebMessagePortChannel, + public IPC::Channel::Listener, + public base::RefCountedThreadSafe<WebMessagePortChannelImpl> { + public: + WebMessagePortChannelImpl(); + WebMessagePortChannelImpl(int route_id, int message_port_id); + + // Queues received and incoming messages until there are no more in-flight + // messages, then sends all of them to the browser process. + void QueueMessages(); + int message_port_id() const { return message_port_id_; } + + private: + friend class base::RefCountedThreadSafe<WebMessagePortChannelImpl>; + ~WebMessagePortChannelImpl(); + + // WebMessagePortChannel implementation. + virtual void setClient(WebKit::WebMessagePortChannelClient* client); + virtual void destroy(); + virtual void entangle(WebKit::WebMessagePortChannel* channel); + virtual void postMessage(const WebKit::WebString& message, + WebKit::WebMessagePortChannelArray* channels); + virtual bool tryGetMessage(WebKit::WebString* message, + WebKit::WebMessagePortChannelArray& channels); + + void Init(); + void Entangle(scoped_refptr<WebMessagePortChannelImpl> channel); + void Send(IPC::Message* message); + + // IPC::Channel::Listener implementation. + virtual void OnMessageReceived(const IPC::Message& message); + + void OnMessage(const string16& message, + const std::vector<int>& sent_message_port_ids, + const std::vector<int>& new_routing_ids); + void OnMessagedQueued(); + + struct Message { + string16 message; + std::vector<WebMessagePortChannelImpl*> ports; + }; + + typedef std::queue<Message> MessageQueue; + MessageQueue message_queue_; + + WebKit::WebMessagePortChannelClient* client_; + Lock lock_; // Locks access to above. + + int route_id_; // The routing id for this object. + int message_port_id_; // A globally unique identifier for this message port. + + DISALLOW_COPY_AND_ASSIGN(WebMessagePortChannelImpl); +}; + +#endif // CHROME_COMMON_WEBMESSAGEPORTCHANNEL_IMPL_H_ diff --git a/chrome/common/win_safe_util.cc b/chrome/common/win_safe_util.cc new file mode 100644 index 0000000..f215566 --- /dev/null +++ b/chrome/common/win_safe_util.cc @@ -0,0 +1,120 @@ +// Copyright (c) 2006-2008 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 <shlobj.h> +#include <shobjidl.h> + +#include "chrome/common/win_safe_util.h" + +#include "app/win_util.h" +#include "base/file_path.h" +#include "base/logging.h" +#include "base/path_service.h" +#include "base/scoped_comptr_win.h" +#include "base/string_util.h" + +namespace win_util { + +// This function implementation is based on the attachment execution +// services functionally deployed with IE6 or Service pack 2. This +// functionality is exposed in the IAttachmentExecute COM interface. +// more information at: +// http://msdn2.microsoft.com/en-us/library/ms647048.aspx +bool SaferOpenItemViaShell(HWND hwnd, const std::wstring& window_title, + const FilePath& full_path, + const std::wstring& source_url) { + ScopedComPtr<IAttachmentExecute> attachment_services; + HRESULT hr = attachment_services.CreateInstance(CLSID_AttachmentServices); + if (FAILED(hr)) { + // We don't have Attachment Execution Services, it must be a pre-XP.SP2 + // Windows installation, or the thread does not have COM initialized. + if (hr == CO_E_NOTINITIALIZED) { + NOTREACHED(); + return false; + } + return OpenItemViaShell(full_path); + } + + // This GUID is associated with any 'don't ask me again' settings that the + // user can select for different file types. + // {2676A9A2-D919-4fee-9187-152100393AB2} + static const GUID kClientID = { 0x2676a9a2, 0xd919, 0x4fee, + { 0x91, 0x87, 0x15, 0x21, 0x0, 0x39, 0x3a, 0xb2 } }; + + attachment_services->SetClientGuid(kClientID); + + if (!window_title.empty()) + attachment_services->SetClientTitle(window_title.c_str()); + + // To help windows decide if the downloaded file is dangerous we can provide + // what the documentation calls evidence. Which we provide now: + // + // Set the file itself as evidence. + hr = attachment_services->SetLocalPath(full_path.value().c_str()); + if (FAILED(hr)) + return false; + // Set the origin URL as evidence. + hr = attachment_services->SetSource(source_url.c_str()); + if (FAILED(hr)) + return false; + + // Now check the windows policy. + bool do_prompt; + hr = attachment_services->CheckPolicy(); + if (S_FALSE == hr) { + // The user prompt is required. + do_prompt = true; + } else if (S_OK == hr) { + // An S_OK means that the file is safe to open without user consent. + do_prompt = false; + } else { + // It is possible that the last call returns an undocumented result + // equal to 0x800c000e which seems to indicate that the URL failed the + // the security check. If you proceed with the Prompt() call the + // Shell might show a dialog that says: + // "windows found that this file is potentially harmful. To help protect + // your computer, Windows has blocked access to this file." + // Upon dismissal of the dialog windows will delete the file (!!). + // So, we can 'return' here but maybe is best to let it happen to fail on + // the safe side. + } + if (do_prompt) { + ATTACHMENT_ACTION action; + // We cannot control what the prompt says or does directly but it + // is a pretty decent dialog; for example, if an excutable is signed it can + // decode and show the publisher and the certificate. + hr = attachment_services->Prompt(hwnd, ATTACHMENT_PROMPT_EXEC, &action); + if (FAILED(hr) || (ATTACHMENT_ACTION_CANCEL == action)) + { + // The user has declined opening the item. + return false; + } + } + return OpenItemViaShellNoZoneCheck(full_path); +} + +bool SetInternetZoneIdentifier(const FilePath& full_path) { + const DWORD kShare = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + std::wstring path = full_path.value() + L":Zone.Identifier"; + HANDLE file = CreateFile(path.c_str(), GENERIC_WRITE, kShare, NULL, + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (INVALID_HANDLE_VALUE == file) + return false; + + const char kIdentifier[] = "[ZoneTransfer]\nZoneId=3"; + DWORD written = 0; + BOOL result = WriteFile(file, kIdentifier, arraysize(kIdentifier), &written, + NULL); + BOOL flush_result = FlushFileBuffers(file); + CloseHandle(file); + + if (!result || !flush_result || written != arraysize(kIdentifier)) { + NOTREACHED(); + return false; + } + + return true; +} + +} // namespace win_util diff --git a/chrome/common/win_safe_util.h b/chrome/common/win_safe_util.h new file mode 100644 index 0000000..d9c7097 --- /dev/null +++ b/chrome/common/win_safe_util.h @@ -0,0 +1,51 @@ +// Copyright (c) 2006-2008 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 CHROME_COMMON_WIN_SAFE_UTIL_H__ +#define CHROME_COMMON_WIN_SAFE_UTIL_H__ + +#include <string> +#include <windows.h> + +class FilePath; + +namespace win_util { + +// Open or run a downloaded file via the Windows shell, possibly showing first +// a consent dialog if the the file is deemed dangerous. This function is an +// enhancement over the OpenItemViaShell() function of win_util.h. +// +// The user consent dialog will be shown or not according to the windows +// execution policy defined in the registry which can be overridden per user. +// The mechanics of the policy are explained in the Microsoft Knowledge base +// number 883260: http://support.microsoft.com/kb/883260 +// +// The 'hwnd' is the handle to the parent window. In case a dialog is displayed +// the parent window will be disabled since the dialog is meant to be modal. +// The 'window_title' is the text displayed on the title bar of the dialog. If +// you pass an empty string the dialog will have a generic 'windows security' +// name on the title bar. +// +// You must provide a valid 'full_path' to the file to be opened and a well +// formed url in 'source_url'. The url should identify the source of the file +// but does not have to be network-reachable. If the url is malformed a +// dialog will be shown telling the user that the file will be blocked. +// +// In the event that there is no default application registered for the file +// specified by 'full_path' it ask the user, via the Windows "Open With" +// dialog. +// Returns 'true' on successful open, 'false' otherwise. +bool SaferOpenItemViaShell(HWND hwnd, const std::wstring& window_title, + const FilePath& full_path, + const std::wstring& source_url); + +// Sets the Zone Identifier on the file to "Internet" (3). Returns true if the +// function succeeds, false otherwise. A failure is expected on system where +// the Zone Identifier is not supported, like a machine with a FAT32 filesystem. +// It should not be considered fatal. +bool SetInternetZoneIdentifier(const FilePath& full_path); + +} // namespace win_util + +#endif // CHROME_COMMON_WIN_SAFE_UTIL_H_ diff --git a/chrome/common/window_container_type.cc b/chrome/common/window_container_type.cc new file mode 100644 index 0000000..b33618e --- /dev/null +++ b/chrome/common/window_container_type.cc @@ -0,0 +1,41 @@ +// Copyright (c) 2010 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 "chrome/common/window_container_type.h" + +#include "base/string_util.h" +#include "third_party/WebKit/WebKit/chromium/public/WebString.h" +#include "third_party/WebKit/WebKit/chromium/public/WebVector.h" +#include "third_party/WebKit/WebKit/chromium/public/WebWindowFeatures.h" + +namespace { + +const char kBackground[] = "background"; +const char kPersistent[] = "persistent"; + +} + +WindowContainerType WindowFeaturesToContainerType( + const WebKit::WebWindowFeatures& window_features) { + bool background = false; + bool persistent = false; + + for (size_t i = 0; i < window_features.additionalFeatures.size(); ++i) { + if (LowerCaseEqualsASCII(window_features.additionalFeatures[i], + kBackground)) + background = true; + else if (LowerCaseEqualsASCII(window_features.additionalFeatures[i], + kPersistent)) + persistent = true; + } + + if (background) { + if (persistent) + return WINDOW_CONTAINER_TYPE_PERSISTENT; + else + return WINDOW_CONTAINER_TYPE_BACKGROUND; + } else { + return WINDOW_CONTAINER_TYPE_NORMAL; + } +} diff --git a/chrome/common/window_container_type.h b/chrome/common/window_container_type.h new file mode 100644 index 0000000..303d1cc --- /dev/null +++ b/chrome/common/window_container_type.h @@ -0,0 +1,35 @@ +// Copyright (c) 2010 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 CHROME_COMMON_WINDOW_CONTAINER_TYPE_H_ +#define CHROME_COMMON_WINDOW_CONTAINER_TYPE_H_ + +namespace WebKit { + +struct WebWindowFeatures; + +} + +// "Container" types which can be requested via the window.open feature +// string. +enum WindowContainerType { + // A window shown in popup or tab. + WINDOW_CONTAINER_TYPE_NORMAL = 0, + + // A window run as a hidden "background" page. + WINDOW_CONTAINER_TYPE_BACKGROUND, + + // A window run as a hidden "background" page that wishes to be started + // upon browser launch and run beyond the lifetime of the pages that + // reference it. + WINDOW_CONTAINER_TYPE_PERSISTENT, + + WINDOW_CONTAINER_TYPE_MAX_VALUE +}; + +// Conversion function: +WindowContainerType WindowFeaturesToContainerType( + const WebKit::WebWindowFeatures& window_features); + +#endif // CHROME_COMMON_WINDOW_CONTAINER_TYPE_H_ diff --git a/chrome/common/worker_messages.h b/chrome/common/worker_messages.h new file mode 100644 index 0000000..1228ba3 --- /dev/null +++ b/chrome/common/worker_messages.h @@ -0,0 +1,133 @@ +// Copyright (c) 2009 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. + +// Defines messages between the browser and worker process, as well as between +// the renderer and worker process. + +#ifndef CHROME_COMMON_WORKER_MESSAGES_H_ +#define CHROME_COMMON_WORKER_MESSAGES_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "chrome/common/common_param_traits.h" +#include "googleurl/src/gurl.h" +#include "ipc/ipc_message_utils.h" + +typedef std::pair<string16, std::vector<int> > QueuedMessage; + +// Parameters structure for WorkerHostMsg_PostConsoleMessageToWorkerObject, +// which has too many data parameters to be reasonably put in a predefined +// IPC message. The data members directly correspond to parameters of +// WebWorkerClient::postConsoleMessageToWorkerObject() +struct WorkerHostMsg_PostConsoleMessageToWorkerObject_Params { + int source_identifier; + int message_type; + int message_level; + string16 message; + int line_number; + string16 source_url; +}; + +// Parameter structure for WorkerProcessMsg_CreateWorker. +struct WorkerProcessMsg_CreateWorker_Params { + GURL url; + bool is_shared; + string16 name; + int route_id; + int creator_process_id; + int creator_appcache_host_id; // Only valid for dedicated workers. + int64 shared_worker_appcache_id; // Only valid for shared workers. +}; + +namespace IPC { + +// Traits for WorkerHostMsg_PostConsoleMessageToWorkerObject_Params structure +// to pack/unpack. +template <> +struct ParamTraits<WorkerHostMsg_PostConsoleMessageToWorkerObject_Params> { + typedef WorkerHostMsg_PostConsoleMessageToWorkerObject_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.source_identifier); + WriteParam(m, p.message_type); + WriteParam(m, p.message_level); + WriteParam(m, p.message); + WriteParam(m, p.line_number); + WriteParam(m, p.source_url); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->source_identifier) && + ReadParam(m, iter, &p->message_type) && + ReadParam(m, iter, &p->message_level) && + ReadParam(m, iter, &p->message) && + ReadParam(m, iter, &p->line_number) && + ReadParam(m, iter, &p->source_url); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.source_identifier, l); + l->append(L", "); + LogParam(p.message_type, l); + l->append(L", "); + LogParam(p.message_level, l); + l->append(L", "); + LogParam(p.message, l); + l->append(L", "); + LogParam(p.line_number, l); + l->append(L", "); + LogParam(p.source_url, l); + l->append(L")"); + } +}; + +// Traits for WorkerProcessMsg_CreateWorker_Params. +template <> +struct ParamTraits<WorkerProcessMsg_CreateWorker_Params> { + typedef WorkerProcessMsg_CreateWorker_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.url); + WriteParam(m, p.is_shared); + WriteParam(m, p.name); + WriteParam(m, p.route_id); + WriteParam(m, p.creator_process_id); + WriteParam(m, p.creator_appcache_host_id); + WriteParam(m, p.shared_worker_appcache_id); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->url) && + ReadParam(m, iter, &p->is_shared) && + ReadParam(m, iter, &p->name) && + ReadParam(m, iter, &p->route_id) && + ReadParam(m, iter, &p->creator_process_id) && + ReadParam(m, iter, &p->creator_appcache_host_id) && + ReadParam(m, iter, &p->shared_worker_appcache_id); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.url, l); + l->append(L", "); + LogParam(p.is_shared, l); + l->append(L", "); + LogParam(p.name, l); + l->append(L", "); + LogParam(p.route_id, l); + l->append(L", "); + LogParam(p.creator_process_id, l); + l->append(L", "); + LogParam(p.creator_appcache_host_id, l); + l->append(L", "); + LogParam(p.shared_worker_appcache_id, l); + l->append(L")"); + } +}; + +} // namespace IPC + +#define MESSAGES_INTERNAL_FILE "chrome/common/worker_messages_internal.h" +#include "ipc/ipc_message_macros.h" + +#endif // CHROME_COMMON_WORKER_MESSAGES_H_ diff --git a/chrome/common/worker_messages_internal.h b/chrome/common/worker_messages_internal.h new file mode 100644 index 0000000..fed4096 --- /dev/null +++ b/chrome/common/worker_messages_internal.h @@ -0,0 +1,126 @@ +// Copyright (c) 2009 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 <utility> +#include <vector> +#include "base/string16.h" +#include "googleurl/src/gurl.h" +#include "ipc/ipc_message_macros.h" + + +//----------------------------------------------------------------------------- +// WorkerProcess messages +// These are messages sent from the browser to the worker process. +IPC_BEGIN_MESSAGES(WorkerProcess) + IPC_MESSAGE_CONTROL1(WorkerProcessMsg_CreateWorker, + WorkerProcessMsg_CreateWorker_Params) + + // Note: these Message Port related messages can also be sent to the + // renderer process. Putting them here since we don't have a shared place + // like common_messages_internal.h + IPC_MESSAGE_ROUTED3(WorkerProcessMsg_Message, + string16 /* message */, + std::vector<int> /* sent_message_port_ids */, + std::vector<int> /* new_routing_ids */) + + // Tells the Message Port Channel object that there are no more in-flight + // messages arriving. + IPC_MESSAGE_ROUTED0(WorkerProcessMsg_MessagesQueued) +IPC_END_MESSAGES(WorkerProcess) + + +//----------------------------------------------------------------------------- +// WorkerProcessHost messages +// These are messages sent from the worker process to the browser process. + +IPC_BEGIN_MESSAGES(WorkerProcessHost) + // Note: these Message Port related messages can also be sent out from the + // renderer process. Putting them here since we don't have a shared place + // like common_messages_internal.h + + // Creates a new Message Port Channel object. The first paramaeter is the + // message port channel's routing id in this process. The second parameter + // is the process-wide-unique identifier for that port. + IPC_SYNC_MESSAGE_CONTROL0_2(WorkerProcessHostMsg_CreateMessagePort, + int /* route_id */, + int /* message_port_id */) + + // Sent when a Message Port Channel object is destroyed. + IPC_MESSAGE_CONTROL1(WorkerProcessHostMsg_DestroyMessagePort, + int /* message_port_id */) + + // Sends a message to a message port. Optionally sends a message port as + // as well if sent_message_port_id != MSG_ROUTING_NONE. + IPC_MESSAGE_CONTROL3(WorkerProcessHostMsg_PostMessage, + int /* sender_message_port_id */, + string16 /* message */, + std::vector<int> /* sent_message_port_ids */) + + // Causes messages sent to the remote port to be delivered to this local port. + IPC_MESSAGE_CONTROL2(WorkerProcessHostMsg_Entangle, + int /* local_message_port_id */, + int /* remote_message_port_id */) + + // Causes the browser to queue messages sent to this port until the the port + // has made sure that all in-flight messages were routed to the new + // destination. + IPC_MESSAGE_CONTROL1(WorkerProcessHostMsg_QueueMessages, + int /* message_port_id */) + + // Sends the browser all the queued messages that arrived at this message port + // after it was sent in a postMessage call. + // NOTE: MSVS can't compile the macro if std::vector<std::pair<string16, int> > + // is used, so we typedef it in worker_messages.h. + IPC_MESSAGE_CONTROL2(WorkerProcessHostMsg_SendQueuedMessages, + int /* message_port_id */, + std::vector<QueuedMessage> /* queued_messages */) +IPC_END_MESSAGES(WorkerProcessHost) + +//----------------------------------------------------------------------------- +// Worker messages +// These are messages sent from the renderer process to the worker process. +IPC_BEGIN_MESSAGES(Worker) + IPC_MESSAGE_ROUTED3(WorkerMsg_StartWorkerContext, + GURL /* url */, + string16 /* user_agent */, + string16 /* source_code */) + + IPC_MESSAGE_ROUTED0(WorkerMsg_TerminateWorkerContext) + + IPC_MESSAGE_ROUTED3(WorkerMsg_PostMessage, + string16 /* message */, + std::vector<int> /* sent_message_port_ids */, + std::vector<int> /* new_routing_ids */) + + IPC_MESSAGE_ROUTED2(WorkerMsg_Connect, + int /* sent_message_port_id */, + int /* routing_id */) + + IPC_MESSAGE_ROUTED0(WorkerMsg_WorkerObjectDestroyed) +IPC_END_MESSAGES(Worker) + + +//----------------------------------------------------------------------------- +// WorkerHost messages +// These are messages sent from the worker process to the renderer process. +IPC_BEGIN_MESSAGES(WorkerHost) + // WorkerMsg_PostMessage is also sent here. + IPC_MESSAGE_ROUTED3(WorkerHostMsg_PostExceptionToWorkerObject, + string16 /* error_message */, + int /* line_number */, + string16 /* source_url*/) + + IPC_MESSAGE_ROUTED1(WorkerHostMsg_PostConsoleMessageToWorkerObject, + WorkerHostMsg_PostConsoleMessageToWorkerObject_Params) + + IPC_MESSAGE_ROUTED1(WorkerHostMsg_ConfirmMessageFromWorkerObject, + bool /* bool has_pending_activity */) + + IPC_MESSAGE_ROUTED1(WorkerHostMsg_ReportPendingActivity, + bool /* bool has_pending_activity */) + + IPC_MESSAGE_CONTROL1(WorkerHostMsg_WorkerContextClosed, + int /* worker_route_id */) + IPC_MESSAGE_ROUTED0(WorkerHostMsg_WorkerContextDestroyed) +IPC_END_MESSAGES(WorkerHost) diff --git a/chrome/common/worker_thread_ticker.cc b/chrome/common/worker_thread_ticker.cc new file mode 100644 index 0000000..452a9ff --- /dev/null +++ b/chrome/common/worker_thread_ticker.cc @@ -0,0 +1,101 @@ +// Copyright (c) 2010 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 "chrome/common/worker_thread_ticker.h" + +#include <algorithm> + +#include "base/logging.h" +#include "base/message_loop.h" +#include "base/task.h" +#include "base/thread.h" + +class WorkerThreadTicker::TimerTask : public Task { + public: + explicit TimerTask(WorkerThreadTicker* ticker) : ticker_(ticker) { + } + + virtual void Run() { + // When the ticker is running, the handler list CANNOT be modified. + // So we can do the enumeration safely without a lock + TickHandlerListType* handlers = &ticker_->tick_handler_list_; + for (TickHandlerListType::const_iterator i = handlers->begin(); + i != handlers->end(); ++i) { + (*i)->OnTick(); + } + + ticker_->ScheduleTimerTask(); + } + + private: + WorkerThreadTicker* ticker_; +}; + +WorkerThreadTicker::WorkerThreadTicker(int tick_interval) + : timer_thread_("worker_thread_ticker"), + is_running_(false), + tick_interval_(tick_interval) { +} + +WorkerThreadTicker::~WorkerThreadTicker() { + Stop(); +} + +bool WorkerThreadTicker::RegisterTickHandler(Callback *tick_handler) { + DCHECK(tick_handler); + AutoLock lock(lock_); + // You cannot change the list of handlers when the timer is running. + // You need to call Stop first. + if (IsRunning()) + return false; + tick_handler_list_.push_back(tick_handler); + return true; +} + +bool WorkerThreadTicker::UnregisterTickHandler(Callback *tick_handler) { + DCHECK(tick_handler); + AutoLock lock(lock_); + // You cannot change the list of handlers when the timer is running. + // You need to call Stop first. + if (IsRunning()) { + return false; + } + TickHandlerListType::iterator index = std::remove(tick_handler_list_.begin(), + tick_handler_list_.end(), + tick_handler); + if (index == tick_handler_list_.end()) { + return false; + } + tick_handler_list_.erase(index, tick_handler_list_.end()); + return true; +} + +bool WorkerThreadTicker::Start() { + // Do this in a lock because we don't want 2 threads to + // call Start at the same time + AutoLock lock(lock_); + if (IsRunning()) + return false; + if (!timer_thread_.Start()) + return false; + is_running_ = true; + ScheduleTimerTask(); + return true; +} + +bool WorkerThreadTicker::Stop() { + // Do this in a lock because we don't want 2 threads to + // call Stop at the same time + AutoLock lock(lock_); + if (!IsRunning()) + return false; + is_running_ = false; + timer_thread_.Stop(); + return true; +} + +void WorkerThreadTicker::ScheduleTimerTask() { + timer_thread_.message_loop()->PostDelayedTask(FROM_HERE, new TimerTask(this), + tick_interval_); +} diff --git a/chrome/common/worker_thread_ticker.h b/chrome/common/worker_thread_ticker.h new file mode 100644 index 0000000..bb39c3b --- /dev/null +++ b/chrome/common/worker_thread_ticker.h @@ -0,0 +1,90 @@ +// Copyright (c) 2009 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 CHROME_COMMON_WORKER_THREAD_TICKER_H_ +#define CHROME_COMMON_WORKER_THREAD_TICKER_H_ + +#include <vector> + +#include "base/lock.h" +#include "base/thread.h" + +// This class provides the following functionality: +// It invokes a set of registered handlers at periodic intervals in +// the context of an arbitrary worker thread. +// The timer runs on a separate thread, so it will run even if the current +// thread is hung. Similarly, the callbacks will be called on a separate +// thread so they won't block the main thread. +class WorkerThreadTicker { + public: + // This callback interface to be implemented by clients of this + // class + class Callback { + public: + // Gets invoked when the timer period is up + virtual void OnTick() = 0; + + protected: + virtual ~Callback() {} + }; + + // tick_interval is the periodic interval in which to invoke the + // registered handlers (in milliseconds) + explicit WorkerThreadTicker(int tick_interval); + + ~WorkerThreadTicker(); + + // Registers a callback handler interface + // tick_handler is the handler interface to register. The ownership of this + // object is not transferred to this class. + bool RegisterTickHandler(Callback *tick_handler); + + // Unregisters a callback handler interface + // tick_handler is the handler interface to unregister + bool UnregisterTickHandler(Callback *tick_handler); + + // Starts the ticker. Returns false if the ticker is already running + // or if the Start fails. + bool Start(); + // Stops the ticker and waits for all callbacks. to be done. This method + // does not provide a way to stop without waiting for the callbacks to be + // done because this is inherently risky. + // Returns false is the ticker is not running + bool Stop(); + bool IsRunning() const { + return is_running_; + } + + void set_tick_interval(int tick_interval) { + tick_interval_ = tick_interval; + } + + int tick_interval() const { + return tick_interval_; + } + + private: + class TimerTask; + + void ScheduleTimerTask(); + + // A list type that holds all registered callback interfaces + typedef std::vector<Callback*> TickHandlerListType; + + // Lock to protect is_running_ and tick_handler_list_ + Lock lock_; + + base::Thread timer_thread_; + bool is_running_; + + // The interval at which the callbacks are to be invoked + int tick_interval_; + + // A list that holds all registered callback interfaces + TickHandlerListType tick_handler_list_; + + DISALLOW_COPY_AND_ASSIGN(WorkerThreadTicker); +}; + +#endif // CHROME_COMMON_WORKER_THREAD_TICKER_H_ diff --git a/chrome/common/worker_thread_ticker_unittest.cc b/chrome/common/worker_thread_ticker_unittest.cc new file mode 100644 index 0000000..71b74c8 --- /dev/null +++ b/chrome/common/worker_thread_ticker_unittest.cc @@ -0,0 +1,108 @@ +// Copyright (c) 2009 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 "chrome/common/worker_thread_ticker.h" + +#include "base/message_loop.h" +#include "base/platform_thread.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +class TestCallback : public WorkerThreadTicker::Callback { + public: + TestCallback() : counter_(0), message_loop_(MessageLoop::current()) { + } + + virtual void OnTick() { + counter_++; + + // Finish the test faster. + message_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask()); + } + + int counter() const { return counter_; } + + private: + int counter_; + MessageLoop* message_loop_; +}; + +class LongCallback : public WorkerThreadTicker::Callback { + public: + virtual void OnTick() { + PlatformThread::Sleep(1500); + } +}; + +void RunMessageLoopForAWhile() { + MessageLoop::current()->PostDelayedTask(FROM_HERE, + new MessageLoop::QuitTask(), 500); + MessageLoop::current()->Run(); +} + +} // namespace + +TEST(WorkerThreadTickerTest, Basic) { + MessageLoop loop; + + TestCallback callback; + WorkerThreadTicker ticker(50); + EXPECT_FALSE(ticker.IsRunning()); + EXPECT_TRUE(ticker.RegisterTickHandler(&callback)); + EXPECT_TRUE(ticker.UnregisterTickHandler(&callback)); + EXPECT_TRUE(ticker.Start()); + EXPECT_FALSE(ticker.RegisterTickHandler(&callback)); + EXPECT_FALSE(ticker.UnregisterTickHandler(&callback)); + EXPECT_TRUE(ticker.IsRunning()); + EXPECT_FALSE(ticker.Start()); // Can't start when it is running. + EXPECT_TRUE(ticker.Stop()); + EXPECT_FALSE(ticker.IsRunning()); + EXPECT_FALSE(ticker.Stop()); // Can't stop when it isn't running. +} + +TEST(WorkerThreadTickerTest, Callback) { + MessageLoop loop; + + TestCallback callback; + WorkerThreadTicker ticker(50); + ASSERT_TRUE(ticker.RegisterTickHandler(&callback)); + + ASSERT_TRUE(ticker.Start()); + RunMessageLoopForAWhile(); + EXPECT_TRUE(callback.counter() > 0); + + ASSERT_TRUE(ticker.Stop()); + const int counter_value = callback.counter(); + RunMessageLoopForAWhile(); + EXPECT_EQ(counter_value, callback.counter()); +} + +TEST(WorkerThreadTickerTest, OutOfScope) { + MessageLoop loop; + + TestCallback callback; + { + WorkerThreadTicker ticker(50); + ASSERT_TRUE(ticker.RegisterTickHandler(&callback)); + + ASSERT_TRUE(ticker.Start()); + RunMessageLoopForAWhile(); + EXPECT_TRUE(callback.counter() > 0); + } + const int counter_value = callback.counter(); + RunMessageLoopForAWhile(); + EXPECT_EQ(counter_value, callback.counter()); +} + +TEST(WorkerThreadTickerTest, LongCallback) { + MessageLoop loop; + + LongCallback callback; + WorkerThreadTicker ticker(50); + ASSERT_TRUE(ticker.RegisterTickHandler(&callback)); + + ASSERT_TRUE(ticker.Start()); + RunMessageLoopForAWhile(); +} diff --git a/chrome/common/zip.cc b/chrome/common/zip.cc new file mode 100644 index 0000000..f1d89b5 --- /dev/null +++ b/chrome/common/zip.cc @@ -0,0 +1,313 @@ +// Copyright (c) 2009 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 "chrome/common/zip.h" + +#include "base/file_util.h" +#include "base/logging.h" +#include "base/string_util.h" +#include "base/utf_string_conversions.h" +#include "net/base/file_stream.h" +#include "third_party/zlib/contrib/minizip/unzip.h" +#include "third_party/zlib/contrib/minizip/zip.h" +#if defined(OS_WIN) +#include "third_party/zlib/contrib/minizip/iowin32.h" +#endif + +static const int kZipMaxPath = 256; +static const int kZipBufSize = 8192; + +// Extract the 'current' selected file from the zip into dest_dir. +// Output filename is stored in out_file. Returns true on success. +static bool ExtractCurrentFile(unzFile zip_file, + const FilePath& dest_dir) { + char filename_inzip[kZipMaxPath] = {0}; + unz_file_info file_info; + int err = unzGetCurrentFileInfo(zip_file, &file_info, filename_inzip, + sizeof(filename_inzip) - 1, NULL, 0, NULL, 0); + if (err != UNZ_OK) + return false; + if (filename_inzip[0] == '\0') + return false; + + err = unzOpenCurrentFile(zip_file); + if (err != UNZ_OK) + return false; + + FilePath::StringType filename; + std::vector<FilePath::StringType> filename_parts; +#if defined(OS_WIN) + filename = UTF8ToWide(filename_inzip); +#elif defined(OS_POSIX) + filename = filename_inzip; +#endif + + // Check the filename here for directory traversal issues. In the name of + // simplicity and security, we might reject a valid filename such as "a..b". + if (filename.find(FILE_PATH_LITERAL("..")) != FilePath::StringType::npos) + return false; + + SplitString(filename, '/', &filename_parts); + + FilePath dest_file(dest_dir); + std::vector<FilePath::StringType>::iterator iter; + for (iter = filename_parts.begin(); iter != filename_parts.end(); ++iter) + dest_file = dest_file.Append(*iter); + + // If this is a directory, just create it and return. + if (filename_inzip[strlen(filename_inzip) - 1] == '/') { + if (!file_util::CreateDirectory(dest_file)) + return false; + return true; + } + + // We can't rely on parent directory entries being specified in the zip, so we + // make sure they are created. + FilePath dir = dest_file.DirName(); + if (!file_util::CreateDirectory(dir)) + return false; + + net::FileStream stream; + int flags = base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_WRITE; + if (stream.Open(dest_file, flags) != 0) + return false; + + bool ret = true; + int num_bytes = 0; + char buf[kZipBufSize]; + do { + num_bytes = unzReadCurrentFile(zip_file, buf, kZipBufSize); + if (num_bytes < 0) { + // If num_bytes < 0, then it's a specific UNZ_* error code. + // While we're not currently handling these codes specifically, save + // it away in case we want to in the future. + err = num_bytes; + break; + } + if (num_bytes > 0) { + if (num_bytes != stream.Write(buf, num_bytes, NULL)) { + ret = false; + break; + } + } + } while (num_bytes > 0); + + stream.Close(); + if (err == UNZ_OK) + err = unzCloseCurrentFile(zip_file); + else + unzCloseCurrentFile(zip_file); // Don't lose the original error code. + if (err != UNZ_OK) + ret = false; + return ret; +} + +#if defined(OS_WIN) +typedef struct { + HANDLE hf; + int error; +} WIN32FILE_IOWIN; + +// This function is derived from third_party/minizip/iowin32.c. +// Its only difference is that it treats the char* as UTF8 and +// uses the Unicode version of CreateFile. +static void* ZipOpenFunc(void *opaque, const char* filename, int mode) { + DWORD desired_access, creation_disposition; + DWORD share_mode, flags_and_attributes; + HANDLE file = 0; + void* ret = NULL; + + desired_access = share_mode = flags_and_attributes = 0; + + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ) { + desired_access = GENERIC_READ; + creation_disposition = OPEN_EXISTING; + share_mode = FILE_SHARE_READ; + } else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) { + desired_access = GENERIC_WRITE | GENERIC_READ; + creation_disposition = OPEN_EXISTING; + } else if (mode & ZLIB_FILEFUNC_MODE_CREATE) { + desired_access = GENERIC_WRITE | GENERIC_READ; + creation_disposition = CREATE_ALWAYS; + } + + std::wstring filename_wstr = UTF8ToWide(filename); + if ((filename != NULL) && (desired_access != 0)) { + file = CreateFile(filename_wstr.c_str(), desired_access, share_mode, + NULL, creation_disposition, flags_and_attributes, NULL); + } + + if (file == INVALID_HANDLE_VALUE) + file = NULL; + + if (file != NULL) { + WIN32FILE_IOWIN file_ret; + file_ret.hf = file; + file_ret.error = 0; + ret = malloc(sizeof(WIN32FILE_IOWIN)); + if (ret == NULL) + CloseHandle(file); + else + *(static_cast<WIN32FILE_IOWIN*>(ret)) = file_ret; + } + return ret; +} +#endif + +bool Unzip(const FilePath& src_file, const FilePath& dest_dir) { +#if defined(OS_WIN) + zlib_filefunc_def zip_funcs; + fill_win32_filefunc(&zip_funcs); + zip_funcs.zopen_file = ZipOpenFunc; +#endif + +#if defined(OS_POSIX) + std::string src_file_str = src_file.value(); + unzFile zip_file = unzOpen(src_file_str.c_str()); +#elif defined(OS_WIN) + std::string src_file_str = WideToUTF8(src_file.value()); + unzFile zip_file = unzOpen2(src_file_str.c_str(), &zip_funcs); +#endif + if (!zip_file) { + LOG(WARNING) << "couldn't create file " << src_file_str; + return false; + } + unz_global_info zip_info; + int err; + err = unzGetGlobalInfo(zip_file, &zip_info); + if (err != UNZ_OK) { + LOG(WARNING) << "couldn't open zip " << src_file_str; + return false; + } + bool ret = true; + for (unsigned int i = 0; i < zip_info.number_entry; ++i) { + if (!ExtractCurrentFile(zip_file, dest_dir)) { + ret = false; + break; + } + + if (i + 1 < zip_info.number_entry) { + err = unzGoToNextFile(zip_file); + if (err != UNZ_OK) { + LOG(WARNING) << "error %d in unzGoToNextFile"; + ret = false; + break; + } + } + } + unzClose(zip_file); + return ret; +} + +static bool AddFileToZip(zipFile zip_file, const FilePath& src_dir) { + net::FileStream stream; + int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ; + if (stream.Open(src_dir, flags) != 0) { + LOG(ERROR) << "Could not open stream for path " + << WideToASCII(src_dir.ToWStringHack()); + return false; + } + + int num_bytes; + char buf[kZipBufSize]; + do { + num_bytes = stream.Read(buf, kZipBufSize, NULL); + if (num_bytes > 0) { + if (ZIP_OK != zipWriteInFileInZip(zip_file, buf, num_bytes)) { + LOG(ERROR) << "Could not write data to zip for path " + << WideToASCII(src_dir.ToWStringHack()); + return false; + } + } + } while (num_bytes > 0); + + return true; +} + +static bool AddEntryToZip(zipFile zip_file, const FilePath& path, + const FilePath& root_path) { +#if defined(OS_WIN) + std::string str_path = + WideToUTF8(path.value().substr(root_path.value().length() + 1)); + ReplaceSubstringsAfterOffset(&str_path, 0u, "\\", "/"); +#else + std::string str_path = path.value().substr(root_path.value().length() + 1); +#endif + + bool is_directory = file_util::DirectoryExists(path); + if (is_directory) + str_path += "/"; + + if (ZIP_OK != zipOpenNewFileInZip( + zip_file, str_path.c_str(), + NULL, NULL, 0u, NULL, 0u, NULL, // file info, extrafield local, length, + // extrafield global, length, comment + Z_DEFLATED, Z_DEFAULT_COMPRESSION)) { + LOG(ERROR) << "Could not open zip file entry " << str_path; + return false; + } + + bool success = true; + if (!is_directory) { + success = AddFileToZip(zip_file, path); + } + + if (ZIP_OK != zipCloseFileInZip(zip_file)) { + LOG(ERROR) << "Could not close zip file entry " << str_path; + return false; + } + + return success; +} + +bool Zip(const FilePath& src_dir, const FilePath& dest_file, + bool include_hidden_files) { + DCHECK(file_util::DirectoryExists(src_dir)); + +#if defined(OS_WIN) + zlib_filefunc_def zip_funcs; + fill_win32_filefunc(&zip_funcs); + zip_funcs.zopen_file = ZipOpenFunc; +#endif + +#if defined(OS_POSIX) + std::string dest_file_str = dest_file.value(); + std::string src_dir_str = src_dir.value(); + zipFile zip_file = zipOpen(dest_file_str.c_str(), APPEND_STATUS_CREATE); +#elif defined(OS_WIN) + std::string dest_file_str = WideToUTF8(dest_file.value()); + zipFile zip_file = zipOpen2(dest_file_str.c_str(), APPEND_STATUS_CREATE, + NULL, // global comment + &zip_funcs); +#endif + + if (!zip_file) { + LOG(WARNING) << "couldn't create file " << dest_file_str; + return false; + } + + bool success = true; + file_util::FileEnumerator file_enumerator( + src_dir, true, // recursive + static_cast<file_util::FileEnumerator::FILE_TYPE>( + file_util::FileEnumerator::FILES | + file_util::FileEnumerator::DIRECTORIES)); + for (FilePath path = file_enumerator.Next(); !path.value().empty(); + path = file_enumerator.Next()) { + if (!include_hidden_files && path.BaseName().ToWStringHack()[0] == L'.') + continue; + + if (!AddEntryToZip(zip_file, path, src_dir)) { + success = false; + return false; + } + } + + if (ZIP_OK != zipClose(zip_file, NULL)) { // global comment + LOG(ERROR) << "Error closing zip file " << dest_file_str; + return false; + } + + return success; +} diff --git a/chrome/common/zip.h b/chrome/common/zip.h new file mode 100644 index 0000000..2c3d456 --- /dev/null +++ b/chrome/common/zip.h @@ -0,0 +1,23 @@ +// Copyright (c) 2009 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 CHROME_COMMON_ZIP_H_ +#define CHROME_COMMON_ZIP_H_ + +#include <vector> + +#include "base/file_path.h" + +// Zip the contents of src_dir into dest_file. src_path must be a directory. +// An entry will *not* be created in the zip for the root folder -- children +// of src_dir will be at the root level of the created zip. +// If |include_hidden_files| is true, files starting with "." are included. +// Otherwise they are omitted. +bool Zip(const FilePath& src_dir, const FilePath& dest_file, + bool include_hidden_files); + +// Unzip the contents of zip_file into dest_dir. +bool Unzip(const FilePath& zip_file, const FilePath& dest_dir); + +#endif // CHROME_COMMON_ZIP_H_ diff --git a/chrome/common/zip_unittest.cc b/chrome/common/zip_unittest.cc new file mode 100644 index 0000000..afb50c0 --- /dev/null +++ b/chrome/common/zip_unittest.cc @@ -0,0 +1,145 @@ +// Copyright (c) 2006-2008 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 <set> + +#include "base/file_util.h" +#include "base/scoped_temp_dir.h" +#include "base/path_service.h" +#include "base/string_util.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/zip.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/platform_test.h" + +namespace { + +// Make the test a PlatformTest to setup autorelease pools properly on Mac. +class ZipTest : public PlatformTest { + protected: + virtual void SetUp() { + PlatformTest::SetUp(); + + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + test_dir_ = temp_dir_.path(); + + FilePath zip_path(test_dir_); + zip_contents_.insert(zip_path.AppendASCII("foo.txt")); + zip_path = zip_path.AppendASCII("foo"); + zip_contents_.insert(zip_path); + zip_contents_.insert(zip_path.AppendASCII("bar.txt")); + zip_path = zip_path.AppendASCII("bar"); + zip_contents_.insert(zip_path); + zip_contents_.insert(zip_path.AppendASCII("baz.txt")); + zip_contents_.insert(zip_path.AppendASCII("quux.txt")); + zip_contents_.insert(zip_path.AppendASCII(".hidden")); + } + + virtual void TearDown() { + PlatformTest::TearDown(); + } + + void TestUnzipFile(const FilePath::StringType& filename, + bool expect_hidden_files) { + FilePath test_dir; + ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir)); + test_dir = test_dir.AppendASCII("zip"); + TestUnzipFile(test_dir.Append(filename), expect_hidden_files); + } + + void TestUnzipFile(const FilePath& path, bool expect_hidden_files) { + ASSERT_TRUE(file_util::PathExists(path)) << "no file " << path.value(); + ASSERT_TRUE(Unzip(path, test_dir_)); + + file_util::FileEnumerator files(test_dir_, true, + static_cast<file_util::FileEnumerator::FILE_TYPE>( + file_util::FileEnumerator::FILES | + file_util::FileEnumerator::DIRECTORIES)); + FilePath next_path = files.Next(); + size_t count = 0; + while (!next_path.value().empty()) { + if (next_path.value().find(FILE_PATH_LITERAL(".svn")) == + FilePath::StringType::npos) { + EXPECT_EQ(zip_contents_.count(next_path), 1U) << + "Couldn't find " << next_path.value(); + count++; + } + next_path = files.Next(); + } + + size_t expected_count = 0; + for (std::set<FilePath>::iterator iter = zip_contents_.begin(); + iter != zip_contents_.end(); ++iter) { + if (expect_hidden_files || iter->BaseName().ToWStringHack()[0] != L'.') + ++expected_count; + } + + EXPECT_EQ(expected_count, count); + } + + // the path to temporary directory used to contain the test operations + FilePath test_dir_; + + ScopedTempDir temp_dir_; + + // hard-coded contents of a known zip file + std::set<FilePath> zip_contents_; +}; + +TEST_F(ZipTest, Unzip) { + TestUnzipFile(FILE_PATH_LITERAL("test.zip"), true); +} + +TEST_F(ZipTest, UnzipUncompressed) { + TestUnzipFile(FILE_PATH_LITERAL("test_nocompress.zip"), true); +} + +TEST_F(ZipTest, UnzipEvil) { + FilePath path; + ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path)); + path = path.AppendASCII("zip").AppendASCII("evil.zip"); + ASSERT_FALSE(Unzip(path, test_dir_)); + FilePath evil_file = test_dir_; + evil_file = evil_file.AppendASCII( + "../levilevilevilevilevilevilevilevilevilevilevilevil"); + ASSERT_FALSE(file_util::PathExists(evil_file)); +} + +TEST_F(ZipTest, UnzipEvil2) { + FilePath path; + ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path)); + path = path.AppendASCII("zip").AppendASCII("evil_via_invalid_utf8.zip"); + ASSERT_TRUE(Unzip(path, test_dir_)); + FilePath evil_file = test_dir_; + evil_file = evil_file.AppendASCII("../evil.txt"); + ASSERT_FALSE(file_util::PathExists(evil_file)); +} + +TEST_F(ZipTest, Zip) { + FilePath src_dir; + ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &src_dir)); + src_dir = src_dir.AppendASCII("zip").AppendASCII("test"); + + ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + FilePath zip_file = temp_dir.path().AppendASCII("out.zip"); + + EXPECT_TRUE(Zip(src_dir, zip_file, true)); + TestUnzipFile(zip_file, true); +} + +TEST_F(ZipTest, ZipIgnoreHidden) { + FilePath src_dir; + ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &src_dir)); + src_dir = src_dir.AppendASCII("zip").AppendASCII("test"); + + ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + FilePath zip_file = temp_dir.path().AppendASCII("out.zip"); + + EXPECT_TRUE(Zip(src_dir, zip_file, false)); + TestUnzipFile(zip_file, false); +} + +} // namespace |