Skip to content

Commit

Permalink
[DE-930] HTTP proxy support (#584)
Browse files Browse the repository at this point in the history
  • Loading branch information
rashtao authored Oct 31, 2024
1 parent d9d8e61 commit 6ef7fa6
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 16 deletions.
6 changes: 6 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,9 @@ jobs:
docker-img: <<parameters.docker-img>>
topology: <<parameters.topology>>
ssl: <<parameters.ssl>>
- run:
name: Start proxy
command: ./docker/start_proxy.sh
- load_cache
- run:
name: mvn dependency:tree
Expand Down Expand Up @@ -235,6 +238,9 @@ jobs:
docker-img: <<parameters.docker-img>>
topology: <<parameters.topology>>
ssl: <<parameters.ssl>>
- run:
name: Start proxy
command: ./docker/start_proxy.sh
- load_cache
- install
- run:
Expand Down
8 changes: 8 additions & 0 deletions docker/start_proxy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash

docker run -d \
-e LOG_LEVEL=Info \
-e AUTH_USER=user \
-e AUTH_PASSWORD=password \
--network=arangodb -p 8888:8888 \
docker.io/kalaksi/tinyproxy:1.7
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ private static String getUserAgent() {
return "JavaDriver/" + PackageVersion.VERSION + " (JVM/" + System.getProperty("java.specification.version") + ")";
}

HttpConnection(final ArangoConfig config, final HostDescription host, final Vertx existingVertx) {
HttpConnection(final ArangoConfig config, final HostDescription host, final HttpProtocolConfig protocolConfig) {
super();
Protocol protocol = config.getProtocol();
ContentType contentType = ContentTypeFactory.of(protocol);
Expand All @@ -113,9 +113,9 @@ private static String getUserAgent() {
).toHttpAuthorization();

Vertx vertxToUse;
if (existingVertx != null) {
if (protocolConfig.getVertx() != null) {
// reuse existing Vert.x
vertxToUse = existingVertx;
vertxToUse = protocolConfig.getVertx();
// Vert.x will not be closed when connection is closed
vertxToClose = null;
LOGGER.debug("Reusing existing Vert.x instance");
Expand Down Expand Up @@ -154,7 +154,8 @@ private static String getUserAgent() {
.setHttp2ClearTextUpgrade(false)
.setProtocolVersion(httpVersion)
.setDefaultHost(host.getHost())
.setDefaultPort(host.getPort());
.setDefaultPort(host.getPort())
.setProxyOptions(protocolConfig.getProxyOptions());

if (compression != Compression.NONE) {
webClientOptions.setTryUseCompression(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,11 @@
public class HttpConnectionFactory implements ConnectionFactory {
private final Logger LOGGER = LoggerFactory.getLogger(HttpConnectionFactory.class);

private final Vertx vertx;
final HttpProtocolConfig protocolConfig;

public HttpConnectionFactory(@UnstableApi final HttpProtocolConfig config) {
HttpProtocolConfig cfg = config != null ? config : HttpProtocolConfig.builder().build();
vertx = cfg.getVertx();
if (vertx == null && !PackageVersion.SHADED && Vertx.currentContext() != null) {
public HttpConnectionFactory(@UnstableApi final HttpProtocolConfig cfg) {
protocolConfig = cfg != null ? cfg : HttpProtocolConfig.builder().build();
if (protocolConfig.getVertx() == null && !PackageVersion.SHADED && Vertx.currentContext() != null) {
LOGGER.warn("Found an existing Vert.x instance, you can reuse it by setting:\n" +
"new ArangoDB.Builder()\n" +
" // ...\n" +
Expand All @@ -51,6 +50,6 @@ public HttpConnectionFactory(@UnstableApi final HttpProtocolConfig config) {
@Override
@UnstableApi
public Connection create(@UnstableApi final ArangoConfig config, final HostDescription host) {
return new HttpConnection(config, host, vertx);
return new HttpConnection(config, host, protocolConfig);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@

import com.arangodb.config.ProtocolConfig;
import io.vertx.core.Vertx;
import io.vertx.core.net.ProxyOptions;

public final class HttpProtocolConfig implements ProtocolConfig {
private final Vertx vertx;
private final ProxyOptions proxyOptions;

public static Builder builder() {
return new Builder();
}

public static class Builder {
private Vertx vertx;
private ProxyOptions proxyOptions;

private Builder() {
}
Expand All @@ -27,16 +30,30 @@ public Builder vertx(Vertx vertx) {
return this;
}

/**
* @param proxyOptions proxy options for HTTP connections
* @return this builder
*/
public Builder proxyOptions(ProxyOptions proxyOptions) {
this.proxyOptions = proxyOptions;
return this;
}

public HttpProtocolConfig build() {
return new HttpProtocolConfig(vertx);
return new HttpProtocolConfig(vertx, proxyOptions);
}
}

private HttpProtocolConfig(Vertx vertx) {
private HttpProtocolConfig(Vertx vertx, ProxyOptions proxyOptions) {
this.vertx = vertx;
this.proxyOptions = proxyOptions;
}

public Vertx getVertx() {
return vertx;
}

public ProxyOptions getProxyOptions() {
return proxyOptions;
}
}
17 changes: 15 additions & 2 deletions test-functional/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
**/SerdeTest.**,
**/SerializableTest.**,
**/JacksonInterferenceTest.**,
**/JacksonRequestContextTest.**
**/JacksonRequestContextTest.**,
**/HttpProxyTest.**
</filesToExclude>
<replacements>
<replacement>
Expand Down Expand Up @@ -101,7 +102,19 @@
</property>
</activation>
<properties>
<testSourceDirectory>src/test-ssl/java</testSourceDirectory>
<testSources>src/test-ssl/java</testSources>
</properties>
</profile>
<profile>
<id>no-ssl</id>
<activation>
<property>
<name>ssl</name>
<value>!true</value>
</property>
</activation>
<properties>
<testSources>src/test/java</testSources>
</properties>
</profile>
<profile>
Expand Down
103 changes: 103 additions & 0 deletions test-functional/src/test-ssl/java/com/arangodb/HttpProxyTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* DISCLAIMER
*
* Copyright 2016 ArangoDB GmbH, Cologne, Germany
*
* Licensed 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.
*
* Copyright holder is ArangoDB GmbH, Cologne, Germany
*/

package com.arangodb;

import com.arangodb.entity.ArangoDBVersion;
import com.arangodb.http.HttpProtocolConfig;
import io.netty.handler.proxy.ProxyConnectException;
import io.vertx.core.net.ProxyOptions;
import io.vertx.core.net.ProxyType;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;
import static org.junit.jupiter.api.Assumptions.assumeTrue;


/**
* @author Michele Rastelli
*/
class HttpProxyTest extends BaseTest {

@ParameterizedTest
@EnumSource(Protocol.class)
void httpProxy(Protocol protocol) {
assumeTrue(protocol != Protocol.VST);

final ArangoDB arangoDB = new ArangoDB.Builder()
.protocol(protocol)
.host("172.28.0.1", 8529)
.password("test")
.useSsl(true)
.sslContext(createSslContext())
.verifyHost(false)
.protocolConfig(HttpProtocolConfig.builder()
.proxyOptions(new ProxyOptions()
.setType(ProxyType.HTTP)
.setHost("172.28.0.1")
.setPort(8888)
.setUsername("user")
.setPassword("password"))
.build())
.build();
final ArangoDBVersion version = arangoDB.getVersion();
assertThat(version).isNotNull();
}


@ParameterizedTest
@EnumSource(Protocol.class)
void httpProxyWrongPassword(Protocol protocol) {
assumeTrue(protocol != Protocol.VST);

final ArangoDB arangoDB = new ArangoDB.Builder()
.protocol(protocol)
.host("172.28.0.1", 8529)
.password("test")
.useSsl(true)
.sslContext(createSslContext())
.verifyHost(false)
.protocolConfig(HttpProtocolConfig.builder()
.proxyOptions(new ProxyOptions()
.setType(ProxyType.HTTP)
.setHost("172.28.0.1")
.setPort(8888)
.setUsername("user")
.setPassword("wrong"))
.build())
.build();
Throwable thrown = catchThrowable(arangoDB::getVersion);
assertThat(thrown)
.isInstanceOf(ArangoDBException.class)
.hasMessageContaining("Cannot contact any host!")
.cause()
.isInstanceOf(ArangoDBMultipleException.class);
List<Throwable> causes = ((ArangoDBMultipleException) thrown.getCause()).getExceptions();
assertThat(causes).allSatisfy(e -> assertThat(e)
.isInstanceOf(ProxyConnectException.class)
.hasMessageContaining("status: 401 Unauthorized"));
assertThat(version).isNotNull();
}

}
5 changes: 3 additions & 2 deletions test-parent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<maven.deploy.skip>true</maven.deploy.skip>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<testSources>src/test/java</testSources>
<shaded/>
</properties>

Expand Down Expand Up @@ -153,7 +154,7 @@
</activation>

<properties>
<testSourceDirectory>src/test/java</testSourceDirectory>
<testSourceDirectory>${testSources}</testSourceDirectory>
<shaded>false</shaded>
</properties>
<dependencies>
Expand Down Expand Up @@ -209,7 +210,7 @@
</execution>
</executions>
<configuration>
<basedir>${project.basedir}/src/test/java</basedir>
<basedir>${project.basedir}/${testSources}</basedir>
<filesToInclude>**</filesToInclude>
<outputBasedir>${project.build.directory}/generated-test-sources</outputBasedir>
<outputDir>replacer</outputDir>
Expand Down

0 comments on commit 6ef7fa6

Please sign in to comment.