From fb08f2d7ac8a5b716e582869d070564b113fe616 Mon Sep 17 00:00:00 2001 From: Fahim Masud Choudhury Date: Mon, 17 Nov 2025 20:51:09 +0600 Subject: [PATCH 1/2] fix: resolve cookie handling for large number of Notes sync requests For syncing large number of notes in Notes app, the requests often fell into inconsistent cookie state, where some requests contained cookies where others did not. These cookies made the server create new sessions, forcing it to often overwhelm with too many sessions. Instead of only clearing the cookie state, the `Cookie` request header is now explicitly removed for requests where cookies are disabled. (Notes, for now). The cookie policy is temporarily overridden to `IGNORE_COOKIES` during the request execution and then restored. --- .../android/lib/common/OwnCloudClient.java | 64 ++++++++++++++++--- 1 file changed, 55 insertions(+), 9 deletions(-) diff --git a/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClient.java b/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClient.java index 02572cd58..577352858 100644 --- a/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClient.java +++ b/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClient.java @@ -27,6 +27,8 @@ package com.owncloud.android.lib.common; import android.net.Uri; +import androidx.annotation.IntDef; + import com.nextcloud.common.DNSCache; import com.nextcloud.common.NextcloudUriDelegate; import com.owncloud.android.lib.common.accounts.AccountUtils; @@ -47,7 +49,6 @@ import org.apache.commons.httpclient.cookie.CookiePolicy; import org.apache.commons.httpclient.params.HttpMethodParams; import org.apache.commons.httpclient.params.HttpParams; -import androidx.annotation.IntDef; import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Retention; @@ -68,16 +69,17 @@ public class OwnCloudClient extends HttpClient { private static final boolean PARAM_SINGLE_COOKIE_HEADER_VALUE = true; private static final String PARAM_PROTOCOL_VERSION = "http.protocol.version"; - private static byte[] sExhaustBuffer = new byte[1024]; + private static final byte[] sExhaustBuffer = new byte[1024]; + private static final String HEADER_NAME_COOKIE = "Cookie"; private static int sInstanceCounter = 0; private final NextcloudUriDelegate nextcloudUriDelegate; private boolean followRedirects = true; private OwnCloudCredentials credentials = null; - private int mInstanceNumber; + private final int mInstanceNumber; private boolean shouldResetCookie = false; - private @CookiesPolicy int cookiesPolicy; + private final @CookiesPolicy int cookiesPolicy; public static final int USE_COOKIES = 0; public static final int DONT_USE_COOKIES = 1; @@ -213,18 +215,32 @@ public class OwnCloudClient extends HttpClient { method.setFollowRedirects(false); /* - * We want to clear cookies here specifically for Notes API. - * Indeed, The Notes server APIs have the Cross-Origin Resource Sharing (CORS) flag, + * We want to ensure cookies are not sent with requests to APIs with CORS enabled. + * These server APIs have the Cross-Origin Resource Sharing (CORS) flag, * so are not able to deal with cookie sessions. + * + * Notes app uses [OwnCloudClient] to sync notes, using /e/OS's Account Manager's + * InputStreamBinder class via AIDL communication. + * + * For creating the OwnCloudClient for Notes, Account Manager supplies + * DONT_USE_COOKIES as cookiesPolicy to exclude cookies from the HTTP requests. */ - if (cookiesPolicy == DONT_USE_COOKIES && method.getURI().getEscapedURI().contains("/apps/notes/")) { - getState().clearCookies(); + CookiePolicySnapshot cookiePolicySnapshot = null; + + if (cookiesPolicy == DONT_USE_COOKIES) { + cookiePolicySnapshot = overrideCookiePolicy(method, CookiePolicy.IGNORE_COOKIES); + removeCookieHeader(method); } - boolean cookiePassedOnRequest = getState().getCookies().length > 0; + boolean cookiePassedOnRequest = cookiesPolicy == USE_COOKIES && + (hasCookieRequestHeader(method) || getState().getCookies().length > 0); int status = super.executeMethod(method); + if (cookiePolicySnapshot != null) { + cookiePolicySnapshot.restore(method); + } + if (status >= 500 && status < 600 && DNSCache.isIPV6First(hostname)) { return retryMethodWithIPv4(method, hostname); } @@ -276,6 +292,7 @@ public class OwnCloudClient extends HttpClient { shouldResetCookie = true; getState().clearCookies(); + removeCookieHeader(method); return executeMethod(method); } @@ -527,4 +544,33 @@ public class OwnCloudClient extends HttpClient { public @CookiesPolicy int getCookiesPolicy() { return cookiesPolicy; } + + private CookiePolicySnapshot overrideCookiePolicy(HttpMethod method, String newPolicy) { + HttpParams params = method.getParams(); + Object previousPolicy = params.getParameter(HttpMethodParams.COOKIE_POLICY); + CookiePolicySnapshot snapshot = new CookiePolicySnapshot(previousPolicy); + params.setParameter(HttpMethodParams.COOKIE_POLICY, newPolicy); + return snapshot; + } + + private boolean hasCookieRequestHeader(HttpMethod method) { + return method.getRequestHeader(HEADER_NAME_COOKIE) != null; + } + + private void removeCookieHeader(HttpMethod method) { + method.removeRequestHeader(HEADER_NAME_COOKIE); + } + + private static final class CookiePolicySnapshot { + private final Object previousPolicy; + + CookiePolicySnapshot(Object previousPolicy) { + this.previousPolicy = previousPolicy; + } + + void restore(HttpMethod method) { + HttpParams params = method.getParams(); + params.setParameter(HttpMethodParams.COOKIE_POLICY, previousPolicy); + } + } } -- GitLab From ea244927390ce44a3cb91c34fb93b651f6b7c232 Mon Sep 17 00:00:00 2001 From: Fahim Masud Choudhury Date: Mon, 17 Nov 2025 20:51:47 +0600 Subject: [PATCH 2/2] chore: bump version to 2.0.4 --- library/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/build.gradle b/library/build.gradle index f232044c0..28b35f367 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -47,7 +47,7 @@ configurations { def versionMajor = 2 def versionMinor = 0 -def versionPatch = 3 +def versionPatch = 4 def upstreamVersion = "2.17" def releasePatch = "release" def libName = "Nextcloud-Android-Library" -- GitLab