Merge from Chromium at DEPS revision r213780
This commit was generated by merge_to_master.py.
Change-Id: I9cf93efc460166e8ae27c76302af9095b402a90e
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index b5c1fc7..ca42870 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -106,7 +106,4 @@
"+third_party/WebKit/public/web/WebScreenInfo.h",
"+third_party/WebKit/public/web/WebTextDirection.h",
"+third_party/WebKit/public/web/WebWindowFeatures.h",
-
- # These should be burned down. http://crbug.com/237267
- "!third_party/WebKit/public/web/WebView.h",
]
diff --git a/chrome/browser/OWNERS b/chrome/browser/OWNERS
index f9db9bc..b614afe 100644
--- a/chrome/browser/OWNERS
+++ b/chrome/browser/OWNERS
@@ -4,6 +4,7 @@
per-file chrome_content_browser_client.cc=*
per-file chrome_content_browser_client.h=*
+per-file chrome_content_browser_client_browsertest.cc=*
per-file chrome_browser_field_trials*=asvitkine@chromium.org
per-file chrome_browser_field_trials*=stevet@chromium.org
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 9879d13..9e5a15e 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1228,14 +1228,16 @@
IDS_FLAGS_ASH_ENABLE_NEW_AUDIO_HANDLER_NAME,
IDS_FLAGS_ASH_ENABLE_NEW_AUDIO_HANDLER_DESCRIPTION,
kOsCrOS,
- ENABLE_DISABLE_VALUE_TYPE("", ash::switches::kAshDisableNewAudioHandler)
+ ENABLE_DISABLE_VALUE_TYPE(ash::switches::kAshEnableNewAudioHandler,
+ ash::switches::kAshDisableNewAudioHandler)
},
{
"ash-audio-device-menu",
IDS_FLAGS_ASH_AUDIO_DEVICE_MENU_NAME,
IDS_FLAGS_ASH_AUDIO_DEVICE_MENU_DESCRIPTION,
kOsCrOS,
- ENABLE_DISABLE_VALUE_TYPE("", ash::switches::kAshDisableAudioDeviceMenu)
+ ENABLE_DISABLE_VALUE_TYPE(ash::switches::kAshEnableAudioDeviceMenu,
+ ash::switches::kAshDisableAudioDeviceMenu)
},
{
"enable-carrier-switching",
diff --git a/chrome/browser/browsing_data/browsing_data_remover.cc b/chrome/browser/browsing_data/browsing_data_remover.cc
index 1eb406a..15b8959 100644
--- a/chrome/browser/browsing_data/browsing_data_remover.cc
+++ b/chrome/browser/browsing_data/browsing_data_remover.cc
@@ -849,10 +849,8 @@
void BrowsingDataRemover::ClearShaderCacheOnUIThread() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- BrowserContext::GetDefaultStoragePartition(profile_)->ClearDataForRange(
- content::StoragePartition::REMOVE_DATA_MASK_SHADER_CACHE,
- content::StoragePartition::kAllStorage,
- delete_begin_, delete_end_,
+ BrowserContext::GetDefaultStoragePartition(profile_)->AsyncClearDataBetween(
+ content::StoragePartition::kShaderStorage, delete_begin_, delete_end_,
base::Bind(&BrowsingDataRemover::ClearedShaderCache,
base::Unretained(this)));
}
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index a166d59..a47541a 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -2195,6 +2195,11 @@
// actually handle them.
handler->AddHandlerPair(&WillHandleBrowserAboutURL,
BrowserURLHandler::null_handler());
+
+ // Handler to rewrite chrome://newtab for InstantExtended.
+ handler->AddHandlerPair(&chrome::HandleNewTabURLRewrite,
+ &chrome::HandleNewTabURLReverseRewrite);
+
// chrome: & friends.
handler->AddHandlerPair(&HandleWebUI, &HandleWebUIReverse);
}
diff --git a/chrome/browser/chrome_content_browser_client_browsertest.cc b/chrome/browser/chrome_content_browser_client_browsertest.cc
index de24691..9d4b494 100644
--- a/chrome/browser/chrome_content_browser_client_browsertest.cc
+++ b/chrome/browser/chrome_content_browser_client_browsertest.cc
@@ -3,8 +3,10 @@
// found in the LICENSE file.
#include "base/command_line.h"
+#include "chrome/browser/search/search.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/navigation_controller.h"
@@ -75,6 +77,37 @@
EXPECT_EQ(url, entry->GetVirtualURL());
}
+IN_PROC_BROWSER_TEST_F(ChromeContentBrowserClientBrowserTest,
+ UberURLHandler_InstantExtendedNewTabPage) {
+ const GURL url_original("chrome://newtab");
+ const GURL url_rewritten("http://example.com/newtab");
+ CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kInstantNewTabURL, url_rewritten.spec());
+ chrome::EnableInstantExtendedAPIForTesting();
+
+ ui_test_utils::NavigateToURL(browser(), url_original);
+ NavigationEntry* entry = GetLastCommittedEntry();
+
+ ASSERT_TRUE(entry != NULL);
+ EXPECT_EQ(url_rewritten, entry->GetURL());
+ EXPECT_EQ(url_original, entry->GetVirtualURL());
+}
+
+IN_PROC_BROWSER_TEST_F(ChromeContentBrowserClientBrowserTest,
+ UberURLHandler_InstantExtendedNewTabPageDisabled) {
+ const GURL url_original("chrome://newtab");
+ const GURL url_rewritten("http://example.com/newtab");
+ CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kInstantNewTabURL, url_rewritten.spec());
+
+ ui_test_utils::NavigateToURL(browser(), url_original);
+ NavigationEntry* entry = GetLastCommittedEntry();
+
+ ASSERT_TRUE(entry != NULL);
+ EXPECT_EQ(url_original, entry->GetURL());
+ EXPECT_EQ(url_original, entry->GetVirtualURL());
+}
+
// Test that a basic navigation works in --site-per-process mode. This prevents
// regressions when that mode calls out into the ChromeContentBrowserClient,
// such as http://crbug.com/164223.
diff --git a/chrome/browser/chrome_page_zoom.cc b/chrome/browser/chrome_page_zoom.cc
index acca565..ae596ce 100644
--- a/chrome/browser/chrome_page_zoom.cc
+++ b/chrome/browser/chrome_page_zoom.cc
@@ -14,8 +14,8 @@
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/user_metrics.h"
#include "content/public/browser/web_contents.h"
+#include "content/public/common/page_zoom.h"
#include "content/public/common/renderer_preferences.h"
-#include "third_party/WebKit/public/web/WebView.h"
using content::UserMetricsAction;
@@ -36,7 +36,7 @@
for (size_t i = 0; i < kPresetZoomFactorsSize; i++) {
double zoom_value = kPresetZoomFactors[i];
if (value_type == PAGE_ZOOM_VALUE_TYPE_LEVEL)
- zoom_value = WebKit::WebView::zoomFactorToZoomLevel(zoom_value);
+ zoom_value = content::ZoomFactorToZoomLevel(zoom_value);
if (content::ZoomValuesEqual(zoom_value, custom_value))
found_custom = true;
zoom_values.push_back(zoom_value);
@@ -44,10 +44,10 @@
// If the preset array did not contain the custom value, append it to the
// vector and then sort.
double min = value_type == PAGE_ZOOM_VALUE_TYPE_LEVEL ?
- WebKit::WebView::zoomFactorToZoomLevel(content::kMinimumZoomFactor) :
+ content::ZoomFactorToZoomLevel(content::kMinimumZoomFactor) :
content::kMinimumZoomFactor;
double max = value_type == PAGE_ZOOM_VALUE_TYPE_LEVEL ?
- WebKit::WebView::zoomFactorToZoomLevel(content::kMaximumZoomFactor) :
+ content::ZoomFactorToZoomLevel(content::kMaximumZoomFactor) :
content::kMaximumZoomFactor;
if (!found_custom && custom_value > min && custom_value < max) {
zoom_values.push_back(custom_value);
diff --git a/chrome/browser/chromeos/drive/change_list_loader_unittest.cc b/chrome/browser/chromeos/drive/change_list_loader_unittest.cc
index d774a64..7605e61 100644
--- a/chrome/browser/chromeos/drive/change_list_loader_unittest.cc
+++ b/chrome/browser/chromeos/drive/change_list_loader_unittest.cc
@@ -66,6 +66,35 @@
DISALLOW_COPY_AND_ASSIGN(TestChangeListLoaderObserver);
};
+class TestDriveService : public FakeDriveService {
+ public:
+ TestDriveService() : never_return_all_resource_list_(false),
+ blocked_call_count_(0) {}
+
+ void set_never_return_all_resource_list(bool value) {
+ never_return_all_resource_list_ = value;
+ }
+
+ int blocked_call_count() const { return blocked_call_count_; }
+
+ // FakeDriveService override.
+ virtual google_apis::CancelCallback GetAllResourceList(
+ const google_apis::GetResourceListCallback& callback) OVERRIDE {
+ if (never_return_all_resource_list_) {
+ ++blocked_call_count_;
+ return google_apis::CancelCallback();
+ }
+ return FakeDriveService::GetAllResourceList(callback);
+ }
+
+ private:
+ // GetAllResourceList never returns result when this is set to true.
+ // Used to emulate the real server's slowness.
+ bool never_return_all_resource_list_;
+
+ int blocked_call_count_; // Number of blocked method calls.
+};
+
class ChangeListLoaderTest : public testing::Test {
protected:
virtual void SetUp() OVERRIDE {
@@ -73,7 +102,7 @@
pref_service_.reset(new TestingPrefServiceSimple);
test_util::RegisterDrivePrefs(pref_service_->registry());
- drive_service_.reset(new FakeDriveService);
+ drive_service_.reset(new TestDriveService);
ASSERT_TRUE(drive_service_->LoadResourceListForWapi(
"gdata/root_feed.json"));
ASSERT_TRUE(drive_service_->LoadAccountMetadataForWapi(
@@ -121,7 +150,7 @@
content::TestBrowserThreadBundle thread_bundle_;
base::ScopedTempDir temp_dir_;
scoped_ptr<TestingPrefServiceSimple> pref_service_;
- scoped_ptr<FakeDriveService> drive_service_;
+ scoped_ptr<TestDriveService> drive_service_;
scoped_ptr<JobScheduler> scheduler_;
scoped_ptr<ResourceMetadataStorage,
test_util::DestroyHelperForTests> metadata_storage_;
@@ -224,6 +253,112 @@
metadata_->GetResourceEntryByPath(file_path, &entry));
}
+TEST_F(ChangeListLoaderTest, LoadIfNeeded_MyDrive) {
+ // Emulate the slowness of GetAllResourceList().
+ drive_service_->set_never_return_all_resource_list(true);
+
+ // Load grand root.
+ FileError error = FILE_ERROR_FAILED;
+ change_list_loader_->LoadIfNeeded(
+ DirectoryFetchInfo(util::kDriveGrandRootSpecialResourceId, 0),
+ google_apis::test_util::CreateCopyResultCallback(&error));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(FILE_ERROR_OK, error);
+
+ // GetAllResourceList() was called.
+ EXPECT_EQ(1, drive_service_->blocked_call_count());
+
+ // My Drive is present in the local metadata, but its child is not.
+ ResourceEntry entry;
+ EXPECT_EQ(FILE_ERROR_OK,
+ metadata_->GetResourceEntryByPath(util::GetDriveMyDriveRootPath(),
+ &entry));
+ const int64 mydrive_changestamp =
+ entry.directory_specific_info().changestamp();
+
+ base::FilePath file_path =
+ util::GetDriveMyDriveRootPath().AppendASCII("File 1.txt");
+ EXPECT_EQ(FILE_ERROR_NOT_FOUND,
+ metadata_->GetResourceEntryByPath(file_path, &entry));
+
+ // Load My Drive.
+ change_list_loader_->LoadIfNeeded(
+ DirectoryFetchInfo(drive_service_->GetRootResourceId(),
+ mydrive_changestamp),
+ google_apis::test_util::CreateCopyResultCallback(&error));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(FILE_ERROR_OK, error);
+
+ // Now the file is present.
+ EXPECT_EQ(FILE_ERROR_OK,
+ metadata_->GetResourceEntryByPath(file_path, &entry));
+}
+
+TEST_F(ChangeListLoaderTest, LoadIfNeeded_NewDirectories) {
+ // Make local metadata up to date.
+ FileError error = FILE_ERROR_FAILED;
+ change_list_loader_->LoadIfNeeded(
+ DirectoryFetchInfo(),
+ google_apis::test_util::CreateCopyResultCallback(&error));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(FILE_ERROR_OK, error);
+
+ // Add a new file.
+ scoped_ptr<google_apis::ResourceEntry> file = AddNewFile("New File");
+ ASSERT_TRUE(file);
+
+ // Emulate the slowness of GetAllResourceList().
+ drive_service_->set_never_return_all_resource_list(true);
+
+ // Enter refreshing state.
+ FileError check_for_updates_error = FILE_ERROR_FAILED;
+ change_list_loader_->CheckForUpdates(
+ google_apis::test_util::CreateCopyResultCallback(
+ &check_for_updates_error));
+ EXPECT_TRUE(change_list_loader_->IsRefreshing());
+
+ // Load My Drive.
+ change_list_loader_->LoadIfNeeded(
+ DirectoryFetchInfo(drive_service_->GetRootResourceId(),
+ metadata_->GetLargestChangestamp()),
+ google_apis::test_util::CreateCopyResultCallback(&error));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(FILE_ERROR_OK, error);
+
+ // The new file is present in the local metadata.
+ base::FilePath file_path =
+ util::GetDriveMyDriveRootPath().AppendASCII(file->title());
+ ResourceEntry entry;
+ EXPECT_EQ(FILE_ERROR_OK,
+ metadata_->GetResourceEntryByPath(file_path, &entry));
+}
+
+TEST_F(ChangeListLoaderTest, LoadIfNeeded_MultipleCalls) {
+ TestChangeListLoaderObserver observer(change_list_loader_.get());
+
+ // Load grand root.
+ FileError error = FILE_ERROR_FAILED;
+ change_list_loader_->LoadIfNeeded(
+ DirectoryFetchInfo(util::kDriveGrandRootSpecialResourceId, 0),
+ google_apis::test_util::CreateCopyResultCallback(&error));
+
+ // Load grand root again without waiting for the result.
+ FileError error2 = FILE_ERROR_FAILED;
+ change_list_loader_->LoadIfNeeded(
+ DirectoryFetchInfo(util::kDriveGrandRootSpecialResourceId, 0),
+ google_apis::test_util::CreateCopyResultCallback(&error2));
+ base::RunLoop().RunUntilIdle();
+
+ // Callback is called for each method call.
+ EXPECT_EQ(FILE_ERROR_OK, error);
+ EXPECT_EQ(FILE_ERROR_OK, error2);
+
+ // No duplicated resource list load and observer events.
+ EXPECT_EQ(1, drive_service_->resource_list_load_count());
+ EXPECT_EQ(1, observer.initial_load_complete_count());
+ EXPECT_EQ(1, observer.load_from_server_complete_count());
+}
+
TEST_F(ChangeListLoaderTest, CheckForUpdates) {
// CheckForUpdates() results in no-op before load.
FileError check_for_updates_error = FILE_ERROR_FAILED;
diff --git a/chrome/browser/chromeos/drive/drive_integration_service.cc b/chrome/browser/chromeos/drive/drive_integration_service.cc
index 1af4edc..139292c 100644
--- a/chrome/browser/chromeos/drive/drive_integration_service.cc
+++ b/chrome/browser/chromeos/drive/drive_integration_service.cc
@@ -232,6 +232,13 @@
drive_notification_manager->RemoveObserver(this);
RemoveDriveMountPoint();
+ debug_info_collector_.reset();
+ download_handler_.reset();
+ file_write_helper_.reset();
+ file_system_.reset();
+ drive_app_registry_.reset();
+ scheduler_.reset();
+ drive_service_.reset();
}
void DriveIntegrationService::AddObserver(
diff --git a/chrome/browser/chromeos/drive/file_cache.cc b/chrome/browser/chromeos/drive/file_cache.cc
index 1b1ef5e..8ef2ab7 100644
--- a/chrome/browser/chromeos/drive/file_cache.cc
+++ b/chrome/browser/chromeos/drive/file_cache.cc
@@ -238,7 +238,6 @@
}
void FileCache::GetFileOnUIThread(const std::string& resource_id,
- const std::string& md5,
const GetFileFromCacheCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(!callback.is_null());
@@ -249,7 +248,6 @@
base::Bind(&FileCache::GetFile,
base::Unretained(this),
resource_id,
- md5,
cache_file_path),
base::Bind(&RunGetFileFromCacheCallback,
callback,
@@ -257,13 +255,12 @@
}
FileError FileCache::GetFile(const std::string& resource_id,
- const std::string& md5,
base::FilePath* cache_file_path) {
AssertOnSequencedWorkerPool();
DCHECK(cache_file_path);
FileCacheEntry cache_entry;
- if (!GetCacheEntry(resource_id, md5, &cache_entry) ||
+ if (!storage_->GetCacheEntry(resource_id, &cache_entry) ||
!cache_entry.is_present())
return FILE_ERROR_NOT_FOUND;
@@ -417,7 +414,6 @@
if (cache_entry.is_dirty())
return FILE_ERROR_OK;
- // Now that file operations have completed, update metadata.
cache_entry.set_is_dirty(true);
return storage_->PutCacheEntry(resource_id, cache_entry) ?
FILE_ERROR_OK : FILE_ERROR_FAILED;
@@ -427,30 +423,24 @@
const std::string& md5) {
AssertOnSequencedWorkerPool();
- // |md5| is the new .<md5> extension to rename the file to.
- // So, search for entry in cache without comparing md5.
- FileCacheEntry cache_entry;
-
// Clearing a dirty file means its entry and actual file blob must exist in
// cache.
+ FileCacheEntry cache_entry;
if (!storage_->GetCacheEntry(resource_id, &cache_entry) ||
!cache_entry.is_present()) {
LOG(WARNING) << "Can't clear dirty state of a file that wasn't cached: "
- << "res_id=" << resource_id
- << ", md5=" << md5;
+ << resource_id;
return FILE_ERROR_NOT_FOUND;
}
// If a file is not dirty (it should have been marked dirty via
// MarkDirtyInCache), clearing its dirty state is an invalid operation.
if (!cache_entry.is_dirty()) {
- LOG(WARNING) << "Can't clear dirty state of a non-dirty file: res_id="
- << resource_id
- << ", md5=" << md5;
+ LOG(WARNING) << "Can't clear dirty state of a non-dirty file: "
+ << resource_id;
return FILE_ERROR_INVALID_OPERATION;
}
- // Now that file operations have completed, update metadata.
cache_entry.set_md5(md5);
cache_entry.set_is_dirty(false);
return storage_->PutCacheEntry(resource_id, cache_entry) ?
diff --git a/chrome/browser/chromeos/drive/file_cache.h b/chrome/browser/chromeos/drive/file_cache.h
index c576b7b..405341b 100644
--- a/chrome/browser/chromeos/drive/file_cache.h
+++ b/chrome/browser/chromeos/drive/file_cache.h
@@ -134,15 +134,12 @@
// |callback| must not be null.
// Must be called on the UI thread.
void GetFileOnUIThread(const std::string& resource_id,
- const std::string& md5,
const GetFileFromCacheCallback& callback);
- // Checks if file corresponding to |resource_id| and |md5| exists in cache,
- // and returns FILE_ERROR_OK with |cache_file_path| storing the path to
- // the file.
+ // Checks if file corresponding to |resource_id| exists in cache, and returns
+ // FILE_ERROR_OK with |cache_file_path| storing the path to the file.
// |cache_file_path| must not be null.
FileError GetFile(const std::string& resource_id,
- const std::string& md5,
base::FilePath* cache_file_path);
// Runs Store() on |blocking_task_runner_|, and calls |callback| with
@@ -205,7 +202,7 @@
// Marks the specified entry dirty.
FileError MarkDirty(const std::string& resource_id);
- // Clears dirty state of the specified entry.
+ // Clears dirty state of the specified entry and updates its MD5.
FileError ClearDirty(const std::string& resource_id,
const std::string& md5);
diff --git a/chrome/browser/chromeos/drive/file_cache_unittest.cc b/chrome/browser/chromeos/drive/file_cache_unittest.cc
index f18830a..7db6e0a 100644
--- a/chrome/browser/chromeos/drive/file_cache_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_cache_unittest.cc
@@ -106,14 +106,11 @@
ASSERT_TRUE(success);
}
- void TestGetFileFromCacheByResourceIdAndMd5(
- const std::string& resource_id,
- const std::string& md5,
- FileError expected_error,
- const std::string& expected_file_extension) {
+ void TestGetFile(const std::string& resource_id,
+ FileError expected_error) {
FileError error = FILE_ERROR_OK;
base::FilePath cache_file_path;
- cache_->GetFileOnUIThread(resource_id, md5,
+ cache_->GetFileOnUIThread(resource_id,
google_apis::test_util::CreateCopyResultCallback(
&error, &cache_file_path));
test_util::RunBlockingPoolTask();
@@ -217,7 +214,7 @@
if (error == FILE_ERROR_OK) {
base::FilePath cache_file_path;
cache_->GetFileOnUIThread(
- resource_id, std::string(),
+ resource_id,
google_apis::test_util::CreateCopyResultCallback(
&error, &cache_file_path));
test_util::RunBlockingPoolTask();
@@ -271,7 +268,6 @@
}
void TestMarkAsUnmounted(const std::string& resource_id,
- const std::string& md5,
const base::FilePath& file_path,
FileError expected_error,
int expected_cache_state) {
@@ -286,7 +282,7 @@
base::FilePath cache_file_path;
cache_->GetFileOnUIThread(
- resource_id, md5,
+ resource_id,
google_apis::test_util::CreateCopyResultCallback(
&error, &cache_file_path));
test_util::RunBlockingPoolTask();
@@ -411,19 +407,11 @@
FILE_ERROR_OK, TEST_CACHE_STATE_PRESENT);
// Then try to get the existing file from cache.
- TestGetFileFromCacheByResourceIdAndMd5(
- resource_id, md5, FILE_ERROR_OK, md5);
+ TestGetFile(resource_id, FILE_ERROR_OK);
- // Get file from cache with same resource id as existing file but different
- // md5.
- TestGetFileFromCacheByResourceIdAndMd5(
- resource_id, "9999", FILE_ERROR_NOT_FOUND, md5);
-
- // Get file from cache with different resource id from existing file but same
- // md5.
+ // Get file from cache with different resource id.
resource_id = "document:1a2b";
- TestGetFileFromCacheByResourceIdAndMd5(
- resource_id, md5, FILE_ERROR_NOT_FOUND, md5);
+ TestGetFile(resource_id, FILE_ERROR_NOT_FOUND);
}
TEST_F(FileCacheTestOnUIThread, RemoveFromCacheSimple) {
@@ -506,16 +494,14 @@
TestPin(resource_id, FILE_ERROR_OK, TEST_CACHE_STATE_PINNED);
// Get the non-existent pinned file from cache.
- TestGetFileFromCacheByResourceIdAndMd5(
- resource_id, md5, FILE_ERROR_NOT_FOUND, md5);
+ TestGetFile(resource_id, FILE_ERROR_NOT_FOUND);
// Store an existing file to the previously pinned non-existent file.
TestStoreToCache(resource_id, md5, dummy_file_path_, FILE_ERROR_OK,
TEST_CACHE_STATE_PRESENT | TEST_CACHE_STATE_PINNED);
// Get the previously pinned and stored file from cache.
- TestGetFileFromCacheByResourceIdAndMd5(
- resource_id, md5, FILE_ERROR_OK, md5);
+ TestGetFile(resource_id, FILE_ERROR_OK);
}
TEST_F(FileCacheTestOnUIThread, RemoveFromCachePinned) {
@@ -595,7 +581,7 @@
base::FilePath dirty_path;
FileError error = FILE_ERROR_FAILED;
cache_->GetFileOnUIThread(
- resource_id, md5,
+ resource_id,
google_apis::test_util::CreateCopyResultCallback(&error, &dirty_path));
test_util::RunBlockingPoolTask();
EXPECT_EQ(FILE_ERROR_OK, error);
@@ -710,12 +696,12 @@
base::FilePath file_path;
FileError error = FILE_ERROR_FAILED;
cache_->GetFileOnUIThread(
- resource_id, md5,
+ resource_id,
google_apis::test_util::CreateCopyResultCallback(&error, &file_path));
test_util::RunBlockingPoolTask();
EXPECT_EQ(FILE_ERROR_OK, error);
- TestMarkAsUnmounted(resource_id, md5, file_path, FILE_ERROR_OK,
+ TestMarkAsUnmounted(resource_id, file_path, FILE_ERROR_OK,
TEST_CACHE_STATE_PRESENT);
EXPECT_TRUE(CacheEntryExists(resource_id, md5));
@@ -895,8 +881,7 @@
cache_->Store(resource_id_tmp, md5_tmp, src_file,
FileCache::FILE_OPERATION_COPY));
base::FilePath tmp_path;
- ASSERT_EQ(FILE_ERROR_OK,
- cache_->GetFile(resource_id_tmp, md5_tmp, &tmp_path));
+ ASSERT_EQ(FILE_ERROR_OK, cache_->GetFile(resource_id_tmp, &tmp_path));
// Store a file as a pinned file and remember the path.
const std::string resource_id_pinned = "id_pinned", md5_pinned = "md5_pinned";
@@ -905,8 +890,7 @@
FileCache::FILE_OPERATION_COPY));
ASSERT_EQ(FILE_ERROR_OK, cache_->Pin(resource_id_pinned));
base::FilePath pinned_path;
- ASSERT_EQ(FILE_ERROR_OK,
- cache_->GetFile(resource_id_pinned, md5_pinned, &pinned_path));
+ ASSERT_EQ(FILE_ERROR_OK, cache_->GetFile(resource_id_pinned, &pinned_path));
// Call FreeDiskSpaceIfNeededFor().
fake_free_disk_space_getter_->set_default_value(test_util::kLotsOfSpace);
diff --git a/chrome/browser/chromeos/drive/file_system.cc b/chrome/browser/chromeos/drive/file_system.cc
index 674dbc4..0962967 100644
--- a/chrome/browser/chromeos/drive/file_system.cc
+++ b/chrome/browser/chromeos/drive/file_system.cc
@@ -756,7 +756,6 @@
drive::internal::SearchMetadata(blocking_task_runner_,
resource_metadata_,
- cache_,
query,
options,
at_most_num_matches,
@@ -949,10 +948,8 @@
// Gets the cache file path.
const std::string& resource_id = entry->resource_id();
- const std::string& md5 = entry->file_specific_info().md5();
cache_->GetFileOnUIThread(
resource_id,
- md5,
base::Bind(
&FileSystem::CheckLocalModificationAndRunAfterGetCacheFile,
weak_ptr_factory_.GetWeakPtr(),
diff --git a/chrome/browser/chromeos/drive/file_system/copy_operation_unittest.cc b/chrome/browser/chromeos/drive/file_system/copy_operation_unittest.cc
index d9643e5..aee7007 100644
--- a/chrome/browser/chromeos/drive/file_system/copy_operation_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_system/copy_operation_unittest.cc
@@ -125,7 +125,6 @@
// The content is "x"s of the file size.
base::FilePath cache_path;
cache()->GetFileOnUIThread(entry.resource_id(),
- entry.file_specific_info().md5(),
google_apis::test_util::CreateCopyResultCallback(
&error, &cache_path));
test_util::RunBlockingPoolTask();
diff --git a/chrome/browser/chromeos/drive/file_system/download_operation.cc b/chrome/browser/chromeos/drive/file_system/download_operation.cc
index a391986..0e01200 100644
--- a/chrome/browser/chromeos/drive/file_system/download_operation.cc
+++ b/chrome/browser/chromeos/drive/file_system/download_operation.cc
@@ -66,29 +66,36 @@
return FILE_ERROR_OK;
}
- // Get the cache file path if available.
- cache->GetFile(entry->resource_id(),
- entry->file_specific_info().md5(),
- cache_file_path);
+ // Leave |cache_file_path| empty when no cache entry is found.
+ FileCacheEntry cache_entry;
+ if (!cache->GetCacheEntry(entry->resource_id(),
+ entry->file_specific_info().md5(),
+ &cache_entry))
+ return FILE_ERROR_OK;
- // If the cache file is available and dirty, the modified file info needs to
- // be stored in |entry|.
+ // Leave |cache_file_path| empty when the stored file is obsolete and has no
+ // local modification.
+ if (!cache_entry.is_dirty() &&
+ entry->file_specific_info().md5() != cache_entry.md5())
+ return FILE_ERROR_OK;
+
+ // Fill |cache_file_path| with the path to the cached file.
+ FileError error = cache->GetFile(entry->resource_id(), cache_file_path);
+ if (error != FILE_ERROR_OK)
+ return error;
+
+ // If the cache file is dirty, the modified file info needs to be stored in
+ // |entry|.
// TODO(kinaba): crbug.com/246469. The logic below is a duplicate of that in
// drive::FileSystem::CheckLocalModificationAndRun. We should merge them once
// the drive::FS side is also converted to run fully on blocking pool.
- if (!cache_file_path->empty()) {
- FileCacheEntry cache_entry;
- if (cache->GetCacheEntry(entry->resource_id(),
- entry->file_specific_info().md5(),
- &cache_entry) &&
- cache_entry.is_dirty()) {
- base::PlatformFileInfo file_info;
- if (file_util::GetFileInfo(*cache_file_path, &file_info)) {
- PlatformFileInfoProto entry_file_info;
- util::ConvertPlatformFileInfoToResourceEntry(file_info,
- &entry_file_info);
- *entry->mutable_file_info() = entry_file_info;
- }
+ if (cache_entry.is_dirty()) {
+ base::PlatformFileInfo file_info;
+ if (file_util::GetFileInfo(*cache_file_path, &file_info)) {
+ PlatformFileInfoProto entry_file_info;
+ util::ConvertPlatformFileInfoToResourceEntry(file_info,
+ &entry_file_info);
+ *entry->mutable_file_info() = entry_file_info;
}
}
@@ -194,7 +201,7 @@
return error;
}
- return cache->GetFile(resource_id, md5, cache_file_path);
+ return cache->GetFile(resource_id, cache_file_path);
}
} // namespace
diff --git a/chrome/browser/chromeos/drive/file_system/open_file_operation.cc b/chrome/browser/chromeos/drive/file_system/open_file_operation.cc
index d23c488..7743c06 100644
--- a/chrome/browser/chromeos/drive/file_system/open_file_operation.cc
+++ b/chrome/browser/chromeos/drive/file_system/open_file_operation.cc
@@ -26,13 +26,12 @@
FileError UpdateFileLocalState(internal::FileCache* cache,
const std::string& resource_id,
- const std::string& md5,
base::FilePath* local_file_path) {
FileError error = cache->MarkDirty(resource_id);
if (error != FILE_ERROR_OK)
return error;
- return cache->GetFile(resource_id, md5, local_file_path);
+ return cache->GetFile(resource_id, local_file_path);
}
} // namespace
@@ -140,7 +139,6 @@
base::Bind(&UpdateFileLocalState,
cache_,
entry->resource_id(),
- entry->file_specific_info().md5(),
new_local_file_path),
base::Bind(&OpenFileOperation::OpenFileAfterUpdateLocalState,
weak_ptr_factory_.GetWeakPtr(),
diff --git a/chrome/browser/chromeos/drive/file_system/truncate_operation_unittest.cc b/chrome/browser/chromeos/drive/file_system/truncate_operation_unittest.cc
index 32ff259..e2c8575 100644
--- a/chrome/browser/chromeos/drive/file_system/truncate_operation_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_system/truncate_operation_unittest.cc
@@ -48,7 +48,7 @@
base::FilePath local_path;
error = FILE_ERROR_FAILED;
cache()->GetFileOnUIThread(
- src_entry.resource_id(), src_entry.file_specific_info().md5(),
+ src_entry.resource_id(),
google_apis::test_util::CreateCopyResultCallback(&error, &local_path));
test_util::RunBlockingPoolTask();
ASSERT_EQ(FILE_ERROR_OK, error);
@@ -107,7 +107,7 @@
base::FilePath local_path;
error = FILE_ERROR_FAILED;
cache()->GetFileOnUIThread(
- src_entry.resource_id(), src_entry.file_specific_info().md5(),
+ src_entry.resource_id(),
google_apis::test_util::CreateCopyResultCallback(&error, &local_path));
test_util::RunBlockingPoolTask();
ASSERT_EQ(FILE_ERROR_OK, error);
diff --git a/chrome/browser/chromeos/drive/file_system/update_operation.cc b/chrome/browser/chromeos/drive/file_system/update_operation.cc
index 7bc4255..324fcda 100644
--- a/chrome/browser/chromeos/drive/file_system/update_operation.cc
+++ b/chrome/browser/chromeos/drive/file_system/update_operation.cc
@@ -40,8 +40,7 @@
if (drive_file_path->empty())
return FILE_ERROR_NOT_FOUND;
- error = cache->GetFile(
- resource_id, entry->file_specific_info().md5(), cache_file_path);
+ error = cache->GetFile(resource_id, cache_file_path);
if (error != FILE_ERROR_OK)
return error;
diff --git a/chrome/browser/chromeos/drive/file_system_unittest.cc b/chrome/browser/chromeos/drive/file_system_unittest.cc
index 95bfd1b..68d79c2 100644
--- a/chrome/browser/chromeos/drive/file_system_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_system_unittest.cc
@@ -772,8 +772,7 @@
EXPECT_TRUE(cache_entry.is_dirty());
base::FilePath cache_file_path;
- EXPECT_EQ(FILE_ERROR_OK,
- cache_->GetFile(file_resource_id, md5, &cache_file_path));
+ EXPECT_EQ(FILE_ERROR_OK, cache_->GetFile(file_resource_id, &cache_file_path));
EXPECT_EQ(cache_file_path, opened_file_path);
// Write a new content.
diff --git a/chrome/browser/chromeos/drive/resource_metadata_storage.cc b/chrome/browser/chromeos/drive/resource_metadata_storage.cc
index 6f7c74d..56a6bc9 100644
--- a/chrome/browser/chromeos/drive/resource_metadata_storage.cc
+++ b/chrome/browser/chromeos/drive/resource_metadata_storage.cc
@@ -121,6 +121,28 @@
return entry_;
}
+bool ResourceMetadataStorage::Iterator::GetCacheEntry(
+ FileCacheEntry* cache_entry) {
+ base::ThreadRestrictions::AssertIOAllowed();
+ DCHECK(!IsAtEnd());
+
+ // Try to seek to the cache entry.
+ std::string current_key = it_->key().ToString();
+ std::string cache_entry_key = GetCacheEntryKey(current_key);
+ it_->Seek(leveldb::Slice(cache_entry_key));
+
+ bool success = it_->Valid() &&
+ it_->key().compare(cache_entry_key) == 0 &&
+ cache_entry->ParseFromArray(it_->value().data(), it_->value().size());
+
+ // Seek back to the original position.
+ it_->Seek(leveldb::Slice(current_key));
+ DCHECK(!IsAtEnd());
+ DCHECK_EQ(current_key, it_->key().ToString());
+
+ return success;
+}
+
void ResourceMetadataStorage::Iterator::Advance() {
base::ThreadRestrictions::AssertIOAllowed();
DCHECK(!IsAtEnd());
diff --git a/chrome/browser/chromeos/drive/resource_metadata_storage.h b/chrome/browser/chromeos/drive/resource_metadata_storage.h
index adac420..0ad61ef 100644
--- a/chrome/browser/chromeos/drive/resource_metadata_storage.h
+++ b/chrome/browser/chromeos/drive/resource_metadata_storage.h
@@ -51,6 +51,9 @@
// Returns the entry currently pointed by this object.
const ResourceEntry& Get() const;
+ // Gets the cache entry which corresponds to |entry_| if available.
+ bool GetCacheEntry(FileCacheEntry* cache_entry);
+
// Advances to the next entry.
void Advance();
diff --git a/chrome/browser/chromeos/drive/resource_metadata_storage_unittest.cc b/chrome/browser/chromeos/drive/resource_metadata_storage_unittest.cc
index a1f31ad..667f920 100644
--- a/chrome/browser/chromeos/drive/resource_metadata_storage_unittest.cc
+++ b/chrome/browser/chromeos/drive/resource_metadata_storage_unittest.cc
@@ -151,24 +151,39 @@
for (size_t i = 0; i < entries.size(); ++i)
EXPECT_TRUE(storage_->PutEntry(entries[i]));
- // Insert some dummy cache entries.
- FileCacheEntry cache_entry;
- EXPECT_TRUE(storage_->PutCacheEntry(entries[0].resource_id(), cache_entry));
- EXPECT_TRUE(storage_->PutCacheEntry(entries[1].resource_id(), cache_entry));
+ // Insert some cache entries.
+ std::map<std::string, FileCacheEntry> cache_entries;
+ cache_entries[entries[0].resource_id()].set_md5("aaaaaa");
+ cache_entries[entries[1].resource_id()].set_md5("bbbbbb");
+ for (std::map<std::string, FileCacheEntry>::iterator it =
+ cache_entries.begin(); it != cache_entries.end(); ++it)
+ EXPECT_TRUE(storage_->PutCacheEntry(it->first, it->second));
// Iterate and check the result.
- std::map<std::string, ResourceEntry> result;
+ std::map<std::string, ResourceEntry> found_entries;
+ std::map<std::string, FileCacheEntry> found_cache_entries;
scoped_ptr<ResourceMetadataStorage::Iterator> it = storage_->GetIterator();
ASSERT_TRUE(it);
for (; !it->IsAtEnd(); it->Advance()) {
const ResourceEntry& entry = it->Get();
- result[entry.resource_id()] = entry;
+ found_entries[entry.resource_id()] = entry;
+
+ FileCacheEntry cache_entry;
+ if (it->GetCacheEntry(&cache_entry))
+ found_cache_entries[entry.resource_id()] = cache_entry;
}
EXPECT_FALSE(it->HasError());
- EXPECT_EQ(entries.size(), result.size());
+ EXPECT_EQ(entries.size(), found_entries.size());
for (size_t i = 0; i < entries.size(); ++i)
- EXPECT_EQ(1U, result.count(entries[i].resource_id()));
+ EXPECT_EQ(1U, found_entries.count(entries[i].resource_id()));
+
+ EXPECT_EQ(cache_entries.size(), found_cache_entries.size());
+ for (std::map<std::string, FileCacheEntry>::iterator it =
+ cache_entries.begin(); it != cache_entries.end(); ++it) {
+ ASSERT_EQ(1U, found_cache_entries.count(it->first));
+ EXPECT_EQ(it->second.md5(), found_cache_entries[it->first].md5());
+ }
}
TEST_F(ResourceMetadataStorageTest, PutCacheEntry) {
diff --git a/chrome/browser/chromeos/drive/search_metadata.cc b/chrome/browser/chromeos/drive/search_metadata.cc
index 9e5b30c..a167830 100644
--- a/chrome/browser/chromeos/drive/search_metadata.cc
+++ b/chrome/browser/chromeos/drive/search_metadata.cc
@@ -10,7 +10,6 @@
#include "base/bind.h"
#include "base/i18n/string_search.h"
#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/chromeos/drive/file_cache.h"
#include "chrome/browser/chromeos/drive/file_system_util.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/escape.h"
@@ -83,7 +82,7 @@
// SEARCH_METADATA_OFFLINE is requested, only hosted documents and cached files
// match with the query. This option can not be used with other options.
bool IsEligibleEntry(const ResourceEntry& entry,
- internal::FileCache* cache,
+ ResourceMetadata::Iterator* it,
int options) {
if ((options & SEARCH_METADATA_EXCLUDE_HOSTED_DOCUMENTS) &&
entry.file_specific_info().is_hosted_document())
@@ -100,9 +99,7 @@
if (entry.file_specific_info().is_hosted_document())
return true;
FileCacheEntry cache_entry;
- cache->GetCacheEntry(entry.resource_id(),
- std::string(),
- &cache_entry);
+ it->GetCacheEntry(&cache_entry);
return cache_entry.is_present();
}
@@ -121,15 +118,16 @@
// the query.
void MaybeAddEntryToResult(
ResourceMetadata* resource_metadata,
- FileCache* cache,
+ ResourceMetadata::Iterator* it,
base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents* query,
int options,
size_t at_most_num_matches,
ScopedPriorityQueue<MetadataSearchResult,
- MetadataSearchResultComparator>* result_candidates,
- const ResourceEntry& entry) {
+ MetadataSearchResultComparator>* result_candidates) {
DCHECK_GE(at_most_num_matches, result_candidates->size());
+ const ResourceEntry& entry = it->Get();
+
// If the candidate set is already full, and this |entry| is old, do nothing.
// We perform this check first in order to avoid the costly find-and-highlight
// or FilePath lookup as much as possible.
@@ -141,7 +139,7 @@
// |options| and matches the query. The base name of the entry must
// contain |query| to match the query.
std::string highlighted;
- if (!IsEligibleEntry(entry, cache, options) ||
+ if (!IsEligibleEntry(entry, it, options) ||
(query && !FindAndHighlight(entry.base_name(), query, &highlighted)))
return;
@@ -153,7 +151,6 @@
// Implements SearchMetadata().
FileError SearchMetadataOnBlockingPool(ResourceMetadata* resource_metadata,
- FileCache* cache,
const std::string& query_text,
int options,
int at_most_num_matches,
@@ -168,10 +165,10 @@
// Iterate over entries.
scoped_ptr<ResourceMetadata::Iterator> it = resource_metadata->GetIterator();
for (; !it->IsAtEnd(); it->Advance()) {
- MaybeAddEntryToResult(resource_metadata, cache,
+ MaybeAddEntryToResult(resource_metadata, it.get(),
query_text.empty() ? NULL : &query,
options,
- at_most_num_matches, &result_candidates, it->Get());
+ at_most_num_matches, &result_candidates);
}
// Prepare the result.
@@ -207,7 +204,6 @@
void SearchMetadata(
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
ResourceMetadata* resource_metadata,
- FileCache* cache,
const std::string& query,
int options,
int at_most_num_matches,
@@ -223,7 +219,6 @@
FROM_HERE,
base::Bind(&SearchMetadataOnBlockingPool,
resource_metadata,
- cache,
query,
options,
at_most_num_matches,
diff --git a/chrome/browser/chromeos/drive/search_metadata.h b/chrome/browser/chromeos/drive/search_metadata.h
index d4e0e6f..e4f140d 100644
--- a/chrome/browser/chromeos/drive/search_metadata.h
+++ b/chrome/browser/chromeos/drive/search_metadata.h
@@ -18,7 +18,6 @@
namespace drive {
namespace internal {
-class FileCache;
class ResourceMetadata;
// Searches the local resource metadata, and returns the entries
@@ -31,7 +30,6 @@
void SearchMetadata(
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
ResourceMetadata* resource_metadata,
- FileCache* cache,
const std::string& query,
int search_options,
int at_most_num_matches,
diff --git a/chrome/browser/chromeos/drive/search_metadata_unittest.cc b/chrome/browser/chromeos/drive/search_metadata_unittest.cc
index 1c9c3d4..9e1ff21 100644
--- a/chrome/browser/chromeos/drive/search_metadata_unittest.cc
+++ b/chrome/browser/chromeos/drive/search_metadata_unittest.cc
@@ -218,7 +218,6 @@
SearchMetadata(base::MessageLoopProxy::current(),
resource_metadata_.get(),
- cache_.get(),
"NonExistent",
SEARCH_METADATA_ALL,
kDefaultAtMostNumMatches,
@@ -236,7 +235,6 @@
SearchMetadata(base::MessageLoopProxy::current(),
resource_metadata_.get(),
- cache_.get(),
"SubDirectory File 1.txt",
SEARCH_METADATA_ALL,
kDefaultAtMostNumMatches,
@@ -259,7 +257,6 @@
// The query is all in lower case.
SearchMetadata(base::MessageLoopProxy::current(),
resource_metadata_.get(),
- cache_.get(),
"subdirectory file 1.txt",
SEARCH_METADATA_ALL,
kDefaultAtMostNumMatches,
@@ -279,7 +276,6 @@
SearchMetadata(base::MessageLoopProxy::current(),
resource_metadata_.get(),
- cache_.get(),
"SubDir",
SEARCH_METADATA_ALL,
kDefaultAtMostNumMatches,
@@ -309,7 +305,6 @@
// returned.
SearchMetadata(base::MessageLoopProxy::current(),
resource_metadata_.get(),
- cache_.get(),
"SubDir",
SEARCH_METADATA_ALL,
1, // at_most_num_matches
@@ -329,7 +324,6 @@
SearchMetadata(base::MessageLoopProxy::current(),
resource_metadata_.get(),
- cache_.get(),
"Directory 1",
SEARCH_METADATA_ALL,
kDefaultAtMostNumMatches,
@@ -348,7 +342,6 @@
SearchMetadata(base::MessageLoopProxy::current(),
resource_metadata_.get(),
- cache_.get(),
"Document",
SEARCH_METADATA_ALL,
kDefaultAtMostNumMatches,
@@ -369,7 +362,6 @@
SearchMetadata(base::MessageLoopProxy::current(),
resource_metadata_.get(),
- cache_.get(),
"Document",
SEARCH_METADATA_EXCLUDE_HOSTED_DOCUMENTS,
kDefaultAtMostNumMatches,
@@ -387,7 +379,6 @@
SearchMetadata(base::MessageLoopProxy::current(),
resource_metadata_.get(),
- cache_.get(),
"",
SEARCH_METADATA_SHARED_WITH_ME,
kDefaultAtMostNumMatches,
@@ -407,7 +398,6 @@
SearchMetadata(base::MessageLoopProxy::current(),
resource_metadata_.get(),
- cache_.get(),
"excludeDir-test",
SEARCH_METADATA_ALL,
kDefaultAtMostNumMatches,
@@ -431,7 +421,6 @@
SearchMetadata(base::MessageLoopProxy::current(),
resource_metadata_.get(),
- cache_.get(),
"excludeDir-test",
SEARCH_METADATA_EXCLUDE_DIRECTORIES,
kDefaultAtMostNumMatches,
@@ -457,7 +446,6 @@
const std::string query = kQueries[i];
SearchMetadata(base::MessageLoopProxy::current(),
resource_metadata_.get(),
- cache_.get(),
query,
SEARCH_METADATA_ALL,
kDefaultAtMostNumMatches,
@@ -485,7 +473,6 @@
SearchMetadata(base::MessageLoopProxy::current(),
resource_metadata_.get(),
- cache_.get(),
"",
SEARCH_METADATA_OFFLINE,
kDefaultAtMostNumMatches,
diff --git a/chrome/browser/chromeos/drive/sync_client_unittest.cc b/chrome/browser/chromeos/drive/sync_client_unittest.cc
index c209643..6c0c8d6 100644
--- a/chrome/browser/chromeos/drive/sync_client_unittest.cc
+++ b/chrome/browser/chromeos/drive/sync_client_unittest.cc
@@ -293,13 +293,13 @@
base::FilePath cache_file;
std::string content;
EXPECT_EQ(FILE_ERROR_OK, cache_->GetFile(resource_ids_["fetched"],
- std::string(), &cache_file));
+ &cache_file));
EXPECT_TRUE(file_util::ReadFileToString(cache_file, &content));
EXPECT_EQ(kRemoteContent, content);
content.clear();
EXPECT_EQ(FILE_ERROR_OK, cache_->GetFile(resource_ids_["dirty"],
- std::string(), &cache_file));
+ &cache_file));
EXPECT_TRUE(file_util::ReadFileToString(cache_file, &content));
EXPECT_EQ(kLocalContent, content);
}
diff --git a/chrome/browser/chromeos/extensions/external_cache.cc b/chrome/browser/chromeos/extensions/external_cache.cc
new file mode 100644
index 0000000..3e19c65
--- /dev/null
+++ b/chrome/browser/chromeos/extensions/external_cache.cc
@@ -0,0 +1,440 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/extensions/external_cache.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/file_util.h"
+#include "base/files/file_enumerator.h"
+#include "base/location.h"
+#include "base/strings/string_util.h"
+#include "base/values.h"
+#include "base/version.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/extensions/crx_installer.h"
+#include "chrome/browser/extensions/external_provider_impl.h"
+#include "chrome/browser/extensions/updater/extension_downloader.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_source.h"
+
+namespace chromeos {
+
+namespace {
+
+// File name extension for CRX files (not case sensitive).
+const char kCRXFileExtension[] = ".crx";
+
+} // namespace
+
+ExternalCache::ExternalCache(const std::string& cache_dir,
+ net::URLRequestContextGetter* request_context,
+ Delegate* delegate)
+ : cache_dir_(cache_dir),
+ request_context_(request_context),
+ delegate_(delegate),
+ cached_extensions_(new base::DictionaryValue()),
+ weak_ptr_factory_(this),
+ worker_pool_token_(
+ content::BrowserThread::GetBlockingPool()->GetSequenceToken()) {
+ notification_registrar_.Add(
+ this,
+ chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
+ content::NotificationService::AllBrowserContextsAndSources());
+}
+
+ExternalCache::~ExternalCache() {
+}
+
+void ExternalCache::UpdateExtensionsList(
+ scoped_ptr<base::DictionaryValue> prefs) {
+ extensions_ = prefs.Pass();
+ CheckCacheNow();
+}
+
+void ExternalCache::OnDamagedFileDetected(const base::FilePath& path) {
+ for (base::DictionaryValue::Iterator it(*cached_extensions_.get());
+ !it.IsAtEnd(); it.Advance()) {
+ const base::DictionaryValue* entry = NULL;
+ if (it.value().GetAsDictionary(&entry)) {
+ NOTREACHED() << "ExternalCache found bad entry with type "
+ << it.value().GetType();
+ continue;
+ }
+
+ std::string external_crx;
+ if (entry->GetString(extensions::ExternalProviderImpl::kExternalCrx,
+ &external_crx) &&
+ external_crx == path.value()) {
+
+ LOG(ERROR) << "ExternalCache extension at " << path.value()
+ << " failed to install, deleting it.";
+ cached_extensions_->Remove(it.key(), NULL);
+ UpdateExtensionLoader();
+
+ // The file will be downloaded again on the next restart.
+ content::BrowserThread::PostTask(
+ content::BrowserThread::FILE, FROM_HERE,
+ base::Bind(base::IgnoreResult(base::DeleteFile), path, true));
+
+ // Don't try to DownloadMissingExtensions() from here,
+ // since it can cause a fail/retry loop.
+ return;
+ }
+ }
+ LOG(ERROR) << "ExternalCache cannot find external_crx " << path.value();
+}
+
+void ExternalCache::Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ switch (type) {
+ case chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR: {
+ extensions::CrxInstaller* installer =
+ content::Source<extensions::CrxInstaller>(source).ptr();
+ OnDamagedFileDetected(installer->source_file());
+ break;
+ }
+
+ default:
+ NOTREACHED();
+ }
+}
+
+void ExternalCache::OnExtensionDownloadFailed(
+ const std::string& id,
+ extensions::ExtensionDownloaderDelegate::Error error,
+ const extensions::ExtensionDownloaderDelegate::PingResult& ping_result,
+ const std::set<int>& request_ids) {
+ if (error == NO_UPDATE_AVAILABLE) {
+ if (!cached_extensions_->HasKey(id)) {
+ LOG(ERROR) << "ExternalCache extension " << id
+ << " not found on update server";
+ }
+ } else {
+ LOG(ERROR) << "ExternalCache failed to download extension " << id
+ << ", error " << error;
+ }
+}
+
+void ExternalCache::OnExtensionDownloadFinished(
+ const std::string& id,
+ const base::FilePath& path,
+ const GURL& download_url,
+ const std::string& version,
+ const extensions::ExtensionDownloaderDelegate::PingResult& ping_result,
+ const std::set<int>& request_ids) {
+ // The explicit copy ctors are to make sure that Bind() binds a copy and not
+ // a reference to the arguments.
+ PostBlockingTask(FROM_HERE,
+ base::Bind(&ExternalCache::BlockingInstallCacheEntry,
+ weak_ptr_factory_.GetWeakPtr(),
+ std::string(cache_dir_),
+ std::string(id),
+ base::FilePath(path),
+ std::string(version)));
+}
+
+void ExternalCache::OnBlacklistDownloadFinished(
+ const std::string& data,
+ const std::string& package_hash,
+ const std::string& version,
+ const extensions::ExtensionDownloaderDelegate::PingResult& ping_result,
+ const std::set<int>& request_ids) {
+ NOTREACHED();
+}
+
+bool ExternalCache::IsExtensionPending(const std::string& id) {
+ // Pending means that there is no installed version yet.
+ return extensions_->HasKey(id) && !cached_extensions_->HasKey(id);
+}
+
+bool ExternalCache::GetExtensionExistingVersion(const std::string& id,
+ std::string* version) {
+ DictionaryValue* extension_dictionary = NULL;
+ if (cached_extensions_->GetDictionary(id, &extension_dictionary)) {
+ return extension_dictionary->GetString(
+ extensions::ExternalProviderImpl::kExternalVersion,
+ version);
+ }
+ return false;
+}
+
+void ExternalCache::CheckCacheNow() {
+ scoped_ptr<DictionaryValue> prefs(extensions_->DeepCopy());
+ PostBlockingTask(FROM_HERE,
+ base::Bind(&ExternalCache::BlockingCheckCache,
+ weak_ptr_factory_.GetWeakPtr(),
+ std::string(cache_dir_),
+ base::Passed(&prefs)));
+}
+
+void ExternalCache::UpdateExtensionLoader() {
+ VLOG(1) << "Notify ExternalCache delegate about cache update";
+ if (delegate_)
+ delegate_->OnExtensionListsUpdated(cached_extensions_.get());
+}
+
+// static
+void ExternalCache::BlockingCheckCache(
+ base::WeakPtr<ExternalCache> external_cache,
+ const std::string& cache_dir,
+ scoped_ptr<base::DictionaryValue> prefs) {
+ BlockingCheckCacheInternal(cache_dir, prefs.get());
+ content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
+ base::Bind(&ExternalCache::OnCacheUpdated,
+ external_cache,
+ base::Passed(&prefs)));
+}
+
+// static
+void ExternalCache::BlockingCheckCacheInternal(const std::string& cache_dir,
+ base::DictionaryValue* prefs) {
+ // Start by verifying that the cache dir exists.
+ base::FilePath dir(cache_dir);
+ if (!base::DirectoryExists(dir)) {
+ // Create it now.
+ if (!file_util::CreateDirectory(dir)) {
+ LOG(ERROR) << "Failed to create ExternalCache directory at "
+ << dir.value();
+
+ // Nothing else to do. Cache won't be used.
+ return;
+ }
+ }
+
+ // Enumerate all the files in the cache |dir|, including directories
+ // and symlinks. Each unrecognized file will be erased.
+ int types = base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES |
+ base::FileEnumerator::SHOW_SYM_LINKS;
+ base::FileEnumerator enumerator(dir, false /* recursive */, types);
+ for (base::FilePath path = enumerator.Next();
+ !path.empty(); path = enumerator.Next()) {
+ base::FileEnumerator::FileInfo info = enumerator.GetInfo();
+ std::string basename = path.BaseName().value();
+
+ if (info.IsDirectory() || file_util::IsLink(info.GetName())) {
+ LOG(ERROR) << "Erasing bad file in ExternalCache directory: " << basename;
+ base::DeleteFile(path, true /* recursive */);
+ continue;
+ }
+
+ // crx files in the cache are named <extension-id>-<version>.crx.
+ std::string id;
+ std::string version;
+ if (EndsWith(basename, kCRXFileExtension, false /* case-sensitive */)) {
+ size_t n = basename.find('-');
+ if (n != std::string::npos && n + 1 < basename.size() - 4) {
+ id = basename.substr(0, n);
+ // Size of |version| = total size - "<id>" - "-" - ".crx"
+ version = basename.substr(n + 1, basename.size() - 5 - id.size());
+ }
+ }
+
+ base::DictionaryValue* entry = NULL;
+ if (!extensions::Extension::IdIsValid(id)) {
+ LOG(ERROR) << "Bad extension id in ExternalCache: " << id;
+ id.clear();
+ } else if (!prefs->GetDictionary(id, &entry)) {
+ LOG(WARNING) << basename << " is in the cache but is not configured by "
+ << "the ExternalCache source, and will be erased.";
+ id.clear();
+ }
+
+ if (!Version(version).IsValid()) {
+ LOG(ERROR) << "Bad extension version in ExternalCache: " << version;
+ version.clear();
+ }
+
+ if (id.empty() || version.empty()) {
+ LOG(ERROR) << "Invalid file in ExternalCache, erasing: " << basename;
+ base::DeleteFile(path, true /* recursive */);
+ continue;
+ }
+
+ // Enforce a lower-case id.
+ id = StringToLowerASCII(id);
+
+ std::string update_url;
+ std::string prev_version_string;
+ std::string prev_crx;
+ if (entry->GetString(extensions::ExternalProviderImpl::kExternalUpdateUrl,
+ &update_url)) {
+ VLOG(1) << "ExternalCache found cached version " << version
+ << " for extension id: " << id;
+ entry->Remove(extensions::ExternalProviderImpl::kExternalUpdateUrl, NULL);
+ entry->SetString(extensions::ExternalProviderImpl::kExternalVersion,
+ version);
+ entry->SetString(extensions::ExternalProviderImpl::kExternalCrx,
+ path.value());
+ if (extension_urls::IsWebstoreUpdateUrl(GURL(update_url))) {
+ entry->SetBoolean(extensions::ExternalProviderImpl::kIsFromWebstore,
+ true);
+ }
+ } else if (
+ entry->GetString(extensions::ExternalProviderImpl::kExternalVersion,
+ &prev_version_string) &&
+ entry->GetString(extensions::ExternalProviderImpl::kExternalCrx,
+ &prev_crx)) {
+ LOG(ERROR) << "Found two ExternalCache files for the same extension, "
+ "will erase the oldest version";
+ Version prev_version(prev_version_string);
+ Version curr_version(version);
+ DCHECK(prev_version.IsValid());
+ DCHECK(curr_version.IsValid());
+ if (prev_version.CompareTo(curr_version) < 0) {
+ base::DeleteFile(base::FilePath(prev_crx), true /* recursive */);
+ entry->SetString(extensions::ExternalProviderImpl::kExternalCrx,
+ path.value());
+ } else {
+ base::DeleteFile(path, true /* recursive */);
+ }
+ } else {
+ NOTREACHED() << "ExternalCache found bad entry for extension id: " << id
+ << " file path: " << path.value();
+ }
+ }
+}
+
+void ExternalCache::OnCacheUpdated(scoped_ptr<base::DictionaryValue> prefs) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+ // If request_context_ is missing we can't download anything.
+ if (!downloader_ && request_context_) {
+ downloader_.reset(
+ new extensions::ExtensionDownloader(this, request_context_));
+ }
+
+ cached_extensions_->Clear();
+ for (base::DictionaryValue::Iterator it(*extensions_.get());
+ !it.IsAtEnd(); it.Advance()) {
+ const base::DictionaryValue* entry = NULL;
+ if (!it.value().GetAsDictionary(&entry)) {
+ LOG(ERROR) << "ExternalCache found bad entry with type "
+ << it.value().GetType();
+ continue;
+ }
+
+ // Check for updates for all extensions configured except for extensions
+ // marked as keep_if_present.
+ std::string update_url;
+ if (downloader_ &&
+ !entry->HasKey(extensions::ExternalProviderImpl::kKeepIfPresent) &&
+ entry->GetString(extensions::ExternalProviderImpl::kExternalUpdateUrl,
+ &update_url)) {
+ downloader_->AddPendingExtension(it.key(), GURL(update_url), 0);
+ }
+
+ base::DictionaryValue* cached_entry = NULL;
+ if (prefs->GetDictionary(it.key(), &cached_entry)) {
+ std::string crx_path;
+ if (!downloader_ ||
+ cached_entry->GetString(
+ extensions::ExternalProviderImpl::kExternalCrx, &crx_path) ||
+ cached_entry->HasKey(
+ extensions::ExternalProviderImpl::kKeepIfPresent)) {
+ base::Value* value = NULL;
+ prefs->Remove(it.key(), &value);
+ cached_extensions_->Set(it.key(), value);
+ }
+ }
+ }
+ if (downloader_)
+ downloader_->StartAllPending();
+
+ VLOG(1) << "Updated ExternalCache, there are "
+ << cached_extensions_->size() << " extensions cached";
+
+ UpdateExtensionLoader();
+}
+
+// static
+void ExternalCache::BlockingInstallCacheEntry(
+ base::WeakPtr<ExternalCache> external_cache,
+ const std::string& app_cache_dir,
+ const std::string& id,
+ const base::FilePath& path,
+ const std::string& version) {
+ Version version_validator(version);
+ if (!version_validator.IsValid()) {
+ LOG(ERROR) << "ExternalCache downloaded extension " << id << " but got bad "
+ << "version: " << version;
+ base::DeleteFile(path, true /* recursive */);
+ return;
+ }
+
+ std::string basename = id + "-" + version + kCRXFileExtension;
+ base::FilePath cache_dir(app_cache_dir);
+ base::FilePath cached_crx_path = cache_dir.Append(basename);
+
+ if (base::PathExists(cached_crx_path)) {
+ LOG(WARNING) << "AppPack downloaded a crx whose filename will overwrite "
+ << "an existing cached crx.";
+ base::DeleteFile(cached_crx_path, true /* recursive */);
+ }
+
+ if (!base::DirectoryExists(cache_dir)) {
+ LOG(ERROR) << "AppPack cache directory does not exist, creating now: "
+ << cache_dir.value();
+ if (!file_util::CreateDirectory(cache_dir)) {
+ LOG(ERROR) << "Failed to create the AppPack cache dir!";
+ base::DeleteFile(path, true /* recursive */);
+ return;
+ }
+ }
+
+ if (!base::Move(path, cached_crx_path)) {
+ LOG(ERROR) << "Failed to move AppPack crx from " << path.value()
+ << " to " << cached_crx_path.value();
+ base::DeleteFile(path, true /* recursive */);
+ return;
+ }
+
+ content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
+ base::Bind(&ExternalCache::OnCacheEntryInstalled,
+ external_cache,
+ std::string(id),
+ cached_crx_path.value(),
+ std::string(version)));
+}
+
+void ExternalCache::OnCacheEntryInstalled(const std::string& id,
+ const std::string& path,
+ const std::string& version) {
+ VLOG(1) << "AppPack installed a new extension in the cache: " << path;
+
+ base::DictionaryValue* entry = NULL;
+ std::string update_url;
+ if (!extensions_->GetDictionary(id, &entry) ||
+ !entry->GetString(extensions::ExternalProviderImpl::kExternalUpdateUrl,
+ &update_url)) {
+ LOG(ERROR) << "ExternalCache cannot find entry for extension " << id;
+ return;
+ }
+
+ // Copy entry to don't modify it inside extensions_.
+ entry = entry->DeepCopy();
+ entry->Remove(extensions::ExternalProviderImpl::kExternalUpdateUrl, NULL);
+ entry->SetString(extensions::ExternalProviderImpl::kExternalVersion, version);
+ entry->SetString(extensions::ExternalProviderImpl::kExternalCrx, path);
+ if (extension_urls::IsWebstoreUpdateUrl(GURL(update_url)))
+ entry->SetBoolean(extensions::ExternalProviderImpl::kIsFromWebstore, true);
+
+ cached_extensions_->Set(id, entry);
+ UpdateExtensionLoader();
+}
+
+void ExternalCache::PostBlockingTask(const tracked_objects::Location& location,
+ const base::Closure& task) {
+ content::BrowserThread::GetBlockingPool()->
+ PostSequencedWorkerTaskWithShutdownBehavior(
+ worker_pool_token_, location, task,
+ base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/extensions/external_cache.h b/chrome/browser/chromeos/extensions/external_cache.h
new file mode 100644
index 0000000..e9415b5
--- /dev/null
+++ b/chrome/browser/chromeos/extensions/external_cache.h
@@ -0,0 +1,172 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_EXTENSIONS_EXTERNAL_CACHE_H_
+#define CHROME_BROWSER_CHROMEOS_EXTENSIONS_EXTERNAL_CACHE_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "chrome/browser/extensions/updater/extension_downloader_delegate.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace extensions {
+class ExtensionDownloader;
+}
+
+namespace net {
+class URLRequestContextGetter;
+}
+
+namespace tracked_objects {
+class Location;
+}
+
+namespace chromeos {
+
+// The ExternalCache manages cache for external extensions.
+class ExternalCache : public content::NotificationObserver,
+ public extensions::ExtensionDownloaderDelegate {
+ public:
+ class Delegate {
+ public:
+ virtual ~Delegate() {}
+ // Caller owns |prefs|.
+ virtual void OnExtensionListsUpdated(
+ const base::DictionaryValue* prefs) = 0;
+ };
+
+ // The |request_context| is used for the update checks.
+ ExternalCache(const std::string& cache_dir,
+ net::URLRequestContextGetter* request_context,
+ Delegate* delegate);
+ virtual ~ExternalCache();
+
+ // Update list of extensions in cache and force update check for them.
+ // ExternalCache gets ownership of |prefs|.
+ void UpdateExtensionsList(scoped_ptr<base::DictionaryValue> prefs);
+
+ // If a user of one of the ExternalCache's extensions detects that
+ // the extension is damaged then this method can be used to remove it from
+ // the cache and retry to download it after a restart.
+ void OnDamagedFileDetected(const base::FilePath& path);
+
+ protected:
+ // Implementation of content::NotificationObserver:
+ virtual void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) OVERRIDE;
+
+ // Implementation of ExtensionDownloaderDelegate:
+ virtual void OnExtensionDownloadFailed(
+ const std::string& id,
+ Error error,
+ const PingResult& ping_result,
+ const std::set<int>& request_ids) OVERRIDE;
+
+ virtual void OnExtensionDownloadFinished(
+ const std::string& id,
+ const base::FilePath& path,
+ const GURL& download_url,
+ const std::string& version,
+ const PingResult& ping_result,
+ const std::set<int>& request_ids) OVERRIDE;
+
+ virtual void OnBlacklistDownloadFinished(
+ const std::string& data,
+ const std::string& package_hash,
+ const std::string& version,
+ const PingResult& ping_result,
+ const std::set<int>& request_ids) OVERRIDE;
+
+ virtual bool IsExtensionPending(const std::string& id) OVERRIDE;
+
+ virtual bool GetExtensionExistingVersion(const std::string& id,
+ std::string* version) OVERRIDE;
+
+ // Starts a cache update check immediately.
+ void CheckCacheNow();
+
+ // Notifies the that the cache has been updated, providing
+ // extensions loader with an updated list of extensions.
+ void UpdateExtensionLoader();
+
+ // Performs a cache update check on the blocking pool. |external_cache| is
+ // used to reply in the UI thread. |prefs| contains the list extensions
+ // anything else is invalid, and should be removed from the cache.
+ // Ownership of |prefs| is transferred to this function.
+ static void BlockingCheckCache(
+ base::WeakPtr<ExternalCache> external_cache,
+ const std::string& app_cache_dir,
+ scoped_ptr<base::DictionaryValue> prefs);
+
+ // Helper for BlockingCheckCache(), updates |prefs|.
+ static void BlockingCheckCacheInternal(
+ const std::string& app_cache_dir,
+ base::DictionaryValue* prefs);
+
+ // Invoked when the cache has been updated. |prefs| contains all the currently
+ // valid crx files in the cache, ownerships is transfered to this function.
+ void OnCacheUpdated(scoped_ptr<base::DictionaryValue> prefs);
+
+ // Invoked to install the downloaded crx file at |path| in the cache.
+ static void BlockingInstallCacheEntry(
+ base::WeakPtr<ExternalCache> external_cache,
+ const std::string& app_cache_dir,
+ const std::string& id,
+ const base::FilePath& path,
+ const std::string& version);
+
+ // Invoked on the UI thread when a new entry has been installed in the cache.
+ void OnCacheEntryInstalled(const std::string& id,
+ const std::string& path,
+ const std::string& version);
+
+ // Helper to post blocking IO tasks to the blocking pool.
+ void PostBlockingTask(const tracked_objects::Location& from_here,
+ const base::Closure& task);
+
+ // Path to the dir where apps cache is stored.
+ std::string cache_dir_;
+
+ // Request context used by the |downloader_|.
+ net::URLRequestContextGetter* request_context_;
+
+ // Delegate that would like to get notifications about cache updates.
+ Delegate* delegate_;
+
+ // This is the list of extensions currently configured.
+ scoped_ptr<base::DictionaryValue> extensions_;
+
+ // This contains extensions that are both currently configured
+ // and that have a valid crx in the cache.
+ scoped_ptr<base::DictionaryValue> cached_extensions_;
+
+ // Used to download the extensions and to check for updates.
+ scoped_ptr<extensions::ExtensionDownloader> downloader_;
+
+ base::WeakPtrFactory<ExternalCache> weak_ptr_factory_;
+
+ // Observes failures to install CRX files.
+ content::NotificationRegistrar notification_registrar_;
+
+ // Unique sequence token so that tasks posted by the ExternalCache are
+ // executed sequentially in the blocking pool.
+ base::SequencedWorkerPool::SequenceToken worker_pool_token_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExternalCache);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_EXTENSIONS_EXTERNAL_CACHE_H_
diff --git a/chrome/browser/chromeos/extensions/external_pref_cache_loader.cc b/chrome/browser/chromeos/extensions/external_pref_cache_loader.cc
new file mode 100644
index 0000000..cd02dae
--- /dev/null
+++ b/chrome/browser/chromeos/extensions/external_pref_cache_loader.cc
@@ -0,0 +1,47 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/extensions/external_pref_cache_loader.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/memory/singleton.h"
+#include "base/values.h"
+#include "chrome/browser/browser_process.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace chromeos {
+
+namespace {
+
+// Directory where the extensions are cached.
+const char kPreinstalledAppsCacheDir[] = "/var/cache/external_cache";
+
+} // namespace
+
+ExternalPrefCacheLoader::ExternalPrefCacheLoader(int base_path_id,
+ Options options)
+ : ExternalPrefLoader(base_path_id, options) {
+}
+
+ExternalPrefCacheLoader::~ExternalPrefCacheLoader() {
+}
+
+void ExternalPrefCacheLoader::OnExtensionListsUpdated(
+ const base::DictionaryValue* prefs) {
+ prefs_.reset(prefs->DeepCopy());
+ ExternalPrefLoader::LoadFinished();
+}
+
+void ExternalPrefCacheLoader::LoadFinished() {
+ if (!external_cache_.get()) {
+ external_cache_.reset(new ExternalCache(kPreinstalledAppsCacheDir,
+ g_browser_process->system_request_context(),
+ this));
+ }
+
+ external_cache_->UpdateExtensionsList(prefs_.Pass());
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/extensions/external_pref_cache_loader.h b/chrome/browser/chromeos/extensions/external_pref_cache_loader.h
new file mode 100644
index 0000000..f886f85
--- /dev/null
+++ b/chrome/browser/chromeos/extensions/external_pref_cache_loader.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_EXTENSIONS_EXTERNAL_PREF_CACHE_LOADER_H_
+#define CHROME_BROWSER_CHROMEOS_EXTENSIONS_EXTERNAL_PREF_CACHE_LOADER_H_
+
+#include "chrome/browser/chromeos/extensions/external_cache.h"
+#include "chrome/browser/extensions/external_pref_loader.h"
+
+namespace chromeos {
+
+// A specialization of the ExternalPrefCacheLoader that caches crx files for
+// external extensions with update URL in common place for all users on the
+// machine.
+class ExternalPrefCacheLoader : public extensions::ExternalPrefLoader,
+ public ExternalCache::Delegate {
+ public:
+ ExternalPrefCacheLoader(int base_path_id, Options options);
+
+ // Implementation of ExternalCache::Delegate:
+ virtual void OnExtensionListsUpdated(
+ const base::DictionaryValue* prefs) OVERRIDE;
+
+ protected:
+ virtual ~ExternalPrefCacheLoader();
+
+ virtual void LoadFinished() OVERRIDE;
+
+ private:
+ friend class base::RefCountedThreadSafe<ExternalLoader>;
+
+ scoped_ptr<ExternalCache> external_cache_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExternalPrefCacheLoader);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_EXTENSIONS_EXTERNAL_PREF_CACHE_LOADER_H_
diff --git a/chrome/browser/chromeos/fileapi/remote_file_system_operation.cc b/chrome/browser/chromeos/fileapi/remote_file_system_operation.cc
deleted file mode 100644
index e51e568..0000000
--- a/chrome/browser/chromeos/fileapi/remote_file_system_operation.cc
+++ /dev/null
@@ -1,244 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/fileapi/remote_file_system_operation.h"
-
-#include "base/bind.h"
-#include "base/platform_file.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/values.h"
-#include "net/url_request/url_request.h"
-#include "url/gurl.h"
-#include "webkit/browser/fileapi/file_system_url.h"
-#include "webkit/browser/fileapi/file_writer_delegate.h"
-
-using fileapi::FileSystemURL;
-
-namespace chromeos {
-
-RemoteFileSystemOperation::RemoteFileSystemOperation(
- scoped_refptr<fileapi::RemoteFileSystemProxyInterface> remote_proxy)
- : remote_proxy_(remote_proxy),
- pending_operation_(kOperationNone) {
-}
-
-RemoteFileSystemOperation::~RemoteFileSystemOperation() {
-}
-
-void RemoteFileSystemOperation::GetMetadata(const FileSystemURL& url,
- const GetMetadataCallback& callback) {
- DCHECK(SetPendingOperationType(kOperationGetMetadata));
- remote_proxy_->GetFileInfo(url, callback);
-}
-
-void RemoteFileSystemOperation::DirectoryExists(const FileSystemURL& url,
- const StatusCallback& callback) {
- DCHECK(SetPendingOperationType(kOperationDirectoryExists));
- remote_proxy_->GetFileInfo(url,
- base::Bind(&RemoteFileSystemOperation::DidDirectoryExists,
- AsWeakPtr(), callback));
-}
-
-void RemoteFileSystemOperation::FileExists(const FileSystemURL& url,
- const StatusCallback& callback) {
- DCHECK(SetPendingOperationType(kOperationFileExists));
- remote_proxy_->GetFileInfo(url,
- base::Bind(base::Bind(&RemoteFileSystemOperation::DidFileExists,
- AsWeakPtr(), callback)));
-}
-
-void RemoteFileSystemOperation::ReadDirectory(const FileSystemURL& url,
- const ReadDirectoryCallback& callback) {
- DCHECK(SetPendingOperationType(kOperationReadDirectory));
- remote_proxy_->ReadDirectory(url, callback);
-}
-
-void RemoteFileSystemOperation::Remove(const FileSystemURL& url, bool recursive,
- const StatusCallback& callback) {
- DCHECK(SetPendingOperationType(kOperationRemove));
- remote_proxy_->Remove(url, recursive,
- base::Bind(&RemoteFileSystemOperation::DidFinishFileOperation,
- AsWeakPtr(), callback));
-}
-
-
-void RemoteFileSystemOperation::CreateDirectory(
- const FileSystemURL& url, bool exclusive, bool recursive,
- const StatusCallback& callback) {
- DCHECK(SetPendingOperationType(kOperationCreateDirectory));
- remote_proxy_->CreateDirectory(url, exclusive, recursive,
- base::Bind(&RemoteFileSystemOperation::DidFinishFileOperation,
- AsWeakPtr(), callback));
-}
-
-void RemoteFileSystemOperation::CreateFile(const FileSystemURL& url,
- bool exclusive,
- const StatusCallback& callback) {
- DCHECK(SetPendingOperationType(kOperationCreateFile));
- remote_proxy_->CreateFile(url, exclusive,
- base::Bind(&RemoteFileSystemOperation::DidFinishFileOperation,
- AsWeakPtr(), callback));
-}
-
-void RemoteFileSystemOperation::Copy(const FileSystemURL& src_url,
- const FileSystemURL& dest_url,
- const StatusCallback& callback) {
- DCHECK(SetPendingOperationType(kOperationCopy));
-
- remote_proxy_->Copy(src_url, dest_url,
- base::Bind(&RemoteFileSystemOperation::DidFinishFileOperation,
- AsWeakPtr(), callback));
-}
-
-void RemoteFileSystemOperation::Move(const FileSystemURL& src_url,
- const FileSystemURL& dest_url,
- const StatusCallback& callback) {
- DCHECK(SetPendingOperationType(kOperationMove));
-
- remote_proxy_->Move(src_url, dest_url,
- base::Bind(&RemoteFileSystemOperation::DidFinishFileOperation,
- AsWeakPtr(), callback));
-}
-
-void RemoteFileSystemOperation::Write(
- const FileSystemURL& url,
- scoped_ptr<fileapi::FileWriterDelegate> writer_delegate,
- scoped_ptr<net::URLRequest> blob_request,
- const WriteCallback& callback) {
- DCHECK(SetPendingOperationType(kOperationWrite));
- file_writer_delegate_ = writer_delegate.Pass();
- file_writer_delegate_->Start(
- blob_request.Pass(),
- base::Bind(&RemoteFileSystemOperation::DidWrite, AsWeakPtr(), callback));
-}
-
-void RemoteFileSystemOperation::Truncate(const FileSystemURL& url,
- int64 length,
- const StatusCallback& callback) {
- DCHECK(SetPendingOperationType(kOperationTruncate));
-
- remote_proxy_->Truncate(url, length,
- base::Bind(&RemoteFileSystemOperation::DidFinishFileOperation,
- AsWeakPtr(), callback));
-}
-
-void RemoteFileSystemOperation::Cancel(const StatusCallback& cancel_callback) {
- DCHECK(cancel_callback_.is_null());
- cancel_callback_ = cancel_callback;
-
- if (file_writer_delegate_) {
- DCHECK_EQ(kOperationWrite, pending_operation_);
- // This will call DidWrite() with ABORT status code.
- file_writer_delegate_->Cancel();
- } else {
- // For truncate we have no way to cancel the inflight operation (for now).
- // Let it just run and dispatch cancel callback later.
- DCHECK_EQ(kOperationTruncate, pending_operation_);
- }
-}
-
-void RemoteFileSystemOperation::TouchFile(const FileSystemURL& url,
- const base::Time& last_access_time,
- const base::Time& last_modified_time,
- const StatusCallback& callback) {
- DCHECK(SetPendingOperationType(kOperationTouchFile));
- remote_proxy_->TouchFile(
- url,
- last_access_time,
- last_modified_time,
- base::Bind(&RemoteFileSystemOperation::DidFinishFileOperation,
- AsWeakPtr(), callback));
-}
-
-void RemoteFileSystemOperation::OpenFile(const FileSystemURL& url,
- int file_flags,
- base::ProcessHandle peer_handle,
- const OpenFileCallback& callback) {
- DCHECK(SetPendingOperationType(kOperationOpenFile));
- remote_proxy_->OpenFile(
- url,
- file_flags,
- peer_handle,
- base::Bind(&RemoteFileSystemOperation::DidOpenFile,
- AsWeakPtr(), url, callback));
-}
-
-fileapi::LocalFileSystemOperation*
-RemoteFileSystemOperation::AsLocalFileSystemOperation() {
- NOTIMPLEMENTED();
- return NULL;
-}
-
-void RemoteFileSystemOperation::CreateSnapshotFile(
- const FileSystemURL& url,
- const SnapshotFileCallback& callback) {
- DCHECK(SetPendingOperationType(kOperationCreateSnapshotFile));
- remote_proxy_->CreateSnapshotFile(url, callback);
-}
-
-bool RemoteFileSystemOperation::SetPendingOperationType(OperationType type) {
- if (pending_operation_ != kOperationNone)
- return false;
- pending_operation_ = type;
- return true;
-}
-
-void RemoteFileSystemOperation::DidDirectoryExists(
- const StatusCallback& callback,
- base::PlatformFileError rv,
- const base::PlatformFileInfo& file_info) {
- if (rv == base::PLATFORM_FILE_OK && !file_info.is_directory)
- rv = base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
- callback.Run(rv);
-}
-
-void RemoteFileSystemOperation::DidFileExists(
- const StatusCallback& callback,
- base::PlatformFileError rv,
- const base::PlatformFileInfo& file_info) {
- if (rv == base::PLATFORM_FILE_OK && file_info.is_directory)
- rv = base::PLATFORM_FILE_ERROR_NOT_A_FILE;
- callback.Run(rv);
-}
-
-void RemoteFileSystemOperation::DidWrite(
- const WriteCallback& write_callback,
- base::PlatformFileError rv,
- int64 bytes,
- FileWriterDelegate::WriteProgressStatus write_status) {
- bool complete = (write_status != FileWriterDelegate::SUCCESS_IO_PENDING);
- StatusCallback cancel_callback = cancel_callback_;
- write_callback.Run(rv, bytes, complete);
- if (!cancel_callback.is_null())
- cancel_callback.Run(base::PLATFORM_FILE_OK);
-}
-
-void RemoteFileSystemOperation::DidFinishFileOperation(
- const StatusCallback& callback,
- base::PlatformFileError rv) {
- if (!cancel_callback_.is_null()) {
- DCHECK_EQ(kOperationTruncate, pending_operation_);
-
- StatusCallback cancel_callback = cancel_callback_;
- callback.Run(base::PLATFORM_FILE_ERROR_ABORT);
- cancel_callback.Run(base::PLATFORM_FILE_OK);
- } else {
- callback.Run(rv);
- }
-}
-
-void RemoteFileSystemOperation::DidOpenFile(
- const fileapi::FileSystemURL& url,
- const OpenFileCallback& callback,
- base::PlatformFileError result,
- base::PlatformFile file,
- base::ProcessHandle peer_handle) {
- callback.Run(
- result, file,
- base::Bind(&fileapi::RemoteFileSystemProxyInterface::NotifyCloseFile,
- remote_proxy_, url),
- peer_handle);
-}
-
-} // namespace chromeos
diff --git a/chrome/browser/chromeos/fileapi/remote_file_system_operation.h b/chrome/browser/chromeos/fileapi/remote_file_system_operation.h
deleted file mode 100644
index a467368..0000000
--- a/chrome/browser/chromeos/fileapi/remote_file_system_operation.h
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CHROMEOS_FILEAPI_REMOTE_FILE_SYSTEM_OPERATION_H_
-#define CHROME_BROWSER_CHROMEOS_FILEAPI_REMOTE_FILE_SYSTEM_OPERATION_H_
-
-#include "base/basictypes.h"
-#include "base/memory/weak_ptr.h"
-#include "webkit/browser/fileapi/file_system_operation.h"
-#include "webkit/browser/fileapi/file_writer_delegate.h"
-#include "webkit/browser/fileapi/remote_file_system_proxy.h"
-
-namespace base {
-class Value;
-}
-
-namespace fileapi {
-class FileWriterDelegate;
-class LocalFileSystemOperation;
-}
-
-namespace chromeos {
-
-// FileSystemOperation implementation for local file systems.
-class RemoteFileSystemOperation
- : public fileapi::FileSystemOperation,
- public base::SupportsWeakPtr<RemoteFileSystemOperation> {
- public:
- typedef fileapi::FileWriterDelegate FileWriterDelegate;
-
- explicit RemoteFileSystemOperation(
- scoped_refptr<fileapi::RemoteFileSystemProxyInterface> remote_proxy);
-
- virtual ~RemoteFileSystemOperation();
-
- // FileSystemOperation overrides.
- virtual void CreateFile(const fileapi::FileSystemURL& url,
- bool exclusive,
- const StatusCallback& callback) OVERRIDE;
- virtual void CreateDirectory(const fileapi::FileSystemURL& url,
- bool exclusive,
- bool recursive,
- const StatusCallback& callback) OVERRIDE;
- virtual void Copy(const fileapi::FileSystemURL& src_url,
- const fileapi::FileSystemURL& dest_url,
- const StatusCallback& callback) OVERRIDE;
- virtual void Move(const fileapi::FileSystemURL& src_url,
- const fileapi::FileSystemURL& dest_url,
- const StatusCallback& callback) OVERRIDE;
- virtual void DirectoryExists(const fileapi::FileSystemURL& url,
- const StatusCallback& callback) OVERRIDE;
- virtual void FileExists(const fileapi::FileSystemURL& url,
- const StatusCallback& callback) OVERRIDE;
- virtual void GetMetadata(const fileapi::FileSystemURL& url,
- const GetMetadataCallback& callback) OVERRIDE;
- virtual void ReadDirectory(const fileapi::FileSystemURL& url,
- const ReadDirectoryCallback& callback) OVERRIDE;
- virtual void Remove(const fileapi::FileSystemURL& url, bool recursive,
- const StatusCallback& callback) OVERRIDE;
- virtual void Write(const fileapi::FileSystemURL& url,
- scoped_ptr<fileapi::FileWriterDelegate> writer_delegate,
- scoped_ptr<net::URLRequest> blob_request,
- const WriteCallback& callback) OVERRIDE;
- virtual void Truncate(const fileapi::FileSystemURL& url, int64 length,
- const StatusCallback& callback) OVERRIDE;
- virtual void Cancel(const StatusCallback& cancel_callback) OVERRIDE;
- virtual void TouchFile(const fileapi::FileSystemURL& url,
- const base::Time& last_access_time,
- const base::Time& last_modified_time,
- const StatusCallback& callback) OVERRIDE;
- virtual void OpenFile(
- const fileapi::FileSystemURL& url,
- int file_flags,
- base::ProcessHandle peer_handle,
- const OpenFileCallback& callback) OVERRIDE;
- virtual fileapi::LocalFileSystemOperation*
- AsLocalFileSystemOperation() OVERRIDE;
- virtual void CreateSnapshotFile(
- const fileapi::FileSystemURL& url,
- const SnapshotFileCallback& callback) OVERRIDE;
-
- private:
- // Used only for internal assertions.
- // Returns false if there's another inflight pending operation.
- bool SetPendingOperationType(OperationType type);
-
- // Generic callback that translates platform errors to WebKit error codes.
- void DidDirectoryExists(const StatusCallback& callback,
- base::PlatformFileError rv,
- const base::PlatformFileInfo& file_info);
- void DidFileExists(const StatusCallback& callback,
- base::PlatformFileError rv,
- const base::PlatformFileInfo& file_info);
- void DidWrite(const WriteCallback& write_callback,
- base::PlatformFileError result,
- int64 bytes,
- FileWriterDelegate::WriteProgressStatus write_status);
- void DidFinishFileOperation(const StatusCallback& callback,
- base::PlatformFileError rv);
- void DidOpenFile(
- const fileapi::FileSystemURL& url,
- const OpenFileCallback& callback,
- base::PlatformFileError result,
- base::PlatformFile file,
- base::ProcessHandle peer_handle);
-
- scoped_refptr<fileapi::RemoteFileSystemProxyInterface> remote_proxy_;
- // A flag to make sure we call operation only once per instance.
- OperationType pending_operation_;
- scoped_ptr<fileapi::FileWriterDelegate> file_writer_delegate_;
-
- StatusCallback cancel_callback_;
-
- DISALLOW_COPY_AND_ASSIGN(RemoteFileSystemOperation);
-};
-
-} // namespace chromeos
-
-#endif // CHROME_BROWSER_CHROMEOS_FILEAPI_REMOTE_FILE_SYSTEM_OPERATION_H_
diff --git a/chrome/browser/chromeos/policy/app_pack_updater.h b/chrome/browser/chromeos/policy/app_pack_updater.h
index 390de7e..9f256b8 100644
--- a/chrome/browser/chromeos/policy/app_pack_updater.h
+++ b/chrome/browser/chromeos/policy/app_pack_updater.h
@@ -22,7 +22,6 @@
class GURL;
namespace extensions {
-class CrxInstaller;
class ExtensionDownloader;
class ExternalLoader;
}
@@ -164,10 +163,6 @@
const std::string& path,
const std::string& version);
- // Handles failure to install CRX files. The file is deleted if it came from
- // the cache.
- void OnCrxInstallFailed(extensions::CrxInstaller* installer);
-
// Helper to post blocking IO tasks to the blocking pool.
void PostBlockingTask(const tracked_objects::Location& from_here,
const base::Closure& task);
diff --git a/chrome/browser/chromeos/system/ash_system_tray_delegate.cc b/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
index a7f7ed9..96f6f9d 100644
--- a/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
+++ b/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
@@ -679,8 +679,10 @@
virtual void ConnectToBluetoothDevice(const std::string& address) OVERRIDE {
device::BluetoothDevice* device = bluetooth_adapter_->GetDevice(address);
- if (!device || device->IsConnecting() || device->IsConnected())
+ if (!device || device->IsConnecting() ||
+ (device->IsConnected() && device->IsPaired())) {
return;
+ }
if (device->IsPaired() && !device->IsConnectable())
return;
if (device->IsPaired() || !device->IsPairable()) {
diff --git a/chrome/browser/chromeos/system_logs/debug_daemon_log_source.cc b/chrome/browser/chromeos/system_logs/debug_daemon_log_source.cc
index 60ba329..feb1d8f 100644
--- a/chrome/browser/chromeos/system_logs/debug_daemon_log_source.cc
+++ b/chrome/browser/chromeos/system_logs/debug_daemon_log_source.cc
@@ -23,6 +23,7 @@
const char kRoutesKeyName[] = "routes";
const char kNetworkStatusKeyName[] = "network-status";
const char kModemStatusKeyName[] = "modem-status";
+const char kWiMaxStatusKeyName[] = "wimax-status";
const char kUserLogFileKeyName[] = "user_log_files";
namespace chromeos {
@@ -53,6 +54,9 @@
client->GetModemStatus(base::Bind(&DebugDaemonLogSource::OnGetModemStatus,
weak_ptr_factory_.GetWeakPtr()));
++num_pending_requests_;
+ client->GetWiMaxStatus(base::Bind(&DebugDaemonLogSource::OnGetWiMaxStatus,
+ weak_ptr_factory_.GetWeakPtr()));
+ ++num_pending_requests_;
client->GetAllLogs(base::Bind(&DebugDaemonLogSource::OnGetLogs,
weak_ptr_factory_.GetWeakPtr()));
++num_pending_requests_;
@@ -94,6 +98,17 @@
RequestCompleted();
}
+void DebugDaemonLogSource::OnGetWiMaxStatus(bool succeeded,
+ const std::string& status) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+ if (succeeded)
+ (*response_)[kWiMaxStatusKeyName] = status;
+ else
+ (*response_)[kWiMaxStatusKeyName] = kNotAvailable;
+ RequestCompleted();
+}
+
void DebugDaemonLogSource::OnGetLogs(bool /* succeeded */,
const KeyValueMap& logs) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
diff --git a/chrome/browser/chromeos/system_logs/debug_daemon_log_source.h b/chrome/browser/chromeos/system_logs/debug_daemon_log_source.h
index aea030f..8d1626c 100644
--- a/chrome/browser/chromeos/system_logs/debug_daemon_log_source.h
+++ b/chrome/browser/chromeos/system_logs/debug_daemon_log_source.h
@@ -33,6 +33,7 @@
void OnGetRoutes(bool succeeded, const std::vector<std::string>& routes);
void OnGetNetworkStatus(bool succeeded, const std::string& status);
void OnGetModemStatus(bool succeeded, const std::string& status);
+ void OnGetWiMaxStatus(bool succeeded, const std::string& status);
void OnGetLogs(bool succeeded,
const KeyValueMap& logs);
void OnGetUserLogFiles(bool succeeded,
diff --git a/chrome/browser/drive/drive_uploader.cc b/chrome/browser/drive/drive_uploader.cc
index 0d4866a..493a763 100644
--- a/chrome/browser/drive/drive_uploader.cc
+++ b/chrome/browser/drive/drive_uploader.cc
@@ -34,6 +34,15 @@
namespace drive {
+namespace {
+// Upload data is split to multiple HTTP request each conveying kUploadChunkSize
+// bytes (except the request for uploading the last chunk of data).
+// The value must be a multiple of 512KB according to the spec of GData WAPI and
+// Drive API v2. It is set to a smaller value than 2^31 for working around
+// server side error (crbug.com/264089).
+const int64 kUploadChunkSize = (1LL << 30); // 1GB
+} // namespace
+
// Structure containing current upload information of file, passed between
// DriveServiceInterface methods and callbacks.
struct DriveUploader::UploadFileInfo {
@@ -316,11 +325,15 @@
return;
}
+ // Limit the size of data uploaded per each request by kUploadChunkSize.
+ const int64 end_position = std::min(upload_file_info->content_length,
+ start_position + kUploadChunkSize);
+
UploadFileInfo* info_ptr = upload_file_info.get();
info_ptr->cancel_callback = drive_service_->ResumeUpload(
info_ptr->upload_location,
start_position,
- info_ptr->content_length,
+ end_position,
info_ptr->content_length,
info_ptr->content_type,
info_ptr->file_path,
diff --git a/chrome/browser/extensions/ad_view_browsertest.cc b/chrome/browser/extensions/ad_view_browsertest.cc
index 045293e..4982cb2 100644
--- a/chrome/browser/extensions/ad_view_browsertest.cc
+++ b/chrome/browser/extensions/ad_view_browsertest.cc
@@ -65,7 +65,15 @@
// This test checks that <adview> attributes are also exposed as properties
// (with the same name and value).
-IN_PROC_BROWSER_TEST_F(AdViewTest, PropertiesAreInSyncWithAttributes) {
+#if defined(OS_WIN)
+// Flaky on Win XP. (http://crbug.com/264362)
+#define MAYBE_PropertiesAreInSyncWithAttributes \
+ DISABLED_PropertiesAreInSyncWithAttributes
+#else
+#define MAYBE_PropertiesAreInSyncWithAttributes \
+ PropertiesAreInSyncWithAttributes
+#endif
+IN_PROC_BROWSER_TEST_F(AdViewTest, MAYBE_PropertiesAreInSyncWithAttributes) {
ASSERT_TRUE(StartEmbeddedTestServer());
ASSERT_TRUE(RunPlatformAppTest(
diff --git a/chrome/browser/extensions/api/downloads/downloads_api.cc b/chrome/browser/extensions/api/downloads/downloads_api.cc
index 03d6613..7de85f4 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api.cc
@@ -808,11 +808,7 @@
EXTENSION_FUNCTION_VALIDATE(params.get());
const extensions::api::downloads::DownloadOptions& options = params->options;
GURL download_url(options.url);
- if (!download_url.is_valid() ||
- (!download_url.SchemeIs("data") &&
- download_url.GetOrigin() != GetExtension()->url().GetOrigin() &&
- !extensions::PermissionsData::HasHostPermission(GetExtension(),
- download_url))) {
+ if (!download_url.is_valid()) {
error_ = download_extension_errors::kInvalidURLError;
return false;
}
@@ -1109,7 +1105,9 @@
EXTENSION_FUNCTION_VALIDATE(params.get());
DownloadItem* download_item = GetDownload(
profile(), include_incognito(), params->download_id);
- if (!download_item || download_item->GetState() != DownloadItem::COMPLETE) {
+ if (!download_item || download_item->GetState() != DownloadItem::COMPLETE ||
+ !GetExtension()->HasAPIPermission(
+ extensions::APIPermission::kDownloadsOpen)) {
error_ = download_extension_errors::kInvalidOperationError;
return false;
}
diff --git a/chrome/browser/extensions/api/downloads/downloads_api_unittest.cc b/chrome/browser/extensions/api/downloads/downloads_api_unittest.cc
index 26450b6..93a40f2 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api_unittest.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api_unittest.cc
@@ -1736,17 +1736,25 @@
"http://",
"#frag",
"foo/bar.html#frag",
- "javascript:document.write(\\\"hello\\\");",
- "javascript:return false;",
- "ftp://example.com/example.txt",
};
for (size_t index = 0; index < arraysize(kInvalidURLs); ++index) {
EXPECT_STREQ(download_extension_errors::kInvalidURLError,
RunFunctionAndReturnError(new DownloadsDownloadFunction(),
base::StringPrintf(
- "[{\"url\": \"%s\"}]", kInvalidURLs[index])).c_str());
+ "[{\"url\": \"%s\"}]", kInvalidURLs[index])).c_str())
+ << kInvalidURLs[index];
}
+
+ EXPECT_STREQ("net::ERR_ACCESS_DENIED", RunFunctionAndReturnError(
+ new DownloadsDownloadFunction(),
+ "[{\"url\": \"javascript:document.write(\\\"hello\\\");\"}]").c_str());
+ EXPECT_STREQ("net::ERR_ACCESS_DENIED", RunFunctionAndReturnError(
+ new DownloadsDownloadFunction(),
+ "[{\"url\": \"javascript:return false;\"}]").c_str());
+ EXPECT_STREQ("net::ERR_NOT_IMPLEMENTED", RunFunctionAndReturnError(
+ new DownloadsDownloadFunction(),
+ "[{\"url\": \"ftp://example.com/example.txt\"}]").c_str());
}
// TODO(benjhayden): Set up a test ftp server, add ftp://localhost* to
diff --git a/chrome/browser/chromeos/extensions/networking_private_api.h b/chrome/browser/extensions/api/networking_private/networking_private_api.h
similarity index 96%
rename from chrome/browser/chromeos/extensions/networking_private_api.h
rename to chrome/browser/extensions/api/networking_private/networking_private_api.h
index d7232a3..cab006d 100644
--- a/chrome/browser/chromeos/extensions/networking_private_api.h
+++ b/chrome/browser/extensions/api/networking_private/networking_private_api.h
@@ -1,12 +1,12 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// These classes implement the chrome.networkingPrivate JavaScript extension
// API.
-#ifndef CHROME_BROWSER_CHROMEOS_EXTENSIONS_NETWORKING_PRIVATE_API_H_
-#define CHROME_BROWSER_CHROMEOS_EXTENSIONS_NETWORKING_PRIVATE_API_H_
+#ifndef CHROME_BROWSER_EXTENSIONS_API_NETWORKING_PRIVATE_NETWORKING_PRIVATE_API_H_
+#define CHROME_BROWSER_EXTENSIONS_API_NETWORKING_PRIVATE_NETWORKING_PRIVATE_API_H_
#include <string>
@@ -250,4 +250,5 @@
DISALLOW_COPY_AND_ASSIGN(NetworkingPrivateVerifyAndEncryptDataFunction);
};
-#endif // CHROME_BROWSER_CHROMEOS_EXTENSIONS_NETWORKING_PRIVATE_API_H_
+#endif // CHROME_BROWSER_EXTENSIONS_API_NETWORKING_PRIVATE_NETWORKING_PRIVATE_API_H_
+
diff --git a/chrome/browser/chromeos/extensions/networking_private_api.cc b/chrome/browser/extensions/api/networking_private/networking_private_api_chromeos.cc
similarity index 98%
rename from chrome/browser/chromeos/extensions/networking_private_api.cc
rename to chrome/browser/extensions/api/networking_private/networking_private_api_chromeos.cc
index 9708b8d..cdaf357 100644
--- a/chrome/browser/chromeos/extensions/networking_private_api.cc
+++ b/chrome/browser/extensions/api/networking_private/networking_private_api_chromeos.cc
@@ -1,8 +1,8 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/chromeos/extensions/networking_private_api.h"
+#include "chrome/browser/extensions/api/networking_private/networking_private_api.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
diff --git a/chrome/browser/extensions/api/networking_private/networking_private_api_nonchromeos.cc b/chrome/browser/extensions/api/networking_private/networking_private_api_nonchromeos.cc
new file mode 100644
index 0000000..55beff7
--- /dev/null
+++ b/chrome/browser/extensions/api/networking_private/networking_private_api_nonchromeos.cc
@@ -0,0 +1,435 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/networking_private/networking_private_api.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.h"
+#include "base/command_line.h"
+#include "base/json/json_reader.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/extensions/event_names.h"
+#include "chrome/browser/extensions/event_router.h"
+#include "chrome/browser/extensions/extension_function_registry.h"
+#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/api/networking_private.h"
+
+using extensions::event_names::kOnNetworkListChanged;
+using extensions::event_names::kOnNetworksChanged;
+using extensions::EventRouter;
+using extensions::ExtensionSystem;
+namespace api = extensions::api::networking_private;
+
+////////////////////////////////////////////////////////////////////////////////
+// NetworkingPrivateGetPropertiesFunction
+
+
+const char kNetworkingPrivateProperties[] = "NetworkingPrivateProperties";
+
+struct NetworkingPrivatePropertiesData : base::SupportsUserData::Data {
+ explicit NetworkingPrivatePropertiesData(const base::DictionaryValue* prop) :
+ properties_(prop->DeepCopy()) { }
+ scoped_ptr<base::DictionaryValue> properties_;
+};
+
+NetworkingPrivateGetPropertiesFunction::
+ ~NetworkingPrivateGetPropertiesFunction() {
+}
+
+bool NetworkingPrivateGetPropertiesFunction::RunImpl() {
+ scoped_ptr<api::GetProperties::Params> params =
+ api::GetProperties::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(params);
+
+ // If there are properties set by SetProperties function, use those.
+ NetworkingPrivatePropertiesData* stored_properties =
+ static_cast<NetworkingPrivatePropertiesData*> (
+ profile()->GetUserData(kNetworkingPrivateProperties));
+ if (stored_properties != NULL) {
+ SetResult(stored_properties->properties_.release());
+ SendResponse(true);
+ return true;
+ }
+
+ const std::string network_properties =
+ "{\"ConnectionState\":\"NotConnected\","
+ "\"GUID\":\"stub_wifi2\","
+ "\"Name\":\"wifi2_PSK\","
+ "\"Type\":\"WiFi\","
+ "\"WiFi\":{"
+ "\"Frequency\":5000,"
+ "\"FrequencyList\":[2400,5000],"
+ "\"SSID\":\"stub_wifi2\","
+ "\"Security\":\"WPA-PSK\","
+ "\"SignalStrength\":80}}";
+
+ if (params->network_guid == "nonexistent_path") {
+ error_ = "Error.DBusFailed";
+ SendResponse(false);
+ } else {
+ SetResult(base::JSONReader::Read(network_properties));
+ SendResponse(true);
+ }
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NetworkingPrivateGetManagedPropertiesFunction
+
+NetworkingPrivateGetManagedPropertiesFunction::
+ ~NetworkingPrivateGetManagedPropertiesFunction() {
+}
+
+bool NetworkingPrivateGetManagedPropertiesFunction::RunImpl() {
+ scoped_ptr<api::GetManagedProperties::Params> params =
+ api::GetManagedProperties::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(params);
+ const std::string network_properties =
+ "{"
+ " \"ConnectionState\": {"
+ " \"Active\": \"NotConnected\","
+ " \"Effective\": \"Unmanaged\""
+ " },"
+ " \"GUID\": \"stub_wifi2\","
+ " \"Name\": {"
+ " \"Active\": \"wifi2_PSK\","
+ " \"Effective\": \"UserPolicy\","
+ " \"UserPolicy\": \"My WiFi Network\""
+ " },"
+ " \"Type\": {"
+ " \"Active\": \"WiFi\","
+ " \"Effective\": \"UserPolicy\","
+ " \"UserPolicy\": \"WiFi\""
+ " },"
+ " \"WiFi\": {"
+ " \"AutoConnect\": {"
+ " \"Active\": false,"
+ " \"UserEditable\": true"
+ " },"
+ " \"Frequency\" : {"
+ " \"Active\": 5000,"
+ " \"Effective\": \"Unmanaged\""
+ " },"
+ " \"FrequencyList\" : {"
+ " \"Active\": [2400, 5000],"
+ " \"Effective\": \"Unmanaged\""
+ " },"
+ " \"Passphrase\": {"
+ " \"Effective\": \"UserSetting\","
+ " \"UserEditable\": true,"
+ " \"UserSetting\": \"FAKE_CREDENTIAL_VPaJDV9x\""
+ " },"
+ " \"SSID\": {"
+ " \"Active\": \"stub_wifi2\","
+ " \"Effective\": \"UserPolicy\","
+ " \"UserPolicy\": \"stub_wifi2\""
+ " },"
+ " \"Security\": {"
+ " \"Active\": \"WPA-PSK\","
+ " \"Effective\": \"UserPolicy\","
+ " \"UserPolicy\": \"WPA-PSK\""
+ " },"
+ " \"SignalStrength\": {"
+ " \"Active\": 80,"
+ " \"Effective\": \"Unmanaged\""
+ " }"
+ " }"
+ "}";
+
+ SetResult(base::JSONReader::Read(network_properties));
+ SendResponse(true);
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NetworkingPrivateGetStateFunction
+
+NetworkingPrivateGetStateFunction::
+ ~NetworkingPrivateGetStateFunction() {
+}
+
+bool NetworkingPrivateGetStateFunction::RunImpl() {
+ scoped_ptr<api::GetState::Params> params =
+ api::GetState::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(params);
+ const std::string network_state =
+ "{"
+ " \"ConnectionState\": \"NotConnected\","
+ " \"GUID\": \"stub_wifi2\","
+ " \"Name\": \"wifi2_PSK\","
+ " \"Type\": \"WiFi\","
+ " \"WiFi\": {"
+ " \"AutoConnect\": false,"
+ " \"FrequencyList\": [2400, 5000],"
+ " \"Security\": \"WPA-PSK\","
+ " \"SignalStrength\": 80"
+ " }"
+ "}";
+ SetResult(base::JSONReader::Read(network_state));
+ SendResponse(true);
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// NetworkingPrivateSetPropertiesFunction
+
+NetworkingPrivateSetPropertiesFunction::
+ ~NetworkingPrivateSetPropertiesFunction() {
+}
+
+bool NetworkingPrivateSetPropertiesFunction::RunImpl() {
+ scoped_ptr<api::SetProperties::Params> params =
+ api::SetProperties::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(params);
+ scoped_ptr<base::DictionaryValue> properties_dict(
+ params->properties.ToValue());
+
+ // Store properties_dict in profile to return from GetProperties.
+ profile()->SetUserData(kNetworkingPrivateProperties,
+ new NetworkingPrivatePropertiesData(properties_dict.get()));
+ SendResponse(true);
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NetworkingPrivateGetVisibleNetworksFunction
+
+NetworkingPrivateGetVisibleNetworksFunction::
+ ~NetworkingPrivateGetVisibleNetworksFunction() {
+}
+
+bool NetworkingPrivateGetVisibleNetworksFunction::RunImpl() {
+ scoped_ptr<api::GetVisibleNetworks::Params> params =
+ api::GetVisibleNetworks::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(params);
+ const std::string networks_json =
+ "[{"
+ " \"ConnectionState\": \"Connected\","
+ " \"GUID\": \"stub_ethernet\","
+ " \"Name\": \"eth0\","
+ " \"Type\": \"Ethernet\""
+ " },"
+ " {"
+ " \"ConnectionState\": \"Connected\","
+ " \"GUID\": \"stub_wifi1\","
+ " \"Name\": \"wifi1\","
+ " \"Type\": \"WiFi\","
+ " \"WiFi\": {"
+ " \"AutoConnect\": false,"
+ " \"FrequencyList\": [2400],"
+ " \"Security\": \"WEP-PSK\","
+ " \"SignalStrength\": 0"
+ " }"
+ " },"
+ " {"
+ " \"ConnectionState\": \"NotConnected\","
+ " \"GUID\": \"stub_wifi2\","
+ " \"Name\": \"wifi2_PSK\","
+ " \"Type\": \"WiFi\","
+ " \"WiFi\": {"
+ " \"AutoConnect\": false,"
+ " \"FrequencyList\": [2400, 5000],"
+ " \"Security\": \"WPA-PSK\","
+ " \"SignalStrength\": 80"
+ " }"
+ " },"
+ " {"
+ " \"Cellular\": {"
+ " \"ActivateOverNonCellularNetwork\": false,"
+ " \"ActivationState\": \"not-activated\","
+ " \"NetworkTechnology\": \"GSM\","
+ " \"RoamingState\": \"home\""
+ " },"
+ " \"ConnectionState\": \"NotConnected\","
+ " \"GUID\": \"stub_cellular1\","
+ " \"Name\": \"cellular1\","
+ " \"Type\": \"Cellular\""
+ " },"
+ " {"
+ " \"ConnectionState\": \"Connected\","
+ " \"GUID\": \"stub_vpn1\","
+ " \"Name\": \"vpn1\","
+ " \"Type\": \"VPN\","
+ " \"VPN\": {"
+ " \"AutoConnect\": false"
+ " }"
+ " }]";
+ ListValue* visible_networks =
+ static_cast<ListValue*>(base::JSONReader::Read(networks_json));
+ // If caller only needs WiFi networks, then remove all other networks.
+ if (params->type == api::GetVisibleNetworks::Params::TYPE_WIFI) {
+ visible_networks->Remove(4, NULL);
+ visible_networks->Remove(3, NULL);
+ visible_networks->Remove(0, NULL);
+ }
+
+ SetResult(visible_networks);
+ SendResponse(true);
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NetworkingPrivateRequestNetworkScanFunction
+
+NetworkingPrivateRequestNetworkScanFunction::
+ ~NetworkingPrivateRequestNetworkScanFunction() {
+}
+
+bool NetworkingPrivateRequestNetworkScanFunction::RunImpl() {
+ // Generate onNetworkListChanged event.
+ std::vector<std::string> changes;
+ changes.push_back("stub_ethernet");
+ changes.push_back("stub_wifi1");
+ changes.push_back("stub_wifi2");
+ changes.push_back("stub_cellular1");
+ changes.push_back("stub_vpn1");
+
+ EventRouter* event_router = ExtensionSystem::Get(profile_)->event_router();
+ scoped_ptr<base::ListValue> args(api::OnNetworkListChanged::Create(changes));
+ scoped_ptr<extensions::Event> extension_event(new extensions::Event(
+ kOnNetworkListChanged, args.Pass()));
+ event_router->BroadcastEvent(extension_event.Pass());
+
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NetworkingPrivateStartConnectFunction
+
+NetworkingPrivateStartConnectFunction::
+ ~NetworkingPrivateStartConnectFunction() {
+}
+
+bool NetworkingPrivateStartConnectFunction::RunImpl() {
+ scoped_ptr<api::StartConnect::Params> params =
+ api::StartConnect::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(params);
+ if (params->network_guid == "nonexistent_path") {
+ error_ = "not-found";
+ SendResponse(false);
+ } else {
+ SendResponse(true);
+ // Set Properties to reflect connected state
+ const std::string network_properties =
+ "{\"ConnectionState\":\"Connected\","
+ "\"GUID\":\"stub_wifi2\","
+ "\"Name\":\"wifi2_PSK\","
+ "\"Type\":\"WiFi\","
+ "\"WiFi\":{"
+ "\"Frequency\":5000,"
+ "\"FrequencyList\":[2400,5000],"
+ "\"SSID\":\"stub_wifi2\","
+ "\"Security\":\"WPA-PSK\","
+ "\"SignalStrength\":80}}";
+
+ // Store network_properties in profile to return from GetProperties.
+ profile()->SetUserData(kNetworkingPrivateProperties,
+ new NetworkingPrivatePropertiesData(
+ static_cast<DictionaryValue*>(
+ base::JSONReader::Read(network_properties))));
+
+ // Broadcast NetworksChanged Event that network is connected
+ EventRouter* event_router = ExtensionSystem::Get(profile_)->event_router();
+ scoped_ptr<base::ListValue> args(api::OnNetworksChanged::Create(
+ std::vector<std::string>(1, params->network_guid)));
+ scoped_ptr<extensions::Event> netchanged_event(
+ new extensions::Event(kOnNetworksChanged, args.Pass()));
+ event_router->BroadcastEvent(netchanged_event.Pass());
+
+ // Generate NetworkListChanged event.
+ std::vector<std::string> list;
+ list.push_back("stub_wifi2");
+ list.push_back("stub_ethernet");
+ list.push_back("stub_wifi1");
+ list.push_back("stub_cellular1");
+ list.push_back("stub_vpn1");
+
+ scoped_ptr<base::ListValue> arg2(api::OnNetworkListChanged::Create(list));
+ scoped_ptr<extensions::Event> netlist_event(new extensions::Event(
+ kOnNetworkListChanged, arg2.Pass()));
+ event_router->BroadcastEvent(netlist_event.Pass());
+ }
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NetworkingPrivateStartDisconnectFunction
+
+NetworkingPrivateStartDisconnectFunction::
+ ~NetworkingPrivateStartDisconnectFunction() {
+}
+
+bool NetworkingPrivateStartDisconnectFunction::RunImpl() {
+ scoped_ptr<api::StartDisconnect::Params> params =
+ api::StartDisconnect::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(params);
+ if (params->network_guid == "nonexistent_path") {
+ error_ = "not-found";
+ SendResponse(false);
+ } else {
+ SendResponse(true);
+
+ // Send Event that network is disconnected. Listener will use GetProperties.
+ EventRouter* event_router = ExtensionSystem::Get(profile_)->event_router();
+ scoped_ptr<base::ListValue> args(api::OnNetworksChanged::Create(
+ std::vector<std::string>(1, params->network_guid)));
+ scoped_ptr<extensions::Event> extension_event(
+ new extensions::Event(kOnNetworksChanged, args.Pass()));
+ event_router->BroadcastEvent(extension_event.Pass());
+ }
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NetworkingPrivateVerifyDestinationFunction
+
+NetworkingPrivateVerifyDestinationFunction::
+ ~NetworkingPrivateVerifyDestinationFunction() {
+}
+
+bool NetworkingPrivateVerifyDestinationFunction::RunImpl() {
+ scoped_ptr<api::VerifyDestination::Params> params =
+ api::VerifyDestination::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(params);
+ SetResult(new base::FundamentalValue(true));
+ SendResponse(true);
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NetworkingPrivateVerifyAndEncryptCredentialsFunction
+
+NetworkingPrivateVerifyAndEncryptCredentialsFunction::
+ ~NetworkingPrivateVerifyAndEncryptCredentialsFunction() {
+}
+
+bool NetworkingPrivateVerifyAndEncryptCredentialsFunction::RunImpl() {
+ scoped_ptr<api::VerifyAndEncryptCredentials::Params> params =
+ api::VerifyAndEncryptCredentials::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(params);
+ SetResult(new base::StringValue("encrypted_credentials"));
+ SendResponse(true);
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NetworkingPrivateVerifyAndEncryptDataFunction
+
+NetworkingPrivateVerifyAndEncryptDataFunction::
+ ~NetworkingPrivateVerifyAndEncryptDataFunction() {
+}
+
+bool NetworkingPrivateVerifyAndEncryptDataFunction::RunImpl() {
+ scoped_ptr<api::VerifyAndEncryptData::Params> params =
+ api::VerifyAndEncryptData::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(params);
+ SetResult(new base::StringValue("encrypted_data"));
+ SendResponse(true);
+ return true;
+}
+
diff --git a/chrome/browser/chromeos/extensions/networking_private_apitest.cc b/chrome/browser/extensions/api/networking_private/networking_private_apitest.cc
similarity index 93%
rename from chrome/browser/chromeos/extensions/networking_private_apitest.cc
rename to chrome/browser/extensions/api/networking_private/networking_private_apitest.cc
index fe7093c..5ab4ef5 100644
--- a/chrome/browser/chromeos/extensions/networking_private_apitest.cc
+++ b/chrome/browser/extensions/api/networking_private/networking_private_apitest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -15,6 +15,8 @@
#include "chrome/browser/policy/policy_types.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/ui_test_utils.h"
+
+#if defined(OS_CHROMEOS)
#include "chromeos/chromeos_switches.h"
#include "chromeos/dbus/cryptohome_client.h"
#include "chromeos/dbus/dbus_thread_manager.h"
@@ -25,7 +27,7 @@
#include "chromeos/network/onc/onc_utils.h"
#include "policy/policy_constants.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
-
+#endif // OS_CHROMEOS
using testing::AnyNumber;
using testing::Return;
using testing::_;
@@ -37,19 +39,35 @@
const char kUser1ProfilePath[] = "/profile/user1/shill";
const char kUserIdStubHashSuffix[] = "-hash";
-void AssignString(std::string* out,
- DBusMethodCallStatus call_status,
- const std::string& result) {
- CHECK_EQ(call_status, DBUS_METHOD_CALL_SUCCESS);
- *out = result;
-}
-
} // namespace
class ExtensionNetworkingPrivateApiTest :
public ExtensionApiTest,
public testing::WithParamInterface<bool> {
public:
+ bool RunNetworkingSubtest(const std::string& subtest) {
+ return RunExtensionSubtest(
+ "networking", "main.html?" + subtest,
+ kFlagEnableFileAccess | kFlagLoadAsComponent);
+ }
+
+ virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
+ EXPECT_CALL(provider_, IsInitializationComplete(_))
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(provider_, RegisterPolicyDomain(_)).Times(AnyNumber());
+ policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_);
+
+ ExtensionApiTest::SetUpInProcessBrowserTestFixture();
+ }
+
+#if defined(OS_CHROMEOS)
+ static void AssignString(std::string* out,
+ DBusMethodCallStatus call_status,
+ const std::string& result) {
+ CHECK_EQ(call_status, DBUS_METHOD_CALL_SUCCESS);
+ *out = result;
+ }
+
virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
ExtensionApiTest::SetUpCommandLine(command_line);
// Whitelist the extension ID of the test extension.
@@ -68,21 +86,6 @@
command_line->AppendSwitch(::switches::kMultiProfiles);
}
- bool RunNetworkingSubtest(const std::string& subtest) {
- return RunExtensionSubtest(
- "networking", "main.html?" + subtest,
- kFlagEnableFileAccess | kFlagLoadAsComponent);
- }
-
- virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
- EXPECT_CALL(provider_, IsInitializationComplete(_))
- .WillRepeatedly(Return(true));
- EXPECT_CALL(provider_, RegisterPolicyDomain(_)).Times(AnyNumber());
- policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_);
-
- ExtensionApiTest::SetUpInProcessBrowserTestFixture();
- }
-
void InitializeSanitizedUsername() {
chromeos::UserManager* user_manager = chromeos::UserManager::Get();
chromeos::User* user = user_manager->GetActiveUser();
@@ -189,6 +192,19 @@
content::RunAllPendingInMessageLoop();
}
+#else // !defined(OS_CHROMEOS)
+ virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+ ExtensionApiTest::SetUpCommandLine(command_line);
+ // Whitelist the extension ID of the test extension.
+ command_line->AppendSwitchASCII(::switches::kWhitelistedExtensionID,
+ "epcifkihnkjgphfkloaaleeakhpmgdmn");
+ }
+
+ virtual void SetUpOnMainThread() OVERRIDE {
+ ExtensionApiTest::SetUpOnMainThread();
+ content::RunAllPendingInMessageLoop();
+ }
+#endif // OS_CHROMEOS
protected:
policy::MockConfigurationPolicyProvider provider_;
@@ -250,6 +266,7 @@
EXPECT_TRUE(RunNetworkingSubtest("setProperties")) << message_;
}
+#if defined(OS_CHROMEOS)
IN_PROC_BROWSER_TEST_P(ExtensionNetworkingPrivateApiTest,
GetManagedProperties) {
ShillServiceClient::TestInterface* service_test =
@@ -302,6 +319,7 @@
EXPECT_TRUE(RunNetworkingSubtest("getManagedProperties")) << message_;
}
+#endif // OS_CHROMEOS
IN_PROC_BROWSER_TEST_P(ExtensionNetworkingPrivateApiTest,
OnNetworksChangedEventConnect) {
@@ -340,3 +358,4 @@
testing::Bool());
} // namespace chromeos
+
diff --git a/chrome/browser/chromeos/extensions/networking_private_event_router.h b/chrome/browser/extensions/api/networking_private/networking_private_event_router.h
similarity index 84%
rename from chrome/browser/chromeos/extensions/networking_private_event_router.h
rename to chrome/browser/extensions/api/networking_private/networking_private_event_router.h
index 9173c76..011c8dd 100644
--- a/chrome/browser/chromeos/extensions/networking_private_event_router.h
+++ b/chrome/browser/extensions/api/networking_private/networking_private_event_router.h
@@ -1,9 +1,9 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_CHROMEOS_EXTENSIONS_NETWORKING_PRIVATE_EVENT_ROUTER_H_
-#define CHROME_BROWSER_CHROMEOS_EXTENSIONS_NETWORKING_PRIVATE_EVENT_ROUTER_H_
+#ifndef CHROME_BROWSER_EXTENSIONS_API_NETWORKING_PRIVATE_NETWORKING_PRIVATE_EVENT_ROUTER_H_
+#define CHROME_BROWSER_EXTENSIONS_API_NETWORKING_PRIVATE_NETWORKING_PRIVATE_EVENT_ROUTER_H_
#include "chrome/browser/extensions/event_router.h"
#include "chromeos/network/network_state_handler_observer.h"
@@ -52,4 +52,5 @@
} // namespace chromeos
-#endif // CHROME_BROWSER_CHROMEOS_EXTENSIONS_NETWORKING_PRIVATE_EVENT_ROUTER_H_
+#endif // CHROME_BROWSER_EXTENSIONS_API_NETWORKING_PRIVATE_NETWORKING_PRIVATE_EVENT_ROUTER_H_
+
diff --git a/chrome/browser/chromeos/extensions/networking_private_event_router.cc b/chrome/browser/extensions/api/networking_private/networking_private_event_router_chromeos.cc
similarity index 95%
rename from chrome/browser/chromeos/extensions/networking_private_event_router.cc
rename to chrome/browser/extensions/api/networking_private/networking_private_event_router_chromeos.cc
index 97b3b60..44d70eb 100644
--- a/chrome/browser/chromeos/extensions/networking_private_event_router.cc
+++ b/chrome/browser/extensions/api/networking_private/networking_private_event_router_chromeos.cc
@@ -1,12 +1,12 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/chromeos/extensions/networking_private_event_router.h"
+#include "chrome/browser/extensions/api/networking_private/networking_private_event_router.h"
#include "base/json/json_writer.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/chromeos/extensions/networking_private_api.h"
+#include "chrome/browser/extensions/api/networking_private/networking_private_api.h"
#include "chrome/browser/extensions/event_names.h"
#include "chrome/browser/extensions/event_router_forwarder.h"
#include "chrome/browser/extensions/extension_system.h"
@@ -139,3 +139,4 @@
}
} // namespace chromeos
+
diff --git a/chrome/browser/chromeos/extensions/networking_private_event_router_factory.cc b/chrome/browser/extensions/api/networking_private/networking_private_event_router_factory.cc
similarity index 83%
rename from chrome/browser/chromeos/extensions/networking_private_event_router_factory.cc
rename to chrome/browser/extensions/api/networking_private/networking_private_event_router_factory.cc
index 1a88b74..6814ffe 100644
--- a/chrome/browser/chromeos/extensions/networking_private_event_router_factory.cc
+++ b/chrome/browser/extensions/api/networking_private/networking_private_event_router_factory.cc
@@ -1,10 +1,10 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/chromeos/extensions/networking_private_event_router_factory.h"
+#include "chrome/browser/extensions/api/networking_private/networking_private_event_router_factory.h"
-#include "chrome/browser/chromeos/extensions/networking_private_event_router.h"
+#include "chrome/browser/extensions/api/networking_private/networking_private_event_router.h"
#include "chrome/browser/extensions/extension_system_factory.h"
#include "chrome/browser/profiles/incognito_helpers.h"
#include "chrome/browser/profiles/profile.h"
@@ -38,7 +38,11 @@
BrowserContextKeyedService*
NetworkingPrivateEventRouterFactory::BuildServiceInstanceFor(
content::BrowserContext* profile) const {
+#if defined(OS_CHROMEOS)
return new NetworkingPrivateEventRouter(static_cast<Profile*>(profile));
+#else // OS_CHROMEOS
+ return NULL;
+#endif // OS_CHROMEOS
}
content::BrowserContext*
diff --git a/chrome/browser/chromeos/extensions/networking_private_event_router_factory.h b/chrome/browser/extensions/api/networking_private/networking_private_event_router_factory.h
similarity index 81%
rename from chrome/browser/chromeos/extensions/networking_private_event_router_factory.h
rename to chrome/browser/extensions/api/networking_private/networking_private_event_router_factory.h
index 0208904..bcd2eba 100644
--- a/chrome/browser/chromeos/extensions/networking_private_event_router_factory.h
+++ b/chrome/browser/extensions/api/networking_private/networking_private_event_router_factory.h
@@ -1,9 +1,9 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_CHROMEOS_EXTENSIONS_NETWORKING_PRIVATE_EVENT_ROUTER_FACTORY_H_
-#define CHROME_BROWSER_CHROMEOS_EXTENSIONS_NETWORKING_PRIVATE_EVENT_ROUTER_FACTORY_H_
+#ifndef CHROME_BROWSER_EXTENSIONS_API_NETWORKING_PRIVATE_NETWORKING_PRIVATE_EVENT_ROUTER_FACTORY_H_
+#define CHROME_BROWSER_EXTENSIONS_API_NETWORKING_PRIVATE_NETWORKING_PRIVATE_EVENT_ROUTER_FACTORY_H_
#include "base/memory/singleton.h"
#include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h"
@@ -49,4 +49,5 @@
} // namespace chromeos
-#endif // CHROME_BROWSER_CHROMEOS_EXTENSIONS_NETWORKING_PRIVATE_EVENT_ROUTER_FACTORY_H_
+#endif // CHROME_BROWSER_EXTENSIONS_API_NETWORKING_PRIVATE_NETWORKING_PRIVATE_EVENT_ROUTER_FACTORY_H_
+
diff --git a/chrome/browser/extensions/app_process_apitest.cc b/chrome/browser/extensions/app_process_apitest.cc
index ee5a829..a1c30b5 100644
--- a/chrome/browser/extensions/app_process_apitest.cc
+++ b/chrome/browser/extensions/app_process_apitest.cc
@@ -10,6 +10,7 @@
#include "chrome/browser/extensions/process_map.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/blocked_content/blocked_content_tab_helper.h"
+#include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_finder.h"
@@ -656,20 +657,28 @@
LoadExtension(test_data_dir_.AppendASCII("app_process"));
ASSERT_TRUE(app);
- content::WindowedNotificationObserver blocker_observer(
- chrome::NOTIFICATION_CONTENT_BLOCKED_STATE_CHANGED,
- content::NotificationService::AllSources());
ui_test_utils::NavigateToURL(
browser(), GetTestBaseURL("app_process").Resolve("path3/container.html"));
- blocker_observer.Wait();
-
WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
BlockedContentTabHelper* blocked_content_tab_helper =
BlockedContentTabHelper::FromWebContents(tab);
- std::vector<WebContents*> blocked_contents;
- blocked_content_tab_helper->GetBlockedContents(&blocked_contents);
- EXPECT_EQ(blocked_contents.size(), 1u);
+ PopupBlockerTabHelper* popup_blocker_tab_helper =
+ PopupBlockerTabHelper::FromWebContents(tab);
+ if (!blocked_content_tab_helper->GetBlockedContentsCount() &&
+ (!popup_blocker_tab_helper ||
+ !popup_blocker_tab_helper->GetBlockedPopupsCount())) {
+ content::WindowedNotificationObserver observer(
+ chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
+ content::NotificationService::AllSources());
+ observer.Wait();
+ }
+
+ EXPECT_EQ(1u,
+ blocked_content_tab_helper->GetBlockedContentsCount() +
+ (popup_blocker_tab_helper
+ ? popup_blocker_tab_helper->GetBlockedPopupsCount()
+ : 0));
}
// Tests that if an extension launches an app via chrome.tabs.create with an URL
diff --git a/chrome/browser/extensions/data_deleter.cc b/chrome/browser/extensions/data_deleter.cc
index 8c8fe4f..46518b0 100644
--- a/chrome/browser/extensions/data_deleter.cc
+++ b/chrome/browser/extensions/data_deleter.cc
@@ -41,19 +41,16 @@
// preserve this code path without checking for isolation because it's
// simpler than special casing. This code should go away once we merge
// the various URLRequestContexts (http://crbug.com/159193).
- partition->ClearDataForOrigin(
- content::StoragePartition::REMOVE_DATA_MASK_ALL,
+ partition->AsyncClearDataForOrigin(
content::StoragePartition::kAllStorage,
storage_origin,
profile->GetRequestContextForExtensions());
} else {
// We don't need to worry about the media request context because that
// shares the same cookie store as the main request context.
- partition->ClearDataForOrigin(
- content::StoragePartition::REMOVE_DATA_MASK_ALL,
- content::StoragePartition::kAllStorage,
- storage_origin,
- partition->GetURLRequestContext());
+ partition->AsyncClearDataForOrigin(content::StoragePartition::kAllStorage,
+ storage_origin,
+ partition->GetURLRequestContext());
}
// Begin removal of the settings for the current extension.
diff --git a/chrome/browser/extensions/external_loader.h b/chrome/browser/extensions/external_loader.h
index 86ffee3..ecadda0 100644
--- a/chrome/browser/extensions/external_loader.h
+++ b/chrome/browser/extensions/external_loader.h
@@ -55,7 +55,7 @@
virtual ~ExternalLoader();
// Notifies the provider that the list of extensions has been loaded.
- void LoadFinished();
+ virtual void LoadFinished();
// Used for passing the list of extensions from the method that loads them
// to |LoadFinished|. To ensure thread safety, the rules are the following:
diff --git a/chrome/browser/extensions/external_pref_loader.h b/chrome/browser/extensions/external_pref_loader.h
index 49b0ce9..c06dd35 100644
--- a/chrome/browser/extensions/external_pref_loader.h
+++ b/chrome/browser/extensions/external_pref_loader.h
@@ -38,6 +38,8 @@
virtual const base::FilePath GetBaseCrxFilePath() OVERRIDE;
protected:
+ virtual ~ExternalPrefLoader() {}
+
virtual void StartLoading() OVERRIDE;
bool IsOptionSet(Options option) {
return (options_ & option) != 0;
@@ -46,8 +48,6 @@
private:
friend class base::RefCountedThreadSafe<ExternalLoader>;
- virtual ~ExternalPrefLoader() {}
-
// Actually searches for and loads candidate standalone extension preference
// files in the path corresponding to |base_path_id|.
// Must be called on the file thread.
diff --git a/chrome/browser/extensions/external_provider_impl.cc b/chrome/browser/extensions/external_provider_impl.cc
index b5f3dc5..677f447 100644
--- a/chrome/browser/extensions/external_provider_impl.cc
+++ b/chrome/browser/extensions/external_provider_impl.cc
@@ -39,6 +39,7 @@
#endif
#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/extensions/external_pref_cache_loader.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/policy/app_pack_updater.h"
#include "chrome/browser/policy/browser_policy_connector.h"
@@ -394,13 +395,19 @@
external_apps_path_id = chrome::DIR_MANAGED_USERS_DEFAULT_APPS;
#endif
+#if defined(OS_CHROMEOS)
+ typedef chromeos::ExternalPrefCacheLoader PrefLoader;
+#else
+ typedef ExternalPrefLoader PrefLoader;
+#endif
+
if (!is_chromeos_demo_session) {
provider_list->push_back(
linked_ptr<ExternalProviderInterface>(
new ExternalProviderImpl(
service,
- new ExternalPrefLoader(external_apps_path_id,
- check_admin_permissions_on_mac),
+ new PrefLoader(external_apps_path_id,
+ check_admin_permissions_on_mac),
profile,
Manifest::EXTERNAL_PREF,
Manifest::EXTERNAL_PREF_DOWNLOAD,
diff --git a/chrome/browser/feedback/feedback_util.cc b/chrome/browser/feedback/feedback_util.cc
index 8095fad..738bf9e 100644
--- a/chrome/browser/feedback/feedback_util.cc
+++ b/chrome/browser/feedback/feedback_util.cc
@@ -38,17 +38,15 @@
#include "net/url_request/url_fetcher_delegate.h"
#include "net/url_request/url_request_status.h"
#include "third_party/icu/source/common/unicode/locid.h"
+#include "third_party/zlib/google/zip.h"
#include "ui/base/l10n/l10n_util.h"
#include "url/gurl.h"
-#if defined(OS_CHROMEOS)
-#include "third_party/zlib/google/zip.h"
-#endif
-
using content::WebContents;
namespace {
-const char kLogsFilename[] = "system_logs.txt";
+const base::FilePath::CharType kLogsFilename[] =
+ FILE_PATH_LITERAL("system_logs.txt");
}
namespace chrome {
@@ -434,7 +432,6 @@
screen_size = rect;
}
-#if defined(OS_CHROMEOS)
// static
bool FeedbackUtil::ZipString(const std::string& logs,
std::string* compressed_logs) {
@@ -443,10 +440,10 @@
// Create a temporary directory, put the logs into a file in it. Create
// another temporary file to receive the zip file in.
- if (!file_util::CreateNewTempDirectory("", &temp_path))
+ if (!file_util::CreateNewTempDirectory(FILE_PATH_LITERAL(""), &temp_path))
return false;
- if (file_util::WriteFile(
- temp_path.Append(kLogsFilename), logs.c_str(), logs.size()) == -1)
+ if (file_util::WriteFile(temp_path.Append(kLogsFilename),
+ logs.c_str(), logs.size()) == -1)
return false;
if (!file_util::CreateTemporaryFile(&zip_file))
return false;
@@ -459,5 +456,3 @@
return true;
}
-#endif // OS_CHROMEOS
-
diff --git a/chrome/browser/feedback/feedback_util.h b/chrome/browser/feedback/feedback_util.h
index 163317d..7849186 100644
--- a/chrome/browser/feedback/feedback_util.h
+++ b/chrome/browser/feedback/feedback_util.h
@@ -76,9 +76,7 @@
static void ClearScreenshotPng();
static void SetScreenshotSize(const gfx::Rect& rect);
static gfx::Rect& GetScreenshotSize();
-#if defined(OS_CHROMEOS)
static bool ZipString(const std::string& logs, std::string* compressed_logs);
-#endif
class PostCleanup;
diff --git a/chrome/browser/feedback/tracing_manager.cc b/chrome/browser/feedback/tracing_manager.cc
new file mode 100644
index 0000000..3ea14cf
--- /dev/null
+++ b/chrome/browser/feedback/tracing_manager.cc
@@ -0,0 +1,135 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/feedback/tracing_manager.h"
+
+#include "base/bind.h"
+#include "base/prefs/pref_service.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/feedback/feedback_util.h"
+#include "chrome/common/pref_names.h"
+#include "content/public/browser/trace_controller.h"
+
+namespace {
+// Only once trace manager can exist at a time.
+TracingManager* g_tracing_manager = NULL;
+// Trace IDs start at 1 and increase.
+int g_next_trace_id = 1;
+}
+
+TracingManager::TracingManager()
+ : current_trace_id_(0),
+ weak_ptr_factory_(this) {
+ DCHECK(!g_tracing_manager);
+ g_tracing_manager = this;
+ StartTracing();
+}
+
+TracingManager::~TracingManager() {
+ DCHECK(g_tracing_manager == this);
+ g_tracing_manager = NULL;
+}
+
+int TracingManager::RequestTrace() {
+ // Return the current trace if one is being collected.
+ if (current_trace_id_)
+ return current_trace_id_;
+
+ current_trace_id_ = g_next_trace_id;
+ ++g_next_trace_id;
+ content::TraceController::GetInstance()->EndTracingAsync(this);
+ return current_trace_id_;
+}
+
+bool TracingManager::GetTraceData(int id, const TraceDataCallback& callback) {
+ // If a trace is being collected currently, send it via callback when
+ // complete.
+ if (current_trace_id_) {
+ // Only allow one trace data request at a time.
+ if (trace_callback_.is_null()) {
+ trace_callback_ = callback;
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ std::map<int, scoped_refptr<base::RefCountedString> >::iterator data =
+ trace_data_.find(id);
+ if (data == trace_data_.end())
+ return false;
+
+ // Always return the data asychronously, so the behavior is consistant.
+ base::MessageLoopProxy::current()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, data->second));
+ return true;
+ }
+}
+
+void TracingManager::DiscardTraceData(int id) {
+ trace_data_.erase(id);
+
+ // If the trace is discarded before it is complete, clean up the accumulators.
+ if (id == current_trace_id_) {
+ current_trace_id_ = 0;
+ data_ = "";
+
+ // If the trace has already been requested, provide an empty string.
+ if (!trace_callback_.is_null()) {
+ trace_callback_.Run(scoped_refptr<base::RefCountedString>());
+ trace_callback_.Reset();
+ }
+ }
+}
+
+void TracingManager::StartTracing() {
+ content::TraceController::GetInstance()->BeginTracing(
+ this, "-test_*",
+ base::debug::TraceLog::RECORD_CONTINUOUSLY);
+}
+
+void TracingManager::OnEndTracingComplete() {
+ if (!current_trace_id_)
+ return;
+
+ std::string output_val;
+ FeedbackUtil::ZipString(data_, &output_val);
+
+ scoped_refptr<base::RefCountedString> output;
+ output->TakeString(&output_val);
+
+ trace_data_[current_trace_id_] = output;
+
+ if (!trace_callback_.is_null()) {
+ trace_callback_.Run(output);
+ trace_callback_.Reset();
+ }
+
+ current_trace_id_ = 0;
+ data_ = "";
+
+ // Tracing has to be restarted asynchronous, so the TracingController can
+ // clean up.
+ base::MessageLoopProxy::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&TracingManager::StartTracing,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void TracingManager::OnTraceDataCollected(
+ const scoped_refptr<base::RefCountedString>& trace_fragment) {
+ if (current_trace_id_)
+ data_ += trace_fragment->data();
+}
+
+// static
+scoped_ptr<TracingManager> TracingManager::Create() {
+ if (g_tracing_manager)
+ return scoped_ptr<TracingManager>();
+ return scoped_ptr<TracingManager>(new TracingManager());
+}
+
+TracingManager* TracingManager::Get() {
+ return g_tracing_manager;
+}
diff --git a/chrome/browser/feedback/tracing_manager.h b/chrome/browser/feedback/tracing_manager.h
new file mode 100644
index 0000000..c70206a
--- /dev/null
+++ b/chrome/browser/feedback/tracing_manager.h
@@ -0,0 +1,80 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_FEEDBACK_TRACING_MANAGER_H_
+#define CHROME_BROWSER_FEEDBACK_TRACING_MANAGER_H_
+
+#include <map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "content/public/browser/trace_subscriber.h"
+
+// Callback used for getting the output of a trace.
+typedef base::Callback<void(scoped_refptr<base::RefCountedString> trace_data)>
+ TraceDataCallback;
+
+// This class is used to manage performance meterics that can be attached to
+// feedback reports. This class is a Singleton that is owned by the preference
+// system. It should only be created when it is enabled, and should only be
+// accessed elsewhere via Get().
+//
+// When a performance trace is desired, TracingManager::Get()->RequestTrace()
+// should be invoked. The TracingManager will then start preparing a zipped
+// version of the performance data. That data can then be requested via
+// GetTraceData(). When the data is no longer needed, it should be discarded
+// via DiscardTraceData().
+class TracingManager : public content::TraceSubscriber {
+ public:
+ virtual ~TracingManager();
+
+ // Create a TracingManager. Can only be called when none exists.
+ static scoped_ptr<TracingManager> Create();
+
+ // Get the current TracingManager. Returns NULL if one doesn't exist.
+ static TracingManager* Get();
+
+ // Request a trace ending at the current time. If a trace is already being
+ // collected, the id for that trace is returned.
+ int RequestTrace();
+
+ // Get the trace data for |id|. On success, true is returned, and the data is
+ // returned via |callback|. Returns false on failure.
+ bool GetTraceData(int id, const TraceDataCallback& callback);
+
+ // Discard the data for trace |id|.
+ void DiscardTraceData(int id);
+
+ private:
+ void StartTracing();
+
+ // content::TraceSubscriber overrides
+ virtual void OnEndTracingComplete() OVERRIDE;
+ virtual void OnTraceDataCollected(
+ const scoped_refptr<base::RefCountedString>& trace_fragment) OVERRIDE;
+
+ TracingManager();
+
+ // Data being collected from the current trace.
+ std::string data_;
+
+ // ID of the trace that is being collected.
+ int current_trace_id_;
+
+ // Mapping of trace ID to trace data.
+ std::map<int, scoped_refptr<base::RefCountedString> > trace_data_;
+
+ // Callback for the current trace request.
+ TraceDataCallback trace_callback_;
+
+ base::WeakPtrFactory<TracingManager> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(TracingManager);
+};
+
+#endif // CHROME_BROWSER_FEEDBACK_TRACING_MANAGER_H_
+
diff --git a/chrome/browser/google_apis/DEPS b/chrome/browser/google_apis/DEPS
index 214c501..20ee665 100644
--- a/chrome/browser/google_apis/DEPS
+++ b/chrome/browser/google_apis/DEPS
@@ -8,14 +8,9 @@
specific_include_rules = {
# AuthService should be gone. crbug.com/162157
"auth_service\.(h|cc)": [
- "!chrome/browser/chrome_notification_types.h",
"!chrome/browser/profiles/profile.h",
- "!chrome/browser/signin/token_service_factory.h",
- "!chrome/browser/signin/token_service.h",
- "!content/public/browser/notification_details.h",
- "!content/public/browser/notification_observer.h",
- "!content/public/browser/notification_registrar.h",
- "!content/public/browser/notification_source.h",
- "!content/public/browser/notification_types.h",
+ "!chrome/browser/signin/oauth2_token_service.h",
+ "!chrome/browser/signin/profile_oauth2_token_service.h",
+ "!chrome/browser/signin/profile_oauth2_token_service_factory.h",
],
}
diff --git a/chrome/browser/google_apis/auth_service.cc b/chrome/browser/google_apis/auth_service.cc
index 7d2017a..195848b 100644
--- a/chrome/browser/google_apis/auth_service.cc
+++ b/chrome/browser/google_apis/auth_service.cc
@@ -8,20 +8,16 @@
#include <vector>
#include "base/bind.h"
+#include "base/location.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/metrics/histogram.h"
-#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/google_apis/auth_service_observer.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/signin/token_service.h"
-#include "chrome/browser/signin/token_service_factory.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_source.h"
-#include "content/public/browser/notification_types.h"
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
#include "google_apis/gaia/gaia_constants.h"
#include "google_apis/gaia/gaia_urls.h"
#include "google_apis/gaia/google_service_auth_error.h"
-#include "google_apis/gaia/oauth2_access_token_fetcher.h"
#if defined(OS_CHROMEOS)
#include "chromeos/login/login_state.h"
@@ -39,62 +35,49 @@
const int kSuccessRatioHistogramTemporaryFailure = 3;
const int kSuccessRatioHistogramMaxValue = 4; // The max value is exclusive.
-} // namespace
-
// OAuth2 authorization token retrieval request.
-class AuthRequest : public OAuth2AccessTokenConsumer {
+class AuthRequest : public OAuth2TokenService::Consumer {
public:
- AuthRequest(net::URLRequestContextGetter* url_request_context_getter,
+ AuthRequest(Profile* profile,
+ net::URLRequestContextGetter* url_request_context_getter,
const AuthStatusCallback& callback,
- const std::vector<std::string>& scopes,
- const std::string& refresh_token);
+ const std::vector<std::string>& scopes);
virtual ~AuthRequest();
- void Start();
-
- // Overridden from OAuth2AccessTokenConsumer:
- virtual void OnGetTokenSuccess(const std::string& access_token,
- const base::Time& expiration_time) OVERRIDE;
- virtual void OnGetTokenFailure(const GoogleServiceAuthError& error) OVERRIDE;
private:
- net::URLRequestContextGetter* url_request_context_getter_;
- std::string refresh_token_;
+ // Overridden from OAuth2TokenService::Consumer:
+ virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
+ const std::string& access_token,
+ const base::Time& expiration_time) OVERRIDE;
+ virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
+ const GoogleServiceAuthError& error) OVERRIDE;
+
AuthStatusCallback callback_;
- std::vector<std::string> scopes_;
- scoped_ptr<OAuth2AccessTokenFetcher> oauth2_access_token_fetcher_;
+ OAuth2TokenService::ScopeSet scopes_;
+ scoped_ptr<OAuth2TokenService::Request> request_;
base::ThreadChecker thread_checker_;
DISALLOW_COPY_AND_ASSIGN(AuthRequest);
};
AuthRequest::AuthRequest(
+ Profile* profile,
net::URLRequestContextGetter* url_request_context_getter,
const AuthStatusCallback& callback,
- const std::vector<std::string>& scopes,
- const std::string& refresh_token)
- : url_request_context_getter_(url_request_context_getter),
- refresh_token_(refresh_token),
- callback_(callback),
- scopes_(scopes) {
+ const std::vector<std::string>& scopes)
+ : callback_(callback),
+ scopes_(scopes.begin(), scopes.end()) {
DCHECK(!callback_.is_null());
+ request_ = ProfileOAuth2TokenServiceFactory::GetForProfile(profile)->
+ StartRequestWithContext(url_request_context_getter, scopes_, this);
}
AuthRequest::~AuthRequest() {}
-void AuthRequest::Start() {
- DCHECK(!refresh_token_.empty());
- oauth2_access_token_fetcher_.reset(new OAuth2AccessTokenFetcher(
- this, url_request_context_getter_));
- oauth2_access_token_fetcher_->Start(
- GaiaUrls::GetInstance()->oauth2_chrome_client_id(),
- GaiaUrls::GetInstance()->oauth2_chrome_client_secret(),
- refresh_token_,
- scopes_);
-}
-
// Callback for OAuth2AccessTokenFetcher on success. |access_token| is the token
// used to start fetching user data.
-void AuthRequest::OnGetTokenSuccess(const std::string& access_token,
+void AuthRequest::OnGetTokenSuccess(const OAuth2TokenService::Request* request,
+ const std::string& access_token,
const base::Time& expiration_time) {
DCHECK(thread_checker_.CalledOnValidThread());
@@ -107,7 +90,8 @@
}
// Callback for OAuth2AccessTokenFetcher on failure.
-void AuthRequest::OnGetTokenFailure(const GoogleServiceAuthError& error) {
+void AuthRequest::OnGetTokenFailure(const OAuth2TokenService::Request* request,
+ const GoogleServiceAuthError& error) {
DCHECK(thread_checker_.CalledOnValidThread());
LOG(WARNING) << "AuthRequest: token request using refresh token failed: "
@@ -137,6 +121,8 @@
delete this;
}
+} // namespace
+
AuthService::AuthService(
Profile* profile,
net::URLRequestContextGetter* url_request_context_getter,
@@ -146,19 +132,19 @@
scopes_(scopes),
weak_ptr_factory_(this) {
DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(profile);
// Get OAuth2 refresh token (if we have any) and register for its updates.
- TokenService* service = TokenServiceFactory::GetForProfile(profile_);
- refresh_token_ = service->GetOAuth2LoginRefreshToken();
- registrar_.Add(this,
- chrome::NOTIFICATION_TOKEN_AVAILABLE,
- content::Source<TokenService>(service));
- registrar_.Add(this,
- chrome::NOTIFICATION_TOKEN_REQUEST_FAILED,
- content::Source<TokenService>(service));
+ OAuth2TokenService* service =
+ ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
+ service->AddObserver(this);
+ has_refresh_token_ = service->RefreshTokenIsAvailable();
}
AuthService::~AuthService() {
+ OAuth2TokenService* service =
+ ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
+ service->RemoveObserver(this);
}
void AuthService::StartAuthentication(const AuthStatusCallback& callback) {
@@ -172,12 +158,12 @@
base::Bind(callback, HTTP_SUCCESS, access_token_));
} else if (HasRefreshToken()) {
// We have refresh token, let's get an access token.
- (new AuthRequest(url_request_context_getter_,
- base::Bind(&AuthService::OnAuthCompleted,
- weak_ptr_factory_.GetWeakPtr(),
- callback),
- scopes_,
- refresh_token_))->Start();
+ new AuthRequest(profile_,
+ url_request_context_getter_,
+ base::Bind(&AuthService::OnAuthCompleted,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback),
+ scopes_);
} else {
relay_proxy->PostTask(FROM_HERE,
base::Bind(callback, GDATA_NOT_READY, std::string()));
@@ -189,7 +175,7 @@
}
bool AuthService::HasRefreshToken() const {
- return !refresh_token_.empty();
+ return has_refresh_token_;
}
const std::string& AuthService::access_token() const {
@@ -201,7 +187,7 @@
}
void AuthService::ClearRefreshToken() {
- refresh_token_.clear();
+ has_refresh_token_ = false;
FOR_EACH_OBSERVER(AuthServiceObserver,
observers_,
@@ -239,24 +225,19 @@
observers_.RemoveObserver(observer);
}
-void AuthService::Observe(int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) {
- DCHECK(type == chrome::NOTIFICATION_TOKEN_AVAILABLE ||
- type == chrome::NOTIFICATION_TOKEN_REQUEST_FAILED);
+void AuthService::OnRefreshTokenAvailable(const std::string& account_id) {
+ OnHandleRefreshToken(true);
+}
- TokenService::TokenAvailableDetails* token_details =
- content::Details<TokenService::TokenAvailableDetails>(details).ptr();
- if (token_details->service() != GaiaConstants::kGaiaOAuth2LoginRefreshToken)
- return;
+void AuthService::OnRefreshTokenRevoked(const std::string& account_id,
+ const GoogleServiceAuthError& error) {
+ OnHandleRefreshToken(false);
+}
+void AuthService::OnHandleRefreshToken(bool has_refresh_token) {
access_token_.clear();
- if (type == chrome::NOTIFICATION_TOKEN_AVAILABLE) {
- TokenService* service = TokenServiceFactory::GetForProfile(profile_);
- refresh_token_ = service->GetOAuth2LoginRefreshToken();
- } else {
- refresh_token_.clear();
- }
+ has_refresh_token_ = has_refresh_token;
+
FOR_EACH_OBSERVER(AuthServiceObserver,
observers_,
OnOAuth2RefreshTokenChanged());
diff --git a/chrome/browser/google_apis/auth_service.h b/chrome/browser/google_apis/auth_service.h
index a5647a7..4c92ab1 100644
--- a/chrome/browser/google_apis/auth_service.h
+++ b/chrome/browser/google_apis/auth_service.h
@@ -12,9 +12,7 @@
#include "base/observer_list.h"
#include "base/threading/thread_checker.h"
#include "chrome/browser/google_apis/auth_service_interface.h"
-#include "chrome/browser/google_apis/gdata_errorcode.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
+#include "chrome/browser/signin/oauth2_token_service.h"
class Profile;
@@ -31,7 +29,7 @@
// (TokenService) and provides OAuth2 token refresh infrastructure.
// All public functions must be called on UI thread.
class AuthService : public AuthServiceInterface,
- public content::NotificationObserver {
+ public OAuth2TokenService::Observer {
public:
// |url_request_context_getter| is used to perform authentication with
// URLFetcher.
@@ -52,10 +50,11 @@
virtual void ClearAccessToken() OVERRIDE;
virtual void ClearRefreshToken() OVERRIDE;
- // Overridden from content::NotificationObserver:
- virtual void Observe(int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) OVERRIDE;
+ // Overridden from OAuth2TokenService::Observer:
+ virtual void OnRefreshTokenAvailable(const std::string& account_id) OVERRIDE;
+ virtual void OnRefreshTokenRevoked(
+ const std::string& account_id,
+ const GoogleServiceAuthError& error) OVERRIDE;
// Sets the access_token as specified. This should be used only for testing.
void set_access_token_for_testing(const std::string& token) {
@@ -68,6 +67,9 @@
static bool CanAuthenticate(Profile* profile);
private:
+ // Called when the state of the refresh token changes.
+ void OnHandleRefreshToken(bool has_refresh_token);
+
// Called when authentication request from StartAuthentication() is
// completed.
void OnAuthCompleted(const AuthStatusCallback& callback,
@@ -76,14 +78,12 @@
Profile* profile_;
net::URLRequestContextGetter* url_request_context_getter_; // Not owned.
- std::string refresh_token_;
+ bool has_refresh_token_;
std::string access_token_;
std::vector<std::string> scopes_;
ObserverList<AuthServiceObserver> observers_;
base::ThreadChecker thread_checker_;
- content::NotificationRegistrar registrar_;
-
// Note: This should remain the last member so it'll be destroyed and
// invalidate its weak pointers before any other members are destroyed.
base::WeakPtrFactory<AuthService> weak_ptr_factory_;
diff --git a/chrome/browser/guestview/webview/webview_constants.cc b/chrome/browser/guestview/webview/webview_constants.cc
index b80b635..2611a7d 100644
--- a/chrome/browser/guestview/webview/webview_constants.cc
+++ b/chrome/browser/guestview/webview/webview_constants.cc
@@ -16,6 +16,8 @@
const char kEventLoadRedirect[] = "webview.onLoadRedirect";
const char kEventLoadStart[] = "webview.onLoadStart";
const char kEventLoadStop[] = "webview.onLoadStop";
+const char kEventResponsive[] = "webview.onResponsive";
+const char kEventUnresponsive[] = "webview.onUnresponsive";
// Parameters/properties on events.
const char kLevel[] = "level";
diff --git a/chrome/browser/guestview/webview/webview_constants.h b/chrome/browser/guestview/webview/webview_constants.h
index e8ce5a4..59532f2 100644
--- a/chrome/browser/guestview/webview/webview_constants.h
+++ b/chrome/browser/guestview/webview/webview_constants.h
@@ -19,11 +19,13 @@
extern const char kEventLoadRedirect[];
extern const char kEventLoadStart[];
extern const char kEventLoadStop[];
+extern const char kEventResponsive[];
+extern const char kEventUnresponsive[];
// Parameters/properties on events.
-extern const char kMessage[];
extern const char kLevel[];
extern const char kLine[];
+extern const char kMessage[];
extern const char kNewURL[];
extern const char kOldURL[];
extern const char kProcessId[];
@@ -35,8 +37,6 @@
extern const char kInternalEntryCount[];
extern const char kInternalProcessId[];
-// Parameters/properties on events.
-
} // namespace webview
#endif // CHROME_BROWSER_GUESTVIEW_WEBVIEW_WEBVIEW_CONSTANTS_H_
diff --git a/chrome/browser/guestview/webview/webview_guest.cc b/chrome/browser/guestview/webview/webview_guest.cc
index 71a4e6c..9bd9389 100644
--- a/chrome/browser/guestview/webview/webview_guest.cc
+++ b/chrome/browser/guestview/webview/webview_guest.cc
@@ -160,6 +160,22 @@
return false;
}
+// TODO(fsamuel): Find a reliable way to test the 'responsive' and
+// 'unresponsive' events.
+void WebViewGuest::RendererResponsive() {
+ scoped_ptr<DictionaryValue> args(new DictionaryValue());
+ args->SetInteger(webview::kProcessId,
+ guest_web_contents()->GetRenderProcessHost()->GetID());
+ DispatchEvent(new GuestView::Event(webview::kEventResponsive, args.Pass()));
+}
+
+void WebViewGuest::RendererUnresponsive() {
+ scoped_ptr<DictionaryValue> args(new DictionaryValue());
+ args->SetInteger(webview::kProcessId,
+ guest_web_contents()->GetRenderProcessHost()->GetID());
+ DispatchEvent(new GuestView::Event(webview::kEventUnresponsive, args.Pass()));
+}
+
void WebViewGuest::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
diff --git a/chrome/browser/guestview/webview/webview_guest.h b/chrome/browser/guestview/webview/webview_guest.h
index 5f63ecd..a13e306 100644
--- a/chrome/browser/guestview/webview/webview_guest.h
+++ b/chrome/browser/guestview/webview/webview_guest.h
@@ -48,6 +48,8 @@
virtual void GuestProcessGone(base::TerminationStatus status) OVERRIDE;
virtual bool HandleKeyboardEvent(
const content::NativeWebKeyboardEvent& event) OVERRIDE;
+ virtual void RendererResponsive() OVERRIDE;
+ virtual void RendererUnresponsive() OVERRIDE;
// NotificationObserver implementation.
virtual void Observe(int type,
diff --git a/chrome/browser/media/webrtc_browsertest_common.cc b/chrome/browser/media/webrtc_browsertest_common.cc
index 83c24fc..cf067b6 100644
--- a/chrome/browser/media/webrtc_browsertest_common.cc
+++ b/chrome/browser/media/webrtc_browsertest_common.cc
@@ -6,7 +6,6 @@
#include "base/file_util.h"
#include "base/path_service.h"
-#include "base/process_util.h"
#include "base/strings/stringprintf.h"
#include "base/test/test_timeouts.h"
#include "base/time/time.h"
diff --git a/chrome/browser/memory_details_android.cc b/chrome/browser/memory_details_android.cc
index 9be87ae..fab8422 100644
--- a/chrome/browser/memory_details_android.cc
+++ b/chrome/browser/memory_details_android.cc
@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "base/memory/scoped_ptr.h"
+#include "base/process/process_iterator.h"
#include "chrome/common/chrome_constants.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/process_type.h"
diff --git a/chrome/browser/metrics/thread_watcher.cc b/chrome/browser/metrics/thread_watcher.cc
index 54e26c7..c8ee4cf 100644
--- a/chrome/browser/metrics/thread_watcher.cc
+++ b/chrome/browser/metrics/thread_watcher.cc
@@ -411,7 +411,7 @@
// static
const int ThreadWatcherList::kUnresponsiveSeconds = 2;
// static
-const int ThreadWatcherList::kUnresponsiveCount = 7;
+const int ThreadWatcherList::kUnresponsiveCount = 9;
// static
const int ThreadWatcherList::kLiveThreadsThreshold = 2;
diff --git a/chrome/browser/net/net_error_tab_helper.cc b/chrome/browser/net/net_error_tab_helper.cc
index 6f20a8a..c441c2c 100644
--- a/chrome/browser/net/net_error_tab_helper.cc
+++ b/chrome/browser/net/net_error_tab_helper.cc
@@ -143,7 +143,7 @@
dns_error_active_(false),
dns_error_page_committed_(false),
dns_probe_status_(chrome_common_net::DNS_PROBE_POSSIBLE),
- enabled_by_trial_(chrome_common_net::DnsProbesEnabledByFieldTrial()) {
+ probes_enabled_(chrome_common_net::DnsProbesEnabled()) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
// If this helper is under test, it won't have a WebContents.
@@ -208,7 +208,7 @@
return testing_state_ == TESTING_FORCE_ENABLED;
// TODO(ttuttle): Disable on mobile?
- return enabled_by_trial_ && *resolve_errors_with_web_service_;
+ return probes_enabled_ && *resolve_errors_with_web_service_;
}
void NetErrorTabHelper::SendInfo() {
diff --git a/chrome/browser/net/net_error_tab_helper.h b/chrome/browser/net/net_error_tab_helper.h
index fd0553e..2a38e0c 100644
--- a/chrome/browser/net/net_error_tab_helper.h
+++ b/chrome/browser/net/net_error_tab_helper.h
@@ -108,8 +108,8 @@
// navigations), it re-sends the status whenever an error page commits.
chrome_common_net::DnsProbeStatus dns_probe_status_;
- // Whether we are enabled to run by the DnsProbe-Enable field trial.
- const bool enabled_by_trial_;
+ // Whether probes are enabled (by the command-line option or the field trial).
+ const bool probes_enabled_;
// Optional callback for browser test to snoop on outgoing NetErrorInfo IPCs.
DnsProbeStatusSnoopCallback dns_probe_status_snoop_callback_;
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service.cc b/chrome/browser/policy/cloud/user_policy_signin_service.cc
index 4091e32..2baff3d 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service.cc
@@ -20,6 +20,7 @@
#include "chrome/browser/signin/token_service_factory.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_source.h"
#include "google_apis/gaia/gaia_constants.h"
#if defined(ENABLE_MANAGED_USERS)
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_base.cc b/chrome/browser/policy/cloud/user_policy_signin_service_base.cc
index d530557..2b78d89 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_base.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_base.cc
@@ -18,6 +18,7 @@
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
+#include "content/public/browser/notification_source.h"
namespace policy {
diff --git a/chrome/browser/prerender/prerender_local_predictor.cc b/chrome/browser/prerender/prerender_local_predictor.cc
index 93525f6..520dc22 100644
--- a/chrome/browser/prerender/prerender_local_predictor.cc
+++ b/chrome/browser/prerender/prerender_local_predictor.cc
@@ -198,6 +198,10 @@
return (transition & content::PAGE_TRANSITION_CHAIN_END) == 0;
}
+bool IsFormSubmit(PageTransition transition) {
+ return (transition & content::PAGE_TRANSITION_FORM_SUBMIT) != 0;
+}
+
bool ShouldExcludeTransitionForPrediction(PageTransition transition) {
return IsBackForward(transition) || IsHomePage(transition) ||
IsIntermediateRedirect(transition);
@@ -441,7 +445,8 @@
if (!last_visited.is_null() &&
last_visited > visits[i].time - max_age &&
last_visited < visits[i].time - min_age) {
- next_urls_currently_found.insert(visits[i].url_id);
+ if (!IsFormSubmit(visits[i].transition))
+ next_urls_currently_found.insert(visits[i].url_id);
}
}
if (i == static_cast<int>(visits.size()) - 1 ||
@@ -715,6 +720,7 @@
PrerenderProperties* prerender_properties = NULL;
for (int i = 0; i < static_cast<int>(info->candidate_urls_.size()); i++) {
+ RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_EXAMINE_NEXT_URL);
url_info.reset(new LocalPredictorURLInfo(info->candidate_urls_[i]));
// We need to check whether we can issue a prerender for this URL.
@@ -813,11 +819,13 @@
p->prerender_handle.get())) {
new_prerender_handle->OnCancel();
new_prerender_handle.reset(NULL);
+ RecordEvent(EVENT_ISSUE_PRERENDER_ALREADY_PRERENDERING);
break;
}
}
if (new_prerender_handle.get()) {
+ RecordEvent(EVENT_ISSUE_PRERENDER_NEW_PRERENDER);
// The new prerender does not match any existing prerenders. Update
// prerender_properties so that it reflects the new entry.
prerender_properties->url_id = url_id;
@@ -829,8 +837,10 @@
prerender_properties->prerender_handle.swap(new_prerender_handle);
// new_prerender_handle now represents the old previou prerender that we
// are replacing. So we need to cancel it.
- if (new_prerender_handle)
+ if (new_prerender_handle) {
new_prerender_handle->OnCancel();
+ RecordEvent(EVENT_ISSUE_PRERENDER_CANCELLED_OLD_PRERENDER);
+ }
}
RecordEvent(EVENT_ADD_VISIT_PRERENDERING);
diff --git a/chrome/browser/prerender/prerender_local_predictor.h b/chrome/browser/prerender/prerender_local_predictor.h
index ebd8e03..67cea7f 100644
--- a/chrome/browser/prerender/prerender_local_predictor.h
+++ b/chrome/browser/prerender/prerender_local_predictor.h
@@ -91,6 +91,10 @@
EVENT_TAB_HELPER_URL_SEEN_NAMESPACE_MATCH = 48,
EVENT_PRERENDER_URL_LOOKUP_MULTIPLE_SOURCE_WEBCONTENTS_FOUND = 49,
EVENT_CONTINUE_PRERENDER_CHECK_ON_SIDE_EFFECT_FREE_WHITELIST = 50,
+ EVENT_CONTINUE_PRERENDER_CHECK_EXAMINE_NEXT_URL = 51,
+ EVENT_ISSUE_PRERENDER_ALREADY_PRERENDERING = 52,
+ EVENT_ISSUE_PRERENDER_NEW_PRERENDER = 53,
+ EVENT_ISSUE_PRERENDER_CANCELLED_OLD_PRERENDER = 54,
EVENT_MAX_VALUE
};
diff --git a/chrome/browser/printing/printing_layout_browsertest.cc b/chrome/browser/printing/printing_layout_browsertest.cc
index 1d80518..cc0c449 100644
--- a/chrome/browser/printing/printing_layout_browsertest.cc
+++ b/chrome/browser/printing/printing_layout_browsertest.cc
@@ -8,6 +8,7 @@
#include "base/files/file_path.h"
#include "base/message_loop/message_loop.h"
#include "base/path_service.h"
+#include "base/process/process.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/test_file_util.h"
diff --git a/chrome/browser/profile_resetter/brandcode_config_fetcher.cc b/chrome/browser/profile_resetter/brandcode_config_fetcher.cc
index b3fb98b..f9c6c83 100644
--- a/chrome/browser/profile_resetter/brandcode_config_fetcher.cc
+++ b/chrome/browser/profile_resetter/brandcode_config_fetcher.cc
@@ -27,12 +27,20 @@
" >\n"
" <updatecheck />\n"
" <data name=\"install\" "
- "index=\"skipfirstrunui-importsearch-defaultbrowser\" />\n"
+ "index=\"__BRANDCODE_PLACEHOLDER__\" />\n"
" </app>\n"
"</request>";
-std::string GetUploadData() {
- return kPostXml;
+// Returns the query to the server which can be used to retrieve the config.
+// |brand| is a brand code, it mustn't be empty.
+std::string GetUploadData(const std::string& brand) {
+ DCHECK(!brand.empty());
+ std::string data(kPostXml);
+ const std::string placeholder("__BRANDCODE_PLACEHOLDER__");
+ size_t placeholder_pos = data.find(placeholder);
+ DCHECK(placeholder_pos != std::string::npos);
+ data.replace(placeholder_pos, placeholder.size(), brand);
+ return data;
}
// Extracts json master prefs from xml.
@@ -130,15 +138,17 @@
} // namespace
BrandcodeConfigFetcher::BrandcodeConfigFetcher(const FetchCallback& callback,
- const GURL& url)
+ const GURL& url,
+ const std::string& brandcode)
: fetch_callback_(callback) {
+ DCHECK(!brandcode.empty());
config_fetcher_.reset(net::URLFetcher::Create(0 /* ID used for testing */,
url,
net::URLFetcher::POST,
this));
config_fetcher_->SetRequestContext(
g_browser_process->system_request_context());
- config_fetcher_->SetUploadData("text/xml", GetUploadData());
+ config_fetcher_->SetUploadData("text/xml", GetUploadData(brandcode));
config_fetcher_->AddExtraRequestHeader("Accept: text/xml");
config_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
net::LOAD_DO_NOT_SAVE_COOKIES |
diff --git a/chrome/browser/profile_resetter/brandcode_config_fetcher.h b/chrome/browser/profile_resetter/brandcode_config_fetcher.h
index cacee4d..bbb5631 100644
--- a/chrome/browser/profile_resetter/brandcode_config_fetcher.h
+++ b/chrome/browser/profile_resetter/brandcode_config_fetcher.h
@@ -20,7 +20,8 @@
typedef base::Callback<void ()> FetchCallback;
BrandcodeConfigFetcher(const FetchCallback& callback,
- const GURL& url);
+ const GURL& url,
+ const std::string& brandcode);
virtual ~BrandcodeConfigFetcher();
bool IsActive() const { return config_fetcher_; }
diff --git a/chrome/browser/profile_resetter/profile_resetter_unittest.cc b/chrome/browser/profile_resetter/profile_resetter_unittest.cc
index f1caa33..0c3b529 100644
--- a/chrome/browser/profile_resetter/profile_resetter_unittest.cc
+++ b/chrome/browser/profile_resetter/profile_resetter_unittest.cc
@@ -72,6 +72,9 @@
using extensions::Extension;
using extensions::Manifest;
+
+// ProfileResetterTest --------------------------------------------------------
+
// ProfileResetterTest sets up the extension, WebData and TemplateURL services.
class ProfileResetterTest : public ExtensionServiceTestBase,
public ProfileResetterTestBase {
@@ -101,6 +104,125 @@
return new TemplateURLService(static_cast<Profile*>(context));
}
+
+// PinnedTabsResetTest --------------------------------------------------------
+
+class PinnedTabsResetTest : public BrowserWithTestWindowTest,
+ public ProfileResetterTestBase {
+ protected:
+ virtual void SetUp() OVERRIDE;
+
+ content::WebContents* CreateWebContents();
+};
+
+void PinnedTabsResetTest::SetUp() {
+ BrowserWithTestWindowTest::SetUp();
+ resetter_.reset(new ProfileResetter(profile()));
+}
+
+content::WebContents* PinnedTabsResetTest::CreateWebContents() {
+ return content::WebContents::Create(
+ content::WebContents::CreateParams(profile()));
+}
+
+
+// ConfigParserTest -----------------------------------------------------------
+
+// URLFetcher delegate that simply records the upload data.
+struct URLFetcherRequestListener : net::URLFetcherDelegate {
+ URLFetcherRequestListener();
+ virtual ~URLFetcherRequestListener();
+
+ virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
+
+ std::string upload_data;
+ net::URLFetcherDelegate* real_delegate;
+};
+
+URLFetcherRequestListener::URLFetcherRequestListener()
+ : real_delegate(NULL) {
+}
+
+URLFetcherRequestListener::~URLFetcherRequestListener() {
+}
+
+void URLFetcherRequestListener::OnURLFetchComplete(
+ const net::URLFetcher* source) {
+ const net::TestURLFetcher* test_fetcher =
+ static_cast<const net::TestURLFetcher*>(source);
+ upload_data = test_fetcher->upload_data();
+ DCHECK(real_delegate);
+ real_delegate->OnURLFetchComplete(source);
+}
+
+class ConfigParserTest : public testing::Test {
+ protected:
+ ConfigParserTest();
+ virtual ~ConfigParserTest();
+
+ scoped_ptr<BrandcodeConfigFetcher> WaitForRequest(const GURL& url);
+
+ net::FakeURLFetcherFactory& factory() { return factory_; }
+
+ private:
+ scoped_ptr<net::FakeURLFetcher> CreateFakeURLFetcher(
+ const GURL& url,
+ net::URLFetcherDelegate* fetcher_delegate,
+ const std::string& response_data,
+ bool success);
+
+ MOCK_METHOD0(Callback, void(void));
+
+ base::MessageLoop loop_;
+ content::TestBrowserThread ui_thread_;
+ content::TestBrowserThread io_thread_;
+ URLFetcherRequestListener request_listener_;
+ net::FakeURLFetcherFactory factory_;
+};
+
+ConfigParserTest::ConfigParserTest()
+ : loop_(base::MessageLoop::TYPE_IO),
+ ui_thread_(content::BrowserThread::UI, &loop_),
+ io_thread_(content::BrowserThread::IO, &loop_),
+ factory_(NULL, base::Bind(&ConfigParserTest::CreateFakeURLFetcher,
+ base::Unretained(this))) {
+}
+
+ConfigParserTest::~ConfigParserTest() {}
+
+scoped_ptr<BrandcodeConfigFetcher> ConfigParserTest::WaitForRequest(
+ const GURL& url) {
+ EXPECT_CALL(*this, Callback());
+ scoped_ptr<BrandcodeConfigFetcher> fetcher(
+ new BrandcodeConfigFetcher(base::Bind(&ConfigParserTest::Callback,
+ base::Unretained(this)),
+ url,
+ "ABCD"));
+ base::MessageLoop::current()->RunUntilIdle();
+ EXPECT_FALSE(fetcher->IsActive());
+ // Look for the brand code in the request.
+ EXPECT_NE(std::string::npos, request_listener_.upload_data.find("ABCD"));
+ return fetcher.Pass();
+}
+
+scoped_ptr<net::FakeURLFetcher> ConfigParserTest::CreateFakeURLFetcher(
+ const GURL& url,
+ net::URLFetcherDelegate* fetcher_delegate,
+ const std::string& response_data,
+ bool success) {
+ request_listener_.real_delegate = fetcher_delegate;
+ scoped_ptr<net::FakeURLFetcher> fetcher(
+ new net::FakeURLFetcher(url, &request_listener_, response_data, success));
+ scoped_refptr<net::HttpResponseHeaders> download_headers =
+ new net::HttpResponseHeaders("");
+ download_headers->AddHeader("Content-Type: text/xml");
+ fetcher->set_response_headers(download_headers);
+ return fetcher.Pass();
+}
+
+
+// helper functions -----------------------------------------------------------
+
scoped_refptr<Extension> CreateExtension(const std::string& name,
const base::FilePath& path,
Manifest::Location location,
@@ -123,78 +245,6 @@
return extension;
}
-class PinnedTabsResetTest : public BrowserWithTestWindowTest,
- public ProfileResetterTestBase {
- protected:
- virtual void SetUp() OVERRIDE;
-
- content::WebContents* CreateWebContents();
-};
-
-void PinnedTabsResetTest::SetUp() {
- BrowserWithTestWindowTest::SetUp();
- resetter_.reset(new ProfileResetter(profile()));
-}
-
-content::WebContents* PinnedTabsResetTest::CreateWebContents() {
- return content::WebContents::Create(
- content::WebContents::CreateParams(profile()));
-}
-
-class ConfigParserTest : public testing::Test {
- protected:
- ConfigParserTest();
- virtual ~ConfigParserTest();
-
- MOCK_METHOD0(Callback, void(void));
-
- scoped_ptr<BrandcodeConfigFetcher> WaitForRequest(const GURL& url);
-
- static scoped_ptr<net::FakeURLFetcher> CreateFakeURLFetcher(
- const GURL& url,
- net::URLFetcherDelegate* d,
- const std::string& response_data,
- bool success);
-
- base::MessageLoop loop_;
- content::TestBrowserThread ui_thread_;
- content::TestBrowserThread io_thread_;
-};
-
-ConfigParserTest::ConfigParserTest()
- : loop_(base::MessageLoop::TYPE_IO),
- ui_thread_(content::BrowserThread::UI, &loop_),
- io_thread_(content::BrowserThread::IO, &loop_) {
-}
-
-ConfigParserTest::~ConfigParserTest() {}
-
-scoped_ptr<BrandcodeConfigFetcher> ConfigParserTest::WaitForRequest(
- const GURL& url) {
- EXPECT_CALL(*this, Callback());
- scoped_ptr<BrandcodeConfigFetcher> fetcher(
- new BrandcodeConfigFetcher(base::Bind(&ConfigParserTest::Callback,
- base::Unretained(this)),
- url));
- base::MessageLoop::current()->RunUntilIdle();
- EXPECT_FALSE(fetcher->IsActive());
- return fetcher.Pass();
-}
-
-scoped_ptr<net::FakeURLFetcher> ConfigParserTest::CreateFakeURLFetcher(
- const GURL& url,
- net::URLFetcherDelegate* d,
- const std::string& response_data,
- bool success) {
- scoped_ptr<net::FakeURLFetcher> fetcher(
- new net::FakeURLFetcher(url, d, response_data, success));
- scoped_refptr<net::HttpResponseHeaders> download_headers =
- new net::HttpResponseHeaders("");
- download_headers->AddHeader("Content-Type: text/xml");
- fetcher->set_response_headers(download_headers);
- return fetcher.Pass();
-}
-
void ReplaceString(std::string* str,
const std::string& placeholder,
const std::string& substitution) {
@@ -523,9 +573,8 @@
// Tries to load unavailable config file.
TEST_F(ConfigParserTest, NoConnectivity) {
- net::FakeURLFetcherFactory factory(NULL);
const std::string url("http://test");
- factory.SetFakeResponse(url, "", false);
+ factory().SetFakeResponse(url, "", false);
scoped_ptr<BrandcodeConfigFetcher> fetcher = WaitForRequest(GURL(url));
EXPECT_FALSE(fetcher->GetSettings());
@@ -533,16 +582,13 @@
// Tries to load available config file.
TEST_F(ConfigParserTest, ParseConfig) {
- net::FakeURLFetcherFactory factory(
- NULL,
- base::Bind(&ConfigParserTest::CreateFakeURLFetcher));
const std::string url("http://test");
std::string xml_config(kXmlConfig);
ReplaceString(&xml_config, "placeholder_for_data", kDistributionConfig);
ReplaceString(&xml_config,
"placeholder_for_id",
"abbaabbaabbaabbaabbaabbaabbaabba");
- factory.SetFakeResponse(url, xml_config, true);
+ factory().SetFakeResponse(url, xml_config, true);
scoped_ptr<BrandcodeConfigFetcher> fetcher = WaitForRequest(GURL(url));
scoped_ptr<BrandcodedDefaultSettings> settings = fetcher->GetSettings();
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
index 38b80e9..35cae78 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -118,8 +118,8 @@
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/extensions/input_method_api.h"
#include "chrome/browser/chromeos/extensions/media_player_api.h"
-#include "chrome/browser/chromeos/extensions/networking_private_event_router_factory.h"
#include "chrome/browser/extensions/api/input_ime/input_ime_api.h"
+#include "chrome/browser/extensions/api/networking_private/networking_private_event_router_factory.h"
#if defined(FILE_MANAGER_EXTENSION)
#include "chrome/browser/chromeos/extensions/file_manager/file_browser_private_api_factory.h"
#endif
diff --git a/chrome/browser/resources/chromeos/login/screen_error_message.html b/chrome/browser/resources/chromeos/login/screen_error_message.html
index 0365067..82db057 100644
--- a/chrome/browser/resources/chromeos/login/screen_error_message.html
+++ b/chrome/browser/resources/chromeos/login/screen_error_message.html
@@ -1,7 +1,7 @@
<div id="error-message" class="step hidden show-offline-error">
<div class="step-contents">
<div class="error-header">
- <img alt class="error-icon" src="chrome://theme/IDR_NETWORK_ERROR">
+ <img alt class="error-icon" src="chrome://theme/IDR_ERROR_NETWORK_OFFLINE">
<div id="captive-portal-title" i18n-content="captivePortalTitle"
class="error-title
show-with-error-state-portal
diff --git a/chrome/browser/resources/file_manager/js/file_copy_manager.js b/chrome/browser/resources/file_manager/js/file_copy_manager.js
index 9fe76ce..766c251 100644
--- a/chrome/browser/resources/file_manager/js/file_copy_manager.js
+++ b/chrome/browser/resources/file_manager/js/file_copy_manager.js
@@ -693,6 +693,8 @@
task, successCallback, errorCallback) {
if (task.zip)
this.serviceZipTask_(task, successCallback, errorCallback);
+ else if (task.move)
+ this.serviceMoveTask_(task, successCallback, errorCallback);
else
this.serviceCopyTask_(task, successCallback, errorCallback);
};
@@ -701,7 +703,6 @@
* Service all entries in the copy (and move) task.
* Note: this method contains also the operation of "Move" due to historical
* reason.
- * TODO(hidehiko): extract "move" related code into another method.
*
* @param {FileCopyManager.Task} task A copy task to be run.
* @param {function()} successCallback On success.
@@ -753,7 +754,7 @@
};
/**
- * Service the next entry in a given task.
+ * Copies the next entry in a given task.
* TODO(olege): Refactor this method into a separate class.
*
* @param {FileManager.Task} task A task.
@@ -817,28 +818,11 @@
onCopyCompleteBase(targetEntry, 0);
};
- var onFilesystemMoveComplete = function(sourceEntry, targetEntry) {
- self.sendOperationEvent_('moved', [sourceEntry, targetEntry]);
- onCopyCompleteBase(targetEntry, 0);
- };
-
var onFilesystemError = function(err) {
onError('FILESYSTEM_ERROR', err);
};
var onDeduplicated = function(targetRelativePath) {
- if (task.move) {
- targetDirEntry.getDirectory(
- PathUtil.dirname(targetRelativePath), {create: false},
- function(dirEntry) {
- sourceEntry.moveTo(dirEntry, PathUtil.basename(targetRelativePath),
- onFilesystemMoveComplete.bind(self, sourceEntry),
- onFilesystemError);
- },
- onFilesystemError);
- return;
- }
-
// TODO(benchan): drive::FileSystem has not implemented directory copy,
// and thus we only call FileEntry.copyTo() for files. Revisit this
// code when drive::FileSystem supports directory copy.
@@ -986,6 +970,106 @@
};
/**
+ * Moves all entries in the task.
+ *
+ * @param {FileCopyManager.Task} task A move task to be run.
+ * @param {function()} successCallback On success.
+ * @param {function(FileCopyManager.Error)} errorCallback On error.
+ * @private
+ */
+FileCopyManager.prototype.serviceMoveTask_ = function(
+ task, successCallback, errorCallback) {
+ this.serviceNextMoveTaskEntry_(
+ task,
+ (function onCompleted() {
+ // We should not dispatch a PROGRESS event when there is no pending
+ // items in the task.
+ if (task.pendingDirectories.length + task.pendingFiles.length == 0) {
+ successCallback();
+ return;
+ }
+
+ // Move the next entry.
+ this.sendProgressEvent_('PROGRESS');
+ this.serviceNextMoveTaskEntry_(
+ task, onCompleted.bind(this), errorCallback);
+ }).bind(this),
+ errorCallback);
+};
+
+/**
+ * Moves the next entry in a given task.
+ *
+ * Implementation note: This method can be simplified more. For example, in
+ * Task.setEntries(), the flag to recurse is set to false for move task,
+ * so that all the entries' originalSourcePath should be
+ * dirname(sourceEntry.fullPath).
+ * Thus, targetRelativePath should contain exact one component. Also we can
+ * skip applyRenames, because the destination directory always should be
+ * task.targetDirEntry.
+ * The unnecessary complexity is due to historical reason.
+ * TODO(hidehiko): Refactor this method.
+ *
+ * @param {FileManager.Task} task A move task.
+ * @param {function()} successCallback On success.
+ * @param {function(FileCopyManager.Error)} errorCallback On error.
+ * @private
+ */
+FileCopyManager.prototype.serviceNextMoveTaskEntry_ = function(
+ task, successCallback, errorCallback) {
+ if (this.maybeCancel_())
+ return;
+
+ var self = this;
+ var sourceEntry = task.getNextEntry();
+
+ if (!sourceEntry) {
+ // All entries in this task have been copied.
+ successCallback();
+ return;
+ }
+
+ var onError = function(reason, data) {
+ self.log_('serviceNextMoveTaskEntry error: ' + reason + ':', data);
+ errorCallback(new FileCopyManager.Error(reason, data));
+ };
+
+ // |sourceEntry.originalSourcePath| is set in util.recurseAndResolveEntries.
+ var sourcePath = sourceEntry.originalSourcePath;
+ if (sourceEntry.fullPath.substr(0, sourcePath.length) != sourcePath) {
+ // We found an entry in the list that is not relative to the base source
+ // path, something is wrong.
+ onError('UNEXPECTED_SOURCE_FILE', sourceEntry.fullPath);
+ return;
+ }
+
+ util.deduplicatePath(
+ task.targetDirEntry,
+ task.applyRenames(sourceEntry.fullPath.substr(sourcePath.length + 1)),
+ function(targetRelativePath) {
+ var onFilesystemError = function(err) {
+ onError('FILESYSTEM_ERROR', err);
+ };
+
+ task.targetDirEntry.getDirectory(
+ PathUtil.dirname(targetRelativePath), {create: false},
+ function(dirEntry) {
+ sourceEntry.moveTo(
+ dirEntry, PathUtil.basename(targetRelativePath),
+ function(targetEntry) {
+ self.sendOperationEvent_(
+ 'moved', [sourceEntry, targetEntry]);
+ task.markEntryComplete(targetEntry, 0);
+ successCallback();
+ },
+ onFilesystemError);
+ },
+ onFilesystemError);
+ },
+ onError);
+};
+
+/**
* Service a zip file creation task.
*
* @param {FileCopyManager.Task} task A zip task to be run.
@@ -1083,7 +1167,7 @@
reportedProgress = progress.loaded;
};
- writer.onwriteend = function() {
+ writer.onwrite = function() {
sourceEntry.getMetadata(function(metadata) {
chrome.fileBrowserPrivate.setLastModified(targetEntry.toURL(),
'' + Math.round(metadata.modificationTime.getTime() / 1000));
diff --git a/chrome/browser/resources/file_manager/js/file_manager.js b/chrome/browser/resources/file_manager/js/file_manager.js
index 66cb272..fc02338 100644
--- a/chrome/browser/resources/file_manager/js/file_manager.js
+++ b/chrome/browser/resources/file_manager/js/file_manager.js
@@ -637,13 +637,13 @@
var doc = this.document_;
- CommandUtil.registerCommand(this.dialogContainer_, 'newfolder',
+ CommandUtil.registerCommand(doc, 'newfolder',
Commands.newFolderCommand, this, this.directoryModel_);
- CommandUtil.registerCommand(this.dialogContainer_, 'newwindow',
+ CommandUtil.registerCommand(doc, 'newwindow',
Commands.newWindowCommand, this, this.directoryModel_);
- CommandUtil.registerCommand(this.dialogContainer_, 'change-default-app',
+ CommandUtil.registerCommand(doc, 'change-default-app',
Commands.changeDefaultAppCommand, this);
CommandUtil.registerCommand(this.volumeList_, 'unmount',
@@ -652,58 +652,53 @@
CommandUtil.registerCommand(this.volumeList_, 'import-photos',
Commands.importCommand, this.volumeList_);
- CommandUtil.registerCommand(this.dialogContainer_, 'format',
+ CommandUtil.registerCommand(doc, 'format',
Commands.formatCommand, this.volumeList_, this,
this.directoryModel_);
- CommandUtil.registerCommand(this.dialogContainer_, 'delete',
+ CommandUtil.registerCommand(doc, 'delete',
Commands.deleteFileCommand, this);
- CommandUtil.registerCommand(this.dialogContainer_, 'rename',
+ CommandUtil.registerCommand(doc, 'rename',
Commands.renameFileCommand, this);
- CommandUtil.registerCommand(this.dialogContainer_, 'volume-help',
+ CommandUtil.registerCommand(doc, 'volume-help',
Commands.volumeHelpCommand, this);
- CommandUtil.registerCommand(this.dialogContainer_, 'drive-buy-more-space',
+ CommandUtil.registerCommand(doc, 'drive-buy-more-space',
Commands.driveBuySpaceCommand, this);
- CommandUtil.registerCommand(this.dialogContainer_,
- 'drive-clear-local-cache', Commands.driveClearCacheCommand, this);
+ CommandUtil.registerCommand(doc, 'drive-clear-local-cache',
+ Commands.driveClearCacheCommand, this);
- CommandUtil.registerCommand(this.dialogContainer_, 'drive-go-to-drive',
+ CommandUtil.registerCommand(doc, 'drive-go-to-drive',
Commands.driveGoToDriveCommand, this);
- CommandUtil.registerCommand(this.dialogContainer_, 'paste',
+ CommandUtil.registerCommand(doc, 'paste',
Commands.pasteFileCommand, doc, this.fileTransferController_);
- CommandUtil.registerCommand(this.dialogContainer_, 'open-with',
+ CommandUtil.registerCommand(doc, 'open-with',
Commands.openWithCommand, this);
- CommandUtil.registerCommand(this.dialogContainer_, 'toggle-pinned',
+ CommandUtil.registerCommand(doc, 'toggle-pinned',
Commands.togglePinnedCommand, this);
- CommandUtil.registerCommand(this.dialogContainer_, 'zip-selection',
+ CommandUtil.registerCommand(doc, 'zip-selection',
Commands.zipSelectionCommand, this, this.directoryModel_);
- CommandUtil.registerCommand(this.dialogContainer_, 'share',
- Commands.shareCommand, this);
+ CommandUtil.registerCommand(doc, 'share', Commands.shareCommand, this);
+ CommandUtil.registerCommand(doc, 'create-folder-shortcut',
+ Commands.createFolderShortcutCommand, this);
+ CommandUtil.registerCommand(doc, 'remove-folder-shortcut',
+ Commands.removeFolderShortcutCommand, this, this.volumeList_);
- CommandUtil.registerCommand(this.dialogContainer_,
- 'create-folder-shortcut', Commands.createFolderShortcutCommand, this);
-
- CommandUtil.registerCommand(this.dialogContainer_,
- 'remove-folder-shortcut', Commands.removeFolderShortcutCommand, this,
- this.volumeList_);
-
- CommandUtil.registerCommand(this.dialogContainer_, 'search',
- Commands.searchCommand, this,
+ CommandUtil.registerCommand(doc, 'search', Commands.searchCommand, this,
this.dialogDom_.querySelector('#search-box'));
// Register commands with CTRL-1..9 shortcuts for switching between
// volumes.
for (var i = 1; i <= 9; i++) {
- CommandUtil.registerCommand(this.dialogContainer_,
+ CommandUtil.registerCommand(doc,
'volume-switch-' + i,
Commands.volumeSwitchCommand,
this.volumeList_,
diff --git a/chrome/browser/resources/gesture_config.js b/chrome/browser/resources/gesture_config.js
index e38baa9..1e201b2 100644
--- a/chrome/browser/resources/gesture_config.js
+++ b/chrome/browser/resources/gesture_config.js
@@ -331,7 +331,12 @@
},
{
key: 'minimum_threshold_start',
- label: 'Start overscroll gesture after scrolling',
+ label: 'Start overscroll gesture (horizontal)',
+ units: 'pixels'
+ },
+ {
+ key: 'vertical_threshold_start',
+ label: 'Start overscroll gesture (vertical)',
units: 'pixels'
},
{
diff --git a/chrome/browser/resources/local_ntp/local_ntp.js b/chrome/browser/resources/local_ntp/local_ntp.js
index e63fbaa..23272e0 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.js
+++ b/chrome/browser/resources/local_ntp/local_ntp.js
@@ -391,8 +391,7 @@
/**
- * Renders the attribution if the image is present and loadable. Otherwise
- * hides it.
+ * Renders the attribution if the URL is present, otherwise hides it.
* @param {string} url The URL of the attribution image, if any.
* @private
*/
@@ -401,18 +400,14 @@
setAttributionVisibility_(false);
return;
}
- var attributionImage = new Image();
- attributionImage.onload = function() {
- var oldAttributionImage = attribution.querySelector('img');
- if (oldAttributionImage)
- removeNode(oldAttributionImage);
+
+ var attributionImage = attribution.querySelector('img');
+ if (!attributionImage) {
+ attributionImage = new Image();
attribution.appendChild(attributionImage);
- setAttributionVisibility_(true);
- };
- attributionImage.onerror = function() {
- setAttributionVisibility_(false);
- };
- attributionImage.src = url;
+ }
+ attributionImage.style.content = url;
+ setAttributionVisibility_(true);
}
diff --git a/chrome/browser/resources/net_internals/waterfall_row.js b/chrome/browser/resources/net_internals/waterfall_row.js
index d24595a..d17ebc3 100644
--- a/chrome/browser/resources/net_internals/waterfall_row.js
+++ b/chrome/browser/resources/net_internals/waterfall_row.js
@@ -41,15 +41,23 @@
addTextNode(this.urlCell_, this.description_);
}
- this.barCell_.innerHTML = '';
+ this.rowCell_.innerHTML = '';
+
var matchingEventPairs = this.findLogEntryPairs_(this.eventTypes_);
// Creates the spacing in the beginning to show start time.
var startTime = this.parentView_.getStartTime();
var sourceEntryStartTime = this.sourceEntry_.getStartTime();
var delay = sourceEntryStartTime - startTime;
- var scaledMinTime = delay * scale;
- this.createNode_(this.barCell_, scaledMinTime, 'padding');
+ var frontNode = addNode(this.rowCell_, 'div');
+ setNodeWidth(frontNode, delay * scale);
+
+ var barCell = addNode(this.rowCell_, 'div');
+ barCell.classList.add('waterfall-view-bar');
+
+ if (this.sourceEntry_.isError()) {
+ barCell.classList.add('error');
+ }
var currentEnd = sourceEntryStartTime;
for (var i = 0; i < matchingEventPairs.length; ++i) {
@@ -64,20 +72,22 @@
// Handles the spaces between events.
if (currentEnd < event.startTime) {
var eventDuration = event.startTime - currentEnd;
- var eventWidth = eventDuration * scale;
- this.createNode_(this.barCell_, eventWidth, this.type_);
+ var padNode = this.createNode_(
+ barCell, eventDuration, this.type_, 'source');
}
// Creates event bars.
var eventType = eventTypeToCssClass_(EventTypeNames[event.eventType]);
- var eventWidth = event.eventDuration * scale;
- this.createNode_(this.barCell_, eventWidth, eventType);
+ var eventNode = this.createNode_(
+ barCell, event.eventDuration, eventType, event);
currentEnd = event.startTime + event.eventDuration;
}
+
// Creates a bar for the part after the last event.
if (this.getEndTime() > currentEnd) {
- var endWidth = (this.getEndTime() - currentEnd) * scale;
- this.createNode_(this.barCell_, endWidth, this.type_);
+ var endDuration = (this.getEndTime() - currentEnd);
+ var endNode = this.createNode_(
+ barCell, endDuration, this.type_, 'source');
}
},
@@ -89,11 +99,84 @@
return this.sourceEntry_.getEndTime();
},
+ clearPopup_: function(parentNode) {
+ parentNode.innerHTML = '';
+ },
+
+ // TODO(viona): Create popup at mouse location.
+ createPopup_: function(parentNode, event, eventType, duration, mouse) {
+ var tableStart = this.parentView_.getStartTime();
+
+ var newPopup = addNode(parentNode, 'div');
+ newPopup.classList.add('waterfall-view-popup');
+
+ var popupList = addNode(newPopup, 'ul');
+ popupList.classList.add('waterfall-view-popup-list');
+
+ this.createPopupItem_(
+ popupList, 'Event Type', eventType);
+ this.createPopupItem_(
+ popupList, 'Event Duration', duration.toFixed(0) + 'ms');
+
+ if (event != 'source') {
+ this.createPopupItem_(
+ popupList, 'Event Start Time', event.startTime - tableStart + 'ms');
+ this.createPopupItem_(
+ popupList, 'Event End Time', event.endTime - tableStart + 'ms');
+ }
+
+ this.createPopupItem_(
+ popupList, 'Source Start Time',
+ this.getStartTime() - tableStart + 'ms');
+ this.createPopupItem_(
+ popupList, 'Source End Time', this.getEndTime() - tableStart + 'ms');
+ this.createPopupItem_(
+ popupList, 'Source ID', this.sourceEntry_.getSourceId());
+ var urlListItem = this.createPopupItem_(
+ popupList, 'Source Description: ', this.description_);
+
+ var viewWidth = $(WaterfallView.MAIN_BOX_ID).offsetWidth;
+ // Controls the overflow of extremely long URLs by cropping to window.
+ if (urlListItem.offsetWidth > viewWidth) {
+ urlListItem.style.width = viewWidth + 'px';
+ }
+ urlListItem.classList.add('waterfall-view-popup-list-url-item');
+
+ this.createPopupItem_(
+ popupList, 'Has Error', this.sourceEntry_.isError());
+
+ // Fixes cases where the popup appears 'off-screen'.
+ var popupLeft = mouse.pageX + $(WaterfallView.MAIN_BOX_ID).scrollLeft;
+ var popupRight = popupLeft + newPopup.offsetWidth;
+ var viewRight = viewWidth + $(WaterfallView.MAIN_BOX_ID).scrollLeft;
+
+ if (viewRight - popupRight < 0) {
+ popupLeft = viewRight - newPopup.offsetWidth;
+ }
+ newPopup.style.left = popupLeft + 'px';
+
+ var popupTop = mouse.pageY + $(WaterfallView.MAIN_BOX_ID).scrollTop;
+ var popupBottom = popupTop + newPopup.offsetHeight;
+ var viewBottom = $(WaterfallView.MAIN_BOX_ID).offsetHeight +
+ $(WaterfallView.MAIN_BOX_ID).scrollTop;
+
+ if (viewBottom - popupBottom < 0) {
+ popupTop = viewBottom - newPopup.offsetHeight;
+ }
+ newPopup.style.top = popupTop + 'px';
+ },
+
+ createPopupItem_: function(parentPopup, key, popupInformation) {
+ var popupItem = addNode(parentPopup, 'li');
+ addTextNode(popupItem, key + ': ' + popupInformation);
+ return popupItem;
+ },
+
createRow_: function() {
// Create a row.
var tr = addNode($(WaterfallView.TBODY_ID), 'tr');
tr._id = this.sourceEntry_.getSourceId();
- this.row_ = tr;
+ this.tableRow = tr;
var idCell = addNode(tr, 'td');
addTextNode(idCell, this.sourceEntry_.getSourceId());
@@ -103,22 +186,30 @@
addTextNode(urlCell, this.description_);
this.urlCell_ = urlCell;
- // Creates the offset for where the color bar appears.
- var barCell = addNode(tr, 'td');
- barCell.classList.add('waterfall-view-row');
- this.barCell_ = barCell;
+ // Creates the color bar.
- this.updateRow();
+ var rowCell = addNode(tr, 'td');
+ rowCell.classList.add('waterfall-view-row');
+ this.rowCell_ = rowCell;
var sourceTypeString = this.sourceEntry_.getSourceTypeString();
this.type_ = eventTypeToCssClass_(sourceTypeString);
+
+ this.updateRow();
},
// Generates nodes.
- createNode_: function(parentNode, durationScaled, eventType) {
+ createNode_: function(parentNode, duration, eventType, event) {
+ var scale = this.parentView_.getScaleFactor();
var newNode = addNode(parentNode, 'div');
- setNodeWidth(newNode, durationScaled);
- newNode.classList.add('waterfall-view-row-' + eventType);
+ setNodeWidth(newNode, duration * scale);
+ newNode.classList.add(eventType);
+ newNode.addEventListener(
+ 'mouseover',
+ this.createPopup_.bind(this, newNode, event, eventType, duration),
+ true);
+ newNode.addEventListener(
+ 'mouseout', this.clearPopup_.bind(this, newNode), true);
return newNode;
},
@@ -135,24 +226,24 @@
var startEntries = {};
var entries = this.sourceEntry_.getLogEntries();
for (var i = 0; i < entries.length; ++i) {
- var type = entries[i].type;
+ var currentEntry = entries[i];
+ var type = currentEntry.type;
if (typeList.indexOf(type) < 0) {
continue;
}
- if (entries[i].phase == EventPhase.PHASE_BEGIN) {
- startEntries[type] = entries[i];
+ if (currentEntry.phase == EventPhase.PHASE_BEGIN) {
+ startEntries[type] = currentEntry;
}
- if (startEntries[type] && entries[i].phase == EventPhase.PHASE_END) {
+ if (startEntries[type] && currentEntry.phase == EventPhase.PHASE_END) {
var event = {
startEntry: startEntries[type],
- endEntry: entries[i],
+ endEntry: currentEntry,
};
matchingEventPairs.push(event);
}
}
return matchingEventPairs;
},
-
};
function eventTypeToCssClass_(rawEventType) {
diff --git a/chrome/browser/resources/net_internals/waterfall_view.css b/chrome/browser/resources/net_internals/waterfall_view.css
index 2d1b636..14a0f60c 100644
--- a/chrome/browser/resources/net_internals/waterfall_view.css
+++ b/chrome/browser/resources/net_internals/waterfall_view.css
@@ -3,6 +3,16 @@
* found in the LICENSE file.
*/
+#waterfall-view-controls {
+ background-color: #FFF;
+ border-color: #000;
+ border-style: solid;
+ border-width: 1px;
+ padding-left: 5px;
+ position: fixed;
+ top: 40px;
+}
+
.waterfall-view-url-cell {
display: inline-block;
overflow: hidden;
@@ -17,44 +27,101 @@
.waterfall-view-row * {
display: inline-block;
- height: 15px;
- opacity: 0.5;
padding-top: 0;
}
-.waterfall-view-row [class*='http-stream-request'] {
- background-color: #000;
+.waterfall-view-bar > * {
+ height: 15px;
}
-.waterfall-view-row [class*='http-transaction-read-headers'] {
- background-color: rgb(255, 0, 0);
+.waterfall-view-popup-list {
+ background-color: rgba(255, 255, 255, 0.8);
+ border-color: #000;
+ border-style: solid;
+ border-width: 2px;
+ color: #000;
+ padding-right: 1em;
+ z-index: -1;
}
-.waterfall-view-row [class*='url-request'] {
- background-color: rgb(0, 0, 255);
+.waterfall-view-popup-list > li {
+ display: list-item;
+}
+.waterfall-view-popup-list-url-item {
+ text-overflow: ellipsis;
+ white-space: nowrap;
}
-.waterfall-view-row [class*='http-stream-job'] {
- background-color: rgb(0, 255, 0);
+.waterfall-view-bar.error {
+ border-color: rgba(255, 0, 0, 0.8);
+ border-style: solid;
+ border-width: 1px;
+ height: 18px;
}
-.waterfall-view-row [class*='proxy-service'] {
- background-color: rgb(122, 122, 0);
+.waterfall-view-row .http-stream-request {
+ background: -webkit-linear-gradient(top, #EEE, rgba(0, 0, 0, 0.5));
}
-.waterfall-view-row [class*='socket-pool-connect-job'] {
- background-color: rgb(0, 122, 122);
+.waterfall-view-row .http-stream-request-bound-to-job {
+ background: -webkit-linear-gradient(top, #EEE, rgba(200, 200, 200, 0.5));
}
-.waterfall-view-row [class*='host-resolver-impl'] {
- background-color: rgb(122, 0, 122);
+.waterfall-view-row .http-transaction-read-headers {
+ background: -webkit-linear-gradient(top, #EEE, rgba(255, 0, 0, 0.5));
}
-.waterfall-view-row [class*='socket'] {
- background-color: rgb(122, 178, 0);
+.waterfall-view-row .url-request {
+ background: -webkit-linear-gradient(top, #EEE, rgba(0, 0, 255, 0.5));
}
-.waterfall-popup {
- display: block;
- font-size: 15px;
+.waterfall-view-row .http-stream-job {
+ background: -webkit-linear-gradient(top, #EEE, rgba(0, 255, 0, 0.5));
+}
+
+.waterfall-view-row .proxy-service {
+ background: -webkit-linear-gradient(top, #EEE, rgba(122, 122, 0, 0.5));
+}
+
+.waterfall-view-row .socket-pool-connect-job {
+ background: -webkit-linear-gradient(top, #EEE, rgba(0, 122, 122, 0.5));
+}
+
+.waterfall-view-row .host-resolver-impl {
+ background: -webkit-linear-gradient(top, #EEE, rgba(122, 0, 122, 0.5));
+}
+
+.waterfall-view-row .socket {
+ background: -webkit-linear-gradient(top, #EEE, rgba(122, 178, 0, 0.5));
+}
+
+.waterfall-view-row .tcp-connect {
+ background: -webkit-linear-gradient(top, #EEE, rgba(0, 178, 122, 0.5));
+}
+
+.waterfall-view-row .ssl-connect {
+ background: -webkit-linear-gradient(top, #EEE, rgba(55, 122, 178, 0.5));
+}
+
+.waterfall-view-popup {
+ display: inline-block;
+ position: absolute;
+}
+
+.waterfall-view-time-scale-row {
+ white-space: nowrap;
+}
+
+.waterfall-view-time-scale {
+ border-color: #000;
+ border-left-style: solid;
+ border-width: 1px;
+ box-sizing: border-box;
+ display: inline-block;
+ height: 15px;
+}
+
+/* Colors every fifth bar red. */
+.waterfall-view-time-scale-special {
+ border-color: rgb(255, 0, 0);
}
diff --git a/chrome/browser/resources/net_internals/waterfall_view.html b/chrome/browser/resources/net_internals/waterfall_view.html
index d605122..ac88a7a 100644
--- a/chrome/browser/resources/net_internals/waterfall_view.html
+++ b/chrome/browser/resources/net_internals/waterfall_view.html
@@ -1,16 +1,18 @@
<!-- =============== Events Waterfall View ================= -->
<div id=waterfall-view-tab-content class=content-box>
<div>
- Information:
- <p>Currently only captures URL Request events. Blue represents URL
- Requests. Red represents Header Reads. Grey represents Stream Requests.
- <input id=waterfall-view-time-scale type="button"
- value="Scale To Fit Window">
+ <div id=waterfall-view-controls>
+ Start Time: <input id=waterfall-view-start-input type=number min=0 value=0>
+ End Time: <input id=waterfall-view-end-input type=number min=0>
+ <input id=waterfall-view-adjust-to-window type=button value="Fit Range in Window">
+ </div>
+ <p>
<table id=waterfall-view-source-list-table>
<thead>
<tr>
<td id=waterfall-view-source-id>ID</td>
<td id=waterfall-view-source-header>Source</td>
+ <td id=waterfall-view-time-scale-labels></td>
</tr>
</thead>
<!-- Events Waterfall table body: This is where request rows go into -->
diff --git a/chrome/browser/resources/net_internals/waterfall_view.js b/chrome/browser/resources/net_internals/waterfall_view.js
index 2f1b0ed..aac15b6 100644
--- a/chrome/browser/resources/net_internals/waterfall_view.js
+++ b/chrome/browser/resources/net_internals/waterfall_view.js
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// TODO(viona): Write a README document/instructions.
+
/** This view displays the event waterfall. */
var WaterfallView = (function() {
'use strict';
@@ -22,7 +24,10 @@
// For adjusting the range of view.
$(WaterfallView.SCALE_ID).addEventListener(
- 'click', this.adjustToWindow_.bind(this), true);
+ 'click', this.setStartEndTimes_.bind(this), true);
+
+ $(WaterfallView.MAIN_BOX_ID).addEventListener(
+ 'mousewheel', this.scrollToZoom_.bind(this), true);
this.initializeSourceList_();
}
@@ -34,9 +39,22 @@
// IDs for special HTML elements in events_waterfall_view.html.
WaterfallView.MAIN_BOX_ID = 'waterfall-view-tab-content';
WaterfallView.TBODY_ID = 'waterfall-view-source-list-tbody';
- WaterfallView.SCALE_ID = 'waterfall-view-time-scale';
+ WaterfallView.SCALE_ID = 'waterfall-view-adjust-to-window';
WaterfallView.ID_HEADER_ID = 'waterfall-view-source-id';
WaterfallView.SOURCE_HEADER_ID = 'waterfall-view-source-header';
+ WaterfallView.TIME_SCALE_HEADER_ID = 'waterfall-view-time-scale-labels';
+ WaterfallView.TIME_RANGE_ID = 'waterfall-view-time-range-submit';
+ WaterfallView.START_TIME_ID = 'waterfall-view-start-input';
+ WaterfallView.END_TIME_ID = 'waterfall-view-end-input';
+
+ // The number of units mouse wheel deltas increase for each tick of the
+ // wheel.
+ var MOUSE_WHEEL_UNITS_PER_CLICK = 120;
+
+ // Amount we zoom for one vertical tick of the mouse wheel, as a ratio.
+ var MOUSE_WHEEL_ZOOM_RATE = 1.25;
+ // Amount we scroll for one horizontal tick of the mouse wheel, in pixels.
+ var MOUSE_WHEEL_SCROLL_RATE = MOUSE_WHEEL_UNITS_PER_CLICK;
cr.addSingletonGetter(WaterfallView);
@@ -55,24 +73,29 @@
this.startTime_ = timeutil.convertTimeTicksToTime(logEntries[0].time);
// Initial scale factor.
this.scaleFactor_ = 0.1;
+ this.eventsList_ = this.createEventsList_();
}
for (var i = 0; i < sourceEntries.length; ++i) {
var sourceEntry = sourceEntries[i];
var id = sourceEntry.getSourceId();
- if (sourceEntry.getSourceType() == EventSourceType.URL_REQUEST) {
- var row = this.sourceIdToRowMap_[id];
- if (!row) {
- var importantEventTypes = [
- EventType.HTTP_STREAM_REQUEST,
- EventType.HTTP_TRANSACTION_READ_HEADERS
- ];
- this.sourceIdToRowMap_[id] =
- new WaterfallRow(this, sourceEntry, importantEventTypes);
- } else {
- row.onSourceUpdated();
+ for (var j = 0; j < this.eventsList_.length; ++j) {
+ var eventObject = this.eventsList_[j];
+ if (sourceEntry.getSourceType() == eventObject.mainEvent) {
+ var row = this.sourceIdToRowMap_[id];
+ if (!row) {
+ var newRow = new WaterfallRow(
+ this, sourceEntry, eventObject.importantEventTypes);
+ if (newRow == undefined) {
+ console.log(sourceEntry);
+ }
+ this.sourceIdToRowMap_[id] = newRow;
+ } else {
+ row.onSourceUpdated();
+ }
}
}
}
+ this.updateTimeScale_(this.scaleFactor_);
},
onAllSourceEntriesDeleted: function() {
@@ -103,28 +126,65 @@
},
/**
- * Changes width of the bars such that horizontally, everything fits into
- * the user's current window size.
- * TODO(viona): Deal with the magic number.
+ * Changes scroll position of the window such that horizontally, everything
+ * within the specified range fits into the user's viewport.
+ * TODO(viona): Find a way to get rid of the magic number.
*/
- adjustToWindow_: function() {
- var usedWidth = $(WaterfallView.SOURCE_HEADER_ID).offsetWidth +
- $(WaterfallView.ID_HEADER_ID).offsetWidth;
- var availableWidth = ($(WaterfallView.MAIN_BOX_ID).offsetWidth -
- usedWidth - 50);
- if (availableWidth <= 0) {
- availableWidth = 1;
- }
+ adjustToWindow_: function(windowStart, windowEnd) {
+ var maxWidth = $(WaterfallView.MAIN_BOX_ID).offsetWidth - 50;
+ $(WaterfallView.TBODY_ID).width = maxWidth + 'px';
var totalDuration = 0;
- for (var id in this.sourceIdToRowMap_) {
- var row = this.sourceIdToRowMap_[id];
- var rowDuration = row.getEndTime() - this.startTime_;
- if (totalDuration < rowDuration) {
- totalDuration = rowDuration;
+ if (windowEnd != -1) {
+ totalDuration = windowEnd - windowStart;
+ } else {
+ for (var id in this.sourceIdToRowMap_) {
+ var row = this.sourceIdToRowMap_[id];
+ var rowDuration = row.getEndTime() - this.startTime_;
+ if (totalDuration < rowDuration && !row.hide) {
+ totalDuration = rowDuration;
+ }
}
}
- var scaleFactor = availableWidth / totalDuration;
- this.scaleAll_(scaleFactor);
+ if (totalDuration <= 0) {
+ return;
+ }
+ this.scaleAll_(maxWidth / totalDuration);
+ var waterfallLeft = $(WaterfallView.TIME_SCALE_HEADER_ID).offsetLeft;
+ $(WaterfallView.MAIN_BOX_ID).scrollLeft =
+ windowStart * this.scaleFactor_ + waterfallLeft;
+ },
+
+ // Updates the time tick indicators.
+ updateTimeScale_: function(scaleFactor) {
+ var timePerTick = 1;
+ var minTickDistance = 20;
+
+ $(WaterfallView.TIME_SCALE_HEADER_ID).innerHTML = '';
+
+ // Holder provides environment to prevent wrapping.
+ var timeTickRow = addNode($(WaterfallView.TIME_SCALE_HEADER_ID), 'div');
+ timeTickRow.classList.add('waterfall-view-time-scale-row');
+
+ var availableWidth = $(WaterfallView.TBODY_ID).clientWidth;
+ var tickDistance = scaleFactor * timePerTick;
+
+ while (tickDistance < minTickDistance) {
+ timePerTick = timePerTick * 10;
+ tickDistance = scaleFactor * timePerTick;
+ }
+
+ var tickCount = availableWidth / tickDistance;
+ for (var i = 0; i < tickCount; ++i) {
+ var timeCell = addNode(timeTickRow, 'div');
+ setNodeWidth(timeCell, tickDistance);
+ timeCell.classList.add('waterfall-view-time-scale');
+ timeCell.title = i * timePerTick + ' to ' +
+ (i + 1) * timePerTick + ' ms';
+ // Red marker for every 5th bar.
+ if (i % 5 == 0) {
+ timeCell.classList.add('waterfall-view-time-scale-special');
+ }
+ }
},
/**
@@ -136,6 +196,76 @@
var row = this.sourceIdToRowMap_[id];
row.updateRow();
}
+ this.updateTimeScale_(scaleFactor);
+ },
+
+ scrollToZoom_: function(event) {
+ // To use scrolling to control zoom, hold down the alt key and scroll.
+ if ('wheelDelta' in event && event.altKey) {
+ var zoomFactor = Math.pow(MOUSE_WHEEL_ZOOM_RATE,
+ event.wheelDeltaY / MOUSE_WHEEL_UNITS_PER_CLICK);
+
+ var waterfallLeft = $(WaterfallView.TIME_SCALE_HEADER_ID).offsetLeft;
+ var oldCursorPosition = event.pageX +
+ $(WaterfallView.MAIN_BOX_ID).scrollLeft;
+ var oldCursorPositionInTable = oldCursorPosition - waterfallLeft;
+
+ this.scaleAll_(this.scaleFactor_ * zoomFactor);
+
+ // Shifts the view when scrolling. newScroll could be less than 0 or
+ // more than the maximum scroll position, but both cases are handled
+ // by the inbuilt scrollLeft implementation.
+ var newScroll =
+ oldCursorPositionInTable * zoomFactor - event.pageX + waterfallLeft;
+ $(WaterfallView.MAIN_BOX_ID).scrollLeft = newScroll;
+ }
+ },
+
+ // Parses user input, then calls adjustToWindow to shift that into view.
+ setStartEndTimes_: function() {
+ var windowStart = parseInt($(WaterfallView.START_TIME_ID).value);
+ var windowEnd = parseInt($(WaterfallView.END_TIME_ID).value);
+ if ($(WaterfallView.END_TIME_ID).value == '') {
+ windowEnd = -1;
+ }
+ if ($(WaterfallView.START_TIME_ID).value == '') {
+ windowStart = 0;
+ }
+ this.adjustToWindow_(windowStart, windowEnd);
+ },
+
+ // Provides a structure that can be used to define source entry types and
+ // the log entries that are of interest.
+ createEventsList_: function() {
+ var eventsList = [];
+ // Creating list of events.
+ // TODO(viona): This is hard-coded. Consider user-input.
+ // Also, work on getting socket information inlined in the
+ // relevant URL_REQUEST events.
+ var urlRequestEvents = [
+ EventType.HTTP_STREAM_REQUEST,
+ EventType.HTTP_STREAM_REQUEST_BOUND_TO_JOB,
+ EventType.HTTP_TRANSACTION_READ_HEADERS
+ ];
+
+ eventsList.push(this.createEventTypeObjects_(
+ EventSourceType.URL_REQUEST, urlRequestEvents));
+
+ var httpStreamJobEvents = [EventType.PROXY_SERVICE];
+ eventsList.push(this.createEventTypeObjects_(
+ EventSourceType.HTTP_STREAM_JOB, httpStreamJobEvents));
+
+ return eventsList;
+ },
+
+ // Creates objects that can be used to define source entry types and
+ // the log entries that are of interest.
+ createEventTypeObjects_: function(mainEventType, eventTypesList) {
+ var eventTypeObject = {
+ mainEvent: mainEventType,
+ importantEventTypes: eventTypesList
+ };
+ return eventTypeObject;
},
};
diff --git a/chrome/browser/resources/print_preview/print_preview.css b/chrome/browser/resources/print_preview/print_preview.css
index ed5424c..9369e1a 100644
--- a/chrome/browser/resources/print_preview/print_preview.css
+++ b/chrome/browser/resources/print_preview/print_preview.css
@@ -295,3 +295,9 @@
height: 100%;
position: relative;
}
+
+html:not(.focus-outline-visible)
+:enabled:focus:-webkit-any(input[type='checkbox'],input[type='radio'],button) {
+ /* Cancel border-color for :focus specified in widgets.css. */
+ border-color: rgba(0,0,0,0.25);
+}
diff --git a/chrome/browser/resources/print_preview/print_preview.html b/chrome/browser/resources/print_preview/print_preview.html
index e246549..1133332 100644
--- a/chrome/browser/resources/print_preview/print_preview.html
+++ b/chrome/browser/resources/print_preview/print_preview.html
@@ -1,5 +1,5 @@
<!DOCTYPE html>
-<html i18n-values="dir:textdirection;" id="print-preview">
+<html i18n-values="dir:textdirection;" id="print-preview" class="focus-outline-visible">
<head>
<meta charset="utf-8">
@@ -29,6 +29,8 @@
<script src="chrome://print/strings.js"></script>
<script src="chrome://resources/js/cr.js"></script>
<script src="chrome://resources/js/cr/event_target.js"></script>
+ <script src="chrome://resources/js/cr/ui.js"></script>
+ <script src="chrome://resources/js/cr/ui/focus_outline_manager.js"></script>
<script src="chrome://resources/js/event_tracker.js"></script>
<script src="chrome://resources/js/local_strings.js"></script>
<script src="chrome://resources/js/util.js"></script>
diff --git a/chrome/browser/resources/print_preview/print_preview.js b/chrome/browser/resources/print_preview/print_preview.js
index 0fc07b7..4f906bd 100644
--- a/chrome/browser/resources/print_preview/print_preview.js
+++ b/chrome/browser/resources/print_preview/print_preview.js
@@ -227,6 +227,7 @@
}
this.nativeLayer_.startGetInitialSettings();
this.destinationStore_.startLoadLocalDestinations();
+ cr.ui.FocusOutlineManager.forDocument(document);
},
/** @override */
diff --git a/chrome/browser/safe_browsing/client_side_detection_host.cc b/chrome/browser/safe_browsing/client_side_detection_host.cc
index 5c5a781..1f67d5c 100644
--- a/chrome/browser/safe_browsing/client_side_detection_host.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_host.cc
@@ -177,18 +177,22 @@
return;
}
+ bool malware_killswitch_on = database_manager_->IsMalwareKillSwitchOn();
+
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
- base::Bind(&ShouldClassifyUrlRequest::CheckCache, this));
+ base::Bind(&ShouldClassifyUrlRequest::CheckCache, this,
+ malware_killswitch_on));
}
- void CheckCache() {
+ void CheckCache(bool malware_killswitch_on) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (canceled_) {
return;
}
+ host_->SetMalwareKillSwitch(malware_killswitch_on);
// If result is cached, we don't want to run classification again
bool is_phishing;
if (csd_service_->GetValidCachedResult(params_.url, &is_phishing)) {
@@ -251,6 +255,7 @@
csd_service_(NULL),
weak_factory_(this),
unsafe_unique_page_id_(-1),
+ malware_killswitch_on_(false),
malware_report_enabled_(false) {
DCHECK(tab);
// Note: csd_service_ and sb_service will be NULL here in testing.
@@ -386,15 +391,16 @@
browse_info_.get() &&
verdict->ParseFromString(verdict_str) &&
verdict->IsInitialized()) {
- if (malware_report_enabled_) {
+ // We do the malware IP matching and request sending if the feature
+ // is enabled.
+ if (malware_report_enabled_ && !MalwareKillSwitchIsOn()) {
scoped_ptr<ClientMalwareRequest> malware_verdict(
new ClientMalwareRequest);
// Start browser-side malware feature extraction. Once we're done it will
// send the malware client verdict request.
malware_verdict->set_url(verdict->url());
feature_extractor_->ExtractMalwareFeatures(
- browse_info_.get(),
- malware_verdict.get());
+ browse_info_.get(), malware_verdict.get());
MalwareFeatureExtractionDone(malware_verdict.Pass());
}
@@ -512,7 +518,8 @@
DCHECK_EQ(type, content::NOTIFICATION_RESOURCE_RESPONSE_STARTED);
const ResourceRequestDetails* req = content::Details<ResourceRequestDetails>(
details).ptr();
- if (req && browse_info_.get()) {
+ if (req && browse_info_.get() && malware_report_enabled_ &&
+ !MalwareKillSwitchIsOn()) {
UpdateIPHostMap(req->socket_address.host() /* ip */,
req->url.host() /* url host */);
}
@@ -545,4 +552,14 @@
database_manager_ = database_manager;
}
+bool ClientSideDetectionHost::MalwareKillSwitchIsOn() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ return malware_killswitch_on_;
+}
+
+void ClientSideDetectionHost::SetMalwareKillSwitch(bool killswitch_on) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ malware_killswitch_on_ = killswitch_on;
+}
+
} // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/client_side_detection_host.h b/chrome/browser/safe_browsing/client_side_detection_host.h
index 7329f52..7f3e93e 100644
--- a/chrome/browser/safe_browsing/client_side_detection_host.h
+++ b/chrome/browser/safe_browsing/client_side_detection_host.h
@@ -102,6 +102,10 @@
SafeBrowsingUIManager* ui_manager,
SafeBrowsingDatabaseManager* database_manager);
+ // Get/Set malware_killswitch_on_ value. These methods called on UI thread.
+ bool MalwareKillSwitchIsOn();
+ void SetMalwareKillSwitch(bool killswitch_on);
+
// This pointer may be NULL if client-side phishing detection is disabled.
ClientSideDetectionService* csd_service_;
// These pointers may be NULL if SafeBrowsing is disabled.
@@ -137,8 +141,14 @@
int unsafe_unique_page_id_;
scoped_ptr<SafeBrowsingUIManager::UnsafeResource> unsafe_resource_;
+ // Whether the malware IP matching feature killswitch is on.
+ // This should be accessed from UI thread.
+ bool malware_killswitch_on_;
+
// Whether the malware bad ip matching and report feature is enabled.
+ // This should be accessed from UI thread.
bool malware_report_enabled_;
+
DISALLOW_COPY_AND_ASSIGN(ClientSideDetectionHost);
};
diff --git a/chrome/browser/safe_browsing/database_manager.cc b/chrome/browser/safe_browsing/database_manager.cc
index 47b238d..db0963a 100644
--- a/chrome/browser/safe_browsing/database_manager.cc
+++ b/chrome/browser/safe_browsing/database_manager.cc
@@ -306,6 +306,14 @@
return database_->ContainsDownloadWhitelistedString(str);
}
+bool SafeBrowsingDatabaseManager::IsMalwareKillSwitchOn() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (!enabled_ || !MakeDatabaseAvailable()) {
+ return true;
+ }
+ return database_->IsMalwareIPMatchKillSwitchOn();
+}
+
bool SafeBrowsingDatabaseManager::CheckBrowseUrl(const GURL& url,
Client* client) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
diff --git a/chrome/browser/safe_browsing/database_manager.h b/chrome/browser/safe_browsing/database_manager.h
index 09f64bd..acc38ef 100644
--- a/chrome/browser/safe_browsing/database_manager.h
+++ b/chrome/browser/safe_browsing/database_manager.h
@@ -172,6 +172,9 @@
// This method is expected to be called on the IO thread.
virtual bool MatchDownloadWhitelistString(const std::string& str);
+ // Check if the CSD malware IP matching kill switch is turned on.
+ virtual bool IsMalwareKillSwitchOn();
+
// Called on the IO thread to cancel a pending check if the result is no
// longer needed.
void CancelCheck(Client* client);
diff --git a/chrome/browser/safe_browsing/download_protection_service.cc b/chrome/browser/safe_browsing/download_protection_service.cc
index 62c12fa..6756bbf 100644
--- a/chrome/browser/safe_browsing/download_protection_service.cc
+++ b/chrome/browser/safe_browsing/download_protection_service.cc
@@ -10,6 +10,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/metrics/histogram.h"
+#include "base/metrics/sparse_histogram.h"
#include "base/sequenced_task_runner_helpers.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
@@ -388,6 +389,14 @@
<< item_->GetUrlChain().back() << ": success="
<< source->GetStatus().is_success() << " response_code="
<< source->GetResponseCode();
+ if (source->GetStatus().is_success()) {
+ UMA_HISTOGRAM_SPARSE_SLOWLY(
+ "SBClientDownload.DownloadRequestResponseCode",
+ source->GetResponseCode());
+ }
+ UMA_HISTOGRAM_SPARSE_SLOWLY(
+ "SBClientDownload.DownloadRequestNetError",
+ -source->GetStatus().error());
DownloadCheckResultReason reason = REASON_SERVER_PING_FAILED;
DownloadCheckResult result = SAFE;
if (source->GetStatus().is_success() &&
diff --git a/chrome/browser/safe_browsing/safe_browsing_database.cc b/chrome/browser/safe_browsing/safe_browsing_database.cc
index 9f43ecd..b193f50 100644
--- a/chrome/browser/safe_browsing/safe_browsing_database.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_database.cc
@@ -12,6 +12,7 @@
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/metrics/stats_counters.h"
+#include "base/process/process.h"
#include "base/process/process_metrics.h"
#include "base/time/time.h"
#include "chrome/browser/safe_browsing/prefix_set.h"
@@ -70,6 +71,12 @@
const char kWhitelistKillSwitchUrl[] =
"sb-ssl.google.com/safebrowsing/csd/killswitch"; // Don't change this!
+// If the hash of this exact expression is on a whitelist then the
+// malware IP blacklisting feature will be disabled in csd.
+// Don't change this!
+const char kMalwareIPKillSwitchUrl[] =
+ "sb-ssl.google.com/safebrowsing/csd/killswitch_malware";
+
// To save space, the incoming |chunk_id| and |list_id| are combined
// into an |encoded_chunk_id| for storage by shifting the |list_id|
// into the low-order bits. These functions decode that information.
@@ -1605,3 +1612,12 @@
whitelist->first.swap(new_whitelist);
}
}
+
+bool SafeBrowsingDatabaseNew::IsMalwareIPMatchKillSwitchOn() {
+ SBFullHash malware_kill_switch;
+ crypto::SHA256HashString(kMalwareIPKillSwitchUrl, &malware_kill_switch,
+ sizeof(malware_kill_switch));
+ std::vector<SBFullHash> full_hashes;
+ full_hashes.push_back(malware_kill_switch);
+ return ContainsWhitelistedHashes(csd_whitelist_, full_hashes);
+}
diff --git a/chrome/browser/safe_browsing/safe_browsing_database.h b/chrome/browser/safe_browsing/safe_browsing_database.h
index 219f1ea..6446e35 100644
--- a/chrome/browser/safe_browsing/safe_browsing_database.h
+++ b/chrome/browser/safe_browsing/safe_browsing_database.h
@@ -171,6 +171,10 @@
const std::vector<SBPrefix>& prefixes,
const std::vector<SBFullHashResult>& full_hits) = 0;
+ // Returns true if the malware IP blacklisting killswitch URL is present
+ // in the csd whitelist.
+ virtual bool IsMalwareIPMatchKillSwitchOn() = 0;
+
// The name of the bloom-filter file for the given database file.
// NOTE(shess): OBSOLETE. Present for deleting stale files.
static base::FilePath BloomFilterForFilename(
@@ -297,6 +301,9 @@
const std::vector<SBPrefix>& prefixes,
const std::vector<SBFullHashResult>& full_hits) OVERRIDE;
+ // Returns the value of malware_kill_switch_;
+ virtual bool IsMalwareIPMatchKillSwitchOn() OVERRIDE;
+
private:
friend class SafeBrowsingDatabaseTest;
FRIEND_TEST_ALL_PREFIXES(SafeBrowsingDatabaseTest, HashCaching);
@@ -368,8 +375,7 @@
// Lock for protecting access to variables that may be used on the
// IO thread. This includes |prefix_set_|, |full_browse_hashes_|,
- // |pending_browse_hashes_|, |prefix_miss_cache_|, |csd_whitelist_|,
- // and |csd_whitelist_all_urls_|.
+ // |pending_browse_hashes_|, |prefix_miss_cache_|, |csd_whitelist_|.
base::Lock lookup_lock_;
// Underlying persistent store for chunk data.
diff --git a/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc b/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc
index ec50a66..7e934a9 100644
--- a/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc
@@ -1365,6 +1365,19 @@
EXPECT_FALSE(database_->ContainsDownloadWhitelistedUrl(
GURL(std::string("http://www.google.com/"))));
+ // Test only add the malware IP killswitch
+ csd_chunks.clear();
+ chunk.hosts.clear();
+ InsertAddChunkHostFullHashes(
+ &chunk, 15, "sb-ssl.google.com/",
+ "sb-ssl.google.com/safebrowsing/csd/killswitch_malware");
+ csd_chunks.push_back(chunk);
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
+ database_->InsertChunks(safe_browsing_util::kCsdWhiteList, csd_chunks);
+ database_->UpdateFinished(true);
+
+ EXPECT_TRUE(database_->IsMalwareIPMatchKillSwitchOn());
+
// Test that the kill-switch works as intended.
csd_chunks.clear();
download_chunks.clear();
@@ -1373,7 +1386,6 @@
InsertAddChunkHostFullHashes(&chunk, 5, "sb-ssl.google.com/",
"sb-ssl.google.com/safebrowsing/csd/killswitch");
csd_chunks.push_back(chunk);
-
chunk.hosts.clear();
InsertAddChunkHostFullHashes(&chunk, 5, "sb-ssl.google.com/",
"sb-ssl.google.com/safebrowsing/csd/killswitch");
@@ -1385,6 +1397,7 @@
download_chunks);
database_->UpdateFinished(true);
+ EXPECT_TRUE(database_->IsMalwareIPMatchKillSwitchOn());
EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
GURL(std::string("https://") + kGood1Url2 + "/c.html")));
EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
@@ -1413,6 +1426,12 @@
csd_chunks.push_back(sub_chunk);
sub_chunk.hosts.clear();
+ InsertSubChunkHostFullHash(
+ &sub_chunk, 10, 15, "sb-ssl.google.com/",
+ "sb-ssl.google.com/safebrowsing/csd/killswitch_malware");
+ csd_chunks.push_back(sub_chunk);
+
+ sub_chunk.hosts.clear();
InsertSubChunkHostFullHash(&sub_chunk, 1, 5,
"sb-ssl.google.com/",
"sb-ssl.google.com/safebrowsing/csd/killswitch");
@@ -1424,6 +1443,7 @@
download_chunks);
database_->UpdateFinished(true);
+ EXPECT_FALSE(database_->IsMalwareIPMatchKillSwitchOn());
EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
GURL(std::string("https://") + kGood1Url2 + "/c.html")));
EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
diff --git a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
index 20543d5..c36e23f 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
@@ -143,6 +143,9 @@
const std::vector<SBFullHashResult>& full_hits) OVERRIDE {
// Do nothing for the cache.
}
+ virtual bool IsMalwareIPMatchKillSwitchOn() OVERRIDE {
+ return false;
+ }
// Fill up the database with test URL.
void AddUrl(const GURL& url,
diff --git a/chrome/browser/search/search.cc b/chrome/browser/search/search.cc
index 883c43e..291fb08 100644
--- a/chrome/browser/search/search.cc
+++ b/chrome/browser/search/search.cc
@@ -161,6 +161,13 @@
google_util::StartsWithCommandLineGoogleBaseURL(url));
}
+// Returns true if |url| matches --instant-new-tab-url.
+bool IsCommandLineInstantNTPURL(const GURL& url) {
+ const GURL ntp_url(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kInstantNewTabURL));
+ return ntp_url.is_valid() && MatchesOriginAndPath(ntp_url, url);
+}
+
// Returns true if |url| can be used as an Instant URL for |profile|.
bool IsInstantURL(const GURL& url, Profile* profile) {
if (!IsInstantExtendedAPIEnabled())
@@ -169,6 +176,9 @@
if (!url.is_valid())
return false;
+ if (IsCommandLineInstantNTPURL(url))
+ return true;
+
TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
if (!template_url)
return false;
@@ -316,11 +326,16 @@
return false;
Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
- return IsInstantExtendedAPIEnabled() &&
- IsRenderedInInstantProcess(contents, profile) &&
- (IsInstantURL(entry->GetVirtualURL(), profile) ||
- entry->GetVirtualURL() == GetLocalInstantURL(profile)) &&
- GetSearchTermsImpl(contents, entry).empty();
+ if (!IsInstantExtendedAPIEnabled() ||
+ !IsRenderedInInstantProcess(contents, profile))
+ return false;
+
+ if (IsInstantURL(entry->GetVirtualURL(), profile) ||
+ entry->GetVirtualURL() == GetLocalInstantURL(profile))
+ return GetSearchTermsImpl(contents, entry).empty();
+
+ return entry->GetVirtualURL() == GURL(chrome::kChromeUINewTabURL) &&
+ IsCommandLineInstantNTPURL(entry->GetURL());
}
bool IsSuggestPrefEnabled(Profile* profile) {
@@ -380,6 +395,12 @@
}
bool ShouldShowInstantNTP() {
+ // If the instant-new-tab-url flag is set, we'll always just load the NTP
+ // directly instead of preloading contents using InstantNTP.
+ const CommandLine* command_line = CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(switches::kInstantNewTabURL))
+ return false;
+
FieldTrialFlags flags;
if (GetFieldTrialInfo(
base::FieldTrialList::FindFullName(kInstantExtendedFieldTrialName),
@@ -478,6 +499,39 @@
return false;
}
+bool HandleNewTabURLRewrite(GURL* url,
+ content::BrowserContext* browser_context) {
+ if (!IsInstantExtendedAPIEnabled())
+ return false;
+
+ if (!url->SchemeIs(chrome::kChromeUIScheme) ||
+ url->host() != chrome::kChromeUINewTabHost)
+ return false;
+
+ const GURL ntp_url(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kInstantNewTabURL));
+ if (!ntp_url.is_valid())
+ return false;
+
+ *url = ntp_url;
+ return true;
+}
+
+bool HandleNewTabURLReverseRewrite(GURL* url,
+ content::BrowserContext* browser_context) {
+ if (!IsInstantExtendedAPIEnabled())
+ return false;
+
+ const GURL ntp_url(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kInstantNewTabURL));
+ if (!MatchesOriginAndPath(ntp_url, *url))
+ return false;
+
+ *url = GURL(chrome::kChromeUINewTabURL);
+ return true;
+}
+
+
void EnableInstantExtendedAPIForTesting() {
CommandLine* cl = CommandLine::ForCurrentProcess();
cl->AppendSwitch(switches::kEnableInstantExtendedAPI);
diff --git a/chrome/browser/search/search.h b/chrome/browser/search/search.h
index 7f1bf78..ef59f2d 100644
--- a/chrome/browser/search/search.h
+++ b/chrome/browser/search/search.h
@@ -18,6 +18,7 @@
class TemplateURLRef;
namespace content {
+class BrowserContext;
class NavigationEntry;
class WebContents;
}
@@ -147,6 +148,17 @@
// Returns true if |contents| corresponds to a preloaded instant extended NTP.
bool IsPreloadedInstantExtendedNTP(const content::WebContents* contents);
+// Rewrites |url| if
+// 1. |url| is kChromeUINewTabURL,
+// 2. InstantExtended is enabled, and
+// 3. The --instant-new-tab-url switch is set to a valid URL.
+// |url| is rewritten to the value of --instant-new-tab-url.
+bool HandleNewTabURLRewrite(GURL* url,
+ content::BrowserContext* browser_context);
+// Reverses the operation from HandleNewTabURLRewrite.
+bool HandleNewTabURLReverseRewrite(GURL* url,
+ content::BrowserContext* browser_context);
+
// -----------------------------------------------------
// The following APIs are exposed for use in tests only.
// -----------------------------------------------------
diff --git a/chrome/browser/search/search_unittest.cc b/chrome/browser/search/search_unittest.cc
index c986500..925a56d 100644
--- a/chrome/browser/search/search_unittest.cc
+++ b/chrome/browser/search/search_unittest.cc
@@ -583,4 +583,23 @@
EXPECT_EQ("http://www.bar.com/webhp?a=b&strk", instant_url.spec());
}
+TEST_F(SearchTest, ShouldShowInstantNTP_Default) {
+ EnableInstantExtendedAPIForTesting();
+ EXPECT_TRUE(ShouldShowInstantNTP());
+}
+
+TEST_F(SearchTest, ShouldShowInstantNTP_DisabledViaFinch) {
+ EnableInstantExtendedAPIForTesting();
+ ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("InstantExtended",
+ "Group1 show_ntp:0"));
+ EXPECT_FALSE(ShouldShowInstantNTP());
+}
+
+TEST_F(SearchTest, ShouldShowInstantNTP_DisabledByInstantNewTabURLSwitch) {
+ EnableInstantExtendedAPIForTesting();
+ CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kInstantNewTabURL, "http://example.com/newtab");
+ EXPECT_FALSE(ShouldShowInstantNTP());
+}
+
} // namespace chrome
diff --git a/chrome/browser/signin/oauth2_token_service.cc b/chrome/browser/signin/oauth2_token_service.cc
index 1790aea..1cc4e18 100644
--- a/chrome/browser/signin/oauth2_token_service.cc
+++ b/chrome/browser/signin/oauth2_token_service.cc
@@ -309,6 +309,14 @@
scoped_ptr<OAuth2TokenService::Request> OAuth2TokenService::StartRequest(
const OAuth2TokenService::ScopeSet& scopes,
OAuth2TokenService::Consumer* consumer) {
+ return StartRequestWithContext(GetRequestContext(), scopes, consumer);
+}
+
+scoped_ptr<OAuth2TokenService::Request>
+OAuth2TokenService::StartRequestWithContext(
+ net::URLRequestContextGetter* getter,
+ const ScopeSet& scopes,
+ Consumer* consumer) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
scoped_ptr<RequestImpl> request(new RequestImpl(consumer));
@@ -340,10 +348,7 @@
}
pending_fetchers_[fetch_parameters] =
- Fetcher::CreateAndStart(this,
- GetRequestContext(),
- refresh_token,
- scopes,
+ Fetcher::CreateAndStart(this, getter, refresh_token, scopes,
request->AsWeakPtr());
return request.PassAs<Request>();
}
diff --git a/chrome/browser/signin/oauth2_token_service.h b/chrome/browser/signin/oauth2_token_service.h
index b40066e..d979fcf 100644
--- a/chrome/browser/signin/oauth2_token_service.h
+++ b/chrome/browser/signin/oauth2_token_service.h
@@ -117,6 +117,14 @@
virtual scoped_ptr<Request> StartRequest(const ScopeSet& scopes,
Consumer* consumer);
+ // This method does the same as |StartRequest| except it uses the request
+ // context given by |getter| instead of using the one returned by
+ // |GetRequestContext| implemented by derived classes.
+ virtual scoped_ptr<Request> StartRequestWithContext(
+ net::URLRequestContextGetter* getter,
+ const ScopeSet& scopes,
+ Consumer* consumer);
+
// Returns true if a refresh token exists. If false, calls to
// |StartRequest| will result in a Consumer::OnGetTokenFailure callback.
virtual bool RefreshTokenIsAvailable();
diff --git a/chrome/browser/signin/signin_manager.cc b/chrome/browser/signin/signin_manager.cc
index f419d84..09a4862 100644
--- a/chrome/browser/signin/signin_manager.cc
+++ b/chrome/browser/signin/signin_manager.cc
@@ -125,18 +125,6 @@
token_service->LoadTokensFromDB();
}
-void SigninManager::CleanupNotificationRegistration() {
- content::Source<TokenService> token_service(
- TokenServiceFactory::GetForProfile(profile_));
- if (registrar_.IsRegistered(this,
- chrome::NOTIFICATION_TOKEN_AVAILABLE,
- token_service)) {
- registrar_.Remove(this,
- chrome::NOTIFICATION_TOKEN_AVAILABLE,
- token_service);
- }
-}
-
std::string SigninManager::SigninTypeToString(
SigninManager::SigninType type) {
switch (type) {
@@ -202,15 +190,6 @@
login_token,
login_captcha,
GaiaAuthFetcher::HostedAccountsNotAllowed);
-
- // Register for token availability. The signin manager will pre-login the
- // user when the GAIA service token is ready for use.
- if (delegate_->AreSigninCookiesAllowed()) {
- TokenService* token_service = TokenServiceFactory::GetForProfile(profile_);
- registrar_.Add(this,
- chrome::NOTIFICATION_TOKEN_AVAILABLE,
- content::Source<TokenService>(token_service));
- }
}
void SigninManager::ProvideSecondFactorAccessCode(
@@ -312,7 +291,6 @@
void SigninManager::ClearTransientSigninData() {
DCHECK(IsInitialized());
- CleanupNotificationRegistration();
client_login_.reset();
last_result_ = ClientLoginResult();
possibly_invalid_username_.clear();
@@ -409,6 +387,11 @@
}
}
+void SigninManager::Shutdown() {
+ local_state_pref_registrar_.RemoveAll();
+ SigninManagerBase::Shutdown();
+}
+
void SigninManager::OnGoogleServicesUsernamePatternChanged() {
if (!GetAuthenticatedUsername().empty() &&
!IsAllowedUsername(GetAuthenticatedUsername())) {
@@ -651,60 +634,21 @@
OnClientLoginFailure(error);
}
-void SigninManager::OnUbertokenSuccess(const std::string& token) {
- ubertoken_fetcher_.reset();
- if (client_login_.get() == NULL) {
- client_login_.reset(
- new GaiaAuthFetcher(this,
- GaiaConstants::kChromeSource,
- profile_->GetRequestContext()));
- }
-
- client_login_->StartMergeSession(token);
-}
-
-void SigninManager::OnUbertokenFailure(const GoogleServiceAuthError& error) {
- LOG(WARNING) << " Unable to login the user to the web: " << error.ToString();
- ubertoken_fetcher_.reset();
-}
-
void SigninManager::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
- switch (type) {
- case chrome::NOTIFICATION_TOKEN_AVAILABLE: {
- TokenService::TokenAvailableDetails* tok_details =
- content::Details<TokenService::TokenAvailableDetails>(
- details).ptr();
+ DCHECK_EQ(content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, type);
- // If a GAIA service token has become available, use it to pre-login the
- // user to other services that depend on GAIA credentials.
- if (tok_details->service() ==
- GaiaConstants::kGaiaOAuth2LoginRefreshToken) {
- ubertoken_fetcher_.reset(new UbertokenFetcher(profile_, this));
- ubertoken_fetcher_->StartFetchingToken();
-
- // We only want to do this once per sign-in.
- CleanupNotificationRegistration();
- }
- break;
- }
- case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: {
- // It's possible we're listening to a "stale" renderer because it was
- // replaced with a new process by process-per-site. In either case,
- // stop listening to it, but only reset signin_process_id_ tracking
- // if this was from the current signin process.
- registrar_.Remove(this,
- content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
- source);
- if (signin_process_id_ ==
- content::Source<content::RenderProcessHost>(source)->GetID()) {
- signin_process_id_ = kInvalidProcessId;
- }
- break;
- }
- default:
- NOTREACHED();
+ // It's possible we're listening to a "stale" renderer because it was
+ // replaced with a new process by process-per-site. In either case,
+ // stop listening to it, but only reset signin_process_id_ tracking
+ // if this was from the current signin process.
+ registrar_.Remove(this,
+ content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
+ source);
+ if (signin_process_id_ ==
+ content::Source<content::RenderProcessHost>(source)->GetID()) {
+ signin_process_id_ = kInvalidProcessId;
}
}
diff --git a/chrome/browser/signin/signin_manager.h b/chrome/browser/signin/signin_manager.h
index 1e84e0a..3c54c94 100644
--- a/chrome/browser/signin/signin_manager.h
+++ b/chrome/browser/signin/signin_manager.h
@@ -33,7 +33,6 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/signin_internals_util.h"
#include "chrome/browser/signin/signin_manager_base.h"
-#include "chrome/browser/signin/ubertoken_fetcher.h"
#include "components/browser_context_keyed_service/browser_context_keyed_service.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
@@ -50,7 +49,6 @@
class SigninManager : public SigninManagerBase,
public GaiaAuthConsumer,
- public UbertokenConsumer,
public content::NotificationObserver {
public:
// The callback invoked once the OAuth token has been fetched during signin,
@@ -120,6 +118,7 @@
// invalid username policy updates, we need to check this during
// initialization and sign the user out.
virtual void Initialize(Profile* profile, PrefService* local_state) OVERRIDE;
+ virtual void Shutdown() OVERRIDE;
// Invoked from an OAuthTokenFetchedCallback to complete user signin.
virtual void CompletePendingSignin();
@@ -161,10 +160,6 @@
virtual void OnGetUserInfoFailure(
const GoogleServiceAuthError& error) OVERRIDE;
- // UbertokenConsumer
- virtual void OnUbertokenSuccess(const std::string& token) OVERRIDE;
- virtual void OnUbertokenFailure(const GoogleServiceAuthError& error) OVERRIDE;
-
// content::NotificationObserver
virtual void Observe(int type,
const content::NotificationSource& source,
@@ -260,8 +255,6 @@
std::string password_; // This is kept empty whenever possible.
bool had_two_factor_error_;
- void CleanupNotificationRegistration();
-
// Result of the last client login, kept pending the lookup of the
// canonical email.
ClientLoginResult last_result_;
@@ -272,9 +265,6 @@
// Registrar for notifications from the TokenService.
content::NotificationRegistrar registrar_;
- // UbertokenFetcher to login to user to the web property.
- scoped_ptr<UbertokenFetcher> ubertoken_fetcher_;
-
// OAuth revocation fetcher for sign outs.
scoped_ptr<GaiaAuthFetcher> revoke_token_fetcher_;
diff --git a/chrome/browser/signin/ubertoken_fetcher.cc b/chrome/browser/signin/ubertoken_fetcher.cc
index 01d9ad4..b726b70 100644
--- a/chrome/browser/signin/ubertoken_fetcher.cc
+++ b/chrome/browser/signin/ubertoken_fetcher.cc
@@ -7,15 +7,13 @@
#include <vector>
#include "base/logging.h"
-#include "base/strings/stringprintf.h"
-#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/signin/token_service.h"
-#include "chrome/browser/signin/token_service_factory.h"
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
+#include "google_apis/gaia/gaia_auth_fetcher.h"
#include "google_apis/gaia/gaia_constants.h"
#include "google_apis/gaia/gaia_urls.h"
#include "google_apis/gaia/google_service_auth_error.h"
-#include "net/base/load_flags.h"
UbertokenFetcher::UbertokenFetcher(Profile* profile,
UbertokenConsumer* consumer)
@@ -28,86 +26,11 @@
}
void UbertokenFetcher::StartFetchingToken() {
- TokenService* token_service = TokenServiceFactory::GetForProfile(profile_);
- if (token_service->HasOAuthLoginToken()) {
- StartFetchingUbertoken();
- } else {
- registrar_.Add(this,
- chrome::NOTIFICATION_TOKEN_AVAILABLE,
- content::Source<TokenService>(token_service));
- registrar_.Add(this,
- chrome::NOTIFICATION_TOKEN_REQUEST_FAILED,
- content::Source<TokenService>(token_service));
- token_service->StartFetchingTokens();
- }
-}
-
-void UbertokenFetcher::StartFetchingUbertoken() {
- TokenService* token_service = TokenServiceFactory::GetForProfile(profile_);
- DCHECK(token_service->HasOAuthLoginToken());
- gaia::OAuthClientInfo client_info;
- GaiaUrls* urls = GaiaUrls::GetInstance();
- client_info.client_id = urls->oauth2_chrome_client_id();
- client_info.client_secret = urls->oauth2_chrome_client_secret();
- gaia_oauth_client_.reset(new gaia::GaiaOAuthClient(
- profile_->GetRequestContext()));
- std::vector<std::string> empty_scope_list; // (Use scope from refresh token.)
- gaia_oauth_client_->RefreshToken(
- client_info, token_service->GetOAuth2LoginRefreshToken(),
- empty_scope_list, 1, this);
-}
-
-void UbertokenFetcher::Observe(int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) {
- DCHECK(type == chrome::NOTIFICATION_TOKEN_AVAILABLE ||
- type == chrome::NOTIFICATION_TOKEN_REQUEST_FAILED);
-
- if (type == chrome::NOTIFICATION_TOKEN_AVAILABLE) {
- TokenService::TokenAvailableDetails* token_details =
- content::Details<TokenService::TokenAvailableDetails>(details).ptr();
- if (token_details->service() !=
- GaiaConstants::kGaiaOAuth2LoginRefreshToken) {
- return;
- }
- registrar_.RemoveAll();
- StartFetchingUbertoken();
- } else {
- TokenService::TokenRequestFailedDetails* token_details =
- content::Details<TokenService::TokenRequestFailedDetails>(details).
- ptr();
- if (token_details->service() == GaiaConstants::kLSOService ||
- token_details->service() ==
- GaiaConstants::kGaiaOAuth2LoginRefreshToken) {
- consumer_->OnUbertokenFailure(token_details->error());
- }
- }
-}
-
-void UbertokenFetcher::OnGetTokensResponse(const std::string& refresh_token,
- const std::string& access_token,
- int expires_in_seconds) {
- NOTREACHED();
-}
-
-void UbertokenFetcher::OnRefreshTokenResponse(const std::string& access_token,
- int expires_in_seconds) {
- gaia_auth_fetcher_.reset(new GaiaAuthFetcher(this,
- GaiaConstants::kChromeSource,
- profile_->GetRequestContext()));
- gaia_auth_fetcher_->StartTokenFetchForUberAuthExchange(access_token);
-}
-
-void UbertokenFetcher::OnOAuthError() {
- GoogleServiceAuthError error(
- GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
- consumer_->OnUbertokenFailure(error);
-}
-
-void UbertokenFetcher::OnNetworkError(int response_code) {
- GoogleServiceAuthError error =
- GoogleServiceAuthError::FromConnectionError(response_code);
- consumer_->OnUbertokenFailure(error);
+ OAuth2TokenService::ScopeSet scopes;
+ scopes.insert(GaiaUrls::GetInstance()->oauth1_login_scope());
+ access_token_request_ =
+ ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)->
+ StartRequest(scopes, this);
}
void UbertokenFetcher::OnUberAuthTokenSuccess(const std::string& token) {
@@ -118,3 +41,21 @@
const GoogleServiceAuthError& error) {
consumer_->OnUbertokenFailure(error);
}
+
+void UbertokenFetcher::OnGetTokenSuccess(
+ const OAuth2TokenService::Request* request,
+ const std::string& access_token,
+ const base::Time& expiration_time) {
+ access_token_request_.reset();
+ gaia_auth_fetcher_.reset(new GaiaAuthFetcher(this,
+ GaiaConstants::kChromeSource,
+ profile_->GetRequestContext()));
+ gaia_auth_fetcher_->StartTokenFetchForUberAuthExchange(access_token);
+}
+
+void UbertokenFetcher::OnGetTokenFailure(
+ const OAuth2TokenService::Request* request,
+ const GoogleServiceAuthError& error) {
+ access_token_request_.reset();
+ consumer_->OnUbertokenFailure(error);
+}
diff --git a/chrome/browser/signin/ubertoken_fetcher.h b/chrome/browser/signin/ubertoken_fetcher.h
index 3c4a516..b7dd6d0 100644
--- a/chrome/browser/signin/ubertoken_fetcher.h
+++ b/chrome/browser/signin/ubertoken_fetcher.h
@@ -6,24 +6,19 @@
#define CHROME_BROWSER_SIGNIN_UBERTOKEN_FETCHER_H_
#include "base/memory/scoped_ptr.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/notification_source.h"
+#include "chrome/browser/signin/oauth2_token_service.h"
#include "google_apis/gaia/gaia_auth_consumer.h"
-#include "google_apis/gaia/gaia_auth_fetcher.h"
-#include "google_apis/gaia/gaia_oauth_client.h"
// Allow to retrieves an uber-auth token for the user. This class uses the
-// |TokenService| and considers that the user is already logged in. It will then
-// retrieve the OAuth2 refresh token, use it to generate an OAuth2 access token
-// and finally use this access token to generate the uber-auth token.
+// |OAuth2TokenService| and considers that the user is already logged in. It
+// will use the OAuth2 access token to generate the uber-auth token.
//
// 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.
+class GaiaAuthFetcher;
class GoogleServiceAuthError;
class Profile;
@@ -37,9 +32,8 @@
};
// Allows to retrieve an uber-auth token.
-class UbertokenFetcher : public content::NotificationObserver,
- public gaia::GaiaOAuthClient::Delegate,
- public GaiaAuthConsumer {
+class UbertokenFetcher : public GaiaAuthConsumer,
+ public OAuth2TokenService::Consumer {
public:
UbertokenFetcher(Profile* profile, UbertokenConsumer* consumer);
virtual ~UbertokenFetcher();
@@ -47,33 +41,23 @@
// Start fetching the token.
void StartFetchingToken();
- // Overriden from gaia::GaiaOAuthClient::Delegate:
- virtual void OnGetTokensResponse(const std::string& refresh_token,
- const std::string& access_token,
- int expires_in_seconds) OVERRIDE;
- virtual void OnRefreshTokenResponse(const std::string& access_token,
- int expires_in_seconds) OVERRIDE;
- virtual void OnOAuthError() OVERRIDE;
- virtual void OnNetworkError(int response_code) OVERRIDE;
-
// Overriden from GaiaAuthConsumer
virtual void OnUberAuthTokenSuccess(const std::string& token) OVERRIDE;
virtual void OnUberAuthTokenFailure(
const GoogleServiceAuthError& error) OVERRIDE;
- // Overriden from content::NotificationObserver:
- virtual void Observe(int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) OVERRIDE;
+ // Overriden from OAuth2TokenService::Consumer:
+ virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
+ const std::string& access_token,
+ const base::Time& expiration_time) OVERRIDE;
+ virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
+ const GoogleServiceAuthError& error) OVERRIDE;
private:
- void StartFetchingUbertoken();
-
Profile* profile_;
UbertokenConsumer* consumer_;
- content::NotificationRegistrar registrar_;
- scoped_ptr<gaia::GaiaOAuthClient> gaia_oauth_client_;
scoped_ptr<GaiaAuthFetcher> gaia_auth_fetcher_;
+ scoped_ptr<OAuth2TokenService::Request> access_token_request_;
DISALLOW_COPY_AND_ASSIGN(UbertokenFetcher);
};
diff --git a/chrome/browser/signin/ubertoken_fetcher_unittest.cc b/chrome/browser/signin/ubertoken_fetcher_unittest.cc
index ec752c7..90b1d78 100644
--- a/chrome/browser/signin/ubertoken_fetcher_unittest.cc
+++ b/chrome/browser/signin/ubertoken_fetcher_unittest.cc
@@ -4,13 +4,16 @@
#include "chrome/browser/signin/ubertoken_fetcher.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/signin/token_service.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
#include "chrome/browser/signin/token_service_unittest.h"
#include "google_apis/gaia/gaia_constants.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
+namespace {
+
class MockUbertokenConsumer : public UbertokenConsumer {
public:
MockUbertokenConsumer()
@@ -37,15 +40,40 @@
int nb_error_;
};
+class MockOAuth2TokenService : public ProfileOAuth2TokenService {
+ // OAuth2TokenService overrides:
+ virtual scoped_ptr<OAuth2TokenService::Request>
+ StartRequest(const OAuth2TokenService::ScopeSet& scopes,
+ OAuth2TokenService::Consumer* consumer) OVERRIDE {
+ // Don't actually make a request.
+ scoped_ptr<OAuth2TokenService::Request> request;
+ return request.Pass();
+ }
+};
+
+
+BrowserContextKeyedService* Build(content::BrowserContext* profile) {
+ MockOAuth2TokenService* token_service = new MockOAuth2TokenService();
+ token_service->Initialize(static_cast<Profile*>(profile));
+ return token_service;
+}
+
+} // namespace
+
class UbertokenFetcherTest : public TokenServiceTestHarness {
public:
virtual void SetUp() OVERRIDE {
TokenServiceTestHarness::SetUp();
+ profile()->CreateRequestContext(NULL);
+
+ ProfileOAuth2TokenServiceFactory::GetInstance()->
+ SetTestingFactoryAndUse(profile(), Build);
UpdateCredentialsOnService();
fetcher_.reset(new UbertokenFetcher(profile(), &consumer_));
}
virtual void TearDown() OVERRIDE {
+ fetcher_.reset();
TokenServiceTestHarness::TearDown();
}
@@ -55,50 +83,51 @@
scoped_ptr<UbertokenFetcher> fetcher_;
};
-TEST_F(UbertokenFetcherTest, TestSuccessWithoutRefreshToken) {
- fetcher_->StartFetchingToken();
- TokenService::TokenAvailableDetails
- details(GaiaConstants::kGaiaOAuth2LoginRefreshToken, "refreshToken");
+TEST_F(UbertokenFetcherTest, Basic) {
+}
+
+TEST_F(UbertokenFetcherTest, Success) {
service()->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
"refreshToken");
- fetcher_->Observe(chrome::NOTIFICATION_TOKEN_AVAILABLE,
- content::Source<TokenService>(service()),
- content::Details<const TokenService::TokenAvailableDetails>(
- &details));
- fetcher_->OnRefreshTokenResponse("accessToken", 3600);
+ fetcher_->StartFetchingToken();
+ fetcher_->OnGetTokenSuccess(NULL, "accessToken", base::Time());
fetcher_->OnUberAuthTokenSuccess("uberToken");
EXPECT_EQ(0, consumer_.nb_error_);
EXPECT_EQ(1, consumer_.nb_correct_token_);
EXPECT_EQ("uberToken", consumer_.last_token_);
}
-TEST_F(UbertokenFetcherTest, TestSuccessWithRefreshToken) {
- service()->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
- "refreshToken");
+TEST_F(UbertokenFetcherTest, NoRefreshToken) {
fetcher_->StartFetchingToken();
- fetcher_->OnRefreshTokenResponse("accessToken", 3600);
- fetcher_->OnUberAuthTokenSuccess("uberToken");
- EXPECT_EQ(0, consumer_.nb_error_);
- EXPECT_EQ(1, consumer_.nb_correct_token_);
- EXPECT_EQ("uberToken", consumer_.last_token_);
-}
-
-
-TEST_F(UbertokenFetcherTest, TestFailures) {
GoogleServiceAuthError error(GoogleServiceAuthError::USER_NOT_SIGNED_UP);
- EXPECT_EQ(0, consumer_.nb_error_);
- TokenService::TokenRequestFailedDetails
- details(GaiaConstants::kGaiaOAuth2LoginRefreshToken, error);
- fetcher_->Observe(
- chrome::NOTIFICATION_TOKEN_REQUEST_FAILED,
- content::Source<TokenService>(service()),
- content::Details<const TokenService::TokenRequestFailedDetails>(
- &details));
+ fetcher_->OnGetTokenFailure(NULL, error);
EXPECT_EQ(1, consumer_.nb_error_);
- fetcher_->OnOAuthError();
- EXPECT_EQ(2, consumer_.nb_error_);
- fetcher_->OnNetworkError(401);
- EXPECT_EQ(3, consumer_.nb_error_);
+ EXPECT_EQ(0, consumer_.nb_correct_token_);
+}
+
+TEST_F(UbertokenFetcherTest, FailureToGetAccessToken) {
+ GoogleServiceAuthError error(GoogleServiceAuthError::USER_NOT_SIGNED_UP);
+
+ service()->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
+ "refreshToken");
+ fetcher_->StartFetchingToken();
+ fetcher_->OnGetTokenFailure(NULL, error);
+
+ EXPECT_EQ(1, consumer_.nb_error_);
+ EXPECT_EQ(0, consumer_.nb_correct_token_);
+ EXPECT_EQ("", consumer_.last_token_);
+}
+
+TEST_F(UbertokenFetcherTest, FailureToGetUberToken) {
+ GoogleServiceAuthError error(GoogleServiceAuthError::USER_NOT_SIGNED_UP);
+
+ service()->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
+ "refreshToken");
+ fetcher_->StartFetchingToken();
+ fetcher_->OnGetTokenSuccess(NULL, "accessToken", base::Time());
fetcher_->OnUberAuthTokenFailure(error);
- EXPECT_EQ(4, consumer_.nb_error_);
+
+ EXPECT_EQ(1, consumer_.nb_error_);
+ EXPECT_EQ(0, consumer_.nb_correct_token_);
+ EXPECT_EQ("", consumer_.last_token_);
}
diff --git a/chrome/browser/ui/app_list/search/webstore_provider.cc b/chrome/browser/ui/app_list/search/webstore_provider.cc
index 479ded0..761cee0 100644
--- a/chrome/browser/ui/app_list/search/webstore_provider.cc
+++ b/chrome/browser/ui/app_list/search/webstore_provider.cc
@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "base/metrics/field_trial.h"
+#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
@@ -16,6 +17,7 @@
#include "chrome/browser/ui/app_list/search/webstore_result.h"
#include "chrome/browser/ui/app_list/search/webstore_search_fetcher.h"
#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/url_constants.h"
#include "url/gurl.h"
namespace app_list {
@@ -34,6 +36,49 @@
return base::FieldTrialList::FindFullName(kFieldTrialName) == kEnable;
}
+// Returns whether or not the user's input string, |query|, might contain any
+// sensitive information, based purely on its value and not where it came from.
+bool IsSensitiveInput(const string16& query) {
+ const GURL query_as_url(query);
+ if (!query_as_url.is_valid())
+ return false;
+
+ // The input can be interpreted as a URL. Check to see if it is potentially
+ // sensitive. (Code shamelessly copied from search_provider.cc's
+ // IsQuerySuitableForSuggest function.)
+
+ // First we check the scheme: if this looks like a URL with a scheme that is
+ // file, we shouldn't send it. Sending such things is a waste of time and a
+ // disclosure of potentially private, local data. If the scheme is OK, we
+ // still need to check other cases below.
+ if (LowerCaseEqualsASCII(query_as_url.scheme(), chrome::kFileScheme))
+ return true;
+
+ // Don't send URLs with usernames, queries or refs. Some of these are
+ // private, and the Suggest server is unlikely to have any useful results
+ // for any of them. Also don't send URLs with ports, as we may initially
+ // think that a username + password is a host + port (and we don't want to
+ // send usernames/passwords), and even if the port really is a port, the
+ // server is once again unlikely to have and useful results.
+ if (!query_as_url.username().empty() ||
+ !query_as_url.port().empty() ||
+ !query_as_url.query().empty() ||
+ !query_as_url.ref().empty()) {
+ return true;
+ }
+
+ // Don't send anything for https except the hostname. Hostnames are OK
+ // because they are visible when the TCP connection is established, but the
+ // specific path may reveal private information.
+ if (LowerCaseEqualsASCII(query_as_url.scheme(), chrome::kHttpsScheme) &&
+ !query_as_url.path().empty() &&
+ query_as_url.path() != "/") {
+ return true;
+ }
+
+ return false;
+}
+
} // namespace
WebstoreProvider::WebstoreProvider(Profile* profile,
@@ -44,6 +89,13 @@
WebstoreProvider::~WebstoreProvider() {}
void WebstoreProvider::Start(const base::string16& query) {
+ ClearResults();
+
+ // If |query| contains sensitive data, bail out and do not create the place
+ // holder "search-web-store" result.
+ if (IsSensitiveInput(query))
+ return;
+
const std::string query_utf8 = UTF16ToUTF8(query);
if (UseWebstoreSearch()) {
@@ -59,7 +111,6 @@
// Add a placeholder result which when clicked will run the user's query in a
// browser. This placeholder is removed when the search results arrive.
- ClearResults();
Add(scoped_ptr<ChromeSearchResult>(
new SearchWebstoreResult(profile_, query_utf8)).Pass());
}
diff --git a/chrome/browser/ui/app_list/search/webstore_provider_browsertest.cc b/chrome/browser/ui/app_list/search/webstore_provider_browsertest.cc
index b60133a..ced21f4 100644
--- a/chrome/browser/ui/app_list/search/webstore_provider_browsertest.cc
+++ b/chrome/browser/ui/app_list/search/webstore_provider_browsertest.cc
@@ -189,5 +189,26 @@
}
}
+IN_PROC_BROWSER_TEST_F(WebstoreProviderTest, NoSearchForSensitiveData) {
+ // None of the following input strings should be accepted because they may
+ // contain private data.
+ const char* inputs[] = {
+ // file: scheme is bad.
+ "file://filename",
+ "FILE://filename",
+ // URLs with usernames, ports, queries or refs are bad.
+ "http://username:password@hostname/",
+ "http://www.example.com:1000",
+ "http://foo:1000",
+ "http://hostname/?query=q",
+ "http://hostname/path#ref",
+ // A https URL with path is bad.
+ "https://hostname/path",
+ };
+
+ for (size_t i = 0; i < arraysize(inputs); ++i)
+ EXPECT_EQ("", RunQuery(inputs[i], ""));
+}
+
} // namespace test
} // namespace app_list
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
index 2fe7f2f..38c6905 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
@@ -101,6 +101,9 @@
// HSL shift to gray out an image.
const color_utils::HSL kGrayImageShift = {-1, 0, 0.8};
+// Limit Wallet items refresh rate to at most once per minute.
+const int kWalletItemsRefreshRateSeconds = 60;
+
// Returns true if |card_type| is supported by Wallet.
bool IsWalletSupportedCard(const std::string& card_type) {
return card_type == autofill::kVisaCard ||
@@ -643,6 +646,17 @@
view_->Hide();
}
+void AutofillDialogControllerImpl::TabActivated() {
+ // If the user switched away from this tab and then switched back, reload the
+ // Wallet items, in case they've changed.
+ int seconds_elapsed_since_last_refresh =
+ (base::TimeTicks::Now() - last_wallet_items_fetch_timestamp_).InSeconds();
+ if (IsPayingWithWallet() && wallet_items_ &&
+ seconds_elapsed_since_last_refresh >= kWalletItemsRefreshRateSeconds) {
+ GetWalletItems();
+ }
+}
+
void AutofillDialogControllerImpl::OnAutocheckoutError() {
DCHECK_EQ(AUTOCHECKOUT_IN_PROGRESS, autocheckout_state_);
GetMetricLogger().LogAutocheckoutDuration(
@@ -901,7 +915,15 @@
}
void AutofillDialogControllerImpl::GetWalletItems() {
+ if (wallet_items_) {
+ previously_selected_instrument_id_ = ActiveInstrument()->object_id();
+ previously_selected_shipping_address_id_ =
+ ActiveShippingAddress()->object_id();
+ }
+
+ last_wallet_items_fetch_timestamp_ = base::TimeTicks::Now();
wallet_items_.reset();
+
// The "Loading..." page should be showing now, which should cause the
// account chooser to hide.
view_->UpdateAccountChooser();
@@ -2092,6 +2114,10 @@
GURL settings_url(chrome::kChromeUISettingsURL);
url = settings_url.Resolve(chrome::kAutofillSubPage);
} else {
+ // Reset |last_wallet_items_fetch_timestamp_| to ensure that the Wallet
+ // data is refreshed as soon as the user switches back to this tab after
+ // potentially editing his data.
+ last_wallet_items_fetch_timestamp_ = base::TimeTicks();
url = SectionForSuggestionsMenuModel(*model) == SECTION_SHIPPING ?
wallet::GetManageAddressesUrl() : wallet::GetManageInstrumentsUrl();
}
@@ -2489,9 +2515,14 @@
addresses[i]->DisplayName(),
addresses[i]->DisplayNameDetail());
- if (addresses[i]->object_id() == wallet_items_->default_address_id())
+ const std::string default_shipping_address_id =
+ !previously_selected_shipping_address_id_.empty() ?
+ previously_selected_shipping_address_id_ :
+ wallet_items_->default_address_id();
+ if (addresses[i]->object_id() == default_shipping_address_id)
suggested_shipping_.SetCheckedItem(key);
}
+ previously_selected_shipping_address_id_.clear();
if (!IsSubmitPausedOn(wallet::VERIFY_CVV)) {
const std::vector<wallet::WalletItems::MaskedInstrument*>& instruments =
@@ -2519,12 +2550,16 @@
if (allowed) {
if (first_active_instrument_key.empty())
first_active_instrument_key = key;
- if (instruments[i]->object_id() ==
- wallet_items_->default_instrument_id()) {
+
+ const std::string default_instrument_id =
+ !previously_selected_instrument_id_.empty() ?
+ previously_selected_instrument_id_ :
+ wallet_items_->default_instrument_id();
+ if (instruments[i]->object_id() == default_instrument_id)
default_instrument_key = key;
- }
}
}
+ previously_selected_instrument_id_.clear();
// TODO(estade): this should have a URL sublabel.
suggested_cc_billing_.AddKeyedItem(
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h
index 88e7429..7769189 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h
@@ -92,6 +92,10 @@
void Show();
void Hide();
+ // Called when the tab hosting this dialog is activated by a user gesture.
+ // Used to trigger a refresh of the user's Wallet data.
+ void TabActivated();
+
// Adds a step in the flow to the Autocheckout UI.
void AddAutocheckoutStep(AutocheckoutStepType step_type);
@@ -597,6 +601,15 @@
scoped_ptr<wallet::WalletItems> wallet_items_;
scoped_ptr<wallet::FullWallet> full_wallet_;
+ // The last active instrument and shipping address object ids. These
+ // variables are only set (i.e. non-empty) when the Wallet items are being
+ // re-fetched.
+ std::string previously_selected_instrument_id_;
+ std::string previously_selected_shipping_address_id_;
+
+ // When the Wallet items were last fetched.
+ base::TimeTicks last_wallet_items_fetch_timestamp_;
+
// Local machine signals to pass along on each request to trigger (or
// discourage) risk challenges; sent if the user is up to date on legal docs.
std::string risk_data_;
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc
index a647868..51f2d16 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc
@@ -2284,4 +2284,59 @@
controller()->ViewClosed();
}
+TEST_F(AutofillDialogControllerTest, ReloadWalletItemsOnActivation) {
+ // Switch into Wallet mode and initialize some Wallet data.
+ SwitchToWallet();
+
+ scoped_ptr<wallet::WalletItems> wallet_items = wallet::GetTestWalletItems();
+ wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
+ wallet_items->AddInstrument(wallet::GetTestNonDefaultMaskedInstrument());
+ wallet_items->AddAddress(wallet::GetTestNonDefaultShippingAddress());
+ wallet_items->AddAddress(wallet::GetTestShippingAddress());
+ controller()->OnDidGetWalletItems(wallet_items.Pass());
+
+ // Initially, the default entries should be selected.
+ ui::MenuModel* cc_billing_model =
+ controller()->MenuModelForSection(SECTION_CC_BILLING);
+ ui::MenuModel* shipping_model =
+ controller()->MenuModelForSection(SECTION_SHIPPING);
+ // "add", "manage", and 2 suggestions.
+ ASSERT_EQ(4, cc_billing_model->GetItemCount());
+ EXPECT_TRUE(cc_billing_model->IsItemCheckedAt(0));
+ // "use billing", "add", "manage", and 2 suggestions.
+ ASSERT_EQ(5, shipping_model->GetItemCount());
+ EXPECT_TRUE(shipping_model->IsItemCheckedAt(2));
+
+ // Select entries other than the defaults.
+ cc_billing_model->ActivatedAt(1);
+ shipping_model->ActivatedAt(1);
+ // "add", "manage", and 2 suggestions.
+ ASSERT_EQ(4, cc_billing_model->GetItemCount());
+ EXPECT_TRUE(cc_billing_model->IsItemCheckedAt(1));
+ // "use billing", "add", "manage", and 2 suggestions.
+ ASSERT_EQ(5, shipping_model->GetItemCount());
+ EXPECT_TRUE(shipping_model-> IsItemCheckedAt(1));
+
+ // Simulate switching away from the tab and back. This should issue a request
+ // for wallet items.
+ EXPECT_CALL(*controller()->GetTestingWalletClient(), GetWalletItems(_));
+ controller()->TabActivated();
+
+ // Simulate a response that includes different items.
+ wallet_items = wallet::GetTestWalletItems();
+ wallet_items->AddInstrument(wallet::GetTestMaskedInstrumentExpired());
+ wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
+ wallet_items->AddInstrument(wallet::GetTestNonDefaultMaskedInstrument());
+ wallet_items->AddAddress(wallet::GetTestNonDefaultShippingAddress());
+ controller()->OnDidGetWalletItems(wallet_items.Pass());
+
+ // The previously selected entries should still be selected.
+ // "add", "manage", and 3 suggestions.
+ ASSERT_EQ(5, cc_billing_model->GetItemCount());
+ EXPECT_TRUE(cc_billing_model->IsItemCheckedAt(2));
+ // "use billing", "add", "manage", and 1 suggestion.
+ ASSERT_EQ(4, shipping_model->GetItemCount());
+ EXPECT_TRUE(shipping_model->IsItemCheckedAt(1));
+}
+
} // namespace autofill
diff --git a/chrome/browser/ui/autofill/tab_autofill_manager_delegate.cc b/chrome/browser/ui/autofill/tab_autofill_manager_delegate.cc
index 44603d9..00007ba 100644
--- a/chrome/browser/ui/autofill/tab_autofill_manager_delegate.cc
+++ b/chrome/browser/ui/autofill/tab_autofill_manager_delegate.cc
@@ -19,6 +19,7 @@
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/chrome_pages.h"
+#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
#include "chrome/common/url_constants.h"
#include "components/autofill/content/browser/autofill_driver_impl.h"
#include "components/autofill/core/common/autofill_pref_names.h"
@@ -46,6 +47,14 @@
DCHECK(!popup_controller_);
}
+void TabAutofillManagerDelegate::TabActivated(int reason) {
+ if (reason != TabStripModelObserver::CHANGE_REASON_USER_GESTURE)
+ return;
+
+ if (dialog_controller_.get())
+ dialog_controller_->TabActivated();
+}
+
PersonalDataManager* TabAutofillManagerDelegate::GetPersonalDataManager() {
Profile* profile =
Profile::FromBrowserContext(web_contents_->GetBrowserContext());
diff --git a/chrome/browser/ui/autofill/tab_autofill_manager_delegate.h b/chrome/browser/ui/autofill/tab_autofill_manager_delegate.h
index 75879bd..004a0bb 100644
--- a/chrome/browser/ui/autofill/tab_autofill_manager_delegate.h
+++ b/chrome/browser/ui/autofill/tab_autofill_manager_delegate.h
@@ -37,6 +37,9 @@
public:
virtual ~TabAutofillManagerDelegate();
+ // Called when the tab corresponding to |this| instance is activated.
+ void TabActivated(int reason);
+
// AutofillManagerDelegate implementation.
virtual PersonalDataManager* GetPersonalDataManager() OVERRIDE;
virtual PrefService* GetPrefs() OVERRIDE;
diff --git a/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc b/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
index c248a37..2c12189 100644
--- a/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
+++ b/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
@@ -262,10 +262,10 @@
// Launch the blocked popup.
EXPECT_EQ(1u, popup_blocker_helper->GetBlockedPopupsCount());
- IDMap<chrome::NavigateParams, IDMapOwnPointer>::const_iterator iter(
- &popup_blocker_helper->GetBlockedPopupRequests());
- ASSERT_FALSE(iter.IsAtEnd());
- popup_blocker_helper->ShowBlockedPopup(iter.GetCurrentKey());
+ std::map<int32, GURL> blocked_requests =
+ popup_blocker_helper->GetBlockedPopupRequests();
+ std::map<int32, GURL>::const_iterator iter = blocked_requests.begin();
+ popup_blocker_helper->ShowBlockedPopup(iter->first);
observer.Wait();
}
@@ -299,10 +299,10 @@
PopupBlockerTabHelper* popup_blocker_helper =
PopupBlockerTabHelper::FromWebContents(web_contents);
EXPECT_EQ(1u, popup_blocker_helper->GetBlockedPopupsCount());
- IDMap<chrome::NavigateParams, IDMapOwnPointer>::const_iterator iter(
- &popup_blocker_helper->GetBlockedPopupRequests());
- ASSERT_FALSE(iter.IsAtEnd());
- popup_blocker_helper->ShowBlockedPopup(iter.GetCurrentKey());
+ std::map<int32, GURL> blocked_requests =
+ popup_blocker_helper->GetBlockedPopupRequests();
+ std::map<int32, GURL>::const_iterator iter = blocked_requests.begin();
+ popup_blocker_helper->ShowBlockedPopup(iter->first);
observer.Wait();
}
@@ -336,10 +336,10 @@
PopupBlockerTabHelper* popup_blocker_helper =
PopupBlockerTabHelper::FromWebContents(web_contents);
EXPECT_EQ(1u, popup_blocker_helper->GetBlockedPopupsCount());
- IDMap<chrome::NavigateParams, IDMapOwnPointer>::const_iterator iter(
- &popup_blocker_helper->GetBlockedPopupRequests());
- ASSERT_FALSE(iter.IsAtEnd());
- popup_blocker_helper->ShowBlockedPopup(iter.GetCurrentKey());
+ std::map<int32, GURL> blocked_requests =
+ popup_blocker_helper->GetBlockedPopupRequests();
+ std::map<int32, GURL>::const_iterator iter = blocked_requests.begin();
+ popup_blocker_helper->ShowBlockedPopup(iter->first);
observer.Wait();
Browser* new_browser = browser_observer.WaitForSingleNewBrowser();
@@ -380,10 +380,54 @@
PopupBlockerTabHelper* popup_blocker_helper =
PopupBlockerTabHelper::FromWebContents(web_contents);
EXPECT_EQ(1u, popup_blocker_helper->GetBlockedPopupsCount());
- IDMap<chrome::NavigateParams, IDMapOwnPointer>::const_iterator iter(
- &popup_blocker_helper->GetBlockedPopupRequests());
- ASSERT_FALSE(iter.IsAtEnd());
- popup_blocker_helper->ShowBlockedPopup(iter.GetCurrentKey());
+ std::map<int32, GURL> blocked_requests =
+ popup_blocker_helper->GetBlockedPopupRequests();
+ std::map<int32, GURL>::const_iterator iter = blocked_requests.begin();
+ popup_blocker_helper->ShowBlockedPopup(iter->first);
+
+ observer.Wait();
+ Browser* new_browser = browser_observer.WaitForSingleNewBrowser();
+
+ // Check that the referrer was correctly set.
+ web_contents = new_browser->tab_strip_model()->GetActiveWebContents();
+ base::string16 expected_title(base::ASCIIToUTF16("PASS"));
+ content::TitleWatcher title_watcher(web_contents, expected_title);
+ EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
+}
+
+IN_PROC_BROWSER_TEST_F(BetterPopupBlockerBrowserTest, WindowFeaturesBarProps) {
+ GURL url(ui_test_utils::GetTestUrl(
+ base::FilePath(kTestDir),
+ base::FilePath(FILE_PATH_LITERAL("popup-windowfeatures.html"))));
+
+ CountRenderViewHosts counter;
+
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ // If the popup blocker blocked the blank post, there should be only one tab.
+ EXPECT_EQ(1u, chrome::GetBrowserCount(browser()->profile(),
+ browser()->host_desktop_type()));
+ EXPECT_EQ(1, browser()->tab_strip_model()->count());
+ WebContents* web_contents =
+ browser()->tab_strip_model()->GetActiveWebContents();
+ EXPECT_EQ(url, web_contents->GetURL());
+
+ // And no new RVH created.
+ EXPECT_EQ(0, counter.GetRenderViewHostCreatedCount());
+
+ content::WindowedNotificationObserver observer(
+ chrome::NOTIFICATION_TAB_ADDED,
+ content::NotificationService::AllSources());
+ ui_test_utils::BrowserAddedObserver browser_observer;
+
+ // Launch the blocked popup.
+ PopupBlockerTabHelper* popup_blocker_helper =
+ PopupBlockerTabHelper::FromWebContents(web_contents);
+ EXPECT_EQ(1u, popup_blocker_helper->GetBlockedPopupsCount());
+ std::map<int32, GURL> blocked_requests =
+ popup_blocker_helper->GetBlockedPopupRequests();
+ std::map<int32, GURL>::const_iterator iter = blocked_requests.begin();
+ popup_blocker_helper->ShowBlockedPopup(iter->first);
observer.Wait();
Browser* new_browser = browser_observer.WaitForSingleNewBrowser();
diff --git a/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc b/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc
index 41b36ff..cc8077c 100644
--- a/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc
+++ b/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc
@@ -9,14 +9,27 @@
#include "chrome/browser/content_settings/tab_specific_content_settings.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser_navigator.h"
+#include "chrome/common/render_messages.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_details.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
+#include "third_party/WebKit/public/web/WebWindowFeatures.h"
+
+using WebKit::WebWindowFeatures;
DEFINE_WEB_CONTENTS_USER_DATA_KEY(PopupBlockerTabHelper);
+struct PopupBlockerTabHelper::BlockedRequest {
+ BlockedRequest(const chrome::NavigateParams& params,
+ const WebWindowFeatures& window_features)
+ : params(params), window_features(window_features) {}
+
+ chrome::NavigateParams params;
+ WebWindowFeatures window_features;
+};
+
PopupBlockerTabHelper::PopupBlockerTabHelper(
content::WebContents* web_contents)
: content::WebContentsObserver(web_contents) {
@@ -49,7 +62,8 @@
}
bool PopupBlockerTabHelper::MaybeBlockPopup(
- const chrome::NavigateParams& params) {
+ const chrome::NavigateParams& params,
+ const WebWindowFeatures& window_features) {
// A page can't spawn popups (or do anything else, either) until its load
// commits, so when we reach here, the popup was spawned by the
// NavigationController's last committed entry, not the active entry. For
@@ -69,7 +83,7 @@
CONTENT_SETTING_ALLOW) {
return false;
} else {
- blocked_popups_.Add(new chrome::NavigateParams(params));
+ blocked_popups_.Add(new BlockedRequest(params, window_features));
TabSpecificContentSettings::FromWebContents(web_contents())->
OnContentBlocked(CONTENT_SETTINGS_TYPE_POPUPS, std::string());
return true;
@@ -77,10 +91,14 @@
}
void PopupBlockerTabHelper::ShowBlockedPopup(int32 id) {
- chrome::NavigateParams* params = blocked_popups_.Lookup(id);
- if (!params)
+ BlockedRequest* popup = blocked_popups_.Lookup(id);
+ if (!popup)
return;
- chrome::Navigate(params);
+ chrome::Navigate(&popup->params);
+ if (popup->params.target_contents) {
+ popup->params.target_contents->Send(new ChromeViewMsg_SetWindowFeatures(
+ popup->params.target_contents->GetRoutingID(), popup->window_features));
+ }
blocked_popups_.Remove(id);
if (blocked_popups_.IsEmpty())
PopupNotificationVisibilityChanged(false);
@@ -90,7 +108,13 @@
return blocked_popups_.size();
}
-IDMap<chrome::NavigateParams, IDMapOwnPointer>&
-PopupBlockerTabHelper::GetBlockedPopupRequests() {
- return blocked_popups_;
+std::map<int32, GURL> PopupBlockerTabHelper::GetBlockedPopupRequests() {
+ std::map<int32, GURL> result;
+ for (IDMap<BlockedRequest, IDMapOwnPointer>::const_iterator iter(
+ &blocked_popups_);
+ !iter.IsAtEnd();
+ iter.Advance()) {
+ result[iter.GetCurrentKey()] = iter.GetCurrentValue()->params.url;
+ }
+ return result;
}
diff --git a/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h b/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h
index 1526054..9631742 100644
--- a/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h
+++ b/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h
@@ -5,13 +5,21 @@
#ifndef CHROME_BROWSER_UI_BLOCKED_CONTENT_POPUP_BLOCKER_TAB_HELPER_H_
#define CHROME_BROWSER_UI_BLOCKED_CONTENT_POPUP_BLOCKER_TAB_HELPER_H_
+#include <map>
+
#include "base/id_map.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
namespace chrome {
struct NavigateParams;
-};
+}
+
+namespace WebKit {
+struct WebWindowFeatures;
+}
+
+class GURL;
// Per-tab class to manage blocked popups.
class PopupBlockerTabHelper
@@ -22,7 +30,8 @@
// Returns true if the popup request defined by |params| should be blocked.
// In that case, it is also added to the |blocked_contents_| container.
- bool MaybeBlockPopup(const chrome::NavigateParams& params);
+ bool MaybeBlockPopup(const chrome::NavigateParams& params,
+ const WebKit::WebWindowFeatures& window_features);
// Creates the blocked popup with |popup_id|.
void ShowBlockedPopup(int32 popup_id);
@@ -31,8 +40,7 @@
size_t GetBlockedPopupsCount() const;
// Returns the mapping from popup IDs to blocked popup requests.
- IDMap<chrome::NavigateParams, IDMapOwnPointer>&
- GetBlockedPopupRequests();
+ std::map<int32, GURL> GetBlockedPopupRequests();
// content::WebContentsObserver overrides:
virtual void DidNavigateMainFrame(
@@ -40,13 +48,15 @@
const content::FrameNavigateParams& params) OVERRIDE;
private:
- explicit PopupBlockerTabHelper(content::WebContents* web_contents);
+ struct BlockedRequest;
friend class content::WebContentsUserData<PopupBlockerTabHelper>;
+ explicit PopupBlockerTabHelper(content::WebContents* web_contents);
+
// Called when the blocked popup notification is shown or hidden.
void PopupNotificationVisibilityChanged(bool visible);
- IDMap<chrome::NavigateParams, IDMapOwnPointer> blocked_popups_;
+ IDMap<BlockedRequest, IDMapOwnPointer> blocked_popups_;
DISALLOW_COPY_AND_ASSIGN(PopupBlockerTabHelper);
};
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 3020251..8fb374d 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -88,6 +88,7 @@
#include "chrome/browser/themes/theme_service.h"
#include "chrome/browser/themes/theme_service_factory.h"
#include "chrome/browser/ui/app_modal_dialogs/javascript_dialog_manager.h"
+#include "chrome/browser/ui/autofill/tab_autofill_manager_delegate.h"
#include "chrome/browser/ui/blocked_content/blocked_content_tab_helper.h"
#include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h"
#include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h"
@@ -1083,6 +1084,9 @@
// This needs to be called after UpdateSearchState().
if (instant_controller_)
instant_controller_->ActiveTabChanged();
+
+ autofill::TabAutofillManagerDelegate::FromWebContents(new_contents)->
+ TabActivated(reason);
}
void Browser::TabMoved(WebContents* contents,
@@ -1289,8 +1293,10 @@
params.disposition == NEW_BACKGROUND_TAB) &&
!params.user_gesture && !CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisablePopupBlocking)) {
- if (popup_blocker_helper->MaybeBlockPopup(nav_params))
+ if (popup_blocker_helper->MaybeBlockPopup(nav_params,
+ WebWindowFeatures())) {
return NULL;
+ }
}
}
@@ -1538,7 +1544,7 @@
else
nav_params.disposition = disposition;
- return !popup_blocker_helper->MaybeBlockPopup(nav_params);
+ return !popup_blocker_helper->MaybeBlockPopup(nav_params, features);
}
return true;
diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
index b2bd578..c50ca8b 100644
--- a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
+++ b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
@@ -547,15 +547,13 @@
void ContentSettingPopupBubbleModel::SetPopups() {
if (CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableBetterPopupBlocking)) {
- IDMap<chrome::NavigateParams, IDMapOwnPointer>& blocked_popups =
+ std::map<int32, GURL> blocked_popups =
PopupBlockerTabHelper::FromWebContents(web_contents())
->GetBlockedPopupRequests();
- for (IDMap<chrome::NavigateParams, IDMapOwnPointer>::const_iterator
- iter(&blocked_popups);
- !iter.IsAtEnd();
- iter.Advance()) {
-
- std::string title(iter.GetCurrentValue()->url.spec());
+ for (std::map<int32, GURL>::const_iterator iter = blocked_popups.begin();
+ iter != blocked_popups.end();
+ ++iter) {
+ std::string title(iter->second.spec());
// The popup may not have a valid URL.
if (title.empty())
title = l10n_util::GetStringUTF8(IDS_TAB_LOADING_TITLE);
@@ -563,7 +561,7 @@
ui::ResourceBundle::GetSharedInstance().GetImageNamed(
IDR_DEFAULT_FAVICON),
title,
- iter.GetCurrentKey());
+ iter->first);
add_popup(popup_item);
}
return;
diff --git a/chrome/browser/ui/gesture_prefs_observer_factory_aura.cc b/chrome/browser/ui/gesture_prefs_observer_factory_aura.cc
index 7c593fa..73c59c8 100644
--- a/chrome/browser/ui/gesture_prefs_observer_factory_aura.cc
+++ b/chrome/browser/ui/gesture_prefs_observer_factory_aura.cc
@@ -55,7 +55,9 @@
{ prefs::kOverscrollVerticalThresholdComplete,
OVERSCROLL_CONFIG_VERT_THRESHOLD_COMPLETE },
{ prefs::kOverscrollMinimumThresholdStart,
- OVERSCROLL_CONFIG_MIN_THRESHOLD_START },
+ OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START },
+ { prefs::kOverscrollVerticalThresholdStart,
+ OVERSCROLL_CONFIG_VERT_THRESHOLD_START },
{ prefs::kOverscrollHorizontalResistThreshold,
OVERSCROLL_CONFIG_HORIZ_RESIST_AFTER },
{ prefs::kOverscrollVerticalResistThreshold,
diff --git a/chrome/browser/ui/search/search_tab_helper.cc b/chrome/browser/ui/search/search_tab_helper.cc
index 1a226db..33e119b 100644
--- a/chrome/browser/ui/search/search_tab_helper.cc
+++ b/chrome/browser/ui/search/search_tab_helper.cc
@@ -195,8 +195,16 @@
void SearchTabHelper::DetermineIfPageSupportsInstant() {
Profile* profile =
Profile::FromBrowserContext(web_contents_->GetBrowserContext());
- if (!chrome::ShouldAssignURLToInstantRenderer(web_contents_->GetURL(),
- profile)) {
+ // Use the underlying URL rather than the virtual URL when checking whether
+ // this navigation can land in the Instant process. Otherwise this check
+ // would fail if a URL like chrome://newtab is being rewritten to an Instant
+ // URL.
+ // TODO(samarth): actually check whether this WebContents is rendered in an
+ // Instant process rather than checking the URL.
+ const content::NavigationEntry* entry =
+ web_contents_->GetController().GetActiveEntry();
+ const GURL& current_url = entry ? entry->GetURL() : web_contents_->GetURL();
+ if (!chrome::ShouldAssignURLToInstantRenderer(current_url, profile)) {
// The page is not in the Instant process. This page does not support
// instant. If we send an IPC message to a page that is not in the Instant
// process, it will never receive it and will never respond. Therefore,
diff --git a/chrome/browser/ui/search_engines/template_url_table_model.cc b/chrome/browser/ui/search_engines/template_url_table_model.cc
index 918ae0f..072885c 100644
--- a/chrome/browser/ui/search_engines/template_url_table_model.cc
+++ b/chrome/browser/ui/search_engines/template_url_table_model.cc
@@ -252,14 +252,7 @@
template_url_service_->RemoveObserver(this);
TemplateURL* template_url = GetTemplateURL(index);
- scoped_ptr<ModelEntry> entry(entries_[index]);
- entries_.erase(entries_.begin() + index);
- if (index < last_search_engine_index_)
- --last_search_engine_index_;
- if (index < last_other_engine_index_)
- --last_other_engine_index_;
- if (observer_)
- observer_->OnItemsRemoved(index, 1);
+ scoped_ptr<ModelEntry> entry(RemoveEntry(index));
// Make sure to remove from the table model first, otherwise the
// TemplateURL would be freed.
@@ -280,13 +273,9 @@
data.SetURL(url);
TemplateURL* turl = new TemplateURL(template_url_service_->profile(), data);
template_url_service_->Add(turl);
- ModelEntry* entry = new ModelEntry(this, turl);
+ scoped_ptr<ModelEntry> entry(new ModelEntry(this, turl));
template_url_service_->AddObserver(this);
- entries_.insert(entries_.begin() + index, entry);
- if (index <= last_other_engine_index_)
- ++last_other_engine_index_;
- if (observer_)
- observer_->OnItemsAdded(index, 1);
+ AddEntry(index, entry.Pass());
}
void TemplateURLTableModel::ModifyTemplateURL(int index,
@@ -332,15 +321,9 @@
if (index < last_search_engine_index_)
return index; // Already in the main group.
- ModelEntry* current_entry = entries_[index];
- entries_.erase(index + entries_.begin());
- if (observer_)
- observer_->OnItemsRemoved(index, 1);
-
+ scoped_ptr<ModelEntry> current_entry(RemoveEntry(index));
const int new_index = last_search_engine_index_++;
- entries_.insert(entries_.begin() + new_index, current_entry);
- if (observer_)
- observer_->OnItemsAdded(new_index, 1);
+ AddEntry(new_index, current_entry.Pass());
return new_index;
}
@@ -393,3 +376,23 @@
void TemplateURLTableModel::OnTemplateURLServiceChanged() {
Reload();
}
+
+scoped_ptr<ModelEntry> TemplateURLTableModel::RemoveEntry(int index) {
+ scoped_ptr<ModelEntry> entry(entries_[index]);
+ entries_.erase(index + entries_.begin());
+ if (index < last_search_engine_index_)
+ --last_search_engine_index_;
+ if (index < last_other_engine_index_)
+ --last_other_engine_index_;
+ if (observer_)
+ observer_->OnItemsRemoved(index, 1);
+ return entry.Pass();
+}
+
+void TemplateURLTableModel::AddEntry(int index, scoped_ptr<ModelEntry> entry) {
+ entries_.insert(entries_.begin() + index, entry.release());
+ if (index <= last_other_engine_index_)
+ ++last_other_engine_index_;
+ if (observer_)
+ observer_->OnItemsAdded(index, 1);
+}
diff --git a/chrome/browser/ui/search_engines/template_url_table_model.h b/chrome/browser/ui/search_engines/template_url_table_model.h
index 5e00d97..864b48c 100644
--- a/chrome/browser/ui/search_engines/template_url_table_model.h
+++ b/chrome/browser/ui/search_engines/template_url_table_model.h
@@ -9,6 +9,7 @@
#include <vector>
#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
#include "chrome/browser/search_engines/template_url_service_observer.h"
#include "ui/base/models/table_model.h"
@@ -110,6 +111,12 @@
// TemplateURLServiceObserver notification.
virtual void OnTemplateURLServiceChanged() OVERRIDE;
+ // Removes the entry at |index| from |entries_| and returns the removed item.
+ scoped_ptr<ModelEntry> RemoveEntry(int index);
+
+ // Adds |entry| to |entries_| at |index| and takes ownership.
+ void AddEntry(int index, scoped_ptr<ModelEntry> entry);
+
ui::TableModelObserver* observer_;
// The entries.
diff --git a/chrome/browser/ui/views/autofill/autofill_dialog_views.cc b/chrome/browser/ui/views/autofill/autofill_dialog_views.cc
index a376e94..478abc6 100644
--- a/chrome/browser/ui/views/autofill/autofill_dialog_views.cc
+++ b/chrome/browser/ui/views/autofill/autofill_dialog_views.cc
@@ -33,6 +33,8 @@
#include "ui/gfx/skia_util.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
+#include "ui/views/bubble/bubble_border.h"
+#include "ui/views/bubble/bubble_frame_view.h"
#include "ui/views/controls/button/blue_button.h"
#include "ui/views/controls/button/checkbox.h"
#include "ui/views/controls/button/image_button.h"
@@ -535,7 +537,6 @@
: image_view_(new views::ImageView()),
message_stack_(new views::View()),
button_(new views::BlueButton(listener, string16())) {
- set_border(views::Border::CreateEmptyBorder(12, 12, 12, 12));
set_background(views::Background::CreateSolidBackground(GetNativeTheme()->
GetSystemColor(ui::NativeTheme::kColorId_DialogBackground)));
@@ -620,8 +621,12 @@
fade_out_.reset();
}
+gfx::Insets AutofillDialogViews::OverlayView::GetInsets() const {
+ return gfx::Insets(12, 12, 12, 12);
+}
+
void AutofillDialogViews::OverlayView::Layout() {
- gfx::Rect bounds = GetContentsBounds();
+ gfx::Rect bounds = ContentBoundsSansBubbleBorder();
if (!message_stack_->visible()) {
image_view_->SetBoundsRect(bounds);
return;
@@ -653,8 +658,9 @@
void AutofillDialogViews::OverlayView::OnPaint(gfx::Canvas* canvas) {
// BubbleFrameView doesn't mask the window, it just draws the border via
// image assets. Match that rounding here.
- static const SkScalar kCornerRadius = SkIntToScalar(2);
- gfx::Rect rect = GetContentsBounds();
+ gfx::Rect rect = ContentBoundsSansBubbleBorder();
+ const SkScalar kCornerRadius = SkIntToScalar(
+ GetBubbleBorder() ? GetBubbleBorder()->GetBorderCornerRadius() : 2);
gfx::Path window_mask;
window_mask.addRoundRect(gfx::RectToSkRect(rect),
kCornerRadius, kCornerRadius);
@@ -706,6 +712,24 @@
views::View::PaintChildren(canvas);
}
+views::BubbleBorder* AutofillDialogViews::OverlayView::GetBubbleBorder() {
+ views::View* frame = GetWidget()->non_client_view()->frame_view();
+ std::string bubble_frame_view_name(views::BubbleFrameView::kViewClassName);
+ if (frame->GetClassName() == bubble_frame_view_name)
+ return static_cast<views::BubbleFrameView*>(frame)->bubble_border();
+ NOTREACHED();
+ return NULL;
+}
+
+gfx::Rect AutofillDialogViews::OverlayView::ContentBoundsSansBubbleBorder() {
+ gfx::Rect bounds = GetContentsBounds();
+ int bubble_width = 5;
+ if (GetBubbleBorder())
+ bubble_width = GetBubbleBorder()->GetBorderThickness();
+ bounds.Inset(bubble_width, bubble_width, bubble_width, bubble_width);
+ return bounds;
+}
+
// AutofillDialogViews::NotificationArea ---------------------------------------
AutofillDialogViews::NotificationArea::NotificationArea(
diff --git a/chrome/browser/ui/views/autofill/autofill_dialog_views.h b/chrome/browser/ui/views/autofill/autofill_dialog_views.h
index cae7ce1..27df407 100644
--- a/chrome/browser/ui/views/autofill/autofill_dialog_views.h
+++ b/chrome/browser/ui/views/autofill/autofill_dialog_views.h
@@ -35,6 +35,7 @@
}
namespace views {
+class BubbleBorder;
class Checkbox;
class Combobox;
class FocusableBorder;
@@ -292,12 +293,19 @@
virtual void AnimationEnded(const ui::Animation* animation) OVERRIDE;
// views::View implementation:
+ virtual gfx::Insets GetInsets() const OVERRIDE;
virtual void Layout() OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
virtual void PaintChildren(gfx::Canvas* canvas) OVERRIDE;
private:
+ // Gets the border of the non-client frame view as a BubbleBorder.
+ views::BubbleBorder* GetBubbleBorder();
+
+ // Gets the bounds of this view without the frame view's bubble border.
+ gfx::Rect ContentBoundsSansBubbleBorder();
+
// Child View. Front and center.
views::ImageView* image_view_;
// Child View. When visible, below |image_view_|.
diff --git a/chrome/browser/ui/views/avatar_menu_bubble_view.cc b/chrome/browser/ui/views/avatar_menu_bubble_view.cc
index 6119289..3089862 100644
--- a/chrome/browser/ui/views/avatar_menu_bubble_view.cc
+++ b/chrome/browser/ui/views/avatar_menu_bubble_view.cc
@@ -472,6 +472,7 @@
// static
AvatarMenuBubbleView* AvatarMenuBubbleView::avatar_bubble_ = NULL;
+bool AvatarMenuBubbleView::close_on_deactivate_ = true;
// static
void AvatarMenuBubbleView::ShowBubble(
@@ -487,6 +488,7 @@
avatar_bubble_ = new AvatarMenuBubbleView(
anchor_view, arrow, anchor_rect, browser);
views::BubbleDelegateView::CreateBubble(avatar_bubble_);
+ avatar_bubble_->set_close_on_deactivate(close_on_deactivate_);
avatar_bubble_->SetBackgroundColors();
avatar_bubble_->SetAlignment(border_alignment);
avatar_bubble_->GetWidget()->Show();
diff --git a/chrome/browser/ui/views/avatar_menu_bubble_view.h b/chrome/browser/ui/views/avatar_menu_bubble_view.h
index 29597b1..c49ae45 100644
--- a/chrome/browser/ui/views/avatar_menu_bubble_view.h
+++ b/chrome/browser/ui/views/avatar_menu_bubble_view.h
@@ -79,6 +79,13 @@
virtual void OnAvatarMenuModelChanged(
AvatarMenuModel* avatar_menu_model) OVERRIDE;
+ // We normally close the bubble any time it becomes inactive but this can lead
+ // to flaky tests where unexpected UI events are triggering this behavior.
+ // Tests should call this with "false" for more consistent operation.
+ static void set_close_on_deactiavte(bool close) {
+ close_on_deactivate_ = close;
+ }
+
private:
AvatarMenuBubbleView(views::View* anchor_view,
views::BubbleBorder::Arrow arrow,
@@ -118,6 +125,7 @@
views::Link* switch_profile_link_;
static AvatarMenuBubbleView* avatar_bubble_;
+ static bool close_on_deactivate_;
// Is set to true if the managed user has clicked on Switch Users.
bool expanded_;
diff --git a/chrome/browser/ui/views/avatar_menu_button_browsertest.cc b/chrome/browser/ui/views/avatar_menu_button_browsertest.cc
index c6e21b3..1a6c4ff1 100644
--- a/chrome/browser/ui/views/avatar_menu_button_browsertest.cc
+++ b/chrome/browser/ui/views/avatar_menu_button_browsertest.cc
@@ -96,6 +96,8 @@
AvatarMenuButton* button = GetAvatarMenuButton();
ASSERT_TRUE(button);
+ AvatarMenuBubbleView::set_close_on_deactiavte(false);
+ ProfileChooserView::set_close_on_deactiavte(false);
static_cast<views::MenuButtonListener*>(button)->OnMenuButtonClicked(
NULL, gfx::Point());
base::MessageLoop::current()->RunUntilIdle();
diff --git a/chrome/browser/ui/views/profile_chooser_view.cc b/chrome/browser/ui/views/profile_chooser_view.cc
index f432e77..afcd69f 100644
--- a/chrome/browser/ui/views/profile_chooser_view.cc
+++ b/chrome/browser/ui/views/profile_chooser_view.cc
@@ -30,6 +30,7 @@
// static
ProfileChooserView* ProfileChooserView::profile_bubble_ = NULL;
+bool ProfileChooserView::close_on_deactivate_ = true;
// static
void ProfileChooserView::ShowBubble(
@@ -45,6 +46,7 @@
profile_bubble_ = new ProfileChooserView(
anchor_view, arrow, anchor_rect, browser);
views::BubbleDelegateView::CreateBubble(profile_bubble_);
+ profile_bubble_->set_close_on_deactivate(close_on_deactivate_);
profile_bubble_->SetAlignment(border_alignment);
profile_bubble_->GetWidget()->Show();
}
diff --git a/chrome/browser/ui/views/profile_chooser_view.h b/chrome/browser/ui/views/profile_chooser_view.h
index 54dcb43..eb33739 100644
--- a/chrome/browser/ui/views/profile_chooser_view.h
+++ b/chrome/browser/ui/views/profile_chooser_view.h
@@ -43,6 +43,13 @@
static bool IsShowing();
static void Hide();
+ // We normally close the bubble any time it becomes inactive but this can lead
+ // to flaky tests where unexpected UI events are triggering this behavior.
+ // Tests should call this with "false" for more consistent operation.
+ static void set_close_on_deactiavte(bool close) {
+ close_on_deactivate_ = close;
+ }
+
private:
friend class AvatarMenuButtonTest;
FRIEND_TEST_ALL_PREFIXES(AvatarMenuButtonTest, NewSignOut);
@@ -72,6 +79,7 @@
AvatarMenuModel* avatar_menu_model) OVERRIDE;
static ProfileChooserView* profile_bubble_;
+ static bool close_on_deactivate_;
views::View* CreateProfileImageView(const gfx::Image& icon, int side);
views::View* CreateProfileCardView(size_t avatar_to_show);
diff --git a/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views.cc b/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views.cc
index bd4df7a..8abb284 100644
--- a/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views.cc
+++ b/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views.cc
@@ -87,7 +87,9 @@
}
void ChromeWebContentsViewDelegateViews::TakeFocus(bool reverse) {
- GetFocusManager()->AdvanceFocus(reverse);
+ views::FocusManager* focus_manager = GetFocusManager();
+ if (focus_manager)
+ focus_manager->AdvanceFocus(reverse);
}
void ChromeWebContentsViewDelegateViews::StoreFocus() {
diff --git a/chrome/browser/ui/webui/chromeos/salsa_ui.cc b/chrome/browser/ui/webui/chromeos/salsa_ui.cc
index eb0bbf2..5d16335 100644
--- a/chrome/browser/ui/webui/chromeos/salsa_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/salsa_ui.cc
@@ -55,6 +55,7 @@
prefs::kOverscrollHorizontalThresholdComplete,
prefs::kOverscrollVerticalThresholdComplete,
prefs::kOverscrollMinimumThresholdStart,
+ prefs::kOverscrollVerticalThresholdStart,
prefs::kOverscrollHorizontalResistThreshold,
prefs::kOverscrollVerticalResistThreshold,
prefs::kImmersiveModeRevealDelayMs,
diff --git a/chrome/browser/ui/webui/identity_internals_ui.cc b/chrome/browser/ui/webui/identity_internals_ui.cc
index e575e49..3b0a167 100644
--- a/chrome/browser/ui/webui/identity_internals_ui.cc
+++ b/chrome/browser/ui/webui/identity_internals_ui.cc
@@ -19,6 +19,7 @@
#include "content/public/browser/web_ui_controller.h"
#include "content/public/browser/web_ui_data_source.h"
#include "content/public/browser/web_ui_message_handler.h"
+#include "google_apis/gaia/gaia_auth_fetcher.h"
#include "google_apis/gaia/gaia_constants.h"
#include "grit/browser_resources.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/ui/webui/ntp/ntp_login_handler.cc b/chrome/browser/ui/webui/ntp/ntp_login_handler.cc
index a5c8050..f20351e 100644
--- a/chrome/browser/ui/webui/ntp/ntp_login_handler.cc
+++ b/chrome/browser/ui/webui/ntp/ntp_login_handler.cc
@@ -38,11 +38,11 @@
#include "content/public/browser/notification_service.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
+#include "content/public/common/page_zoom.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "net/base/escape.h"
#include "skia/ext/image_operations.h"
-#include "third_party/WebKit/public/web/WebView.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/image/image.h"
@@ -164,8 +164,7 @@
success = args->GetDouble(3, &height);
DCHECK(success);
- double zoom =
- WebKit::WebView::zoomLevelToZoomFactor(web_contents->GetZoomLevel());
+ double zoom = content::ZoomLevelToZoomFactor(web_contents->GetZoomLevel());
gfx::Rect rect(x * zoom, y * zoom, width * zoom, height * zoom);
browser->window()->ShowAvatarBubble(web_ui()->GetWebContents(), rect);
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc
index 800b984..d6aed6a 100644
--- a/chrome/browser/ui/webui/options/browser_options_handler.cc
+++ b/chrome/browser/ui/webui/options/browser_options_handler.cc
@@ -79,7 +79,6 @@
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "grit/theme_resources.h"
-#include "third_party/WebKit/public/web/WebView.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/webui/web_ui_util.h"
@@ -1468,8 +1467,7 @@
void BrowserOptionsHandler::HandleDefaultZoomFactor(const ListValue* args) {
double zoom_factor;
if (ExtractDoubleValue(args, &zoom_factor)) {
- default_zoom_level_.SetValue(
- WebKit::WebView::zoomFactorToZoomLevel(zoom_factor));
+ default_zoom_level_.SetValue(content::ZoomFactorToZoomLevel(zoom_factor));
}
}
@@ -1670,7 +1668,7 @@
PrefService* pref_service = Profile::FromWebUI(web_ui())->GetPrefs();
double default_zoom_level = pref_service->GetDouble(prefs::kDefaultZoomLevel);
double default_zoom_factor =
- WebKit::WebView::zoomLevelToZoomFactor(default_zoom_level);
+ content::ZoomLevelToZoomFactor(default_zoom_level);
// Generate a vector of zoom factors from an array of known presets along with
// the default factor added if necessary.
diff --git a/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc b/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc
index c8b991d..ad50697 100644
--- a/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc
+++ b/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc
@@ -1011,14 +1011,8 @@
void InternetOptionsHandler::EnableCellularCallback(
const base::ListValue* args) {
NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
- if (!handler->IsTechnologyEnabled(NetworkStateHandler::kMatchTypeMobile)) {
- handler->SetTechnologyEnabled(
- NetworkStateHandler::kMatchTypeMobile, true,
- base::Bind(&ShillError, "EnableCellularCallback"));
- return;
- }
- const DeviceState* device = handler->GetDeviceStateByType(
- NetworkStateHandler::kMatchTypeMobile);
+ const DeviceState* device =
+ handler->GetDeviceStateByType(flimflam::kTypeCellular);
if (!device) {
LOG(ERROR) << "Mobile device not found.";
return;
@@ -1028,6 +1022,12 @@
SimDialogDelegate::SIM_DIALOG_UNLOCK);
return;
}
+ if (!handler->IsTechnologyEnabled(flimflam::kTypeCellular)) {
+ handler->SetTechnologyEnabled(
+ flimflam::kTypeCellular, true,
+ base::Bind(&ShillError, "EnableCellularCallback"));
+ return;
+ }
if (device->IsSimAbsent()) {
MobileConfig* config = MobileConfig::GetInstance();
if (config->IsReady()) {
diff --git a/chrome/browser/ui/webui/options/reset_profile_settings_handler.cc b/chrome/browser/ui/webui/options/reset_profile_settings_handler.cc
index f28ec88..68ee2bb 100644
--- a/chrome/browser/ui/webui/options/reset_profile_settings_handler.cc
+++ b/chrome/browser/ui/webui/options/reset_profile_settings_handler.cc
@@ -28,6 +28,7 @@
namespace options {
ResetProfileSettingsHandler::ResetProfileSettingsHandler() {
+ google_util::GetBrand(&brandcode_);
}
ResetProfileSettingsHandler::~ResetProfileSettingsHandler() {
@@ -68,8 +69,8 @@
void ResetProfileSettingsHandler::HandleResetProfileSettings(
const ListValue* /*value*/) {
- DCHECK(config_fetcher_);
- if (config_fetcher_->IsActive()) {
+ DCHECK(brandcode_.empty() || config_fetcher_);
+ if (config_fetcher_ && config_fetcher_->IsActive()) {
// Reset once the prefs are fetched.
config_fetcher_->SetCallback(
base::Bind(&ResetProfileSettingsHandler::ResetProfile,
@@ -84,11 +85,13 @@
}
void ResetProfileSettingsHandler::OnShowResetProfileDialog(const ListValue*) {
- // TODO(vasilii): use a real request.
+ if (brandcode_.empty())
+ return;
config_fetcher_.reset(new BrandcodeConfigFetcher(
base::Bind(&ResetProfileSettingsHandler::OnSettingsFetched,
Unretained(this)),
- GURL("https://tools.google.com/service/update2")));
+ GURL("https://tools.google.com/service/update2"),
+ brandcode_));
}
void ResetProfileSettingsHandler::OnSettingsFetched() {
@@ -100,13 +103,18 @@
void ResetProfileSettingsHandler::ResetProfile() {
DCHECK(resetter_);
DCHECK(!resetter_->IsActive());
- DCHECK(config_fetcher_);
- DCHECK(!config_fetcher_->IsActive());
- scoped_ptr<BrandcodedDefaultSettings> default_settings =
- config_fetcher_->GetSettings();
- config_fetcher_.reset();
- // If we failed to fetch BrandcodedDefaultSettings, use default settings.
+ scoped_ptr<BrandcodedDefaultSettings> default_settings;
+ if (config_fetcher_) {
+ DCHECK(!config_fetcher_->IsActive());
+ default_settings = config_fetcher_->GetSettings();
+ config_fetcher_.reset();
+ } else {
+ DCHECK(brandcode_.empty());
+ }
+
+ // If failed to fetch BrandcodedDefaultSettings or this is an organic
+ // installation, use default settings.
if (!default_settings)
default_settings.reset(new BrandcodedDefaultSettings);
resetter_->Reset(
diff --git a/chrome/browser/ui/webui/options/reset_profile_settings_handler.h b/chrome/browser/ui/webui/options/reset_profile_settings_handler.h
index 999b023..9431590 100644
--- a/chrome/browser/ui/webui/options/reset_profile_settings_handler.h
+++ b/chrome/browser/ui/webui/options/reset_profile_settings_handler.h
@@ -54,6 +54,9 @@
scoped_ptr<BrandcodeConfigFetcher> config_fetcher_;
+ // Contains Chrome brand code; empty for organic Chrome.
+ std::string brandcode_;
+
DISALLOW_COPY_AND_ASSIGN(ResetProfileSettingsHandler);
};
diff --git a/chrome/browser/upgrade_detector_impl.cc b/chrome/browser/upgrade_detector_impl.cc
index 15602d4..0bfdbf5 100644
--- a/chrome/browser/upgrade_detector_impl.cc
+++ b/chrome/browser/upgrade_detector_impl.cc
@@ -14,6 +14,7 @@
#include "base/memory/singleton.h"
#include "base/metrics/field_trial.h"
#include "base/path_service.h"
+#include "base/process/launch.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"