-
Notifications
You must be signed in to change notification settings - Fork 24
fix(android): sync Cronet and token-refresh requests with CookieManager #73
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
Changes from 1 commit
c343524
7d4c684
6a26d11
25f5968
f3ba8fe
07a1a5c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,6 +2,7 @@ package com.margelo.nitro.nitrofetch | |
|
|
||
| import android.app.Application | ||
| import android.content.Context | ||
| import android.webkit.CookieManager | ||
| import org.json.JSONArray | ||
| import org.json.JSONObject | ||
| import java.net.HttpURLConnection | ||
|
|
@@ -151,16 +152,47 @@ object AutoPrefetcher { | |
| conn.doInput = true | ||
| if (body != null) conn.doOutput = true | ||
|
|
||
| var hasCookieHeader = false | ||
| reqHeaders?.keys()?.forEachRemaining { k -> | ||
| if (k.equals("Cookie", ignoreCase = true)) hasCookieHeader = true | ||
| conn.setRequestProperty(k, reqHeaders.optString(k, "")) | ||
| } | ||
|
|
||
| if (!hasCookieHeader) { | ||
| try { | ||
| val jar = CookieManager.getInstance() | ||
| val cookieHeader = jar.getCookie(urlStr) | ||
| if (!cookieHeader.isNullOrEmpty()) { | ||
| conn.setRequestProperty("Cookie", cookieHeader) | ||
| } | ||
| } catch (_: Throwable) { | ||
| // Best-effort — CookieManager may not be initialized yet | ||
| } | ||
| } | ||
|
|
||
| if (body != null) { | ||
| conn.outputStream.use { it.write(body.toByteArray(Charsets.UTF_8)) } | ||
| } | ||
|
|
||
| val status = conn.responseCode | ||
| if (status !in 200..299) return null | ||
| if (status !in 200..299) { | ||
| android.util.Log.d("NitroFetch", "[TokenRefresh] Refresh endpoint returned HTTP $status") | ||
| return null | ||
| } | ||
|
|
||
| try { | ||
| val cookieManager = CookieManager.getInstance() | ||
| conn.headerFields?.forEach { (key, values) -> | ||
| if (key?.equals("Set-Cookie", ignoreCase = true) == true) { | ||
| values.forEach { cookieValue -> | ||
| cookieManager.setCookie(urlStr, cookieValue) | ||
| } | ||
| } | ||
| } | ||
| cookieManager.flush() | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will run everytime even though we dont have cookies . Maybe we can add check here to run only if actually set-cookie exist
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also maybe we flush once on onSucceeded . Idk if thats good . Ideally we should not flush on every redirect |
||
| } catch (_: Throwable) { | ||
| // Best-effort — CookieManager may not be initialized yet | ||
| } | ||
|
|
||
| val responseBody = conn.inputStream.use { it.bufferedReader(Charsets.UTF_8).readText() } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,7 @@ package com.margelo.nitro.nitrofetch | |
| import android.net.Uri | ||
| import android.os.Trace | ||
| import android.util.Log | ||
| import android.webkit.CookieManager | ||
| import com.facebook.proguard.annotations.DoNotStrip | ||
| import com.margelo.nitro.NitroModules | ||
| import com.margelo.nitro.core.ArrayBuffer | ||
|
|
@@ -48,6 +49,25 @@ class NitroFetchClient(private val engine: CronetEngine, private val executor: E | |
| } | ||
|
|
||
| companion object { | ||
| private fun hasCookieHeader(request: NitroRequest): Boolean { | ||
| return request.headers?.any { it.key.equals("Cookie", ignoreCase = true) } == true | ||
| } | ||
|
|
||
| private fun storeResponseCookies(responseUrl: String, info: UrlResponseInfo) { | ||
| try { | ||
| val cookieManager = CookieManager.getInstance() | ||
| val setCookieHeaders = info.allHeadersAsList.filter { | ||
| it.key.equals("Set-Cookie", ignoreCase = true) | ||
| } | ||
| for (header in setCookieHeaders) { | ||
| cookieManager.setCookie(responseUrl, header.value) | ||
| } | ||
| cookieManager.flush() | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above |
||
| } catch (exception: Exception) { | ||
| Log.w("NitroFetchClient", "Failed to store response cookies", exception) | ||
| } | ||
| } | ||
|
|
||
| @JvmStatic | ||
| fun fetch( | ||
| req: NitroRequest, | ||
|
|
@@ -87,6 +107,7 @@ class NitroFetchClient(private val engine: CronetEngine, private val executor: E | |
|
|
||
| override fun onRedirectReceived(request: UrlRequest, info: UrlResponseInfo, newLocationUrl: String) { | ||
| if (shouldFollowRedirects) { | ||
| storeResponseCookies(info.url, info) | ||
| request.followRedirect() | ||
| } else { | ||
| // Return the redirect response as-is without following | ||
|
|
@@ -131,6 +152,7 @@ class NitroFetchClient(private val engine: CronetEngine, private val executor: E | |
| Trace.endAsyncSection(traceLabel, traceCookie) | ||
| } | ||
| try { | ||
| storeResponseCookies(info.url, info) | ||
| val headersArr: Array<NitroHeader> = | ||
| info.allHeadersAsList.map { NitroHeader(it.key, it.value) }.toTypedArray() | ||
| val status = info.httpStatusCode | ||
|
|
@@ -184,6 +206,18 @@ class NitroFetchClient(private val engine: CronetEngine, private val executor: E | |
| builder.setHttpMethod(method) | ||
| req.headers?.forEach { (k, v) -> builder.addHeader(k, v) } | ||
|
|
||
| if (!hasCookieHeader(req)) { | ||
| try { | ||
| val cookieManager = CookieManager.getInstance() | ||
| val cookie = cookieManager.getCookie(url) | ||
| if (!cookie.isNullOrEmpty()) { | ||
| builder.addHeader("Cookie", cookie) | ||
| } | ||
| } catch (exception: Exception) { | ||
| Log.w("NitroFetchClient", "Failed to attach cookie header", exception) | ||
| } | ||
| } | ||
|
|
||
| val formParts = req.bodyFormData | ||
| if (formParts != null && formParts.isNotEmpty()) { | ||
| val (multipartBody, contentType) = buildMultipartBody(formParts) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lets create this in a function like NitroFetchClient.kt . Lets avoid 2 code doing the exact thing but in different ways