Quarkus: Rest Client Builder ignores http proxy properties

Created on 13 Jan 2020  路  13Comments  路  Source: quarkusio/quarkus

Describe the bug
(Describe the problem clearly and concisely.)
Rest Client Builder ignores http proxy properties.

Consider this piece of code that creates a customized REST Client implementation according to the microprofile specification:

 public MyRestClient restClient() {

        MyRestClient build = RestClientBuilder.newBuilder()
                .baseUri(UriBuilder.fromUri("http://localhost:3001").build())
                .property(PROPERTY_PROXY_HOST, "localhost")
                .property(PROPERTY_PROXY_PORT, 3001)
                .property(PROPERTY_PROXY_SCHEME, "http")
                .build(MyRestClient.class);
        return build;
    }

Expected behavior
Calls to services usiing this client should pass through the proxy.

Actual behavior
Proxy is totally ignored, and no matter if there is a proxy setup, the calls to any service will succeed

To Reproduce
Steps to reproduce the behavior:

  1. Open the attached project
  2. Replace the "localhost:3001" endpoint with any endpoint (google.com for example)
  3. Make a call to http://localhost:8080/hello
  4. The call succeeds, but it shouldn't!

Configuration

//

Environment (please complete the following information):

  • Output of uname -a or ver: 4.19.91-1-MANJARO #1 SMP Sat Dec 21 11:18:44 UTC 2019 x86_64 GNU/Linux
  • Output of java -version: Java 8
  • Quarkus version or git rev: 1.1.1

Additional context

From numerous breakpoints I put while investigating this, I may have an idea of why this happens :

The underlying implementation of the builder is RestEasyClientBuilderImpl, and it seems that the proxy settings are being picked up, BUT they are not used under certain circumstances.

This is the relevant piece that sets the proxy:

  boolean resetProxy = false;
        if (this.defaultProxy == null) {
            resetProxy = true;
            this.setProxyIfNeeded(config);
        }

        ClientHttpEngine engine = this.httpEngine != null ? this.httpEngine : (new ClientHttpEngineBuilder43()).resteasyClientBuilder(this).build();
        if (resetProxy) {
            this.defaultProxy = null;
        }

So, the this.setProxyIfNeeded() will pick up the proxy settings and create a new proxy. But in the following lines, the this.httpEngine is always != null, which means that the new ClientHttpEngineBuilder43()).resteasyClientBuilder(this).build() will not be used, so the proxy settings will not actually be used to create a new HTTP engine with those properties inside.

Example Project:
code-with-quarkus.zip

arerest-client kinbug triagout-of-date

Most helpful comment

I took a stab in fixing this in Resteasy, @gastaldi @geoand . I hope I made the correct fix (https://github.com/resteasy/Resteasy/pull/2268).

On a side note, it seems that the microprofile rest-client specification hasn't yet implemented setting the http-proxy either through a RestClientBuilder, or through the application.properties configuration (ref: https://github.com/eclipse/microprofile-rest-client/issues/55). Leaving this part to the actual implementation (Resteasy in this case) to handle this, by setting those properties, which I found inside the JBoss docs. RestEasyClientBuilder has support for setting a proxy but, unfortunately, does not provide the build(Class) method of the microprofile by itself, so it also cannot be used in this case.

In short, if this method does not work, I can find no alternative way of setting an http-proxy with the quarkus http client other than this undocumented method (it's documented on the part of Resteasy, but Quarkus does not explicitly mention it).

All 13 comments

cc @kenfinnigan @asoldano

@csotiriou thanks for reporting!

Have you perhaps omitted to attach the reproducer project?

@geoand you are right, I attached now the project, thanks.

I haven't tested it yet, but does it work if you set the http.proxyHost system property?

@gastaldi seems like it has the same behavior, perhaps for different reasons.

Still, setting this proxy setting will make all http clients use this proxy, which is not what I need for this project.

I took a stab in fixing this in Resteasy, @gastaldi @geoand . I hope I made the correct fix (https://github.com/resteasy/Resteasy/pull/2268).

On a side note, it seems that the microprofile rest-client specification hasn't yet implemented setting the http-proxy either through a RestClientBuilder, or through the application.properties configuration (ref: https://github.com/eclipse/microprofile-rest-client/issues/55). Leaving this part to the actual implementation (Resteasy in this case) to handle this, by setting those properties, which I found inside the JBoss docs. RestEasyClientBuilder has support for setting a proxy but, unfortunately, does not provide the build(Class) method of the microprofile by itself, so it also cannot be used in this case.

In short, if this method does not work, I can find no alternative way of setting an http-proxy with the quarkus http client other than this undocumented method (it's documented on the part of Resteasy, but Quarkus does not explicitly mention it).

@csotiriou is this issue going to be fixed by https://github.com/quarkusio/quarkus/pull/7316 which updates RESTEasy version to 4.5.1.Final?

@rsvoboda If https://github.com/resteasy/Resteasy/pull/2268 is contained in Resteasy 4.5.1, then yes, probably it will be fixed.

I tried the app with Quarkus 1.3.0.FInal and proxy settings are picked up.

Getting expected Caused by: java.net.ConnectException: Connection refused (Connection refused)

Hi, could you please provide example how to setup proxy for rest client in quarkus please?
the
.../mp-rest/proxy.enabled=true
...//mp-rest/proxy.endpoint=http://ipAddress:port

doesn't work for me.

@ferinoc the specification does not mention anything about proxy settings - but I see that the specification for 2.0 (https://projects.eclipse.org/projects/technology.microprofile/releases/rest-client-2.0) will bring proxy configurations via properties.

Vendor implementations can use their own properties - which is what I did with Quarkus. Check my initial comment / post in this issue to see what you can do to enable proxy support until micro profile rest client 2.0 arrives.

@csotiriou Thank you very much, it is working.

Thanks for implementing the proxy configuration for RestClientBuilder. I am having troubles however running a @InjectMock RestClient built with RestClientBuilder instead of @RegisterRestClient - it's basically either complaining about not being able to mock a proxy class when I don't use @RestClient identifier, or can't deal with ambiguous beans (when I use @RestClient identifier).

Do we have any working example on a JUnit5 RestClientBuilder Mock, that allows me to use your solution and still perform Unit Tests with same RestClient getting mocked as required?

Was this page helpful?
0 / 5 - 0 ratings