From 79f239ac08c48738d93293e068aa78f6ed3935cd Mon Sep 17 00:00:00 2001 From: milanmajchrak Date: Thu, 2 Jul 2026 16:10:03 +0200 Subject: [PATCH 1/2] fix: abort leaked request Context in StatelessAuthenticationFilter (backport dc57ffded8 / #852) Backport the behavioral fix from dc57ffded8 ("Transaction bug - close context in finally block", PR #852) which is on dtq-dev/customer/lindat but missing from customer/zcu-data. On the request error path a slow submission upload could leave its Hibernate session bound to the Tomcat thread with a dirty, stale Item: the upload throws before reaching context.commit(), and DSpaceRequestContextFilter assigns its `context` local only AFTER chain.doFilter, so on an exception the local stays null and its finally skips the abort -> the session leaks. A later request on that thread then flushes the stale Item as a full-row UPDATE (Item has no @DynamicUpdate/@Version), reverting owning_collection->NULL and in_archive->false while collection2item + handle survive -> the item becomes an unsearchable orphan (e.g. handle 20.500.14592/107). Wrap chain.doFilter in the outer StatelessAuthenticationFilter with a try/finally that reads the Context from the request attribute and abort()s it if still valid, cleaning up the leaked context the inner filter missed. No-op on the normal success path. Only the StatelessAuthenticationFilter hunk is ported; the diagnostic/CI files in dc57ffded8 are omitted (they conflict and are not needed). Co-Authored-By: Claude Opus 4.8 (cherry picked from commit ea6116ebec1a82403b1bbe07be8cc5da38edaf8b) --- .../StatelessAuthenticationFilter.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/StatelessAuthenticationFilter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/StatelessAuthenticationFilter.java index 964d35f42c34..6d2139b26849 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/StatelessAuthenticationFilter.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/StatelessAuthenticationFilter.java @@ -99,7 +99,23 @@ protected void doFilterInternal(HttpServletRequest req, if (authentication != null) { SecurityContextHolder.getContext().setAuthentication(authentication); } - chain.doFilter(req, res); + + try { + chain.doFilter(req, res); + } finally { + // Complete the context to avoid transactions getting stuck in the connection pool in the + // `idle in transaction` state. + // TODO add the issue url + Context context = (Context) req.getAttribute(ContextUtil.DSPACE_CONTEXT); + // Ensure the context is cleared after the request is done + if (context != null && context.isValid()) { + try { + context.abort(); + } catch (Exception e) { + log.error("{} occurred while trying to close", e.getMessage(), e); + } + } + } } /** From c55a155759815fb0f50610fc09d362dbad7eee68 Mon Sep 17 00:00:00 2001 From: Juraj Roka <95219754+jr-rk@users.noreply.github.com> Date: Thu, 2 Jul 2026 18:59:43 +0200 Subject: [PATCH 2/2] docs: clarify Context-abort comment and link #1353 (Copilot review) --- .../app/rest/security/StatelessAuthenticationFilter.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/StatelessAuthenticationFilter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/StatelessAuthenticationFilter.java index 6d2139b26849..38e87e8dff2d 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/StatelessAuthenticationFilter.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/StatelessAuthenticationFilter.java @@ -103,9 +103,9 @@ protected void doFilterInternal(HttpServletRequest req, try { chain.doFilter(req, res); } finally { - // Complete the context to avoid transactions getting stuck in the connection pool in the - // `idle in transaction` state. - // TODO add the issue url + // Abort the request-scoped DSpace Context if it is still open, so a leaked, dirty + // Hibernate session is not left bound to the worker thread (prevents orphaned items). + // See https://github.com/dataquest-dev/DSpace/issues/1353 Context context = (Context) req.getAttribute(ContextUtil.DSPACE_CONTEXT); // Ensure the context is cleared after the request is done if (context != null && context.isValid()) {