diff options
author | bradnelson@google.com <bradnelson@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-03 21:55:29 +0000 |
---|---|---|
committer | bradnelson@google.com <bradnelson@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-03 21:55:29 +0000 |
commit | 21e581224e3229921d1ffb955ead8cf826d7a009 (patch) | |
tree | d69d32705f75f50bbd38d6d57b0601f4c3eb751f /chrome | |
parent | 0ec65a206162e22de14d2c50661fee6046c0c877 (diff) | |
download | chromium_src-21e581224e3229921d1ffb955ead8cf826d7a009.zip chromium_src-21e581224e3229921d1ffb955ead8cf826d7a009.tar.gz chromium_src-21e581224e3229921d1ffb955ead8cf826d7a009.tar.bz2 |
Rolling back 22317
BUG=None
TEST=None
TBR=tim
Review URL: http://codereview.chromium.org/160542
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@22321 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
29 files changed, 0 insertions, 6901 deletions
diff --git a/chrome/browser/sync/auth_error_state.h b/chrome/browser/sync/auth_error_state.h deleted file mode 100644 index 863a9eb..0000000 --- a/chrome/browser/sync/auth_error_state.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_PERSONALIZATION_AUTH_ERROR_STATE_H_ -#define CHROME_PERSONALIZATION_AUTH_ERROR_STATE_H_ - -#include <string> -#include "base/string_util.h" - -enum AuthErrorState { - AUTH_ERROR_NONE = 0, - // The credentials supplied to GAIA were either invalid, or the locally - // cached credentials have expired. If this happens, the sync system - // will continue as if offline until authentication is reattempted. - AUTH_ERROR_INVALID_GAIA_CREDENTIALS, - // The GAIA user is not authorized to use the sync service. - AUTH_ERROR_USER_NOT_SIGNED_UP, - // Could not connect to server to verify credentials. This could be in - // response to either failure to connect to GAIA or failure to connect to - // the service needing GAIA tokens during authentication. - AUTH_ERROR_CONNECTION_FAILED, -}; - -#endif // CHROME_PERSONALIZATION_AUTH_ERROR_STATE diff --git a/chrome/browser/sync/engine/syncapi.h b/chrome/browser/sync/engine/syncapi.h deleted file mode 100644 index da50cc2..0000000 --- a/chrome/browser/sync/engine/syncapi.h +++ /dev/null @@ -1,709 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file defines the "sync API", an interface to the syncer -// backend that exposes (1) the core functionality of maintaining a consistent -// local snapshot of a hierarchical object set; (2) a means to transactionally -// access and modify those objects; (3) a means to control client/server -// synchronization tasks, namely: pushing local object modifications to a -// server, pulling nonlocal object modifications from a server to this client, -// and resolving conflicts that may arise between the two; and (4) an -// abstraction of some external functionality that is to be provided by the -// host environment. -// -// This interface is used as the entry point into the syncer backend -// when the backend is compiled as a library and embedded in another -// application. A goal for this interface layer is to depend on very few -// external types, so that an application can use the sync backend -// without introducing a dependency on specific types. A non-goal is to -// have binary compatibility across versions or compilers; this allows the -// interface to use C++ classes. An application wishing to use the sync API -// should ideally compile the syncer backend and this API as part of the -// application's own build, to avoid e.g. mismatches in calling convention, -// structure padding, or name mangling that could arise if there were a -// compiler mismatch. -// -// The schema of the objects in the sync domain is based on the model, which -// is essentially a hierarchy of items and folders similar to a filesystem, -// but with a few important differences. The sync API contains fields -// such as URL to easily allow the embedding application to store web -// browser bookmarks. Also, the sync API allows duplicate titles in a parent. -// Consequently, it does not support looking up an object by title -// and parent, since such a lookup is not uniquely determined. Lastly, -// unlike a filesystem model, objects in the Sync API model have a strict -// ordering within a parent; the position is manipulable by callers, and -// children of a node can be enumerated in the order of their position. - -#ifndef CHROME_BROWSER_SYNC_ENGINE_SYNCAPI_H_ -#define CHROME_BROWSER_SYNC_ENGINE_SYNCAPI_H_ - -#include "base/basictypes.h" - -#if (defined(OS_WIN) || defined(OS_WINDOWS)) -typedef wchar_t sync_char16; -#else -typedef uint16 sync_char16; -#endif - -// The MSVC compiler for Windows requires that any classes exported by, or -// imported from, a dynamic library be decorated with the following fanciness. -#if (defined(OS_WIN) || defined(OS_WINDOWS)) -#if COMPILING_SYNCAPI_LIBRARY -#define SYNC_EXPORT __declspec(dllexport) -#else -#define SYNC_EXPORT __declspec(dllimport) -#endif -#else -#define SYNC_EXPORT -#endif // OS_WIN || OS_WINDOWS - -// Forward declarations of internal class types so that sync API objects -// may have opaque pointers to these types. -namespace syncable { -class BaseTransaction; -class DirectoryManager; -class Entry; -class MutableEntry; -class ReadTransaction; -class ScopedDirLookup; -class WriteTransaction; -} - -namespace sync_api { - -// Forward declarations of classes to be defined later in this file. -class BaseTransaction; -class HttpPostProviderFactory; -class ModelSafeWorkerInterface; -class SyncManager; -class WriteTransaction; -struct UserShare; - -// A valid BaseNode will never have an ID of zero. -static const int64 kInvalidId = 0; - -// BaseNode wraps syncable::Entry, and corresponds to a single object's state. -// This, like syncable::Entry, is intended for use on the stack. A valid -// transaction is necessary to create a BaseNode or any of its children. -// Unlike syncable::Entry, a sync API BaseNode is identified primarily by its -// int64 metahandle, which we call an ID here. -class SYNC_EXPORT BaseNode { - public: - // All subclasses of BaseNode must provide a way to initialize themselves by - // doing an ID lookup. Returns false on failure. An invalid or deleted - // ID will result in failure. - virtual bool InitByIdLookup(int64 id) = 0; - - // Each object is identified by a 64-bit id (internally, the syncable - // metahandle). These ids are strictly local handles. They will persist - // on this client, but the same object on a different client may have a - // different ID value. - int64 GetId() const; - - // Nodes are hierarchically arranged into a single-rooted tree. - // InitByRootLookup on ReadNode allows access to the root. GetParentId is - // how you find a node's parent. - int64 GetParentId() const; - - // Nodes are either folders or not. This corresponds to the IS_DIR property - // of syncable::Entry. - bool GetIsFolder() const; - - // Returns the title of the object as a C string. The memory is owned by - // BaseNode and becomes invalid if GetTitle() is called a second time on this - // node, or when the node is destroyed. A caller should convert this - // immediately into e.g. a std::string. Uniqueness of the title is not - // enforced on siblings -- it is not an error for two children to share - // a title. - const sync_char16* GetTitle() const; - - // Returns the URL of a bookmark object as a C string. The memory is owned - // by BaseNode and becomes invalid if GetURL() is called a second time on - // this node, or when the node is destroyed. A caller should convert this - // immediately into e.g. a std::string. - const sync_char16* GetURL() const; - - // Return a pointer to the byte data of the favicon image for this node. - // Will return NULL if there is no favicon data associated with this node. - // The length of the array is returned to the caller via |size_in_bytes|. - // Favicons are expected to be PNG images, and though no verification is - // done on the syncapi client of this, the server may reject favicon updates - // that are invalid for whatever reason. - const unsigned char* GetFaviconBytes(size_t* size_in_bytes); - - // Returns the local external ID associated with the node. - int64 GetExternalId() const; - - // Return the ID of the node immediately before this in the sibling order. - // For the first node in the ordering, return 0. - int64 GetPredecessorId() const; - - // Return the ID of the node immediately after this in the sibling order. - // For the last node in the ordering, return 0. - int64 GetSuccessorId() const; - - // Return the ID of the first child of this node. If this node has no - // children, return 0. - int64 GetFirstChildId() const; - - // Get an array containing the IDs of this node's children. The memory is - // owned by BaseNode and becomes invalid if GetChildIds() is called a second - // time on this node, or when the node is destroyed. Return the array size - // in the child_count parameter. - const int64* GetChildIds(size_t* child_count) const; - - // These virtual accessors provide access to data members of derived classes. - virtual const syncable::Entry* GetEntry() const = 0; - virtual const BaseTransaction* GetTransaction() const = 0; - - protected: - BaseNode(); - virtual ~BaseNode(); - - private: - struct BaseNodeInternal; - - // Node is meant for stack use only. - void* operator new(size_t size); - - // Provides storage for member functions that return pointers to class - // memory, e.g. C strings returned by GetTitle(). - BaseNodeInternal* data_; - - DISALLOW_COPY_AND_ASSIGN(BaseNode); -}; - -// WriteNode extends BaseNode to add mutation, and wraps -// syncable::MutableEntry. A WriteTransaction is needed to create a WriteNode. -class SYNC_EXPORT WriteNode : public BaseNode { - public: - // Create a WriteNode using the given transaction. - explicit WriteNode(WriteTransaction* transaction); - virtual ~WriteNode(); - - // A client must use one (and only one) of the following Init variants to - // populate the node. - - // BaseNode implementation. - virtual bool InitByIdLookup(int64 id); - - // Create a new node with the specified parent and predecessor. Use a NULL - // |predecessor| to indicate that this is to be the first child. - // |predecessor| must be a child of |new_parent| or NULL. Returns false on - // failure. - bool InitByCreation(const BaseNode& parent, const BaseNode* predecessor); - - // These Set() functions correspond to the Get() functions of BaseNode. - void SetIsFolder(bool folder); - void SetTitle(const sync_char16* title); - void SetURL(const sync_char16* url); - void SetFaviconBytes(const unsigned char* bytes, size_t size_in_bytes); - // External ID is a client-only field, so setting it doesn't cause the item to - // be synced again. - void SetExternalId(int64 external_id); - - // Remove this node and its children. - void Remove(); - - // Set a new parent and position. Position is specified by |predecessor|; if - // it is NULL, the node is moved to the first position. |predecessor| must - // be a child of |new_parent| or NULL. Returns false on failure.. - bool SetPosition(const BaseNode& new_parent, const BaseNode* predecessor); - - // Implementation of BaseNode's abstract virtual accessors. - virtual const syncable::Entry* GetEntry() const; - - virtual const BaseTransaction* GetTransaction() const; - - private: - void* operator new(size_t size); // Node is meant for stack use only. - - // Helper to set the previous node. - void PutPredecessor(const BaseNode* predecessor); - - // Sets IS_UNSYNCED and SYNCING to ensure this entry is considered in an - // upcoming commit pass. - void MarkForSyncing(); - - // The underlying syncable object which this class wraps. - syncable::MutableEntry* entry_; - - // The sync API transaction that is the parent of this node. - WriteTransaction* transaction_; - - DISALLOW_COPY_AND_ASSIGN(WriteNode); -}; - -// ReadNode wraps a syncable::Entry to provide the functionality of a -// read-only BaseNode. -class SYNC_EXPORT ReadNode : public BaseNode { - public: - // Create an unpopulated ReadNode on the given transaction. Call some flavor - // of Init to populate the ReadNode with a database entry. - explicit ReadNode(const BaseTransaction* transaction); - virtual ~ReadNode(); - - // A client must use one (and only one) of the following Init variants to - // populate the node. - - // BaseNode implementation. - virtual bool InitByIdLookup(int64 id); - - // There is always a root node, so this can't fail. The root node is - // never mutable, so root lookup is only possible on a ReadNode. - void InitByRootLookup(); - - // Each server-created permanent node is tagged with a unique string. - // Look up the node with the particular tag. If it does not exist, - // return false. Since these nodes are special, lookup is only - // provided only through ReadNode. - bool InitByTagLookup(const sync_char16* tag); - - // Implementation of BaseNode's abstract virtual accessors. - virtual const syncable::Entry* GetEntry() const; - virtual const BaseTransaction* GetTransaction() const; - - private: - void* operator new(size_t size); // Node is meant for stack use only. - - // The underlying syncable object which this class wraps. - syncable::Entry* entry_; - - // The sync API transaction that is the parent of this node. - const BaseTransaction* transaction_; - - DISALLOW_COPY_AND_ASSIGN(ReadNode); -}; - -// Sync API's BaseTransaction, ReadTransaction, and WriteTransaction allow for -// batching of several read and/or write operations. The read and write -// operations are performed by creating ReadNode and WriteNode instances using -// the transaction. These transaction classes wrap identically named classes in -// syncable, and are used in a similar way. Unlike syncable::BaseTransaction, -// whose construction requires an explicit syncable::ScopedDirLookup, a sync -// API BaseTransaction creates its own ScopedDirLookup implicitly. -class SYNC_EXPORT BaseTransaction { - public: - // Provide access to the underlying syncable.h objects from BaseNode. - virtual syncable::BaseTransaction* GetWrappedTrans() const = 0; - const syncable::ScopedDirLookup& GetLookup() const { return *lookup_; } - - protected: - // The ScopedDirLookup is created in the constructor and destroyed - // in the destructor. Creation of the ScopedDirLookup is not expected - // to fail. - explicit BaseTransaction(UserShare* share); - virtual ~BaseTransaction(); - - private: - // A syncable ScopedDirLookup, which is the parent of syncable transactions. - syncable::ScopedDirLookup* lookup_; - - DISALLOW_COPY_AND_ASSIGN(BaseTransaction); -}; - -// Sync API's ReadTransaction is a read-only BaseTransaction. It wraps -// a syncable::ReadTransaction. -class SYNC_EXPORT ReadTransaction : public BaseTransaction { - public: - // Start a new read-only transaction on the specified repository. - explicit ReadTransaction(UserShare* share); - virtual ~ReadTransaction(); - - // BaseTransaction override. - virtual syncable::BaseTransaction* GetWrappedTrans() const; - private: - void* operator new(size_t size); // Transaction is meant for stack use only. - - // The underlying syncable object which this class wraps. - syncable::ReadTransaction* transaction_; - - DISALLOW_COPY_AND_ASSIGN(ReadTransaction); -}; - -// Sync API's WriteTransaction is a read/write BaseTransaction. It wraps -// a syncable::WriteTransaction. -class SYNC_EXPORT WriteTransaction : public BaseTransaction { - public: - // Start a new read/write transaction. - explicit WriteTransaction(UserShare* share); - virtual ~WriteTransaction(); - - // Provide access to the syncable.h transaction from the API WriteNode. - virtual syncable::BaseTransaction* GetWrappedTrans() const; - syncable::WriteTransaction* GetWrappedWriteTrans() { return transaction_; } - - private: - void* operator new(size_t size); // Transaction is meant for stack use only. - - // The underlying syncable object which this class wraps. - syncable::WriteTransaction* transaction_; - - DISALLOW_COPY_AND_ASSIGN(WriteTransaction); -}; - -// SyncManager encapsulates syncable::DirectoryManager and serves as the parent -// of all other objects in the sync API. SyncManager is thread-safe. If -// multiple threads interact with the same local sync repository (i.e. the -// same sqlite database), they should share a single SyncManager instance. The -// caller should typically create one SyncManager for the lifetime of a user -// session. -class SYNC_EXPORT SyncManager { - public: - // SyncInternal contains the implementation of SyncManager, while abstracting - // internal types from clients of the interface. - class SyncInternal; - - // ChangeRecord indicates a single item that changed as a result of a sync - // operation. This gives the sync id of the node that changed, and the type - // of change. To get the actual property values after an ADD or UPDATE, the - // client should get the node with InitByIdLookup(), using the provided id. - struct ChangeRecord { - enum Action { - ACTION_ADD, - ACTION_DELETE, - ACTION_UPDATE, - }; - ChangeRecord() : id(kInvalidId), action(ACTION_ADD) {} - int64 id; - Action action; - }; - - // When the SyncManager is unable to initiate the syncing process due to a - // failure during authentication, AuthProblem describes the actual problem - // more precisely. - enum AuthProblem { - AUTH_PROBLEM_NONE = 0, - // The credentials supplied to GAIA were either invalid, or the locally - // cached credentials have expired. If this happens, the sync system - // will continue as if offline until authentication is reattempted. - AUTH_PROBLEM_INVALID_GAIA_CREDENTIALS, - // The GAIA user is not authorized to use the sync service. - AUTH_PROBLEM_USER_NOT_SIGNED_UP, - // Could not connect to server to verify credentials. This could be in - // response to either failure to connect to GAIA or failure to connect to - // the sync service during authentication. - AUTH_PROBLEM_CONNECTION_FAILED, - }; - - // Status encapsulates detailed state about the internals of the SyncManager. - struct Status { - // Summary is a distilled set of important information that the end-user may - // wish to be informed about (through UI, for example). Note that if a - // summary state requires user interaction (such as auth failures), more - // detailed information may be contained in additional status fields. - enum Summary { - // The internal instance is in an unrecognizable state. This should not - // happen. - INVALID = 0, - // Can't connect to server, but there are no pending changes in - // our local cache. - OFFLINE, - // Can't connect to server, and there are pending changes in our - // local cache. - OFFLINE_UNSYNCED, - // Connected and syncing. - SYNCING, - // Connected, no pending changes. - READY, - // User has chosen to pause syncing. - PAUSED, - // Internal sync error. - CONFLICT, - // Can't connect to server, and we haven't completed the initial - // sync yet. So there's nothing we can do but wait for the server. - OFFLINE_UNUSABLE, - }; - Summary summary; - - // Various server related information. - bool authenticated; // Successfully authenticated via GAIA. - bool server_up; // True if we have received at least one good - // reply from the server. - bool server_reachable; // True if we received any reply from the server. - bool server_broken; // True of the syncer is stopped because of server - // issues. - - bool notifications_enabled; // True only if subscribed for notifications. - int notifications_received; - int notifications_sent; - - // Various Syncer data. - int unsynced_count; - int conflicting_count; - bool syncing; - bool syncer_paused; - bool initial_sync_ended; - bool syncer_stuck; - int64 updates_available; - int64 updates_received; - bool disk_full; - bool invalid_store; - int max_consecutive_errors; // The max number of errors from any component. - }; - - // An interface the embedding application implements to receive notifications - // from the SyncManager. Register an observer via SyncManager::AddObserver. - // This observer is an event driven model as the events may be raised from - // different internal threads, and simply providing an "OnStatusChanged" type - // notification complicates things such as trying to determine "what changed", - // if different members of the Status object are modified from different - // threads. This way, the event is explicit, and it is safe for the Observer - // to dispatch to a native thread or synchronize accordingly. - class Observer { - public: - Observer() { } - virtual ~Observer() { } - // Notify the observer that changes have been applied to the sync model. - // This will be invoked on the same thread as on which ApplyChanges was - // called. |changes| is an array of size |change_count|, and contains the ID - // of each individual item that was changed. |changes| exists only - // for the duration of the call. Because the observer is passed a |trans|, - // the observer can assume a read lock on the database that will be released - // after the function returns. - // - // The SyncManager constructs |changes| in the following guaranteed order: - // - // 1. Deletions, from leaves up to parents. - // 2. Updates to existing items with synced parents & predecessors. - // 3. New items with synced parents & predecessors. - // 4. Items with parents & predecessors in |changes|. - // 5. Repeat #4 until all items are in |changes|. - // - // Thus, an implementation of OnChangesApplied should be able to - // process the change records in the order without having to worry about - // forward dependencies. But since deletions come before reparent - // operations, a delete may temporarily orphan a node that is - // updated later in the list. - virtual void OnChangesApplied(const BaseTransaction* trans, - const ChangeRecord* changes, - int change_count) = 0; - - // A round-trip sync-cycle took place and the syncer has resolved any - // conflicts that may have arisen. This is kept separate from - // OnStatusChanged as there isn't really any state update; it is plainly - // a notification of a state transition. - virtual void OnSyncCycleCompleted() = 0; - - // Called when user interaction may be required due to an auth problem. - virtual void OnAuthProblem(AuthProblem auth_problem) = 0; - - // Called when initialization is complete to the point that SyncManager can - // process changes. This does not necessarily mean authentication succeeded - // or that the SyncManager is online. - // IMPORTANT: Creating any type of transaction before receiving this - // notification is illegal! - // WARNING: Calling methods on the SyncManager before receiving this - // message, unless otherwise specified, produces undefined behavior. - virtual void OnInitializationComplete() = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(Observer); - }; - - // Create an uninitialized SyncManager. Callers must Init() before using. - SyncManager(); - virtual ~SyncManager(); - - // Initialize the sync manager. |database_location| specifies the path of - // the directory in which to locate a sqlite repository storing the syncer - // backend state. Initialization will open the database, or create it if it - // does not already exist. Returns false on failure. - // |sync_server_and_path| and |sync_server_port| represent the Chrome sync - // server to use, and |use_ssl| specifies whether to communicate securely; - // the default is false. - // |gaia_service_id| is the service id used for GAIA authentication. If it's - // null then default will be used. - // |post_factory| will be owned internally and used to create - // instances of an HttpPostProvider. - // |auth_post_factory| will be owned internally and used to create - // instances of an HttpPostProvider for communicating with GAIA. - // TODO(timsteele): It seems like one factory should suffice, but for now to - // avoid having to deal with threading issues since the auth code and syncer - // code live on separate threads that run simultaneously, we just dedicate - // one to each component. Long term we may want to reconsider the HttpBridge - // API to take all the params in one chunk in a threadsafe manner.. which is - // still suboptimal as there will be high contention between the two threads - // on startup; so maybe what we have now is the best solution- it does mirror - // the CURL implementation as each thread creates their own internet handle. - // Investigate. - // |model_safe_worker| ownership is given to the SyncManager. - // |user_agent| is a 7-bit ASCII string suitable for use as the User-Agent - // HTTP header. Used internally when collecting stats to classify clients. - bool Init(const sync_char16* database_location, - const char* sync_server_and_path, - int sync_server_port, - const char* gaia_service_id, - const char* gaia_source, - bool use_ssl, - HttpPostProviderFactory* post_factory, - HttpPostProviderFactory* auth_post_factory, - ModelSafeWorkerInterface* model_safe_worker, - bool attempt_last_user_authentication, - const char* user_agent); - - // Returns the username last used for a successful authentication as a - // null-terminated string. Returns empty if there is no such username. - // The memory is not owned by the caller and should be copied. - const char* GetAuthenticatedUsername(); - - // Submit credentials to GAIA for verification and start the - // syncing process on success. On success, both |username| and the obtained - // auth token are persisted on disk for future re-use. - // If authentication fails, OnAuthProblem is called on our Observer. - // The Observer may, in turn, decide to try again with new - // credentials. Calling this method again is the appropriate course of action - // to "retry". - // |username| and |password| are expected to be owned by the caller. - void Authenticate(const char* username, const char* password); - - // Adds a listener to be notified of sync events. - // NOTE: It is OK (in fact, it's probably a good idea) to call this before - // having received OnInitializationCompleted. - void SetObserver(Observer* observer); - - // Remove the observer set by SetObserver (no op if none was set). - // Make sure to call this if the Observer set in SetObserver is being - // destroyed so the SyncManager doesn't potentially dereference garbage. - void RemoveObserver(); - - // Status-related getters. Typically GetStatusSummary will suffice, but - // GetDetailedSyncStatus can be useful for gathering debug-level details of - // the internals of the sync engine. - Status::Summary GetStatusSummary() const; - Status GetDetailedStatus() const; - - // Get the internal implementation for use by BaseTransaction, etc. - SyncInternal* GetImpl() const; - - // Call periodically from a database-safe thread to persist recent changes - // to the syncapi model. - void SaveChanges(); - - // Invoking this method will result in the syncapi bypassing authentication - // and opening a local store suitable for testing client code. When in this - // mode, nothing will ever get synced to a server (in fact no HTTP - // communication will take place). - // Note: The SyncManager precondition that you must first call Init holds; - // this will fail unless we're initialized. - void SetupForTestMode(const sync_char16* test_username); - - // Issue a final SaveChanges, close sqlite handles, and stop running threads. - // Must be called from the same thread that called Init(). - void Shutdown(); - - UserShare* GetUserShare() const; - - private: - // An opaque pointer to the nested private class. - SyncInternal* data_; - - DISALLOW_COPY_AND_ASSIGN(SyncManager); -}; - -// An interface the embedding application (e.g. Chromium) implements to -// provide required HTTP POST functionality to the syncer backend. -// This interface is designed for one-time use. You create one, use it, and -// create another if you want to make a subsequent POST. -// TODO(timsteele): Bug 1482576. Consider splitting syncapi.h into two files: -// one for the API defining the exports, which doesn't need to be included from -// anywhere internally, and another file for the interfaces like this one. -class HttpPostProviderInterface { - public: - HttpPostProviderInterface() { } - virtual ~HttpPostProviderInterface() { } - - // Use specified user agent string when POSTing. If not called a default UA - // may be used. - virtual void SetUserAgent(const char* user_agent) = 0; - - // Set the URL to POST to. - virtual void SetURL(const char* url, int port) = 0; - - // Set the type, length and content of the POST payload. - // |content_type| is a null-terminated MIME type specifier. - // |content| is a data buffer; Do not interpret as a null-terminated string. - // |content_length| is the total number of chars in |content|. It is used to - // assign/copy |content| data. - virtual void SetPostPayload(const char* content_type, int content_length, - const char* content) = 0; - - // Add the specified cookie to the request context using the url set by - // SetURL as the key. |cookie| should be a standard cookie line - // [e.g "name=val; name2=val2"]. |cookie| should be copied. - virtual void AddCookieForRequest(const char* cookie) = 0; - - // Returns true if the URL request succeeded. If the request failed, - // os_error() may be non-zero and hence contain more information. - virtual bool MakeSynchronousPost(int* os_error_code, int* response_code) = 0; - - // Get the length of the content returned in the HTTP response. - // This does not count the trailing null-terminating character returned - // by GetResponseContent, so it is analogous to calling string.length. - virtual int GetResponseContentLength() const = 0; - - // Get the content returned in the HTTP response. - // This is a null terminated string of characters. - // Value should be copied. - virtual const char* GetResponseContent() const = 0; - - // To simplify passing a vector<string> across this API, we provide the - // following two methods. Use GetResponseCookieCount to bound a loop calling - // GetResponseCookieAt once for each integer in the range - // [0, GetNumCookiesInResponse). The char* returned should be copied. - virtual int GetResponseCookieCount() const = 0; - virtual const char* GetResponseCookieAt(int cookie_number) const = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(HttpPostProviderInterface); -}; - -// A factory to create HttpPostProviders to hide details about the -// implementations and dependencies. -// A factory instance itself should be owned by whomever uses it to create -// HttpPostProviders. -class HttpPostProviderFactory { - public: - // Obtain a new HttpPostProviderInterface instance, owned by caller. - virtual HttpPostProviderInterface* Create() = 0; - - // When the interface is no longer needed (ready to be cleaned up), clients - // must call Destroy(). - // This allows actual HttpPostProvider subclass implementations to be - // reference counted, which is useful if a particular implementation uses - // multiple threads to serve network requests. - virtual void Destroy(HttpPostProviderInterface* http) = 0; - virtual ~HttpPostProviderFactory() { } -}; - -// A class syncapi clients should use whenever the underlying model is bound to -// a particular thread in the embedding application. This exposes an interface -// by which any model-modifying invocations will be forwarded to the -// appropriate thread in the embedding application. -// "model safe" refers to not allowing an embedding application model to fall -// out of sync with the syncable::Directory due to race conditions. -class ModelSafeWorkerInterface { - public: - virtual ~ModelSafeWorkerInterface() { } - // A Visitor is passed to CallDoWorkFromModelSafeThreadAndWait invocations, - // and it's sole purpose is to provide a way for the ModelSafeWorkerInterface - // implementation to actually _do_ the work required, by calling the only - // method on this class, DoWork(). - class Visitor { - public: - virtual ~Visitor() { } - // When on a model safe thread, this should be called to have the syncapi - // actually perform the work needing to be done. - virtual void DoWork() = 0; - }; - // Subclasses should implement to invoke DoWork on |visitor| once on a thread - // appropriate for data model modifications. - // While it doesn't hurt, the impl does not need to be re-entrant (for now). - // Note: |visitor| is owned by caller. - virtual void CallDoWorkFromModelSafeThreadAndWait(Visitor* visitor) = 0; -}; - -} // namespace sync_api - -#endif // CHROME_BROWSER_SYNC_ENGINE_SYNCAPI_H_ diff --git a/chrome/browser/sync/glue/bookmark_model_worker.cc b/chrome/browser/sync/glue/bookmark_model_worker.cc deleted file mode 100644 index be97167..0000000 --- a/chrome/browser/sync/glue/bookmark_model_worker.cc +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifdef CHROME_PERSONALIZATION - -#include "chrome/browser/sync/glue/bookmark_model_worker.h" - -#include "base/message_loop.h" -#include "base/waitable_event.h" - -namespace browser_sync { - -void BookmarkModelWorker::CallDoWorkFromModelSafeThreadAndWait( - ModelSafeWorkerInterface::Visitor* visitor) { - // It is possible this gets called when we are in the STOPPING state, because - // the UI loop has initiated shutdown but the syncer hasn't got the memo yet. - // This is fine, the work will get scheduled and run normally or run by our - // code handling this case in Stop(). - DCHECK_NE(state_, STOPPED); - if (state_ == STOPPED) - return; - if (MessageLoop::current() == bookmark_model_loop_) { - DLOG(WARNING) << "CallDoWorkFromModelSafeThreadAndWait called from " - << "bookmark_model_loop_. Probably a nested invocation?"; - visitor->DoWork(); - return; - } - - // Create an unsignaled event to wait on. - base::WaitableEvent work_done(false, false); - { - // We lock only to avoid PostTask'ing a NULL pending_work_ (because it - // could get Run() in Stop() and call OnTaskCompleted before we post). - // The task is owned by the message loop as per usual. - AutoLock lock(pending_work_lock_); - DCHECK(!pending_work_); - pending_work_ = new CallDoWorkAndSignalTask(visitor, &work_done, this); - bookmark_model_loop_->PostTask(FROM_HERE, pending_work_); - } - syncapi_event_.Signal(); // Notify that the syncapi produced work for us. - work_done.Wait(); -} - -BookmarkModelWorker::~BookmarkModelWorker() { - DCHECK_EQ(state_, STOPPED); -} - -void BookmarkModelWorker::OnSyncerShutdownComplete() { - // The SyncerThread has terminated and we are no longer needed by syncapi. - // The UI loop initiated shutdown and is (or will be) waiting in Stop(). - // We could either be WORKING or RUNNING_MANUAL_SHUTDOWN_PUMP, depending - // on where we timeslice the UI thread in Stop; but we can't be STOPPED, - // because that would imply NotifySyncapiShutdownComplete already signaled. - DCHECK_NE(state_, STOPPED); - - syncapi_has_shutdown_ = true; - syncapi_event_.Signal(); -} - -void BookmarkModelWorker::Stop() { - DCHECK_EQ(MessageLoop::current(), bookmark_model_loop_); - DCHECK_EQ(state_, WORKING); - - // We're on our own now, the beloved UI MessageLoop is no longer running. - // Any tasks scheduled or to be scheduled on the UI MessageLoop will not run. - state_ = RUNNING_MANUAL_SHUTDOWN_PUMP; - - // Drain any final task manually until the SyncerThread tells us it has - // totally finished. Note we use a 'while' loop and not 'if'. The main subtle - // reason for this is that syncapi_event could be signaled the first time we - // come through due to an old CallDoWork call, and we need to keep looping - // until the SyncerThread either calls it again or tells us it is done. There - // should only ever be 0 or 1 tasks Run() here, however. - while (!syncapi_has_shutdown_) { - { - AutoLock lock(pending_work_lock_); - if (pending_work_) - pending_work_->Run(); - } - syncapi_event_.Wait(); // Signaled either by new task, or SyncerThread - // termination. - } - - state_ = STOPPED; -} - -void BookmarkModelWorker::CallDoWorkAndSignalTask::Run() { - if (!visitor_) { - // This can happen during tests or cases where there are more than just the - // default BookmarkModelWorker in existence and it gets destroyed before - // the main UI loop has terminated. There is no easy way to assert the - // loop is running / not running at the moment, so we just provide cancel - // semantics here and short-circuit. - // TODO(timsteele): Maybe we should have the message loop destruction - // observer fire when the loop has ended, just a bit before it - // actually gets destroyed. - return; - } - visitor_->DoWork(); - - // Sever ties with visitor_ to allow the sanity-checking above that we don't - // get run twice. - visitor_ = NULL; - - // Notify the BookmarkModelWorker that scheduled us that we have run - // successfully. - scheduler_->OnTaskCompleted(); - work_done_->Signal(); // Unblock the syncer thread that scheduled us. -} - -} // namespace browser_sync - -#endif // CHROME_PERSONALIZATION
\ No newline at end of file diff --git a/chrome/browser/sync/glue/bookmark_model_worker.h b/chrome/browser/sync/glue/bookmark_model_worker.h deleted file mode 100644 index 4ddb5f8..0000000 --- a/chrome/browser/sync/glue/bookmark_model_worker.h +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifdef CHROME_PERSONALIZATION - -#ifndef CHROME_BROWSER_SYNC_GLUE_BOOKMARK_MODEL_WORKER_H_ -#define CHROME_BROWSER_SYNC_GLUE_BOOKMARK_MODEL_WORKER_H_ - -#include "base/lock.h" -#include "base/task.h" -#include "base/waitable_event.h" -#include "chrome/browser/sync/engine/syncapi.h" - -class MessageLoop; - -namespace browser_sync { - -// A ModelSafeWorker for bookmarks that accepts work requests from the syncapi -// that need to be fulfilled from the MessageLoop home to the BookmarkModel -// (this is typically the "main" UI thread). -// -// Lifetime note: Instances of this class will generally be owned by the -// SyncerThread. When the SyncerThread _object_ is destroyed, the -// BookmarkModelWorker will be destroyed. The SyncerThread object is destroyed -// after the actual syncer pthread has exited. -class BookmarkModelWorker : - public sync_api::ModelSafeWorkerInterface { - public: - explicit BookmarkModelWorker(MessageLoop* bookmark_model_loop) - : state_(WORKING), - pending_work_(NULL), - syncapi_has_shutdown_(false), - bookmark_model_loop_(bookmark_model_loop), - syncapi_event_(false, false) { - } - virtual ~BookmarkModelWorker(); - - // A simple task to signal a waitable event after calling DoWork on a visitor. - class CallDoWorkAndSignalTask : public Task { - public: - CallDoWorkAndSignalTask(ModelSafeWorkerInterface::Visitor* visitor, - base::WaitableEvent* work_done, - BookmarkModelWorker* scheduler) - : visitor_(visitor), work_done_(work_done), scheduler_(scheduler) { - } - virtual ~CallDoWorkAndSignalTask() { } - - // Task implementation. - virtual void Run(); - - private: - // Task data - a visitor that knows how to DoWork, and a waitable event - // to signal after the work has been done. - ModelSafeWorkerInterface::Visitor* visitor_; - base::WaitableEvent* work_done_; - - // The BookmarkModelWorker responsible for scheduling us. - BookmarkModelWorker* const scheduler_; - - DISALLOW_COPY_AND_ASSIGN(CallDoWorkAndSignalTask); - }; - - // Called by the UI thread on shutdown of the sync service. Blocks until - // the BookmarkModelWorker has safely met termination conditions, namely that - // no task scheduled by CallDoWorkFromModelSafeThreadAndWait remains un- - // processed and that syncapi will not schedule any further work for us to do. - void Stop(); - - // ModelSafeWorkerInterface implementation. Called on syncapi SyncerThread. - virtual void CallDoWorkFromModelSafeThreadAndWait( - ModelSafeWorkerInterface::Visitor* visitor); - - // Upon receiving this idempotent call, the ModelSafeWorkerInterface can - // assume no work will ever be scheduled again from now on. If it has any work - // that it has not yet completed, it must make sure to run it as soon as - // possible as the Syncer is trying to shut down. Called from the CoreThread. - void OnSyncerShutdownComplete(); - - // Callback from |pending_work_| to notify us that it has been run. - // Called on |bookmark_model_loop_|. - void OnTaskCompleted() { pending_work_ = NULL; } - - private: - // The life-cycle of a BookmarkModelWorker in three states. - enum State { - // We hit the ground running in this state and remain until - // the UI loop calls Stop(). - WORKING, - // Stop() sequence has been initiated, but we have not received word that - // the SyncerThread has terminated and doesn't need us anymore. Since the - // UI MessageLoop is not running at this point, we manually process any - // last pending_task_ that the Syncer throws at us, effectively dedicating - // the UI thread to terminating the Syncer. - RUNNING_MANUAL_SHUTDOWN_PUMP, - // We have come to a complete stop, no scheduled work remains, and no work - // will be scheduled from now until our destruction. - STOPPED, - }; - - // This is set by the UI thread, but is not explicitly thread safe, so only - // read this value from other threads when you know it is absolutely safe (e.g - // there is _no_ way we can be in CallDoWork with state_ = STOPPED, so it is - // safe to read / compare in this case). - State state_; - - // We keep a reference to any task we have scheduled so we can gracefully - // force them to run if the syncer is trying to shutdown. - Task* pending_work_; - Lock pending_work_lock_; - - // Set by the SyncCoreThread when Syncapi shutdown has completed and the - // SyncerThread has terminated, so no more work will be scheduled. Read by - // the UI thread in Stop(). - bool syncapi_has_shutdown_; - - // The BookmarkModel's home-sweet-home MessageLoop. - MessageLoop* const bookmark_model_loop_; - - // Used as a barrier at shutdown to ensure the SyncerThread terminates before - // we allow the UI thread to return from Stop(). This gets signalled whenever - // one of two events occur: a new pending_work_ task was scheduled, or the - // SyncerThread has terminated. We only care about (1) when we are in Stop(), - // because we have to manually Run() the task. - base::WaitableEvent syncapi_event_; - - DISALLOW_COPY_AND_ASSIGN(BookmarkModelWorker); -}; - -} // namespace browser_sync - -#endif // CHROME_BROWSER_SYNC_GLUE_BOOKMARK_MODEL_WORKER_H_ - -#endif // CHROME_PERSONALIZATION
\ No newline at end of file diff --git a/chrome/browser/sync/glue/bookmark_model_worker_unittest.cc b/chrome/browser/sync/glue/bookmark_model_worker_unittest.cc deleted file mode 100644 index ad674a8..0000000 --- a/chrome/browser/sync/glue/bookmark_model_worker_unittest.cc +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -#ifdef CHROME_PERSONALIZATION - -#include "base/thread.h" -#include "chrome/browser/sync/engine/syncapi.h" -#include "chrome/browser/sync/glue/bookmark_model_worker.h" -#include "testing/gtest/include/gtest/gtest.h" - -using browser_sync::BookmarkModelWorker; -using namespace sync_api; - -// Various boilerplate, primarily for the StopWithPendingWork test. - -class BookmarkModelWorkerVisitor : public ModelSafeWorkerInterface::Visitor { - public: - BookmarkModelWorkerVisitor(MessageLoop* faux_ui_loop, - base::WaitableEvent* was_run, - bool quit_loop) - : faux_ui_loop_(faux_ui_loop), quit_loop_when_run_(quit_loop), - was_run_(was_run) { } - virtual ~BookmarkModelWorkerVisitor() { } - - virtual void DoWork() { - EXPECT_EQ(MessageLoop::current(), faux_ui_loop_); - was_run_->Signal(); - if (quit_loop_when_run_) - MessageLoop::current()->Quit(); - } - - private: - MessageLoop* faux_ui_loop_; - bool quit_loop_when_run_; - base::WaitableEvent* was_run_; - DISALLOW_COPY_AND_ASSIGN(BookmarkModelWorkerVisitor); -}; - -// A faux-syncer that only interacts with its model safe worker. -class Syncer { - public: - explicit Syncer(BookmarkModelWorker* worker) : worker_(worker){ } - ~Syncer() { } - - void SyncShare(BookmarkModelWorkerVisitor* visitor) { - worker_->CallDoWorkFromModelSafeThreadAndWait(visitor); - } - private: - BookmarkModelWorker* worker_; - DISALLOW_COPY_AND_ASSIGN(Syncer); -}; - -// A task run from the SyncerThread to "sync share", ie tell the Syncer to -// ask it's ModelSafeWorker to do something. -class FakeSyncShareTask : public Task { - public: - FakeSyncShareTask(Syncer* syncer, BookmarkModelWorkerVisitor* visitor) - : syncer_(syncer), visitor_(visitor) { - } - virtual void Run() { - syncer_->SyncShare(visitor_); - } - private: - Syncer* syncer_; - BookmarkModelWorkerVisitor* visitor_; - DISALLOW_COPY_AND_ASSIGN(FakeSyncShareTask); -}; - -// A task run from the CoreThread to simulate terminating syncapi. -class FakeSyncapiShutdownTask : public Task { - public: - FakeSyncapiShutdownTask(base::Thread* syncer_thread, - BookmarkModelWorker* worker, - base::WaitableEvent** jobs, - size_t job_count) - : syncer_thread_(syncer_thread), worker_(worker), jobs_(jobs), - job_count_(job_count), all_jobs_done_(false, false) { } - virtual void Run() { - // In real life, we would try and close a sync directory, which would - // result in the syncer calling it's own destructor, which results in - // the SyncerThread::HaltSyncer being called, which sets the - // syncer in RequestEarlyExit mode and waits until the Syncer finishes - // SyncShare to remove the syncer from it's watch. Here we just manually - // wait until all outstanding jobs are done to simulate what happens in - // SyncerThread::HaltSyncer. - all_jobs_done_.WaitMany(jobs_, job_count_); - - // These two calls are made from SyncBackendHost::Core::DoShutdown. - syncer_thread_->Stop(); - worker_->OnSyncerShutdownComplete(); - } - private: - base::Thread* syncer_thread_; - BookmarkModelWorker* worker_; - base::WaitableEvent** jobs_; - size_t job_count_; - base::WaitableEvent all_jobs_done_; - DISALLOW_COPY_AND_ASSIGN(FakeSyncapiShutdownTask); -}; - -class BookmarkModelWorkerTest : public testing::Test { - public: - BookmarkModelWorkerTest() : faux_syncer_thread_("FauxSyncerThread"), - faux_core_thread_("FauxCoreThread") { } - - virtual void SetUp() { - faux_syncer_thread_.Start(); - bmw_.reset(new BookmarkModelWorker(&faux_ui_loop_)); - syncer_.reset(new Syncer(bmw_.get())); - } - - Syncer* syncer() { return syncer_.get(); } - BookmarkModelWorker* bmw() { return bmw_.get(); } - base::Thread* core_thread() { return &faux_core_thread_; } - base::Thread* syncer_thread() { return &faux_syncer_thread_; } - MessageLoop* ui_loop() { return &faux_ui_loop_; } - private: - MessageLoop faux_ui_loop_; - base::Thread faux_syncer_thread_; - base::Thread faux_core_thread_; - scoped_ptr<BookmarkModelWorker> bmw_; - scoped_ptr<Syncer> syncer_; -}; - -TEST_F(BookmarkModelWorkerTest, ScheduledWorkRunsOnUILoop) { - base::WaitableEvent v_was_run(false, false); - scoped_ptr<BookmarkModelWorkerVisitor> v( - new BookmarkModelWorkerVisitor(ui_loop(), &v_was_run, true)); - - syncer_thread()->message_loop()->PostTask(FROM_HERE, - new FakeSyncShareTask(syncer(), v.get())); - - // We are on the UI thread, so run our loop to process the - // (hopefully) scheduled task from a SyncShare invocation. - MessageLoop::current()->Run(); - - bmw()->OnSyncerShutdownComplete(); - bmw()->Stop(); - syncer_thread()->Stop(); -} - -TEST_F(BookmarkModelWorkerTest, StopWithPendingWork) { - // What we want to set up is the following: - // ("ui_thread" is the thread we are currently executing on) - // 1 - simulate the user shutting down the browser, and the ui thread needing - // to terminate the core thread. - // 2 - the core thread is where the syncapi is accessed from, and so it needs - // to shut down the SyncerThread. - // 3 - the syncer is waiting on the BookmarkModelWorker to - // perform a task for it. - // The BookmarkModelWorker's manual shutdown pump will save the day, as the - // UI thread is not actually trying to join() the core thread, it is merely - // waiting for the SyncerThread to give it work or to finish. After that, it - // will join the core thread which should succeed as the SyncerThread has left - // the building. Unfortunately this test as written is not provably decidable, - // as it will always halt on success, but it may not on failure (namely if - // the task scheduled by the Syncer is _never_ run). - core_thread()->Start(); - base::WaitableEvent v_ran(false, false); - scoped_ptr<BookmarkModelWorkerVisitor> v(new BookmarkModelWorkerVisitor( - ui_loop(), &v_ran, false)); - base::WaitableEvent* jobs[] = { &v_ran }; - - // The current message loop is not running, so queue a task to cause - // BookmarkModelWorker::Stop() to play a crucial role. See comment below. - syncer_thread()->message_loop()->PostTask(FROM_HERE, - new FakeSyncShareTask(syncer(), v.get())); - - // This is what gets the core_thread blocked on the syncer_thread. - core_thread()->message_loop()->PostTask(FROM_HERE, - new FakeSyncapiShutdownTask(syncer_thread(), bmw(), jobs, 1)); - - // This is what gets the UI thread blocked until NotifyExitRequested, - // which is called when FakeSyncapiShutdownTask runs and deletes the syncer. - bmw()->Stop(); - - EXPECT_FALSE(syncer_thread()->IsRunning()); - core_thread()->Stop(); -} - -TEST_F(BookmarkModelWorkerTest, HypotheticalManualPumpFlooding) { - // This situation should not happen in real life because the Syncer should - // never send more than one CallDoWork notification after early_exit_requested - // has been set, but our BookmarkModelWorker is built to handle this case - // nonetheless. It may be needed in the future, and since we support it and - // it is not actually exercised in the wild this test is essential. - // It is identical to above except we schedule more than one visitor. - core_thread()->Start(); - - // Our ammunition. - base::WaitableEvent fox1_ran(false, false); - scoped_ptr<BookmarkModelWorkerVisitor> fox1(new BookmarkModelWorkerVisitor( - ui_loop(), &fox1_ran, false)); - base::WaitableEvent fox2_ran(false, false); - scoped_ptr<BookmarkModelWorkerVisitor> fox2(new BookmarkModelWorkerVisitor( - ui_loop(), &fox2_ran, false)); - base::WaitableEvent fox3_ran(false, false); - scoped_ptr<BookmarkModelWorkerVisitor> fox3(new BookmarkModelWorkerVisitor( - ui_loop(), &fox3_ran, false)); - base::WaitableEvent* jobs[] = { &fox1_ran, &fox2_ran, &fox3_ran }; - - // The current message loop is not running, so queue a task to cause - // BookmarkModelWorker::Stop() to play a crucial role. See comment below. - syncer_thread()->message_loop()->PostTask(FROM_HERE, - new FakeSyncShareTask(syncer(), fox1.get())); - syncer_thread()->message_loop()->PostTask(FROM_HERE, - new FakeSyncShareTask(syncer(), fox2.get())); - - // This is what gets the core_thread blocked on the syncer_thread. - core_thread()->message_loop()->PostTask(FROM_HERE, - new FakeSyncapiShutdownTask(syncer_thread(), bmw(), jobs, 3)); - syncer_thread()->message_loop()->PostTask(FROM_HERE, - new FakeSyncShareTask(syncer(), fox3.get())); - - // This is what gets the UI thread blocked until NotifyExitRequested, - // which is called when FakeSyncapiShutdownTask runs and deletes the syncer. - bmw()->Stop(); - - // Was the thread killed? - EXPECT_FALSE(syncer_thread()->IsRunning()); - core_thread()->Stop(); -} - -#endif // CHROME_PERSONALIZATION
\ No newline at end of file diff --git a/chrome/browser/sync/glue/http_bridge.cc b/chrome/browser/sync/glue/http_bridge.cc deleted file mode 100644 index 1a01c87..0000000 --- a/chrome/browser/sync/glue/http_bridge.cc +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifdef CHROME_PERSONALIZATION - -#include "chrome/browser/sync/glue/http_bridge.h" - -#include "base/message_loop.h" -#include "base/string_util.h" -#include "chrome/browser/chrome_thread.h" -#include "chrome/browser/profile.h" -#include "net/base/cookie_monster.h" -#include "net/base/load_flags.h" -#include "net/http/http_network_layer.h" -#include "net/proxy/proxy_service.h" -#include "net/url_request/url_request_status.h" -#include "webkit/glue/webkit_glue.h" - -namespace browser_sync { - -HttpBridge::RequestContext* HttpBridgeFactory::GetRequestContext() { - if (!request_context_) { - request_context_ = - new HttpBridge::RequestContext(Profile::GetDefaultRequestContext()); - request_context_->AddRef(); - } - return request_context_; -} - -HttpBridgeFactory::~HttpBridgeFactory() { - if (request_context_) { - // Clean up request context on IO thread. - ChromeThread::GetMessageLoop(ChromeThread::IO)->ReleaseSoon(FROM_HERE, - request_context_); - request_context_ = NULL; - } -} - -sync_api::HttpPostProviderInterface* HttpBridgeFactory::Create() { - // TODO(timsteele): We want the active profile request context. - HttpBridge* http = new HttpBridge(GetRequestContext(), - ChromeThread::GetMessageLoop(ChromeThread::IO)); - http->AddRef(); - return http; -} - -void HttpBridgeFactory::Destroy(sync_api::HttpPostProviderInterface* http) { - static_cast<HttpBridge*>(http)->Release(); -} - -HttpBridge::RequestContext::RequestContext( - const URLRequestContext* baseline_context) { - - // Create empty, in-memory cookie store. - cookie_store_ = new net::CookieMonster(); - - // We don't use a cache for bridged loads, but we do want to share proxy info. - host_resolver_ = baseline_context->host_resolver(); - proxy_service_ = baseline_context->proxy_service(); - http_transaction_factory_ = - net::HttpNetworkLayer::CreateFactory(host_resolver_, proxy_service_); - - // TODO(timsteele): We don't currently listen for pref changes of these - // fields or CookiePolicy; I'm not sure we want to strictly follow the - // default settings, since for example if the user chooses to block all - // cookies, sync will start failing. Also it seems like accept_lang/charset - // should be tied to whatever the sync servers expect (if anything). These - // fields should probably just be settable by sync backend; though we should - // figure out if we need to give the user explicit control over policies etc. - accept_language_ = baseline_context->accept_language(); - accept_charset_ = baseline_context->accept_charset(); - - // We default to the browser's user agent. This can (and should) be overridden - // with set_user_agent. - user_agent_ = webkit_glue::GetUserAgent(GURL()); -} - -HttpBridge::RequestContext::~RequestContext() { - delete cookie_store_; - delete http_transaction_factory_; -} - -HttpBridge::HttpBridge(HttpBridge::RequestContext* context, - MessageLoop* io_loop) - : context_for_request_(context), - url_poster_(NULL), - created_on_loop_(MessageLoop::current()), - io_loop_(io_loop), - request_completed_(false), - request_succeeded_(false), - http_response_code_(-1), - http_post_completed_(false, false), - use_io_loop_for_testing_(false) { - context_for_request_->AddRef(); -} - -HttpBridge::~HttpBridge() { - io_loop_->ReleaseSoon(FROM_HERE, context_for_request_); -} - -void HttpBridge::SetUserAgent(const char* user_agent) { - DCHECK_EQ(MessageLoop::current(), created_on_loop_); - DCHECK(!request_completed_); - context_for_request_->set_user_agent(user_agent); -} - -void HttpBridge::SetURL(const char* url, int port) { - DCHECK_EQ(MessageLoop::current(), created_on_loop_); - DCHECK(!request_completed_); - DCHECK(url_for_request_.is_empty()) - << "HttpBridge::SetURL called more than once?!"; - GURL temp(url); - GURL::Replacements replacements; - std::string port_str = IntToString(port); - replacements.SetPort(port_str.c_str(), - url_parse::Component(0, port_str.length())); - url_for_request_ = temp.ReplaceComponents(replacements); -} - -void HttpBridge::SetPostPayload(const char* content_type, - int content_length, - const char* content) { - DCHECK_EQ(MessageLoop::current(), created_on_loop_); - DCHECK(!request_completed_); - DCHECK(content_type_.empty()) << "Bridge payload already set."; - DCHECK_GE(content_length, 0) << "Content length < 0"; - content_type_ = content_type; - if (!content || (content_length == 0)) { - DCHECK_EQ(content_length, 0); - request_content_ = " "; // TODO(timsteele): URLFetcher requires non-empty - // content for POSTs whereas CURL does not, for now - // we hack this to support the sync backend. - } else { - request_content_.assign(content, content_length); - } -} - -void HttpBridge::AddCookieForRequest(const char* cookie) { - DCHECK_EQ(MessageLoop::current(), created_on_loop_); - DCHECK(!request_completed_); - DCHECK(url_for_request_.is_valid()) << "Valid URL not set."; - if (!url_for_request_.is_valid()) return; - - if (!context_for_request_->cookie_store()->SetCookie(url_for_request_, - cookie)) { - DLOG(WARNING) << "Cookie " << cookie - << " could not be added for url: " << url_for_request_ << "."; - } -} - -bool HttpBridge::MakeSynchronousPost(int* os_error_code, int* response_code) { - DCHECK_EQ(MessageLoop::current(), created_on_loop_); - DCHECK(!request_completed_); - DCHECK(url_for_request_.is_valid()) << "Invalid URL for request"; - DCHECK(!content_type_.empty()) << "Payload not set"; - DCHECK(context_for_request_->is_user_agent_set()) << "User agent not set"; - - io_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, - &HttpBridge::CallMakeAsynchronousPost)); - - if (!http_post_completed_.Wait()) // Block until network request completes. - NOTREACHED(); // See OnURLFetchComplete. - - DCHECK(request_completed_); - *os_error_code = os_error_code_; - *response_code = http_response_code_; - return request_succeeded_; -} - -void HttpBridge::MakeAsynchronousPost() { - DCHECK_EQ(MessageLoop::current(), io_loop_); - DCHECK(!request_completed_); - - url_poster_ = new URLFetcher(url_for_request_, URLFetcher::POST, this); - url_poster_->set_request_context(context_for_request_); - url_poster_->set_upload_data(content_type_, request_content_); - - if (use_io_loop_for_testing_) - url_poster_->set_io_loop(io_loop_); - - url_poster_->Start(); -} - -int HttpBridge::GetResponseContentLength() const { - DCHECK_EQ(MessageLoop::current(), created_on_loop_); - DCHECK(request_completed_); - return response_content_.size(); -} - -const char* HttpBridge::GetResponseContent() const { - DCHECK_EQ(MessageLoop::current(), created_on_loop_); - DCHECK(request_completed_); - return response_content_.c_str(); -} - -int HttpBridge::GetResponseCookieCount() const { - DCHECK_EQ(MessageLoop::current(), created_on_loop_); - DCHECK(request_completed_); - return response_cookies_.size(); -} - -const char* HttpBridge::GetResponseCookieAt(int cookie_number) const { - DCHECK_EQ(MessageLoop::current(), created_on_loop_); - DCHECK(request_completed_); - bool valid_number = (cookie_number >= 0) && - (static_cast<size_t>(cookie_number) < response_cookies_.size()); - DCHECK(valid_number); - if (!valid_number) - return NULL; - return response_cookies_[cookie_number].c_str(); -} - -void HttpBridge::OnURLFetchComplete(const URLFetcher *source, const GURL &url, - const URLRequestStatus &status, - int response_code, - const ResponseCookies &cookies, - const std::string &data) { - DCHECK_EQ(MessageLoop::current(), io_loop_); - - request_completed_ = true; - request_succeeded_ = (URLRequestStatus::SUCCESS == status.status()); - http_response_code_ = response_code; - os_error_code_ = status.os_error(); - - // TODO(timsteele): For now we need this "fixup" to match up with what the - // sync backend expects. This seems to be non-standard and shouldn't be done - // here in HttpBridge, and it breaks part of the unittest. - for (size_t i = 0; i < cookies.size(); ++i) { - net::CookieMonster::ParsedCookie parsed_cookie(cookies[i]); - std::string cookie = " \t \t \t \t \t"; - cookie += parsed_cookie.Name() + "\t"; - cookie += parsed_cookie.Value(); - response_cookies_.push_back(cookie); - } - - response_content_ = data; - - // End of the line for url_poster_. It lives only on the io_loop. - // We defer deletion because we're inside a callback from a component of the - // URLFetcher, so it seems most natural / "polite" to let the stack unwind. - io_loop_->DeleteSoon(FROM_HERE, url_poster_); - url_poster_ = NULL; - - // Wake the blocked syncer thread in MakeSynchronousPost. - // WARNING: DONT DO ANYTHING AFTER THIS CALL! |this| may be deleted! - http_post_completed_.Signal(); -} - -} // namespace browser_sync - -#endif // CHROME_PERSONALIZATION
\ No newline at end of file diff --git a/chrome/browser/sync/glue/http_bridge.h b/chrome/browser/sync/glue/http_bridge.h deleted file mode 100644 index 1e11e90..0000000 --- a/chrome/browser/sync/glue/http_bridge.h +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifdef CHROME_PERSONALIZATION - -#ifndef CHROME_BROWSER_SYNC_GLUE_HTTP_BRIDGE_H_ -#define CHROME_BROWSER_SYNC_GLUE_HTTP_BRIDGE_H_ - -#include "base/ref_counted.h" -#include "base/waitable_event.h" -#include "chrome/browser/net/url_fetcher.h" -#include "chrome/browser/sync/engine/syncapi.h" -#include "googleurl/src/gurl.h" -#include "net/url_request/url_request_context.h" -#include "testing/gtest/include/gtest/gtest_prod.h" - -class MessageLoop; -class HttpBridgeTest; - -namespace browser_sync { - -// A bridge between the syncer and Chromium HTTP layers. -// Provides a way for the sync backend to use Chromium directly for HTTP -// requests rather than depending on a third party provider (e.g libcurl). -// This is a one-time use bridge. Create one for each request you want to make. -// It is RefCountedThreadSafe because it can PostTask to the io loop, and thus -// needs to stick around across context switches, etc. -class HttpBridge : public base::RefCountedThreadSafe<HttpBridge>, - public sync_api::HttpPostProviderInterface, - public URLFetcher::Delegate { - public: - // A request context used for HTTP requests bridged from the sync backend. - // A bridged RequestContext has a dedicated in-memory cookie store and does - // not use a cache. Thus the same type can be used for incognito mode. - // TODO(timsteele): We subclass here instead of add a factory method on - // ChromeURLRequestContext because: - // 1) we want the ability to set_user_agent - // 2) avoids ifdefs for now - // 3) not sure we want to strictly follow settings for cookie policy, - // accept lang/charset, since changing these could break syncing. - class RequestContext : public URLRequestContext { - public: - // |baseline_context| is used to obtain the accept-language, - // accept-charsets, and proxy service information for bridged requests. - // Typically |baseline_context| should be the URLRequestContext of the - // currently active profile. - explicit RequestContext(const URLRequestContext* baseline_context); - virtual ~RequestContext(); - - // Set the user agent for requests using this context. The default is - // the browser's UA string. - void set_user_agent(const std::string& ua) { user_agent_ = ua; } - bool is_user_agent_set() const { return !user_agent_.empty(); } - - virtual const std::string& GetUserAgent(const GURL& url) const { - // If the user agent is set explicitly return that, otherwise call the - // base class method to return default value. - return user_agent_.empty() ? - URLRequestContext::GetUserAgent(url) : user_agent_; - } - - private: - std::string user_agent_; - - DISALLOW_COPY_AND_ASSIGN(RequestContext); - }; - - HttpBridge(RequestContext* context, MessageLoop* io_loop); - virtual ~HttpBridge(); - - // sync_api::HttpPostProvider implementation. - virtual void SetUserAgent(const char* user_agent); - virtual void SetURL(const char* url, int port); - virtual void SetPostPayload(const char* content_type, int content_length, - const char* content); - virtual void AddCookieForRequest(const char* cookie); - virtual bool MakeSynchronousPost(int* os_error_code, int* response_code); - virtual int GetResponseContentLength() const; - virtual const char* GetResponseContent() const; - virtual int GetResponseCookieCount() const; - virtual const char* GetResponseCookieAt(int cookie_number) const; - - // URLFetcher::Delegate implementation. - virtual void OnURLFetchComplete(const URLFetcher* source, const GURL& url, - const URLRequestStatus& status, - int response_code, - const ResponseCookies& cookies, - const std::string& data); - - protected: - // Protected virtual so the unit test can override to shunt network requests. - virtual void MakeAsynchronousPost(); - - private: - friend class ::HttpBridgeTest; - - // Called on the io_loop_ to issue the network request. The extra level - // of indirection is so that the unit test can override this behavior but we - // still have a function to statically pass to PostTask. - void CallMakeAsynchronousPost() { MakeAsynchronousPost(); } - - // A customized URLRequestContext for bridged requests. See RequestContext - // definition for details. - RequestContext* context_for_request_; - - // Our hook into the network layer is a URLFetcher. USED ONLY ON THE IO LOOP, - // so we can block created_on_loop_ while the fetch is in progress. - // NOTE: This is not a scoped_ptr for a reason. It must be deleted on the same - // thread that created it, which isn't the same thread |this| gets deleted on. - // We must manually delete url_poster_ on the io_loop_. - URLFetcher* url_poster_; - - // The message loop of the thread we were created on. This is the thread that - // will block on MakeSynchronousPost while the IO thread fetches data from - // the network. - // This should be the main syncer thread (SyncerThread) which is what blocks - // on network IO through curl_easy_perform. - MessageLoop* const created_on_loop_; - - // Member variable for the IO loop instead of asking ChromeThread directly, - // done this way for testability. - MessageLoop* const io_loop_; - - // The URL to POST to. - GURL url_for_request_; - - // POST payload information. - std::string content_type_; - std::string request_content_; - - // Cached response data. - bool request_completed_; - bool request_succeeded_; - int http_response_code_; - int os_error_code_; - ResponseCookies response_cookies_; - std::string response_content_; - - // A waitable event we use to provide blocking semantics to - // MakeSynchronousPost. We block created_on_loop_ while the io_loop_ fetches - // network request. - base::WaitableEvent http_post_completed_; - - // This is here so that the unit test subclass can force our URLFetcher to - // use the io_loop_ passed on construction for network requests, rather than - // ChromeThread::IO's message loop (which won't exist in testing). - bool use_io_loop_for_testing_; - - DISALLOW_COPY_AND_ASSIGN(HttpBridge); -}; - -class HttpBridgeFactory - : public sync_api::HttpPostProviderFactory { - public: - HttpBridgeFactory() : request_context_(NULL) { } - virtual ~HttpBridgeFactory(); - virtual sync_api::HttpPostProviderInterface* Create(); - virtual void Destroy(sync_api::HttpPostProviderInterface* http); - private: - HttpBridge::RequestContext* GetRequestContext(); - // We must Release() this from the IO thread. - HttpBridge::RequestContext* request_context_; - DISALLOW_COPY_AND_ASSIGN(HttpBridgeFactory); -}; - -} // namespace browser_sync - -#endif // CHROME_BROWSER_SYNC_GLUE_HTTP_BRIDGE_H_ - -#endif // CHROME_PERSONALIZATION
\ No newline at end of file diff --git a/chrome/browser/sync/glue/http_bridge_unittest.cc b/chrome/browser/sync/glue/http_bridge_unittest.cc deleted file mode 100644 index 4dd9a9b..0000000 --- a/chrome/browser/sync/glue/http_bridge_unittest.cc +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -#ifdef CHROME_PERSONALIZATION - -#include "base/thread.h" -#include "chrome/browser/sync/glue/http_bridge.h" -#include "net/url_request/url_request_unittest.h" -#include "testing/gtest/include/gtest/gtest.h" - -using browser_sync::HttpBridge; - -namespace { -// TODO(timsteele): Should use PathService here. See Chromium Issue 3113. -const char16 kDocRoot[] = L"chrome/test/data"; -} - -class HttpBridgeTest : public testing::Test { - public: - HttpBridgeTest() : io_thread_("HttpBridgeTest IO thread") { - } - - virtual void SetUp() { - base::Thread::Options options; - options.message_loop_type = MessageLoop::TYPE_IO; - io_thread_.StartWithOptions(options); - } - - virtual void TearDown() { - io_thread_.Stop(); - } - - HttpBridge* BuildBridge() { - if (!request_context_) { - request_context_ = new HttpBridge::RequestContext( - new TestURLRequestContext()); - } - HttpBridge* bridge = new HttpBridge(request_context_, - io_thread_.message_loop()); - bridge->use_io_loop_for_testing_ = true; - return bridge; - } - - MessageLoop* io_thread_loop() { return io_thread_.message_loop(); } - private: - // Separate thread for IO used by the HttpBridge. - scoped_refptr<HttpBridge::RequestContext> request_context_; - base::Thread io_thread_; -}; - -// An HttpBridge that doesn't actually make network requests and just calls -// back with dummy response info. -class ShuntedHttpBridge : public HttpBridge { - public: - ShuntedHttpBridge(const URLRequestContext* baseline_context, - MessageLoop* io_loop, HttpBridgeTest* test) - : HttpBridge(new HttpBridge::RequestContext(baseline_context), - io_loop), test_(test) { } - protected: - virtual void MakeAsynchronousPost() { - ASSERT_TRUE(MessageLoop::current() == test_->io_thread_loop()); - // We don't actually want to make a request for this test, so just callback - // as if it completed. - test_->io_thread_loop()->PostTask(FROM_HERE, - NewRunnableMethod(this, &ShuntedHttpBridge::CallOnURLFetchComplete)); - } - private: - void CallOnURLFetchComplete() { - ASSERT_TRUE(MessageLoop::current() == test_->io_thread_loop()); - // We return one cookie and a dummy content response. - ResponseCookies cookies; - cookies.push_back("cookie1"); - std::string response_content = "success!"; - OnURLFetchComplete(NULL, GURL("www.google.com"), URLRequestStatus(), - 200, cookies, response_content); - } - HttpBridgeTest* test_; -}; - -// Test the HttpBridge without actually making any network requests. -TEST_F(HttpBridgeTest, TestMakeSynchronousPostShunted) { - scoped_refptr<HttpBridge> http_bridge(new ShuntedHttpBridge( - new TestURLRequestContext(), io_thread_loop(), this)); - http_bridge->SetUserAgent("bob"); - http_bridge->SetURL("http://www.google.com", 9999); - http_bridge->SetPostPayload("text/plain", 2, " "); - - int os_error = 0; - int response_code = 0; - bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); - EXPECT_TRUE(success); - EXPECT_EQ(200, response_code); - EXPECT_EQ(0, os_error); - EXPECT_EQ(1, http_bridge->GetResponseCookieCount()); - // TODO(timsteele): This is a valid test condition, it's just temporarily - // broken so that HttpBridge satisfies the ServerConnectionManager. -#if FIXED_SYNC_BACKEND_COOKIE_PARSING - EXPECT_EQ(std::string("cookie1"), - std::string(http_bridge->GetResponseCookieAt(0))); -#endif - EXPECT_EQ(8, http_bridge->GetResponseContentLength()); - EXPECT_EQ(std::string("success!"), - std::string(http_bridge->GetResponseContent())); -} - -// Full round-trip test of the HttpBridge, using default UA string and -// no request cookies. -TEST_F(HttpBridgeTest, TestMakeSynchronousPostLiveWithPayload) { - scoped_refptr<HTTPTestServer> server = HTTPTestServer::CreateServer(kDocRoot, - NULL); - ASSERT_TRUE(NULL != server.get()); - - scoped_refptr<HttpBridge> http_bridge(BuildBridge()); - - std::string payload = "this should be echoed back"; - GURL echo = server->TestServerPage("echo"); - http_bridge->SetURL(echo.spec().c_str(), echo.IntPort()); - http_bridge->SetPostPayload("application/x-www-form-urlencoded", - payload.length() + 1, payload.c_str()); - int os_error = 0; - int response_code = 0; - bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); - EXPECT_TRUE(success); - EXPECT_EQ(200, response_code); - EXPECT_EQ(0, os_error); - EXPECT_EQ(0, http_bridge->GetResponseCookieCount()); - EXPECT_EQ(payload.length() + 1, http_bridge->GetResponseContentLength()); - EXPECT_EQ(payload, std::string(http_bridge->GetResponseContent())); -} - -// Full round-trip test of the HttpBridge, using custom UA string and -// multiple request cookies. -TEST_F(HttpBridgeTest, TestMakeSynchronousPostLiveComprehensive) { - scoped_refptr<HTTPTestServer> server = HTTPTestServer::CreateServer(kDocRoot, - NULL); - ASSERT_TRUE(NULL != server.get()); - scoped_refptr<HttpBridge> http_bridge(BuildBridge()); - - GURL echo_header = server->TestServerPage("echoall"); - http_bridge->SetUserAgent("bob"); - http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort()); - http_bridge->AddCookieForRequest("foo=bar"); - http_bridge->AddCookieForRequest("baz=boo"); - std::string test_payload = "###TEST PAYLOAD###"; - http_bridge->SetPostPayload("text/html", test_payload.length() + 1, - test_payload.c_str()); - - int os_error = 0; - int response_code = 0; - bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); - EXPECT_TRUE(success); - EXPECT_EQ(200, response_code); - EXPECT_EQ(0, os_error); - EXPECT_EQ(0, http_bridge->GetResponseCookieCount()); - std::string response = http_bridge->GetResponseContent(); -// TODO(timsteele): This is a valid test condition, it's just temporarily -// broken so that HttpBridge satisfies the ServerConnectionManager; the format -// seems to be surprising the TestServer, because it isn't echoing the headers -// properly. -#if FIXED_SYNCER_BACKEND_COOKIE_PARSING - EXPECT_NE(std::string::npos, response.find("Cookie: foo=bar; baz=boo")); - EXPECT_NE(std::string::npos, response.find("User-Agent: bob")); -#endif - EXPECT_NE(std::string::npos, response.find(test_payload.c_str())); -} - -#endif // CHROME_PERSONALIZATION
\ No newline at end of file diff --git a/chrome/browser/sync/glue/model_associator.cc b/chrome/browser/sync/glue/model_associator.cc deleted file mode 100644 index 3d73612..0000000 --- a/chrome/browser/sync/glue/model_associator.cc +++ /dev/null @@ -1,504 +0,0 @@ -// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifdef CHROME_PERSONALIZATION - -#include "chrome/browser/sync/glue/model_associator.h" - -#include <stack> - -#include "base/message_loop.h" -#include "base/task.h" -#include "chrome/browser/bookmarks/bookmark_model.h" -#include "chrome/browser/sync/engine/syncapi.h" -#include "chrome/browser/sync/profile_sync_service.h" - -namespace browser_sync { - -// The sync protocol identifies top-level entities by means of well-known tags, -// which should not be confused with titles. Each tag corresponds to a -// singleton instance of a particular top-level node in a user's share; the -// tags are consistent across users. The tags allow us to locate the specific -// folders whose contents we care about synchronizing, without having to do a -// lookup by name or path. The tags should not be made user-visible. -// For example, the tag "bookmark_bar" represents the permanent node for -// bookmarks bar in Chrome. The tag "other_bookmarks" represents the permanent -// folder Other Bookmarks in Chrome. -// -// It is the responsibility of something upstream (at time of writing, -// the sync server) to create these tagged nodes when initializing sync -// for the first time for a user. Thus, once the backend finishes -// initializing, the ProfileSyncService can rely on the presence of tagged -// nodes. -// -// TODO(ncarter): Pull these tags from an external protocol specification -// rather than hardcoding them here. -static const wchar_t* kOtherBookmarksTag = L"other_bookmarks"; -static const wchar_t* kBookmarkBarTag = L"bookmark_bar"; - -// Bookmark comparer for map of bookmark nodes. -class BookmarkComparer { - public: - // Compares the two given nodes and returns whether node1 should appear - // before node2 in strict weak ordering. - bool operator()(const BookmarkNode* node1, - const BookmarkNode* node2) const { - DCHECK(node1); - DCHECK(node2); - - // Keep folder nodes before non-folder nodes. - if (node1->is_folder() != node2->is_folder()) - return node1->is_folder(); - - int result = node1->GetTitle().compare(node2->GetTitle()); - if (result != 0) - return result < 0; - - result = node1->GetURL().spec().compare(node2->GetURL().spec()); - if (result != 0) - return result < 0; - - return false; - } -}; - -// Provides the following abstraction: given a parent bookmark node, find best -// matching child node for many sync nodes. -class BookmarkNodeFinder { - public: - // Creats an instance with the given parent bookmark node. - explicit BookmarkNodeFinder(const BookmarkNode* parent_node); - - // Finds best matching node for the given sync node. - // Returns the matching node if one exists; NULL otherwise. If a matching - // node is found, it's removed for further matches. - const BookmarkNode* FindBookmarkNode(const sync_api::BaseNode& sync_node); - - private: - typedef std::set<const BookmarkNode*, BookmarkComparer> BookmarkNodesSet; - - const BookmarkNode* parent_node_; - BookmarkNodesSet child_nodes_; - - DISALLOW_COPY_AND_ASSIGN(BookmarkNodeFinder); -}; - -BookmarkNodeFinder::BookmarkNodeFinder(const BookmarkNode* parent_node) - : parent_node_(parent_node) { - for (int i = 0; i < parent_node_->GetChildCount(); ++i) - child_nodes_.insert(parent_node_->GetChild(i)); -} - -const BookmarkNode* BookmarkNodeFinder::FindBookmarkNode( - const sync_api::BaseNode& sync_node) { - // Create a bookmark node from the given sync node. - BookmarkNode temp_node(GURL(sync_node.GetURL())); - temp_node.SetTitle(UTF16ToWide(sync_node.GetTitle())); - if (sync_node.GetIsFolder()) - temp_node.SetType(BookmarkNode::FOLDER); - else - temp_node.SetType(BookmarkNode::URL); - - const BookmarkNode* result = NULL; - BookmarkNodesSet::iterator iter = child_nodes_.find(&temp_node); - if (iter != child_nodes_.end()) { - result = *iter; - // Remove the matched node so we don't match with it again. - child_nodes_.erase(iter); - } - - return result; -} - -ModelAssociator::ModelAssociator(ProfileSyncService* sync_service) - : sync_service_(sync_service), - task_pending_(false) { - DCHECK(sync_service_); -} - -void ModelAssociator::ClearAll() { - id_map_.clear(); - id_map_inverse_.clear(); - dirty_assocations_sync_ids_.clear(); -} - -int64 ModelAssociator::GetSyncIdFromBookmarkId(int64 node_id) const { - BookmarkIdToSyncIdMap::const_iterator iter = id_map_.find(node_id); - return iter == id_map_.end() ? sync_api::kInvalidId : iter->second; -} - -bool ModelAssociator::GetBookmarkIdFromSyncId(int64 sync_id, - int64* node_id) const { - SyncIdToBookmarkIdMap::const_iterator iter = id_map_inverse_.find(sync_id); - if (iter == id_map_inverse_.end()) - return false; - *node_id = iter->second; - return true; -} - -bool ModelAssociator::InitSyncNodeFromBookmarkId( - int64 node_id, - sync_api::BaseNode* sync_node) { - DCHECK(sync_node); - int64 sync_id = GetSyncIdFromBookmarkId(node_id); - if (sync_id == sync_api::kInvalidId) - return false; - if (!sync_node->InitByIdLookup(sync_id)) - return false; - DCHECK(sync_node->GetId() == sync_id); - return true; -} - -const BookmarkNode* ModelAssociator::GetBookmarkNodeFromSyncId(int64 sync_id) { - int64 node_id; - if (!GetBookmarkIdFromSyncId(sync_id, &node_id)) - return false; - BookmarkModel* model = sync_service_->profile()->GetBookmarkModel(); - return model->GetNodeByID(node_id); -} - -void ModelAssociator::AssociateIds(int64 node_id, int64 sync_id) { - DCHECK_NE(sync_id, sync_api::kInvalidId); - DCHECK(id_map_.find(node_id) == id_map_.end()); - DCHECK(id_map_inverse_.find(sync_id) == id_map_inverse_.end()); - id_map_[node_id] = sync_id; - id_map_inverse_[sync_id] = node_id; - dirty_assocations_sync_ids_.insert(sync_id); - PostPersistAssociationsTask(); -} - -void ModelAssociator::DisassociateIds(int64 sync_id) { - SyncIdToBookmarkIdMap::iterator iter = id_map_inverse_.find(sync_id); - if (iter == id_map_inverse_.end()) - return; - id_map_.erase(iter->second); - id_map_inverse_.erase(iter); - dirty_assocations_sync_ids_.erase(sync_id); -} - -bool ModelAssociator::BookmarkModelHasUserCreatedNodes() const { - BookmarkModel* model = sync_service_->profile()->GetBookmarkModel(); - DCHECK(model->IsLoaded()); - return model->GetBookmarkBarNode()->GetChildCount() > 0 || - model->other_node()->GetChildCount() > 0; -} - -bool ModelAssociator::SyncModelHasUserCreatedNodes() { - int64 bookmark_bar_sync_id; - if (!GetSyncIdForTaggedNode(WideToUTF16(kBookmarkBarTag), - &bookmark_bar_sync_id)) { - NOTREACHED(); - return false; - } - int64 other_bookmarks_sync_id; - if (!GetSyncIdForTaggedNode(WideToUTF16(kOtherBookmarksTag), - &other_bookmarks_sync_id)) { - NOTREACHED(); - return false; - } - - sync_api::ReadTransaction trans( - sync_service_->backend()->GetUserShareHandle()); - - sync_api::ReadNode bookmark_bar_node(&trans); - if (!bookmark_bar_node.InitByIdLookup(bookmark_bar_sync_id)) { - NOTREACHED(); - return false; - } - - sync_api::ReadNode other_bookmarks_node(&trans); - if (!other_bookmarks_node.InitByIdLookup(other_bookmarks_sync_id)) { - NOTREACHED(); - return false; - } - - // Sync model has user created nodes if either one of the permanent nodes - // has children. - return bookmark_bar_node.GetFirstChildId() != sync_api::kInvalidId || - other_bookmarks_node.GetFirstChildId() != sync_api::kInvalidId; -} - -bool ModelAssociator::NodesMatch(const BookmarkNode* bookmark, - const sync_api::BaseNode* sync_node) const { - if (bookmark->GetTitle() != UTF16ToWide(sync_node->GetTitle())) - return false; - if (bookmark->is_folder() != sync_node->GetIsFolder()) - return false; - if (bookmark->is_url()) { - if (bookmark->GetURL() != GURL(sync_node->GetURL())) - return false; - } - // Don't compare favicons here, because they are not really - // user-updated and we don't have versioning information -- a site changing - // its favicon shouldn't result in a bookmark mismatch. - return true; -} - -bool ModelAssociator::AssociateTaggedPermanentNode( - const BookmarkNode* permanent_node, - const string16 &tag) { - // Do nothing if |permanent_node| is already initialized and associated. - int64 sync_id = GetSyncIdFromBookmarkId(permanent_node->id()); - if (sync_id != sync_api::kInvalidId) - return true; - if (!GetSyncIdForTaggedNode(tag, &sync_id)) - return false; - - AssociateIds(permanent_node->id(), sync_id); - return true; -} - -bool ModelAssociator::GetSyncIdForTaggedNode(const string16& tag, - int64* sync_id) { - sync_api::ReadTransaction trans( - sync_service_->backend()->GetUserShareHandle()); - sync_api::ReadNode sync_node(&trans); - if (!sync_node.InitByTagLookup(tag.c_str())) - return false; - *sync_id = sync_node.GetId(); - return true; -} - -bool ModelAssociator::AssociateModels() { - // Try to load model associations from persisted associations first. If that - // succeeds, we don't need to run the complex model matching algorithm. - if (LoadAssociations()) - return true; - - ClearAll(); - - // We couldn't load model assocations from persisted assocations. So build - // them. - return BuildAssocations(); -} - -bool ModelAssociator::BuildAssocations() { - // Algorithm description: - // Match up the roots and recursively do the following: - // * For each sync node for the current sync parent node, find the best - // matching bookmark node under the corresponding bookmark parent node. - // If no matching node is found, create a new bookmark node in the same - // position as the corresponding sync node. - // If a matching node is found, update the properties of it from the - // corresponding sync node. - // * When all children sync nodes are done, add the extra children bookmark - // nodes to the sync parent node. - // - // This algorithm will do a good job of merging when folder names are a good - // indicator of the two folders being the same. It will handle reordering and - // new node addition very well (without creating duplicates). - // This algorithm will not do well if the folder name has changes but the - // children under them are all the same. - - BookmarkModel* model = sync_service_->profile()->GetBookmarkModel(); - DCHECK(model->IsLoaded()); - - // To prime our association, we associate the top-level nodes, Bookmark Bar - // and Other Bookmarks. - if (!AssociateTaggedPermanentNode(model->other_node(), - WideToUTF16(kOtherBookmarksTag))) { - NOTREACHED() << "Server did not create top-level nodes. Possibly we " - << "are running against an out-of-date server?"; - return false; - } - if (!AssociateTaggedPermanentNode(model->GetBookmarkBarNode(), - WideToUTF16(kBookmarkBarTag))) { - NOTREACHED() << "Server did not create top-level nodes. Possibly we " - << "are running against an out-of-date server?"; - return false; - } - int64 bookmark_bar_sync_id = GetSyncIdFromBookmarkId( - model->GetBookmarkBarNode()->id()); - DCHECK(bookmark_bar_sync_id != sync_api::kInvalidId); - int64 other_bookmarks_sync_id = GetSyncIdFromBookmarkId( - model->other_node()->id()); - DCHECK(other_bookmarks_sync_id!= sync_api::kInvalidId); - - std::stack<int64> dfs_stack; - dfs_stack.push(other_bookmarks_sync_id); - dfs_stack.push(bookmark_bar_sync_id); - - sync_api::WriteTransaction trans( - sync_service_->backend()->GetUserShareHandle()); - - while (!dfs_stack.empty()) { - int64 sync_parent_id = dfs_stack.top(); - dfs_stack.pop(); - - sync_api::ReadNode sync_parent(&trans); - if (!sync_parent.InitByIdLookup(sync_parent_id)) { - NOTREACHED(); - return false; - } - // Only folder nodes are pushed on to the stack. - DCHECK(sync_parent.GetIsFolder()); - - const BookmarkNode* parent_node = GetBookmarkNodeFromSyncId(sync_parent_id); - DCHECK(parent_node->is_folder()); - - BookmarkNodeFinder node_finder(parent_node); - - int index = 0; - int64 sync_child_id = sync_parent.GetFirstChildId(); - while (sync_child_id != sync_api::kInvalidId) { - sync_api::WriteNode sync_child_node(&trans); - if (!sync_child_node.InitByIdLookup(sync_child_id)) { - NOTREACHED(); - return false; - } - - const BookmarkNode* child_node = NULL; - child_node = node_finder.FindBookmarkNode(sync_child_node); - if (child_node) { - model->Move(child_node, parent_node, index); - // Set the favicon for bookmark node from sync node or vice versa. - if (!sync_service_->SetBookmarkFavicon(&sync_child_node, child_node)) - sync_service_->SetSyncNodeFavicon(child_node, &sync_child_node); - } else { - // Create a new bookmark node for the sync node. - child_node = sync_service_->CreateBookmarkNode(&sync_child_node, - parent_node, - index); - } - AssociateIds(child_node->id(), sync_child_id); - if (sync_child_node.GetIsFolder()) - dfs_stack.push(sync_child_id); - - sync_child_id = sync_child_node.GetSuccessorId(); - ++index; - } - - // At this point all the children nodes of the parent sync node have - // corresponding children in the parent bookmark node and they are all in - // the right positions: from 0 to index - 1. - // So the children starting from index in the parent bookmark node are the - // ones that are not present in the parent sync node. So create them. - for (int i = index; i < parent_node->GetChildCount(); ++i) { - sync_child_id = sync_service_->CreateSyncNode(parent_node, i, &trans); - if (parent_node->GetChild(i)->is_folder()) - dfs_stack.push(sync_child_id); - } - } - return true; -} - -void ModelAssociator::PostPersistAssociationsTask() { - // No need to post a task if a task is already pending. - if (task_pending_) - return; - task_pending_ = true; - MessageLoop::current()->PostTask( - FROM_HERE, - NewRunnableMethod(this, &ModelAssociator::PersistAssociations)); -} - -void ModelAssociator::PersistAssociations() { - DCHECK(task_pending_); - task_pending_ = false; - - // If there are no dirty assocations we have nothing to do. We handle this - // explicity instead of letting the for loop do it to avoid creating a write - // transaction in this case. - if (dirty_assocations_sync_ids_.empty()) { - DCHECK(id_map_.empty()); - DCHECK(id_map_inverse_.empty()); - return; - } - - sync_api::WriteTransaction trans( - sync_service_->backend()->GetUserShareHandle()); - DirtyAssocationsSyncIds::iterator iter; - for (iter = dirty_assocations_sync_ids_.begin(); - iter != dirty_assocations_sync_ids_.end(); - ++iter) { - int64 sync_id = *iter; - sync_api::WriteNode sync_node(&trans); - if (!sync_node.InitByIdLookup(sync_id)) { - sync_service_->SetUnrecoverableError(); - return; - } - int64 node_id; - if (GetBookmarkIdFromSyncId(sync_id, &node_id)) - sync_node.SetExternalId(node_id); - else - NOTREACHED(); - } - dirty_assocations_sync_ids_.clear(); -} - -bool ModelAssociator::LoadAssociations() { - BookmarkModel* model = sync_service_->profile()->GetBookmarkModel(); - DCHECK(model->IsLoaded()); - // If the bookmarks changed externally, our previous assocations may not be - // valid; so return false. - if (model->file_changed()) - return false; - - // Our persisted assocations should be valid. Try to populate id assocation - // maps using persisted assocations. - - int64 other_bookmarks_id; - if (!GetSyncIdForTaggedNode(WideToUTF16(kOtherBookmarksTag), - &other_bookmarks_id)) { - NOTREACHED(); // We should always be able to find the permanent nodes. - return false; - } - int64 bookmark_bar_id; - if (!GetSyncIdForTaggedNode(WideToUTF16(kBookmarkBarTag), &bookmark_bar_id)) { - NOTREACHED(); // We should always be able to find the permanent nodes. - return false; - } - - std::stack<int64> dfs_stack; - dfs_stack.push(other_bookmarks_id); - dfs_stack.push(bookmark_bar_id); - - sync_api::ReadTransaction trans( - sync_service_->backend()->GetUserShareHandle()); - - while (!dfs_stack.empty()) { - int64 parent_id = dfs_stack.top(); - dfs_stack.pop(); - sync_api::ReadNode sync_parent(&trans); - if (!sync_parent.InitByIdLookup(parent_id)) { - NOTREACHED(); - return false; - } - - int64 external_id = sync_parent.GetExternalId(); - if (external_id == 0) - return false; - - const BookmarkNode* node = model->GetNodeByID(external_id); - if (!node) - return false; - - // Don't try to call NodesMatch on permanent nodes like bookmark bar and - // other bookmarks. They are not expected to match. - if (node != model->GetBookmarkBarNode() && - node != model->other_node() && - !NodesMatch(node, &sync_parent)) - return false; - - AssociateIds(external_id, sync_parent.GetId()); - - // Add all children of the current node to the stack. - int64 child_id = sync_parent.GetFirstChildId(); - while (child_id != sync_api::kInvalidId) { - dfs_stack.push(child_id); - sync_api::ReadNode child_node(&trans); - if (!child_node.InitByIdLookup(child_id)) { - NOTREACHED(); - return false; - } - child_id = child_node.GetSuccessorId(); - } - } - DCHECK(dfs_stack.empty()); - return true; -} - -} // namespace browser_sync - -#endif // CHROME_PERSONALIZATION diff --git a/chrome/browser/sync/glue/model_associator.h b/chrome/browser/sync/glue/model_associator.h deleted file mode 100644 index a81f337..0000000 --- a/chrome/browser/sync/glue/model_associator.h +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifdef CHROME_PERSONALIZATION - -#ifndef CHROME_BROWSER_SYNC_GLUE_MODEL_ASSOCATOR_H_ -#define CHROME_BROWSER_SYNC_GLUE_MODEL_ASSOCATOR_H_ - -#include <map> -#include <set> -#include <string> - -#include "base/basictypes.h" -#include "base/ref_counted.h" -#include "base/scoped_ptr.h" -#include "base/string16.h" - -class BookmarkNode; - -namespace sync_api { -class BaseNode; -class BaseTransaction; -class ReadNode; -}; - -class ProfileSyncService; - -namespace browser_sync { - -// Contains all model assocation related logic: -// * Algorithm to associate bookmark model and sync model. -// * Methods to get a bookmark node for a given sync node and vice versa. -// * Persisting model assocations and loading them back. -class ModelAssociator - : public base::RefCountedThreadSafe<ModelAssociator> { - public: - explicit ModelAssociator(ProfileSyncService* sync_service); - virtual ~ModelAssociator() { } - - // Clears all assocations . - void ClearAll(); - - // Returns sync id for the given bookmark node id. - // Returns sync_api::kInvalidId if the sync node is not found for the given - // bookmark node id. - int64 GetSyncIdFromBookmarkId(int64 node_id) const; - - // Stores bookmark node id for the given sync id in bookmark_id. Returns true - // if the bookmark id was successfully found; false otherwise. - bool GetBookmarkIdFromSyncId(int64 sync_id, int64* bookmark_id) const; - - // Initializes the given sync node from the given bookmark node id. - // Returns false if no sync node was found for the given bookmark node id or - // if the initialization of sync node fails. - bool InitSyncNodeFromBookmarkId(int64 node_id, sync_api::BaseNode* sync_node); - - // Returns the bookmark node for the given sync id. - // Returns NULL if no bookmark node is found for the given sync id. - const BookmarkNode* GetBookmarkNodeFromSyncId(int64 sync_id); - - // Associates the given bookmark node id with the given sync id. - void AssociateIds(int64 node_id, int64 sync_id); - // Disassociate the ids that correspond to the given sync id. - void DisassociateIds(int64 sync_id); - - // Returns whether the bookmark model has user created nodes or not. That is, - // whether there are nodes in the bookmark model except the bookmark bar and - // other bookmarks. - bool BookmarkModelHasUserCreatedNodes() const; - - // Returns whether the sync model has nodes other than the permanent tagged - // nodes. - bool SyncModelHasUserCreatedNodes(); - - // AssociateModels iterates through both the sync and the browser - // bookmark model, looking for matched pairs of items. For any pairs it - // finds, it will call AssociateSyncID. For any unmatched items, - // MergeAndAssociateModels will try to repair the match, e.g. by adding a new - // node. After successful completion, the models should be identical and - // corresponding. Returns true on success. On failure of this step, we - // should abort the sync operation and report an error to the user. - bool AssociateModels(); - - protected: - // Stores the id of the node with the given tag in |sync_id|. - // Returns of that node was found successfully. - // Tests override this. - virtual bool GetSyncIdForTaggedNode(const string16& tag, int64* sync_id); - - // Returns sync service instance. - ProfileSyncService* sync_service() { return sync_service_; } - - private: - typedef std::map<int64, int64> BookmarkIdToSyncIdMap; - typedef std::map<int64, int64> SyncIdToBookmarkIdMap; - typedef std::set<int64> DirtyAssocationsSyncIds; - - // Posts a task to persist dirty assocations. - void PostPersistAssociationsTask(); - // Persists all dirty assocations. - void PersistAssociations(); - - // Loads the persisted assocations into in-memory maps. - // If the persisted associations are out-of-date due to some reason, returns - // false; otehrwise returns true. - bool LoadAssociations(); - - // Matches up the bookmark model and the sync model to build model - // assocations. - bool BuildAssocations(); - - // Associate a top-level node of the bookmark model with a permanent node in - // the sync domain. Such permanent nodes are identified by a tag that is - // well known to the server and the client, and is unique within a particular - // user's share. For example, "other_bookmarks" is the tag for the Other - // Bookmarks folder. The sync nodes are server-created. - bool AssociateTaggedPermanentNode(const BookmarkNode* permanent_node, - const string16& tag); - - // Compare the properties of a pair of nodes from either domain. - bool NodesMatch(const BookmarkNode* bookmark, - const sync_api::BaseNode* sync_node) const; - - ProfileSyncService* sync_service_; - BookmarkIdToSyncIdMap id_map_; - SyncIdToBookmarkIdMap id_map_inverse_; - // Stores sync ids for dirty associations. - DirtyAssocationsSyncIds dirty_assocations_sync_ids_; - - // Indicates whether there is already a pending task to persist dirty model - // associations. - bool task_pending_; - - DISALLOW_COPY_AND_ASSIGN(ModelAssociator); -}; - -} // namespace browser_sync - -#endif // CHROME_BROWSER_SYNC_GLUE_MODEL_ASSOCATOR_H_ -#endif // CHROME_PERSONALIZATION
\ No newline at end of file diff --git a/chrome/browser/sync/glue/sync_backend_host.cc b/chrome/browser/sync/glue/sync_backend_host.cc deleted file mode 100644 index 4614ee3..0000000 --- a/chrome/browser/sync/glue/sync_backend_host.cc +++ /dev/null @@ -1,308 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifdef CHROME_PERSONALIZATION - -#include "base/file_version_info.h" -#include "base/file_util.h" -#include "base/string_util.h" -#include "chrome/browser/sync/glue/sync_backend_host.h" -#include "chrome/browser/sync/glue/http_bridge.h" -#include "chrome/browser/sync/glue/bookmark_model_worker.h" -#include "webkit/glue/webkit_glue.h" - -static const char kSwitchSyncServiceURL[] = "sync-url"; -static const char kSwitchSyncServicePort[] = "sync-port"; -static const int kSaveChangesIntervalSeconds = 10; -static const char kGaiaServiceId[] = "chromiumsync"; -static const char kGaiaSourceForChrome[] = "ChromiumBrowser"; -static const FilePath::CharType kSyncDataFolderName[] = - FILE_PATH_LITERAL("Sync Data"); - -namespace browser_sync { - -SyncBackendHost::SyncBackendHost(SyncFrontend* frontend, - const FilePath& profile_path) - : core_thread_("Chrome_SyncCoreThread"), - frontend_loop_(MessageLoop::current()), - bookmark_model_worker_(NULL), - frontend_(frontend), - sync_data_folder_path_(profile_path.Append(kSyncDataFolderName)), - last_auth_error_(AUTH_ERROR_NONE) { - core_ = new Core(this); -} - -SyncBackendHost::~SyncBackendHost() { - DCHECK(!core_ && !frontend_) << "Must call Shutdown before destructor."; -} - -void SyncBackendHost::Initialize(const GURL& sync_service_url) { - if (!core_thread_.Start()) - return; - - bookmark_model_worker_ = new BookmarkModelWorker(frontend_loop_); - core_thread_.message_loop()->PostTask(FROM_HERE, - NewRunnableMethod(core_.get(), &SyncBackendHost::Core::DoInitialize, - sync_service_url, bookmark_model_worker_, true)); -} - -void SyncBackendHost::Authenticate(const std::string& username, - const std::string& password) { - core_thread_.message_loop()->PostTask(FROM_HERE, - NewRunnableMethod(core_.get(), &SyncBackendHost::Core::DoAuthenticate, - username, password)); -} - -void SyncBackendHost::Shutdown(bool sync_disabled) { - // Thread shutdown should occur in the following order: - // - SyncerThread - // - CoreThread - // - UI Thread (stops some time after we return from this call). - core_thread_.message_loop()->PostTask(FROM_HERE, - NewRunnableMethod(core_.get(), - &SyncBackendHost::Core::DoShutdown, - sync_disabled)); - - // Before joining the core_thread_, we wait for the BookmarkModelWorker to - // give us the green light that it is not depending on the frontend_loop_ to - // process any more tasks. Stop() blocks until this termination condition - // is true. - bookmark_model_worker_->Stop(); - - // Stop will return once the thread exits, which will be after DoShutdown - // runs. DoShutdown needs to run from core_thread_ because the sync backend - // requires any thread that opened sqlite handles to relinquish them - // personally. We need to join threads, because otherwise the main Chrome - // thread (ui loop) can exit before DoShutdown finishes, at which point - // virtually anything the sync backend does (or the post-back to - // frontend_loop_ by our Core) will epically fail because the CRT won't be - // initialized. For now this only ever happens at sync-enabled-Chrome exit, - // meaning bug 1482548 applies to prolonged "waiting" that may occur in - // DoShutdown. - core_thread_.Stop(); - - bookmark_model_worker_ = NULL; - frontend_ = NULL; - core_ = NULL; // Releases reference to core_. -} - -void SyncBackendHost::Core::NotifyFrontend(FrontendNotification notification) { - if (!host_ || !host_->frontend_) { - return; // This can happen in testing because the UI loop processes tasks - // after an instance of SyncBackendHost was destroyed. In real - // life this doesn't happen. - } - switch(notification) { - case INITIALIZED: - host_->frontend_->OnBackendInitialized(); - return; - case SYNC_CYCLE_COMPLETED: - host_->frontend_->OnSyncCycleCompleted(); - return; - } -} - -SyncBackendHost::UserShareHandle SyncBackendHost::GetUserShareHandle() const { - return core_->syncapi()->GetUserShare(); -} - -SyncBackendHost::Status SyncBackendHost::GetDetailedStatus() { - return core_->syncapi()->GetDetailedStatus(); -} - -SyncBackendHost::StatusSummary SyncBackendHost::GetStatusSummary() { - return core_->syncapi()->GetStatusSummary(); -} - -string16 SyncBackendHost::GetAuthenticatedUsername() const { - return UTF8ToUTF16(core_->syncapi()->GetAuthenticatedUsername()); -} - -AuthErrorState SyncBackendHost::GetAuthErrorState() const { - return last_auth_error_; -} - -SyncBackendHost::Core::Core(SyncBackendHost* backend) - : host_(backend), - syncapi_(new sync_api::SyncManager()) { -} - -// Helper to construct a user agent string (ASCII) suitable for use by -// the syncapi for any HTTP communication. This string is used by the sync -// backend for classifying client types when calculating statistics. -std::string MakeUserAgentForSyncapi() { - std::string user_agent; - user_agent = "Chrome "; -#if defined (OS_WIN) - user_agent += "WIN "; -#elif defined (OS_LINUX) - user_agent += "LINUX "; -#elif defined (OS_MACOSX) - user_agent += "MAC "; -#endif - scoped_ptr<FileVersionInfo> version_info( - FileVersionInfo::CreateFileVersionInfoForCurrentModule()); - if (version_info == NULL) { - DLOG(ERROR) << "Unable to create FileVersionInfo object"; - return user_agent; - } - - user_agent += WideToASCII(version_info->product_version()); - user_agent += " (" + WideToASCII(version_info->last_change()) + ")"; - if (!version_info->is_official_build()) - user_agent += "-devel"; - return user_agent; -} - -void SyncBackendHost::Core::DoInitialize( - const GURL& service_url, - BookmarkModelWorker* bookmark_model_worker, - bool attempt_last_user_authentication) { - DCHECK(MessageLoop::current() == host_->core_thread_.message_loop()); - - // Make sure that the directory exists before initializing the backend. - // If it already exists, this will do no harm. - bool success = file_util::CreateDirectory(host_->sync_data_folder_path()); - DCHECK(success); - - syncapi_->SetObserver(this); - string16 path_str; -#if defined (OS_WIN) - path_str = host_->sync_data_folder_path().value(); -#elif (defined (OS_LINUX) || defined (OS_MACOSX)) - path_str = UTF8ToUTF16(sync_data_folder_path().value()); -#endif - success = syncapi_->Init(path_str.c_str(), - (service_url.host() + service_url.path()).c_str(), - service_url.EffectiveIntPort(), - kGaiaServiceId, - kGaiaSourceForChrome, - service_url.SchemeIsSecure(), - new HttpBridgeFactory(), - new HttpBridgeFactory(), - bookmark_model_worker, - attempt_last_user_authentication, - MakeUserAgentForSyncapi().c_str()); - DCHECK(success) << "Syncapi initialization failed!"; -} - -void SyncBackendHost::Core::DoAuthenticate(const std::string& username, - const std::string& password) { - DCHECK(MessageLoop::current() == host_->core_thread_.message_loop()); - syncapi_->Authenticate(username.c_str(), password.c_str()); -} - -void SyncBackendHost::Core::DoShutdown(bool sync_disabled) { - DCHECK(MessageLoop::current() == host_->core_thread_.message_loop()); - - save_changes_timer_.Stop(); - syncapi_->Shutdown(); // Stops the SyncerThread. - syncapi_->RemoveObserver(); - host_->bookmark_model_worker_->OnSyncerShutdownComplete(); - - if (sync_disabled && - file_util::DirectoryExists(host_->sync_data_folder_path())) { - // Delete the sync data folder to cleanup backend data. - bool success = file_util::Delete(host_->sync_data_folder_path(), true); - DCHECK(success); - } - - host_ = NULL; -} - -static AuthErrorState AuthProblemToAuthError( - const sync_api::SyncManager::AuthProblem& auth_problem) { - switch(auth_problem) { - case sync_api::SyncManager::AUTH_PROBLEM_NONE: - return AUTH_ERROR_NONE; - case sync_api::SyncManager::AUTH_PROBLEM_INVALID_GAIA_CREDENTIALS: - return AUTH_ERROR_INVALID_GAIA_CREDENTIALS; - case sync_api::SyncManager::AUTH_PROBLEM_CONNECTION_FAILED: - return AUTH_ERROR_CONNECTION_FAILED; - case sync_api::SyncManager::AUTH_PROBLEM_USER_NOT_SIGNED_UP: - return AUTH_ERROR_USER_NOT_SIGNED_UP; - } - - NOTREACHED() << "Unknown AuthProblem."; - return AUTH_ERROR_NONE; -} - -void SyncBackendHost::Core::OnChangesApplied( - const sync_api::BaseTransaction* trans, - const sync_api::SyncManager::ChangeRecord* changes, - int change_count) { - if (!host_ || !host_->frontend_) { - DCHECK(false) << "OnChangesApplied called after Shutdown?"; - return; - } - - // ChangesApplied is the one exception that should come over from the sync - // backend already on the service_loop_ thanks to our BookmarkModelWorker. - // SyncFrontend changes exclusively on the UI loop, because it updates - // the bookmark model. As such, we don't need to worry about changes that - // have been made to the bookmark model but not yet applied to the sync - // model -- such changes only happen on the UI loop, and there's no - // contention. - if (host_->frontend_loop_ != MessageLoop::current()) { - // TODO(ncarter): Bug 1480644. Make this a DCHECK once syncapi filters - // out all irrelevant changes. - DLOG(WARNING) << "Could not update bookmark model from non-UI thread"; - return; - } - host_->frontend_->ApplyModelChanges(trans, changes, change_count); -} - -void SyncBackendHost::Core::OnSyncCycleCompleted() { - host_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, - &Core::NotifyFrontend, SYNC_CYCLE_COMPLETED)); -} - -void SyncBackendHost::Core::OnInitializationComplete() { - if (!host_ || !host_->frontend_) - return; // We may have been told to Shutdown before initialization - // completed. - - // We could be on some random sync backend thread, so MessageLoop::current() - // can definitely be null in here. - host_->frontend_loop_->PostTask(FROM_HERE, - NewRunnableMethod(this, &Core::NotifyFrontend, INITIALIZED)); - - // Initialization is complete, so we can schedule recurring SaveChanges. - host_->core_thread_.message_loop()->PostTask(FROM_HERE, - NewRunnableMethod(this, &Core::StartSavingChanges)); -} - -void SyncBackendHost::Core::OnAuthProblem( - sync_api::SyncManager::AuthProblem auth_problem) { - // We could be on SyncEngine_AuthWatcherThread. Post to our core loop so - // we can modify state. - host_->frontend_loop_->PostTask(FROM_HERE, - NewRunnableMethod(this, &Core::HandleAuthErrorEventOnFrontendLoop, - AuthProblemToAuthError(auth_problem))); -} - -void SyncBackendHost::Core::HandleAuthErrorEventOnFrontendLoop( - AuthErrorState new_auth_error) { - if (!host_ || !host_->frontend_) - return; - - DCHECK_EQ(MessageLoop::current(), host_->frontend_loop_); - - host_->last_auth_error_ = new_auth_error; - host_->frontend_->OnAuthError(); -} - -void SyncBackendHost::Core::StartSavingChanges() { - save_changes_timer_.Start( - base::TimeDelta::FromSeconds(kSaveChangesIntervalSeconds), - this, &Core::SaveChanges); -} - -void SyncBackendHost::Core::SaveChanges() { - syncapi_->SaveChanges(); -} - -} // namespace browser_sync - -#endif diff --git a/chrome/browser/sync/glue/sync_backend_host.h b/chrome/browser/sync/glue/sync_backend_host.h deleted file mode 100644 index eb89e43..0000000 --- a/chrome/browser/sync/glue/sync_backend_host.h +++ /dev/null @@ -1,274 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifdef CHROME_PERSONALIZATION - -#ifndef CHROME_BROWSER_SYNC_GLUE_SYNC_BACKEND_HOST_H_ -#define CHROME_BROWSER_SYNC_GLUE_SYNC_BACKEND_HOST_H_ - -#include <string> - -#include "base/file_path.h" -#include "base/lock.h" -#include "base/message_loop.h" -#include "base/ref_counted.h" -#include "base/thread.h" -#include "base/timer.h" -#include "chrome/browser/sync/auth_error_state.h" -#include "chrome/browser/sync/engine/syncapi.h" -#include "chrome/browser/sync/glue/bookmark_model_worker.h" -#include "googleurl/src/gurl.h" - -namespace browser_sync { - -class SyncFrontend; - -// A UI-thread safe API into the sync backend that "hosts" the top-level -// syncapi element, the SyncManager, on its own thread. This class handles -// dispatch of potentially blocking calls to appropriate threads and ensures -// that the SyncFrontend is only accessed on the UI loop. -class SyncBackendHost { - public: - typedef sync_api::UserShare* UserShareHandle; - typedef sync_api::SyncManager::Status::Summary StatusSummary; - typedef sync_api::SyncManager::Status Status; - - // Create a SyncBackendHost with a reference to the |frontend| that it serves - // and communicates to via the SyncFrontend interface (on the same thread - // it used to call the constructor). - SyncBackendHost(SyncFrontend* frontend, const FilePath& proifle_path); - ~SyncBackendHost(); - - // Called on |frontend_loop_| to kick off asynchronous initialization. - void Initialize(const GURL& service_url); - - // Called on |frontend_loop_| to kick off asynchronous authentication. - void Authenticate(const std::string& username, const std::string& password); - - // Called on |frontend_loop_| to kick off shutdown. - // |sync_disabled| indicates if syncing is being disabled or not. - // See the implementation and Core::DoShutdown for details. - void Shutdown(bool sync_disabled); - - // Called on |frontend_loop_| to obtain a handle to the UserShare needed - // for creating transactions. - UserShareHandle GetUserShareHandle() const; - - // Called from any thread to obtain current status information in detailed or - // summarized form. - Status GetDetailedStatus(); - StatusSummary GetStatusSummary(); - AuthErrorState GetAuthErrorState() const; - - const FilePath& sync_data_folder_path() const { - return sync_data_folder_path_; - } - - // Returns the authenticated username of the sync user, or empty if none - // exists. It will only exist if the authentication service provider (e.g - // GAIA) has confirmed the username is authentic. - string16 GetAuthenticatedUsername() const; - -#ifdef UNIT_TEST - // Called from unit test to bypass authentication and initialize the syncapi - // to a state suitable for testing but not production. - void InitializeForTestMode(const std::wstring& test_user) { - if (!core_thread_.Start()) - return; - bookmark_model_worker_ = new BookmarkModelWorker(frontend_loop_); - core_thread_.message_loop()->PostTask(FROM_HERE, - NewRunnableMethod(core_.get(), - &SyncBackendHost::Core::DoInitializeForTest, - bookmark_model_worker_, - test_user)); - } -#endif - - private: - // The real guts of SyncBackendHost, to keep the public client API clean. - class Core : public base::RefCountedThreadSafe<SyncBackendHost::Core>, - public sync_api::SyncManager::Observer { - public: - explicit Core(SyncBackendHost* backend); - - // Note: This destructor should *always* be called from the thread that - // created it, and *always* after core_thread_ has exited. The syncapi - // watches thread exit events and keeps pointers to objects this dtor will - // destroy, so this ordering is important. - ~Core() { - } - - // SyncManager::Observer implementation. The Core just acts like an air - // traffic controller here, forwarding incoming messages to appropriate - // landing threads. - virtual void OnChangesApplied( - const sync_api::BaseTransaction* trans, - const sync_api::SyncManager::ChangeRecord* changes, - int change_count); - virtual void OnSyncCycleCompleted(); - virtual void OnInitializationComplete(); - virtual void OnAuthProblem( - sync_api::SyncManager::AuthProblem auth_problem); - - // Note: - // - // The Do* methods are the various entry points from our SyncBackendHost. - // It calls us on a dedicated thread to actually perform synchronous - // (and potentially blocking) syncapi operations. - // - // Called on the SyncBackendHost core_thread_ to perform initialization - // of the syncapi on behalf of SyncBackendHost::Initialize. - void DoInitialize(const GURL& service_url, - BookmarkModelWorker* bookmark_model_worker_, - bool attempt_last_user_authentication); - - // Called on our SyncBackendHost's core_thread_ to perform authentication - // on behalf of SyncBackendHost::Authenticate. - void DoAuthenticate(const std::string& username, - const std::string& password); - - // The shutdown order is a bit complicated: - // 1) From |core_thread_|, invoke the syncapi Shutdown call to do a final - // SaveChanges, close sqlite handles, and halt the syncer thread (which - // could potentially block for 1 minute). - // 2) Then, from |frontend_loop_|, halt the core_thread_. This causes - // syncapi thread-exit handlers to run and make use of cached pointers to - // various components owned implicitly by us. - // 3) Destroy this Core. That will delete syncapi components in a safe order - // because the thread that was using them has exited (in step 2). - void DoShutdown(bool stopping_sync); - - sync_api::SyncManager* syncapi() { return syncapi_.get(); } - -#ifdef UNIT_TEST - // Special form of initialization that does not try and authenticate the - // last known user (since it will fail in test mode) and does some extra - // setup to nudge the syncapi into a useable state. - void DoInitializeForTest(BookmarkModelWorker* bookmark_model_worker, - const std::wstring& test_user) { - DoInitialize(GURL(), bookmark_model_worker, false); - syncapi_->SetupForTestMode(WideToUTF16(test_user).c_str()); - } -#endif - - private: - // FrontendNotification defines parameters for NotifyFrontend. Each enum - // value corresponds to the one SyncFrontend interface method that - // NotifyFrontend should invoke. - enum FrontendNotification { - INITIALIZED, // OnBackendInitialized. - SYNC_CYCLE_COMPLETED, // A round-trip sync-cycle took place and - // the syncer has resolved any conflicts - // that may have arisen. - }; - - // NotifyFrontend is how the Core communicates with the frontend across - // threads. Having this extra method (rather than having the Core PostTask - // to the frontend explicitly) means SyncFrontend implementations don't - // need to be RefCountedThreadSafe because NotifyFrontend is invoked on the - // |frontend_loop_|. - void NotifyFrontend(FrontendNotification notification); - - // Invoked when initialization of syncapi is complete and we can start - // our timer. - // This must be called from the thread on which SaveChanges is intended to - // be run on; the host's |core_thread_|. - void StartSavingChanges(); - - // Invoked periodically to tell the syncapi to persist its state - // by writing to disk. - // This is called from the thread we were created on (which is the - // SyncBackendHost |core_thread_|), using a repeating timer that is kicked - // off as soon as the SyncManager tells us it completed - // initialization. - void SaveChanges(); - - // Dispatched to from HandleAuthErrorEventOnCoreLoop to handle updating - // frontend UI components. - void HandleAuthErrorEventOnFrontendLoop(AuthErrorState new_auth_error); - - // Our parent SyncBackendHost - SyncBackendHost* host_; - - // The timer used to periodically call SaveChanges. - base::RepeatingTimer<Core> save_changes_timer_; - - // The top-level syncapi entry point. - scoped_ptr<sync_api::SyncManager> syncapi_; - - DISALLOW_COPY_AND_ASSIGN(Core); - }; - - // A thread we dedicate for use by our Core to perform initialization, - // authentication, handle messages from the syncapi, and periodically tell - // the syncapi to persist itself. - base::Thread core_thread_; - - // Our core, which communicates directly to the syncapi. - scoped_refptr<Core> core_; - - // A reference to the MessageLoop used to construct |this|, so we know how - // to safely talk back to the SyncFrontend. - MessageLoop* const frontend_loop_; - - // We hold on to the BookmarkModelWorker created for the syncapi to ensure - // shutdown occurs in the sequence we expect by calling Stop() at the - // appropriate time. It is guaranteed to be valid because the worker is - // only destroyed when the SyncManager is destroyed, which happens when - // our Core is destroyed, which happens in Shutdown(). - BookmarkModelWorker* bookmark_model_worker_; - - // The frontend which we serve (and are owned by). - SyncFrontend* frontend_; - - // Path of the folder that stores the sync data files. - FilePath sync_data_folder_path_; - - // UI-thread cache of the last AuthErrorState received from syncapi. - AuthErrorState last_auth_error_; - - DISALLOW_COPY_AND_ASSIGN(SyncBackendHost); -}; - -// SyncFrontend is the interface used by SyncBackendHost to communicate with -// the entity that created it and, presumably, is interested in sync-related -// activity. -// NOTE: All methods will be invoked by a SyncBackendHost on the same thread -// used to create that SyncBackendHost. -class SyncFrontend { - public: - typedef sync_api::BaseTransaction BaseTransaction; - typedef sync_api::SyncManager::ChangeRecord ChangeRecord; - SyncFrontend() { - } - - // The backend has completed initialization and it is now ready to accept and - // process changes. - virtual void OnBackendInitialized() = 0; - - // The backend queried the server recently and received some updates. - virtual void OnSyncCycleCompleted() = 0; - - // The backend encountered an authentication problem and requests new - // credentials to be provided. See SyncBackendHost::Authenticate for details. - virtual void OnAuthError() = 0; - - // Changes have been applied to the backend model and are ready to be - // applied to the frontend model. See syncapi.h for detailed instructions on - // how to interpret and process |changes|. - virtual void ApplyModelChanges(const BaseTransaction* trans, - const ChangeRecord* changes, - int change_count) = 0; - protected: - // Don't delete through SyncFrontend interface. - virtual ~SyncFrontend() { - } - private: - DISALLOW_COPY_AND_ASSIGN(SyncFrontend); -}; - -} // namespace browser_sync - -#endif // CHROME_BROWSER_SYNC_GLUE_SYNC_BACKEND_HOST_H_ -#endif // CHROME_PERSONALIZATION diff --git a/chrome/browser/sync/personalization.cc b/chrome/browser/sync/personalization.cc deleted file mode 100644 index 8f007cf..0000000 --- a/chrome/browser/sync/personalization.cc +++ /dev/null @@ -1,339 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifdef CHROME_PERSONALIZATION - -#include "chrome/browser/sync/personalization.h" - -#include "app/resource_bundle.h" -#include "base/command_line.h" -#include "base/file_path.h" -#include "base/file_util.h" -#include "base/path_service.h" -#include "base/string_util.h" -#include "chrome/app/chrome_dll_resource.h" -#include "chrome/browser/browser.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/browser_url_handler.h" -#include "chrome/browser/command_updater.h" -#include "chrome/browser/options_window.h" -#include "chrome/browser/profile.h" -#include "chrome/browser/profile_manager.h" -#include "chrome/common/chrome_paths.h" -#include "chrome/common/chrome_switches.h" -#include "chrome/common/jstemplate_builder.h" -#include "chrome/common/notification_service.h" -#include "chrome/common/pref_service.h" -#include "chrome/browser/dom_ui/new_tab_page_sync_handler.h" -#include "chrome/browser/sync/personalization_strings.h" -#include "chrome/browser/sync/auth_error_state.h" -#include "chrome/browser/sync/profile_sync_service.h" -#include "googleurl/src/gurl.h" -#include "grit/app_resources.h" -#include "grit/browser_resources.h" -#include "net/url_request/url_request.h" - -using sync_api::SyncManager; - -// TODO(ncarter): Move these switches into chrome_switches. They are here -// now because we want to keep them secret during early development. -namespace switches { - const wchar_t kSyncServiceURL[] = L"sync-url"; - const wchar_t kSyncServicePort[] = L"sync-port"; - const wchar_t kSyncUserForTest[] = L"sync-user-for-test"; - const wchar_t kSyncPasswordForTest[] = L"sync-password-for-test"; -} - -// TODO(munjal): Move these preferences to common/pref_names.h. -// Names of various preferences. -namespace prefs { - const wchar_t kSyncPath[] = L"sync"; - const wchar_t kSyncLastSyncedTime[] = L"sync.last_synced_time"; - const wchar_t kSyncUserName[] = L"sync.username"; - const wchar_t kSyncHasSetupCompleted[] = L"sync.has_setup_completed"; -} - -// Top-level path for our network layer DataSource. -static const char kCloudyResourcesPath[] = "resources"; -// Path for cloudy:stats page. -static const char kCloudyStatsPath[] = "stats"; -// Path for the gaia sync login dialog. -static const char kCloudyGaiaLoginPath[] = "gaialogin"; -static const char kCloudyMergeAndSyncPath[] = "mergeandsync"; -static const char kCloudyThrobberPath[] = "throbber.png"; -static const char kCloudySetupFlowPath[] = "setup"; - -namespace Personalization { - -static std::wstring MakeAuthErrorText(AuthErrorState state) { - switch (state) { - case AUTH_ERROR_INVALID_GAIA_CREDENTIALS: - return L"INVALID_GAIA_CREDENTIALS"; - case AUTH_ERROR_USER_NOT_SIGNED_UP: - return L"USER_NOT_SIGNED_UP"; - case AUTH_ERROR_CONNECTION_FAILED: - return L"CONNECTION_FAILED"; - default: - return std::wstring(); - } -} - -bool IsP13NDisabled(Profile* profile) { - const CommandLine* command_line = CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch(switches::kDisableP13n)) - return true; - return !profile || profile->GetProfilePersonalization() == NULL; -} - -bool NeedsDOMUI(const GURL& url) { - return url.SchemeIs(kPersonalizationScheme) && - (url.path().find(kCloudyGaiaLoginPath) != std::string::npos) || - (url.path().find(kCloudySetupFlowPath) != std::string::npos) || - (url.path().find(kCloudyMergeAndSyncPath) != std::string::npos); -} - -class CloudyResourceSource : public ChromeURLDataManager::DataSource { - public: - CloudyResourceSource() - : DataSource(kCloudyResourcesPath, MessageLoop::current()) { - } - virtual ~CloudyResourceSource() { } - - virtual void StartDataRequest(const std::string& path, int request_id); - - virtual std::string GetMimeType(const std::string& path) const { - if (path == kCloudyThrobberPath) - return "image/png"; - else - return "text/html"; - } - private: - DISALLOW_COPY_AND_ASSIGN(CloudyResourceSource); -}; - -class CloudyStatsSource : public ChromeURLDataManager::DataSource { - public: - CloudyStatsSource() : DataSource(kCloudyStatsPath, MessageLoop::current()) { - } - virtual ~CloudyStatsSource() { } - virtual void StartDataRequest(const std::string& path, int request_id) { - std::string response(MakeCloudyStats()); - scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes); - html_bytes->data.resize(response.size()); - std::copy(response.begin(), response.end(), html_bytes->data.begin()); - SendResponse(request_id, html_bytes); - } - virtual std::string GetMimeType(const std::string& path) const { - return "text/html"; - } - private: - DISALLOW_COPY_AND_ASSIGN(CloudyStatsSource); -}; - -DOMMessageHandler* CreateNewTabPageHandler(DOMUI* dom_ui) { - return (new NewTabPageSyncHandler())->Attach(dom_ui); -} - -std::string GetNewTabSource() { - static const StringPiece new_tab_html( - ResourceBundle::GetSharedInstance().GetRawDataResource( - IDR_NEW_TAB_P13N_HTML)); - - std::string data_uri("data:text/html,"); - data_uri.append(std::string(new_tab_html.data(), new_tab_html.size())); - return GURL(data_uri).spec(); -} - -std::wstring GetMenuItemInfoText(Browser* browser) { - browser->command_updater()->UpdateCommandEnabled(IDC_P13N_INFO, true); - return kMenuLabelStartSync; -} - -void HandleMenuItemClick(Profile* p) { - // The menu item is enabled either when the sync is not enabled by the user - // or when it's enabled but the user name is empty. In the former case enable - // sync. In the latter case, show the login dialog. - ProfileSyncService* service = p->GetProfilePersonalization()->sync_service(); - DCHECK(service); - if (service->IsSyncEnabledByUser()) { - ShowOptionsWindow(OPTIONS_PAGE_USER_DATA, OPTIONS_GROUP_NONE, p); - } else { - service->EnableForUser(); - } -} - -} // namespace Personalization - -class ProfilePersonalizationImpl : public ProfilePersonalization, - public NotificationObserver { - public: - explicit ProfilePersonalizationImpl(Profile *p) - : profile_(p) { - // g_browser_process and/or io_thread may not exist during testing. - if (g_browser_process && g_browser_process->io_thread()) { - // Add our network layer data source for 'cloudy' URLs. - // TODO(timsteele): This one belongs in BrowserAboutHandler. - g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE, - NewRunnableMethod(&chrome_url_data_manager, - &ChromeURLDataManager::AddDataSource, - new Personalization::CloudyStatsSource())); - g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE, - NewRunnableMethod(&chrome_url_data_manager, - &ChromeURLDataManager::AddDataSource, - new Personalization::CloudyResourceSource())); - } - - registrar_.Add(this, NotificationType::BOOKMARK_MODEL_LOADED, - Source<Profile>(profile_)); - } - virtual ~ProfilePersonalizationImpl() {} - - // ProfilePersonalization implementation - virtual ProfileSyncService* sync_service() { - if (!sync_service_.get()) - InitSyncService(); - return sync_service_.get(); - } - - // NotificationObserver implementation. - virtual void Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details) { - DCHECK_EQ(type.value, NotificationType::BOOKMARK_MODEL_LOADED); - if (!sync_service_.get()) - InitSyncService(); - registrar_.RemoveAll(); - } - - void InitSyncService() { - sync_service_.reset(new ProfileSyncService(profile_)); - sync_service_->Initialize(); - } - - private: - Profile* profile_; - NotificationRegistrar registrar_; - scoped_ptr<ProfileSyncService> sync_service_; - DISALLOW_COPY_AND_ASSIGN(ProfilePersonalizationImpl); -}; - -namespace Personalization { - -void CloudyResourceSource::StartDataRequest(const std::string& path_raw, - int request_id) { - scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes); - if (path_raw == kCloudyThrobberPath) { - ResourceBundle::GetSharedInstance().LoadImageResourceBytes(IDR_THROBBER, - &html_bytes->data); - SendResponse(request_id, html_bytes); - return; - } - - std::string response; - if (path_raw == kCloudyGaiaLoginPath) { - static const StringPiece html(ResourceBundle::GetSharedInstance() - .GetRawDataResource(IDR_GAIA_LOGIN_HTML)); - response = html.as_string(); - } else if (path_raw == kCloudyMergeAndSyncPath) { - static const StringPiece html(ResourceBundle::GetSharedInstance() - .GetRawDataResource(IDR_MERGE_AND_SYNC_HTML)); - response = html.as_string(); - } else if (path_raw == kCloudySetupFlowPath) { - static const StringPiece html(ResourceBundle::GetSharedInstance() - .GetRawDataResource(IDR_SYNC_SETUP_FLOW_HTML)); - response = html.as_string(); - } - // Send the response. - html_bytes->data.resize(response.size()); - std::copy(response.begin(), response.end(), html_bytes->data.begin()); - SendResponse(request_id, html_bytes); -} - -ProfilePersonalization* CreateProfilePersonalization(Profile* p) { - return new ProfilePersonalizationImpl(p); -} - -void CleanupProfilePersonalization(ProfilePersonalization* p) { - if (p) delete p; -} - -static void AddBoolDetail(ListValue* details, const std::wstring& stat_name, - bool stat_value) { - DictionaryValue* val = new DictionaryValue; - val->SetString(L"stat_name", stat_name); - val->SetBoolean(L"stat_value", stat_value); - details->Append(val); -} - -static void AddIntDetail(ListValue* details, const std::wstring& stat_name, - int64 stat_value) { - DictionaryValue* val = new DictionaryValue; - val->SetString(L"stat_name", stat_name); - val->SetString(L"stat_value", FormatNumber(stat_value)); - details->Append(val); -} - -std::string MakeCloudyStats() { - FilePath user_data_dir; - if (!PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) - return std::string(); - ProfileManager* profile_manager = g_browser_process->profile_manager(); - Profile* profile = profile_manager->GetDefaultProfile(user_data_dir); - ProfilePersonalization* p13n_profile = profile->GetProfilePersonalization(); - ProfileSyncService* service = p13n_profile->sync_service(); - - DictionaryValue strings; - if (!service->IsSyncEnabledByUser()) { - strings.SetString(L"summary", L"SYNC DISABLED"); - } else { - SyncManager::Status full_status(service->QueryDetailedSyncStatus()); - - strings.SetString(L"summary", - ProfileSyncService::BuildSyncStatusSummaryText( - full_status.summary)); - - strings.Set(L"authenticated", - new FundamentalValue(full_status.authenticated)); - strings.SetString(L"auth_problem", - MakeAuthErrorText(service->GetAuthErrorState())); - - strings.SetString(L"time_since_sync", service->GetLastSyncedTimeString()); - - ListValue* details = new ListValue(); - strings.Set(L"details", details); - AddBoolDetail(details, L"Server Up", full_status.server_up); - AddBoolDetail(details, L"Server Reachable", full_status.server_reachable); - AddBoolDetail(details, L"Server Broken", full_status.server_broken); - AddBoolDetail(details, L"Notifications Enabled", - full_status.notifications_enabled); - AddIntDetail(details, L"Notifications Received", - full_status.notifications_received); - AddIntDetail(details, L"Notifications Sent", - full_status.notifications_sent); - AddIntDetail(details, L"Unsynced Count", full_status.unsynced_count); - AddIntDetail(details, L"Conflicting Count", full_status.conflicting_count); - AddBoolDetail(details, L"Syncing", full_status.syncing); - AddBoolDetail(details, L"Syncer Paused", full_status.syncer_paused); - AddBoolDetail(details, L"Initial Sync Ended", - full_status.initial_sync_ended); - AddBoolDetail(details, L"Syncer Stuck", full_status.syncer_stuck); - AddIntDetail(details, L"Updates Available", full_status.updates_available); - AddIntDetail(details, L"Updates Received", full_status.updates_received); - AddBoolDetail(details, L"Disk Full", full_status.disk_full); - AddBoolDetail(details, L"Invalid Store", full_status.invalid_store); - AddIntDetail(details, L"Max Consecutive Errors", - full_status.max_consecutive_errors); - } - - static const StringPiece sync_html( - ResourceBundle::GetSharedInstance().GetRawDataResource( - IDR_ABOUT_SYNC_HTML)); - - return jstemplate_builder::GetTemplateHtml( - sync_html, &strings , "t" /* template root node id */); -} - -} // namespace Personalization - -#endif diff --git a/chrome/browser/sync/personalization.h b/chrome/browser/sync/personalization.h deleted file mode 100644 index 2e22e0b..0000000 --- a/chrome/browser/sync/personalization.h +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifdef CHROME_PERSONALIZATION - -// TODO(timsteele): Remove this file by finding proper homes for everything in -// trunk. -#ifndef CHROME_BROWSER_SYNC_PERSONALIZATION_H_ -#define CHROME_BROWSER_SYNC_PERSONALIZATION_H_ - -#include <string> -#include "base/basictypes.h" -#include "chrome/browser/dom_ui/chrome_url_data_manager.h" - -class Browser; -class DOMUI; -class DOMMessageHandler; -class Profile; -class RenderView; -class RenderViewHost; -class WebFrame; -class WebView; - -class ProfileSyncService; -class ProfileSyncServiceObserver; - -namespace views { class View; } - -// TODO(ncarter): Move these switches into chrome_switches. They are here -// now because we want to keep them secret during early development. -namespace switches { - -extern const wchar_t kSyncServiceURL[]; -extern const wchar_t kSyncServicePort[]; -extern const wchar_t kSyncUserForTest[]; -extern const wchar_t kSyncPasswordForTest[]; - -} - -// Names of various preferences. -// TODO(munjal): Move these preferences to common/pref_names.h. -namespace prefs { -extern const wchar_t kSyncPath[]; -extern const wchar_t kSyncLastSyncedTime[]; -extern const wchar_t kSyncUserName[]; -extern const wchar_t kSyncHasSetupCompleted[]; -} - -// Contains a profile sync service, which is initialized at profile creation. -// A pointer to this class is passed as a handle. -class ProfilePersonalization { - public: - ProfilePersonalization() {} - virtual ~ProfilePersonalization() {} - - virtual ProfileSyncService* sync_service() = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(ProfilePersonalization); -}; - -// Contains methods to perform Personalization-related tasks on behalf of the -// caller. -namespace Personalization { - -// Checks if P13N is globally disabled or not, and that |profile| has a valid -// ProfilePersonalization member (it can be NULL for TestingProfiles). -bool IsP13NDisabled(Profile* profile); - -// Returns whether |url| should be loaded in a DOMUI. -bool NeedsDOMUI(const GURL& url); - -// Construct a new ProfilePersonalization and return it so the caller can take -// ownership. -ProfilePersonalization* CreateProfilePersonalization(Profile* p); - -// The caller of Create...() above should call this when the returned -// ProfilePersonalization object should be deleted. -void CleanupProfilePersonalization(ProfilePersonalization* p); - -// Handler for "cloudy:stats" -std::string MakeCloudyStats(); - -// Construct a new DOMMessageHandler for the new tab page |dom_ui|. -DOMMessageHandler* CreateNewTabPageHandler(DOMUI* dom_ui); - -// Get HTML for the Personalization iframe in the New Tab Page. -std::string GetNewTabSource(); - -// Returns the text for personalization info menu item and sets its enabled -// state. -std::wstring GetMenuItemInfoText(Browser* browser); - -// Performs appropriate action when the sync menu item is clicked. -void HandleMenuItemClick(Profile* p); -} // namespace Personalization - -// The internal scheme used to retrieve HTML resources for personalization -// related code (e.g cloudy:stats, GAIA login page). -// We need to ensure the GAIA login HTML is loaded into an HTMLDialogContents. -// Outside of p13n (for the time being) only "gears://" gives this (see -// HtmlDialogContents::IsHtmlDialogUrl) for the application shortcut dialog. -// TODO(timsteele): We should have a robust way to handle this to allow more -// reuse of our HTML dialog code, perhaps by using a dedicated "dialog-resource" -// scheme (chrome-resource is coupled to DOM_UI). Figure out if that is the best -// course of action / pitch this idea to chromium-dev. -static const char kPersonalizationScheme[] = "cloudy"; - -#endif // CHROME_BROWSER_SYNC_PERSONALIZATION_H_ -#endif // CHROME_PERSONALIZATION diff --git a/chrome/browser/sync/personalization_strings.h b/chrome/browser/sync/personalization_strings.h deleted file mode 100644 index ed3036d..0000000 --- a/chrome/browser/sync/personalization_strings.h +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Contains all string resources usec by the personalization module. - -// TODO(munjal): This file should go away once the personalization module -// becomes public. At that point, we have to put all the strings below in the -// generated resources file. - -#ifdef CHROME_PERSONALIZATION - -// TODO(timsteele): Rename this file; 'personalization' is deprecated. -#ifndef CHROME_BROWSER_SYNC_PERSONALIZATION_STRINGS_H_ -#define CHROME_BROWSER_SYNC_PERSONALIZATION_STRINGS_H_ - -// User Data tab in the Options menu. -static const wchar_t kSyncGroupName[] = L"Bookmark Sync:"; -static const wchar_t kSyncNotSetupInfo[] = - L"You are not set up to sync your bookmarks with your other computers."; -static const wchar_t kStartSyncButtonLabel[] = L"Synchronize my bookmarks..."; -static const wchar_t kSyncAccountLabel[] = L"Synced to "; -static const wchar_t kLastSyncedLabel[] = L"Last synced: "; -static const wchar_t kSyncCredentialsNeededLabel[] = - L"Account login details are not yet entered."; -static const wchar_t kSyncAuthenticatingLabel[] = L"Authenticating..."; -static const wchar_t kSyncInvalidCredentialsError[] = - L"Invalid user name or password."; -static const wchar_t kSyncOtherLoginErrorLabel[] = - L"Error signing in."; -static const wchar_t kSyncExpiredCredentialsError[] = - L"Login details are out of date."; -static const wchar_t kSyncServerNotReachableError[] = - L"Sync server is not reachable. Retrying..."; -static const wchar_t kSyncReLoginLinkLabel[] = L"Login again"; -static const wchar_t kStopSyncButtonLabel[] = L"Stop syncing this account"; - -// Sync status messages. -static const wchar_t kLastSyncedTimeNever[] = L"Never."; -static const wchar_t kLastSyncedTimeWithinLastMinute[] = L"Just now."; - -// Sync merge warning dialog strings. -static const wchar_t kMergeWarningMessageText[] = - L"WARNING: Your existing online bookmarks will be merged with the " - L"bookmarks on this machine. You can use the Bookmark Manager to organize " - L"your bookmarks after the merge."; -static const wchar_t kCancelSyncButtonLabel[] = L"Cancel"; -static const wchar_t kMergeAndSyncButtonLabel[] = L"Merge and Sync"; - -// Various strings for the new tab page personalization. -static const char kSyncSectionTitle[] = "Bookmark Sync"; -static const char kSyncErrorSectionTitle[] = "Bookmark Sync Error!"; -static const char kSyncPromotionMsg[] = - "You can sync your bookmarks across computers using your Google account."; -static const wchar_t kSyncServerUnavailableMsg[] = - L"Google Chrome could not sync your bookmarks because it could not connect " - L"to the sync server. Retrying..."; -static const char kStartNowLinkText[] = "Start now."; -static const char kSettingUpText[] = "Setup in progress..."; - -// Sync menu item strings. -static const wchar_t kMenuLabelStartSync[] = L"Sync my bookmarks..."; - -// Login dialog strings. -static const wchar_t kLoginDialogTitle[] = L"Sync my bookmarks"; - -#endif // CHROME_BROWSER_SYNC_PERSONALIZATION_STRINGS_H_ - -#endif // CHROME_PERSONALIZATION diff --git a/chrome/browser/sync/profile_sync_service.cc b/chrome/browser/sync/profile_sync_service.cc deleted file mode 100644 index e596e28..0000000 --- a/chrome/browser/sync/profile_sync_service.cc +++ /dev/null @@ -1,886 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifdef CHROME_PERSONALIZATION -#include "chrome/browser/sync/profile_sync_service.h" - -#include <stack> -#include <vector> - -#include "base/basictypes.h" -#include "base/command_line.h" -#include "base/file_path.h" -#include "base/file_util.h" -#include "base/gfx/png_encoder.h" -#include "base/stl_util-inl.h" -#include "base/string_util.h" -#include "base/time.h" -#include "chrome/browser/bookmarks/bookmark_utils.h" -#include "chrome/browser/history/history_notifications.h" -#include "chrome/browser/history/history_types.h" -#include "chrome/browser/profile.h" -#include "chrome/common/chrome_switches.h" -#include "chrome/common/pref_service.h" -#include "chrome/common/time_format.h" -#include "chrome/browser/sync/personalization.h" -#include "chrome/browser/sync/personalization_strings.h" -#include "chrome/browser/sync/engine/syncapi.h" -#include "views/window/window.h" - -using browser_sync::ModelAssociator; -using browser_sync::SyncBackendHost; - -ProfileSyncService::ProfileSyncService(Profile* profile) - : last_auth_error_(AUTH_ERROR_NONE), - profile_(profile), - backend_initialized_(false), - expecting_first_run_auth_needed_event_(false), - is_auth_in_progress_(false), - ready_to_process_changes_(false), - unrecoverable_error_detected_(false), - ALLOW_THIS_IN_INITIALIZER_LIST(wizard_(this)) { -} - -ProfileSyncService::~ProfileSyncService() { - Shutdown(false); -} - -void ProfileSyncService::Initialize() { - InitSettings(); - RegisterPreferences(); - if (!profile()->GetPrefs()->GetBoolean(prefs::kSyncHasSetupCompleted)) - DisableForUser(); // Clean up in case of previous crash / setup abort. - else - StartUp(); -} - -void ProfileSyncService::InitSettings() { - const CommandLine& command_line = *CommandLine::ForCurrentProcess(); - - // Override the sync server URL from the command-line, if sync server and sync - // port command-line arguments exist. - if (command_line.HasSwitch(switches::kSyncServiceURL)) { - std::wstring value(command_line.GetSwitchValue(switches::kSyncServiceURL)); - if (!value.empty()) { - GURL custom_sync_url(WideToUTF8(value)); - if (custom_sync_url.is_valid()) { - sync_service_url_ = custom_sync_url; - } else { - LOG(WARNING) << "The following sync URL specified at the command-line " - << "is invalid: " << value; - } - } - } else { - NOTREACHED() << "--sync-url is required when sync is enabled."; - } - - if (command_line.HasSwitch(switches::kSyncServicePort)) { - std::string port_str = WideToUTF8(command_line.GetSwitchValue( - switches::kSyncServicePort)); - if (!port_str.empty()) { - GURL::Replacements replacements; - replacements.SetPortStr(port_str); - sync_service_url_ = sync_service_url_.ReplaceComponents(replacements); - } - } -} - -void ProfileSyncService::RegisterPreferences() { - PrefService* pref_service = profile_->GetPrefs(); - if (pref_service->IsPrefRegistered(prefs::kSyncUserName)) - return; - pref_service->RegisterStringPref(prefs::kSyncUserName, std::wstring()); - pref_service->RegisterStringPref(prefs::kSyncLastSyncedTime, std::wstring()); - pref_service->RegisterBooleanPref(prefs::kSyncHasSetupCompleted, false); -} - -void ProfileSyncService::LoadPreferences() { - PrefService* pref_service = profile_->GetPrefs(); - std::wstring last_synced_time_string = - pref_service->GetString(prefs::kSyncLastSyncedTime); - if (!last_synced_time_string.empty()) { - int64 last_synced_time; - bool success = StringToInt64(WideToUTF16(last_synced_time_string), - &last_synced_time); - if (success) { - last_synced_time_ = base::Time::FromInternalValue(last_synced_time); - } else { - NOTREACHED(); - } - } -} - -void ProfileSyncService::ClearPreferences() { - PrefService* pref_service = profile_->GetPrefs(); - pref_service->ClearPref(prefs::kSyncUserName); - pref_service->ClearPref(prefs::kSyncLastSyncedTime); - pref_service->ClearPref(prefs::kSyncHasSetupCompleted); - - pref_service->ScheduleSavePersistentPrefs(); -} - -void ProfileSyncService::InitializeBackend() { - backend_->Initialize(sync_service_url_); -} - -void ProfileSyncService::StartUp() { - // Don't start up multiple times. - if (backend_.get()) - return; - - LoadPreferences(); - - backend_.reset(new SyncBackendHost(this, profile_->GetPath())); - - // We add ourselves as an observer, and we remain one forever. Note we don't - // keep any pointer to the model, we just receive notifications from it. - BookmarkModel* model = profile_->GetBookmarkModel(); - model->AddObserver(this); - - // Create new model assocation manager. - model_associator_ = new ModelAssociator(this); - - // TODO(timsteele): HttpBridgeFactory should take a const* to the profile's - // URLRequestContext, because it needs it to create HttpBridge objects, and - // it may need to do that before the default request context has been set - // up. For now, call GetRequestContext lazy-init to force creation. - profile_->GetRequestContext(); - InitializeBackend(); -} - -void ProfileSyncService::Shutdown(bool sync_disabled) { - if (backend_.get()) { - backend_->Shutdown(sync_disabled); - backend_.reset(); - } - - BookmarkModel* model = profile_->GetBookmarkModel(); - if (model) - model->RemoveObserver(this); - - // Clear all assocations and throw away the assocation manager instance. - if (model_associator_.get()) { - model_associator_->ClearAll(); - model_associator_ = NULL; - } - - // Clear various flags. - is_auth_in_progress_ = false; - backend_initialized_ = false; - expecting_first_run_auth_needed_event_ = false; - ready_to_process_changes_ = false; - last_attempted_user_email_.clear(); -} - -void ProfileSyncService::EnableForUser() { - if (wizard_.IsVisible()) { - // TODO(timsteele): Focus wizard. - return; - } - expecting_first_run_auth_needed_event_ = true; - - StartUp(); - FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged()); -} - -void ProfileSyncService::DisableForUser() { - if (wizard_.IsVisible()) { - // TODO(timsteele): Focus wizard. - return; - } - Shutdown(true); - ClearPreferences(); - - FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged()); -} - -void ProfileSyncService::Loaded(BookmarkModel* model) { - StartProcessingChangesIfReady(); -} - -void ProfileSyncService::UpdateSyncNodeProperties(const BookmarkNode* src, - sync_api::WriteNode* dst) { - // Set the properties of the item. - dst->SetIsFolder(src->is_folder()); - dst->SetTitle(WideToUTF16(src->GetTitle()).c_str()); - // URL is passed as a C string here because this interface avoids - // string16. SetURL copies the data into its own memory. - string16 url = UTF8ToUTF16(src->GetURL().spec()); - dst->SetURL(url.c_str()); - SetSyncNodeFavicon(src, dst); -} - -void ProfileSyncService::EncodeFavicon(const BookmarkNode* src, - std::vector<unsigned char>* dst) const { - const SkBitmap& favicon = profile_->GetBookmarkModel()->GetFavIcon(src); - - dst->clear(); - - // Check for zero-dimension images. This can happen if the favicon is - // still being loaded. - if (favicon.empty()) - return; - - // Re-encode the BookmarkNode's favicon as a PNG, and pass the data to the - // sync subsystem. - if (!PNGEncoder::EncodeBGRASkBitmap(favicon, false, dst)) - return; -} - -void ProfileSyncService::RemoveOneSyncNode(sync_api::WriteTransaction* trans, - const BookmarkNode* node) { - sync_api::WriteNode sync_node(trans); - if (!model_associator_->InitSyncNodeFromBookmarkId(node->id(), &sync_node)) { - SetUnrecoverableError(); - return; - } - // This node should have no children. - DCHECK(sync_node.GetFirstChildId() == sync_api::kInvalidId); - // Remove association and delete the sync node. - model_associator_->DisassociateIds(sync_node.GetId()); - sync_node.Remove(); -} - -void ProfileSyncService::RemoveSyncNodeHierarchy(const BookmarkNode* topmost) { - sync_api::WriteTransaction trans(backend_->GetUserShareHandle()); - - // Later logic assumes that |topmost| has been unlinked. - DCHECK(!topmost->GetParent()); - - // A BookmarkModel deletion event means that |node| and all its children were - // deleted. Sync backend expects children to be deleted individually, so we do - // a depth-first-search here. At each step, we consider the |index|-th child - // of |node|. |index_stack| stores index values for the parent levels. - std::stack<int> index_stack; - index_stack.push(0); // For the final pop. It's never used. - const BookmarkNode* node = topmost; - int index = 0; - while (node) { - // The top of |index_stack| should always be |node|'s index. - DCHECK(!node->GetParent() || (node->GetParent()->IndexOfChild(node) == - index_stack.top())); - if (index == node->GetChildCount()) { - // If we've processed all of |node|'s children, delete |node| and move - // on to its successor. - RemoveOneSyncNode(&trans, node); - node = node->GetParent(); - index = index_stack.top() + 1; // (top() + 0) was what we removed. - index_stack.pop(); - } else { - // If |node| has an unprocessed child, process it next after pushing the - // current state onto the stack. - DCHECK_LT(index, node->GetChildCount()); - index_stack.push(index); - node = node->GetChild(index); - index = 0; - } - } - DCHECK(index_stack.empty()); // Nothing should be left on the stack. -} - -bool ProfileSyncService::MergeAndSyncAcceptanceNeeded() const { - // If we've shown the dialog before, don't show it again. - if (profile_->GetPrefs()->GetBoolean(prefs::kSyncHasSetupCompleted)) - return false; - - return model_associator_->BookmarkModelHasUserCreatedNodes() && - model_associator_->SyncModelHasUserCreatedNodes(); -} - -bool ProfileSyncService::IsSyncEnabledByUser() const { - return profile_->GetPrefs()->GetBoolean(prefs::kSyncHasSetupCompleted); -} - -void ProfileSyncService::UpdateLastSyncedTime() { - last_synced_time_ = base::Time::Now(); - profile_->GetPrefs()->SetString(prefs::kSyncLastSyncedTime, - Int64ToWString(last_synced_time_.ToInternalValue())); -} - -void ProfileSyncService::BookmarkNodeAdded(BookmarkModel* model, - const BookmarkNode* parent, - int index) { - if (!ShouldPushChanges()) - return; - - DCHECK(backend_->GetUserShareHandle()); - - // Acquire a scoped write lock via a transaction. - sync_api::WriteTransaction trans(backend_->GetUserShareHandle()); - - CreateSyncNode(parent, index, &trans); -} - -int64 ProfileSyncService::CreateSyncNode(const BookmarkNode* parent, - int index, - sync_api::WriteTransaction* trans) { - const BookmarkNode* child = parent->GetChild(index); - DCHECK(child); - - // Create a WriteNode container to hold the new node. - sync_api::WriteNode sync_child(trans); - - // Actually create the node with the appropriate initial position. - if (!PlaceSyncNode(CREATE, parent, index, trans, &sync_child)) { - LOG(WARNING) << "Sync node creation failed; recovery unlikely"; - SetUnrecoverableError(); - return sync_api::kInvalidId; - } - - UpdateSyncNodeProperties(child, &sync_child); - - // Associate the ID from the sync domain with the bookmark node, so that we - // can refer back to this item later. - model_associator_->AssociateIds(child->id(), sync_child.GetId()); - - return sync_child.GetId(); -} - -void ProfileSyncService::BookmarkNodeRemoved(BookmarkModel* model, - const BookmarkNode* parent, - int index, - const BookmarkNode* node) { - if (!ShouldPushChanges()) - return; - - RemoveSyncNodeHierarchy(node); -} - -void ProfileSyncService::BookmarkNodeChanged(BookmarkModel* model, - const BookmarkNode* node) { - if (!ShouldPushChanges()) - return; - - // We shouldn't see changes to the top-level nodes. - DCHECK_NE(node, model->GetBookmarkBarNode()); - DCHECK_NE(node, model->other_node()); - - // Acquire a scoped write lock via a transaction. - sync_api::WriteTransaction trans(backend_->GetUserShareHandle()); - - // Lookup the sync node that's associated with |node|. - sync_api::WriteNode sync_node(&trans); - if (!model_associator_->InitSyncNodeFromBookmarkId(node->id(), &sync_node)) { - SetUnrecoverableError(); - return; - } - - UpdateSyncNodeProperties(node, &sync_node); - - DCHECK_EQ(sync_node.GetIsFolder(), node->is_folder()); - DCHECK_EQ(model_associator_->GetBookmarkNodeFromSyncId( - sync_node.GetParentId()), - node->GetParent()); - // This node's index should be one more than the predecessor's index. - DCHECK_EQ(node->GetParent()->IndexOfChild(node), - CalculateBookmarkModelInsertionIndex(node->GetParent(), - &sync_node)); -} - -void ProfileSyncService::BookmarkNodeMoved(BookmarkModel* model, - const BookmarkNode* old_parent, - int old_index, - const BookmarkNode* new_parent, - int new_index) { - if (!ShouldPushChanges()) - return; - - const BookmarkNode* child = new_parent->GetChild(new_index); - // We shouldn't see changes to the top-level nodes. - DCHECK_NE(child, model->GetBookmarkBarNode()); - DCHECK_NE(child, model->other_node()); - - // Acquire a scoped write lock via a transaction. - sync_api::WriteTransaction trans(backend_->GetUserShareHandle()); - - // Lookup the sync node that's associated with |child|. - sync_api::WriteNode sync_node(&trans); - if (!model_associator_->InitSyncNodeFromBookmarkId(child->id(), - &sync_node)) { - SetUnrecoverableError(); - return; - } - - if (!PlaceSyncNode(MOVE, new_parent, new_index, &trans, &sync_node)) { - SetUnrecoverableError(); - return; - } -} - -void ProfileSyncService::BookmarkNodeFavIconLoaded(BookmarkModel* model, - const BookmarkNode* node) { - BookmarkNodeChanged(model, node); -} - -void ProfileSyncService::BookmarkNodeChildrenReordered( - BookmarkModel* model, const BookmarkNode* node) { - if (!ShouldPushChanges()) - return; - - // Acquire a scoped write lock via a transaction. - sync_api::WriteTransaction trans(backend_->GetUserShareHandle()); - - // The given node's children got reordered. We need to reorder all the - // children of the corresponding sync node. - for (int i = 0; i < node->GetChildCount(); ++i) { - sync_api::WriteNode sync_child(&trans); - if (!model_associator_->InitSyncNodeFromBookmarkId(node->GetChild(i)->id(), - &sync_child)) { - SetUnrecoverableError(); - return; - } - DCHECK_EQ(sync_child.GetParentId(), - model_associator_->GetSyncIdFromBookmarkId(node->id())); - - if (!PlaceSyncNode(MOVE, node, i, &trans, &sync_child)) { - SetUnrecoverableError(); - return; - } - } -} - -bool ProfileSyncService::PlaceSyncNode(MoveOrCreate operation, - const BookmarkNode* parent, - int index, - sync_api::WriteTransaction* trans, - sync_api::WriteNode* dst) { - sync_api::ReadNode sync_parent(trans); - if (!model_associator_->InitSyncNodeFromBookmarkId(parent->id(), - &sync_parent)) { - LOG(WARNING) << "Parent lookup failed"; - SetUnrecoverableError(); - return false; - } - - bool success = false; - if (index == 0) { - // Insert into first position. - success = (operation == CREATE) ? dst->InitByCreation(sync_parent, NULL) : - dst->SetPosition(sync_parent, NULL); - if (success) { - DCHECK_EQ(dst->GetParentId(), sync_parent.GetId()); - DCHECK_EQ(dst->GetId(), sync_parent.GetFirstChildId()); - DCHECK_EQ(dst->GetPredecessorId(), sync_api::kInvalidId); - } - } else { - // Find the bookmark model predecessor, and insert after it. - const BookmarkNode* prev = parent->GetChild(index - 1); - sync_api::ReadNode sync_prev(trans); - if (!model_associator_->InitSyncNodeFromBookmarkId(prev->id(), - &sync_prev)) { - LOG(WARNING) << "Predecessor lookup failed"; - return false; - } - success = (operation == CREATE) ? - dst->InitByCreation(sync_parent, &sync_prev) : - dst->SetPosition(sync_parent, &sync_prev); - if (success) { - DCHECK_EQ(dst->GetParentId(), sync_parent.GetId()); - DCHECK_EQ(dst->GetPredecessorId(), sync_prev.GetId()); - DCHECK_EQ(dst->GetId(), sync_prev.GetSuccessorId()); - } - } - return success; -} - -// An invariant has been violated. Transition to an error state where we try -// to do as little work as possible, to avoid further corruption or crashes. -void ProfileSyncService::SetUnrecoverableError() { - unrecoverable_error_detected_ = true; - LOG(ERROR) << "Unrecoverable error detected -- ProfileSyncService unusable."; -} - -// Determine the bookmark model index to which a node must be moved so that -// predecessor of the node (in the bookmark model) matches the predecessor of -// |source| (in the sync model). -// As a precondition, this assumes that the predecessor of |source| has been -// updated and is already in the correct position in the bookmark model. -int ProfileSyncService::CalculateBookmarkModelInsertionIndex( - const BookmarkNode* parent, - const sync_api::BaseNode* child_info) const { - DCHECK(parent); - DCHECK(child_info); - int64 predecessor_id = child_info->GetPredecessorId(); - // A return ID of kInvalidId indicates no predecessor. - if (predecessor_id == sync_api::kInvalidId) - return 0; - - // Otherwise, insert after the predecessor bookmark node. - const BookmarkNode* predecessor = - model_associator_->GetBookmarkNodeFromSyncId(predecessor_id); - DCHECK(predecessor); - DCHECK_EQ(predecessor->GetParent(), parent); - return parent->IndexOfChild(predecessor) + 1; -} - -void ProfileSyncService::OnBackendInitialized() { - backend_initialized_ = true; - - PrefService* pref_service = profile_->GetPrefs(); - DCHECK(pref_service->IsPrefRegistered(prefs::kSyncUserName)); - pref_service->SetString(prefs::kSyncUserName, - UTF16ToWide(backend_->GetAuthenticatedUsername())); - StartProcessingChangesIfReady(); - - // The very first time the backend initializes is effectively the first time - // we can say we successfully "synced". last_synced_time_ will only be null - // in this case, because the pref wasn't restored on StartUp. - if (last_synced_time_.is_null()) - UpdateLastSyncedTime(); - FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged()); -} - -void ProfileSyncService::OnSyncCycleCompleted() { - UpdateLastSyncedTime(); - FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged()); -} - -void ProfileSyncService::OnAuthError() { - last_auth_error_ = backend_->GetAuthErrorState(); - // Protect against the in-your-face dialogs that pop out of nowhere. - // Require the user to click somewhere to run the setup wizard in the case - // of a steady-state auth failure. - if (wizard_.IsVisible() || expecting_first_run_auth_needed_event_) { - wizard_.Step(AUTH_ERROR_NONE == backend_->GetAuthErrorState() ? - SyncSetupWizard::GAIA_SUCCESS : SyncSetupWizard::GAIA_LOGIN); - } - - if (expecting_first_run_auth_needed_event_) { - last_auth_error_ = AUTH_ERROR_NONE; - expecting_first_run_auth_needed_event_ = false; - } - - is_auth_in_progress_ = false; - // Fan the notification out to interested UI-thread components. - FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged()); -} - -void ProfileSyncService::ShowLoginDialog() { - if (wizard_.IsVisible()) - return; - if (last_auth_error_ != AUTH_ERROR_NONE) - wizard_.Step(SyncSetupWizard::GAIA_LOGIN); -} - -// ApplyModelChanges is called by the sync backend after changes have been made -// to the sync engine's model. Apply these changes to the browser bookmark -// model. -void ProfileSyncService::ApplyModelChanges( - const sync_api::BaseTransaction* trans, - const sync_api::SyncManager::ChangeRecord* changes, - int change_count) { - if (!ShouldPushChanges()) - return; - - // A note about ordering. Sync backend is responsible for ordering the change - // records in the following order: - // - // 1. Deletions, from leaves up to parents. - // 2. Existing items with synced parents & predecessors. - // 3. New items with synced parents & predecessors. - // 4. Items with parents & predecessors in the list. - // 5. Repeat #4 until all items are in the list. - // - // "Predecessor" here means the previous item within a given folder; an item - // in the first position is always said to have a synced predecessor. - // For the most part, applying these changes in the order given will yield - // the correct result. There is one exception, however: for items that are - // moved away from a folder that is being deleted, we will process the delete - // before the move. Since deletions in the bookmark model propagate from - // parent to child, we must move them to a temporary location. - BookmarkModel* model = profile_->GetBookmarkModel(); - - // We are going to make changes to the bookmarks model, but don't want to end - // up in a feedback loop, so remove ourselves as an observer while applying - // changes. - model->RemoveObserver(this); - - // A parent to hold nodes temporarily orphaned by parent deletion. It is - // lazily created inside the loop. - const BookmarkNode* foster_parent = NULL; - for (int i = 0; i < change_count; ++i) { - const BookmarkNode* dst = - model_associator_->GetBookmarkNodeFromSyncId(changes[i].id); - // Ignore changes to the permanent top-level nodes. We only care about - // their children. - if ((dst == model->GetBookmarkBarNode()) || (dst == model->other_node())) - continue; - if (changes[i].action == - sync_api::SyncManager::ChangeRecord::ACTION_DELETE) { - // Deletions should always be at the front of the list. - DCHECK(i == 0 || changes[i-1].action == changes[i].action); - // Children of a deleted node should not be deleted; they may be - // reparented by a later change record. Move them to a temporary place. - DCHECK(dst) << "Could not find node to be deleted"; - const BookmarkNode* parent = dst->GetParent(); - if (dst->GetChildCount()) { - if (!foster_parent) { - foster_parent = model->AddGroup(model->other_node(), - model->other_node()->GetChildCount(), - std::wstring()); - } - for (int i = dst->GetChildCount() - 1; i >= 0; --i) { - model->Move(dst->GetChild(i), foster_parent, - foster_parent->GetChildCount()); - } - } - DCHECK_EQ(dst->GetChildCount(), 0) << "Node being deleted has children"; - model->Remove(parent, parent->IndexOfChild(dst)); - dst = NULL; - model_associator_->DisassociateIds(changes[i].id); - } else { - DCHECK_EQ((changes[i].action == - sync_api::SyncManager::ChangeRecord::ACTION_ADD), (dst == NULL)) - << "ACTION_ADD should be seen if and only if the node is unknown."; - - sync_api::ReadNode src(trans); - if (!src.InitByIdLookup(changes[i].id)) { - LOG(ERROR) << "ApplyModelChanges was passed a bad ID"; - SetUnrecoverableError(); - return; - } - - CreateOrUpdateBookmarkNode(&src, model); - } - } - // Clean up the temporary node. - if (foster_parent) { - // There should be no nodes left under the foster parent. - DCHECK_EQ(foster_parent->GetChildCount(), 0); - model->Remove(foster_parent->GetParent(), - foster_parent->GetParent()->IndexOfChild(foster_parent)); - foster_parent = NULL; - } - - // We are now ready to hear about bookmarks changes again. - model->AddObserver(this); -} - -// Create a bookmark node corresponding to |src| if one is not already -// associated with |src|. -const BookmarkNode* ProfileSyncService::CreateOrUpdateBookmarkNode( - sync_api::BaseNode* src, - BookmarkModel* model) { - const BookmarkNode* parent = - model_associator_->GetBookmarkNodeFromSyncId(src->GetParentId()); - if (!parent) { - DLOG(WARNING) << "Could not find parent of node being added/updated." - << " Node title: " << src->GetTitle() - << ", parent id = " << src->GetParentId(); - return NULL; - } - int index = CalculateBookmarkModelInsertionIndex(parent, src); - const BookmarkNode* dst = model_associator_->GetBookmarkNodeFromSyncId( - src->GetId()); - if (!dst) { - dst = CreateBookmarkNode(src, parent, index); - model_associator_->AssociateIds(dst->id(), src->GetId()); - } else { - // URL and is_folder are not expected to change. - // TODO(ncarter): Determine if such changes should be legal or not. - DCHECK_EQ(src->GetIsFolder(), dst->is_folder()); - - // Handle reparenting and/or repositioning. - model->Move(dst, parent, index); - - // Handle title update and URL changes due to possible conflict resolution - // that can happen if both a local user change and server change occur - // within a sufficiently small time interval. - const BookmarkNode* old_dst = dst; - dst = bookmark_utils::ApplyEditsWithNoGroupChange(model, parent, dst, - UTF16ToWide(src->GetTitle()), - src->GetIsFolder() ? GURL() : GURL(src->GetURL()), - NULL); // NULL because we don't need a BookmarkEditor::Handler. - if (dst != old_dst) { // dst was replaced with a new node with new URL. - model_associator_->DisassociateIds(src->GetId()); - model_associator_->AssociateIds(dst->id(), src->GetId()); - } - SetBookmarkFavicon(src, dst); - } - - return dst; -} - -// Creates a bookmark node under the given parent node from the given sync -// node. Returns the newly created node. -const BookmarkNode* ProfileSyncService::CreateBookmarkNode( - sync_api::BaseNode* sync_node, - const BookmarkNode* parent, - int index) const { - DCHECK(parent); - DCHECK(index >= 0 && index <= parent->GetChildCount()); - BookmarkModel* model = profile_->GetBookmarkModel(); - - const BookmarkNode* node; - if (sync_node->GetIsFolder()) { - node = model->AddGroup(parent, index, UTF16ToWide(sync_node->GetTitle())); - } else { - GURL url(sync_node->GetURL()); - node = model->AddURL(parent, index, UTF16ToWide(sync_node->GetTitle()), url); - SetBookmarkFavicon(sync_node, node); - } - return node; -} - -// Sets the favicon of the given bookmark node from the given sync node. -bool ProfileSyncService::SetBookmarkFavicon( - sync_api::BaseNode* sync_node, - const BookmarkNode* bookmark_node) const { - size_t icon_size = 0; - const unsigned char* icon_bytes = sync_node->GetFaviconBytes(&icon_size); - if (!icon_size || !icon_bytes) - return false; - - // Registering a favicon requires that we provide a source URL, but we - // don't know where these came from. Currently we just use the - // destination URL, which is not correct, but since the favicon URL - // is used as a key in the history's thumbnail DB, this gives us a value - // which does not collide with others. - GURL fake_icon_url = bookmark_node->GetURL(); - - std::vector<unsigned char> icon_bytes_vector(icon_bytes, - icon_bytes + icon_size); - - HistoryService* history = - profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); - - history->AddPage(bookmark_node->GetURL()); - history->SetFavIcon(bookmark_node->GetURL(), - fake_icon_url, - icon_bytes_vector); - - return true; -} - -void ProfileSyncService::SetSyncNodeFavicon( - const BookmarkNode* bookmark_node, - sync_api::WriteNode* sync_node) const { - std::vector<unsigned char> favicon_bytes; - EncodeFavicon(bookmark_node, &favicon_bytes); - if (!favicon_bytes.empty()) - sync_node->SetFaviconBytes(&favicon_bytes[0], favicon_bytes.size()); -} - -SyncBackendHost::StatusSummary ProfileSyncService::QuerySyncStatusSummary() { - return backend_->GetStatusSummary(); -} - -SyncBackendHost::Status ProfileSyncService::QueryDetailedSyncStatus() { - return backend_->GetDetailedStatus(); -} - -std::wstring ProfileSyncService::BuildSyncStatusSummaryText( - const sync_api::SyncManager::Status::Summary& summary) { - switch (summary) { - case sync_api::SyncManager::Status::OFFLINE: - return L"OFFLINE"; - case sync_api::SyncManager::Status::OFFLINE_UNSYNCED: - return L"OFFLINE_UNSYNCED"; - case sync_api::SyncManager::Status::SYNCING: - return L"SYNCING"; - case sync_api::SyncManager::Status::READY: - return L"READY"; - case sync_api::SyncManager::Status::PAUSED: - return L"PAUSED"; - case sync_api::SyncManager::Status::CONFLICT: - return L"CONFLICT"; - case sync_api::SyncManager::Status::OFFLINE_UNUSABLE: - return L"OFFLINE_UNUSABLE"; - case sync_api::SyncManager::Status::INVALID: // fall through - default: - return L"UNKNOWN"; - } -} - -std::wstring ProfileSyncService::GetLastSyncedTimeString() const { - if (last_synced_time_.is_null()) - return kLastSyncedTimeNever; - - base::TimeDelta last_synced = base::Time::Now() - last_synced_time_; - - if (last_synced < base::TimeDelta::FromMinutes(1)) - return kLastSyncedTimeWithinLastMinute; - - return TimeFormat::TimeElapsed(last_synced); -} - -string16 ProfileSyncService::GetAuthenticatedUsername() const { - return backend_->GetAuthenticatedUsername(); -} - -void ProfileSyncService::OnUserSubmittedAuth( - const std::string& username, const std::string& password) { - last_attempted_user_email_ = username; - is_auth_in_progress_ = true; - FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged()); - backend_->Authenticate(username, password); -} - -void ProfileSyncService::OnUserAcceptedMergeAndSync() { - bool merge_success = model_associator_->AssociateModels(); - wizard_.Step(SyncSetupWizard::DONE); // TODO(timsteele): error state? - if (!merge_success) { - LOG(ERROR) << "Model assocation failed."; - SetUnrecoverableError(); - return; - } - - ready_to_process_changes_ = true; - FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged()); -} - -void ProfileSyncService::OnUserCancelledDialog() { - if (!profile_->GetPrefs()->GetBoolean(prefs::kSyncHasSetupCompleted)) { - // A sync dialog was aborted before authentication or merge acceptance. - // Rollback. - DisableForUser(); - } - FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged()); -} - -void ProfileSyncService::StartProcessingChangesIfReady() { - BookmarkModel* model = profile_->GetBookmarkModel(); - - DCHECK(!ready_to_process_changes_); - - // First check if the subsystems are ready. We can't proceed until they - // both have finished loading. - if (!model->IsLoaded()) - return; - if (!backend_initialized_) - return; - - // Show the sync merge warning dialog if needed. - if (MergeAndSyncAcceptanceNeeded()) { - wizard_.Step(SyncSetupWizard::MERGE_AND_SYNC); - return; - } - - // We're ready to merge the models. - bool merge_success = model_associator_->AssociateModels(); - wizard_.Step(SyncSetupWizard::DONE); // TODO(timsteele): error state? - if (!merge_success) { - LOG(ERROR) << "Model assocation failed."; - SetUnrecoverableError(); - return; - } - - ready_to_process_changes_ = true; - FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged()); -} - -void ProfileSyncService::AddObserver(Observer* observer) { - observers_.AddObserver(observer); -} - -void ProfileSyncService::RemoveObserver(Observer* observer) { - observers_.RemoveObserver(observer); -} - -bool ProfileSyncService::ShouldPushChanges() { - return ready_to_process_changes_ && // Wait for model load and merge. - !unrecoverable_error_detected_; // Halt after any terrible events. -} - -#endif // CHROME_PERSONALIZATION diff --git a/chrome/browser/sync/profile_sync_service.h b/chrome/browser/sync/profile_sync_service.h deleted file mode 100644 index 288752f..0000000 --- a/chrome/browser/sync/profile_sync_service.h +++ /dev/null @@ -1,368 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifdef CHROME_PERSONALIZATION - -#ifndef CHROME_BROWSER_SYNC_PROFILE_SYNC_SERVICE_H_ -#define CHROME_BROWSER_SYNC_PROFILE_SYNC_SERVICE_H_ - -#include <string> -#include <map> -#include <vector> - -#include "base/basictypes.h" -#include "base/file_path.h" -#include "base/observer_list.h" -#include "base/scoped_ptr.h" -#include "chrome/browser/bookmarks/bookmark_model.h" -#include "chrome/browser/profile.h" -#include "chrome/browser/sync/glue/model_associator.h" -#include "chrome/browser/sync/glue/sync_backend_host.h" -#include "chrome/browser/views/sync/sync_setup_wizard.h" -#include "googleurl/src/gurl.h" - -class CommandLine; -class MessageLoop; -class Profile; - -namespace browser_sync { -class ModelAssociator; -} - -// Various UI components such as the New Tab page can be driven by observing -// the ProfileSyncService through this interface. -class ProfileSyncServiceObserver { - public: - // When one of the following events occurs, OnStateChanged() is called. - // Observers should query the service to determine what happened. - // - We initialized successfully. - // - There was an authentication error and the user needs to reauthenticate. - // - The sync servers are unavailable at this time. - // - Credentials are now in flight for authentication. - virtual void OnStateChanged() = 0; - protected: - virtual ~ProfileSyncServiceObserver() { } -}; - -// ProfileSyncService is the layer between browser subsystems like bookmarks, -// and the sync backend. -class ProfileSyncService : public BookmarkModelObserver, - public browser_sync::SyncFrontend { - public: - typedef ProfileSyncServiceObserver Observer; - typedef browser_sync::SyncBackendHost::Status Status; - - ProfileSyncService(Profile* profile); - virtual ~ProfileSyncService(); - - // Initializes the object. This should be called every time an object of this - // class is constructed. - void Initialize(); - - // Enables/disables sync for user. - virtual void EnableForUser(); - virtual void DisableForUser(); - - // Whether sync is enabled by user or not. - bool IsSyncEnabledByUser() const; - - // BookmarkModelObserver implementation. - virtual void Loaded(BookmarkModel* model); - virtual void BookmarkModelBeingDeleted(BookmarkModel* model) {} - virtual void BookmarkNodeMoved(BookmarkModel* model, - const BookmarkNode* old_parent, - int old_index, - const BookmarkNode* new_parent, - int new_index); - virtual void BookmarkNodeAdded(BookmarkModel* model, - const BookmarkNode* parent, - int index); - virtual void BookmarkNodeRemoved(BookmarkModel* model, - const BookmarkNode* parent, - int index, - const BookmarkNode* node); - virtual void BookmarkNodeChanged(BookmarkModel* model, - const BookmarkNode* node); - virtual void BookmarkNodeFavIconLoaded(BookmarkModel* model, - const BookmarkNode* node); - virtual void BookmarkNodeChildrenReordered(BookmarkModel* model, - const BookmarkNode* node); - - // SyncFrontend implementation. - virtual void OnBackendInitialized(); - virtual void OnSyncCycleCompleted(); - virtual void OnAuthError(); - virtual void ApplyModelChanges( - const sync_api::BaseTransaction* trans, - const sync_api::SyncManager::ChangeRecord* changes, - int change_count); - - // Called when a user enters credentials through UI. - virtual void OnUserSubmittedAuth(const std::string& username, - const std::string& password); - - // Called when a user decides whether to merge and sync or abort. - virtual void OnUserAcceptedMergeAndSync(); - - // Called when a user cancels any setup dialog (login, merge and sync, etc). - virtual void OnUserCancelledDialog(); - - // Get various information for displaying in the user interface. - browser_sync::SyncBackendHost::StatusSummary QuerySyncStatusSummary(); - browser_sync::SyncBackendHost::Status QueryDetailedSyncStatus(); - - AuthErrorState GetAuthErrorState() const { - return last_auth_error_; - } - - // Displays a dialog for the user to enter GAIA credentials and attempt - // re-authentication, and returns true if it actually opened the dialog. - // Returns false if a dialog is already showing, an auth attempt is in - // progress, the sync system is already authenticated, or some error - // occurred preventing the action. We make it the duty of ProfileSyncService - // to open the dialog to easily ensure only one is ever showing. - bool SetupInProgress() const { - return !IsSyncEnabledByUser() && WizardIsVisible(); - } - bool WizardIsVisible() const { return wizard_.IsVisible(); } - void ShowLoginDialog(); - - // Pretty-printed strings for a given StatusSummary. - static std::wstring BuildSyncStatusSummaryText( - const browser_sync::SyncBackendHost::StatusSummary& summary); - - // Returns true if the SyncBackendHost has told us it's ready to accept - // changes. - // TODO(timsteele): What happens if the bookmark model is loaded, a change - // takes place, and the backend isn't initialized yet? - bool sync_initialized() const { return backend_initialized_; } - - bool UIShouldDepictAuthInProgress() const { - return is_auth_in_progress_; - } - - // A timestamp marking the last time the service observed a transition from - // the SYNCING state to the READY state. Note that this does not reflect the - // last time we polled the server to see if there were any changes; the - // timestamp is only snapped when syncing takes place and we download or - // upload some bookmark entity. - const base::Time& last_synced_time() const { return last_synced_time_; } - - // Returns a user-friendly string form of last synced time (in minutes). - std::wstring GetLastSyncedTimeString() const; - - // Returns the authenticated username of the sync user, or empty if none - // exists. It will only exist if the authentication service provider (e.g - // GAIA) has confirmed the username is authentic. - virtual string16 GetAuthenticatedUsername() const; - - const std::string& last_attempted_user_email() const { - return last_attempted_user_email_; - } - - // The profile we are syncing for. - Profile* profile() { return profile_; } - - // Adds/removes an observer. ProfileSyncService does not take ownership of - // the observer. - void AddObserver(Observer* observer); - void RemoveObserver(Observer* observer); - - protected: - // Call this after any of the subsystems being synced (the bookmark - // model and the sync backend) finishes its initialization. When everything - // is ready, this function will bootstrap the subsystems so that they are - // initially in sync, and start forwarding changes between the two models. - void StartProcessingChangesIfReady(); - - // Various member accessors needed by unit tests. - browser_sync::SyncBackendHost* backend() { return backend_.get(); } - - // Call this when normal operation detects that the bookmark model and the - // syncer model are inconsistent, or similar. The ProfileSyncService will - // try to avoid doing any work to avoid crashing or corrupting things - // further, and will report an error status if queried. - void SetUnrecoverableError(); - - // Returns whether processing changes is allowed. Check this before doing - // any model-modifying operations. - bool ShouldPushChanges(); - - // Starts up the backend sync components. - void StartUp(); - // Shuts down the backend sync components. - // |sync_disabled| indicates if syncing is being disabled or not. - void Shutdown(bool sync_disabled); - - // Tests need to override this. - virtual void InitializeBackend(); - - // Tests need this. - void set_model_associator(browser_sync::ModelAssociator* manager) { - model_associator_ = manager; - } - - // We keep track of the last auth error observed so we can cover up the first - // "expected" auth failure from observers. - // TODO(timsteele): Same as expecting_first_run_auth_needed_event_. Remove - // this! - AuthErrorState last_auth_error_; - - // Cache of the last name the client attempted to authenticate. - std::string last_attempted_user_email_; - - private: - friend class browser_sync::ModelAssociator; - friend class ProfileSyncServiceTest; - friend class ProfileSyncServiceTestHarness; - friend class TestModelAssociator; - FRIEND_TEST(ProfileSyncServiceTest, UnrecoverableErrorSuspendsService); - - enum MoveOrCreate { - MOVE, - CREATE, - }; - - // Initializes the various settings from the command line. - void InitSettings(); - - // Methods to register, load and remove preferences. - void RegisterPreferences(); - void LoadPreferences(); - void ClearPreferences(); - - // Treat the |index|th child of |parent| as a newly added node, and create a - // corresponding node in the sync domain using |trans|. All properties - // will be transferred to the new node. A node corresponding to |parent| - // must already exist and be associated for this call to succeed. Returns - // the ID of the just-created node, or if creation fails, kInvalidID. - int64 CreateSyncNode(const BookmarkNode* parent, - int index, - sync_api::WriteTransaction* trans); - - // Create a bookmark node corresponding to |src| if one is not already - // associated with |src|. Returns the node that was created or updated. - const BookmarkNode* CreateOrUpdateBookmarkNode( - sync_api::BaseNode* src, - BookmarkModel* model); - - // Creates a bookmark node under the given parent node from the given sync - // node. Returns the newly created node. - const BookmarkNode* CreateBookmarkNode( - sync_api::BaseNode* sync_node, - const BookmarkNode* parent, - int index) const; - - // Sets the favicon of the given bookmark node from the given sync node. - // Returns whether the favicon was set in the bookmark node. - bool SetBookmarkFavicon(sync_api::BaseNode* sync_node, - const BookmarkNode* bookmark_node) const; - - // Sets the favicon of the given sync node from the given bookmark node. - void SetSyncNodeFavicon(const BookmarkNode* bookmark_node, - sync_api::WriteNode* sync_node) const; - - // Helper function to determine the appropriate insertion index of sync node - // |node| under the Bookmark model node |parent|, to make the positions - // match up between the two models. This presumes that the predecessor of the - // item (in the bookmark model) has already been moved into its appropriate - // position. - int CalculateBookmarkModelInsertionIndex( - const BookmarkNode* parent, - const sync_api::BaseNode* node) const; - - // Helper function used to fix the position of a sync node so that it matches - // the position of a corresponding bookmark model node. |parent| and - // |index| identify the bookmark model position. |dst| is the node whose - // position is to be fixed. If |operation| is CREATE, treat |dst| as an - // uncreated node and set its position via InitByCreation(); otherwise, - // |dst| is treated as an existing node, and its position will be set via - // SetPosition(). |trans| is the transaction to which |dst| belongs. Returns - // false on failure. - bool PlaceSyncNode(MoveOrCreate operation, - const BookmarkNode* parent, - int index, - sync_api::WriteTransaction* trans, - sync_api::WriteNode* dst); - - // Copy properties (but not position) from |src| to |dst|. - void UpdateSyncNodeProperties(const BookmarkNode* src, - sync_api::WriteNode* dst); - - // Helper function to encode a bookmark's favicon into a PNG byte vector. - void EncodeFavicon(const BookmarkNode* src, - std::vector<unsigned char>* dst) const; - - // Remove the sync node corresponding to |node|. It shouldn't have - // any children. - void RemoveOneSyncNode(sync_api::WriteTransaction* trans, - const BookmarkNode* node); - - // Remove all the sync nodes associated with |node| and its children. - void RemoveSyncNodeHierarchy(const BookmarkNode* node); - - // Whether the sync merge warning should be shown. - bool MergeAndSyncAcceptanceNeeded() const; - - // Sets the last synced time to the current time. - void UpdateLastSyncedTime(); - - // The profile whose data we are synchronizing. - Profile* profile_; - - // TODO(ncarter): Put this in a profile, once there is UI for it. - // This specifies where to find the sync server. - GURL sync_service_url_; - - // Model assocation manager instance. - scoped_refptr<browser_sync::ModelAssociator> model_associator_; - - // The last time we detected a successful transition from SYNCING state. - // Our backend notifies us whenever we should take a new snapshot. - base::Time last_synced_time_; - - // Our asynchronous backend to communicate with sync components living on - // other threads. - scoped_ptr<browser_sync::SyncBackendHost> backend_; - - // Whether the SyncBackendHost has been initialized. - bool backend_initialized_; - - // Set to true when the user first enables sync, and we are waiting for - // syncapi to give us the green light on providing credentials for the first - // time. It is set back to false as soon as we get this message, and is - // false all other times so we don't have to persist this value as it will - // get initialized to false. - // TODO(timsteele): Remove this by way of starting the wizard when enabling - // sync *before* initializing the backend. syncapi will need to change, but - // it means we don't have to wait for the first AuthError; if we ever get - // one, it is actually an error and this bool isn't needed. - bool expecting_first_run_auth_needed_event_; - - // Various pieces of UI query this value to determine if they should show - // an "Authenticating.." type of message. We are the only central place - // all auth attempts funnel through, so it makes sense to provide this. - // As its name suggests, this should NOT be used for anything other than UI. - bool is_auth_in_progress_; - - // True only after all bootstrapping has succeeded: the bookmark model is - // loaded, the sync backend is initialized, and the two domains are - // consistent with one another. - bool ready_to_process_changes_; - - // True if an unrecoverable error (e.g. violation of an assumed invariant) - // occurred during syncer operation. This value should be checked before - // doing any work that might corrupt things further. - bool unrecoverable_error_detected_; - - SyncSetupWizard wizard_; - - ObserverList<Observer> observers_; - - DISALLOW_COPY_AND_ASSIGN(ProfileSyncService); -}; - -#endif // CHROME_BROWSER_SYNC_PROFILE_SYNC_SERVICE_H_ - -#endif // CHROME_PERSONALIZATION diff --git a/chrome/browser/sync/profile_sync_service_unittest.cc b/chrome/browser/sync/profile_sync_service_unittest.cc deleted file mode 100644 index 41f6050..0000000 --- a/chrome/browser/sync/profile_sync_service_unittest.cc +++ /dev/null @@ -1,1272 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifdef CHROME_PERSONALIZATION - -#include "testing/gtest/include/gtest/gtest.h" - -#include <stack> -#include <vector> - -#include "base/command_line.h" -#include "base/string_util.h" -#include "base/string16.h" -#include "chrome/browser/bookmarks/bookmark_model.h" -#include "chrome/browser/profile.h" -#include "chrome/common/pref_service.h" -#include "chrome/browser/sync/engine/syncapi.h" -#include "chrome/browser/sync/glue/model_associator.h" -#include "chrome/browser/sync/profile_sync_service.h" -#include "chrome/test/testing_profile.h" - -using std::vector; -using browser_sync::ModelAssociator; -using browser_sync::SyncBackendHost; - -class TestModelAssociator : public ModelAssociator { - public: - TestModelAssociator(ProfileSyncService* service) - : ModelAssociator(service) { - } - - virtual bool GetSyncIdForTaggedNode(const string16& tag, int64* sync_id) { - sync_api::WriteTransaction trans( - sync_service()->backend()->GetUserShareHandle()); - sync_api::ReadNode root(&trans); - root.InitByRootLookup(); - - // First, try to find a node with the title among the root's children. - // This will be the case if we are testing model persistence, and - // are reloading a sync repository created earlier in the test. - for (int64 id = root.GetFirstChildId(); id != sync_api::kInvalidId; /***/) { - sync_api::ReadNode child(&trans); - if (!child.InitByIdLookup(id)) { - NOTREACHED(); - break; - } - if (tag == child.GetTitle()) { - *sync_id = id; - return true; - } - id = child.GetSuccessorId(); - } - - sync_api::WriteNode node(&trans); - if (!node.InitByCreation(root, NULL)) - return false; - node.SetIsFolder(true); - node.SetTitle(tag.c_str()); - node.SetExternalId(0); - *sync_id = node.GetId(); - return true; - } -}; - -class TestProfileSyncService : public ProfileSyncService { - public: - TestProfileSyncService(Profile* profile) : ProfileSyncService(profile) { - PrefService* pref_service = profile->GetPrefs(); - if (pref_service->IsPrefRegistered(prefs::kSyncUserName)) - return; - pref_service->RegisterStringPref(prefs::kSyncUserName, string16()); - pref_service->RegisterStringPref(prefs::kSyncLastSyncedTime, string16()); - pref_service->RegisterBooleanPref(prefs::kSyncHasSetupCompleted, true); - } - virtual ~TestProfileSyncService() { - } - - virtual void InitializeBackend() { - set_model_associator(new TestModelAssociator(this)); - backend()->InitializeForTestMode(L"testuser"); - // The SyncBackend posts a task to the current loop when initialization - // completes. - MessageLoop::current()->Run(); - // Initialization is synchronous for test mode, so we should be good to go. - DCHECK(sync_initialized()); - } - - virtual void OnBackendInitialized() { - ProfileSyncService::OnBackendInitialized(); - MessageLoop::current()->Quit(); - } - - virtual bool MergeAndSyncAcceptanceNeeded() { - // Never show the dialog. - return false; - } -}; - -// FakeServerChange constructs a list of sync_api::ChangeRecords while modifying -// the sync model, and can pass the ChangeRecord list to a -// sync_api::SyncObserver (i.e., the ProfileSyncService) to test the client -// change-application behavior. -// Tests using FakeServerChange should be careful to avoid back-references, -// since FakeServerChange will send the edits in the order specified. -class FakeServerChange { - public: - explicit FakeServerChange(sync_api::WriteTransaction* trans) : trans_(trans) { - } - - // Pretend that the server told the syncer to add a bookmark object. - int64 Add(const string16& title, - const string16& url, - bool is_folder, - int64 parent_id, - int64 predecessor_id) { - sync_api::ReadNode parent(trans_); - EXPECT_TRUE(parent.InitByIdLookup(parent_id)); - sync_api::WriteNode node(trans_); - if (predecessor_id == 0) { - EXPECT_TRUE(node.InitByCreation(parent, NULL)); - } else { - sync_api::ReadNode predecessor(trans_); - EXPECT_TRUE(predecessor.InitByIdLookup(predecessor_id)); - EXPECT_EQ(predecessor.GetParentId(), parent.GetId()); - EXPECT_TRUE(node.InitByCreation(parent, &predecessor)); - } - EXPECT_EQ(node.GetPredecessorId(), predecessor_id); - EXPECT_EQ(node.GetParentId(), parent_id); - node.SetIsFolder(is_folder); - node.SetTitle(title.c_str()); - if (!is_folder) { - GURL gurl(url); - node.SetURL(url.c_str()); - } - sync_api::SyncManager::ChangeRecord record; - record.action = sync_api::SyncManager::ChangeRecord::ACTION_ADD; - record.id = node.GetId(); - changes_.push_back(record); - return node.GetId(); - } - - // Add a bookmark folder. - int64 AddFolder(const string16& title, - int64 parent_id, - int64 predecessor_id) { - return Add(title, string16(), true, parent_id, predecessor_id); - } - - // Add a bookmark. - int64 AddURL(const string16& title, - const string16& url, - int64 parent_id, - int64 predecessor_id) { - return Add(title, url, false, parent_id, predecessor_id); - } - - // Pretend that the server told the syncer to delete an object. - void Delete(int64 id) { - { - // Delete the sync node. - sync_api::WriteNode node(trans_); - EXPECT_TRUE(node.InitByIdLookup(id)); - EXPECT_FALSE(node.GetFirstChildId()); - node.Remove(); - } - { - // Verify the deletion. - sync_api::ReadNode node(trans_); - EXPECT_FALSE(node.InitByIdLookup(id)); - } - - sync_api::SyncManager::ChangeRecord record; - record.action = sync_api::SyncManager::ChangeRecord::ACTION_DELETE; - record.id = id; - // Deletions are always first in the changelist, but we can't actually do - // WriteNode::Remove() on the node until its children are moved. So, as - // a practical matter, users of FakeServerChange must move or delete - // children before parents. Thus, we must insert the deletion record - // at the front of the vector. - changes_.insert(changes_.begin(), record); - } - - // Set a new title value, and return the old value. - string16 ModifyTitle(int64 id, const string16& new_title) { - sync_api::WriteNode node(trans_); - EXPECT_TRUE(node.InitByIdLookup(id)); - string16 old_title = node.GetTitle(); - node.SetTitle(new_title.c_str()); - SetModified(id); - return old_title; - } - - // Set a new URL value, and return the old value. - // TODO(ncarter): Determine if URL modifications are even legal. - string16 ModifyURL(int64 id, const string16& new_url) { - sync_api::WriteNode node(trans_); - EXPECT_TRUE(node.InitByIdLookup(id)); - EXPECT_FALSE(node.GetIsFolder()); - string16 old_url = node.GetURL(); - node.SetURL(new_url.c_str()); - SetModified(id); - return old_url; - } - - // Set a new parent and predecessor value. Return the old parent id. - // We could return the old predecessor id, but it turns out not to be - // very useful for assertions. - int64 ModifyPosition(int64 id, int64 parent_id, int64 predecessor_id) { - sync_api::ReadNode parent(trans_); - EXPECT_TRUE(parent.InitByIdLookup(parent_id)); - sync_api::WriteNode node(trans_); - EXPECT_TRUE(node.InitByIdLookup(id)); - int64 old_parent_id = node.GetParentId(); - if (predecessor_id == 0) { - EXPECT_TRUE(node.SetPosition(parent, NULL)); - } else { - sync_api::ReadNode predecessor(trans_); - EXPECT_TRUE(predecessor.InitByIdLookup(predecessor_id)); - EXPECT_EQ(predecessor.GetParentId(), parent.GetId()); - EXPECT_TRUE(node.SetPosition(parent, &predecessor)); - } - SetModified(id); - return old_parent_id; - } - - // Pass the fake change list to |service|. - void ApplyPendingChanges(ProfileSyncService* service) { - service->ApplyModelChanges(trans_, changes_.size() ? &changes_[0] : NULL, - changes_.size()); - } - - const vector<sync_api::SyncManager::ChangeRecord>& changes() { - return changes_; - } - - private: - // Helper function to push an ACTION_UPDATE record onto the back - // of the changelist. - void SetModified(int64 id) { - // Coalesce multi-property edits. - if (changes_.size() > 0 && changes_.back().id == id && - changes_.back().action == - sync_api::SyncManager::ChangeRecord::ACTION_UPDATE) - return; - sync_api::SyncManager::ChangeRecord record; - record.action = sync_api::SyncManager::ChangeRecord::ACTION_UPDATE; - record.id = id; - changes_.push_back(record); - } - - // The transaction on which everything happens. - sync_api::WriteTransaction *trans_; - - // The change list we construct. - vector<sync_api::SyncManager::ChangeRecord> changes_; -}; - -class ProfileSyncServiceTest : public testing::Test { - protected: - enum LoadOption { LOAD_FROM_STORAGE, DELETE_EXISTING_STORAGE }; - enum SaveOption { SAVE_TO_STORAGE, DONT_SAVE_TO_STORAGE }; - ProfileSyncServiceTest() : model_(NULL) { - profile_.reset(new TestingProfile()); - profile_->set_has_history_service(true); - } - virtual ~ProfileSyncServiceTest() { - // Kill the service before the profile. - service_.reset(); - profile_.reset(); - } - - ModelAssociator* associator() { - DCHECK(service_.get()); - return service_->model_associator_; - } - - void StartSyncService() { - if (!service_.get()) { - service_.reset(new TestProfileSyncService(profile_.get())); - service_->Initialize(); - } - // The service may have already started sync automatically if it's already - // enabled by user once. - if (!service_->IsSyncEnabledByUser()) - service_->EnableForUser(); - } - void StopSyncService(SaveOption save) { - if (save == DONT_SAVE_TO_STORAGE) - service_->DisableForUser(); - service_.reset(); - } - - // Load (or re-load) the bookmark model. |load| controls use of the - // bookmarks file on disk. |save| controls whether the newly loaded - // bookmark model will write out a bookmark file as it goes. - void LoadBookmarkModel(LoadOption load, SaveOption save) { - bool delete_bookmarks = load == DELETE_EXISTING_STORAGE; - profile_->CreateBookmarkModel(delete_bookmarks); - model_ = profile_->GetBookmarkModel(); - // Wait for the bookmarks model to load. - profile_->BlockUntilBookmarkModelLoaded(); - // This noticeably speeds up the unit tests that request it. - if (save == DONT_SAVE_TO_STORAGE) - model_->ClearStore(); - } - - void ExpectSyncerNodeMatching(sync_api::BaseTransaction* trans, - const BookmarkNode* bnode) { - sync_api::ReadNode gnode(trans); - EXPECT_TRUE(associator()->InitSyncNodeFromBookmarkId(bnode->id(), &gnode)); - // Non-root node titles and parents must match. - if (bnode != model_->GetBookmarkBarNode() && - bnode != model_->other_node()) { - EXPECT_EQ(bnode->GetTitle(), gnode.GetTitle()); - EXPECT_EQ(associator()->GetBookmarkNodeFromSyncId(gnode.GetParentId()), - bnode->GetParent()); - } - EXPECT_EQ(bnode->is_folder(), gnode.GetIsFolder()); - if (bnode->is_url()) - EXPECT_EQ(bnode->GetURL(), GURL(gnode.GetURL())); - - // Check for position matches. - int browser_index = bnode->GetParent()->IndexOfChild(bnode); - if (browser_index == 0) { - EXPECT_EQ(gnode.GetPredecessorId(), 0); - } else { - const BookmarkNode* bprev = - bnode->GetParent()->GetChild(browser_index - 1); - sync_api::ReadNode gprev(trans); - ASSERT_TRUE(associator()->InitSyncNodeFromBookmarkId(bprev->id(), - &gprev)); - EXPECT_EQ(gnode.GetPredecessorId(), gprev.GetId()); - EXPECT_EQ(gnode.GetParentId(), gprev.GetParentId()); - } - if (browser_index == bnode->GetParent()->GetChildCount() - 1) { - EXPECT_EQ(gnode.GetSuccessorId(), 0); - } else { - const BookmarkNode* bnext = - bnode->GetParent()->GetChild(browser_index + 1); - sync_api::ReadNode gnext(trans); - ASSERT_TRUE(associator()->InitSyncNodeFromBookmarkId(bnext->id(), - &gnext)); - EXPECT_EQ(gnode.GetSuccessorId(), gnext.GetId()); - EXPECT_EQ(gnode.GetParentId(), gnext.GetParentId()); - } - if (bnode->GetChildCount()) { - EXPECT_TRUE(gnode.GetFirstChildId()); - } - } - - void ExpectSyncerNodeMatching(const BookmarkNode* bnode) { - sync_api::ReadTransaction trans(service_->backend_->GetUserShareHandle()); - ExpectSyncerNodeMatching(&trans, bnode); - } - - void ExpectBrowserNodeMatching(sync_api::BaseTransaction* trans, - int64 sync_id) { - EXPECT_TRUE(sync_id); - const BookmarkNode* bnode = - associator()->GetBookmarkNodeFromSyncId(sync_id); - ASSERT_TRUE(bnode); - int64 id = associator()->GetSyncIdFromBookmarkId(bnode->id()); - EXPECT_EQ(id, sync_id); - ExpectSyncerNodeMatching(trans, bnode); - } - - void ExpectBrowserNodeUnknown(int64 sync_id) { - EXPECT_FALSE(associator()->GetBookmarkNodeFromSyncId(sync_id)); - } - - void ExpectBrowserNodeKnown(int64 sync_id) { - EXPECT_TRUE(associator()->GetBookmarkNodeFromSyncId(sync_id)); - } - - void ExpectSyncerNodeKnown(const BookmarkNode* node) { - int64 sync_id = associator()->GetSyncIdFromBookmarkId(node->id()); - EXPECT_NE(sync_id, sync_api::kInvalidId); - } - - void ExpectSyncerNodeUnknown(const BookmarkNode* node) { - int64 sync_id = associator()->GetSyncIdFromBookmarkId(node->id()); - EXPECT_EQ(sync_id, sync_api::kInvalidId); - } - - void ExpectBrowserNodeTitle(int64 sync_id, const string16& title) { - const BookmarkNode* bnode = - associator()->GetBookmarkNodeFromSyncId(sync_id); - ASSERT_TRUE(bnode); - EXPECT_EQ(bnode->GetTitle(), title); - } - - void ExpectBrowserNodeURL(int64 sync_id, const string16& url) { - const BookmarkNode* bnode = - associator()->GetBookmarkNodeFromSyncId(sync_id); - ASSERT_TRUE(bnode); - GURL url2(url); - EXPECT_EQ(url2, bnode->GetURL()); - } - - void ExpectBrowserNodeParent(int64 sync_id, int64 parent_sync_id) { - const BookmarkNode* node = associator()->GetBookmarkNodeFromSyncId(sync_id); - ASSERT_TRUE(node); - const BookmarkNode* parent = - associator()->GetBookmarkNodeFromSyncId(parent_sync_id); - EXPECT_TRUE(parent); - EXPECT_EQ(node->GetParent(), parent); - } - - void ExpectModelMatch(sync_api::BaseTransaction* trans) { - const BookmarkNode* root = model_->root_node(); - EXPECT_EQ(root->IndexOfChild(model_->GetBookmarkBarNode()), 0); - EXPECT_EQ(root->IndexOfChild(model_->other_node()), 1); - - std::stack<int64> stack; - stack.push(bookmark_bar_id()); - while (!stack.empty()) { - int64 id = stack.top(); - stack.pop(); - if (!id) continue; - - ExpectBrowserNodeMatching(trans, id); - - sync_api::ReadNode gnode(trans); - ASSERT_TRUE(gnode.InitByIdLookup(id)); - stack.push(gnode.GetFirstChildId()); - stack.push(gnode.GetSuccessorId()); - } - } - - void ExpectModelMatch() { - sync_api::ReadTransaction trans(service_->backend_->GetUserShareHandle()); - ExpectModelMatch(&trans); - } - - int64 other_bookmarks_id() { - return associator()->GetSyncIdFromBookmarkId(model_->other_node()->id()); - } - - int64 bookmark_bar_id() { - return associator()->GetSyncIdFromBookmarkId( - model_->GetBookmarkBarNode()->id()); - } - - SyncBackendHost* backend() { return service_->backend_.get(); } - - // This serves as the "UI loop" on which the ProfileSyncService lives and - // operates. It is needed because the SyncBackend can post tasks back to - // the service, meaning it can't be null. It doesn't have to be running, - // though -- OnInitializationCompleted is the only example (so far) in this - // test where we need to Run the loop to swallow a task and then quit, to - // avoid leaking the ProfileSyncService (the PostTask will retain the callee - // and caller until the task is run). - MessageLoop message_loop_; - - scoped_ptr<ProfileSyncService> service_; - scoped_ptr<TestingProfile> profile_; - BookmarkModel* model_; -}; - -TEST_F(ProfileSyncServiceTest, InitialState) { - LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE); - StartSyncService(); - - EXPECT_TRUE(other_bookmarks_id()); - EXPECT_TRUE(bookmark_bar_id()); - - ExpectModelMatch(); -} - -TEST_F(ProfileSyncServiceTest, BookmarkModelOperations) { - LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE); - StartSyncService(); - - // Test addition. - const BookmarkNode* folder = - model_->AddGroup(model_->other_node(), 0, L"foobar"); - ExpectSyncerNodeMatching(folder); - ExpectModelMatch(); - const BookmarkNode* folder2 = model_->AddGroup(folder, 0, L"nested"); - ExpectSyncerNodeMatching(folder2); - ExpectModelMatch(); - const BookmarkNode* url1 = model_->AddURL( - folder, 0, L"Internets #1 Pies Site", GURL(L"http://www.easypie.com/")); - ExpectSyncerNodeMatching(url1); - ExpectModelMatch(); - const BookmarkNode* url2 = model_->AddURL( - folder, 1, L"Airplanes", GURL(L"http://www.easyjet.com/")); - ExpectSyncerNodeMatching(url2); - ExpectModelMatch(); - - // Test modification. - model_->SetTitle(url2, L"EasyJet"); - ExpectModelMatch(); - model_->Move(url1, folder2, 0); - ExpectModelMatch(); - model_->Move(folder2, model_->GetBookmarkBarNode(), 0); - ExpectModelMatch(); - model_->SetTitle(folder2, L"Not Nested"); - ExpectModelMatch(); - model_->Move(folder, folder2, 0); - ExpectModelMatch(); - model_->SetTitle(folder, L"who's nested now?"); - ExpectModelMatch(); - - // Test deletion. - // Delete a single item. - model_->Remove(url2->GetParent(), url2->GetParent()->IndexOfChild(url2)); - ExpectModelMatch(); - // Delete an item with several children. - model_->Remove(folder2->GetParent(), - folder2->GetParent()->IndexOfChild(folder2)); - ExpectModelMatch(); -} - -TEST_F(ProfileSyncServiceTest, ServerChangeProcessing) { - LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE); - StartSyncService(); - - sync_api::WriteTransaction trans(backend()->GetUserShareHandle()); - - FakeServerChange adds(&trans); - int64 f1 = adds.AddFolder(L"Server Folder B", bookmark_bar_id(), 0); - int64 f2 = adds.AddFolder(L"Server Folder A", bookmark_bar_id(), f1); - int64 u1 = adds.AddURL(L"Some old site", L"ftp://nifty.andrew.cmu.edu/", - bookmark_bar_id(), f2); - int64 u2 = adds.AddURL(L"Nifty", L"ftp://nifty.andrew.cmu.edu/", f1, 0); - // u3 is a duplicate URL - int64 u3 = adds.AddURL(L"Nifty2", L"ftp://nifty.andrew.cmu.edu/", f1, u2); - // u4 is a duplicate title, different URL. - int64 u4 = adds.AddURL(L"Some old site", L"http://slog.thestranger.com/", - bookmark_bar_id(), u1); - // u5 tests an empty-string title. - string16 javascript_url(L"javascript:(function(){var w=window.open(" \ - L"'about:blank','gnotesWin','location=0,menubar=0," \ - L"scrollbars=0,status=0,toolbar=0,width=300," \ - L"height=300,resizable');});"); - int64 u5 = adds.AddURL(L"", javascript_url, other_bookmarks_id(), 0); - - vector<sync_api::SyncManager::ChangeRecord>::const_iterator it; - // The bookmark model shouldn't yet have seen any of the nodes of |adds|. - for (it = adds.changes().begin(); it != adds.changes().end(); ++it) - ExpectBrowserNodeUnknown(it->id); - - adds.ApplyPendingChanges(service_.get()); - - // Make sure the bookmark model received all of the nodes in |adds|. - for (it = adds.changes().begin(); it != adds.changes().end(); ++it) - ExpectBrowserNodeMatching(&trans, it->id); - ExpectModelMatch(&trans); - - // Part two: test modifications. - FakeServerChange mods(&trans); - // Mess with u2, and move it into empty folder f2 - // TODO(ncarter): Determine if we allow ModifyURL ops or not. - /* string16 u2_old_url = mods.ModifyURL(u2, L"http://www.google.com"); */ - string16 u2_old_title = mods.ModifyTitle(u2, L"The Google"); - int64 u2_old_parent = mods.ModifyPosition(u2, f2, 0); - - // Now move f1 after u2. - string16 f1_old_title = mods.ModifyTitle(f1, L"Server Folder C"); - int64 f1_old_parent = mods.ModifyPosition(f1, f2, u2); - - // Then add u3 after f1. - int64 u3_old_parent = mods.ModifyPosition(u3, f2, f1); - - // Test that the property changes have not yet taken effect. - ExpectBrowserNodeTitle(u2, u2_old_title); - /* ExpectBrowserNodeURL(u2, u2_old_url); */ - ExpectBrowserNodeParent(u2, u2_old_parent); - - ExpectBrowserNodeTitle(f1, f1_old_title); - ExpectBrowserNodeParent(f1, f1_old_parent); - - ExpectBrowserNodeParent(u3, u3_old_parent); - - // Apply the changes. - mods.ApplyPendingChanges(service_.get()); - - // Check for successful application. - for (it = mods.changes().begin(); it != mods.changes().end(); ++it) - ExpectBrowserNodeMatching(&trans, it->id); - ExpectModelMatch(&trans); - - // Part 3: Test URL deletion. - FakeServerChange dels(&trans); - dels.Delete(u2); - dels.Delete(u3); - - ExpectBrowserNodeKnown(u2); - ExpectBrowserNodeKnown(u3); - - dels.ApplyPendingChanges(service_.get()); - - ExpectBrowserNodeUnknown(u2); - ExpectBrowserNodeUnknown(u3); - ExpectModelMatch(&trans); -} - -// Tests a specific case in ApplyModelChanges where we move the -// children out from under a parent, and then delete the parent -// in the same changelist. The delete shows up first in the changelist, -// requiring the children to be moved to a temporary location. -TEST_F(ProfileSyncServiceTest, ServerChangeRequiringFosterParent) { - LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE); - StartSyncService(); - - sync_api::WriteTransaction trans(backend()->GetUserShareHandle()); - - // Stress the immediate children of other_node because that's where - // ApplyModelChanges puts a temporary foster parent node. - string16 url(L"http://dev.chromium.org/"); - FakeServerChange adds(&trans); - int64 f0 = other_bookmarks_id(); // + other_node - int64 f1 = adds.AddFolder(L"f1", f0, 0); // + f1 - int64 f2 = adds.AddFolder(L"f2", f1, 0); // + f2 - int64 u3 = adds.AddURL( L"u3", url, f2, 0); // + u3 - int64 u4 = adds.AddURL( L"u4", url, f2, u3); // + u4 - int64 u5 = adds.AddURL( L"u5", url, f1, f2); // + u5 - int64 f6 = adds.AddFolder(L"f6", f1, u5); // + f6 - int64 u7 = adds.AddURL( L"u7", url, f0, f1); // + u7 - - vector<sync_api::SyncManager::ChangeRecord>::const_iterator it; - // The bookmark model shouldn't yet have seen any of the nodes of |adds|. - for (it = adds.changes().begin(); it != adds.changes().end(); ++it) - ExpectBrowserNodeUnknown(it->id); - - adds.ApplyPendingChanges(service_.get()); - - // Make sure the bookmark model received all of the nodes in |adds|. - for (it = adds.changes().begin(); it != adds.changes().end(); ++it) - ExpectBrowserNodeMatching(&trans, it->id); - ExpectModelMatch(&trans); - - // We have to do the moves before the deletions, but FakeServerChange will - // put the deletion at the front of the changelist. - FakeServerChange ops(&trans); - ops.ModifyPosition(f6, other_bookmarks_id(), 0); - ops.ModifyPosition(u3, other_bookmarks_id(), f1); // Prev == f1 is OK here. - ops.ModifyPosition(f2, other_bookmarks_id(), u7); - ops.ModifyPosition(u7, f2, 0); - ops.ModifyPosition(u4, other_bookmarks_id(), f2); - ops.ModifyPosition(u5, f6, 0); - ops.Delete(f1); - - ops.ApplyPendingChanges(service_.get()); - - ExpectModelMatch(&trans); -} - -// Simulate a server change record containing a valid but non-canonical URL. -TEST_F(ProfileSyncServiceTest, ServerChangeWithNonCanonicalURL) { - LoadBookmarkModel(DELETE_EXISTING_STORAGE, SAVE_TO_STORAGE); - StartSyncService(); - - { - sync_api::WriteTransaction trans(backend()->GetUserShareHandle()); - - FakeServerChange adds(&trans); - std::string url("http://dev.chromium.org"); - EXPECT_NE(GURL(url).spec(), url); - int64 u1 = adds.AddURL(L"u1", UTF8ToWide(url), other_bookmarks_id(), 0); - - adds.ApplyPendingChanges(service_.get()); - - EXPECT_TRUE(model_->other_node()->GetChildCount() == 1); - ExpectModelMatch(&trans); - } - - // Now reboot the sync service, forcing a merge step. - StopSyncService(SAVE_TO_STORAGE); - LoadBookmarkModel(LOAD_FROM_STORAGE, SAVE_TO_STORAGE); - StartSyncService(); - - // There should still be just the one bookmark. - EXPECT_TRUE(model_->other_node()->GetChildCount() == 1); - ExpectModelMatch(); -} - -// Simulate a server change record containing an invalid URL (per GURL). -// TODO(ncarter): Disabled due to crashes. Fix bug 1677563. -TEST_F(ProfileSyncServiceTest, DISABLED_ServerChangeWithInvalidURL) { - LoadBookmarkModel(DELETE_EXISTING_STORAGE, SAVE_TO_STORAGE); - StartSyncService(); - - int child_count = 0; - { - sync_api::WriteTransaction trans(backend()->GetUserShareHandle()); - - FakeServerChange adds(&trans); - EXPECT_FALSE(GURL("x").is_valid()); - int64 u1 = adds.AddURL(L"u1", L"x", other_bookmarks_id(), 0); - - adds.ApplyPendingChanges(service_.get()); - - // We're lenient about what should happen -- the model could wind up with - // the node or without it; but things should be consistent, and we - // shouldn't crash. - child_count = model_->other_node()->GetChildCount(); - EXPECT_TRUE(child_count == 0 || child_count == 1); - ExpectModelMatch(&trans); - } - - // Now reboot the sync service, forcing a merge step. - StopSyncService(SAVE_TO_STORAGE); - LoadBookmarkModel(LOAD_FROM_STORAGE, SAVE_TO_STORAGE); - StartSyncService(); - - // Things ought not to have changed. - EXPECT_EQ(model_->other_node()->GetChildCount(), child_count); - ExpectModelMatch(); -} - -// Test strings that might pose a problem if the titles ever became used as -// file names in the sync backend. -TEST_F(ProfileSyncServiceTest, CornerCaseNames) { - // TODO(ncarter): Bug 1570238 explains the failure of this test. - LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE); - StartSyncService(); - - char16* names[] = { - // The empty string. - L"", - // Illegal Windows filenames. - L"CON", L"PRN", L"AUX", L"NUL", L"COM1", L"COM2", L"COM3", L"COM4", - L"COM5", L"COM6", L"COM7", L"COM8", L"COM9", L"LPT1", L"LPT2", L"LPT3", - L"LPT4", L"LPT5", L"LPT6", L"LPT7", L"LPT8", L"LPT9", - // Current/parent directory markers. - L".", L"..", L"...", - // Files created automatically by the Windows shell. - L"Thumbs.db", L".DS_Store", - // Names including Win32-illegal characters, and path separators. - L"foo/bar", L"foo\\bar", L"foo?bar", L"foo:bar", L"foo|bar", L"foo\"bar", - L"foo'bar", L"foo<bar", L"foo>bar", L"foo%bar", L"foo*bar", L"foo]bar", - L"foo[bar", - }; - // Create both folders and bookmarks using each name. - GURL url("http://www.doublemint.com"); - for (int i = 0; i < arraysize(names); ++i) { - model_->AddGroup(model_->other_node(), 0, names[i]); - model_->AddURL(model_->other_node(), 0, names[i], url); - } - - // Verify that the browser model matches the sync model. - EXPECT_EQ(model_->other_node()->GetChildCount(), 2*arraysize(names)); - ExpectModelMatch(); -} - -// Stress the internal representation of position by sparse numbers. We want -// to repeatedly bisect the range of available positions, to force the -// syncer code to renumber its ranges. Pick a number big enough so that it -// would exhaust 32bits of room between items a couple of times. -TEST_F(ProfileSyncServiceTest, RepeatedMiddleInsertion) { - LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE); - StartSyncService(); - - static const int kTimesToInsert = 256; - - // Create two book-end nodes to insert between. - model_->AddGroup(model_->other_node(), 0, L"Alpha"); - model_->AddGroup(model_->other_node(), 1, L"Omega"); - int count = 2; - - // Test insertion in first half of range by repeatedly inserting in second - // position. - for (int i = 0; i < kTimesToInsert; ++i) { - string16 title = string16(L"Pre-insertion ") + IntToWString(i); - model_->AddGroup(model_->other_node(), 1, title); - count++; - } - - // Test insertion in second half of range by repeatedly inserting in - // second-to-last position. - for (int i = 0; i < kTimesToInsert; ++i) { - string16 title = string16(L"Post-insertion ") + IntToWString(i); - model_->AddGroup(model_->other_node(), count - 1, title); - count++; - } - - // Verify that the browser model matches the sync model. - EXPECT_EQ(model_->other_node()->GetChildCount(), count); - ExpectModelMatch(); -} - -// Introduce a consistency violation into the model, and see that it -// puts itself into a lame, error state. -TEST_F(ProfileSyncServiceTest, UnrecoverableErrorSuspendsService) { - LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE); - StartSyncService(); - - // Synchronization should be up and running at this point. - EXPECT_TRUE(service_->ShouldPushChanges()); - - // Add a node which will be the target of the consistency violation. - const BookmarkNode* node = - model_->AddGroup(model_->other_node(), 0, L"node"); - ExpectSyncerNodeMatching(node); - - // Now destroy the syncer node as if we were the ProfileSyncService without - // updating the ProfileSyncService state. This should introduce - // inconsistency between the two models. - { - sync_api::WriteTransaction trans(service_->backend_->GetUserShareHandle()); - sync_api::WriteNode sync_node(&trans); - EXPECT_TRUE(associator()->InitSyncNodeFromBookmarkId(node->id(), - &sync_node)); - sync_node.Remove(); - } - // The models don't match at this point, but the ProfileSyncService - // doesn't know it yet. - ExpectSyncerNodeKnown(node); - EXPECT_TRUE(service_->ShouldPushChanges()); - - // Add a child to the inconsistent node. This should cause detection of the - // problem. - const BookmarkNode* nested = model_->AddGroup(node, 0, L"nested"); - EXPECT_FALSE(service_->ShouldPushChanges()); - ExpectSyncerNodeUnknown(nested); - - // Try to add a node under a totally different parent. This should also - // fail -- the ProfileSyncService should stop processing changes after - // encountering a consistency violation. - const BookmarkNode* unrelated = model_->AddGroup( - model_->GetBookmarkBarNode(), 0, L"unrelated"); - EXPECT_FALSE(service_->ShouldPushChanges()); - ExpectSyncerNodeUnknown(unrelated); - - // TODO(ncarter): We ought to test the ProfileSyncService state machine - // directly here once that's formalized and exposed. -} - -struct TestData { - const char16* title; - const char16* url; -}; - -// TODO(ncarter): Integrate the existing TestNode/PopulateNodeFromString code -// in the bookmark model unittest, to make it simpler to set up test data -// here (and reduce the amount of duplication among tests), and to reduce the -// duplication. -class ProfileSyncServiceTestWithData : public ProfileSyncServiceTest { - protected: - // Populates or compares children of the given bookmark node from/with the - // given test data array with the given size. - void PopulateFromTestData(const BookmarkNode* node, - const TestData* data, - int size); - void CompareWithTestData(const BookmarkNode* node, - const TestData* data, - int size); - - void ExpectBookmarkModelMatchesTestData(); - void WriteTestDataToBookmarkModel(); -}; - -namespace { - -// Constants for bookmark model that looks like: -// |-- Bookmark bar -// | |-- u2, http://www.u2.com/ -// | |-- f1 -// | | |-- f1u4, http://www.f1u4.com/ -// | | |-- f1u2, http://www.f1u2.com/ -// | | |-- f1u3, http://www.f1u3.com/ -// | | +-- f1u1, http://www.f1u1.com/ -// | |-- u1, http://www.u1.com/ -// | +-- f2 -// | |-- f2u2, http://www.f2u2.com/ -// | |-- f2u4, http://www.f2u4.com/ -// | |-- f2u3, http://www.f2u3.com/ -// | +-- f2u1, http://www.f2u1.com/ -// +-- Other bookmarks -// |-- f3 -// | |-- f3u4, http://www.f3u4.com/ -// | |-- f3u2, http://www.f3u2.com/ -// | |-- f3u3, http://www.f3u3.com/ -// | +-- f3u1, http://www.f3u1.com/ -// |-- u4, http://www.u4.com/ -// |-- u3, http://www.u3.com/ -// --- f4 -// | |-- f4u1, http://www.f4u1.com/ -// | |-- f4u2, http://www.f4u2.com/ -// | |-- f4u3, http://www.f4u3.com/ -// | +-- f4u4, http://www.f4u4.com/ -// |-- dup -// | +-- dupu1, http://www.dupu1.com/ -// +-- dup -// +-- dupu2, http://www.dupu1.com/ -// -static TestData kBookmarkBarChildren[] = { - { L"u2", L"http://www.u2.com/" }, - { L"f1", NULL }, - { L"u1", L"http://www.u1.com/" }, - { L"f2", NULL }, -}; -static TestData kF1Children[] = { - { L"f1u4", L"http://www.f1u4.com/" }, - { L"f1u2", L"http://www.f1u2.com/" }, - { L"f1u3", L"http://www.f1u3.com/" }, - { L"f1u1", L"http://www.f1u1.com/" }, -}; -static TestData kF2Children[] = { - { L"f2u2", L"http://www.f2u2.com/" }, - { L"f2u4", L"http://www.f2u4.com/" }, - { L"f2u3", L"http://www.f2u3.com/" }, - { L"f2u1", L"http://www.f2u1.com/" }, -}; - -static TestData kOtherBookmarksChildren[] = { - { L"f3", NULL }, - { L"u4", L"http://www.u4.com/" }, - { L"u3", L"http://www.u3.com/" }, - { L"f4", NULL }, - { L"dup", NULL }, - { L"dup", NULL }, -}; -static TestData kF3Children[] = { - { L"f3u4", L"http://www.f3u4.com/" }, - { L"f3u2", L"http://www.f3u2.com/" }, - { L"f3u3", L"http://www.f3u3.com/" }, - { L"f3u1", L"http://www.f3u1.com/" }, -}; -static TestData kF4Children[] = { - { L"f4u1", L"http://www.f4u1.com/" }, - { L"f4u2", L"http://www.f4u2.com/" }, - { L"f4u3", L"http://www.f4u3.com/" }, - { L"f4u4", L"http://www.f4u4.com/" }, -}; -static TestData kDup1Children[] = { - { L"dupu1", L"http://www.dupu1.com/" }, -}; -static TestData kDup2Children[] = { - { L"dupu2", L"http://www.dupu2.com/" }, -}; - -} // anonymous namespace. - -void ProfileSyncServiceTestWithData::PopulateFromTestData( - const BookmarkNode* node, const TestData* data, int size) { - DCHECK(node); - DCHECK(data); - DCHECK(node->is_folder()); - for (int i = 0; i < size; ++i) { - const TestData& item = data[i]; - if (item.url) { - model_->AddURL(node, i, item.title, GURL(item.url)); - } else { - model_->AddGroup(node, i, item.title); - } - } -} - -void ProfileSyncServiceTestWithData::CompareWithTestData( - const BookmarkNode* node, const TestData* data, int size) { - DCHECK(node); - DCHECK(data); - DCHECK(node->is_folder()); - for (int i = 0; i < size; ++i) { - const BookmarkNode* child_node = node->GetChild(i); - const TestData& item = data[i]; - EXPECT_TRUE(child_node->GetTitle() == item.title); - if (item.url) { - EXPECT_FALSE(child_node->is_folder()); - EXPECT_TRUE(child_node->is_url()); - EXPECT_TRUE(child_node->GetURL() == GURL(item.url)); - } else { - EXPECT_TRUE(child_node->is_folder()); - EXPECT_FALSE(child_node->is_url()); - } - } -} - -// TODO(munjal): We should implement some way of generating random data and can -// use the same seed to generate the same sequence. -void ProfileSyncServiceTestWithData::WriteTestDataToBookmarkModel() { - const BookmarkNode* bookmarks_bar_node = model_->GetBookmarkBarNode(); - PopulateFromTestData(bookmarks_bar_node, - kBookmarkBarChildren, - arraysize(kBookmarkBarChildren)); - - ASSERT_GE(bookmarks_bar_node->GetChildCount(), 4); - const BookmarkNode* f1_node = bookmarks_bar_node->GetChild(1); - PopulateFromTestData(f1_node, kF1Children, arraysize(kF1Children)); - const BookmarkNode* f2_node = bookmarks_bar_node->GetChild(3); - PopulateFromTestData(f2_node, kF2Children, arraysize(kF2Children)); - - const BookmarkNode* other_bookmarks_node = model_->other_node(); - PopulateFromTestData(other_bookmarks_node, - kOtherBookmarksChildren, - arraysize(kOtherBookmarksChildren)); - - ASSERT_GE(other_bookmarks_node->GetChildCount(), 6); - const BookmarkNode* f3_node = other_bookmarks_node->GetChild(0); - PopulateFromTestData(f3_node, kF3Children, arraysize(kF3Children)); - const BookmarkNode* f4_node = other_bookmarks_node->GetChild(3); - PopulateFromTestData(f4_node, kF4Children, arraysize(kF4Children)); - const BookmarkNode* dup_node = other_bookmarks_node->GetChild(4); - PopulateFromTestData(dup_node, kDup1Children, arraysize(kDup1Children)); - dup_node = other_bookmarks_node->GetChild(5); - PopulateFromTestData(dup_node, kDup2Children, arraysize(kDup2Children)); - - ExpectBookmarkModelMatchesTestData(); -} - -void ProfileSyncServiceTestWithData::ExpectBookmarkModelMatchesTestData() { - const BookmarkNode* bookmark_bar_node = model_->GetBookmarkBarNode(); - CompareWithTestData(bookmark_bar_node, - kBookmarkBarChildren, - arraysize(kBookmarkBarChildren)); - - ASSERT_GE(bookmark_bar_node->GetChildCount(), 4); - const BookmarkNode* f1_node = bookmark_bar_node->GetChild(1); - CompareWithTestData(f1_node, kF1Children, arraysize(kF1Children)); - const BookmarkNode* f2_node = bookmark_bar_node->GetChild(3); - CompareWithTestData(f2_node, kF2Children, arraysize(kF2Children)); - - const BookmarkNode* other_bookmarks_node = model_->other_node(); - CompareWithTestData(other_bookmarks_node, - kOtherBookmarksChildren, - arraysize(kOtherBookmarksChildren)); - - ASSERT_GE(other_bookmarks_node->GetChildCount(), 6); - const BookmarkNode* f3_node = other_bookmarks_node->GetChild(0); - CompareWithTestData(f3_node, kF3Children, arraysize(kF3Children)); - const BookmarkNode* f4_node = other_bookmarks_node->GetChild(3); - CompareWithTestData(f4_node, kF4Children, arraysize(kF4Children)); - const BookmarkNode* dup_node = other_bookmarks_node->GetChild(4); - CompareWithTestData(dup_node, kDup1Children, arraysize(kDup1Children)); - dup_node = other_bookmarks_node->GetChild(5); - CompareWithTestData(dup_node, kDup2Children, arraysize(kDup2Children)); -} - -// Tests persistence of the profile sync service by destroying the -// profile sync service and then reloading it from disk. -TEST_F(ProfileSyncServiceTestWithData, Persistence) { - LoadBookmarkModel(DELETE_EXISTING_STORAGE, SAVE_TO_STORAGE); - StartSyncService(); - - WriteTestDataToBookmarkModel(); - - ExpectModelMatch(); - - // Force both models to discard their data and reload from disk. This - // simulates what would happen if the browser were to shutdown normally, - // and then relaunch. - StopSyncService(SAVE_TO_STORAGE); - LoadBookmarkModel(LOAD_FROM_STORAGE, SAVE_TO_STORAGE); - StartSyncService(); - - ExpectBookmarkModelMatchesTestData(); - - // With the BookmarkModel contents verified, ExpectModelMatch will - // verify the contents of the sync model. - ExpectModelMatch(); -} - -// Tests the merge case when the BookmarkModel is non-empty but the -// sync model is empty. This corresponds to uploading browser -// bookmarks to an initially empty, new account. -TEST_F(ProfileSyncServiceTestWithData, MergeWithEmptySyncModel) { - // Don't start the sync service until we've populated the bookmark model. - LoadBookmarkModel(DELETE_EXISTING_STORAGE, SAVE_TO_STORAGE); - - WriteTestDataToBookmarkModel(); - - // Restart the profile sync service. This should trigger a merge step - // during initialization -- we expect the browser bookmarks to be written - // to the sync service during this call. - StartSyncService(); - - // Verify that the bookmark model hasn't changed, and that the sync model - // matches it exactly. - ExpectBookmarkModelMatchesTestData(); - ExpectModelMatch(); -} - -// Tests the merge case when the BookmarkModel is empty but the sync model is -// non-empty. This corresponds (somewhat) to a clean install of the browser, -// with no bookmarks, connecting to a sync account that has some bookmarks. -TEST_F(ProfileSyncServiceTestWithData, MergeWithEmptyBookmarkModel) { - LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE); - StartSyncService(); - - WriteTestDataToBookmarkModel(); - - ExpectModelMatch(); - - // Force the sync service to shut down and write itself to disk. - StopSyncService(SAVE_TO_STORAGE); - - // Blow away the bookmark model -- it should be empty afterwards. - LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE); - EXPECT_EQ(model_->GetBookmarkBarNode()->GetChildCount(), 0); - EXPECT_EQ(model_->other_node()->GetChildCount(), 0); - - // Now restart the sync service. Starting it should populate the bookmark - // model -- test for consistency. - StartSyncService(); - ExpectBookmarkModelMatchesTestData(); - ExpectModelMatch(); -} - -// Tests the merge cases when both the models are expected to be identical -// after the merge. -TEST_F(ProfileSyncServiceTestWithData, MergeExpectedIdenticalModels) { - LoadBookmarkModel(DELETE_EXISTING_STORAGE, SAVE_TO_STORAGE); - StartSyncService(); - WriteTestDataToBookmarkModel(); - ExpectModelMatch(); - StopSyncService(SAVE_TO_STORAGE); - - // At this point both the bookmark model and the server should have the - // exact same data and it should match the test data. - LoadBookmarkModel(LOAD_FROM_STORAGE, DONT_SAVE_TO_STORAGE); - StartSyncService(); - ExpectBookmarkModelMatchesTestData(); - ExpectModelMatch(); - StopSyncService(SAVE_TO_STORAGE); - - // Now reorder some bookmarks in the bookmark model and then merge. Make - // sure we get the order of the server after merge. - LoadBookmarkModel(LOAD_FROM_STORAGE, DONT_SAVE_TO_STORAGE); - ExpectBookmarkModelMatchesTestData(); - const BookmarkNode* bookmark_bar = model_->GetBookmarkBarNode(); - ASSERT_TRUE(bookmark_bar); - ASSERT_GT(bookmark_bar->GetChildCount(), 1); - model_->Move(bookmark_bar->GetChild(0), bookmark_bar, 1); - StartSyncService(); - ExpectModelMatch(); - ExpectBookmarkModelMatchesTestData(); -} - -// Tests the merge cases when both the models are expected to be identical -// after the merge. -TEST_F(ProfileSyncServiceTestWithData, MergeModelsWithSomeExtras) { - LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE); - WriteTestDataToBookmarkModel(); - ExpectBookmarkModelMatchesTestData(); - - // Remove some nodes and reorder some nodes. - const BookmarkNode* bookmark_bar_node = model_->GetBookmarkBarNode(); - int remove_index = 2; - ASSERT_GT(bookmark_bar_node->GetChildCount(), remove_index); - const BookmarkNode* child_node = bookmark_bar_node->GetChild(remove_index); - ASSERT_TRUE(child_node); - ASSERT_TRUE(child_node->is_url()); - model_->Remove(bookmark_bar_node, remove_index); - ASSERT_GT(bookmark_bar_node->GetChildCount(), remove_index); - child_node = bookmark_bar_node->GetChild(remove_index); - ASSERT_TRUE(child_node); - ASSERT_TRUE(child_node->is_folder()); - model_->Remove(bookmark_bar_node, remove_index); - - const BookmarkNode* other_node = model_->other_node(); - ASSERT_GE(other_node->GetChildCount(), 1); - const BookmarkNode* f3_node = other_node->GetChild(0); - ASSERT_TRUE(f3_node); - ASSERT_TRUE(f3_node->is_folder()); - remove_index = 2; - ASSERT_GT(f3_node->GetChildCount(), remove_index); - model_->Remove(f3_node, remove_index); - ASSERT_GT(f3_node->GetChildCount(), remove_index); - model_->Remove(f3_node, remove_index); - - StartSyncService(); - ExpectModelMatch(); - StopSyncService(SAVE_TO_STORAGE); - - LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE); - WriteTestDataToBookmarkModel(); - ExpectBookmarkModelMatchesTestData(); - - // Remove some nodes and reorder some nodes. - bookmark_bar_node = model_->GetBookmarkBarNode(); - remove_index = 0; - ASSERT_GT(bookmark_bar_node->GetChildCount(), remove_index); - child_node = bookmark_bar_node->GetChild(remove_index); - ASSERT_TRUE(child_node); - ASSERT_TRUE(child_node->is_url()); - model_->Remove(bookmark_bar_node, remove_index); - ASSERT_GT(bookmark_bar_node->GetChildCount(), remove_index); - child_node = bookmark_bar_node->GetChild(remove_index); - ASSERT_TRUE(child_node); - ASSERT_TRUE(child_node->is_folder()); - model_->Remove(bookmark_bar_node, remove_index); - - ASSERT_GE(bookmark_bar_node->GetChildCount(), 2); - model_->Move(bookmark_bar_node->GetChild(0), bookmark_bar_node, 1); - - other_node = model_->other_node(); - ASSERT_GE(other_node->GetChildCount(), 1); - f3_node = other_node->GetChild(0); - ASSERT_TRUE(f3_node); - ASSERT_TRUE(f3_node->is_folder()); - remove_index = 0; - ASSERT_GT(f3_node->GetChildCount(), remove_index); - model_->Remove(f3_node, remove_index); - ASSERT_GT(f3_node->GetChildCount(), remove_index); - model_->Remove(f3_node, remove_index); - - ASSERT_GE(other_node->GetChildCount(), 4); - model_->Move(other_node->GetChild(0), other_node, 1); - model_->Move(other_node->GetChild(2), other_node, 3); - - StartSyncService(); - ExpectModelMatch(); - - // AFter the merge, the model should match the test data. - ExpectBookmarkModelMatchesTestData(); -} - -// Tests that when persisted model assocations are used, things work fine. -TEST_F(ProfileSyncServiceTestWithData, ModelAssociationPersistence) { - LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE); - WriteTestDataToBookmarkModel(); - StartSyncService(); - ExpectModelMatch(); - // Force the sync service to shut down and write itself to disk. - StopSyncService(SAVE_TO_STORAGE); - // Now restart the sync service. This time it should use the persistent - // assocations. - StartSyncService(); - ExpectModelMatch(); -} - -TEST_F(ProfileSyncServiceTestWithData, SortChildren) { - LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE); - StartSyncService(); - - // Write test data to bookmark model and verify that the models match. - WriteTestDataToBookmarkModel(); - const BookmarkNode* folder_added = model_->other_node()->GetChild(0); - ASSERT_TRUE(folder_added); - ASSERT_TRUE(folder_added->is_folder()); - - ExpectModelMatch(); - - // Sort the other-bookmarks children and expect that hte models match. - model_->SortChildren(folder_added); - ExpectModelMatch(); -} - -// See what happens if we enable sync but then delete the "Sync Data" -// folder. -TEST_F(ProfileSyncServiceTestWithData, RecoverAfterDeletingSyncDataDirectory) { - LoadBookmarkModel(DELETE_EXISTING_STORAGE, SAVE_TO_STORAGE); - StartSyncService(); - - WriteTestDataToBookmarkModel(); - - // While the service is running. - FilePath sync_data_directory = backend()->sync_data_folder_path(); - - // Simulate a normal shutdown for the sync service (don't disable it for - // the user, which would reset the preferences and delete the sync data - // directory). - StopSyncService(SAVE_TO_STORAGE); - - // Now pretend that the user has deleted this directory from the disk. - file_util::Delete(sync_data_directory, true); - - // Restart the sync service. - StartSyncService(); - - // Make sure we're back in sync. In real life, the user would need - // to reauthenticate before this happens, but in the test, authentication - // is sidestepped. - ExpectBookmarkModelMatchesTestData(); - ExpectModelMatch(); -} - -#endif // CHROME_PERSONALIZATION
\ No newline at end of file diff --git a/chrome/browser/sync/resources/about_sync.html b/chrome/browser/sync/resources/about_sync.html deleted file mode 100644 index 0fbd6df..0000000 --- a/chrome/browser/sync/resources/about_sync.html +++ /dev/null @@ -1,165 +0,0 @@ -<html> -</html> -<html id="t"> -<head> -<title>About Sync</title> - -<style type="text/css"> -body { - font-size: 84%; - font-family: Arial, Helvetica, sans-serif; - padding: 0.75em; - margin: 0; - min-width: 45em; -} - -h1 { - font-size: 110%; - font-weight: bold; - color: #4a8ee6; - letter-spacing: -1px; - padding: 0; - margin: 0; -} -h2 { - font-size: 110%; - letter-spacing: -1px; - font-weight: normal; - color: #4a8ee6; - padding: 0; - margin: 0; - padding: 0.5em 1em; - color: #3a75bd; - margin-left: -38px; - padding-left: 38px; - - border-top: 1px solid #3a75bd; - padding-top: 0.5em; - -} -h2:first-child { - border-top: 0; - padding-top: 0; -} - -div#header { - padding: 0.75em 1em; - padding-top: 0.6em; - padding-left: 0; - margin-bottom: 0.75em; - position: relative; - overflow: hidden; - background: #5296de; - -webkit-background-size: 100%; - border: 1px solid #3a75bd; - -webkit-border-radius: 6px; - color: white; - text-shadow: 0 0 2px black; -} -div#header h1 { - padding-left: 37px; - margin: 0; - display: inline; - background: url('gear.png') 12px 60% no-repeat; - color: white; -} -div#header p { - font-size: 84%; - font-style: italic; - padding: 0; - margin: 0; - color: white; - padding-left: 0.4em; - display: inline; -} - -table.list { - line-height: 200%; - border-collapse: collapse; - font-size: 84%; - table-layout: fixed; -} -table.list:not([class*='filtered']) tr:nth-child(odd) td { - background: #eff3ff; -} - -table.list td { - padding: 0 0.5em; - vertical-align: top; - line-height: 1.4em; - padding-top: 0.35em; -} -table.list tr td:nth-last-child(1), -table.list tr th:nth-last-child(1) { - padding-right: 1em; -} -table.list:not([class*='filtered']) .tab .name { - padding-left: 1.5em; -} - -table.list .name { -} - -table.list .name div { - height: 1.6em; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} - -table.list .number { - width: 7em; - text-align: right; -} - -table.list#details tr:not([class*='firstRow']) > *:nth-child(1), -table.list#details tr:not([class*='firstRow']) > *:nth-child(4), -table.list#details tr.firstRow th:nth-child(1), -table.list#details tr.firstRow th:nth-child(2) { - border-right: 1px solid #b5c6de; -} -table.list#details .name { - padding-left: 25px; - background-position: 5px center; - background-repeat: no-repeat; -} -</style> -</head> -<body> - <div id='header'> - <h1>About Sync</h1> - <p> Sync engine diagnostic data</p> - </div> - <div id='content'> - <h2> Summary </h2> - <strong jscontent="summary"></strong> - <br /><br /><br /> - <h2> Details </h2> - <table class='list' id='details'> - <tr> - <td class='name'> Authenticated </td> - <td class='number'> - <div jscontent="authenticated"> </div> - <div jsdisplay="!authenticated" - style="color:red" - jscontent="auth_problem"></div> - </td> - </tr> - </tr> - <tr> - <td class='name'>Last Synced</td> - <td class='number' jscontent="time_since_sync"> </td> - </tr> - <tr jsselect="details"> - <td class='name'> - <div jscontent="stat_name"></div> - </td> - <td class='number'> - <div jscontent="stat_value"></div> - </td> - </tr> - </table> - </div> -</body> -</html> - diff --git a/chrome/browser/sync/resources/close.png b/chrome/browser/sync/resources/close.png Binary files differdeleted file mode 100644 index 84ff892..0000000 --- a/chrome/browser/sync/resources/close.png +++ /dev/null diff --git a/chrome/browser/sync/resources/gaia_login.html b/chrome/browser/sync/resources/gaia_login.html deleted file mode 100644 index 17cc102..0000000 --- a/chrome/browser/sync/resources/gaia_login.html +++ /dev/null @@ -1,331 +0,0 @@ -<html> -<style type="text/css"><!-- - body,td,div,p,a,font,span {font-family: arial,sans-serif;} - body { bgcolor:"#ffffff" } - A:link {color:#0000cc; } - A:visited { color:#551a8b; } - A:active { color:#ff0000; } - .form-noindent {background-color: #ffffff; border: #C3D9FF 1px solid} ---></style> - <head> - <style type="text/css"><!-- - .body { margin-left: 3em; - margin-right: 5em; - font-family: arial,sans-serif; } - div.errorbox-good {} - div.errorbox-bad {} - div.errormsg { color: red; font-size: smaller; - font-family: arial,sans-serif;} - font.errormsg { color: red; font-size: smaller; - font-family: arial,sans-serif;} - hr { - border: 0; - background-color:#DDDDDD; - height: 1px; - width: 100%; - text-align: left; - margin: 5px; - } - --></style> - </head> - <body dir="ltr" bgcolor="#ffffff" vlink="#666666" - style="margin-bottom: 0" onload="initForm();"> - <table width="100%" align="center" cellpadding="1" cellspacing="1"> - <tr> - <td valign="top"> <!-- LOGIN BOX --> - <script> - function gaia_setFocus() { - var f = null; - if (document.getElementById) { - f = document.getElementById("gaia_loginform"); - } else if (window.gaia_loginform) { - f = window.gaia_loginform; - } - if (f) { - if (f.Email && (f.Email.value == null || f.Email.value == "")) { - f.Email.focus(); - } else if (f.Passwd) { - f.Passwd.focus(); - } - } - } - - function advanceThrobber() { - var throbber = document.getElementById('throb'); - throbber.style.backgroundPositionX = - ((parseInt(throbber.style.backgroundPositionX) - 16) % 576) + 'px'; - } - - function showGaiaLogin(args) { - var throbber = document.getElementById('throbber_container'); - throbber.style.display = "none"; - var f = document.getElementById("gaia_loginform"); - if (f) { - f.Email.value = args.user; - } - resetErrorVisibility(); - var t = document.getElementById("errormsg_1_Password"); - if (t) { - t.innerHTML = "Username and password do not match. [<a href=\"http://www.google.com/support/accounts/bin/answer.py?ctx=ch&answer=27444\">?</a>]"; - } - if (1 == args.error) { - setElementDisplay("errormsg_1_Password", 'table-row'); - setBlurbError(); - } - if (3 == args.error) { - setElementDisplay("errormsg_0_Connection", 'table-row'); - setBlurbError(); - } - document.getElementById("signIn").disabled = false; - gaia_setFocus(); - } - - function CloseDialog() { - chrome.send("DialogClose", [""]); - } - - function showGaiaSuccessAndClose() { - document.getElementById("signIn").value = "Success!"; - setTimeout(CloseDialog, 1600); - } - - function showGaiaSuccessAndSettingUp() { - document.getElementById("signIn").value = "Setting up..."; - } - - function initForm() { - setInterval(advanceThrobber, 30); - var args = JSON.parse(chrome.dialogArguments); - showGaiaLogin(args); - } - - function sendCredentialsAndClose() { - if (!setErrorVisibility()) - return false; - - var throbber = document.getElementById('throbber_container'); - throbber.style.display = "inline"; - var f = document.getElementById("gaia_loginform"); - var result = JSON.stringify({"user" : f.Email.value, - "pass" : f.Passwd.value}); - document.getElementById("signIn").disabled = true; - chrome.send("SubmitAuth", [result]); - } - - function setElementDisplay(id, display) { - var d = document.getElementById(id); - if (d) - d.style.display = display; - } - - function setBlurbError() { - var blurb = document.getElementById("top_blurb"); - blurb.innerHTML = - '<font size="-1">Setting up Bookmarks Sync<br/><br/><b>Error signing in.</b></font>'; - } - - function resetErrorVisibility() { - setElementDisplay("errormsg_0_Email", 'none'); - setElementDisplay("errormsg_0_Password", 'none'); - setElementDisplay("errormsg_1_Password", 'none'); - setElementDisplay("errormsg_0_Connection", 'none'); - } - - function setErrorVisibility() { - resetErrorVisibility(); - var f = document.getElementById("gaia_loginform"); - if (null == f.Email.value || "" == f.Email.value) { - setElementDisplay("errormsg_0_Email", 'table-row'); - setBlurbError(); - return false; - } - if (null == f.Passwd.value || "" == f.Passwd.value) { - setElementDisplay("errormsg_0_Password", 'table-row'); - setBlurbError(); - return false; - } - return true; - } - </script> -<style type="text/css"><!-- - div.errormsg { color: red; font-size: smaller; font-family:arial,sans-serif; } - font.errormsg { color: red; font-size: smaller; font-family:arial,sans-serif;} ---></style> -<style type="text/css"><!-- -.gaia.le.lbl { font-family: Arial, Helvetica, sans-serif; font-size: smaller; } -.gaia.le.fpwd { font-family: Arial, Helvetica, sans-serif; font-size: 70%; } -.gaia.le.chusr { font-family: Arial, Helvetica, sans-serif; font-size: 70%; } -.gaia.le.val { font-family: Arial, Helvetica, sans-serif; font-size: smaller; } -.gaia.le.button { font-family: Arial, Helvetica, sans-serif; font-size: smaller; } -.gaia.le.rem { font-family: Arial, Helvetica, sans-serif; font-size: smaller; } -.gaia.captchahtml.desc { font-family: arial, sans-serif; font-size: smaller; } -.gaia.captchahtml.cmt { font-family: arial, sans-serif; font-size: smaller; - font-style: italic; } ---></style> -<p id="top_blurb"> <font size="-1"> -Google Chrome can sync your bookmarks with your Google account – -bookmarks you create on this computer will be made instantly visible on all the -computers synced to the same account.</font></p> -<form id="gaia_loginform" onsubmit="sendCredentialsAndClose(); return false;"> -<div id="gaia_loginbox"> -<table class="form-noindent" cellspacing="3" cellpadding="5" width="100%" - border="0"> - <tr> - <td valign="top" style="text-align:center" nowrap="nowrap" - bgcolor="#e8eefa"> - <div class="loginBox"> - <table id="gaia_table" align="center" border="0" cellpadding="1" - cellspacing="0"> - <tr> - <td colspan="2" align="center"> - <font size="-1"> Sign in with your </font> - <table> - <tr> - <td valign="top"> - <img src="google_transparent.png" alt="Google"> - </img> - </td> - <td valign="middle"> - <font size="+0"><b>Account</b> </font> - </td> - </tr> - </table> - </td> - </tr> - <script type="text/javascript"><!-- - function onPreCreateAccount() { - return true; - } - function onPreLogin() { - if (window["onlogin"] != null) { - return onlogin(); - } else { - return true; - } - } - --></script> - <tr> - <td colspan="2" align="center"> </td> - </tr> - <tr> - <td nowrap="nowrap"> - <div align="right"> - <span class="gaia le lbl"> - Email: - </span> - </div> - </td> - <td> - <input type="text" name="Email" id="Email" size="18" - value="" class='gaia le val' /> - </td> - </tr> - <tr> - <td></td> - <td align="left"> - <div class="errormsg" id="errormsg_0_Email"> - Required field cannot be left blank - </div> - </td> - </tr> - <tr> - <td></td> - <td align="left"> </td> - </tr> - <tr> - <td align="right"> - <span class="gaia le lbl"> - Password: - </span> - </td> - <td> - <input type="password" name="Passwd" id="Passwd" size="18" - class="gaia le val"/> - </td> - </tr> - <tr> - <td></td> - <td align="left"> - <div class="errormsg" id="errormsg_0_Password"> - Required field cannot be left blank - </div> - </td> - </tr> - <tr> - <td> - </td> - <td align="left"> - <div class="errormsg" id="errormsg_1_Password"> - </div> - </td> - </tr> - <tr> - <td> - </td> - <td align="left"> - <div class="errormsg" id="errormsg_0_Connection"> - Could not connect to the server - </div> - </td> - </tr> - <tr> - <td> - </td> - <td align="left"> - </td> - </tr> - <tr> - <td> - </td> - <td align="left"> - <table> - <tr> - <td> - <div id="throbber_container" style="display:none"> - <div id="throb" style="background-image:url(throbber.png); - width:16px; height:16px; background-position:0px;"> - </div> - </div> - </td> - <td> - <input id="signIn" type="button" class="gaia le button" - name="signIn" value="Sign in" - onclick="sendCredentialsAndClose();" /> - </td> - </tr> - </table> - </td> - </tr> - <tr id="ga-fprow"> - <td colspan="2" height="16.0" class="gaia le fpwd" - align="center" valign="bottom"> - <a href="http://www.google.com/support/accounts/bin/answer.py?answer=48598&hl=en&fpUrl=https%3A%2F%2Fwww.google.com%2Faccounts%2FForgotPasswd%3FfpOnly%3D1%26service%3Dchromiumsync" - target=_blank> - I cannot access my account - </a> - </td> - </tr> - <tr> - <td colspan="2" height="16.0" class="gaia le fpwd" - align="center" valign="bottom"> - <a href="javascript:var popup=window.open('https%3A%5Cx2F%5Cx2Fwww.google.com%5Cx2Faccounts%5Cx2FNewAccount%3Fservice%3Dchromiumsync', 'NewAccount', 'height=870,width=870,resizable=yes,scrollbars=yes');"> - Create a Google account - </a> - </td> - </tr> - </table> - </div> - </td> - </tr> -</table> -</div> -</form> -</td> -</tr> - </table> - <div align="right"> - <input type="button" name="cancel" value="Cancel" onclick="CloseDialog();"/> - </div> - </table> -</body> -</html> diff --git a/chrome/browser/sync/resources/gear.png b/chrome/browser/sync/resources/gear.png Binary files differdeleted file mode 100644 index 3dce105..0000000 --- a/chrome/browser/sync/resources/gear.png +++ /dev/null diff --git a/chrome/browser/sync/resources/google_transparent.png b/chrome/browser/sync/resources/google_transparent.png Binary files differdeleted file mode 100644 index 73edad4..0000000 --- a/chrome/browser/sync/resources/google_transparent.png +++ /dev/null diff --git a/chrome/browser/sync/resources/merge_and_sync.html b/chrome/browser/sync/resources/merge_and_sync.html deleted file mode 100644 index 58a769b..0000000 --- a/chrome/browser/sync/resources/merge_and_sync.html +++ /dev/null @@ -1,66 +0,0 @@ -<HTML> -<HEAD> -<TITLE></TITLE> -<style type="text/css"> - body,td,div,p,a,font,span {font-family: arial,sans-serif;} - body { bgcolor:"#ffffff" } -.gaia.le.button { font-family: Arial, Helvetica, sans-serif; font-size: smaller; } -</style> -<script> - function advanceThrobber() { - var throbber = document.getElementById('throb'); - throbber.style.backgroundPositionX = - ((parseInt(throbber.style.backgroundPositionX) - 16) % 576) + 'px'; - } - - function acceptMergeAndSync() { - var throbber = document.getElementById('throbber_container'); - throbber.style.display = "inline"; - document.getElementById("acceptMerge").disabled = true; - chrome.send("SubmitMergeAndSync", [""]); - } - - function Close() { - chrome.send("DialogClose", [""]); - } - - function showMergeAndSyncDone() { - var throbber = document.getElementById('throbber_container'); - throbber.style.display = "none"; - document.getElementById("header").innerHTML = - "<font size='-1'><b>All done!</b></font>"; - document.getElementById("close").value = "Close"; - setTimeout(Close, 1600); - } -</script> -</HEAD> -<BODY onload="setInterval(advanceThrobber, 30);"> -<p id="header"><font size="-1"><b>Your bookmarks will be merged.</b></font></p><br /> -<img src="merge_and_sync.png" alt="Merge and sync" /> -<br /> -<p><font size="-1"> -Your existing online bookmarks will be merged with the -bookmarks on this machine. You can use the Bookmark Manager to organize -your bookmarks after the merge.</font></p> -<br /> -<table align="right"> - <tr> - <td> - <div id="throbber_container" style="display:none"> - <div id="throb" style="background-image:url(throbber.png); - width:16px; height:16px; background-position:0px;"> - </div> - </div> - </td> - <td> - <input id="acceptMerge" type="button" class="gaia le button" name="accept" - value="Merge and sync" - onclick="acceptMergeAndSync();" /> - </td> - <td> - <input id="close" type="button" value="Abort" onclick="Close();"/> - </td> - </tr> -</table> -</BODY> -</HTML> diff --git a/chrome/browser/sync/resources/merge_and_sync.png b/chrome/browser/sync/resources/merge_and_sync.png Binary files differdeleted file mode 100644 index a506a34..0000000 --- a/chrome/browser/sync/resources/merge_and_sync.png +++ /dev/null diff --git a/chrome/browser/sync/resources/new_tab_personalization.html b/chrome/browser/sync/resources/new_tab_personalization.html deleted file mode 100644 index 73cf346..0000000 --- a/chrome/browser/sync/resources/new_tab_personalization.html +++ /dev/null @@ -1,117 +0,0 @@ -<html> -<head> -<style type="text/css"> -body { - font-family:arial; - background-color:white; - font-size:80%; - margin:0px; -} -.section-title { - color:#000; - line-height:19pt; - font-size:95%; - font-weight:bold; - margin-bottom:4px; - margin-left: 0px; -} -a { - color:#0000cc; - white-space: nowrap; -} -.sidebar { - width: 207px; - padding:3px 10px 3px 9px; - -webkit-border-radius:5px 5px; - margin-bottom:10px; -} -</style> -<script> -function resizeFrame(newsize) { - chrome.send("ResizeP13N", [newsize.toString()]); -} -</script> -</head> -<body> -<div id="sync" class="sidebar"> - <table id="titletable" width="200" cellpadding="0" cellspacing="0" - style="display:none"> - <tr> - <td id="messagetitle" align="left" class="section-title"> - </td> - <td align="right"> - <a href="#" onclick="resizeFrame(0);"> - <img id="greenclose" src="close.png"/> - </a> - </td> - </tr> - </table> - <div id="syncContainer"></div> -</div> -<script> -/* Return a DOM element with tag name |elem| and attributes |attrs|. */ -function DOM(elem, attrs) { - var elem = document.createElement(elem); - for (var attr in attrs) { - elem[attr] = attrs[attr]; - } - return elem; -} - -function renderSyncMessage(message) { - var section = document.getElementById('sync'); - var container = document.getElementById('syncContainer'); - var title = document.getElementById('messagetitle'); - var titletable = document.getElementById('titletable'); - container.innerHTML = ''; - title.innerHTML = ''; - titletable.style.display = "none"; - section.style.display = "block"; - - /* Set the sync section background color. */ - if (message.msgtype == "error") { - section.style.backgroundColor = "#f8d1ca"; - } else if (message.msgtype == "presynced") { - section.style.backgroundColor = "#e0f8ca"; - } else { - section.style.backgroundColor = "#e1ecfe"; - } - - if (message.msgtype != "synced") { - /* Any message except the status normal / synced to - message requires extra markup for a title, close button, - and links. */ - var titletxt = document.createTextNode(message.title); - title.appendChild(titletxt); - titletable.style.display = "block"; - } - - /* The main message of the sync section. */ - var txt = DOM('p'); - txt.style.margin = 0; - txt.appendChild(document.createTextNode(message.msg)); - container.appendChild(txt); - - /* If we should show a link, create the href. */ - if (message.linktext) { - var link = DOM('a', { href:"#", title: message.linktext}); - link.onclick = function(tt) { - return function() { - chrome.send("SyncLinkClicked", [tt]); - return false; - } - } (message.title); - - /* Tie it together. */ - link.appendChild(document.createTextNode(message.linktext)); - container.appendChild(link); - } - - /* Tell our container to resize to fit us appropriately. */ - resizeFrame(document.body.scrollHeight); -} - -chrome.send("GetSyncMessage"); -</script> -</body> -</html>
\ No newline at end of file diff --git a/chrome/browser/sync/resources/setup_flow.html b/chrome/browser/sync/resources/setup_flow.html deleted file mode 100644 index 82db8a9..0000000 --- a/chrome/browser/sync/resources/setup_flow.html +++ /dev/null @@ -1,19 +0,0 @@ -<HTML id='t'> -<style type="text/css"> -</style> -<HEAD> -<TITLE></TITLE> -<script> - function showMergeAndSync() { - document.getElementById("login").style.display = "none"; - document.getElementById("merge").style.display = "block"; - } -</script> -</HEAD> -<BODY style="margin:0; border:0;"> - <iframe id="login" frameborder="0" width="100%" scrolling="no" height="100%" - src="cloudy://resources/gaialogin"></iframe> - <iframe id="merge" frameborder="0" width="100%" scrolling="no" height="100%" - src="cloudy://resources/mergeandsync" style="display:none"></iframe> -</BODY> -</HTML> diff --git a/chrome/browser/sync/sync_status_ui_helper.cc b/chrome/browser/sync/sync_status_ui_helper.cc deleted file mode 100644 index 22a1f6c..0000000 --- a/chrome/browser/sync/sync_status_ui_helper.cc +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifdef CHROME_PERSONALIZATION - -#include "chrome/browser/sync/sync_status_ui_helper.h" - -#include "base/string_util.h" -#include "chrome/browser/sync/auth_error_state.h" -#include "chrome/browser/sync/personalization_strings.h" -#include "chrome/browser/sync/profile_sync_service.h" - -static void GetLabelsForAuthError(AuthErrorState auth_error, - ProfileSyncService* service, std::wstring* status_label, - std::wstring* link_label) { - if (link_label) - link_label->assign(kSyncReLoginLinkLabel); - if (auth_error == AUTH_ERROR_INVALID_GAIA_CREDENTIALS) { - // If the user name is empty then the first login failed, otherwise the - // credentials are out-of-date. - if (service->GetAuthenticatedUsername().empty()) - status_label->append(kSyncInvalidCredentialsError); - else - status_label->append(kSyncExpiredCredentialsError); - } else if (auth_error == AUTH_ERROR_CONNECTION_FAILED) { - // Note that there is little the user can do if the server is not - // reachable. Since attempting to re-connect is done automatically by - // the Syncer, we do not show the (re)login link. - status_label->append(kSyncServerUnavailableMsg); - if (link_label) - link_label->clear(); - } else { - status_label->append(kSyncOtherLoginErrorLabel); - } -} - -static std::wstring GetSyncedStateStatusLabel(ProfileSyncService* service) { - std::wstring label; - std::wstring user_name(UTF16ToWide(service->GetAuthenticatedUsername())); - if (user_name.empty()) - return label; - - label += kSyncAccountLabel; - label += user_name; - label += L"\n"; - label += kLastSyncedLabel; - label += service->GetLastSyncedTimeString(); - return label; -} - -// static -SyncStatusUIHelper::MessageType SyncStatusUIHelper::GetLabels( - ProfileSyncService* service, std::wstring* status_label, - std::wstring* link_label) { - MessageType result_type(SYNCED); - bool sync_enabled = service->IsSyncEnabledByUser(); - - if (sync_enabled) { - ProfileSyncService::Status status(service->QueryDetailedSyncStatus()); - AuthErrorState auth_error(service->GetAuthErrorState()); - // Either show auth error information with a link to re-login, auth in prog, - // or note that everything is OK with the last synced time. - status_label->assign(GetSyncedStateStatusLabel(service)); - if (status.authenticated) { - // Everything is peachy. - DCHECK_EQ(auth_error, AUTH_ERROR_NONE); - } else if (service->UIShouldDepictAuthInProgress()) { - status_label->append(kSyncAuthenticatingLabel); - result_type = PRE_SYNCED; - } else if (auth_error != AUTH_ERROR_NONE) { - GetLabelsForAuthError(auth_error, service, status_label, link_label); - result_type = SYNC_ERROR; - } else { - NOTREACHED() << "Setup complete, backend !authenticated, AUTH_ERROR_NONE"; - } - } else { - // Either show auth error information with a link to re-login, auth in prog, - // or provide a link to continue with setup. - result_type = PRE_SYNCED; - if (service->SetupInProgress()) { - ProfileSyncService::Status status(service->QueryDetailedSyncStatus()); - AuthErrorState auth_error(service->GetAuthErrorState()); - status_label->assign(UTF8ToWide(kSettingUpText)); - if (service->UIShouldDepictAuthInProgress()) { - status_label->assign(kSyncAuthenticatingLabel); - } else if (auth_error != AUTH_ERROR_NONE) { - status_label->clear(); - GetLabelsForAuthError(auth_error, service, status_label, NULL); - result_type = SYNC_ERROR; - } else if (!status.authenticated) { - status_label->assign(kSyncCredentialsNeededLabel); - } - } else { - status_label->assign(kSyncNotSetupInfo); - } - } - return result_type; -} - -#endif // CHROME_PERSONALIZATION diff --git a/chrome/browser/sync/sync_status_ui_helper.h b/chrome/browser/sync/sync_status_ui_helper.h deleted file mode 100644 index 6241ead..0000000 --- a/chrome/browser/sync/sync_status_ui_helper.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifdef CHROME_PERSONALIZATION - -#ifndef CHROME_BROWSER_SYNC_SYNC_STATUS_UI_HELPER_H_ -#define CHROME_BROWSER_SYNC_SYNC_STATUS_UI_HELPER_H_ - -#include "base/string16.h" - -class ProfileSyncService; - -// Utility to gather current sync status information from the sync service and -// constructs messages suitable for showing in UI. -class SyncStatusUIHelper { - public: - enum MessageType { - PRE_SYNCED, // User has not set up sync. - SYNCED, // We are synced and authenticated to a gmail account. - SYNC_ERROR, // A sync error (such as invalid credentials) has occurred. - }; - - // Create status and link labels for the current status labels and link text - // by querying |service|. - static MessageType GetLabels(ProfileSyncService* service, - std::wstring* status_label, - std::wstring* link_label); - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(SyncStatusUIHelper); -}; - -#endif // CHROME_BROWSER_SYNC_SYNC_STATUS_UI_HELPER_H_ -#endif // CHROME_PERSONALIZATION |