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

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


The following commit(s) were added to refs/heads/branch_9x by this push:
     new c5d2c4629f9 Revert "SOLR-17286: Remote Proxy via Jetty HttpClient 
(#3447)"
c5d2c4629f9 is described below

commit c5d2c4629f928fa8c8b4310435b87bd075c2b645
Author: David Smiley <[email protected]>
AuthorDate: Mon Aug 25 09:24:06 2025 -0400

    Revert "SOLR-17286: Remote Proxy via Jetty HttpClient (#3447)"
    
    This reverts commit 31570101be82d52ce93daebcd2fb2af1aa794d28.
---
 solr/CHANGES.txt                                   |   3 +-
 .../src/java/org/apache/solr/bench/Docs.java       |   8 +-
 .../solr/bench/MiniClusterBenchStateTest.java      |  23 ++--
 solr/core/build.gradle                             |   1 -
 .../src/java/org/apache/solr/api/V2HttpCall.java   |   4 +-
 .../apache/solr/servlet/CoreContainerProvider.java |  12 ++
 .../java/org/apache/solr/servlet/HttpSolrCall.java | 142 +++++++++++++++++--
 .../org/apache/solr/servlet/HttpSolrProxy.java     | 153 ---------------------
 .../apache/solr/servlet/SolrDispatchFilter.java    |  17 ++-
 .../client/solrj/impl/Krb5HttpClientUtils.java     |   1 -
 .../solr/client/solrj/impl/Http2SolrClient.java    |  10 +-
 .../client/solrj/impl/Krb5HttpClientBuilder.java   |   1 -
 .../PreemptiveBasicAuthClientBuilderFactory.java   |   7 +-
 13 files changed, 181 insertions(+), 201 deletions(-)

diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 9f6aed27a9a..3744a6b5597 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -36,8 +36,7 @@ Dependency Upgrades
 
 Other Changes
 ---------------------
-* SOLR-17286: When proxying requests to another node, use Jetty HttpClient not 
Apache HttpClient.
-  (David Smiley)
+(No changes)
 
 ==================  9.9.1 ==================
 Bug Fixes
diff --git a/solr/benchmark/src/java/org/apache/solr/bench/Docs.java 
b/solr/benchmark/src/java/org/apache/solr/bench/Docs.java
index b3c28bc1d4b..d256739acae 100644
--- a/solr/benchmark/src/java/org/apache/solr/bench/Docs.java
+++ b/solr/benchmark/src/java/org/apache/solr/bench/Docs.java
@@ -26,13 +26,13 @@ import java.util.Queue;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
 import org.apache.lucene.util.RamUsageEstimator;
 import org.apache.solr.bench.generators.MultiString;
 import org.apache.solr.bench.generators.SolrGen;
 import org.apache.solr.common.SolrDocument;
 import org.apache.solr.common.SolrInputDocument;
 import org.apache.solr.common.util.CollectionUtil;
-import org.apache.solr.common.util.ExecutorUtil;
 import org.apache.solr.common.util.SolrNamedThreadFactory;
 import org.apache.solr.common.util.SuppressForbidden;
 import org.quicktheories.core.Gen;
@@ -110,7 +110,11 @@ public class Docs {
       executorService.execute(() -> docs.add(Docs.this.inputDocument()));
     }
 
-    ExecutorUtil.shutdownAndAwaitTermination(executorService);
+    executorService.shutdown();
+    boolean result = executorService.awaitTermination(10, TimeUnit.MINUTES);
+    if (!result) {
+      throw new RuntimeException("Timeout waiting for doc adds to finish");
+    }
     log(
         "done preGenerateDocs docs="
             + docs.size()
diff --git 
a/solr/benchmark/src/test/org/apache/solr/bench/MiniClusterBenchStateTest.java 
b/solr/benchmark/src/test/org/apache/solr/bench/MiniClusterBenchStateTest.java
index 82708f6a34e..af568e3bb98 100644
--- 
a/solr/benchmark/src/test/org/apache/solr/bench/MiniClusterBenchStateTest.java
+++ 
b/solr/benchmark/src/test/org/apache/solr/bench/MiniClusterBenchStateTest.java
@@ -26,13 +26,15 @@ import static 
org.apache.solr.bench.generators.SourceDSL.longs;
 import static org.apache.solr.bench.generators.SourceDSL.strings;
 
 import com.carrotsearch.randomizedtesting.annotations.ThreadLeakLingering;
+import java.lang.invoke.MethodHandles;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.concurrent.TimeUnit;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.client.solrj.request.QueryRequest;
 import org.apache.solr.client.solrj.response.QueryResponse;
+import org.apache.solr.common.SolrInputDocument;
 import org.apache.solr.common.params.ModifiableSolrParams;
-import org.junit.After;
 import org.junit.Test;
 import org.openjdk.jmh.annotations.Mode;
 import org.openjdk.jmh.infra.BenchmarkParams;
@@ -40,12 +42,12 @@ import org.openjdk.jmh.infra.IterationParams;
 import org.openjdk.jmh.runner.IterationType;
 import org.openjdk.jmh.runner.WorkloadParams;
 import org.openjdk.jmh.runner.options.TimeValue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 @ThreadLeakLingering(linger = 10)
 public class MiniClusterBenchStateTest extends SolrTestCaseJ4 {
-  private MiniClusterState.MiniClusterBenchState miniBenchState;
-  private BaseBenchState baseBenchState;
-  private BenchmarkParams benchParams;
+  private static final Logger log = 
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
   @Test
   public void testMiniClusterState() throws Exception {
@@ -53,8 +55,9 @@ public class MiniClusterBenchStateTest extends SolrTestCaseJ4 
{
     System.setProperty("workBaseDir", createTempDir("work").toString());
     System.setProperty("random.counts", "true");
 
-    miniBenchState = new MiniClusterState.MiniClusterBenchState();
-    benchParams =
+    MiniClusterState.MiniClusterBenchState miniBenchState =
+        new MiniClusterState.MiniClusterBenchState();
+    BenchmarkParams benchParams =
         new BenchmarkParams(
             "benchmark",
             "generatedTarget",
@@ -77,7 +80,7 @@ public class MiniClusterBenchStateTest extends SolrTestCaseJ4 
{
             "vmVersion",
             "jmhVersion",
             TimeValue.seconds(10));
-    baseBenchState = new BaseBenchState();
+    BaseBenchState baseBenchState = new BaseBenchState();
     baseBenchState.doSetup(benchParams);
     miniBenchState.doSetup(benchParams, baseBenchState);
 
@@ -108,7 +111,7 @@ public class MiniClusterBenchStateTest extends 
SolrTestCaseJ4 {
             .field(doubles().all());
 
     int numDocs = 50;
-    docs.preGenerate(numDocs);
+    Iterator<SolrInputDocument> docIt = docs.preGenerate(numDocs);
 
     miniBenchState.index(collection, docs, numDocs);
 
@@ -121,12 +124,8 @@ public class MiniClusterBenchStateTest extends 
SolrTestCaseJ4 {
     BaseBenchState.log("match all query result=" + result);
 
     assertEquals(numDocs, result.getResults().getNumFound());
-  }
 
-  @After
-  public void after() throws Exception {
     BaseBenchState.doTearDown(benchParams);
-
     miniBenchState.tearDown(benchParams);
     miniBenchState.shutdownMiniCluster(benchParams, baseBenchState);
   }
diff --git a/solr/core/build.gradle b/solr/core/build.gradle
index 51db9824312..72ac2dbe293 100644
--- a/solr/core/build.gradle
+++ b/solr/core/build.gradle
@@ -122,7 +122,6 @@ dependencies {
   implementation 'org.eclipse.jetty:jetty-client'
   implementation 'org.eclipse.jetty:jetty-http'
   implementation 'org.eclipse.jetty:jetty-io'
-  implementation 'org.eclipse.jetty:jetty-util'
   implementation 'org.eclipse.jetty.toolchain:jetty-servlet-api'
 
   // ZooKeeper
diff --git a/solr/core/src/java/org/apache/solr/api/V2HttpCall.java 
b/solr/core/src/java/org/apache/solr/api/V2HttpCall.java
index 3480d8f7f5b..24cb696aeee 100644
--- a/solr/core/src/java/org/apache/solr/api/V2HttpCall.java
+++ b/solr/core/src/java/org/apache/solr/api/V2HttpCall.java
@@ -349,7 +349,7 @@ public class V2HttpCall extends HttpSolrCall {
   }
 
   /**
-   * Differentiate between "admin" and "remoteproxy"-type requests; executing 
each as appropriate.
+   * Differentiate between "admin" and "remotequery"-type requests; executing 
each as appropriate.
    *
    * <p>The JAX-RS framework used by {@link V2HttpCall} doesn't provide any 
easy way to check in
    * advance whether a Jersey application can handle an incoming request. 
This, in turn, makes it
@@ -360,7 +360,7 @@ public class V2HttpCall extends HttpSolrCall {
    * <p>This method uses this strategy to differentiate between admin requests 
that don't require a
    * {@link SolrCore}, but whose path happen to contain a core/collection name 
(e.g.
    * ADDREPLICAPROP's path of
-   * /collections/collName/shards/shardName/replicas/replicaName/properties), 
and "REMOTEPROXY"
+   * /collections/collName/shards/shardName/replicas/replicaName/properties), 
and "REMOTEQUERY"
    * requests which do require a local SolrCore to process.
    */
   @Override
diff --git 
a/solr/core/src/java/org/apache/solr/servlet/CoreContainerProvider.java 
b/solr/core/src/java/org/apache/solr/servlet/CoreContainerProvider.java
index 10ae2bff6f2..8b8bc3c927d 100644
--- a/solr/core/src/java/org/apache/solr/servlet/CoreContainerProvider.java
+++ b/solr/core/src/java/org/apache/solr/servlet/CoreContainerProvider.java
@@ -49,6 +49,7 @@ import javax.servlet.ServletContext;
 import javax.servlet.ServletContextEvent;
 import javax.servlet.ServletContextListener;
 import javax.servlet.UnavailableException;
+import org.apache.http.client.HttpClient;
 import org.apache.lucene.store.MMapDirectory;
 import org.apache.lucene.util.VectorUtil;
 import org.apache.solr.client.api.util.SolrVersion;
@@ -83,6 +84,7 @@ public class CoreContainerProvider implements 
ServletContextListener {
   private final String metricTag = SolrMetricProducer.getUniqueMetricTag(this, 
null);
   private CoreContainer cores;
   private Properties extraProperties;
+  private HttpClient httpClient;
   private SolrMetricManager metricManager;
   private RateLimitManager rateLimitManager;
   private String registryName;
@@ -121,6 +123,14 @@ public class CoreContainerProvider implements 
ServletContextListener {
     return cores;
   }
 
+  /**
+   * @see SolrDispatchFilter#getHttpClient()
+   */
+  HttpClient getHttpClient() throws UnavailableException {
+    checkReady();
+    return httpClient;
+  }
+
   private void checkReady() throws UnavailableException {
     // TODO throw AlreadyClosedException instead?
     if (cores == null) {
@@ -166,6 +176,7 @@ public class CoreContainerProvider implements 
ServletContextListener {
       }
     } finally {
       if (cc != null) {
+        httpClient = null;
         cc.shutdown();
       }
     }
@@ -218,6 +229,7 @@ public class CoreContainerProvider implements 
ServletContextListener {
               });
 
       coresInit = createCoreContainer(computeSolrHome(servletContext), 
extraProperties);
+      this.httpClient = 
coresInit.getUpdateShardHandler().getDefaultHttpClient();
       setupJvmMetrics(coresInit, coresInit.getNodeConfig().getMetricsConfig());
 
       SolrZkClient zkClient = null;
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 895c00603dd..1fd374536b5 100644
--- a/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
+++ b/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
@@ -36,13 +36,16 @@ import io.opentracing.Span;
 import io.opentracing.tag.Tags;
 import java.io.EOFException;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.OutputStream;
 import java.lang.invoke.MethodHandles;
 import java.nio.charset.StandardCharsets;
+import java.security.Principal;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedHashSet;
@@ -59,10 +62,26 @@ import java.util.stream.Collectors;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import net.jcip.annotations.ThreadSafe;
+import org.apache.http.Header;
+import org.apache.http.HeaderIterator;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpDelete;
+import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpHead;
+import org.apache.http.client.methods.HttpOptions;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.client.methods.HttpRequestBase;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.entity.InputStreamEntity;
 import org.apache.solr.api.ApiBag;
 import org.apache.solr.api.V2HttpCall;
 import org.apache.solr.client.api.util.SolrVersion;
 import org.apache.solr.client.solrj.impl.CloudSolrClient;
+import org.apache.solr.client.solrj.impl.HttpClientUtil;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.SolrException.ErrorCode;
 import org.apache.solr.common.cloud.Aliases;
@@ -114,7 +133,6 @@ 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;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.MarkerFactory;
@@ -124,6 +142,8 @@ import org.slf4j.MarkerFactory;
 public class HttpSolrCall {
   private static final Logger log = 
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
+  public static final String ORIGINAL_USER_PRINCIPAL_HEADER = 
"originalUserPrincipal";
+
   public static final String INTERNAL_REQUEST_COUNT = "_forwardedCount";
 
   protected final SolrDispatchFilter solrDispatchFilter;
@@ -480,6 +500,12 @@ public class HttpSolrCall {
     }
   }
 
+  protected void sendRemoteQuery() throws IOException {
+    SolrRequestInfo.setRequestInfo(new SolrRequestInfo(req, new 
SolrQueryResponse(), action));
+    mustClearSolrRequestInfo = true;
+    remoteQuery(coreUrl + path, response);
+  }
+
   /** This method processes the request. */
   public Action call() throws IOException {
 
@@ -604,7 +630,7 @@ public class HttpSolrCall {
 
   /**
    * Handle a request whose "type" could not be discerned in advance and may 
be either "admin" or
-   * "remoteproxy".
+   * "remotequery".
    *
    * <p>Some implementations (such as {@link V2HttpCall}) may find it 
difficult to differentiate all
    * request types in advance. This method serves as a hook; allowing those 
implementations to
@@ -702,20 +728,107 @@ public class HttpSolrCall {
     }
   }
 
-  protected void sendRemoteQuery() throws IOException {
+  // TODO using Http2Client
+  private void remoteQuery(String coreUrl, HttpServletResponse resp) throws 
IOException {
+    HttpRequestBase method;
+    HttpEntity httpEntity = null;
+
     ModifiableSolrParams updatedQueryParams = new 
ModifiableSolrParams(queryParams);
     int forwardCount = queryParams.getInt(INTERNAL_REQUEST_COUNT, 0) + 1;
     updatedQueryParams.set(INTERNAL_REQUEST_COUNT, forwardCount);
     String queryStr = updatedQueryParams.toQueryString();
 
-    String coreUrlAndPath = coreUrl + path;
-    log.info("Proxying request to: {}", coreUrlAndPath);
     try {
-      response.reset(); // clear all headers and status
-      HttpClient httpClient = cores.getDefaultHttpSolrClient().getHttpClient();
-      HttpSolrProxy.doHttpProxy(httpClient, req, response, coreUrlAndPath + 
queryStr);
-    } catch (Exception e) {
-      // note: don't handle interruption differently; we are stopping
+      String urlstr = coreUrl + queryStr;
+
+      boolean isPostOrPutRequest = "POST".equals(req.getMethod()) || 
"PUT".equals(req.getMethod());
+      if ("GET".equals(req.getMethod())) {
+        method = new HttpGet(urlstr);
+      } else if ("HEAD".equals(req.getMethod())) {
+        method = new HttpHead(urlstr);
+      } else if (isPostOrPutRequest) {
+        HttpEntityEnclosingRequestBase entityRequest =
+            "POST".equals(req.getMethod()) ? new HttpPost(urlstr) : new 
HttpPut(urlstr);
+        InputStream in = req.getInputStream();
+        HttpEntity entity = new InputStreamEntity(in, req.getContentLength());
+        entityRequest.setEntity(entity);
+        method = entityRequest;
+      } else if ("DELETE".equals(req.getMethod())) {
+        method = new HttpDelete(urlstr);
+      } else if ("OPTIONS".equals(req.getMethod())) {
+        method = new HttpOptions(urlstr);
+      } else {
+        throw new SolrException(
+            SolrException.ErrorCode.SERVER_ERROR, "Unexpected method type: " + 
req.getMethod());
+      }
+
+      for (Enumeration<String> e = req.getHeaderNames(); e.hasMoreElements(); 
) {
+        String headerName = e.nextElement();
+        if (!"host".equalsIgnoreCase(headerName)
+            && !"authorization".equalsIgnoreCase(headerName)
+            && !"accept".equalsIgnoreCase(headerName)) {
+          method.addHeader(headerName, req.getHeader(headerName));
+        }
+      }
+      // These headers not supported for HttpEntityEnclosingRequests
+      if (method instanceof HttpEntityEnclosingRequest) {
+        method.removeHeaders(TRANSFER_ENCODING_HEADER);
+        method.removeHeaders(CONTENT_LENGTH_HEADER);
+      }
+
+      // Make sure the user principal is forwarded when its exist
+      HttpClientContext httpClientRequestContext =
+          HttpClientUtil.createNewHttpClientRequestContext();
+      Principal userPrincipal = req.getUserPrincipal();
+      if (userPrincipal != null) {
+        // Normally the context contains a static userToken to enable reuse 
resources. However, if a
+        // personal Principal object exists, we use that instead, also as a 
means to transfer
+        // authentication information to Auth plugins that wish to intercept 
the request later
+        if (log.isDebugEnabled()) {
+          log.debug("Forwarding principal {}", userPrincipal);
+        }
+        httpClientRequestContext.setUserToken(userPrincipal);
+      }
+
+      // Execute the method.
+      final HttpResponse response =
+          solrDispatchFilter.getHttpClient().execute(method, 
httpClientRequestContext);
+      int httpStatus = response.getStatusLine().getStatusCode();
+      httpEntity = response.getEntity();
+
+      resp.setStatus(httpStatus);
+      for (HeaderIterator responseHeaders = response.headerIterator();
+          responseHeaders.hasNext(); ) {
+        Header header = responseHeaders.nextHeader();
+
+        // We pull out these two headers below because they can cause chunked
+        // encoding issues with Tomcat
+        if (header != null
+            && !header.getName().equalsIgnoreCase(TRANSFER_ENCODING_HEADER)
+            && !header.getName().equalsIgnoreCase(CONNECTION_HEADER)) {
+
+          // NOTE: explicitly using 'setHeader' instead of 'addHeader' so that
+          // the remote nodes values for any response headers will overide any 
that
+          // may have already been set locally (ex: by the local jetty's 
RewriteHandler config)
+          resp.setHeader(header.getName(), header.getValue());
+        }
+      }
+
+      if (httpEntity != null) {
+        if (httpEntity.getContentEncoding() != null)
+          resp.setHeader(
+              httpEntity.getContentEncoding().getName(),
+              httpEntity.getContentEncoding().getValue());
+        if (httpEntity.getContentType() != null)
+          resp.setContentType(httpEntity.getContentType().getValue());
+
+        InputStream is = httpEntity.getContent();
+        OutputStream os = resp.getOutputStream();
+
+        is.transferTo(os);
+      }
+
+    } catch (IOException e) {
       sendError(
           new SolrException(
               SolrException.ErrorCode.SERVER_ERROR,
@@ -724,10 +837,8 @@ public class HttpSolrCall {
                   + " with _forwardCount: "
                   + forwardCount,
               e));
-    } catch (Error e) {
-      throw e;
-    } catch (Throwable e) {
-      throw new RuntimeException(e);
+    } finally {
+      Utils.consumeFully(httpEntity);
     }
   }
 
@@ -1206,6 +1317,9 @@ public class HttpSolrCall {
     };
   }
 
+  static final String CONNECTION_HEADER = "Connection";
+  static final String TRANSFER_ENCODING_HEADER = "Transfer-Encoding";
+  static final String CONTENT_LENGTH_HEADER = "Content-Length";
   List<CommandOperation> parsedCommands;
 
   public List<CommandOperation> getCommands(boolean validateInput) {
diff --git a/solr/core/src/java/org/apache/solr/servlet/HttpSolrProxy.java 
b/solr/core/src/java/org/apache/solr/servlet/HttpSolrProxy.java
deleted file mode 100644
index 0282f360f05..00000000000
--- a/solr/core/src/java/org/apache/solr/servlet/HttpSolrProxy.java
+++ /dev/null
@@ -1,153 +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 io.opentracing.util.GlobalTracer;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.util.EnumSet;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import org.apache.solr.util.tracing.TraceUtils;
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.client.api.Request;
-import org.eclipse.jetty.client.api.Response;
-import org.eclipse.jetty.client.api.Result;
-import org.eclipse.jetty.client.util.InputStreamRequestContent;
-import org.eclipse.jetty.http.HttpField;
-import org.eclipse.jetty.http.HttpFields;
-import org.eclipse.jetty.http.HttpHeader;
-
-/** Helper class for proxying the request to another Solr node. */
-// Tried to use Jetty's ProxyServlet instead but ran into inexplicable 
difficulties:  EOF/reset.
-// Perhaps was related to its use of ServletRequest.startAsync()/AsyncContext
-class HttpSolrProxy {
-  // TODO add X-Forwarded-For and with comma delimited
-
-  private static final Set<HttpHeader> HOP_BY_HOP_HEADERS =
-      EnumSet.of(
-          HttpHeader.CONNECTION,
-          HttpHeader.KEEP_ALIVE,
-          HttpHeader.PROXY_AUTHENTICATE,
-          HttpHeader.PROXY_AUTHORIZATION,
-          HttpHeader.TE,
-          HttpHeader.TRANSFER_ENCODING,
-          HttpHeader.UPGRADE);
-
-  // Methods that shouldn't have a body according to HTTP spec
-  private static final Set<String> NO_BODY_METHODS = Set.of("GET", "HEAD", 
"DELETE");
-
-  static void doHttpProxy(
-      HttpClient httpClient,
-      HttpServletRequest servletReq,
-      HttpServletResponse servletRsp,
-      String url)
-      throws Throwable {
-    Request proxyReq = 
httpClient.newRequest(url).method(servletReq.getMethod());
-
-    // clearing them first to ensure there's no stock entries (e.g. user-agent)
-    proxyReq.headers(proxyFields -> copyRequestHeaders(servletReq, 
proxyFields.clear()));
-
-    // FYI see InstrumentedHttpListenerFactory
-    TraceUtils.injectTraceContext(proxyReq, GlobalTracer.get().activeSpan());
-    // TODO client spans.  See OTEL agent's approach:
-    // 
https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/jetty-httpclient/jetty-httpclient-12.0
-
-    if (!NO_BODY_METHODS.contains(servletReq.getMethod())) {
-      proxyReq.body(
-          new InputStreamRequestContent(servletReq.getContentType(), 
servletReq.getInputStream()));
-    }
-
-    CompletableFuture<Result> resultFuture = new CompletableFuture<>();
-
-    proxyReq.send(
-        new Response.Listener() {
-          private final byte[] buffer = new byte[8192];
-
-          @Override
-          public void onBegin(Response response) {
-            servletRsp.setStatus(response.getStatus());
-          }
-
-          @Override
-          public void onHeaders(Response response) {
-            copyResponseHeaders(response, servletRsp);
-          }
-
-          @Override
-          public void onContent(Response response, ByteBuffer content) {
-            try {
-              final OutputStream clientOutputStream = 
servletRsp.getOutputStream();
-
-              // Copy content to the client's output stream in chunks using 
the existing buffer
-              int remaining = content.remaining();
-              while (remaining > 0) {
-                int chunkSize = Math.min(remaining, buffer.length);
-                content.get(buffer, 0, chunkSize);
-                clientOutputStream.write(buffer, 0, chunkSize);
-                remaining -= chunkSize;
-              }
-              clientOutputStream.flush();
-            } catch (IOException e) {
-              throw new RuntimeException(e);
-            }
-          }
-
-          @Override
-          public void onComplete(Result result) {
-            resultFuture.complete(result);
-          }
-        });
-
-    Result result = resultFuture.get(); // waits
-    var failure = result.getFailure();
-    if (failure != null) {
-      throw failure;
-    }
-  }
-
-  private static void copyRequestHeaders(
-      HttpServletRequest servletReq, HttpFields.Mutable proxyFields) {
-    servletReq
-        .getHeaderNames()
-        .asIterator()
-        .forEachRemaining(
-            headerName -> {
-              HttpHeader knownHeader = HttpHeader.CACHE.get(headerName); // 
maybe null
-              if (!HOP_BY_HOP_HEADERS.contains(knownHeader)) {
-                servletReq
-                    .getHeaders(headerName)
-                    .asIterator()
-                    .forEachRemaining(headerVal -> proxyFields.add(headerName, 
headerVal));
-              }
-            });
-  }
-
-  private static void copyResponseHeaders(Response proxyRsp, 
HttpServletResponse servletRsp) {
-    for (HttpField headerField : proxyRsp.getHeaders()) {
-      HttpHeader knownHeader = headerField.getHeader();
-      if (!HOP_BY_HOP_HEADERS.contains(knownHeader)) {
-        // HttpField: even if multiple values, it's encoded as one comma 
delimited value
-        servletRsp.addHeader(headerField.getName(), headerField.getValue());
-      }
-    }
-  }
-}
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 7e8f5aa447e..cfdac952858 100644
--- a/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
+++ b/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
@@ -40,6 +40,7 @@ import javax.servlet.UnavailableException;
 import javax.servlet.http.HttpFilter;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import org.apache.http.client.HttpClient;
 import org.apache.solr.api.V2HttpCall;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.SolrException.ErrorCode;
@@ -90,6 +91,15 @@ public class SolrDispatchFilter extends HttpFilter 
implements PathExcluder {
 
   public final boolean isV2Enabled = V2ApiUtils.isEnabled();
 
+  public HttpClient getHttpClient() {
+    try {
+      return containerProvider.getHttpClient();
+    } catch (UnavailableException e) {
+      throw new SolrException(
+          ErrorCode.SERVER_ERROR, "Internal Http Client Unavailable, startup 
may have failed");
+    }
+  }
+
   /**
    * Enum to define action that needs to be processed. PASSTHROUGH: Pass 
through to another filter
    * via webapp. FORWARD: Forward rewritten URI (without path prefix and 
core/collection name) to
@@ -124,7 +134,6 @@ public class SolrDispatchFilter extends HttpFilter 
implements PathExcluder {
 
   @Override
   public void init(FilterConfig config) throws ServletException {
-    super.init(config);
     try {
       containerProvider = 
CoreContainerProvider.serviceForContext(config.getServletContext());
       boolean isCoordinator =
@@ -192,11 +201,9 @@ public class SolrDispatchFilter extends HttpFilter 
implements PathExcluder {
             }
           });
     } finally {
+      ServletUtils.consumeInputFully(request, response);
       SolrRequestInfo.reset();
-      if (!request.isAsyncStarted()) { // jetty's proxy uses this
-        ServletUtils.consumeInputFully(request, response);
-        SolrRequestParsers.cleanupMultipartFiles(request);
-      }
+      SolrRequestParsers.cleanupMultipartFiles(request);
     }
   }
 
diff --git 
a/solr/modules/hadoop-auth/src/test/org/apache/solr/client/solrj/impl/Krb5HttpClientUtils.java
 
b/solr/modules/hadoop-auth/src/test/org/apache/solr/client/solrj/impl/Krb5HttpClientUtils.java
index 967c32c82ad..8f78c5035fb 100644
--- 
a/solr/modules/hadoop-auth/src/test/org/apache/solr/client/solrj/impl/Krb5HttpClientUtils.java
+++ 
b/solr/modules/hadoop-auth/src/test/org/apache/solr/client/solrj/impl/Krb5HttpClientUtils.java
@@ -38,7 +38,6 @@ public class Krb5HttpClientUtils {
     HttpAuthenticationStore authenticationStore = new 
HttpAuthenticationStore();
     
authenticationStore.addAuthentication(createSPNEGOAuthentication(principalName));
     http2Client
-        .getHttpClient()
         .getProtocolHandlers()
         .put(new 
WWWAuthenticationProtocolHandler(http2Client.getHttpClient()));
     http2Client.setAuthenticationStore(authenticationStore);
diff --git 
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Http2SolrClient.java 
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Http2SolrClient.java
index 4e5761c2095..7462798a06a 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Http2SolrClient.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Http2SolrClient.java
@@ -214,14 +214,14 @@ public class Http2SolrClient extends HttpSolrClientBase {
     this.listenerFactory.add(factory);
   }
 
-  /** internal use only */
-  public HttpClient getHttpClient() {
+  // internal usage only
+  HttpClient getHttpClient() {
     return httpClient;
   }
 
-  @Deprecated(since = "9.10")
-  public ProtocolHandlers getProtocolHandlers() {
-    return getHttpClient().getProtocolHandlers();
+  // internal usage only
+  ProtocolHandlers getProtocolHandlers() {
+    return httpClient.getProtocolHandlers();
   }
 
   private HttpClient createHttpClient(Builder builder) {
diff --git 
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Krb5HttpClientBuilder.java
 
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Krb5HttpClientBuilder.java
index 3e555d533e8..8b47d45d2f0 100644
--- 
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Krb5HttpClientBuilder.java
+++ 
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Krb5HttpClientBuilder.java
@@ -131,7 +131,6 @@ public class Krb5HttpClientBuilder implements 
HttpClientBuilderFactory {
     authenticationStore.addAuthentication(createSPNEGOAuthentication());
     http2Client.setAuthenticationStore(authenticationStore);
     http2Client
-        .getHttpClient()
         .getProtocolHandlers()
         .put(new 
WWWAuthenticationProtocolHandler(http2Client.getHttpClient()));
   }
diff --git 
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/PreemptiveBasicAuthClientBuilderFactory.java
 
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/PreemptiveBasicAuthClientBuilderFactory.java
index 2b8c183065b..0d1231baa74 100644
--- 
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/PreemptiveBasicAuthClientBuilderFactory.java
+++ 
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/PreemptiveBasicAuthClientBuilderFactory.java
@@ -95,9 +95,10 @@ public class PreemptiveBasicAuthClientBuilderFactory 
implements HttpClientBuilde
     authenticationStore.addAuthentication(
         new SolrBasicAuthentication(basicAuthUser, basicAuthPass));
     client.setAuthenticationStore(authenticationStore);
-    var httpClient = client.getHttpClient();
-    httpClient.getProtocolHandlers().put(new 
WWWAuthenticationProtocolHandler(httpClient));
-    httpClient.getProtocolHandlers().put(new 
ProxyAuthenticationProtocolHandler(httpClient));
+    client.getProtocolHandlers().put(new 
WWWAuthenticationProtocolHandler(client.getHttpClient()));
+    client
+        .getProtocolHandlers()
+        .put(new ProxyAuthenticationProtocolHandler(client.getHttpClient()));
   }
 
   @Override

Reply via email to