You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@solr.apache.org by st...@apache.org on 2023/08/16 18:04:57 UTC

[solr] branch main updated: SOLR-16859 Missing Proxy support for Http2SolrClient (#1779)

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

stillalex 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 21740acc339 SOLR-16859 Missing Proxy support for Http2SolrClient (#1779)
21740acc339 is described below

commit 21740acc3392645ffc08b4dd07e26e8235a03880
Author: Alex D <st...@apache.org>
AuthorDate: Wed Aug 16 11:04:51 2023 -0700

    SOLR-16859 Missing Proxy support for Http2SolrClient (#1779)
---
 solr/CHANGES.txt                                   |  2 +
 .../solr/client/solrj/impl/Http2SolrClient.java    | 52 ++++++++++++
 .../solrj/impl/Http2SolrClientProxyTest.java       | 95 ++++++++++++++++++++++
 3 files changed, 149 insertions(+)

diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index a0ff03bc0bc..b7606af3ba7 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -120,6 +120,8 @@ Bug Fixes
 
 * PR#1826: Allow looking up Solr Package repo when that URL references a raw repository.json hosted on Github when the file is JSON but the mimetype used is text/plain. (Eric Pugh)
 
+* SOLR-16859: Missing Proxy support for Http2SolrClient (Alex Deparvu)
+
 Dependency Upgrades
 ---------------------
 (No changes)
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 648504a816a..25513a74dd4 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
@@ -76,7 +76,12 @@ import org.apache.solr.common.util.SolrNamedThreadFactory;
 import org.apache.solr.common.util.Utils;
 import org.eclipse.jetty.client.HttpClient;
 import org.eclipse.jetty.client.HttpClientTransport;
+import org.eclipse.jetty.client.HttpProxy;
+import org.eclipse.jetty.client.Origin.Address;
+import org.eclipse.jetty.client.Origin.Protocol;
 import org.eclipse.jetty.client.ProtocolHandlers;
+import org.eclipse.jetty.client.ProxyConfiguration;
+import org.eclipse.jetty.client.Socks4Proxy;
 import org.eclipse.jetty.client.api.AuthenticationStore;
 import org.eclipse.jetty.client.api.Request;
 import org.eclipse.jetty.client.api.Response;
@@ -281,6 +286,8 @@ public class Http2SolrClient extends SolrClient {
     if (builder.connectionTimeoutMillis != null)
       httpClient.setConnectTimeout(builder.connectionTimeoutMillis);
 
+    setupProxy(builder, httpClient);
+
     try {
       httpClient.start();
     } catch (Exception e) {
@@ -291,6 +298,29 @@ public class Http2SolrClient extends SolrClient {
     return httpClient;
   }
 
+  private void setupProxy(Builder builder, HttpClient httpClient) {
+    if (builder.proxyHost == null) {
+      return;
+    }
+    Address address = new Address(builder.proxyHost, builder.proxyPort);
+
+    final ProxyConfiguration.Proxy proxy;
+    if (builder.proxyIsSocks4) {
+      proxy = new Socks4Proxy(address, builder.proxyIsSecure);
+    } else {
+      final Protocol protocol;
+      if (builder.useHttp1_1) {
+        protocol = HttpClientTransportOverHTTP.HTTP11;
+      } else {
+        // see HttpClientTransportOverHTTP2#newOrigin
+        String protocolName = builder.proxyIsSecure ? "h2" : "h2c";
+        protocol = new Protocol(List.of(protocolName), false);
+      }
+      proxy = new HttpProxy(address, builder.proxyIsSecure, protocol);
+    }
+    httpClient.getProxyConfiguration().addProxy(proxy);
+  }
+
   @Override
   public void close() {
     // we wait for async requests, so far devs don't want to give sugar for this
@@ -1018,6 +1048,10 @@ public class Http2SolrClient extends SolrClient {
     protected ResponseParser responseParser;
     private Set<String> urlParamNames;
     private CookieStore cookieStore = getDefaultCookieStore();
+    private String proxyHost;
+    private int proxyPort;
+    private boolean proxyIsSocks4;
+    private boolean proxyIsSecure;
 
     public Builder() {}
 
@@ -1241,6 +1275,24 @@ public class Http2SolrClient extends SolrClient {
       this.cookieStore = cookieStore;
       return this;
     }
+
+    /**
+     * Setup a proxy
+     *
+     * @param host The proxy host
+     * @param port The proxy port
+     * @param isSocks4 If true creates an SOCKS 4 proxy, otherwise creates an HTTP proxy
+     * @param isSecure If true enables the secure flag on the proxy
+     * @return this Builder
+     */
+    public Builder withProxyConfiguration(
+        String host, int port, boolean isSocks4, boolean isSecure) {
+      this.proxyHost = host;
+      this.proxyPort = port;
+      this.proxyIsSocks4 = isSocks4;
+      this.proxyIsSecure = isSecure;
+      return this;
+    }
   }
 
   public Set<String> getUrlParamNames() {
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/Http2SolrClientProxyTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/Http2SolrClientProxyTest.java
new file mode 100644
index 00000000000..09f3601c47b
--- /dev/null
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/Http2SolrClientProxyTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.client.solrj.impl;
+
+import com.carrotsearch.randomizedtesting.RandomizedTest;
+import java.nio.file.Path;
+import java.util.Properties;
+import org.apache.solr.SolrJettyTestBase;
+import org.apache.solr.client.solrj.SolrQuery;
+import org.apache.solr.common.SolrInputDocument;
+import org.apache.solr.embedded.JettyConfig;
+import org.apache.solr.embedded.JettySolrRunner;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class Http2SolrClientProxyTest extends SolrJettyTestBase {
+
+  // TODO add SSL test
+
+  @BeforeClass
+  public static void beforeTest() throws Exception {
+    RandomizedTest.assumeFalse(sslConfig.isSSLMode());
+
+    JettyConfig jettyConfig =
+        JettyConfig.builder().withSSLConfig(sslConfig.buildServerSSLConfig()).build();
+    createAndStartJettyWithProxy(legacyExampleCollection1SolrHome(), new Properties(), jettyConfig);
+  }
+
+  public static JettySolrRunner createAndStartJettyWithProxy(
+      String solrHome, Properties nodeProperties, JettyConfig jettyConfig) throws Exception {
+
+    initCore(null, null, solrHome);
+
+    Path coresDir = createTempDir().resolve("cores");
+
+    Properties props = new Properties();
+    props.setProperty("name", DEFAULT_TEST_CORENAME);
+    props.setProperty("configSet", "collection1");
+    props.setProperty("config", "${solrconfig:solrconfig.xml}");
+    props.setProperty("schema", "${schema:schema.xml}");
+
+    writeCoreProperties(coresDir.resolve("core"), props, "RestTestBase");
+
+    Properties nodeProps = new Properties(nodeProperties);
+    nodeProps.setProperty("coreRootDirectory", coresDir.toString());
+    nodeProps.setProperty("configSetBaseDir", solrHome);
+
+    jetty = new JettySolrRunner(solrHome, nodeProps, jettyConfig, true);
+    jetty.start();
+    port = jetty.getLocalPort();
+    return jetty;
+  }
+
+  /** Setup a simple http proxy and verify a request works */
+  @Test
+  public void testProxy() throws Exception {
+    var proxy = jetty.getProxy();
+    assertNotNull(proxy);
+
+    String host = proxy.getUrl().getHost();
+    String url = "http://" + host + ":" + (proxy.getUrl().getPort() + 10) + "/solr";
+
+    var builder =
+        new Http2SolrClient.Builder(url)
+            .withProxyConfiguration(host, proxy.getListenPort(), false, false);
+
+    try (Http2SolrClient client = builder.build()) {
+      String id = "1234";
+      SolrInputDocument doc = new SolrInputDocument();
+      doc.addField("id", id);
+      client.add(DEFAULT_TEST_COLLECTION_NAME, doc);
+      client.commit(DEFAULT_TEST_COLLECTION_NAME);
+      assertEquals(
+          1,
+          client
+              .query(DEFAULT_TEST_COLLECTION_NAME, new SolrQuery("id:" + id))
+              .getResults()
+              .getNumFound());
+    }
+  }
+}