Commit message: None
CVE: CVE-2015-6772
CWE: CWE-264
Vulnerability description: The DOM implementation in Blink, as used in Google Chrome before 47.0.2526.73, does not prevent javascript: URL navigation while a document is being detached, which allows remote attackers to bypass the Same Origin Policy via crafted JavaScript code that improperly interacts with a plugin.

Project: Chrome

void OfflinePageDownloadBridge::Destroy(JNIEnv* env,
                                        const JavaParamRef<jobject>&) {
  delete this;
}

Project: Chrome

void DownloadAsFile(content::WebContents* web_contents, const GURL& url) {
  content::DownloadManager* dlm = content::BrowserContext::GetDownloadManager(
      web_contents->GetBrowserContext());
  std::unique_ptr<download::DownloadUrlParameters> dl_params(
      content::DownloadRequestUtils::CreateDownloadForWebContentsMainFrame(
          web_contents, url, NO_TRAFFIC_ANNOTATION_YET));

  content::NavigationEntry* entry =
      web_contents->GetController().GetLastCommittedEntry();
  DCHECK(entry);
  content::Referrer referrer =
      content::Referrer::SanitizeForRequest(url, entry->GetReferrer());
  dl_params->set_referrer(referrer.url);
  dl_params->set_referrer_policy(content::Referrer::ReferrerPolicyForUrlRequest(
      referrer.policy));

  dl_params->set_prefer_cache(true);
  dl_params->set_prompt(false);
  dl_params->set_download_source(download::DownloadSource::OFFLINE_PAGE);
  dlm->DownloadUrl(std::move(dl_params));
}

Project: Chrome

DownloadUIAdapterDelegate::DownloadUIAdapterDelegate(OfflinePageModel* model)
    : model_(model) {}

Project: Chrome

void DuplicateCheckDone(const GURL& url,
                        const GURL& original_url,
                        const ScopedJavaGlobalRef<jobject>& j_tab_ref,
                        const std::string& origin,
                        OfflinePageUtils::DuplicateCheckResult result) {
  if (result == OfflinePageUtils::DuplicateCheckResult::NOT_FOUND) {
    SavePageIfNotNavigatedAway(url, original_url, j_tab_ref, origin);
    return;
  }

  content::WebContents* web_contents = GetWebContentsFromJavaTab(j_tab_ref);
  if (!web_contents)
    return;

  bool duplicate_request_exists =
      result == OfflinePageUtils::DuplicateCheckResult::DUPLICATE_REQUEST_FOUND;
  OfflinePageInfoBarDelegate::Create(
      base::Bind(&SavePageIfNotNavigatedAway, url, original_url, j_tab_ref,
                 origin),
      url, duplicate_request_exists, web_contents);
}

Project: Chrome

content::WebContents* GetWebContentsByFrameID(int render_process_id,
                                              int render_frame_id) {
  content::RenderFrameHost* render_frame_host =
      content::RenderFrameHost::FromID(render_process_id, render_frame_id);
  if (!render_frame_host)
    return NULL;
  return content::WebContents::FromRenderFrameHost(render_frame_host);
}

Project: Chrome

content::ResourceRequestInfo::WebContentsGetter GetWebContentsGetter(
    content::WebContents* web_contents) {
  int frame_tree_node_id = web_contents->GetMainFrame()->GetFrameTreeNodeId();
  if (frame_tree_node_id != -1) {
    return base::Bind(content::WebContents::FromFrameTreeNodeId,
                      frame_tree_node_id);
  }

  return base::Bind(&GetWebContentsByFrameID,
                    web_contents->GetMainFrame()->GetProcess()->GetID(),
                    web_contents->GetMainFrame()->GetRoutingID());
}

Project: Chrome

bool DownloadUIAdapterDelegate::IsTemporarilyHiddenInUI(
    const ClientId& client_id) {
  return false;
}

Project: Chrome

bool DownloadUIAdapterDelegate::IsVisibleInUI(const ClientId& client_id) {
  const std::string& name_space = client_id.name_space;
  return model_->GetPolicyController()->IsSupportedByDownload(name_space) &&
         base::IsValidGUID(client_id.id);
}

Project: Chrome

void JNI_OfflinePageDownloadBridge_StartDownload(
    JNIEnv* env,
    const JavaParamRef<jclass>& clazz,
    const JavaParamRef<jobject>& j_tab,
    const JavaParamRef<jstring>& j_origin) {
  TabAndroid* tab = TabAndroid::GetNativeTab(env, j_tab);
  if (!tab)
    return;

  content::WebContents* web_contents = tab->web_contents();
  if (!web_contents)
    return;

  std::string origin = ConvertJavaStringToUTF8(env, j_origin);
  ScopedJavaGlobalRef<jobject> j_tab_ref(env, j_tab);

  content::ResourceRequestInfo::WebContentsGetter web_contents_getter =
      GetWebContentsGetter(web_contents);
  DownloadControllerBase::Get()->AcquireFileAccessPermission(
      web_contents_getter,
      base::Bind(&OnOfflinePageAcquireFileAccessPermissionDone,
                 web_contents_getter, j_tab_ref, origin));
}

Project: Chrome

OfflinePageDownloadBridge::OfflinePageDownloadBridge(
    JNIEnv* env,
    const JavaParamRef<jobject>& obj)
    : weak_java_ref_(env, obj) {}

Project: Chrome

void OnOfflinePageAcquireFileAccessPermissionDone(
    const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter,
    const ScopedJavaGlobalRef<jobject>& j_tab_ref,
    const std::string& origin,
    bool granted) {
  if (!granted)
    return;

  content::WebContents* web_contents = web_contents_getter.Run();
  if (!web_contents)
    return;

  GURL url = web_contents->GetLastCommittedURL();
  if (url.is_empty())
    return;

  if (!offline_pages::OfflinePageUtils::CanDownloadAsOfflinePage(
          url, web_contents->GetContentsMimeType())) {
    DownloadAsFile(web_contents, url);
    return;
  }

  GURL original_url =
      offline_pages::OfflinePageUtils::GetOriginalURLFromWebContents(
          web_contents);
  OfflinePageUtils::CheckDuplicateDownloads(
      chrome::GetBrowserContextRedirectedInIncognito(
          web_contents->GetBrowserContext()),
      url,
      base::Bind(&DuplicateCheckDone, url, original_url, j_tab_ref, origin));
}

Project: Chrome

void SavePageIfNotNavigatedAway(const GURL& url,
                                const GURL& original_url,
                                const ScopedJavaGlobalRef<jobject>& j_tab_ref,
                                const std::string& origin) {
  content::WebContents* web_contents = GetWebContentsFromJavaTab(j_tab_ref);
  if (!web_contents)
    return;

  GURL current_url = web_contents->GetLastCommittedURL();
  if (!OfflinePageUtils::EqualsIgnoringFragment(current_url, url))
    return;

  offline_pages::ClientId client_id;
  client_id.name_space = offline_pages::kDownloadNamespace;
  client_id.id = base::GenerateGUID();
  int64_t request_id = OfflinePageModel::kInvalidOfflineId;

  if (offline_pages::IsBackgroundLoaderForDownloadsEnabled()) {
    offline_pages::RequestCoordinator* request_coordinator =
        offline_pages::RequestCoordinatorFactory::GetForBrowserContext(
            web_contents->GetBrowserContext());
    if (request_coordinator) {
      offline_pages::RequestCoordinator::SavePageLaterParams params;
      params.url = current_url;
      params.client_id = client_id;
      params.availability =
          RequestCoordinator::RequestAvailability::DISABLED_FOR_OFFLINER;
      params.original_url = original_url;
      params.request_origin = origin;
      request_id =
          request_coordinator->SavePageLater(params, base::DoNothing());
    } else {
      DVLOG(1) << "SavePageIfNotNavigatedAway has no valid coordinator.";
    }
  }

  offline_pages::RecentTabHelper* tab_helper =
      RecentTabHelper::FromWebContents(web_contents);
  if (!tab_helper) {
    if (request_id != OfflinePageModel::kInvalidOfflineId) {
      offline_pages::RequestCoordinator* request_coordinator =
          offline_pages::RequestCoordinatorFactory::GetForBrowserContext(
              web_contents->GetBrowserContext());
      if (request_coordinator)
        request_coordinator->EnableForOffliner(request_id, client_id);
      else
        DVLOG(1) << "SavePageIfNotNavigatedAway has no valid coordinator.";
    }
    return;
  }
  tab_helper->ObserveAndDownloadCurrentPage(client_id, request_id, origin);

  OfflinePageNotificationBridge notification_bridge;
  notification_bridge.ShowDownloadingToast();
}

Project: Chrome

void DownloadUIAdapterDelegate::SetUIAdapter(DownloadUIAdapter* ui_adapter) {}

Project: Chrome

OfflinePageDownloadBridge::~OfflinePageDownloadBridge() {}