blob: abc62c6ec2c11735b7a351755f530e5745ed5972 [file] [log] [blame]
// Copyright 2015 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/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/time/time.h"
#include "chrome/browser/android/cookies/cookies_fetcher.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_switches.h"
#include "jni/CookiesFetcher_jni.h"
#include "net/cookies/cookie_monster.h"
#include "net/cookies/cookie_store.h"
#include "net/url_request/url_request_context.h"
CookiesFetcher::CookiesFetcher(JNIEnv* env, jobject obj, Profile* profile) {
}
CookiesFetcher::~CookiesFetcher() {
}
void CookiesFetcher::Destroy(JNIEnv* env, const JavaParamRef<jobject>& obj) {
delete this;
}
void CookiesFetcher::PersistCookies(JNIEnv* env,
const JavaParamRef<jobject>& obj) {
Profile* profile = ProfileManager::GetPrimaryUserProfile();
if (!profile->HasOffTheRecordProfile()) {
// There is no work to be done. We might consider calling
// the Java callback if needed.
return;
}
profile = profile->GetOffTheRecordProfile();
scoped_refptr<net::URLRequestContextGetter> getter(
profile->GetRequestContext());
// Take a strong global reference to the Java counter part and hold
// on to it. This ensures the object would not be GC'd so we can call
// the Java callback.
jobject_.Reset(env, obj);
// The rest must be done from the IO thread.
content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
base::Bind(&CookiesFetcher::PersistCookiesInternal,
base::Unretained(this), getter));
}
void CookiesFetcher::PersistCookiesInternal(
net::URLRequestContextGetter* getter) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
net::CookieStore* store = getter->GetURLRequestContext()->cookie_store();
// Nullable sometimes according to docs. There is no work need to be done
// but we can consider calling the Java callback with empty output.
if (!store) {
jobject_.Reset();
return;
}
net::CookieMonster* monster = store->GetCookieMonster();
monster->GetAllCookiesAsync(base::Bind(
&CookiesFetcher::OnCookiesFetchFinished, base::Unretained(this)));
}
void CookiesFetcher::OnCookiesFetchFinished(const net::CookieList& cookies) {
JNIEnv* env = base::android::AttachCurrentThread();
ScopedJavaLocalRef<jobjectArray> joa =
Java_CookiesFetcher_createCookiesArray(
env, jobject_.obj(), cookies.size());
int index = 0;
for (net::CookieList::const_iterator i = cookies.begin();
i != cookies.end(); ++i) {
ScopedJavaLocalRef<jobject> java_cookie = Java_CookiesFetcher_createCookie(
env, jobject_.obj(),
base::android::ConvertUTF8ToJavaString(env, i->Source().spec()).obj(),
base::android::ConvertUTF8ToJavaString(env, i->Name()).obj(),
base::android::ConvertUTF8ToJavaString(env, i->Value()).obj(),
base::android::ConvertUTF8ToJavaString(env, i->Domain()).obj(),
base::android::ConvertUTF8ToJavaString(env, i->Path()).obj(),
i->CreationDate().ToInternalValue(), i->ExpiryDate().ToInternalValue(),
i->LastAccessDate().ToInternalValue(), i->IsSecure(), i->IsHttpOnly(),
i->IsSameSite(), i->Priority());
env->SetObjectArrayElement(joa.obj(), index++, java_cookie.obj());
}
Java_CookiesFetcher_onCookieFetchFinished(env, jobject_.obj(), joa.obj());
// Give up the reference.
jobject_.Reset();
}
void CookiesFetcher::RestoreCookies(JNIEnv* env,
const JavaParamRef<jobject>& obj,
const JavaParamRef<jstring>& url,
const JavaParamRef<jstring>& name,
const JavaParamRef<jstring>& value,
const JavaParamRef<jstring>& domain,
const JavaParamRef<jstring>& path,
int64_t creation,
int64_t expiration,
int64_t last_access,
bool secure,
bool httponly,
bool same_site,
int priority) {
Profile* profile = ProfileManager::GetPrimaryUserProfile();
if (!profile->HasOffTheRecordProfile()) {
return; // Don't create it. There is nothing to do.
}
profile = profile->GetOffTheRecordProfile();
scoped_refptr<net::URLRequestContextGetter> getter(
profile->GetRequestContext());
net::CanonicalCookie cookie(
GURL(base::android::ConvertJavaStringToUTF8(env, url)),
base::android::ConvertJavaStringToUTF8(env, name),
base::android::ConvertJavaStringToUTF8(env, value),
base::android::ConvertJavaStringToUTF8(env, domain),
base::android::ConvertJavaStringToUTF8(env, path),
base::Time::FromInternalValue(creation),
base::Time::FromInternalValue(expiration),
base::Time::FromInternalValue(last_access), secure, httponly, same_site,
static_cast<net::CookiePriority>(priority));
// The rest must be done from the IO thread.
content::BrowserThread::PostTask(
content::BrowserThread::IO,
FROM_HERE,
base::Bind(&CookiesFetcher::RestoreToCookieJarInternal,
base::Unretained(this),
getter,
cookie));
}
void CookiesFetcher::RestoreToCookieJarInternal(
net::URLRequestContextGetter* getter,
const net::CanonicalCookie& cookie) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
net::CookieStore* store = getter->GetURLRequestContext()->cookie_store();
// Nullable sometimes according to docs.
if (!store) {
return;
}
net::CookieMonster* monster = store->GetCookieMonster();
base::Callback<void(bool success)> cb;
// TODO(estark): Remove kEnableExperimentalWebPlatformFeatures check
// when we decide whether to ship cookie
// prefixes. https://crbug.com/541511
bool experimental_features_enabled =
base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableExperimentalWebPlatformFeatures);
monster->SetCookieWithDetailsAsync(
cookie.Source(), cookie.Name(), cookie.Value(), cookie.Domain(),
cookie.Path(), cookie.ExpiryDate(), cookie.IsSecure(),
cookie.IsHttpOnly(), cookie.IsSameSite(), experimental_features_enabled,
experimental_features_enabled, cookie.Priority(), cb);
}
// JNI functions
static jlong Init(JNIEnv* env, const JavaParamRef<jobject>& obj) {
return reinterpret_cast<intptr_t>(new CookiesFetcher(env, obj, 0));
}
// Register native methods
bool RegisterCookiesFetcher(JNIEnv* env) {
return RegisterNativesImpl(env);
}