From ea6116ebec1a82403b1bbe07be8cc5da38edaf8b Mon Sep 17 00:00:00 2001 From: milanmajchrak Date: Thu, 2 Jul 2026 16:10:03 +0200 Subject: [PATCH] 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 --- .../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); + } + } + } } /**