This is an automated email from the ASF dual-hosted git repository.

gus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git


The following commit(s) were added to refs/heads/main by this push:
     new 0538d17e5dd SOLR-18044 EssentialSolrRequestFilter to perform 
non-optional request wrapping operations  (#3997)
0538d17e5dd is described below

commit 0538d17e5ddb2a0f01bfe16884d1255c5fa45fb7
Author: Gus Heck <[email protected]>
AuthorDate: Sat Jan 3 18:02:16 2026 -0500

    SOLR-18044 EssentialSolrRequestFilter to perform non-optional request 
wrapping operations  (#3997)
---
 changelog/unreleased/SOLR-18042.yml                |  8 --
 changelog/unreleased/SOLR-18044.yml                |  8 ++
 .../solr/servlet/EssentialSolrRequestFilter.java   | 97 ++++++++++++++++++++++
 .../java/org/apache/solr/servlet/HttpSolrCall.java |  5 --
 .../apache/solr/servlet/LoadAdminUiServlet.java    |  4 +-
 .../org/apache/solr/servlet/MdcLoggingFilter.java  | 57 -------------
 .../apache/solr/servlet/SolrDispatchFilter.java    | 31 +++----
 .../org/apache/solr/embedded/JettySolrRunner.java  | 10 +--
 solr/webapp/web/WEB-INF/web.xml                    |  2 +-
 9 files changed, 125 insertions(+), 97 deletions(-)

diff --git a/changelog/unreleased/SOLR-18042.yml 
b/changelog/unreleased/SOLR-18042.yml
deleted file mode 100644
index 73ea60967df..00000000000
--- a/changelog/unreleased/SOLR-18042.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-# See https://github.com/apache/solr/blob/main/dev-docs/changelog.adoc
-title: SOLR 18042 - MDC Logging context lifecycle is now managed by a servlet 
filter
-type: other # added, changed, fixed, deprecated, removed, dependency_update, 
security, other
-authors:
-  - name: Gus Heck
-links:
-  - name: SOLR-18042
-    url: https://issues.apache.org/jira/browse/SOLR-18042
diff --git a/changelog/unreleased/SOLR-18044.yml 
b/changelog/unreleased/SOLR-18044.yml
new file mode 100644
index 00000000000..8f1c723b9bf
--- /dev/null
+++ b/changelog/unreleased/SOLR-18044.yml
@@ -0,0 +1,8 @@
+# See https://github.com/apache/solr/blob/main/dev-docs/changelog.adoc
+title: EssentialSolrRequestFilter has been added to perform non-optional 
request wrapping operations required for proper functioning of Solr
+type: other # added, changed, fixed, deprecated, removed, dependency_update, 
security, other
+authors:
+  - name: Gus Heck
+links:
+  - name: SOLR-18044
+    url: https://issues.apache.org/jira/browse/SOLR-18044
diff --git 
a/solr/core/src/java/org/apache/solr/servlet/EssentialSolrRequestFilter.java 
b/solr/core/src/java/org/apache/solr/servlet/EssentialSolrRequestFilter.java
new file mode 100644
index 00000000000..076d7caae6c
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/servlet/EssentialSolrRequestFilter.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.servlet;
+
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.lang.invoke.MethodHandles;
+import org.apache.solr.common.util.SuppressForbidden;
+import org.apache.solr.logging.MDCLoggingContext;
+import org.apache.solr.logging.MDCSnapshot;
+import org.apache.solr.request.SolrRequestInfo;
+import org.apache.solr.util.RTimerTree;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Servlet Filter to set up and tear down a various things that downstream 
code in solr relies on.
+ * It is expected that solr will fail to function as intended without the 
conditions initialized in
+ * this filter. Before adding anything to this filter ask yourself if a user 
could run without the
+ * feature you are adding (either with an alternative implementation or 
without it at all to reduce
+ * cpu/memory/dependencies). If it is not essential, it should have its own 
separate filter. Also,
+ * please include a comment indicating why the thing added is essential.
+ */
+public class EssentialSolrRequestFilter extends CoreContainerAwareHttpFilter {
+
+  // Best to put constant here because solr is not supposed to be functional 
(or compile)
+  // without this filter.
+  public static final String CORE_CONTAINER_REQUEST_ATTRIBUTE = 
"org.apache.solr.CoreContainer";
+  private static final Logger log = 
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+  @Override
+  @SuppressForbidden(
+      reason =
+          "Set the thread contextClassLoader for all 3rd party dependencies 
that we cannot control")
+  protected void doFilter(HttpServletRequest req, HttpServletResponse res, 
FilterChain chain)
+      throws IOException, ServletException {
+    ClassLoader contextClassLoader = 
Thread.currentThread().getContextClassLoader();
+    // this autocloseable is here to invoke MDCSnapshot.close() which restores 
captured state
+    try (var mdcSnapshot = MDCSnapshot.create()) {
+
+      // MDC logging *shouldn't* be essential but currently is, see SOLR-18050.
+      // Our use of SLF4J indicates that we intend logging to be pluggable, and
+      // some implementations won't have an MDC, so having it as essential 
limits
+      // logging implementations.
+      log.trace("MDC snapshot recorded {}", mdcSnapshot); // avoid both 
compiler and ide warning.
+      MDCLoggingContext.reset();
+      MDCLoggingContext.setNode(getCores());
+
+      // This is essential to accommodate libraries that (annoyingly) use
+      // Thread.currentThread().getContextClassLoader()
+      
Thread.currentThread().setContextClassLoader(getCores().getResourceLoader().getClassLoader());
+
+      // set a request timer which can be reused by requests if needed
+      // Request Timer is essential for QueryLimits functionality as well as
+      // timing our requests.
+      req.setAttribute(SolrRequestParsers.REQUEST_TIMER_SERVLET_ATTRIBUTE, new 
RTimerTree());
+
+      // put the core container in request attribute
+      // This is essential for the LoadAdminUiServlet class. Removing it will 
cause 404
+      req.setAttribute(CORE_CONTAINER_REQUEST_ATTRIBUTE, getCores());
+      chain.doFilter(req, res);
+    } finally {
+      // cleanups for above stuff
+      MDCLoggingContext.reset();
+      Thread.currentThread().setContextClassLoader(contextClassLoader);
+
+      // This is an essential safety valve to ensure we don't accidentally 
bleed information
+      // between requests.
+      SolrRequestInfo.reset();
+      if (!req.isAsyncStarted()) { // jetty's proxy uses this
+
+        // essential to avoid SOLR-8453 and SOLR-8683
+        ServletUtils.consumeInputFully(req, res);
+
+        // essential to remove temporary files created during multipart 
requests.
+        SolrRequestParsers.cleanupMultipartFiles(req);
+      }
+    }
+  }
+}
diff --git a/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java 
b/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
index 97a9677b69b..774519b2577 100644
--- a/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
+++ b/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
@@ -99,7 +99,6 @@ import org.apache.solr.servlet.SolrDispatchFilter.Action;
 import org.apache.solr.servlet.cache.HttpCacheHeaderUtil;
 import org.apache.solr.servlet.cache.Method;
 import org.apache.solr.update.processor.DistributingUpdateProcessorFactory;
-import org.apache.solr.util.RTimerTree;
 import org.apache.solr.util.tracing.TraceUtils;
 import org.apache.zookeeper.KeeperException;
 import org.eclipse.jetty.client.HttpClient;
@@ -157,10 +156,6 @@ public class HttpSolrCall {
     this.path = ServletUtils.getPathAfterContext(req);
 
     req.setAttribute(HttpSolrCall.class.getName(), this);
-    // set a request timer which can be reused by requests if needed
-    req.setAttribute(SolrRequestParsers.REQUEST_TIMER_SERVLET_ATTRIBUTE, new 
RTimerTree());
-    // put the core container in request attribute
-    req.setAttribute("org.apache.solr.CoreContainer", cores);
   }
 
   public String getPath() {
diff --git a/solr/core/src/java/org/apache/solr/servlet/LoadAdminUiServlet.java 
b/solr/core/src/java/org/apache/solr/servlet/LoadAdminUiServlet.java
index bbbd9166c51..24b0d6e1063 100644
--- a/solr/core/src/java/org/apache/solr/servlet/LoadAdminUiServlet.java
+++ b/solr/core/src/java/org/apache/solr/servlet/LoadAdminUiServlet.java
@@ -16,6 +16,8 @@
  */
 package org.apache.solr.servlet;
 
+import static 
org.apache.solr.servlet.EssentialSolrRequestFilter.CORE_CONTAINER_REQUEST_ATTRIBUTE;
+
 import com.google.common.net.HttpHeaders;
 import jakarta.servlet.http.HttpServlet;
 import jakarta.servlet.http.HttpServletRequest;
@@ -62,7 +64,7 @@ public final class LoadAdminUiServlet extends HttpServlet {
 
     // This attribute is set by the SolrDispatchFilter
     String admin = 
request.getRequestURI().substring(request.getContextPath().length());
-    CoreContainer cores = (CoreContainer) 
request.getAttribute("org.apache.solr.CoreContainer");
+    CoreContainer cores = (CoreContainer) 
request.getAttribute(CORE_CONTAINER_REQUEST_ATTRIBUTE);
     try (InputStream in = getServletContext().getResourceAsStream(admin)) {
       if (in != null && cores != null) {
         response.setCharacterEncoding("UTF-8");
diff --git a/solr/core/src/java/org/apache/solr/servlet/MdcLoggingFilter.java 
b/solr/core/src/java/org/apache/solr/servlet/MdcLoggingFilter.java
deleted file mode 100644
index 30dda327295..00000000000
--- a/solr/core/src/java/org/apache/solr/servlet/MdcLoggingFilter.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.solr.servlet;
-
-import jakarta.servlet.FilterChain;
-import jakarta.servlet.ServletException;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.lang.invoke.MethodHandles;
-import org.apache.solr.common.util.SuppressForbidden;
-import org.apache.solr.logging.MDCLoggingContext;
-import org.apache.solr.logging.MDCSnapshot;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/** Servlet Filter to set up and tear down MDC Logging context for each 
reqeust. */
-public class MdcLoggingFilter extends CoreContainerAwareHttpFilter {
-
-  private static final Logger log = 
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
-
-  @Override
-  @SuppressForbidden(
-      reason =
-          "Set the thread contextClassLoader for all 3rd party dependencies 
that we cannot control")
-  protected void doFilter(HttpServletRequest req, HttpServletResponse res, 
FilterChain chain)
-      throws IOException, ServletException {
-    ClassLoader contextClassLoader = 
Thread.currentThread().getContextClassLoader();
-    // this autocloseable is here to invoke MDCSnapshot.close() which restores 
captured state
-    try (var mdcSnapshot = MDCSnapshot.create()) {
-      log.trace("MDC snapshot recorded {}", mdcSnapshot); // avoid both 
compiler and ide warning.
-      MDCLoggingContext.reset();
-      MDCLoggingContext.setNode(getCores());
-      // This doesn't belong here, but for the moment it is here to preserve 
it's relative
-      // timing of execution for now. Probably I will break this out in a 
subsequent change
-      
Thread.currentThread().setContextClassLoader(getCores().getResourceLoader().getClassLoader());
-      chain.doFilter(req, res);
-    } finally {
-      MDCLoggingContext.reset();
-      Thread.currentThread().setContextClassLoader(contextClassLoader);
-    }
-  }
-}
diff --git a/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java 
b/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
index 6d80be11c70..43de6e2bd07 100644
--- a/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
+++ b/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
@@ -37,7 +37,6 @@ import org.apache.solr.common.util.ExecutorUtil;
 import org.apache.solr.core.CoreContainer;
 import org.apache.solr.core.NodeRoles;
 import org.apache.solr.handler.api.V2ApiUtils;
-import org.apache.solr.request.SolrRequestInfo;
 import org.apache.solr.security.AuditEvent;
 import org.apache.solr.security.AuditEvent.EventType;
 import org.apache.solr.security.AuthenticationPlugin;
@@ -146,25 +145,17 @@ public class SolrDispatchFilter extends 
CoreContainerAwareHttpFilter {
       throws IOException, ServletException {
     setTracer(request, getCores().getTracer());
     RateLimitManager rateLimitManager = getRateLimitManager();
-    try {
-      ServletUtils.rateLimitRequest(
-          rateLimitManager,
-          request,
-          response,
-          () -> {
-            try {
-              dispatch(chain, request, response, retry);
-            } catch (IOException | ServletException | 
SolrAuthenticationException e) {
-              throw new ExceptionWhileTracing(e);
-            }
-          });
-    } finally {
-      SolrRequestInfo.reset();
-      if (!request.isAsyncStarted()) { // jetty's proxy uses this
-        ServletUtils.consumeInputFully(request, response);
-        SolrRequestParsers.cleanupMultipartFiles(request);
-      }
-    }
+    ServletUtils.rateLimitRequest(
+        rateLimitManager,
+        request,
+        response,
+        () -> {
+          try {
+            dispatch(chain, request, response, retry);
+          } catch (IOException | ServletException | 
SolrAuthenticationException e) {
+            throw new ExceptionWhileTracing(e);
+          }
+        });
   }
 
   private void dispatch(
diff --git 
a/solr/test-framework/src/java/org/apache/solr/embedded/JettySolrRunner.java 
b/solr/test-framework/src/java/org/apache/solr/embedded/JettySolrRunner.java
index 2825b1f4a72..99ebe39fe67 100644
--- a/solr/test-framework/src/java/org/apache/solr/embedded/JettySolrRunner.java
+++ b/solr/test-framework/src/java/org/apache/solr/embedded/JettySolrRunner.java
@@ -61,7 +61,7 @@ import org.apache.solr.common.util.Utils;
 import org.apache.solr.core.CoreContainer;
 import org.apache.solr.metrics.SolrMetricManager;
 import org.apache.solr.servlet.CoreContainerProvider;
-import org.apache.solr.servlet.MdcLoggingFilter;
+import org.apache.solr.servlet.EssentialSolrRequestFilter;
 import org.apache.solr.servlet.PathExclusionFilter;
 import org.apache.solr.servlet.SolrDispatchFilter;
 import org.apache.solr.util.SocketProxy;
@@ -113,7 +113,7 @@ public class JettySolrRunner {
 
   volatile FilterHolder debugFilter;
   volatile FilterHolder pathExcludeFilter;
-  volatile FilterHolder mdcLoggingFilter;
+  volatile FilterHolder essentialFilter;
   volatile FilterHolder dispatchFilter;
 
   private int jettyPort = -1;
@@ -412,8 +412,8 @@ public class JettySolrRunner {
       pathExcludeFilter.setInitParameter("excludePatterns", excludePatterns);
 
       // logging context setup
-      mdcLoggingFilter = 
root.getServletHandler().newFilterHolder(Source.EMBEDDED);
-      mdcLoggingFilter.setHeldClass(MdcLoggingFilter.class);
+      essentialFilter = 
root.getServletHandler().newFilterHolder(Source.EMBEDDED);
+      essentialFilter.setHeldClass(EssentialSolrRequestFilter.class);
 
       // This is our main workhorse
       dispatchFilter = 
root.getServletHandler().newFilterHolder(Source.EMBEDDED);
@@ -421,7 +421,7 @@ public class JettySolrRunner {
 
       // Map dispatchFilter in same path as in web.xml
       root.addFilter(pathExcludeFilter, "/*", 
EnumSet.of(DispatcherType.REQUEST));
-      root.addFilter(mdcLoggingFilter, "/*", 
EnumSet.of(DispatcherType.REQUEST));
+      root.addFilter(essentialFilter, "/*", 
EnumSet.of(DispatcherType.REQUEST));
       root.addFilter(dispatchFilter, "/*", EnumSet.of(DispatcherType.REQUEST));
 
       // Default servlet as a fall-through
diff --git a/solr/webapp/web/WEB-INF/web.xml b/solr/webapp/web/WEB-INF/web.xml
index a7df6a32113..af5e733526c 100644
--- a/solr/webapp/web/WEB-INF/web.xml
+++ b/solr/webapp/web/WEB-INF/web.xml
@@ -46,7 +46,7 @@
 
   <filter>
     <filter-name>MDCLoggingFilter</filter-name>
-    <filter-class>org.apache.solr.servlet.MdcLoggingFilter</filter-class>
+    
<filter-class>org.apache.solr.servlet.EssentialSolrRequestFilter</filter-class>
   </filter>
 
   <filter-mapping>

Reply via email to