| Index: chrome/browser/importer/toolbar_importer.cc
|
| diff --git a/chrome/browser/importer/toolbar_importer.cc b/chrome/browser/importer/toolbar_importer.cc
|
| deleted file mode 100644
|
| index dea1d6115de030d4c0cbb08d351eab76780c92b3..0000000000000000000000000000000000000000
|
| --- a/chrome/browser/importer/toolbar_importer.cc
|
| +++ /dev/null
|
| @@ -1,573 +0,0 @@
|
| -// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "chrome/browser/importer/toolbar_importer.h"
|
| -
|
| -#include <limits>
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/rand_util.h"
|
| -#include "base/strings/string_number_conversions.h"
|
| -#include "base/strings/string_split.h"
|
| -#include "base/strings/utf_string_conversions.h"
|
| -#include "chrome/browser/bookmarks/imported_bookmark_entry.h"
|
| -#include "chrome/browser/first_run/first_run.h"
|
| -#include "chrome/browser/importer/importer_bridge.h"
|
| -#include "chrome/browser/importer/importer_data_types.h"
|
| -#include "chrome/browser/profiles/profile.h"
|
| -#include "content/public/browser/browser_thread.h"
|
| -#include "grit/generated_resources.h"
|
| -#include "net/base/load_flags.h"
|
| -#include "net/url_request/url_fetcher.h"
|
| -#include "third_party/libxml/chromium/libxml_utils.h"
|
| -
|
| -using content::BrowserThread;
|
| -
|
| -// Toolbar5Importer
|
| -const char Toolbar5Importer::kXmlApiReplyXmlTag[] = "xml_api_reply";
|
| -const char Toolbar5Importer::kBookmarksXmlTag[] = "bookmarks";
|
| -const char Toolbar5Importer::kBookmarkXmlTag[] = "bookmark";
|
| -const char Toolbar5Importer::kTitleXmlTag[] = "title";
|
| -const char Toolbar5Importer::kUrlXmlTag[] = "url";
|
| -const char Toolbar5Importer::kTimestampXmlTag[] = "timestamp";
|
| -const char Toolbar5Importer::kLabelsXmlTag[] = "labels";
|
| -const char Toolbar5Importer::kLabelsXmlCloseTag[] = "/labels";
|
| -const char Toolbar5Importer::kLabelXmlTag[] = "label";
|
| -const char Toolbar5Importer::kAttributesXmlTag[] = "attributes";
|
| -
|
| -const char Toolbar5Importer::kRandomNumberToken[] = "{random_number}";
|
| -const char Toolbar5Importer::kAuthorizationToken[] = "{auth_token}";
|
| -const char Toolbar5Importer::kAuthorizationTokenPrefix[] = "/*";
|
| -const char Toolbar5Importer::kAuthorizationTokenSuffix[] = "*/";
|
| -const char Toolbar5Importer::kMaxNumToken[] = "{max_num}";
|
| -const char Toolbar5Importer::kMaxTimestampToken[] = "{max_timestamp}";
|
| -
|
| -const char Toolbar5Importer::kT5AuthorizationTokenUrl[] =
|
| - "http://www.google.com/notebook/token?zx={random_number}";
|
| -const char Toolbar5Importer::kT5FrontEndUrlTemplate[] =
|
| - "http://www.google.com/notebook/toolbar?cmd=list&tok={auth_token}&"
|
| - "num={max_num}&min={max_timestamp}&all=0&zx={random_number}";
|
| -
|
| -// Importer methods.
|
| -
|
| -// The constructor should set the initial state to NOT_USED.
|
| -Toolbar5Importer::Toolbar5Importer()
|
| - : state_(NOT_USED),
|
| - items_to_import_(importer::NONE),
|
| - token_fetcher_(NULL),
|
| - data_fetcher_(NULL) {
|
| -}
|
| -
|
| -// The destructor insures that the fetchers are currently not being used, as
|
| -// their thread-safe implementation requires that they are cancelled from the
|
| -// thread in which they were constructed.
|
| -Toolbar5Importer::~Toolbar5Importer() {
|
| - DCHECK(!token_fetcher_);
|
| - DCHECK(!data_fetcher_);
|
| -}
|
| -
|
| -void Toolbar5Importer::StartImport(
|
| - const importer::SourceProfile& source_profile,
|
| - uint16 items,
|
| - ImporterBridge* bridge) {
|
| - DCHECK(bridge);
|
| -
|
| - bridge_ = bridge;
|
| - items_to_import_ = items;
|
| - DCHECK(source_profile.request_context_getter.get());
|
| - request_context_getter_ = source_profile.request_context_getter;
|
| - state_ = INITIALIZED;
|
| -
|
| - bridge_->NotifyStarted();
|
| - ContinueImport();
|
| -}
|
| -
|
| -// The public cancel method serves two functions, as a callback from the UI
|
| -// as well as an internal callback in case of cancel. An internal callback
|
| -// is required since the URLFetcher must be destroyed from the thread it was
|
| -// created.
|
| -void Toolbar5Importer::Cancel() {
|
| - // In the case when the thread is not importing messages we are to
|
| - // cancel as soon as possible.
|
| - Importer::Cancel();
|
| -
|
| - // If we are conducting network operations, post a message to the importer
|
| - // thread for synchronization.
|
| - if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
|
| - EndImport();
|
| - } else {
|
| - BrowserThread::PostTask(
|
| - BrowserThread::UI, FROM_HERE,
|
| - base::Bind(&Toolbar5Importer::Cancel, this));
|
| - }
|
| -}
|
| -
|
| -void Toolbar5Importer::OnURLFetchComplete(const net::URLFetcher* source) {
|
| - if (cancelled()) {
|
| - EndImport();
|
| - return;
|
| - }
|
| -
|
| - if (200 != source->GetResponseCode()) { // HTTP/Ok
|
| - // Cancelling here will update the UI and bypass the rest of bookmark
|
| - // import.
|
| - EndImportBookmarks();
|
| - return;
|
| - }
|
| -
|
| - std::string data;
|
| - source->GetResponseAsString(&data);
|
| - switch (state_) {
|
| - case GET_AUTHORIZATION_TOKEN:
|
| - GetBookmarkDataFromServer(data);
|
| - break;
|
| - case GET_BOOKMARKS:
|
| - GetBookmarksFromServerDataResponse(data);
|
| - break;
|
| - default:
|
| - NOTREACHED() << "Invalid state.";
|
| - EndImportBookmarks();
|
| - break;
|
| - }
|
| -}
|
| -
|
| -void Toolbar5Importer::ContinueImport() {
|
| - DCHECK((items_to_import_ == importer::FAVORITES) ||
|
| - (items_to_import_ == importer::NONE)) <<
|
| - "The items requested are not supported";
|
| -
|
| - // The order here is important. Each Begin... will clear the flag
|
| - // of its item before its task finishes and re-enters this method.
|
| - if (importer::NONE == items_to_import_) {
|
| - EndImport();
|
| - return;
|
| - }
|
| - if ((items_to_import_ & importer::FAVORITES) && !cancelled()) {
|
| - items_to_import_ &= ~importer::FAVORITES;
|
| - BeginImportBookmarks();
|
| - return;
|
| - }
|
| - // TODO(brg): Import history, autocomplete, other toolbar information
|
| - // in a future release.
|
| -
|
| - // This code should not be reached, but gracefully handles the possibility
|
| - // that StartImport was called with unsupported items_to_import.
|
| - if (!cancelled())
|
| - EndImport();
|
| -}
|
| -
|
| -void Toolbar5Importer::EndImport() {
|
| - if (state_ != DONE) {
|
| - state_ = DONE;
|
| - // By spec the fetchers must be destroyed within the same
|
| - // thread they are created. The importer is destroyed in the ui_thread
|
| - // so when we complete in the file_thread we destroy them first.
|
| - if (NULL != token_fetcher_) {
|
| - delete token_fetcher_;
|
| - token_fetcher_ = NULL;
|
| - }
|
| -
|
| - if (NULL != data_fetcher_) {
|
| - delete data_fetcher_;
|
| - data_fetcher_ = NULL;
|
| - }
|
| -
|
| - if (bridge_.get())
|
| - bridge_->NotifyEnded();
|
| - }
|
| -}
|
| -
|
| -void Toolbar5Importer::BeginImportBookmarks() {
|
| - bridge_->NotifyItemStarted(importer::FAVORITES);
|
| - GetAuthenticationFromServer();
|
| -}
|
| -
|
| -void Toolbar5Importer::EndImportBookmarks() {
|
| - bridge_->NotifyItemEnded(importer::FAVORITES);
|
| - ContinueImport();
|
| -}
|
| -
|
| -
|
| -// Notebook front-end connection manager implementation follows.
|
| -void Toolbar5Importer::GetAuthenticationFromServer() {
|
| - if (cancelled()) {
|
| - EndImport();
|
| - return;
|
| - }
|
| -
|
| - // Authentication is a token string retrieved from the authentication server
|
| - // To access it we call the url below with a random number replacing the
|
| - // value in the string.
|
| - state_ = GET_AUTHORIZATION_TOKEN;
|
| -
|
| - // Random number construction.
|
| - int random = base::RandInt(0, std::numeric_limits<int>::max());
|
| - std::string random_string = base::UintToString(random);
|
| -
|
| - // Retrieve authorization token from the network.
|
| - std::string url_string(kT5AuthorizationTokenUrl);
|
| - url_string.replace(url_string.find(kRandomNumberToken),
|
| - arraysize(kRandomNumberToken) - 1,
|
| - random_string);
|
| - GURL url(url_string);
|
| -
|
| - // Because the importer is started as the result of a user action which
|
| - // explicitly requires authentication, sending cookies here is reasonable.
|
| - token_fetcher_ = net::URLFetcher::Create(
|
| - url, net::URLFetcher::GET, this);
|
| - token_fetcher_->SetRequestContext(request_context_getter_.get());
|
| - token_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES);
|
| - token_fetcher_->Start();
|
| -}
|
| -
|
| -void Toolbar5Importer::GetBookmarkDataFromServer(const std::string& response) {
|
| - if (cancelled()) {
|
| - EndImport();
|
| - return;
|
| - }
|
| -
|
| - state_ = GET_BOOKMARKS;
|
| -
|
| - // Parse and verify the authorization token from the response.
|
| - std::string token;
|
| - if (!ParseAuthenticationTokenResponse(response, &token)) {
|
| - EndImportBookmarks();
|
| - return;
|
| - }
|
| -
|
| - // Build the Toolbar FE connection string, and call the server for
|
| - // the xml blob. We must tag the connection string with a random number.
|
| - std::string conn_string = kT5FrontEndUrlTemplate;
|
| - int random = base::RandInt(0, std::numeric_limits<int>::max());
|
| - std::string random_string = base::UintToString(random);
|
| - conn_string.replace(conn_string.find(kRandomNumberToken),
|
| - arraysize(kRandomNumberToken) - 1,
|
| - random_string);
|
| - conn_string.replace(conn_string.find(kAuthorizationToken),
|
| - arraysize(kAuthorizationToken) - 1,
|
| - token);
|
| - GURL url(conn_string);
|
| -
|
| - // Because the importer is started as the result of a user action which
|
| - // explicitly requires authentication, sending cookies here is reasonable.
|
| - data_fetcher_ = net::URLFetcher::Create(
|
| - url, net::URLFetcher::GET, this);
|
| - data_fetcher_->SetRequestContext(request_context_getter_.get());
|
| - data_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES);
|
| - data_fetcher_->Start();
|
| -}
|
| -
|
| -void Toolbar5Importer::GetBookmarksFromServerDataResponse(
|
| - const std::string& response) {
|
| - if (cancelled()) {
|
| - EndImport();
|
| - return;
|
| - }
|
| -
|
| - state_ = PARSE_BOOKMARKS;
|
| -
|
| - XmlReader reader;
|
| - if (reader.Load(response) && !cancelled()) {
|
| - // Construct Bookmarks
|
| - std::vector<ImportedBookmarkEntry> bookmarks;
|
| - if (ParseBookmarksFromReader(&reader, &bookmarks,
|
| - bridge_->GetLocalizedString(IDS_BOOKMARK_GROUP_FROM_GOOGLE_TOOLBAR)))
|
| - AddBookmarksToChrome(bookmarks);
|
| - }
|
| - EndImportBookmarks();
|
| -}
|
| -
|
| -bool Toolbar5Importer::ParseAuthenticationTokenResponse(
|
| - const std::string& response,
|
| - std::string* token) {
|
| - DCHECK(token);
|
| -
|
| - *token = response;
|
| - size_t position = token->find(kAuthorizationTokenPrefix);
|
| - if (0 != position)
|
| - return false;
|
| - token->replace(position, arraysize(kAuthorizationTokenPrefix) - 1, "");
|
| -
|
| - position = token->find(kAuthorizationTokenSuffix);
|
| - if (token->size() != (position + (arraysize(kAuthorizationTokenSuffix) - 1)))
|
| - return false;
|
| - token->replace(position, arraysize(kAuthorizationTokenSuffix) - 1, "");
|
| -
|
| - return true;
|
| -}
|
| -
|
| -// Parsing
|
| -bool Toolbar5Importer::ParseBookmarksFromReader(
|
| - XmlReader* reader,
|
| - std::vector<ImportedBookmarkEntry>* bookmarks,
|
| - const string16& bookmark_group_string) {
|
| - DCHECK(reader);
|
| - DCHECK(bookmarks);
|
| -
|
| - // The XML blob returned from the server is described in the
|
| - // Toolbar-Notebook/Bookmarks Protocol document located at
|
| - // https://docs.google.com/a/google.com/Doc?docid=cgt3m7dr_24djt62m&hl=en
|
| - // We are searching for the section with structure
|
| - // <bookmarks><bookmark>...</bookmark><bookmark>...</bookmark></bookmarks>
|
| -
|
| - // Locate the |bookmarks| blob.
|
| - if (!reader->SkipToElement())
|
| - return false;
|
| -
|
| - if (!LocateNextTagByName(reader, kBookmarksXmlTag))
|
| - return false;
|
| -
|
| - // Parse each |bookmark| blob
|
| - while (LocateNextTagWithStopByName(reader, kBookmarkXmlTag,
|
| - kBookmarksXmlTag)) {
|
| - ImportedBookmarkEntry bookmark_entry;
|
| - std::vector<BookmarkFolderType> folders;
|
| - if (ExtractBookmarkInformation(reader, &bookmark_entry, &folders,
|
| - bookmark_group_string)) {
|
| - // For each folder we create a new bookmark entry. Duplicates will
|
| - // be detected when we attempt to create the bookmark in the profile.
|
| - for (std::vector<BookmarkFolderType>::iterator folder = folders.begin();
|
| - folder != folders.end();
|
| - ++folder) {
|
| - bookmark_entry.path = *folder;
|
| - bookmarks->push_back(bookmark_entry);
|
| - }
|
| - }
|
| - }
|
| -
|
| - if (0 == bookmarks->size())
|
| - return false;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool Toolbar5Importer::LocateNextOpenTag(XmlReader* reader) {
|
| - DCHECK(reader);
|
| -
|
| - while (!reader->SkipToElement()) {
|
| - if (!reader->Read())
|
| - return false;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool Toolbar5Importer::LocateNextTagByName(XmlReader* reader,
|
| - const std::string& tag) {
|
| - DCHECK(reader);
|
| -
|
| - // Locate the |tag| blob.
|
| - while (tag != reader->NodeName()) {
|
| - if (!reader->Read() || !LocateNextOpenTag(reader))
|
| - return false;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool Toolbar5Importer::LocateNextTagWithStopByName(XmlReader* reader,
|
| - const std::string& tag,
|
| - const std::string& stop) {
|
| - DCHECK(reader);
|
| -
|
| - DCHECK_NE(tag, stop);
|
| - // Locate the |tag| blob.
|
| - while (tag != reader->NodeName()) {
|
| - // Move to the next open tag.
|
| - if (!reader->Read() || !LocateNextOpenTag(reader))
|
| - return false;
|
| - // If we encounter the stop word return false.
|
| - if (stop == reader->NodeName())
|
| - return false;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool Toolbar5Importer::ExtractBookmarkInformation(
|
| - XmlReader* reader,
|
| - ImportedBookmarkEntry* bookmark_entry,
|
| - std::vector<BookmarkFolderType>* bookmark_folders,
|
| - const string16& bookmark_group_string) {
|
| - DCHECK(reader);
|
| - DCHECK(bookmark_entry);
|
| - DCHECK(bookmark_folders);
|
| -
|
| - // The following is a typical bookmark entry.
|
| - // The reader should be pointing to the <title> tag at the moment.
|
| - //
|
| - // <bookmark>
|
| - // <title>MyTitle</title>
|
| - // <url>http://www.sohu.com/</url>
|
| - // <timestamp>1153328691085181</timestamp>
|
| - // <id>N123nasdf239</id>
|
| - // <notebook_id>Bxxxxxxx</notebook_id> (for bookmarks, a special id is used)
|
| - // <section_id>Sxxxxxx</section_id>
|
| - // <has_highlight>0</has_highlight>
|
| - // <labels>
|
| - // <label>China</label>
|
| - // <label>^k</label> (if this special label is present, the note is deleted)
|
| - // </labels>
|
| - // <attributes>
|
| - // <attribute>
|
| - // <name>favicon_url</name>
|
| - // <value>http://www.sohu.com/favicon.ico</value>
|
| - // </attribute>
|
| - // <attribute>
|
| - // <name>favicon_timestamp</name>
|
| - // <value>1153328653</value>
|
| - // </attribute>
|
| - // <attribute>
|
| - // <name>notebook_name</name>
|
| - // <value>My notebook 0</value>
|
| - // </attribute>
|
| - // <attribute>
|
| - // <name>section_name</name>
|
| - // <value>My section 0</value>
|
| - // </attribute>
|
| - // </attributes>
|
| - // </bookmark>
|
| - //
|
| - // We parse the blob in order, title->url->timestamp etc. Any failure
|
| - // causes us to skip this bookmark.
|
| -
|
| - if (!ExtractTitleFromXmlReader(reader, bookmark_entry))
|
| - return false;
|
| - if (!ExtractUrlFromXmlReader(reader, bookmark_entry))
|
| - return false;
|
| - if (!ExtractTimeFromXmlReader(reader, bookmark_entry))
|
| - return false;
|
| - if (!ExtractFoldersFromXmlReader(reader, bookmark_folders,
|
| - bookmark_group_string))
|
| - return false;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool Toolbar5Importer::ExtractNamedValueFromXmlReader(XmlReader* reader,
|
| - const std::string& name,
|
| - std::string* buffer) {
|
| - DCHECK(reader);
|
| - DCHECK(buffer);
|
| -
|
| - if (name != reader->NodeName())
|
| - return false;
|
| - if (!reader->ReadElementContent(buffer))
|
| - return false;
|
| - return true;
|
| -}
|
| -
|
| -bool Toolbar5Importer::ExtractTitleFromXmlReader(
|
| - XmlReader* reader,
|
| - ImportedBookmarkEntry* entry) {
|
| - DCHECK(reader);
|
| - DCHECK(entry);
|
| -
|
| - if (!LocateNextTagWithStopByName(reader, kTitleXmlTag, kUrlXmlTag))
|
| - return false;
|
| - std::string buffer;
|
| - if (!ExtractNamedValueFromXmlReader(reader, kTitleXmlTag, &buffer)) {
|
| - return false;
|
| - }
|
| - entry->title = UTF8ToUTF16(buffer);
|
| - return true;
|
| -}
|
| -
|
| -bool Toolbar5Importer::ExtractUrlFromXmlReader(
|
| - XmlReader* reader,
|
| - ImportedBookmarkEntry* entry) {
|
| - DCHECK(reader);
|
| - DCHECK(entry);
|
| -
|
| - if (!LocateNextTagWithStopByName(reader, kUrlXmlTag, kTimestampXmlTag))
|
| - return false;
|
| - std::string buffer;
|
| - if (!ExtractNamedValueFromXmlReader(reader, kUrlXmlTag, &buffer)) {
|
| - return false;
|
| - }
|
| - entry->url = GURL(buffer);
|
| - return true;
|
| -}
|
| -
|
| -bool Toolbar5Importer::ExtractTimeFromXmlReader(
|
| - XmlReader* reader,
|
| - ImportedBookmarkEntry* entry) {
|
| - DCHECK(reader);
|
| - DCHECK(entry);
|
| - if (!LocateNextTagWithStopByName(reader, kTimestampXmlTag, kLabelsXmlTag))
|
| - return false;
|
| - std::string buffer;
|
| - if (!ExtractNamedValueFromXmlReader(reader, kTimestampXmlTag, &buffer)) {
|
| - return false;
|
| - }
|
| - int64 timestamp;
|
| - if (!base::StringToInt64(buffer, ×tamp)) {
|
| - return false;
|
| - }
|
| - entry->creation_time = base::Time::FromTimeT(timestamp);
|
| - return true;
|
| -}
|
| -
|
| -bool Toolbar5Importer::ExtractFoldersFromXmlReader(
|
| - XmlReader* reader,
|
| - std::vector<BookmarkFolderType>* bookmark_folders,
|
| - const string16& bookmark_group_string) {
|
| - DCHECK(reader);
|
| - DCHECK(bookmark_folders);
|
| -
|
| - // Read in the labels for this bookmark from the xml. There may be many
|
| - // labels for any one bookmark.
|
| - if (!LocateNextTagWithStopByName(reader, kLabelsXmlTag, kAttributesXmlTag))
|
| - return false;
|
| -
|
| - // It is within scope to have an empty labels section, so we do not
|
| - // return false if the labels are empty.
|
| - if (!reader->Read() || !LocateNextOpenTag(reader))
|
| - return false;
|
| -
|
| - std::vector<string16> label_vector;
|
| - while (kLabelXmlTag == reader->NodeName()) {
|
| - std::string label_buffer;
|
| - if (!reader->ReadElementContent(&label_buffer)) {
|
| - label_buffer = "";
|
| - }
|
| - label_vector.push_back(UTF8ToUTF16(label_buffer));
|
| - LocateNextOpenTag(reader);
|
| - }
|
| -
|
| - if (0 == label_vector.size()) {
|
| - if (!first_run::IsChromeFirstRun()) {
|
| - bookmark_folders->resize(1);
|
| - (*bookmark_folders)[0].push_back(bookmark_group_string);
|
| - }
|
| - return true;
|
| - }
|
| -
|
| - // We will be making one bookmark folder for each label.
|
| - bookmark_folders->resize(label_vector.size());
|
| -
|
| - for (size_t index = 0; index < label_vector.size(); ++index) {
|
| - // If this is the first run then we place favorites with no labels
|
| - // in the title bar. Else they are placed in the "Google Toolbar" folder.
|
| - if (!first_run::IsChromeFirstRun() || !label_vector[index].empty()) {
|
| - (*bookmark_folders)[index].push_back(bookmark_group_string);
|
| - }
|
| -
|
| - // If the label and is in the form "xxx:yyy:zzz" this was created from an
|
| - // IE or Firefox folder. We undo the label creation and recreate the
|
| - // correct folder.
|
| - std::vector<string16> folder_names;
|
| - base::SplitString(label_vector[index], ':', &folder_names);
|
| - (*bookmark_folders)[index].insert((*bookmark_folders)[index].end(),
|
| - folder_names.begin(), folder_names.end());
|
| - }
|
| -
|
| - return true;
|
| -}
|
| -
|
| -void Toolbar5Importer::AddBookmarksToChrome(
|
| - const std::vector<ImportedBookmarkEntry>& bookmarks) {
|
| - if (!bookmarks.empty() && !cancelled()) {
|
| - const string16& first_folder_name =
|
| - bridge_->GetLocalizedString(IDS_BOOKMARK_GROUP_FROM_GOOGLE_TOOLBAR);
|
| - bridge_->AddBookmarks(bookmarks, first_folder_name);
|
| - }
|
| -}
|
|
|