-
Notifications
You must be signed in to change notification settings - Fork 9.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement an efficient Android CookieJar (sqldelight?) #2890
Comments
Is it possible add |
Yeah, just copy it into your codebase. |
Could you release a new version okhttp3? React-Native need QuotePreservingCookieJar.java to address Issue 10121. |
We will not be adding |
Still up for this one? Mind if I take a crack at it? I've started reviewing https://tools.ietf.org/html/rfc6265 and the internal Java (CookieManager/InMemoryCookieStore) implementations. I assume this will be replacing those things. It seems okhttp3.Cookie is already doing a lot of the heavy lifting, so thinking this shouldn't be a huge undertaking. |
Yeah for sure. The most difficult part is deciding how the persistence model works. I’d love to have Sqlite but sadly we don’t. What do you think? |
Ahh, I see. So this should support automatic disk persistence, in addition to in memory. RE: SQLite - I'm still getting up to speed so I'm not entirely sure the role there. My hunch is that would provide faster access when reading cookies from disk on a fresh load. I wonder if a simple index would work there. I don't know enough yet on the access patterns, so maybe it wouldn't be enough. |
I, from my perspective as a user, would be very happy with an in-memory implementation as a first addition. |
There’s a handful of interesting problems we’d be able to solve with a
Maybe that’s sufficient to start? |
Alright, I'll attempt to draft something using the CookieJar as a first client and see where that takes me. |
I did some experimenting here and realized, would it make sense to back this with DiskLruCache? It seems any key-value like storage would behave in a similar way:
All of these are supported by DiskLruCache. |
You’re blowing my mind a bit, I never thought of that as an option! Yeah, for sure. Keys would be domain names? |
In case it can be of any help you can check my implementation of a PersistentCookieJar. Some problems that I see with it for the moment:
Both problems can be solved with your proposals. For example using the DiskLruCache and storing all cookies of the same domain(ignoring subdomains) into .properties files and deserializing the .properties into a collection in memory after the first call to loadForRequestUrl() for any URL of the domain. |
@swankjesse yes, that's my thought right now. Thanks @franmontiel, I'll have a look. |
@swankjesse I'm a little confused why I have a use case for explicitly using cookie values surrounded by quotes such as Is there any plan for future OkHttp3 releases stopping the deletion of quotes in I'm syncing cookies between Just realized 3.10 milestone on the sidebar. Is that when the new default cookie jar implementation aimed to be released in? Is the recommendation just replacing |
We'll probably punt this beyond 3.10. Getting this right is challenging because OkHttp can't use Android-only APIs. I recommend the persistent cookie jar code linked above if you're targeting Android and not the JVM. |
With the release of 4.x, where does this issue stand? |
I use this implementation to store cookies in memory (Inspired by PersistentCookieJar). class MemoryCookieJar : CookieJar {
private val cache = mutableSetOf<WrappedCookie>()
@Synchronized
override fun loadForRequest(url: HttpUrl): List<Cookie> {
val cookiesToRemove = mutableSetOf<WrappedCookie>()
val validCookies = mutableSetOf<WrappedCookie>()
cache.forEach { cookie ->
if (cookie.isExpired()) {
cookiesToRemove.add(cookie)
} else if (cookie.matches(url)) {
validCookies.add(cookie)
}
}
cache.removeAll(cookiesToRemove)
return validCookies.toList().map(WrappedCookie::unwrap)
}
@Synchronized
override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {
val cookiesToAdd = cookies.map { WrappedCookie.wrap(it) }
cache.removeAll(cookiesToAdd)
cache.addAll(cookiesToAdd)
}
@Synchronized
fun clear() {
cache.clear()
}
}
class WrappedCookie private constructor(val cookie: Cookie) {
fun unwrap() = cookie
fun isExpired() = cookie.expiresAt < System.currentTimeMillis()
fun matches(url: HttpUrl) = cookie.matches(url)
override fun equals(other: Any?): Boolean {
if (other !is WrappedCookie) return false
return other.cookie.name == cookie.name &&
other.cookie.domain == cookie.domain &&
other.cookie.path == cookie.path &&
other.cookie.secure == cookie.secure &&
other.cookie.hostOnly == cookie.hostOnly
}
override fun hashCode(): Int {
var hash = 17
hash = 31 * hash + cookie.name.hashCode()
hash = 31 * hash + cookie.domain.hashCode()
hash = 31 * hash + cookie.path.hashCode()
hash = 31 * hash + if (cookie.secure) 0 else 1
hash = 31 * hash + if (cookie.hostOnly) 0 else 1
return hash
}
companion object {
fun wrap(cookie: Cookie) = WrappedCookie(cookie)
}
} Usage: val okHttp = OkHttpClient.Builder()
.cookieJar(MemoryCookieJar())
.build() |
I would also like to see OkHttp's own |
@headsvk yikes. Looks like they inexplicably introduced a regression. |
Arguably this paragraph in the spec says that a Set-Cookie with non matching path can be rejected
But this is a stretch, and it isn't clearly spelled out in MUST, SHOULD terms. Just implied here. |
Any opinion as of 4.9.0 of whether you'd be happy with an okhttp-android module using Android APIs here. I think we have test infra now (locally, not CI yet) to build against this correctly. |
The feature we want is sqlite storage, or perhaps even MySQL storage. Doing a module that uses SQDelight to store cookies to a DB would be a nice win. Could also do similarly for HSTS, for example. |
@swankjesse is this worthwhile for 5.0? We can now use android APIs. |
Not for 5.0. Good for the backlog. |
The
JavaNetCookieJar
is a hazard to use, particularly because it usesHttpCookie
behind the scenes. That class unnecessarily quotes cookie values, and we need to do gross things to strip them off. This behavior is particularly bad because sometimes it doesn’t strip the quotes and we end up stripping off quotes that we shouldn’t.The text was updated successfully, but these errors were encountered: