Commit message: None
CVE: CVE-2013-2876
CWE: CWE-264
Vulnerability description: browser/extensions/api/tabs/tabs_api.cc in Google Chrome before 28.0.1500.71 does not properly enforce restrictions on the capture of screenshots by extensions, which allows remote attackers to obtain sensitive information about the content of a previous page via vectors involving an interstitial page.

Project: Chrome

void TabsCaptureVisibleTabFunction::CopyFromBackingStoreComplete(
    bool succeeded,
    const SkBitmap& bitmap) {
  if (succeeded) {
    VLOG(1) << "captureVisibleTab() got image from backing store.";
    SendResultFromBitmap(bitmap);
    return;
  }

  WebContents* web_contents = NULL;
  if (!GetTabToCapture(&web_contents)) {
    SendInternalError();
    return;
  }

  content::RenderWidgetHost* render_widget_host =
      web_contents->GetRenderViewHost();
  if (!render_widget_host) {
    SendInternalError();
    return;
  }

  render_widget_host->GetSnapshotFromRenderer(
      gfx::Rect(),
      base::Bind(
          &TabsCaptureVisibleTabFunction::GetSnapshotFromRendererComplete,
          this));
}

Project: Chrome

Browser* CreateBrowserWindow(const Browser::CreateParams& params,
                             Profile* profile,
                             const std::string& extension_id) {
  bool use_existing_browser_window = false;

#if defined(OS_WIN)
  if (win8::IsSingleWindowMetroMode())
    use_existing_browser_window = true;
#endif  // OS_WIN

  Browser* new_window = NULL;
  if (use_existing_browser_window)
    new_window = chrome::FindTabbedBrowser(profile, false,
                                           params.host_desktop_type);

  if (!new_window)
    new_window = new Browser(params);
  return new_window;
}

Project: Chrome

void ExecuteCodeInTabFunction::DidLoadAndLocalizeFile(bool success,
                                                      const std::string& data) {
  if (success) {
    if (!Execute(data))
      SendResponse(false);
  } else {
    error_ = ErrorUtils::FormatErrorMessage(keys::kLoadFileError,
        resource_.relative_path().AsUTF8Unsafe());
    SendResponse(false);
  }
}

Project: Chrome

void ExecuteCodeInTabFunction::DidLoadFile(bool success,
                                           const std::string& data) {
  std::string function_name = name();
  const extensions::Extension* extension = GetExtension();

  if (success &&
      function_name == TabsInsertCSSFunction::function_name() &&
      extension != NULL &&
      data.find(
          extensions::MessageBundle::kMessageBegin) != std::string::npos) {
    BrowserThread::PostTask(
        BrowserThread::FILE, FROM_HERE,
        base::Bind(&ExecuteCodeInTabFunction::LocalizeCSS, this,
                   data,
                   extension->id(),
                   extension->path(),
                   extensions::LocaleInfo::GetDefaultLocale(extension)));
  } else {
    DidLoadAndLocalizeFile(success, data);
  }
}

Project: Chrome

Browser* GetBrowserInProfileWithId(Profile* profile,
                                   const int window_id,
                                   bool include_incognito,
                                   std::string* error_message) {
  Profile* incognito_profile =
      include_incognito && profile->HasOffTheRecordProfile() ?
          profile->GetOffTheRecordProfile() : NULL;
  for (chrome::BrowserIterator it; !it.done(); it.Next()) {
    Browser* browser = *it;
    if ((browser->profile() == profile ||
         browser->profile() == incognito_profile) &&
        ExtensionTabUtil::GetWindowId(browser) == window_id &&
        browser->window()) {
      return browser;
    }
  }

  if (error_message)
    *error_message = ErrorUtils::FormatErrorMessage(
        keys::kWindowNotFoundError, base::IntToString(window_id));

  return NULL;
}

Project: Chrome

void TabsCaptureVisibleTabFunction::GetSnapshotFromRendererComplete(
    bool succeeded,
    const SkBitmap& bitmap) {
  if (!succeeded) {
    SendInternalError();
  } else {
    VLOG(1) << "captureVisibleTab() got image from renderer.";
    SendResultFromBitmap(bitmap);
  }
}

Project: Chrome

bool GetTabById(int tab_id,
                Profile* profile,
                bool include_incognito,
                Browser** browser,
                TabStripModel** tab_strip,
                content::WebContents** contents,
                int* tab_index,
                std::string* error_message) {
  if (ExtensionTabUtil::GetTabById(tab_id, profile, include_incognito,
                                   browser, tab_strip, contents, tab_index))
    return true;

  if (error_message)
    *error_message = ErrorUtils::FormatErrorMessage(
        keys::kTabNotFoundError, base::IntToString(tab_id));

  return false;
}

Project: Chrome

bool TabsCaptureVisibleTabFunction::GetTabToCapture(
    WebContents** web_contents) {
  Browser* browser = NULL;
  int window_id = extension_misc::kCurrentWindowId;

  if (HasOptionalArgument(0))
    EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &window_id));

  if (!GetBrowserFromWindowID(this, window_id, &browser))
    return false;

  *web_contents = browser->tab_strip_model()->GetActiveWebContents();
  if (*web_contents == NULL) {
    error_ = keys::kInternalVisibleTabCaptureError;
    return false;
  }

  return true;
};

Project: Chrome

bool GetWindowFromWindowID(UIThreadExtensionFunction* function,
                           int window_id,
                           WindowController** controller) {
  if (window_id == extension_misc::kCurrentWindowId) {
    WindowController* extension_window_controller =
        function->dispatcher()->delegate()->GetExtensionWindowController();
    if (extension_window_controller) {
      *controller = extension_window_controller;
    } else {
      *controller = WindowControllerList::GetInstance()->
          CurrentWindowForFunction(function);
    }
    if (!(*controller)) {
      function->SetError(keys::kNoCurrentWindowError);
      return false;
    }
  } else {
    *controller = WindowControllerList::GetInstance()->
        FindWindowForFunctionById(function, window_id);
    if (!(*controller)) {
      function->SetError(ErrorUtils::FormatErrorMessage(
          keys::kWindowNotFoundError, base::IntToString(window_id)));
      return false;
    }
  }
  return true;
}

Project: Chrome

void TabsDetectLanguageFunction::GotLanguage(const std::string& language) {
  SetResult(Value::CreateStringValue(language.c_str()));
  SendResponse(true);

  Release();  // Balanced in Run()
}

Project: Chrome

bool ExecuteCodeInTabFunction::HasPermission() {
  if (Init() &&
      extension_->HasAPIPermissionForTab(execute_tab_id_,
                                         extensions::APIPermission::kTab)) {
    return true;
  }
  return ExtensionFunction::HasPermission();
}

Project: Chrome

bool ExecuteCodeInTabFunction::Init() {
  if (details_.get())
    return true;

  int tab_id = -1;
  if (args_->GetInteger(0, &tab_id))
    EXTENSION_FUNCTION_VALIDATE(tab_id >= 0);

  DictionaryValue* details_value = NULL;
  if (!args_->GetDictionary(1, &details_value))
    return false;
  scoped_ptr<InjectDetails> details(new InjectDetails());
  if (!InjectDetails::Populate(*details_value, details.get()))
    return false;

  if (tab_id == -1) {
    Browser* browser = GetCurrentBrowser();
    if (!browser)
      return false;
    content::WebContents* web_contents = NULL;
    if (!ExtensionTabUtil::GetDefaultTab(browser, &web_contents, &tab_id))
      return false;
  }

  execute_tab_id_ = tab_id;
  details_ = details.Pass();
  return true;
}

Project: Chrome

void ExecuteCodeInTabFunction::LocalizeCSS(
    const std::string& data,
    const std::string& extension_id,
    const base::FilePath& extension_path,
    const std::string& extension_default_locale) {
  scoped_ptr<SubstitutionMap> localization_messages(
      extension_file_util::LoadMessageBundleSubstitutionMap(
          extension_path, extension_id, extension_default_locale));

  std::string css_data = data;
  std::string error;
  extensions::MessageBundle::ReplaceMessagesWithExternalDictionary(
      *localization_messages, &css_data, &error);

  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      base::Bind(&ExecuteCodeInTabFunction::DidLoadAndLocalizeFile, this,
                 true, css_data));
}

Project: Chrome

bool MatchesQueryArg(QueryArg arg, bool value) {
  if (arg == NOT_SET)
    return true;

  return (arg == MATCH_TRUE && value) || (arg == MATCH_FALSE && !value);
}

Project: Chrome

void TabsDetectLanguageFunction::Observe(
    int type,
    const content::NotificationSource& source,
    const content::NotificationDetails& details) {
  std::string language;
  if (type == chrome::NOTIFICATION_TAB_LANGUAGE_DETERMINED)
    language = *content::Details<std::string>(details).ptr();

  registrar_.RemoveAll();

  GotLanguage(language);
}

Project: Chrome

void TabsUpdateFunction::OnExecuteCodeFinished(const std::string& error,
                                              int32 on_page_id,
                                              const GURL& url,
                                              const ListValue& script_result) {
  if (error.empty())
    PopulateResult();
  else
    error_ = error;
  SendResponse(error.empty());
}

Project: Chrome

void ExecuteCodeInTabFunction::OnExecuteCodeFinished(const std::string& error,
                                                     int32 on_page_id,
                                                     const GURL& on_url,
                                                     const ListValue& result) {
  if (!error.empty())
    SetError(error);

  SendResponse(error.empty());
}

Project: Chrome

void TabsExecuteScriptFunction::OnExecuteCodeFinished(const std::string& error,
                                                      int32 on_page_id,
                                                      const GURL& on_url,
                                                      const ListValue& result) {
  if (error.empty())
    SetResult(result.DeepCopy());
  ExecuteCodeInTabFunction::OnExecuteCodeFinished(error, on_page_id, on_url,
                                                  result);
}

Project: Chrome

QueryArg ParseBoolQueryArg(base::DictionaryValue* query, const char* key) {
  if (query->HasKey(key)) {
    bool value = false;
    CHECK(query->GetBoolean(key, &value));
    return value ? MATCH_TRUE : MATCH_FALSE;
  }
  return NOT_SET;
}

Project: Chrome

void TabsUpdateFunction::PopulateResult() {
  if (!has_callback())
    return;

  SetResult(ExtensionTabUtil::CreateTabValue(web_contents_, GetExtension()));
}

Project: Chrome

void TabsCaptureVisibleTabFunction::RegisterUserPrefs(
    PrefRegistrySyncable* registry) {
  registry->RegisterBooleanPref(prefs::kDisableScreenshots, false,
                                PrefRegistrySyncable::UNSYNCABLE_PREF);
}

Project: Chrome

bool WindowsGetFunction::RunImpl() {
  scoped_ptr<Get::Params> params(Get::Params::Create(*args_));
  EXTENSION_FUNCTION_VALIDATE(params.get());

  bool populate_tabs = false;
  if (params->get_info.get() && params->get_info->populate.get())
    populate_tabs = *params->get_info->populate;

  WindowController* controller;
  if (!GetWindowFromWindowID(this, params->window_id, &controller))
    return false;

  if (populate_tabs)
    SetResult(controller->CreateWindowValueWithTabs(GetExtension()));
  else
    SetResult(controller->CreateWindowValue());
  return true;
}

Project: Chrome

bool WindowsGetCurrentFunction::RunImpl() {
  scoped_ptr<GetCurrent::Params> params(GetCurrent::Params::Create(*args_));
  EXTENSION_FUNCTION_VALIDATE(params.get());

  bool populate_tabs = false;
  if (params->get_info.get() && params->get_info->populate.get())
    populate_tabs = *params->get_info->populate;

  WindowController* controller;
  if (!GetWindowFromWindowID(this,
                             extension_misc::kCurrentWindowId,
                             &controller)) {
    return false;
  }
  if (populate_tabs)
    SetResult(controller->CreateWindowValueWithTabs(GetExtension()));
  else
    SetResult(controller->CreateWindowValue());
  return true;
}

Project: Chrome

bool WindowsGetLastFocusedFunction::RunImpl() {
  scoped_ptr<GetLastFocused::Params> params(
      GetLastFocused::Params::Create(*args_));
  EXTENSION_FUNCTION_VALIDATE(params.get());

  bool populate_tabs = false;
  if (params->get_info.get() && params->get_info->populate.get())
    populate_tabs = *params->get_info->populate;

  Browser* browser = chrome::FindAnyBrowser(
      profile(), include_incognito(), chrome::GetActiveDesktop());
  if (!browser || !browser->window()) {
    error_ = keys::kNoLastFocusedWindowError;
    return false;
  }
  WindowController* controller =
      browser->extension_window_controller();
  if (populate_tabs)
    SetResult(controller->CreateWindowValueWithTabs(GetExtension()));
  else
    SetResult(controller->CreateWindowValue());
  return true;
}

Project: Chrome

bool WindowsGetAllFunction::RunImpl() {
  scoped_ptr<GetAll::Params> params(GetAll::Params::Create(*args_));
  EXTENSION_FUNCTION_VALIDATE(params.get());

  bool populate_tabs = false;
  if (params->get_info.get() && params->get_info->populate.get())
    populate_tabs = *params->get_info->populate;

  ListValue* window_list = new ListValue();
  const WindowControllerList::ControllerList& windows =
      WindowControllerList::GetInstance()->windows();
  for (WindowControllerList::ControllerList::const_iterator iter =
           windows.begin();
       iter != windows.end(); ++iter) {
    if (!this->CanOperateOnWindow(*iter))
      continue;
    if (populate_tabs)
      window_list->Append((*iter)->CreateWindowValueWithTabs(GetExtension()));
    else
      window_list->Append((*iter)->CreateWindowValue());
  }
  SetResult(window_list);
  return true;
}

Project: Chrome

bool WindowsUpdateFunction::RunImpl() {
  int window_id = extension_misc::kUnknownWindowId;
  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &window_id));
  DictionaryValue* update_props;
  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &update_props));

  WindowController* controller;
  if (!GetWindowFromWindowID(this, window_id, &controller))
    return false;

#if defined(OS_WIN)
  if (win8::IsSingleWindowMetroMode()) {
    SetResult(controller->CreateWindowValue());
    return true;
  }
#endif

  ui::WindowShowState show_state = ui::SHOW_STATE_DEFAULT;  // No change.
  std::string state_str;
  if (update_props->HasKey(keys::kShowStateKey)) {
    EXTENSION_FUNCTION_VALIDATE(update_props->GetString(keys::kShowStateKey,
                                                        &state_str));
    if (state_str == keys::kShowStateValueNormal) {
      show_state = ui::SHOW_STATE_NORMAL;
    } else if (state_str == keys::kShowStateValueMinimized) {
      show_state = ui::SHOW_STATE_MINIMIZED;
    } else if (state_str == keys::kShowStateValueMaximized) {
      show_state = ui::SHOW_STATE_MAXIMIZED;
    } else if (state_str == keys::kShowStateValueFullscreen) {
      show_state = ui::SHOW_STATE_FULLSCREEN;
    } else {
      error_ = keys::kInvalidWindowStateError;
      return false;
    }
  }

  if (show_state != ui::SHOW_STATE_FULLSCREEN &&
      show_state != ui::SHOW_STATE_DEFAULT)
    controller->SetFullscreenMode(false, GetExtension()->url());

  switch (show_state) {
    case ui::SHOW_STATE_MINIMIZED:
      controller->window()->Minimize();
      break;
    case ui::SHOW_STATE_MAXIMIZED:
      controller->window()->Maximize();
      break;
    case ui::SHOW_STATE_FULLSCREEN:
      if (controller->window()->IsMinimized() ||
          controller->window()->IsMaximized())
        controller->window()->Restore();
      controller->SetFullscreenMode(true, GetExtension()->url());
      break;
    case ui::SHOW_STATE_NORMAL:
      controller->window()->Restore();
      break;
    default:
      break;
  }

  gfx::Rect bounds;
  if (controller->window()->IsMinimized())
    bounds = controller->window()->GetRestoredBounds();
  else
    bounds = controller->window()->GetBounds();
  bool set_bounds = false;

  int bounds_val;
  if (update_props->HasKey(keys::kLeftKey)) {
    EXTENSION_FUNCTION_VALIDATE(update_props->GetInteger(
        keys::kLeftKey,
        &bounds_val));
    bounds.set_x(bounds_val);
    set_bounds = true;
  }

  if (update_props->HasKey(keys::kTopKey)) {
    EXTENSION_FUNCTION_VALIDATE(update_props->GetInteger(
        keys::kTopKey,
        &bounds_val));
    bounds.set_y(bounds_val);
    set_bounds = true;
  }

  if (update_props->HasKey(keys::kWidthKey)) {
    EXTENSION_FUNCTION_VALIDATE(update_props->GetInteger(
        keys::kWidthKey,
        &bounds_val));
    bounds.set_width(bounds_val);
    set_bounds = true;
  }

  if (update_props->HasKey(keys::kHeightKey)) {
    EXTENSION_FUNCTION_VALIDATE(update_props->GetInteger(
        keys::kHeightKey,
        &bounds_val));
    bounds.set_height(bounds_val);
    set_bounds = true;
  }

  if (set_bounds) {
    if (show_state == ui::SHOW_STATE_MINIMIZED ||
        show_state == ui::SHOW_STATE_MAXIMIZED ||
        show_state == ui::SHOW_STATE_FULLSCREEN) {
      error_ = keys::kInvalidWindowStateError;
      return false;
    }
    controller->window()->SetBounds(bounds);
  }

  bool active_val = false;
  if (update_props->HasKey(keys::kFocusedKey)) {
    EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean(
        keys::kFocusedKey, &active_val));
    if (active_val) {
      if (show_state == ui::SHOW_STATE_MINIMIZED) {
        error_ = keys::kInvalidWindowStateError;
        return false;
      }
      controller->window()->Activate();
    } else {
      if (show_state == ui::SHOW_STATE_MAXIMIZED ||
          show_state == ui::SHOW_STATE_FULLSCREEN) {
        error_ = keys::kInvalidWindowStateError;
        return false;
      }
      controller->window()->Deactivate();
    }
  }

  bool draw_attention = false;
  if (update_props->HasKey(keys::kDrawAttentionKey)) {
    EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean(
        keys::kDrawAttentionKey, &draw_attention));
    controller->window()->FlashFrame(draw_attention);
  }

  SetResult(controller->CreateWindowValue());

  return true;
}

Project: Chrome

bool WindowsRemoveFunction::RunImpl() {
  int window_id = -1;
  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &window_id));

  WindowController* controller;
  if (!GetWindowFromWindowID(this, window_id, &controller))
    return false;

#if defined(OS_WIN)
  if (win8::IsSingleWindowMetroMode())
    return false;
#endif

  WindowController::Reason reason;
  if (!controller->CanClose(&reason)) {
    if (reason == WindowController::REASON_NOT_EDITABLE)
      error_ = keys::kTabStripNotEditableError;
    return false;
  }
  controller->window()->Close();
  return true;
}

Project: Chrome

bool TabsGetSelectedFunction::RunImpl() {
  int window_id = extension_misc::kCurrentWindowId;

  if (HasOptionalArgument(0))
    EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &window_id));

  Browser* browser = NULL;
  if (!GetBrowserFromWindowID(this, window_id, &browser))
    return false;

  TabStripModel* tab_strip = browser->tab_strip_model();
  WebContents* contents = tab_strip->GetActiveWebContents();
  if (!contents) {
    error_ = keys::kNoSelectedTabError;
    return false;
  }
  SetResult(ExtensionTabUtil::CreateTabValue(contents,
                                             tab_strip,
                                             tab_strip->active_index(),
                                             GetExtension()));
  return true;
}

Project: Chrome

bool TabsQueryFunction::RunImpl() {
  DictionaryValue* query = NULL;
  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &query));

  QueryArg active = ParseBoolQueryArg(query, keys::kActiveKey);
  QueryArg pinned = ParseBoolQueryArg(query, keys::kPinnedKey);
  QueryArg selected = ParseBoolQueryArg(query, keys::kHighlightedKey);
  QueryArg current_window = ParseBoolQueryArg(query, keys::kCurrentWindowKey);
  QueryArg focused_window =
      ParseBoolQueryArg(query, keys::kLastFocusedWindowKey);

  QueryArg loading = NOT_SET;
  if (query->HasKey(keys::kStatusKey)) {
    std::string status;
    EXTENSION_FUNCTION_VALIDATE(query->GetString(keys::kStatusKey, &status));
    loading = (status == keys::kStatusValueLoading) ? MATCH_TRUE : MATCH_FALSE;
  }

  URLPattern url_pattern(URLPattern::SCHEME_ALL, "<all_urls>");
  if (query->HasKey(keys::kUrlKey)) {
    std::string value;
    EXTENSION_FUNCTION_VALIDATE(query->GetString(keys::kUrlKey, &value));
    url_pattern = URLPattern(URLPattern::SCHEME_ALL, value);
  }

  std::string title;
  if (query->HasKey(keys::kTitleKey))
    EXTENSION_FUNCTION_VALIDATE(
        query->GetString(keys::kTitleKey, &title));

  int window_id = extension_misc::kUnknownWindowId;
  if (query->HasKey(keys::kWindowIdKey))
    EXTENSION_FUNCTION_VALIDATE(
        query->GetInteger(keys::kWindowIdKey, &window_id));

  int index = -1;
  if (query->HasKey(keys::kIndexKey))
    EXTENSION_FUNCTION_VALIDATE(
        query->GetInteger(keys::kIndexKey, &index));

  std::string window_type;
  if (query->HasKey(keys::kWindowTypeLongKey))
    EXTENSION_FUNCTION_VALIDATE(
        query->GetString(keys::kWindowTypeLongKey, &window_type));

  ListValue* result = new ListValue();
  for (chrome::BrowserIterator it; !it.done(); it.Next()) {
    Browser* browser = *it;
    if (!profile()->IsSameProfile(browser->profile()))
      continue;

    if (!browser->window())
      continue;

    if (!include_incognito() && profile() != browser->profile())
      continue;

    if (window_id >= 0 && window_id != ExtensionTabUtil::GetWindowId(browser))
      continue;

    if (window_id == extension_misc::kCurrentWindowId &&
        browser != GetCurrentBrowser())
      continue;

    if (!MatchesQueryArg(current_window, browser == GetCurrentBrowser()))
      continue;

    if (!MatchesQueryArg(focused_window, browser->window()->IsActive()))
      continue;

    if (!window_type.empty() &&
        window_type !=
        browser->extension_window_controller()->GetWindowTypeText())
      continue;

    TabStripModel* tab_strip = browser->tab_strip_model();
    for (int i = 0; i < tab_strip->count(); ++i) {
      const WebContents* web_contents = tab_strip->GetWebContentsAt(i);

      if (index > -1 && i != index)
        continue;

      if (!MatchesQueryArg(selected, tab_strip->IsTabSelected(i)))
        continue;

      if (!MatchesQueryArg(active, i == tab_strip->active_index()))
        continue;

      if (!MatchesQueryArg(pinned, tab_strip->IsTabPinned(i)))
        continue;

      if (!title.empty() && !MatchPattern(web_contents->GetTitle(),
                                          UTF8ToUTF16(title)))
        continue;

      if (!url_pattern.MatchesURL(web_contents->GetURL()))
        continue;

      if (!MatchesQueryArg(loading, web_contents->IsLoading()))
        continue;

      result->Append(ExtensionTabUtil::CreateTabValue(
          web_contents, tab_strip, i, GetExtension()));
    }
  }

  SetResult(result);
  return true;
}

Project: Chrome

bool TabsCreateFunction::RunImpl() {
  DictionaryValue* args = NULL;
  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));

  int window_id = extension_misc::kCurrentWindowId;
  if (args->HasKey(keys::kWindowIdKey))
    EXTENSION_FUNCTION_VALIDATE(args->GetInteger(
        keys::kWindowIdKey, &window_id));

  Browser* browser = NULL;
  if (!GetBrowserFromWindowID(this, window_id, &browser))
    return false;

  if (!browser->is_type_tabbed() && browser->IsAttemptingToCloseBrowser())
    browser = chrome::FindTabbedBrowser(profile(), include_incognito(),
                                        browser->host_desktop_type());

  if (!browser || !browser->window())
    return false;

  WebContents* opener = NULL;
  if (args->HasKey(keys::kOpenerTabIdKey)) {
    int opener_id = -1;
    EXTENSION_FUNCTION_VALIDATE(args->GetInteger(
        keys::kOpenerTabIdKey, &opener_id));

    if (!ExtensionTabUtil::GetTabById(
            opener_id, profile(), include_incognito(),
            NULL, NULL, &opener, NULL))
      return false;
  }


  std::string url_string;
  GURL url;
  if (args->HasKey(keys::kUrlKey)) {
    EXTENSION_FUNCTION_VALIDATE(args->GetString(keys::kUrlKey,
                                                &url_string));
    url = ExtensionTabUtil::ResolvePossiblyRelativeURL(url_string,
                                                       GetExtension());
    if (!url.is_valid()) {
      error_ = ErrorUtils::FormatErrorMessage(keys::kInvalidUrlError,
                                                       url_string);
      return false;
    }
  }

  if (ExtensionTabUtil::IsCrashURL(url)) {
    error_ = keys::kNoCrashBrowserError;
    return false;
  }

  bool active = true;
  if (args->HasKey(keys::kSelectedKey))
    EXTENSION_FUNCTION_VALIDATE(args->GetBoolean(keys::kSelectedKey, &active));

  if (args->HasKey(keys::kActiveKey))
    EXTENSION_FUNCTION_VALIDATE(args->GetBoolean(keys::kActiveKey, &active));

  bool pinned = false;
  if (args->HasKey(keys::kPinnedKey))
    EXTENSION_FUNCTION_VALIDATE(args->GetBoolean(keys::kPinnedKey, &pinned));

  if (url.SchemeIs(extensions::kExtensionScheme) &&
      !extensions::IncognitoInfo::IsSplitMode(GetExtension()) &&
      browser->profile()->IsOffTheRecord()) {
    Profile* profile = browser->profile()->GetOriginalProfile();
    chrome::HostDesktopType desktop_type = browser->host_desktop_type();

    browser = chrome::FindTabbedBrowser(profile, false, desktop_type);
    if (!browser) {
      browser = new Browser(Browser::CreateParams(Browser::TYPE_TABBED,
                                                  profile, desktop_type));
      browser->window()->Show();
    }
  }

  int index = -1;
  if (args->HasKey(keys::kIndexKey))
    EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kIndexKey, &index));

  TabStripModel* tab_strip = browser->tab_strip_model();

  index = std::min(std::max(index, -1), tab_strip->count());

  int add_types = active ? TabStripModel::ADD_ACTIVE : TabStripModel::ADD_NONE;
  add_types |= TabStripModel::ADD_FORCE_INDEX;
  if (pinned)
    add_types |= TabStripModel::ADD_PINNED;
  chrome::NavigateParams params(browser, url, content::PAGE_TRANSITION_LINK);
  params.disposition = active ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB;
  params.tabstrip_index = index;
  params.tabstrip_add_types = add_types;
  chrome::Navigate(&params);

  tab_strip = params.browser->tab_strip_model();
  int new_index = tab_strip->GetIndexOfWebContents(params.target_contents);
  if (opener)
    tab_strip->SetOpenerOfWebContentsAt(new_index, opener);

  if (active) {
    params.target_contents->GetDelegate()->ActivateContents(
        params.target_contents);
  }

  if (has_callback()) {
    SetResult(ExtensionTabUtil::CreateTabValue(
        params.target_contents,
        tab_strip, new_index, GetExtension()));
  }

  return true;
}

Project: Chrome

bool TabsDuplicateFunction::RunImpl() {
  int tab_id = -1;
  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id));

  Browser* browser = NULL;
  TabStripModel* tab_strip = NULL;
  int tab_index = -1;
  if (!GetTabById(tab_id, profile(), include_incognito(),
                  &browser, &tab_strip, NULL, &tab_index, &error_)) {
    return false;
  }

  WebContents* new_contents = chrome::DuplicateTabAt(browser, tab_index);
  if (!has_callback())
    return true;

  TabStripModel* new_tab_strip = NULL;
  int new_tab_index = -1;
  ExtensionTabUtil::GetTabStripModel(new_contents,
                                     &new_tab_strip,
                                     &new_tab_index);
  if (!new_tab_strip || new_tab_index == -1) {
    return false;
  }

  SetResult(ExtensionTabUtil::CreateTabValue(
      new_contents,
      new_tab_strip, new_tab_index, GetExtension()));

  return true;
}

Project: Chrome

bool TabsGetCurrentFunction::RunImpl() {
  DCHECK(dispatcher());

  WebContents* contents = dispatcher()->delegate()->GetAssociatedWebContents();
  if (contents)
    SetResult(ExtensionTabUtil::CreateTabValue(contents, GetExtension()));

  return true;
}

Project: Chrome

bool TabsHighlightFunction::RunImpl() {
  DictionaryValue* info = NULL;
  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &info));

  int window_id = extension_misc::kCurrentWindowId;
  if (info->HasKey(keys::kWindowIdKey))
    EXTENSION_FUNCTION_VALIDATE(
        info->GetInteger(keys::kWindowIdKey, &window_id));

  Browser* browser = NULL;
  if (!GetBrowserFromWindowID(this, window_id, &browser))
    return false;

  TabStripModel* tabstrip = browser->tab_strip_model();
  ui::ListSelectionModel selection;
  int active_index = -1;

  Value* tab_value = NULL;
  EXTENSION_FUNCTION_VALIDATE(info->Get(keys::kTabsKey, &tab_value));

  std::vector<int> tab_indices;
  EXTENSION_FUNCTION_VALIDATE(extensions::ReadOneOrMoreIntegers(
      tab_value, &tab_indices));

  for (size_t i = 0; i < tab_indices.size(); ++i) {
    int index = tab_indices[i];

    if (!tabstrip->ContainsIndex(index)) {
      error_ = ErrorUtils::FormatErrorMessage(
          keys::kTabIndexNotFoundError, base::IntToString(index));
      return false;
    }

    if (active_index == -1)
      active_index = index;

    selection.AddIndexToSelection(index);
  }

  if (selection.empty()) {
    error_ = keys::kNoHighlightedTabError;
    return false;
  }

  selection.set_active(active_index);
  browser->tab_strip_model()->SetSelectionFromModel(selection);
  SetResult(
      browser->extension_window_controller()->CreateWindowValueWithTabs(
          GetExtension()));
  return true;
}

Project: Chrome

bool TabsUpdateFunction::RunImpl() {
  DictionaryValue* update_props = NULL;
  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &update_props));

  Value* tab_value = NULL;
  if (HasOptionalArgument(0)) {
    EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &tab_value));
  }

  int tab_id = -1;
  WebContents* contents = NULL;
  if (tab_value == NULL || tab_value->IsType(Value::TYPE_NULL)) {
    Browser* browser = GetCurrentBrowser();
    if (!browser) {
      error_ = keys::kNoCurrentWindowError;
      return false;
    }
    contents = browser->tab_strip_model()->GetActiveWebContents();
    if (!contents) {
      error_ = keys::kNoSelectedTabError;
      return false;
    }
    tab_id = SessionID::IdForTab(contents);
  } else {
    EXTENSION_FUNCTION_VALIDATE(tab_value->GetAsInteger(&tab_id));
  }

  int tab_index = -1;
  TabStripModel* tab_strip = NULL;
  if (!GetTabById(tab_id, profile(), include_incognito(),
                  NULL, &tab_strip, &contents, &tab_index, &error_)) {
    return false;
  }

  web_contents_ = contents;


  bool is_async = false;
  if (!UpdateURLIfPresent(update_props, tab_id, &is_async))
    return false;

  bool active = false;
  if (update_props->HasKey(keys::kSelectedKey))
    EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean(
        keys::kSelectedKey, &active));

  if (update_props->HasKey(keys::kActiveKey))
    EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean(
        keys::kActiveKey, &active));

  if (active) {
    if (tab_strip->active_index() != tab_index) {
      tab_strip->ActivateTabAt(tab_index, false);
      DCHECK_EQ(contents, tab_strip->GetActiveWebContents());
    }
    web_contents_->GetDelegate()->ActivateContents(web_contents_);
  }

  if (update_props->HasKey(keys::kHighlightedKey)) {
    bool highlighted = false;
    EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean(
        keys::kHighlightedKey, &highlighted));
    if (highlighted != tab_strip->IsTabSelected(tab_index))
      tab_strip->ToggleSelectionAt(tab_index);
  }

  if (update_props->HasKey(keys::kPinnedKey)) {
    bool pinned = false;
    EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean(
        keys::kPinnedKey, &pinned));
    tab_strip->SetTabPinned(tab_index, pinned);

    tab_index = tab_strip->GetIndexOfWebContents(contents);
  }

  if (update_props->HasKey(keys::kOpenerTabIdKey)) {
    int opener_id = -1;
    EXTENSION_FUNCTION_VALIDATE(update_props->GetInteger(
        keys::kOpenerTabIdKey, &opener_id));

    WebContents* opener_contents = NULL;
    if (!ExtensionTabUtil::GetTabById(
            opener_id, profile(), include_incognito(),
            NULL, NULL, &opener_contents, NULL))
      return false;

    tab_strip->SetOpenerOfWebContentsAt(tab_index, opener_contents);
  }

  if (!is_async) {
    PopulateResult();
    SendResponse(true);
  }
  return true;
}

Project: Chrome

bool TabsMoveFunction::RunImpl() {
  Value* tab_value = NULL;
  EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &tab_value));

  std::vector<int> tab_ids;
  EXTENSION_FUNCTION_VALIDATE(extensions::ReadOneOrMoreIntegers(
      tab_value, &tab_ids));

  DictionaryValue* update_props = NULL;
  int new_index;
  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &update_props));
  EXTENSION_FUNCTION_VALIDATE(update_props->GetInteger(keys::kIndexKey,
      &new_index));

  ListValue tab_values;
  for (size_t i = 0; i < tab_ids.size(); ++i) {
    Browser* source_browser = NULL;
    TabStripModel* source_tab_strip = NULL;
    WebContents* contents = NULL;
    int tab_index = -1;
    if (!GetTabById(tab_ids[i], profile(), include_incognito(),
                    &source_browser, &source_tab_strip, &contents,
                    &tab_index, &error_))
      return false;

    if (!source_browser->window()->IsTabStripEditable()) {
      error_ = keys::kTabStripNotEditableError;
      return false;
    }

    new_index += i;

    if (update_props->HasKey(keys::kWindowIdKey)) {
      Browser* target_browser = NULL;
      int window_id = extension_misc::kUnknownWindowId;
      EXTENSION_FUNCTION_VALIDATE(update_props->GetInteger(
          keys::kWindowIdKey, &window_id));

      if (!GetBrowserFromWindowID(this, window_id, &target_browser))
        return false;

      if (!target_browser->window()->IsTabStripEditable()) {
        error_ = keys::kTabStripNotEditableError;
        return false;
      }

      if (!target_browser->is_type_tabbed()) {
        error_ = keys::kCanOnlyMoveTabsWithinNormalWindowsError;
        return false;
      }

      if (target_browser->profile() != source_browser->profile()) {
        error_ = keys::kCanOnlyMoveTabsWithinSameProfileError;
        return false;
      }

      if (ExtensionTabUtil::GetWindowId(target_browser) !=
          ExtensionTabUtil::GetWindowId(source_browser)) {
        TabStripModel* target_tab_strip = target_browser->tab_strip_model();
        WebContents* web_contents =
            source_tab_strip->DetachWebContentsAt(tab_index);
        if (!web_contents) {
          error_ = ErrorUtils::FormatErrorMessage(
              keys::kTabNotFoundError, base::IntToString(tab_ids[i]));
          return false;
        }

        if (new_index > target_tab_strip->count() || new_index < 0)
          new_index = target_tab_strip->count();

        target_tab_strip->InsertWebContentsAt(
            new_index, web_contents, TabStripModel::ADD_NONE);

        if (has_callback()) {
          tab_values.Append(ExtensionTabUtil::CreateTabValue(
              web_contents,
              target_tab_strip,
              new_index,
              GetExtension()));
        }

        continue;
      }
    }

    if (new_index >= source_tab_strip->count() || new_index < 0)
      new_index = source_tab_strip->count() - 1;

    if (new_index != tab_index)
      source_tab_strip->MoveWebContentsAt(tab_index, new_index, false);

    if (has_callback()) {
      tab_values.Append(ExtensionTabUtil::CreateTabValue(
          contents, source_tab_strip, new_index, GetExtension()));
    }
  }

  if (!has_callback())
    return true;

  if (tab_ids.size() > 1) {
    SetResult(tab_values.DeepCopy());
  } else if (tab_ids.size() == 1) {
    Value* value = NULL;
    CHECK(tab_values.Get(0, &value));
    SetResult(value->DeepCopy());
  }
  return true;
}

Project: Chrome

bool TabsRemoveFunction::RunImpl() {
  Value* tab_value = NULL;
  EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &tab_value));

  std::vector<int> tab_ids;
  EXTENSION_FUNCTION_VALIDATE(extensions::ReadOneOrMoreIntegers(
      tab_value, &tab_ids));

  for (size_t i = 0; i < tab_ids.size(); ++i) {
    Browser* browser = NULL;
    WebContents* contents = NULL;
    if (!GetTabById(tab_ids[i], profile(), include_incognito(),
                    &browser, NULL, &contents, NULL, &error_))
      return false;

    if (!browser->window()->IsTabStripEditable()) {
      error_ = keys::kTabStripNotEditableError;
      return false;
    }

    contents->Close();
  }
  return true;
}

Project: Chrome

bool TabsDetectLanguageFunction::RunImpl() {
  int tab_id = 0;
  Browser* browser = NULL;
  WebContents* contents = NULL;

  if (HasOptionalArgument(0)) {
    EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id));
    if (!GetTabById(tab_id, profile(), include_incognito(),
                    &browser, NULL, &contents, NULL, &error_)) {
      return false;
    }
    if (!browser || !contents)
      return false;
  } else {
    browser = GetCurrentBrowser();
    if (!browser)
      return false;
    contents = browser->tab_strip_model()->GetActiveWebContents();
    if (!contents)
      return false;
  }

  if (contents->GetController().NeedsReload()) {
    error_ = keys::kCannotDetermineLanguageOfUnloadedTab;
    return false;
  }

  AddRef();  // Balanced in GotLanguage().

  TranslateTabHelper* translate_tab_helper =
      TranslateTabHelper::FromWebContents(contents);
  if (!translate_tab_helper->language_state().original_language().empty()) {
    MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
        &TabsDetectLanguageFunction::GotLanguage, this,
        translate_tab_helper->language_state().original_language()));
    return true;
  }
  registrar_.Add(this, chrome::NOTIFICATION_TAB_LANGUAGE_DETERMINED,
                 content::Source<WebContents>(contents));
  registrar_.Add(
      this, chrome::NOTIFICATION_TAB_CLOSING,
      content::Source<NavigationController>(&(contents->GetController())));
  registrar_.Add(
      this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
      content::Source<NavigationController>(&(contents->GetController())));
  return true;
}

Project: Chrome

bool ExecuteCodeInTabFunction::RunImpl() {
  EXTENSION_FUNCTION_VALIDATE(Init());

  if (!details_->code.get() && !details_->file.get()) {
    error_ = keys::kNoCodeOrFileToExecuteError;
    return false;
  }
  if (details_->code.get() && details_->file.get()) {
    error_ = keys::kMoreThanOneValuesError;
    return false;
  }

  content::WebContents* contents = NULL;

  CHECK_GE(execute_tab_id_, 0);
  if (!GetTabById(execute_tab_id_, profile(),
                  include_incognito(),
                  NULL, NULL, &contents, NULL, &error_)) {
    return false;
  }

  CHECK(contents);
  if (!GetExtension()->CanExecuteScriptOnPage(contents->GetURL(),
                                              contents->GetURL(),
                                              execute_tab_id_,
                                              NULL,
                                              &error_)) {
    return false;
  }

  if (details_->code.get())
    return Execute(*details_->code);

  CHECK(details_->file.get());
  resource_ = GetExtension()->GetResource(*details_->file);

  if (resource_.extension_root().empty() || resource_.relative_path().empty()) {
    error_ = keys::kNoCodeOrFileToExecuteError;
    return false;
  }

  scoped_refptr<FileReader> file_reader(new FileReader(
      resource_, base::Bind(&ExecuteCodeInTabFunction::DidLoadFile, this)));
  file_reader->Start();

  return true;
}

Project: Chrome

void TabsCaptureVisibleTabFunction::SendInternalError() {
  error_ = keys::kInternalVisibleTabCaptureError;
  SendResponse(false);
}

Project: Chrome

void TabsCaptureVisibleTabFunction::SendResultFromBitmap(
    const SkBitmap& screen_capture) {
  std::vector<unsigned char> data;
  SkAutoLockPixels screen_capture_lock(screen_capture);
  bool encoded = false;
  std::string mime_type;
  switch (image_format_) {
    case FORMAT_JPEG:
      encoded = gfx::JPEGCodec::Encode(
          reinterpret_cast<unsigned char*>(screen_capture.getAddr32(0, 0)),
          gfx::JPEGCodec::FORMAT_SkBitmap,
          screen_capture.width(),
          screen_capture.height(),
          static_cast<int>(screen_capture.rowBytes()),
          image_quality_,
          &data);
      mime_type = keys::kMimeTypeJpeg;
      break;
    case FORMAT_PNG:
      encoded = gfx::PNGCodec::EncodeBGRASkBitmap(
          screen_capture,
          true,  // Discard transparency.
          &data);
      mime_type = keys::kMimeTypePng;
      break;
    default:
      NOTREACHED() << "Invalid image format.";
  }

  if (!encoded) {
    error_ = keys::kInternalVisibleTabCaptureError;
    SendResponse(false);
    return;
  }

  std::string base64_result;
  base::StringPiece stream_as_string(
      reinterpret_cast<const char*>(vector_as_array(&data)), data.size());

  base::Base64Encode(stream_as_string, &base64_result);
  base64_result.insert(0, base::StringPrintf("data:%s;base64,",
                                             mime_type.c_str()));
  SetResult(new StringValue(base64_result));
  SendResponse(true);
}

Project: Chrome

bool WindowsCreateFunction::ShouldOpenIncognitoWindow(
    const base::DictionaryValue* args,
    std::vector<GURL>* urls,
    bool* is_error) {
  *is_error = false;
  const IncognitoModePrefs::Availability incognito_availability =
      IncognitoModePrefs::GetAvailability(profile_->GetPrefs());
  bool incognito = false;
  if (args && args->HasKey(keys::kIncognitoKey)) {
    EXTENSION_FUNCTION_VALIDATE(args->GetBoolean(keys::kIncognitoKey,
                                                 &incognito));
    if (incognito && incognito_availability == IncognitoModePrefs::DISABLED) {
      error_ = keys::kIncognitoModeIsDisabled;
      *is_error = true;
      return false;
    }
    if (!incognito && incognito_availability == IncognitoModePrefs::FORCED) {
      error_ = keys::kIncognitoModeIsForced;
      *is_error = true;
      return false;
    }
  } else if (incognito_availability == IncognitoModePrefs::FORCED) {
    incognito = true;
  }

  if (incognito && !profile_->IsGuestSession()) {
    std::string first_url_erased;
    for (size_t i = 0; i < urls->size();) {
      if (chrome::IsURLAllowedInIncognito((*urls)[i], profile())) {
        i++;
      } else {
        if (first_url_erased.empty())
          first_url_erased = (*urls)[i].spec();
        urls->erase(urls->begin() + i);
      }
    }
    if (urls->empty() && !first_url_erased.empty()) {
      error_ = ErrorUtils::FormatErrorMessage(
          keys::kURLsNotAllowedInIncognitoError, first_url_erased);
      *is_error = true;
      return false;
    }
  }
  return incognito;
}

Project: Chrome

TabsUpdateFunction::TabsUpdateFunction() : web_contents_(NULL) {
}

Project: Chrome

bool TabsUpdateFunction::UpdateURLIfPresent(DictionaryValue* update_props,
                                           int tab_id,
                                           bool* is_async) {
  if (!update_props->HasKey(keys::kUrlKey))
    return true;

  std::string url_string;
  EXTENSION_FUNCTION_VALIDATE(update_props->GetString(
      keys::kUrlKey, &url_string));
  GURL url = ExtensionTabUtil::ResolvePossiblyRelativeURL(
      url_string, GetExtension());

  if (!url.is_valid()) {
    error_ = ErrorUtils::FormatErrorMessage(
        keys::kInvalidUrlError, url_string);
    return false;
  }

  if (ExtensionTabUtil::IsCrashURL(url)) {
    error_ = keys::kNoCrashBrowserError;
    return false;
  }

  if (url.SchemeIs(chrome::kJavaScriptScheme)) {
    if (!GetExtension()->CanExecuteScriptOnPage(
            web_contents_->GetURL(),
            web_contents_->GetURL(),
            tab_id,
            NULL,
            &error_)) {
      return false;
    }

    extensions::TabHelper::FromWebContents(web_contents_)->
        script_executor()->ExecuteScript(
            extension_id(),
            ScriptExecutor::JAVASCRIPT,
            url.path(),
            ScriptExecutor::TOP_FRAME,
            extensions::UserScript::DOCUMENT_IDLE,
            ScriptExecutor::MAIN_WORLD,
            false /* is_web_view */,
            base::Bind(&TabsUpdateFunction::OnExecuteCodeFinished, this));

    *is_async = true;
    return true;
  }

  web_contents_->GetController().LoadURL(
      url, content::Referrer(), content::PAGE_TRANSITION_LINK, std::string());

  if (!url.SchemeIs(chrome::kJavaScriptScheme))
    DCHECK_EQ(url.spec(), web_contents_->GetURL().spec());

  return true;
}

Project: Chrome

ExecuteCodeInTabFunction::~ExecuteCodeInTabFunction() {}