<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/extension_dom_ui.h"

#include "base/string_util.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/extensions/extension_bookmark_manager_api.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/bindings_policy.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/url_constants.h"

namespace {
const wchar_t kExtensionURLOverrides[] = L"extensions.chrome_url_overrides";
}

ExtensionDOMUI::ExtensionDOMUI(TabContents* tab_contents)
    : DOMUI(tab_contents) {
  // TODO(aa): It would be cool to show the extension's icon in here.
  hide_favicon_ = true;
  should_hide_url_ = true;
  bindings_ = BindingsPolicy::EXTENSION;

  // For chrome:// overrides, some of the defaults are a little different.
  GURL url = tab_contents->GetURL();
  if (url.SchemeIs(chrome::kChromeUIScheme)) {
    if (url.host() == chrome::kChromeUINewTabHost) {
      focus_location_bar_by_default_ = true;
    } else {
      // Current behavior of other chrome:// pages is to display the URL.
      should_hide_url_ = false;
    }
  }
}

void ExtensionDOMUI::ResetExtensionFunctionDispatcher(
    RenderViewHost* render_view_host) {
  // Use the NavigationController to get the URL rather than the TabContents
  // since this is the real underlying URL (see HandleChromeURLOverride).
  NavigationController& controller = tab_contents()->controller();
  const GURL& url = controller.GetActiveEntry()->url();
  extension_function_dispatcher_.reset(
      new ExtensionFunctionDispatcher(render_view_host, this, url));
}

void ExtensionDOMUI::ResetExtensionBookmarkManagerEventRouter() {
  if (CommandLine::ForCurrentProcess()->HasSwitch(
      switches::kEnableTabbedBookmarkManager)) {
    extension_bookmark_manager_event_router_.reset(
        new ExtensionBookmarkManagerEventRouter(GetProfile(), tab_contents()));
  }
}

void ExtensionDOMUI::RenderViewCreated(RenderViewHost* render_view_host) {
  ResetExtensionFunctionDispatcher(render_view_host);
  ResetExtensionBookmarkManagerEventRouter();
}

void ExtensionDOMUI::RenderViewReused(RenderViewHost* render_view_host) {
  ResetExtensionFunctionDispatcher(render_view_host);
  ResetExtensionBookmarkManagerEventRouter();
}

void ExtensionDOMUI::ProcessDOMUIMessage(const std::string& message,
                                         const Value* content,
                                         int request_id,
                                         bool has_callback) {
  extension_function_dispatcher_->HandleRequest(message, content, request_id,
                                                has_callback);
}

Browser* ExtensionDOMUI::GetBrowser(bool include_incognito) const {
  Browser* browser = NULL;
  TabContentsDelegate* tab_contents_delegate = tab_contents()->delegate();
  if (tab_contents_delegate) {
    browser = tab_contents_delegate->GetBrowser();
    if (browser && browser->profile()->IsOffTheRecord() && !include_incognito) {
      // Fall back to the toplevel regular browser if we don't want to include
      // incognito browsers.
      browser = BrowserList::GetLastActiveWithProfile(
          browser->profile()->GetOriginalProfile());
    }
  }
  return browser;
}

Profile* ExtensionDOMUI::GetProfile() {
  return DOMUI::GetProfile();
}

gfx::NativeWindow ExtensionDOMUI::GetFrameNativeWindow() {
  gfx::NativeWindow native_window =
      ExtensionFunctionDispatcher::Delegate::GetFrameNativeWindow();

  // If there was no window associated with the function dispatcher delegate,
  // then this DOMUI may be hosted in an ExternalTabContainer, and a framing
  // window will be accessible through the tab_contents.
  if (!native_window) {
    TabContentsDelegate* tab_contents_delegate = tab_contents()->delegate();
    if (tab_contents_delegate)
      native_window = tab_contents_delegate->GetFrameNativeWindow();
  }

  return native_window;
}

gfx::NativeView ExtensionDOMUI::GetNativeViewOfHost() {
  return tab_contents()->GetRenderWidgetHostView()->GetNativeView();
}

////////////////////////////////////////////////////////////////////////////////
// chrome:// URL overrides

// static
void ExtensionDOMUI::RegisterUserPrefs(PrefService* prefs) {
  prefs->RegisterDictionaryPref(kExtensionURLOverrides);
}

// static
bool ExtensionDOMUI::HandleChromeURLOverride(GURL* url, Profile* profile) {
  if (!url->SchemeIs(chrome::kChromeUIScheme))
    return false;

  // Even when the extensions service is enabled by default, it's still
  // disabled in incognito mode.
  ExtensionsService* service = profile->GetExtensionsService();
  if (!service)
    return false;

  const DictionaryValue* overrides =
      profile->GetPrefs()->GetDictionary(kExtensionURLOverrides);
  std::string page = url->host();
  ListValue* url_list;
  if (!overrides || !overrides->GetList(UTF8ToWide(page), &url_list))
    return false;

  if (!service->is_ready()) {
    // TODO(erikkay) So far, it looks like extensions load before the new tab
    // page.  I don't know if we have anything that enforces this, so add this
    // check for safety.
    NOTREACHED() << "Chrome URL override requested before extensions loaded";
    return false;
  }

  while (url_list->GetSize()) {
    Value* val;
    url_list->Get(0, &val);

    // Verify that the override value is good.  If not, unregister it and find
    // the next one.
    std::string override;
    if (!val->GetAsString(&override)) {
      NOTREACHED();
      UnregisterChromeURLOverride(page, profile, val);
      continue;
    }
    GURL extension_url(override);
    if (!extension_url.is_valid()) {
      NOTREACHED();
      UnregisterChromeURLOverride(page, profile, val);
      continue;
    }

    // Verify that the extension that's being referred to actually exists.
    Extension* extension = service->GetExtensionByURL(extension_url);
    if (!extension) {
      // This can currently happen if you use --load-extension one run, and
      // then don't use it the next.  It could also happen if an extension
      // were deleted directly from the filesystem, etc.
      LOG(WARNING) << "chrome URL override present for non-existant extension";
      UnregisterChromeURLOverride(page, profile, val);
      continue;
    }

    *url = extension_url;
    return true;
  }
  return false;
}

// static
void ExtensionDOMUI::RegisterChromeURLOverrides(
    Profile* profile, const Extension::URLOverrideMap& overrides) {
  if (overrides.empty())
    return;

  PrefService* prefs = profile->GetPrefs();
  DictionaryValue* all_overrides =
      prefs->GetMutableDictionary(kExtensionURLOverrides);

  // For each override provided by the extension, add it to the front of
  // the override list if it's not already in the list.
  Extension::URLOverrideMap::const_iterator iter = overrides.begin();
  for (;iter != overrides.end(); ++iter) {
    const std::wstring key = UTF8ToWide((*iter).first);
    ListValue* page_overrides;
    if (!all_overrides->GetList(key, &page_overrides)) {
      page_overrides = new ListValue();
      all_overrides->Set(key, page_overrides);
    } else {
      // Verify that the override isn't already in the list.
      ListValue::iterator i = page_overrides->begin();
      for (; i != page_overrides->end(); ++i) {
        std::string override_val;
        if (!(*i)->GetAsString(&override_val)) {
          NOTREACHED();
          continue;
        }
        if (override_val == (*iter).first)
          break;
      }
      // This value is already in the list, leave it alone.
      if (i != page_overrides->end())
        continue;
    }
    // Insert the override at the front of the list.  Last registered override
    // wins.
    page_overrides->Insert(0, new StringValue((*iter).second.spec()));
  }
}

// static
void ExtensionDOMUI::UnregisterAndReplaceOverride(const std::string& page,
    Profile* profile, ListValue* list, Value* override) {
  int index = list->Remove(*override);
  if (index == 0) {
    // This is the active override, so we need to find all existing
    // tabs for this override and get them to reload the original URL.
    for (TabContentsIterator iterator; !iterator.done(); ++iterator) {
      TabContents* tab = *iterator;
      if (tab->profile() != profile)
        continue;

      GURL url = tab->GetURL();
      if (!url.SchemeIs(chrome::kChromeUIScheme) || url.host() != page)
        continue;

      // Don't use Reload() since |url| isn't the same as the internal URL
      // that NavigationController has.
      tab->controller().LoadURL(url, url, PageTransition::RELOAD);
    }
  }
}

// static
void ExtensionDOMUI::UnregisterChromeURLOverride(const std::string& page,
    Profile* profile, Value* override) {
  if (!override)
    return;
  PrefService* prefs = profile->GetPrefs();
  DictionaryValue* all_overrides =
      prefs->GetMutableDictionary(kExtensionURLOverrides);
  ListValue* page_overrides;
  if (!all_overrides->GetList(UTF8ToWide(page), &page_overrides)) {
    // If it's being unregistered, it should already be in the list.
    NOTREACHED();
    return;
  } else {
    UnregisterAndReplaceOverride(page, profile, page_overrides, override);
  }
}

RenderViewHost* ExtensionDOMUI::GetRenderViewHost() {
  return tab_contents() ? tab_contents()->render_view_host() : NULL;
}

// static
void ExtensionDOMUI::UnregisterChromeURLOverrides(
    Profile* profile, const Extension::URLOverrideMap& overrides) {
  if (overrides.empty())
    return;
  PrefService* prefs = profile->GetPrefs();
  DictionaryValue* all_overrides =
      prefs->GetMutableDictionary(kExtensionURLOverrides);
  Extension::URLOverrideMap::const_iterator iter = overrides.begin();
  for (;iter != overrides.end(); ++iter) {
    std::wstring page = UTF8ToWide((*iter).first);
    ListValue* page_overrides;
    if (!all_overrides->GetList(page, &page_overrides)) {
      // If it's being unregistered, it should already be in the list.
      NOTREACHED();
      continue;
    } else {
      StringValue override((*iter).second.spec());
      UnregisterAndReplaceOverride((*iter).first, profile,
                                   page_overrides, &override);
    }
  }
}
<commit_msg>Hide the URL for all chrome_url_overrides.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/extension_dom_ui.h"

#include "base/string_util.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/extensions/extension_bookmark_manager_api.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/bindings_policy.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/url_constants.h"

namespace {
const wchar_t kExtensionURLOverrides[] = L"extensions.chrome_url_overrides";
}

ExtensionDOMUI::ExtensionDOMUI(TabContents* tab_contents)
    : DOMUI(tab_contents) {
  // TODO(aa): It would be cool to show the extension's icon in here.
  hide_favicon_ = true;
  should_hide_url_ = true;
  bindings_ = BindingsPolicy::EXTENSION;

  // For chrome:// overrides, some of the defaults are a little different.
  GURL url = tab_contents->GetURL();
  if (url.SchemeIs(chrome::kChromeUIScheme) &&
      url.host() == chrome::kChromeUINewTabHost) {
    focus_location_bar_by_default_ = true;
  }
}

void ExtensionDOMUI::ResetExtensionFunctionDispatcher(
    RenderViewHost* render_view_host) {
  // Use the NavigationController to get the URL rather than the TabContents
  // since this is the real underlying URL (see HandleChromeURLOverride).
  NavigationController& controller = tab_contents()->controller();
  const GURL& url = controller.GetActiveEntry()->url();
  extension_function_dispatcher_.reset(
      new ExtensionFunctionDispatcher(render_view_host, this, url));
}

void ExtensionDOMUI::ResetExtensionBookmarkManagerEventRouter() {
  if (CommandLine::ForCurrentProcess()->HasSwitch(
      switches::kEnableTabbedBookmarkManager)) {
    extension_bookmark_manager_event_router_.reset(
        new ExtensionBookmarkManagerEventRouter(GetProfile(), tab_contents()));
  }
}

void ExtensionDOMUI::RenderViewCreated(RenderViewHost* render_view_host) {
  ResetExtensionFunctionDispatcher(render_view_host);
  ResetExtensionBookmarkManagerEventRouter();
}

void ExtensionDOMUI::RenderViewReused(RenderViewHost* render_view_host) {
  ResetExtensionFunctionDispatcher(render_view_host);
  ResetExtensionBookmarkManagerEventRouter();
}

void ExtensionDOMUI::ProcessDOMUIMessage(const std::string& message,
                                         const Value* content,
                                         int request_id,
                                         bool has_callback) {
  extension_function_dispatcher_->HandleRequest(message, content, request_id,
                                                has_callback);
}

Browser* ExtensionDOMUI::GetBrowser(bool include_incognito) const {
  Browser* browser = NULL;
  TabContentsDelegate* tab_contents_delegate = tab_contents()->delegate();
  if (tab_contents_delegate) {
    browser = tab_contents_delegate->GetBrowser();
    if (browser && browser->profile()->IsOffTheRecord() && !include_incognito) {
      // Fall back to the toplevel regular browser if we don't want to include
      // incognito browsers.
      browser = BrowserList::GetLastActiveWithProfile(
          browser->profile()->GetOriginalProfile());
    }
  }
  return browser;
}

Profile* ExtensionDOMUI::GetProfile() {
  return DOMUI::GetProfile();
}

gfx::NativeWindow ExtensionDOMUI::GetFrameNativeWindow() {
  gfx::NativeWindow native_window =
      ExtensionFunctionDispatcher::Delegate::GetFrameNativeWindow();

  // If there was no window associated with the function dispatcher delegate,
  // then this DOMUI may be hosted in an ExternalTabContainer, and a framing
  // window will be accessible through the tab_contents.
  if (!native_window) {
    TabContentsDelegate* tab_contents_delegate = tab_contents()->delegate();
    if (tab_contents_delegate)
      native_window = tab_contents_delegate->GetFrameNativeWindow();
  }

  return native_window;
}

gfx::NativeView ExtensionDOMUI::GetNativeViewOfHost() {
  return tab_contents()->GetRenderWidgetHostView()->GetNativeView();
}

////////////////////////////////////////////////////////////////////////////////
// chrome:// URL overrides

// static
void ExtensionDOMUI::RegisterUserPrefs(PrefService* prefs) {
  prefs->RegisterDictionaryPref(kExtensionURLOverrides);
}

// static
bool ExtensionDOMUI::HandleChromeURLOverride(GURL* url, Profile* profile) {
  if (!url->SchemeIs(chrome::kChromeUIScheme))
    return false;

  // Even when the extensions service is enabled by default, it's still
  // disabled in incognito mode.
  ExtensionsService* service = profile->GetExtensionsService();
  if (!service)
    return false;

  const DictionaryValue* overrides =
      profile->GetPrefs()->GetDictionary(kExtensionURLOverrides);
  std::string page = url->host();
  ListValue* url_list;
  if (!overrides || !overrides->GetList(UTF8ToWide(page), &url_list))
    return false;

  if (!service->is_ready()) {
    // TODO(erikkay) So far, it looks like extensions load before the new tab
    // page.  I don't know if we have anything that enforces this, so add this
    // check for safety.
    NOTREACHED() << "Chrome URL override requested before extensions loaded";
    return false;
  }

  while (url_list->GetSize()) {
    Value* val;
    url_list->Get(0, &val);

    // Verify that the override value is good.  If not, unregister it and find
    // the next one.
    std::string override;
    if (!val->GetAsString(&override)) {
      NOTREACHED();
      UnregisterChromeURLOverride(page, profile, val);
      continue;
    }
    GURL extension_url(override);
    if (!extension_url.is_valid()) {
      NOTREACHED();
      UnregisterChromeURLOverride(page, profile, val);
      continue;
    }

    // Verify that the extension that's being referred to actually exists.
    Extension* extension = service->GetExtensionByURL(extension_url);
    if (!extension) {
      // This can currently happen if you use --load-extension one run, and
      // then don't use it the next.  It could also happen if an extension
      // were deleted directly from the filesystem, etc.
      LOG(WARNING) << "chrome URL override present for non-existant extension";
      UnregisterChromeURLOverride(page, profile, val);
      continue;
    }

    *url = extension_url;
    return true;
  }
  return false;
}

// static
void ExtensionDOMUI::RegisterChromeURLOverrides(
    Profile* profile, const Extension::URLOverrideMap& overrides) {
  if (overrides.empty())
    return;

  PrefService* prefs = profile->GetPrefs();
  DictionaryValue* all_overrides =
      prefs->GetMutableDictionary(kExtensionURLOverrides);

  // For each override provided by the extension, add it to the front of
  // the override list if it's not already in the list.
  Extension::URLOverrideMap::const_iterator iter = overrides.begin();
  for (;iter != overrides.end(); ++iter) {
    const std::wstring key = UTF8ToWide((*iter).first);
    ListValue* page_overrides;
    if (!all_overrides->GetList(key, &page_overrides)) {
      page_overrides = new ListValue();
      all_overrides->Set(key, page_overrides);
    } else {
      // Verify that the override isn't already in the list.
      ListValue::iterator i = page_overrides->begin();
      for (; i != page_overrides->end(); ++i) {
        std::string override_val;
        if (!(*i)->GetAsString(&override_val)) {
          NOTREACHED();
          continue;
        }
        if (override_val == (*iter).first)
          break;
      }
      // This value is already in the list, leave it alone.
      if (i != page_overrides->end())
        continue;
    }
    // Insert the override at the front of the list.  Last registered override
    // wins.
    page_overrides->Insert(0, new StringValue((*iter).second.spec()));
  }
}

// static
void ExtensionDOMUI::UnregisterAndReplaceOverride(const std::string& page,
    Profile* profile, ListValue* list, Value* override) {
  int index = list->Remove(*override);
  if (index == 0) {
    // This is the active override, so we need to find all existing
    // tabs for this override and get them to reload the original URL.
    for (TabContentsIterator iterator; !iterator.done(); ++iterator) {
      TabContents* tab = *iterator;
      if (tab->profile() != profile)
        continue;

      GURL url = tab->GetURL();
      if (!url.SchemeIs(chrome::kChromeUIScheme) || url.host() != page)
        continue;

      // Don't use Reload() since |url| isn't the same as the internal URL
      // that NavigationController has.
      tab->controller().LoadURL(url, url, PageTransition::RELOAD);
    }
  }
}

// static
void ExtensionDOMUI::UnregisterChromeURLOverride(const std::string& page,
    Profile* profile, Value* override) {
  if (!override)
    return;
  PrefService* prefs = profile->GetPrefs();
  DictionaryValue* all_overrides =
      prefs->GetMutableDictionary(kExtensionURLOverrides);
  ListValue* page_overrides;
  if (!all_overrides->GetList(UTF8ToWide(page), &page_overrides)) {
    // If it's being unregistered, it should already be in the list.
    NOTREACHED();
    return;
  } else {
    UnregisterAndReplaceOverride(page, profile, page_overrides, override);
  }
}

RenderViewHost* ExtensionDOMUI::GetRenderViewHost() {
  return tab_contents() ? tab_contents()->render_view_host() : NULL;
}

// static
void ExtensionDOMUI::UnregisterChromeURLOverrides(
    Profile* profile, const Extension::URLOverrideMap& overrides) {
  if (overrides.empty())
    return;
  PrefService* prefs = profile->GetPrefs();
  DictionaryValue* all_overrides =
      prefs->GetMutableDictionary(kExtensionURLOverrides);
  Extension::URLOverrideMap::const_iterator iter = overrides.begin();
  for (;iter != overrides.end(); ++iter) {
    std::wstring page = UTF8ToWide((*iter).first);
    ListValue* page_overrides;
    if (!all_overrides->GetList(page, &page_overrides)) {
      // If it's being unregistered, it should already be in the list.
      NOTREACHED();
      continue;
    } else {
      StringValue override((*iter).second.spec());
      UnregisterAndReplaceOverride((*iter).first, profile,
                                   page_overrides, &override);
    }
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/message_loop.h"
#include "base/string16.h"
#include "chrome/browser/printing/print_job.h"
#include "chrome/browser/printing/print_job_worker.h"
#include "chrome/common/chrome_notification_types.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_service.h"
#include "printing/printed_pages_source.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace {

class TestSource : public printing::PrintedPagesSource {
 public:
  virtual string16 RenderSourceName() OVERRIDE {
    return string16();
  }
};

class TestPrintJobWorker : public printing::PrintJobWorker {
 public:
  explicit TestPrintJobWorker(printing::PrintJobWorkerOwner* owner)
      : printing::PrintJobWorker(owner) {
  }
  friend class TestOwner;
};

class TestOwner : public printing::PrintJobWorkerOwner {
 public:
  virtual void GetSettingsDone(const printing::PrintSettings& new_settings,
                               printing::PrintingContext::Result result) {
    EXPECT_FALSE(true);
  }
  virtual printing::PrintJobWorker* DetachWorker(
      printing::PrintJobWorkerOwner* new_owner) {
    // We're screwing up here since we're calling worker from the main thread.
    // That's fine for testing. It is actually simulating PrinterQuery behavior.
    TestPrintJobWorker* worker(new TestPrintJobWorker(new_owner));
    EXPECT_TRUE(worker->Start());
    worker->printing_context()->UseDefaultSettings();
    settings_ = worker->printing_context()->settings();
    return worker;
  }
  virtual MessageLoop* message_loop() {
    EXPECT_FALSE(true);
    return NULL;
  }
  virtual const printing::PrintSettings& settings() const {
    return settings_;
  }
  virtual int cookie() const {
    return 42;
  }

 private:
  printing::PrintSettings settings_;
};

class TestPrintJob : public printing::PrintJob {
 public:
  explicit TestPrintJob(volatile bool* check) : check_(check) {
  }
 private:
  ~TestPrintJob() {
    *check_ = true;
  }
  volatile bool* check_;
};

class TestPrintNotifObserv : public content::NotificationObserver {
 public:
  // content::NotificationObserver
  virtual void Observe(int type,
                       const content::NotificationSource& source,
                       const content::NotificationDetails& details) {
    ADD_FAILURE();
  }
};

}  // namespace

typedef testing::Test PrintJobTest;

// Crashes under Linux Aura, see http://crbug.com/100340
#if defined(USE_AURA) && !defined(OS_WIN)
#define MAYBE_SimplePrint DISABLED_SimplePrint
#else
#define MAYBE_SimplePrint SimplePrint
#endif
TEST_F(PrintJobTest, MAYBE_SimplePrint) {
  // Test the multi-threaded nature of PrintJob to make sure we can use it with
  // known lifetime.

  // This message loop is actually never run.
  MessageLoop current;

  content::NotificationRegistrar registrar_;
  TestPrintNotifObserv observ;
  registrar_.Add(&observ, content::NOTIFICATION_ALL,
                 content::NotificationService::AllSources());
  volatile bool check = false;
  scoped_refptr<printing::PrintJob> job(new TestPrintJob(&check));
  EXPECT_EQ(MessageLoop::current(), job->message_loop());
  scoped_refptr<TestOwner> owner(new TestOwner);
  TestSource source;
  job->Initialize(owner, &source, 1);
  job->Stop();
  job = NULL;
  EXPECT_TRUE(check);
}

TEST_F(PrintJobTest, SimplePrintLateInit) {
  volatile bool check = false;
  MessageLoop current;
  scoped_refptr<printing::PrintJob> job(new TestPrintJob(&check));
  job = NULL;
  EXPECT_TRUE(check);
  /* TODO(maruel): Test these.
  job->Initialize()
  job->Observe();
  job->GetSettingsDone();
  job->DetachWorker();
  job->message_loop();
  job->settings();
  job->cookie();
  job->GetSettings(printing::DEFAULTS, printing::ASK_USER, NULL);
  job->StartPrinting();
  job->Stop();
  job->Cancel();
  job->RequestMissingPages();
  job->FlushJob(timeout_ms);
  job->DisconnectSource();
  job->is_job_pending();
  job->document();
  // Private
  job->UpdatePrintedDocument(NULL);
  scoped_refptr<printing::JobEventDetails> event_details;
  job->OnNotifyPrintJobEvent(event_details);
  job->OnDocumentDone();
  job->ControlledWorkerShutdown();
  */
}
<commit_msg>Remove SimplePrint unit test issue from aura build.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/message_loop.h"
#include "base/string16.h"
#include "chrome/browser/printing/print_job.h"
#include "chrome/browser/printing/print_job_worker.h"
#include "chrome/common/chrome_notification_types.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_service.h"
#include "printing/printed_pages_source.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace {

class TestSource : public printing::PrintedPagesSource {
 public:
  virtual string16 RenderSourceName() OVERRIDE {
    return string16();
  }
};

class TestPrintJobWorker : public printing::PrintJobWorker {
 public:
  explicit TestPrintJobWorker(printing::PrintJobWorkerOwner* owner)
      : printing::PrintJobWorker(owner) {
  }
  friend class TestOwner;
};

class TestOwner : public printing::PrintJobWorkerOwner {
 public:
  virtual void GetSettingsDone(const printing::PrintSettings& new_settings,
                               printing::PrintingContext::Result result) {
    EXPECT_FALSE(true);
  }
  virtual printing::PrintJobWorker* DetachWorker(
      printing::PrintJobWorkerOwner* new_owner) {
    // We're screwing up here since we're calling worker from the main thread.
    // That's fine for testing. It is actually simulating PrinterQuery behavior.
    TestPrintJobWorker* worker(new TestPrintJobWorker(new_owner));
    EXPECT_TRUE(worker->Start());
    worker->printing_context()->UseDefaultSettings();
    settings_ = worker->printing_context()->settings();
    return worker;
  }
  virtual MessageLoop* message_loop() {
    EXPECT_FALSE(true);
    return NULL;
  }
  virtual const printing::PrintSettings& settings() const {
    return settings_;
  }
  virtual int cookie() const {
    return 42;
  }

 private:
  printing::PrintSettings settings_;
};

class TestPrintJob : public printing::PrintJob {
 public:
  explicit TestPrintJob(volatile bool* check) : check_(check) {
  }
 private:
  ~TestPrintJob() {
    *check_ = true;
  }
  volatile bool* check_;
};

class TestPrintNotifObserv : public content::NotificationObserver {
 public:
  // content::NotificationObserver
  virtual void Observe(int type,
                       const content::NotificationSource& source,
                       const content::NotificationDetails& details) {
    ADD_FAILURE();
  }
};

}  // namespace

typedef testing::Test PrintJobTest;

#if !defined(USE_AURA)
TEST_F(PrintJobTest, SimplePrint) {
  // Test the multi-threaded nature of PrintJob to make sure we can use it with
  // known lifetime.

  // This message loop is actually never run.
  MessageLoop current;

  content::NotificationRegistrar registrar_;
  TestPrintNotifObserv observ;
  registrar_.Add(&observ, content::NOTIFICATION_ALL,
                 content::NotificationService::AllSources());
  volatile bool check = false;
  scoped_refptr<printing::PrintJob> job(new TestPrintJob(&check));
  EXPECT_EQ(MessageLoop::current(), job->message_loop());
  scoped_refptr<TestOwner> owner(new TestOwner);
  TestSource source;
  job->Initialize(owner, &source, 1);
  job->Stop();
  job = NULL;
  EXPECT_TRUE(check);
}
#endif

TEST_F(PrintJobTest, SimplePrintLateInit) {
  volatile bool check = false;
  MessageLoop current;
  scoped_refptr<printing::PrintJob> job(new TestPrintJob(&check));
  job = NULL;
  EXPECT_TRUE(check);
  /* TODO(maruel): Test these.
  job->Initialize()
  job->Observe();
  job->GetSettingsDone();
  job->DetachWorker();
  job->message_loop();
  job->settings();
  job->cookie();
  job->GetSettings(printing::DEFAULTS, printing::ASK_USER, NULL);
  job->StartPrinting();
  job->Stop();
  job->Cancel();
  job->RequestMissingPages();
  job->FlushJob(timeout_ms);
  job->DisconnectSource();
  job->is_job_pending();
  job->document();
  // Private
  job->UpdatePrintedDocument(NULL);
  scoped_refptr<printing::JobEventDetails> event_details;
  job->OnNotifyPrintJobEvent(event_details);
  job->OnDocumentDone();
  job->ControlledWorkerShutdown();
  */
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/automation/url_request_automation_job.h"

#include "base/message_loop.h"
#include "base/time.h"
#include "chrome/browser/automation/automation_resource_message_filter.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/test/automation/automation_messages.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/http/http_util.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"

using base::Time;
using base::TimeDelta;

// The list of filtered headers that are removed from requests sent via
// StartAsync(). These must be lower case.
static const char* kFilteredHeaderStrings[] = {
  "accept",
  "authorization",
  "cache-control",
  "connection",
  "cookie",
  "expect",
  "if-match",
  "if-modified-since",
  "if-none-match",
  "if-range",
  "if-unmodified-since",
  "max-forwards",
  "proxy-authorization",
  "te",
  "upgrade",
  "via"
};

// This class manages the interception of network requests for automation.
// It looks at the request, and creates an intercept job if it indicates
// that it should use automation channel.
// NOTE: All methods must be called on the IO thread.
class AutomationRequestInterceptor : public URLRequest::Interceptor {
 public:
  AutomationRequestInterceptor() {
    URLRequest::RegisterRequestInterceptor(this);
  }

  virtual ~AutomationRequestInterceptor() {
    URLRequest::UnregisterRequestInterceptor(this);
  }

  // URLRequest::Interceptor
  virtual URLRequestJob* MaybeIntercept(URLRequest* request);

 private:
  DISALLOW_COPY_AND_ASSIGN(AutomationRequestInterceptor);
};

URLRequestJob* AutomationRequestInterceptor::MaybeIntercept(
    URLRequest* request) {
  ResourceDispatcherHost::ExtraRequestInfo* request_info =
      ResourceDispatcherHost::ExtraInfoForRequest(request);
  if (request_info) {
    AutomationResourceMessageFilter::AutomationDetails details;
    if (AutomationResourceMessageFilter::LookupRegisteredRenderView(
            request_info->process_id, request_info->route_id, &details)) {
      URLRequestAutomationJob* job = new URLRequestAutomationJob(request,
          details.tab_handle, details.filter);
      return job;
    }
  }

  return NULL;
}

static URLRequest::Interceptor* GetAutomationRequestInterceptor() {
  return Singleton<AutomationRequestInterceptor>::get();
}

int URLRequestAutomationJob::instance_count_ = 0;

URLRequestAutomationJob::URLRequestAutomationJob(
    URLRequest* request, int tab, AutomationResourceMessageFilter* filter)
    : URLRequestJob(request), id_(0), tab_(tab), message_filter_(filter),
      pending_buf_size_(0) {
  DLOG(INFO) << "URLRequestAutomationJob create. Count: " << ++instance_count_;
  if (message_filter_) {
    id_ = message_filter_->NewRequestId();
    DCHECK(id_);
  } else {
    NOTREACHED();
  }
}

URLRequestAutomationJob::~URLRequestAutomationJob() {
  DLOG(INFO) << "URLRequestAutomationJob delete. Count: " << --instance_count_;
  Cleanup();
}

bool URLRequestAutomationJob::InitializeInterceptor() {
  // AutomationRequestInterceptor will register itself when it
  // is first created.
  URLRequest::Interceptor* interceptor = GetAutomationRequestInterceptor();
  return (interceptor != NULL);
}

// URLRequestJob Implementation.
void URLRequestAutomationJob::Start() {
  // Start reading asynchronously so that all error reporting and data
  // callbacks happen as they would for network requests.
  MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
      this, &URLRequestAutomationJob::StartAsync));
}

void URLRequestAutomationJob::Kill() {
  if (message_filter_.get()) {
    message_filter_->Send(new AutomationMsg_RequestEnd(0, tab_, id_,
        URLRequestStatus(URLRequestStatus::CANCELED, 0)));
  }
  DisconnectFromMessageFilter();
  URLRequestJob::Kill();
}

bool URLRequestAutomationJob::ReadRawData(
    net::IOBuffer* buf, int buf_size, int* bytes_read) {
  DLOG(INFO) << "URLRequestAutomationJob: " <<
      request_->url().spec() << " - read pending: " << buf_size;
  pending_buf_ = buf;
  pending_buf_size_ = buf_size;

  message_filter_->Send(new AutomationMsg_RequestRead(0, tab_, id_,
      buf_size));
  SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
  return false;
}

bool URLRequestAutomationJob::GetMimeType(std::string* mime_type) const {
  if (!mime_type_.empty()) {
    *mime_type = mime_type_;
  } else if (headers_) {
    headers_->GetMimeType(mime_type);
  }

  return (!mime_type->empty());
}

bool URLRequestAutomationJob::GetCharset(std::string* charset) {
  if (headers_)
    return headers_->GetCharset(charset);
  return false;
}

void URLRequestAutomationJob::GetResponseInfo(net::HttpResponseInfo* info) {
  if (headers_)
    info->headers = headers_;
  if (request_->url().SchemeIsSecure()) {
    // Make up a fake certificate for this response since we don't have
    // access to the real SSL info.
    const char* kCertIssuer = "Chrome Internal";
    const int kLifetimeDays = 100;

    info->ssl_info.cert =
        new net::X509Certificate(request_->url().GetWithEmptyPath().spec(),
                                 kCertIssuer,
                                 Time::Now(),
                                 Time::Now() +
                                     TimeDelta::FromDays(kLifetimeDays));
    info->ssl_info.cert_status = 0;
    info->ssl_info.security_bits = 0;
  }
}

int URLRequestAutomationJob::GetResponseCode() const {
  if (headers_)
    return headers_->response_code();

  static const int kDefaultResponseCode = 200;
  return kDefaultResponseCode;
}

bool URLRequestAutomationJob::IsRedirectResponse(
    GURL* location, int* http_status_code) {
  static const int kHttpRedirectResponseCode = 301;

  if (!redirect_url_.empty()) {
    *http_status_code = kHttpRedirectResponseCode;
    *location = GURL(redirect_url_);
    return true;
  }
  return false;
}

int URLRequestAutomationJob::MayFilterMessage(const IPC::Message& message) {
  switch (message.type()) {
    case AutomationMsg_RequestStarted::ID:
    case AutomationMsg_RequestData::ID:
    case AutomationMsg_RequestEnd::ID: {
      void* iter = NULL;
      int tab = 0;
      int id = 0;
      if (message.ReadInt(&iter, &tab) && message.ReadInt(&iter, &id)) {
        DCHECK(id);
        return id;
      }
      break;
    }
  }

  return 0;
}

void URLRequestAutomationJob::OnMessage(const IPC::Message& message) {
  IPC_BEGIN_MESSAGE_MAP(URLRequestAutomationJob, message)
    IPC_MESSAGE_HANDLER(AutomationMsg_RequestStarted, OnRequestStarted)
    IPC_MESSAGE_HANDLER(AutomationMsg_RequestData, OnDataAvailable)
    IPC_MESSAGE_HANDLER(AutomationMsg_RequestEnd, OnRequestEnd)
  IPC_END_MESSAGE_MAP()
}

void URLRequestAutomationJob::OnRequestStarted(
    int tab, int id, const IPC::AutomationURLResponse& response) {
  DLOG(INFO) << "URLRequestAutomationJob: " <<
      request_->url().spec() << " - response started.";
  set_expected_content_size(response.content_length);
  mime_type_ = response.mime_type;

  redirect_url_ = response.redirect_url;

  GURL url_for_cookies =
      GURL(redirect_url_.empty() ? request_->url().spec().c_str() :
          redirect_url_.c_str());

  URLRequestContext* ctx = request_->context();

  if (!response.headers.empty()) {
    headers_ = new net::HttpResponseHeaders(
        net::HttpUtil::AssembleRawHeaders(response.headers.data(),
                                          response.headers.size()));
    // Parse and set HTTP cookies.
    const std::string name = "Set-Cookie";
    std::string value;
    std::vector<std::string> response_cookies;

    void* iter = NULL;
    while (headers_->EnumerateHeader(&iter, name, &value)) {
      if (request_->context()->InterceptCookie(request_, &value))
        response_cookies.push_back(value);
    }

    if (response_cookies.size()) {
      if (ctx && ctx->cookie_store() &&
          ctx->cookie_policy()->CanSetCookie(
              url_for_cookies, request_->first_party_for_cookies())) {
        net::CookieOptions options;
        options.set_include_httponly();
        ctx->cookie_store()->SetCookiesWithOptions(url_for_cookies,
                                                   response_cookies,
                                                   options);
      }
    }
  }

  if (ctx && ctx->cookie_store() && !response.persistent_cookies.empty() &&
      ctx->cookie_policy()->CanSetCookie(
          url_for_cookies, request_->first_party_for_cookies())) {
    StringTokenizer cookie_parser(response.persistent_cookies, ";");

    while (cookie_parser.GetNext()) {
      net::CookieOptions options;
      ctx->cookie_store()->SetCookieWithOptions(url_for_cookies,
                                                cookie_parser.token(),
                                                options);
    }
  }

  NotifyHeadersComplete();
}

void URLRequestAutomationJob::OnDataAvailable(
    int tab, int id, const std::string& bytes) {
  DLOG(INFO) << "URLRequestAutomationJob: " <<
      request_->url().spec() << " - data available, Size: " << bytes.size();
  DCHECK(!bytes.empty());

  // The request completed, and we have all the data.
  // Clear any IO pending status.
  SetStatus(URLRequestStatus());

  if (pending_buf_ && pending_buf_->data()) {
    DCHECK_GE(pending_buf_size_, bytes.size());
    const int bytes_to_copy = std::min(bytes.size(), pending_buf_size_);
    memcpy(pending_buf_->data(), &bytes[0], bytes_to_copy);

    pending_buf_ = NULL;
    pending_buf_size_ = 0;

    NotifyReadComplete(bytes_to_copy);
  }
}

void URLRequestAutomationJob::OnRequestEnd(
    int tab, int id, const URLRequestStatus& status) {
  DLOG(INFO) << "URLRequestAutomationJob: " <<
      request_->url().spec() << " - request end. Status: " << status.status();

  DisconnectFromMessageFilter();
  NotifyDone(status);

  // Reset any pending reads.
  if (pending_buf_) {
    pending_buf_ = NULL;
    pending_buf_size_ = 0;
    NotifyReadComplete(0);
  }
}

void URLRequestAutomationJob::Cleanup() {
  headers_ = NULL;
  mime_type_.erase();

  id_ = 0;
  tab_ = 0;

  DCHECK(message_filter_ == NULL);
  DisconnectFromMessageFilter();

  pending_buf_ = NULL;
  pending_buf_size_ = 0;
}

void URLRequestAutomationJob::StartAsync() {
  DLOG(INFO) << "URLRequestAutomationJob: start request: " <<
      (request_ ? request_->url().spec() : "NULL request");

  // If the job is cancelled before we got a chance to start it
  // we have nothing much to do here.
  if (is_done())
    return;

  if (!request_) {
    NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED,
        net::ERR_FAILED));
    return;
  }

  // Register this request with automation message filter.
  message_filter_->RegisterRequest(this);

  // Strip unwanted headers.
  std::string new_request_headers(
      net::HttpUtil::StripHeaders(request_->extra_request_headers(),
                                  kFilteredHeaderStrings,
                                  arraysize(kFilteredHeaderStrings)));

  // Ask automation to start this request.
  IPC::AutomationURLRequest automation_request = {
    request_->url().spec(),
    request_->method(),
    request_->referrer(),
    new_request_headers,
    request_->get_upload()
  };

  DCHECK(message_filter_);
  message_filter_->Send(new AutomationMsg_RequestStart(0, tab_, id_,
      automation_request));
}

void URLRequestAutomationJob::DisconnectFromMessageFilter() {
  if (message_filter_) {
    message_filter_->UnRegisterRequest(this);
    message_filter_ = NULL;
  }
}
<commit_msg>We should only handle http and https in the URL job created to enable automation clients to handle URL requests.<commit_after>// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/automation/url_request_automation_job.h"

#include "base/message_loop.h"
#include "base/time.h"
#include "chrome/browser/automation/automation_resource_message_filter.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/test/automation/automation_messages.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/http/http_util.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"

using base::Time;
using base::TimeDelta;

// The list of filtered headers that are removed from requests sent via
// StartAsync(). These must be lower case.
static const char* kFilteredHeaderStrings[] = {
  "accept",
  "authorization",
  "cache-control",
  "connection",
  "cookie",
  "expect",
  "if-match",
  "if-modified-since",
  "if-none-match",
  "if-range",
  "if-unmodified-since",
  "max-forwards",
  "proxy-authorization",
  "te",
  "upgrade",
  "via"
};

// This class manages the interception of network requests for automation.
// It looks at the request, and creates an intercept job if it indicates
// that it should use automation channel.
// NOTE: All methods must be called on the IO thread.
class AutomationRequestInterceptor : public URLRequest::Interceptor {
 public:
  AutomationRequestInterceptor() {
    URLRequest::RegisterRequestInterceptor(this);
  }

  virtual ~AutomationRequestInterceptor() {
    URLRequest::UnregisterRequestInterceptor(this);
  }

  // URLRequest::Interceptor
  virtual URLRequestJob* MaybeIntercept(URLRequest* request);

 private:
  DISALLOW_COPY_AND_ASSIGN(AutomationRequestInterceptor);
};

URLRequestJob* AutomationRequestInterceptor::MaybeIntercept(
    URLRequest* request) {
  if (request->url().SchemeIs("http") || request->url().SchemeIs("https")) {
    ResourceDispatcherHost::ExtraRequestInfo* request_info =
        ResourceDispatcherHost::ExtraInfoForRequest(request);
    if (request_info) {
      AutomationResourceMessageFilter::AutomationDetails details;
      if (AutomationResourceMessageFilter::LookupRegisteredRenderView(
              request_info->process_id, request_info->route_id, &details)) {
        URLRequestAutomationJob* job = new URLRequestAutomationJob(request,
            details.tab_handle, details.filter);
        return job;
      }
    }
  }

  return NULL;
}

static URLRequest::Interceptor* GetAutomationRequestInterceptor() {
  return Singleton<AutomationRequestInterceptor>::get();
}

int URLRequestAutomationJob::instance_count_ = 0;

URLRequestAutomationJob::URLRequestAutomationJob(
    URLRequest* request, int tab, AutomationResourceMessageFilter* filter)
    : URLRequestJob(request), id_(0), tab_(tab), message_filter_(filter),
      pending_buf_size_(0) {
  DLOG(INFO) << "URLRequestAutomationJob create. Count: " << ++instance_count_;
  if (message_filter_) {
    id_ = message_filter_->NewRequestId();
    DCHECK(id_);
  } else {
    NOTREACHED();
  }
}

URLRequestAutomationJob::~URLRequestAutomationJob() {
  DLOG(INFO) << "URLRequestAutomationJob delete. Count: " << --instance_count_;
  Cleanup();
}

bool URLRequestAutomationJob::InitializeInterceptor() {
  // AutomationRequestInterceptor will register itself when it
  // is first created.
  URLRequest::Interceptor* interceptor = GetAutomationRequestInterceptor();
  return (interceptor != NULL);
}

// URLRequestJob Implementation.
void URLRequestAutomationJob::Start() {
  // Start reading asynchronously so that all error reporting and data
  // callbacks happen as they would for network requests.
  MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
      this, &URLRequestAutomationJob::StartAsync));
}

void URLRequestAutomationJob::Kill() {
  if (message_filter_.get()) {
    message_filter_->Send(new AutomationMsg_RequestEnd(0, tab_, id_,
        URLRequestStatus(URLRequestStatus::CANCELED, 0)));
  }
  DisconnectFromMessageFilter();
  URLRequestJob::Kill();
}

bool URLRequestAutomationJob::ReadRawData(
    net::IOBuffer* buf, int buf_size, int* bytes_read) {
  DLOG(INFO) << "URLRequestAutomationJob: " <<
      request_->url().spec() << " - read pending: " << buf_size;
  pending_buf_ = buf;
  pending_buf_size_ = buf_size;

  message_filter_->Send(new AutomationMsg_RequestRead(0, tab_, id_,
      buf_size));
  SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
  return false;
}

bool URLRequestAutomationJob::GetMimeType(std::string* mime_type) const {
  if (!mime_type_.empty()) {
    *mime_type = mime_type_;
  } else if (headers_) {
    headers_->GetMimeType(mime_type);
  }

  return (!mime_type->empty());
}

bool URLRequestAutomationJob::GetCharset(std::string* charset) {
  if (headers_)
    return headers_->GetCharset(charset);
  return false;
}

void URLRequestAutomationJob::GetResponseInfo(net::HttpResponseInfo* info) {
  if (headers_)
    info->headers = headers_;
  if (request_->url().SchemeIsSecure()) {
    // Make up a fake certificate for this response since we don't have
    // access to the real SSL info.
    const char* kCertIssuer = "Chrome Internal";
    const int kLifetimeDays = 100;

    info->ssl_info.cert =
        new net::X509Certificate(request_->url().GetWithEmptyPath().spec(),
                                 kCertIssuer,
                                 Time::Now(),
                                 Time::Now() +
                                     TimeDelta::FromDays(kLifetimeDays));
    info->ssl_info.cert_status = 0;
    info->ssl_info.security_bits = 0;
  }
}

int URLRequestAutomationJob::GetResponseCode() const {
  if (headers_)
    return headers_->response_code();

  static const int kDefaultResponseCode = 200;
  return kDefaultResponseCode;
}

bool URLRequestAutomationJob::IsRedirectResponse(
    GURL* location, int* http_status_code) {
  static const int kHttpRedirectResponseCode = 301;

  if (!redirect_url_.empty()) {
    *http_status_code = kHttpRedirectResponseCode;
    *location = GURL(redirect_url_);
    return true;
  }
  return false;
}

int URLRequestAutomationJob::MayFilterMessage(const IPC::Message& message) {
  switch (message.type()) {
    case AutomationMsg_RequestStarted::ID:
    case AutomationMsg_RequestData::ID:
    case AutomationMsg_RequestEnd::ID: {
      void* iter = NULL;
      int tab = 0;
      int id = 0;
      if (message.ReadInt(&iter, &tab) && message.ReadInt(&iter, &id)) {
        DCHECK(id);
        return id;
      }
      break;
    }
  }

  return 0;
}

void URLRequestAutomationJob::OnMessage(const IPC::Message& message) {
  IPC_BEGIN_MESSAGE_MAP(URLRequestAutomationJob, message)
    IPC_MESSAGE_HANDLER(AutomationMsg_RequestStarted, OnRequestStarted)
    IPC_MESSAGE_HANDLER(AutomationMsg_RequestData, OnDataAvailable)
    IPC_MESSAGE_HANDLER(AutomationMsg_RequestEnd, OnRequestEnd)
  IPC_END_MESSAGE_MAP()
}

void URLRequestAutomationJob::OnRequestStarted(
    int tab, int id, const IPC::AutomationURLResponse& response) {
  DLOG(INFO) << "URLRequestAutomationJob: " <<
      request_->url().spec() << " - response started.";
  set_expected_content_size(response.content_length);
  mime_type_ = response.mime_type;

  redirect_url_ = response.redirect_url;

  GURL url_for_cookies =
      GURL(redirect_url_.empty() ? request_->url().spec().c_str() :
          redirect_url_.c_str());

  URLRequestContext* ctx = request_->context();

  if (!response.headers.empty()) {
    headers_ = new net::HttpResponseHeaders(
        net::HttpUtil::AssembleRawHeaders(response.headers.data(),
                                          response.headers.size()));
    // Parse and set HTTP cookies.
    const std::string name = "Set-Cookie";
    std::string value;
    std::vector<std::string> response_cookies;

    void* iter = NULL;
    while (headers_->EnumerateHeader(&iter, name, &value)) {
      if (request_->context()->InterceptCookie(request_, &value))
        response_cookies.push_back(value);
    }

    if (response_cookies.size()) {
      if (ctx && ctx->cookie_store() &&
          ctx->cookie_policy()->CanSetCookie(
              url_for_cookies, request_->first_party_for_cookies())) {
        net::CookieOptions options;
        options.set_include_httponly();
        ctx->cookie_store()->SetCookiesWithOptions(url_for_cookies,
                                                   response_cookies,
                                                   options);
      }
    }
  }

  if (ctx && ctx->cookie_store() && !response.persistent_cookies.empty() &&
      ctx->cookie_policy()->CanSetCookie(
          url_for_cookies, request_->first_party_for_cookies())) {
    StringTokenizer cookie_parser(response.persistent_cookies, ";");

    while (cookie_parser.GetNext()) {
      net::CookieOptions options;
      ctx->cookie_store()->SetCookieWithOptions(url_for_cookies,
                                                cookie_parser.token(),
                                                options);
    }
  }

  NotifyHeadersComplete();
}

void URLRequestAutomationJob::OnDataAvailable(
    int tab, int id, const std::string& bytes) {
  DLOG(INFO) << "URLRequestAutomationJob: " <<
      request_->url().spec() << " - data available, Size: " << bytes.size();
  DCHECK(!bytes.empty());

  // The request completed, and we have all the data.
  // Clear any IO pending status.
  SetStatus(URLRequestStatus());

  if (pending_buf_ && pending_buf_->data()) {
    DCHECK_GE(pending_buf_size_, bytes.size());
    const int bytes_to_copy = std::min(bytes.size(), pending_buf_size_);
    memcpy(pending_buf_->data(), &bytes[0], bytes_to_copy);

    pending_buf_ = NULL;
    pending_buf_size_ = 0;

    NotifyReadComplete(bytes_to_copy);
  }
}

void URLRequestAutomationJob::OnRequestEnd(
    int tab, int id, const URLRequestStatus& status) {
  DLOG(INFO) << "URLRequestAutomationJob: " <<
      request_->url().spec() << " - request end. Status: " << status.status();

  DisconnectFromMessageFilter();
  NotifyDone(status);

  // Reset any pending reads.
  if (pending_buf_) {
    pending_buf_ = NULL;
    pending_buf_size_ = 0;
    NotifyReadComplete(0);
  }
}

void URLRequestAutomationJob::Cleanup() {
  headers_ = NULL;
  mime_type_.erase();

  id_ = 0;
  tab_ = 0;

  DCHECK(message_filter_ == NULL);
  DisconnectFromMessageFilter();

  pending_buf_ = NULL;
  pending_buf_size_ = 0;
}

void URLRequestAutomationJob::StartAsync() {
  DLOG(INFO) << "URLRequestAutomationJob: start request: " <<
      (request_ ? request_->url().spec() : "NULL request");

  // If the job is cancelled before we got a chance to start it
  // we have nothing much to do here.
  if (is_done())
    return;

  if (!request_) {
    NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED,
        net::ERR_FAILED));
    return;
  }

  // Register this request with automation message filter.
  message_filter_->RegisterRequest(this);

  // Strip unwanted headers.
  std::string new_request_headers(
      net::HttpUtil::StripHeaders(request_->extra_request_headers(),
                                  kFilteredHeaderStrings,
                                  arraysize(kFilteredHeaderStrings)));

  // Ask automation to start this request.
  IPC::AutomationURLRequest automation_request = {
    request_->url().spec(),
    request_->method(),
    request_->referrer(),
    new_request_headers,
    request_->get_upload()
  };

  DCHECK(message_filter_);
  message_filter_->Send(new AutomationMsg_RequestStart(0, tab_, id_,
      automation_request));
}

void URLRequestAutomationJob::DisconnectFromMessageFilter() {
  if (message_filter_) {
    message_filter_->UnRegisterRequest(this);
    message_filter_ = NULL;
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/sync/glue/preference_model_associator.h"

#include "base/json/json_reader.h"
#include "base/logging.h"
#include "base/values.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/synchronized_preferences.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/protocol/preference_specifics.pb.h"
#include "chrome/common/json_value_serializer.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"

namespace browser_sync {

PreferenceModelAssociator::PreferenceModelAssociator(
    ProfileSyncService* sync_service)
    : sync_service_(sync_service),
      preferences_node_id_(sync_api::kInvalidId) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK(sync_service_);

  // Add the list of kSynchronizedPreferences to our local
  // synced_preferences set, taking care to filter out any preferences
  // that are not registered.
  PrefService* pref_service = sync_service_->profile()->GetPrefs();
  for (size_t i = 0; i < arraysize(kSynchronizedPreferences); ++i) {
    if (pref_service->FindPreference(kSynchronizedPreferences[i]))
      synced_preferences_.insert(kSynchronizedPreferences[i]);
  }
}

PreferenceModelAssociator::~PreferenceModelAssociator() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}

bool PreferenceModelAssociator::InitPrefNodeAndAssociate(
    sync_api::WriteTransaction* trans,
    const sync_api::BaseNode& root,
    const PrefService::Preference* pref) {
  DCHECK(pref);

  PrefService* pref_service = sync_service_->profile()->GetPrefs();
  base::JSONReader reader;
  std::string tag = pref->name();
  sync_api::WriteNode node(trans);
  if (node.InitByClientTagLookup(syncable::PREFERENCES, tag)) {
    // The server has a value for the preference.
    const sync_pb::PreferenceSpecifics& preference(
        node.GetPreferenceSpecifics());
    DCHECK_EQ(tag, preference.name());

    if (pref->IsUserModifiable()) {
      scoped_ptr<Value> value(
          reader.JsonToValue(preference.value(), false, false));
      std::string pref_name = preference.name();
      if (!value.get()) {
        LOG(ERROR) << "Failed to deserialize preference value: "
                   << reader.GetErrorMessage();
        return false;
      }

      // Merge the server value of this preference with the local value.
      scoped_ptr<Value> new_value(MergePreference(*pref, *value));

      // Update the local preference based on what we got from the
      // sync server.
      if (!pref->GetValue()->Equals(new_value.get()))
        pref_service->Set(pref_name.c_str(), *new_value);

      AfterUpdateOperations(pref_name);

      // If the merge resulted in an updated value, write it back to
      // the sync node.
      if (!value->Equals(new_value.get()) &&
          !WritePreferenceToNode(pref->name(), *new_value, &node))
        return false;
    }
    Associate(pref, node.GetId());
  } else if (pref->IsUserControlled()) {
    // The server doesn't have a value, but we have a user-controlled value,
    // so we push it to the server.
    sync_api::WriteNode write_node(trans);
    if (!write_node.InitUniqueByCreation(syncable::PREFERENCES, root, tag)) {
      LOG(ERROR) << "Failed to create preference sync node.";
      return false;
    }

    // Update the sync node with the local value for this preference.
    if (!WritePreferenceToNode(pref->name(), *pref->GetValue(), &write_node))
      return false;

    Associate(pref, write_node.GetId());
  }

  return true;
}

bool PreferenceModelAssociator::AssociateModels() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  PrefService* pref_service = sync_service_->profile()->GetPrefs();

  int64 root_id;
  if (!GetSyncIdForTaggedNode(kPreferencesTag, &root_id)) {
    LOG(ERROR) << "Server did not create the top-level preferences node. We "
               << "might be running against an out-of-date server.";
    return false;
  }

  sync_api::WriteTransaction trans(sync_service_->GetUserShare());
  sync_api::ReadNode root(&trans);
  if (!root.InitByIdLookup(root_id)) {
    LOG(ERROR) << "Server did not create the top-level preferences node. We "
               << "might be running against an out-of-date server.";
    return false;
  }

  for (std::set<std::string>::iterator it = synced_preferences_.begin();
       it != synced_preferences_.end(); ++it) {
    const PrefService::Preference* pref =
        pref_service->FindPreference((*it).c_str());
    InitPrefNodeAndAssociate(&trans, root, pref);
  }
  return true;
}

bool PreferenceModelAssociator::DisassociateModels() {
  id_map_.clear();
  id_map_inverse_.clear();
  return true;
}

bool PreferenceModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) {
  DCHECK(has_nodes);
  *has_nodes = false;
  int64 preferences_sync_id;
  if (!GetSyncIdForTaggedNode(kPreferencesTag, &preferences_sync_id)) {
    LOG(ERROR) << "Server did not create the top-level preferences node. We "
               << "might be running against an out-of-date server.";
    return false;
  }
  sync_api::ReadTransaction trans(sync_service_->GetUserShare());

  sync_api::ReadNode preferences_node(&trans);
  if (!preferences_node.InitByIdLookup(preferences_sync_id)) {
    LOG(ERROR) << "Server did not create the top-level preferences node. We "
               << "might be running against an out-of-date server.";
    return false;
  }

  // The sync model has user created nodes if the preferences folder has any
  // children.
  *has_nodes = sync_api::kInvalidId != preferences_node.GetFirstChildId();
  return true;
}

const PrefService::Preference*
PreferenceModelAssociator::GetChromeNodeFromSyncId(int64 sync_id) {
  return NULL;
}

bool PreferenceModelAssociator::InitSyncNodeFromChromeId(
    const std::string& node_id,
    sync_api::BaseNode* sync_node) {
  return false;
}

int64 PreferenceModelAssociator::GetSyncIdFromChromeId(
    const std::string& preference_name) {
  PreferenceNameToSyncIdMap::const_iterator iter =
      id_map_.find(preference_name);
  return iter == id_map_.end() ? sync_api::kInvalidId : iter->second;
}

void PreferenceModelAssociator::Associate(
    const PrefService::Preference* preference, int64 sync_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK_NE(sync_api::kInvalidId, sync_id);
  DCHECK(id_map_.find(preference->name()) == id_map_.end());
  DCHECK(id_map_inverse_.find(sync_id) == id_map_inverse_.end());
  id_map_[preference->name()] = sync_id;
  id_map_inverse_[sync_id] = preference->name();
}

void PreferenceModelAssociator::Disassociate(int64 sync_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  SyncIdToPreferenceNameMap::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);
}

bool PreferenceModelAssociator::GetSyncIdForTaggedNode(const std::string& tag,
                                                       int64* sync_id) {
  sync_api::ReadTransaction trans(sync_service_->GetUserShare());
  sync_api::ReadNode sync_node(&trans);
  if (!sync_node.InitByTagLookup(tag.c_str()))
    return false;
  *sync_id = sync_node.GetId();
  return true;
}

Value* PreferenceModelAssociator::MergePreference(
    const PrefService::Preference& local_pref,
    const Value& server_value) {
  const std::string& name(local_pref.name());
  if (name == prefs::kURLsToRestoreOnStartup ||
      name == prefs::kDesktopNotificationAllowedOrigins ||
      name == prefs::kDesktopNotificationDeniedOrigins) {
    return MergeListValues(*local_pref.GetValue(), server_value);
  }

  if (name == prefs::kContentSettingsPatterns ||
      name == prefs::kGeolocationContentSettings) {
    return MergeDictionaryValues(*local_pref.GetValue(), server_value);
  }

  // If this is not a specially handled preference, server wins.
  return server_value.DeepCopy();
}

bool PreferenceModelAssociator::WritePreferenceToNode(
    const std::string& name,
    const Value& value,
    sync_api::WriteNode* node) {
  std::string serialized;
  JSONStringValueSerializer json(&serialized);
  if (!json.Serialize(value)) {
    LOG(ERROR) << "Failed to serialize preference value.";
    return false;
  }

  sync_pb::PreferenceSpecifics preference;
  preference.set_name(name);
  preference.set_value(serialized);
  node->SetPreferenceSpecifics(preference);
  // TODO(viettrungluu): eliminate conversion (it's temporary)
  node->SetTitle(UTF8ToWide(name));
  return true;
}

Value* PreferenceModelAssociator::MergeListValues(const Value& from_value,
                                                  const Value& to_value) {
  if (from_value.GetType() == Value::TYPE_NULL)
    return to_value.DeepCopy();
  if (to_value.GetType() == Value::TYPE_NULL)
    return from_value.DeepCopy();

  DCHECK(from_value.GetType() == Value::TYPE_LIST);
  DCHECK(to_value.GetType() == Value::TYPE_LIST);
  const ListValue& from_list_value = static_cast<const ListValue&>(from_value);
  const ListValue& to_list_value = static_cast<const ListValue&>(to_value);
  ListValue* result = to_list_value.DeepCopy();

  for (ListValue::const_iterator i = from_list_value.begin();
       i != from_list_value.end(); ++i) {
    Value* value = (*i)->DeepCopy();
    if (!result->AppendIfNotPresent(value))
      delete value;
  }
  return result;
}

Value* PreferenceModelAssociator::MergeDictionaryValues(
    const Value& from_value,
    const Value& to_value) {
  if (from_value.GetType() == Value::TYPE_NULL)
    return to_value.DeepCopy();
  if (to_value.GetType() == Value::TYPE_NULL)
    return from_value.DeepCopy();

  DCHECK(from_value.GetType() == Value::TYPE_DICTIONARY);
  DCHECK(to_value.GetType() == Value::TYPE_DICTIONARY);
  const DictionaryValue& from_dict_value =
      static_cast<const DictionaryValue&>(from_value);
  const DictionaryValue& to_dict_value =
      static_cast<const DictionaryValue&>(to_value);
  DictionaryValue* result = to_dict_value.DeepCopy();

  for (DictionaryValue::key_iterator key = from_dict_value.begin_keys();
       key != from_dict_value.end_keys(); ++key) {
    Value* from_value;
    bool success = from_dict_value.GetWithoutPathExpansion(*key, &from_value);
    DCHECK(success);

    Value* to_key_value;
    if (result->GetWithoutPathExpansion(*key, &to_key_value)) {
      if (to_key_value->GetType() == Value::TYPE_DICTIONARY) {
        Value* merged_value = MergeDictionaryValues(*from_value, *to_key_value);
        result->SetWithoutPathExpansion(*key, merged_value);
      }
      // Note that for all other types we want to preserve the "to"
      // values so we do nothing here.
    } else {
      result->SetWithoutPathExpansion(*key, from_value->DeepCopy());
    }
  }
  return result;
}

void PreferenceModelAssociator::AfterUpdateOperations(
    const std::string& pref_name) {
  // The bookmark bar visibility preference requires a special
  // notification to update the UI.
  if (0 == pref_name.compare(prefs::kShowBookmarkBar)) {
    NotificationService::current()->Notify(
        NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED,
        Source<PreferenceModelAssociator>(this),
        NotificationService::NoDetails());
  }
}

}  // namespace browser_sync
<commit_msg>Handle sync values of wrong type more graceful.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/sync/glue/preference_model_associator.h"

#include "base/json/json_reader.h"
#include "base/logging.h"
#include "base/values.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/synchronized_preferences.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/protocol/preference_specifics.pb.h"
#include "chrome/common/json_value_serializer.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"

namespace browser_sync {

PreferenceModelAssociator::PreferenceModelAssociator(
    ProfileSyncService* sync_service)
    : sync_service_(sync_service),
      preferences_node_id_(sync_api::kInvalidId) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK(sync_service_);

  // Add the list of kSynchronizedPreferences to our local
  // synced_preferences set, taking care to filter out any preferences
  // that are not registered.
  PrefService* pref_service = sync_service_->profile()->GetPrefs();
  for (size_t i = 0; i < arraysize(kSynchronizedPreferences); ++i) {
    if (pref_service->FindPreference(kSynchronizedPreferences[i]))
      synced_preferences_.insert(kSynchronizedPreferences[i]);
  }
}

PreferenceModelAssociator::~PreferenceModelAssociator() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}

bool PreferenceModelAssociator::InitPrefNodeAndAssociate(
    sync_api::WriteTransaction* trans,
    const sync_api::BaseNode& root,
    const PrefService::Preference* pref) {
  DCHECK(pref);

  PrefService* pref_service = sync_service_->profile()->GetPrefs();
  base::JSONReader reader;
  std::string tag = pref->name();
  sync_api::WriteNode node(trans);
  if (node.InitByClientTagLookup(syncable::PREFERENCES, tag)) {
    // The server has a value for the preference.
    const sync_pb::PreferenceSpecifics& preference(
        node.GetPreferenceSpecifics());
    DCHECK_EQ(tag, preference.name());

    if (pref->IsUserModifiable()) {
      scoped_ptr<Value> value(
          reader.JsonToValue(preference.value(), false, false));
      std::string pref_name = preference.name();
      if (!value.get()) {
        LOG(ERROR) << "Failed to deserialize preference value: "
                   << reader.GetErrorMessage();
        return false;
      }

      // Merge the server value of this preference with the local value.
      scoped_ptr<Value> new_value(MergePreference(*pref, *value));

      // Update the local preference based on what we got from the
      // sync server.
      if (new_value->IsType(Value::TYPE_NULL)) {
        pref_service->ClearPref(pref_name.c_str());
      } else if (!new_value->IsType(pref->GetType())) {
        LOG(WARNING) << "Synced value for " << preference.name()
                     << " is of type " << new_value->GetType()
                     << " which doesn't match pref type " << pref->GetType();
      } else if (!pref->GetValue()->Equals(new_value.get())) {
        pref_service->Set(pref_name.c_str(), *new_value);
      }

      AfterUpdateOperations(pref_name);

      // If the merge resulted in an updated value, write it back to
      // the sync node.
      if (!value->Equals(new_value.get()) &&
          !WritePreferenceToNode(pref->name(), *new_value, &node))
        return false;
    }
    Associate(pref, node.GetId());
  } else if (pref->IsUserControlled()) {
    // The server doesn't have a value, but we have a user-controlled value,
    // so we push it to the server.
    sync_api::WriteNode write_node(trans);
    if (!write_node.InitUniqueByCreation(syncable::PREFERENCES, root, tag)) {
      LOG(ERROR) << "Failed to create preference sync node.";
      return false;
    }

    // Update the sync node with the local value for this preference.
    if (!WritePreferenceToNode(pref->name(), *pref->GetValue(), &write_node))
      return false;

    Associate(pref, write_node.GetId());
  }

  return true;
}

bool PreferenceModelAssociator::AssociateModels() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  PrefService* pref_service = sync_service_->profile()->GetPrefs();

  int64 root_id;
  if (!GetSyncIdForTaggedNode(kPreferencesTag, &root_id)) {
    LOG(ERROR) << "Server did not create the top-level preferences node. We "
               << "might be running against an out-of-date server.";
    return false;
  }

  sync_api::WriteTransaction trans(sync_service_->GetUserShare());
  sync_api::ReadNode root(&trans);
  if (!root.InitByIdLookup(root_id)) {
    LOG(ERROR) << "Server did not create the top-level preferences node. We "
               << "might be running against an out-of-date server.";
    return false;
  }

  for (std::set<std::string>::iterator it = synced_preferences_.begin();
       it != synced_preferences_.end(); ++it) {
    const PrefService::Preference* pref =
        pref_service->FindPreference((*it).c_str());
    InitPrefNodeAndAssociate(&trans, root, pref);
  }
  return true;
}

bool PreferenceModelAssociator::DisassociateModels() {
  id_map_.clear();
  id_map_inverse_.clear();
  return true;
}

bool PreferenceModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) {
  DCHECK(has_nodes);
  *has_nodes = false;
  int64 preferences_sync_id;
  if (!GetSyncIdForTaggedNode(kPreferencesTag, &preferences_sync_id)) {
    LOG(ERROR) << "Server did not create the top-level preferences node. We "
               << "might be running against an out-of-date server.";
    return false;
  }
  sync_api::ReadTransaction trans(sync_service_->GetUserShare());

  sync_api::ReadNode preferences_node(&trans);
  if (!preferences_node.InitByIdLookup(preferences_sync_id)) {
    LOG(ERROR) << "Server did not create the top-level preferences node. We "
               << "might be running against an out-of-date server.";
    return false;
  }

  // The sync model has user created nodes if the preferences folder has any
  // children.
  *has_nodes = sync_api::kInvalidId != preferences_node.GetFirstChildId();
  return true;
}

const PrefService::Preference*
PreferenceModelAssociator::GetChromeNodeFromSyncId(int64 sync_id) {
  return NULL;
}

bool PreferenceModelAssociator::InitSyncNodeFromChromeId(
    const std::string& node_id,
    sync_api::BaseNode* sync_node) {
  return false;
}

int64 PreferenceModelAssociator::GetSyncIdFromChromeId(
    const std::string& preference_name) {
  PreferenceNameToSyncIdMap::const_iterator iter =
      id_map_.find(preference_name);
  return iter == id_map_.end() ? sync_api::kInvalidId : iter->second;
}

void PreferenceModelAssociator::Associate(
    const PrefService::Preference* preference, int64 sync_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK_NE(sync_api::kInvalidId, sync_id);
  DCHECK(id_map_.find(preference->name()) == id_map_.end());
  DCHECK(id_map_inverse_.find(sync_id) == id_map_inverse_.end());
  id_map_[preference->name()] = sync_id;
  id_map_inverse_[sync_id] = preference->name();
}

void PreferenceModelAssociator::Disassociate(int64 sync_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  SyncIdToPreferenceNameMap::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);
}

bool PreferenceModelAssociator::GetSyncIdForTaggedNode(const std::string& tag,
                                                       int64* sync_id) {
  sync_api::ReadTransaction trans(sync_service_->GetUserShare());
  sync_api::ReadNode sync_node(&trans);
  if (!sync_node.InitByTagLookup(tag.c_str()))
    return false;
  *sync_id = sync_node.GetId();
  return true;
}

Value* PreferenceModelAssociator::MergePreference(
    const PrefService::Preference& local_pref,
    const Value& server_value) {
  const std::string& name(local_pref.name());
  if (name == prefs::kURLsToRestoreOnStartup ||
      name == prefs::kDesktopNotificationAllowedOrigins ||
      name == prefs::kDesktopNotificationDeniedOrigins) {
    return MergeListValues(*local_pref.GetValue(), server_value);
  }

  if (name == prefs::kContentSettingsPatterns ||
      name == prefs::kGeolocationContentSettings) {
    return MergeDictionaryValues(*local_pref.GetValue(), server_value);
  }

  // If this is not a specially handled preference, server wins.
  return server_value.DeepCopy();
}

bool PreferenceModelAssociator::WritePreferenceToNode(
    const std::string& name,
    const Value& value,
    sync_api::WriteNode* node) {
  std::string serialized;
  JSONStringValueSerializer json(&serialized);
  if (!json.Serialize(value)) {
    LOG(ERROR) << "Failed to serialize preference value.";
    return false;
  }

  sync_pb::PreferenceSpecifics preference;
  preference.set_name(name);
  preference.set_value(serialized);
  node->SetPreferenceSpecifics(preference);
  // TODO(viettrungluu): eliminate conversion (it's temporary)
  node->SetTitle(UTF8ToWide(name));
  return true;
}

Value* PreferenceModelAssociator::MergeListValues(const Value& from_value,
                                                  const Value& to_value) {
  if (from_value.GetType() == Value::TYPE_NULL)
    return to_value.DeepCopy();
  if (to_value.GetType() == Value::TYPE_NULL)
    return from_value.DeepCopy();

  DCHECK(from_value.GetType() == Value::TYPE_LIST);
  DCHECK(to_value.GetType() == Value::TYPE_LIST);
  const ListValue& from_list_value = static_cast<const ListValue&>(from_value);
  const ListValue& to_list_value = static_cast<const ListValue&>(to_value);
  ListValue* result = to_list_value.DeepCopy();

  for (ListValue::const_iterator i = from_list_value.begin();
       i != from_list_value.end(); ++i) {
    Value* value = (*i)->DeepCopy();
    if (!result->AppendIfNotPresent(value))
      delete value;
  }
  return result;
}

Value* PreferenceModelAssociator::MergeDictionaryValues(
    const Value& from_value,
    const Value& to_value) {
  if (from_value.GetType() == Value::TYPE_NULL)
    return to_value.DeepCopy();
  if (to_value.GetType() == Value::TYPE_NULL)
    return from_value.DeepCopy();

  DCHECK(from_value.GetType() == Value::TYPE_DICTIONARY);
  DCHECK(to_value.GetType() == Value::TYPE_DICTIONARY);
  const DictionaryValue& from_dict_value =
      static_cast<const DictionaryValue&>(from_value);
  const DictionaryValue& to_dict_value =
      static_cast<const DictionaryValue&>(to_value);
  DictionaryValue* result = to_dict_value.DeepCopy();

  for (DictionaryValue::key_iterator key = from_dict_value.begin_keys();
       key != from_dict_value.end_keys(); ++key) {
    Value* from_value;
    bool success = from_dict_value.GetWithoutPathExpansion(*key, &from_value);
    DCHECK(success);

    Value* to_key_value;
    if (result->GetWithoutPathExpansion(*key, &to_key_value)) {
      if (to_key_value->GetType() == Value::TYPE_DICTIONARY) {
        Value* merged_value = MergeDictionaryValues(*from_value, *to_key_value);
        result->SetWithoutPathExpansion(*key, merged_value);
      }
      // Note that for all other types we want to preserve the "to"
      // values so we do nothing here.
    } else {
      result->SetWithoutPathExpansion(*key, from_value->DeepCopy());
    }
  }
  return result;
}

void PreferenceModelAssociator::AfterUpdateOperations(
    const std::string& pref_name) {
  // The bookmark bar visibility preference requires a special
  // notification to update the UI.
  if (0 == pref_name.compare(prefs::kShowBookmarkBar)) {
    NotificationService::current()->Notify(
        NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED,
        Source<PreferenceModelAssociator>(this),
        NotificationService::NoDetails());
  }
}

}  // namespace browser_sync
<|endoftext|>


<commit_before>#ifndef Bull_WglPbuffer_hpp
#define Bull_WglPbuffer_hpp

#include <Bull/Render/Context/ExtensionsLoader.hpp>

#define WGL_DRAW_TO_PBUFFER_ARB    0x202D
#define WGL_MAX_PBUFFER_PIXELS_ARB 0x202E
#define WGL_MAX_PBUFFER_WIDTH_ARB  0x202F
#define WGL_MAX_PBUFFER_HEIGHT_ARB 0x2030
#define WGL_PBUFFER_LARGEST_ARB    0x2033
#define WGL_PBUFFER_WIDTH_ARB      0x2034
#define WGL_PBUFFER_HEIGHT_ARB     0x2035
#define WGL_PBUFFER_LOST_ARB       0x2036

namespace Bull
{
    namespace prv
    {
        HPBUFFER (WINAPI* wglCreatePbuffer)(HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList) = nullptr;
        HDC (WINAPI* wglGetPbufferDC)(HPBUFFER hPbuffer) = nullptr;
        int (WINAPI* wglReleasePbufferDC)(HPBUFFER hPbuffer, HDC hDC) = nullptr;
        BOOL (WINAPI* wglDestroyPbuffer)(HPBUFFER hPbuffer) = nullptr;
        BOOL (WINAPI* wglQueryPbuffer)(HPBUFFER hPbuffer, int iAttribute, int *piValue) = nullptr;

        ExtensionsLoader::Extension WglPbuffer("WGL_ARB_pbuffer", []
        {
            wglCreatePbuffer    = reinterpret_cast<HPBUFFER (WINAPI*)(HDC, int, int , int, const int*)>(GlContext::getFunction("wglCreatePbufferARB"));
            wglGetPbufferDC     = reinterpret_cast<HDC (WINAPI*)(HPBUFFER)>(GlContext::getFunction("wglGetPbufferDCARB"));
            wglReleasePbufferDC = reinterpret_cast<int (WINAPI*)(HPBUFFER, HDC hDC)>(GlContext::getFunction("wglReleasePbufferDCARB"));
            wglDestroyPbuffer   = reinterpret_cast<BOOL (WINAPI*)(HPBUFFER)>(GlContext::getFunction("wglDestroyPbufferARB"));
            wglQueryPbuffer     = reinterpret_cast<BOOL (WINAPI*)(HPBUFFER, int, int *)>(GlContext::getFunction("wglQueryPbufferARB"));

            return wglCreatePbuffer && wglGetPbufferDC && wglReleasePbufferDC && wglDestroyPbuffer && wglQueryPbuffer;
        });
    }
}

#endif // Bull_WglPbuffer_hpp
<commit_msg>[Render/WglContext] Fix header protection<commit_after>#ifndef BULL_RENDER_CONTEXT_WGL_WGLPBUFFER_HPP
#define BULL_RENDER_CONTEXT_WGL_WGLPBUFFER_HPP

#include <Bull/Render/Context/ExtensionsLoader.hpp>

#define WGL_DRAW_TO_PBUFFER_ARB    0x202D
#define WGL_MAX_PBUFFER_PIXELS_ARB 0x202E
#define WGL_MAX_PBUFFER_WIDTH_ARB  0x202F
#define WGL_MAX_PBUFFER_HEIGHT_ARB 0x2030
#define WGL_PBUFFER_LARGEST_ARB    0x2033
#define WGL_PBUFFER_WIDTH_ARB      0x2034
#define WGL_PBUFFER_HEIGHT_ARB     0x2035
#define WGL_PBUFFER_LOST_ARB       0x2036

namespace Bull
{
    namespace prv
    {
        HPBUFFER (WINAPI* wglCreatePbuffer)(HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList) = nullptr;
        HDC (WINAPI* wglGetPbufferDC)(HPBUFFER hPbuffer) = nullptr;
        int (WINAPI* wglReleasePbufferDC)(HPBUFFER hPbuffer, HDC hDC) = nullptr;
        BOOL (WINAPI* wglDestroyPbuffer)(HPBUFFER hPbuffer) = nullptr;
        BOOL (WINAPI* wglQueryPbuffer)(HPBUFFER hPbuffer, int iAttribute, int *piValue) = nullptr;

        ExtensionsLoader::Extension WglPbuffer("WGL_ARB_pbuffer", []
        {
            wglCreatePbuffer    = reinterpret_cast<HPBUFFER (WINAPI*)(HDC, int, int , int, const int*)>(GlContext::getFunction("wglCreatePbufferARB"));
            wglGetPbufferDC     = reinterpret_cast<HDC (WINAPI*)(HPBUFFER)>(GlContext::getFunction("wglGetPbufferDCARB"));
            wglReleasePbufferDC = reinterpret_cast<int (WINAPI*)(HPBUFFER, HDC hDC)>(GlContext::getFunction("wglReleasePbufferDCARB"));
            wglDestroyPbuffer   = reinterpret_cast<BOOL (WINAPI*)(HPBUFFER)>(GlContext::getFunction("wglDestroyPbufferARB"));
            wglQueryPbuffer     = reinterpret_cast<BOOL (WINAPI*)(HPBUFFER, int, int *)>(GlContext::getFunction("wglQueryPbufferARB"));

            return wglCreatePbuffer && wglGetPbufferDC && wglReleasePbufferDC && wglDestroyPbuffer && wglQueryPbuffer;
        });
    }
}

#endif // BULL_RENDER_CONTEXT_WGL_WGLPBUFFER_HPP
<|endoftext|>