Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Webclient doesnt support proxy server #617

Closed
nischit7 opened this issue Feb 25, 2019 · 6 comments
Closed

Webclient doesnt support proxy server #617

nischit7 opened this issue Feb 25, 2019 · 6 comments
Labels
status/invalid We don't feel this issue is valid

Comments

@nischit7
Copy link

nischit7 commented Feb 25, 2019

Expected behavior

When webclient is intialized with proxy server configuration, HTTP calls should succeed.

Actual behavior

When one configures spring webclient with proxy server, it throws -

23:30:22.422 [reactor-http-nio-4] WARN  reactor.netty.http.client.HttpClientConnect - [id: 0x28550c92, L:/127.0.0.1:56179 - R:localhost/127.0.0.1:59541] The connection observed an error
io.netty.handler.proxy.ProxyConnectException: http, none, localhost/127.0.0.1:59541 => localhost:36849, status: 404 Not Found
	at io.netty.handler.proxy.HttpProxyHandler.handleResponse(HttpProxyHandler.java:188)
	at io.netty.handler.proxy.ProxyHandler.channelRead(ProxyHandler.java:260)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
	at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:438)
	at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:323)
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:297)
	at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:253)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1408)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:930)
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:677)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:612)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:529)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:491)
	at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:905)
	at java.lang.Thread.run(Thread.java:748)

Steps to reproduce

Initially I was wondering if this has anything to do with my setup itself. That means, whether wiremock is doing proxy server role properly.
I then tried on spring rest template and did exactly the same as spring webclient (refer test case below). It succeeded. I also tried with local squid proxy server it succeeded too.
I also tried with other netty backed async HTTP clients (such as org.asynchttpclient). They succeeded with the setup.

import java.net.InetSocketAddress;
import java.net.Proxy;
import java.nio.charset.StandardCharsets;

import javax.net.ssl.SSLException;

import com.fasterxml.jackson.databind.JsonNode;
import com.github.tomakehurst.wiremock.client.MappingBuilder;
import com.github.tomakehurst.wiremock.http.RequestMethod;
import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder;

import org.apache.http.conn.HttpHostConnectException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.client.reactive.ClientHttpConnector;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.http.client.reactive.ReactorResourceFactory;
import org.springframework.util.SocketUtils;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.WebClient;
import org.testng.annotations.AfterMethod;

import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;

import io.netty.channel.ChannelOption;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;

import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import reactor.netty.tcp.ProxyProvider;

import lombok.extern.slf4j.Slf4j;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;

@Slf4j
public class ProxyServerTest {

    private final String HOST = "localhost";
    private final String MOCK_ENDPOINT = "/my/endpoint";

    private WireMockServer targetServer;
    private WireMockServer proxyServer;
    private WireMock targetWireMock;
    private WireMock proxyWireMock;
    private ReactorResourceFactory reactorResourceFactory;
    private String targetBaseUrl;

    @BeforeMethod (alwaysRun = true)
    public void setup() {
        final int targetPort = SocketUtils.findAvailableTcpPort();
        this.targetServer = new WireMockServer(WireMockConfiguration.wireMockConfig().port(targetPort));
        this.targetServer.start();
        this.targetWireMock = new WireMock(targetPort);
        this.targetWireMock.resetMappings();
        this.targetBaseUrl = "http://" + HOST + ":" + targetPort;

        final int proxyPort = SocketUtils.findAvailableTcpPort();
        this.proxyServer = new WireMockServer(WireMockConfiguration.wireMockConfig().port(proxyPort).enableBrowserProxying(true));
        this.proxyServer.start();
        this.proxyWireMock = new WireMock(proxyPort);
        this.proxyWireMock.resetMappings();

        this.reactorResourceFactory = new ReactorResourceFactory();
        this.reactorResourceFactory.setUseGlobalResources(true);;
        this.reactorResourceFactory.afterPropertiesSet();
    }

    @AfterMethod (alwaysRun = true)
    public void tearDown() throws HttpHostConnectException {
        this.reactorResourceFactory.destroy();
        this.targetWireMock.shutdown();
        this.targetServer.stop();

        try {
            this.proxyWireMock.shutdown();
            this.proxyServer.stop();
        } catch (final Exception ex) {
            log.warn("Proxy server is shutdown already");
        }
    }

    @Test
    public void restTemplateWithWireMockAsProxyServer() {
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();

        Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(HOST, this.proxyServer.port()));
        requestFactory.setProxy(proxy);

        final RequestPatternBuilder reqPatternBuilder = RequestPatternBuilder.newRequestPattern(
                RequestMethod.GET, WireMock.urlEqualTo(MOCK_ENDPOINT));
        final MappingBuilder mappingBuilder = WireMock.get(WireMock.urlEqualTo(reqPatternBuilder.build().getUrl()));

        reqPatternBuilder.withHeader(HttpHeaders.ACCEPT, WireMock.containing(MediaType.APPLICATION_JSON_VALUE))
                .withHeader(HttpHeaders.ACCEPT_CHARSET, WireMock.containing(StandardCharsets.UTF_8.name().toUpperCase()));
        mappingBuilder.willReturn(WireMock.aResponse()
                .withStatus(HttpStatus.OK.value())
                .withBody("{ \"success\": true }")
                .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE));
        this.targetWireMock.register(mappingBuilder);

        ResponseEntity<JsonNode> responseEntity = new RestTemplate(requestFactory).getForEntity(this.targetBaseUrl + MOCK_ENDPOINT, JsonNode.class);
        assertThat(responseEntity.getStatusCode(), is(HttpStatus.OK));
        assertThat(responseEntity.getBody(), notNullValue());
    }

    @Test (expectedExceptions = ResourceAccessException.class)
    public void restTemplateWithWireMockAsProxyServerStopped() {
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();

        Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(HOST, this.proxyServer.port()));
        requestFactory.setProxy(proxy);

        stubServer();

        this.proxyWireMock.shutdown();
        this.proxyServer.stop();

        ResponseEntity<JsonNode> responseEntity = new RestTemplate(requestFactory).getForEntity(this.targetBaseUrl + MOCK_ENDPOINT, JsonNode.class);
        assertThat(responseEntity.getStatusCode(), is(HttpStatus.OK));
        assertThat(responseEntity.getBody(), notNullValue());
    }

    /**
     * Download and install https://squidman.net/, if you are testing on mac.
     */
    @Test
    public void restTemplateWithSquidAsProxyServer() {
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();

        Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(HOST, 8080));
        requestFactory.setProxy(proxy);

        stubServer();

        ResponseEntity<JsonNode> responseEntity = new RestTemplate(requestFactory).getForEntity(this.targetBaseUrl + MOCK_ENDPOINT, JsonNode.class);
        assertThat(responseEntity.getStatusCode(), is(HttpStatus.OK));
        assertThat(responseEntity.getBody(), notNullValue());
    }

    @Test
    public void webclientWithWireMockAsProxyServer() {

        stubServer();

        final WebClient webClient = WebClient.builder()
                .baseUrl(this.targetBaseUrl)
                .clientConnector(getClientHttpConnector())
                .build();

        webClient.get()
                .uri(MOCK_ENDPOINT).headers(httpHeaders -> {
                    httpHeaders.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
                    httpHeaders.add(HttpHeaders.ACCEPT_CHARSET, StandardCharsets.UTF_8.name());
                })
                .retrieve()
                .bodyToMono(String.class)
                .block();
    }

    private ClientHttpConnector getClientHttpConnector() {
        return new ReactorClientHttpConnector(this.reactorResourceFactory, httpClient -> httpClient.tcpConfiguration(tcpClient -> {
            try {
                final SslContext sslContext = SslContextBuilder.forClient()
                        .build();
                tcpClient.secure(t -> t.sslContext(sslContext))
                        .option(ChannelOption.SO_KEEPALIVE, false)
                        .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5_000);
                tcpClient = tcpClient.proxy(proxy -> proxy.type(ProxyProvider.Proxy.HTTP).host(HOST).port(this.proxyServer.port()).build());
                return tcpClient;
            } catch (final SSLException ex) {
                throw new IllegalStateException("Unable to create SSL context", ex);
            }
        }));
    }

    private void stubServer() {
        final RequestPatternBuilder reqPatternBuilder = RequestPatternBuilder.newRequestPattern(
                RequestMethod.GET, WireMock.urlEqualTo(MOCK_ENDPOINT));
        final MappingBuilder mappingBuilder = WireMock.get(WireMock.urlEqualTo(reqPatternBuilder.build().getUrl()));

        reqPatternBuilder.withHeader(HttpHeaders.ACCEPT, WireMock.containing(MediaType.APPLICATION_JSON_VALUE))
                .withHeader(HttpHeaders.ACCEPT_CHARSET, WireMock.containing(StandardCharsets.UTF_8.name().toUpperCase()));
        mappingBuilder.willReturn(WireMock.aResponse()
                .withStatus(HttpStatus.OK.value())
                .withBody("{ \"success\": true }")
                .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE));
        this.targetWireMock.register(mappingBuilder);
    }
}

Reactor Netty version

0.8.5.RELEASE

JVM version (e.g. java -version)

java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)

OS version (e.g. uname -a)

16.7.0 Darwin Kernel Version 16.7.0: Sun Oct 28 22:30:19 PDT 2018; root:xnu-3789.73.27~1/RELEASE_X86_64 x86_64

@violetagg
Copy link
Member

@nischit7 I think the issue here is that WireMock does not support forward (browser) proxying to an HTTPS target https://github.com/tomakehurst/wiremock/issues/401

Reactor Netty uses the functionality provided by Netty for proxying the requests, that functionality is based on HTTP CONNECT method, according to the issue above this is not supported by WireMock.

If you need proxy server for testing purposes you can try Hoverfly.
On the link below you can see how we use it in our tests.
https://github.com/reactor/reactor-netty/blob/master/src/test/java/reactor/netty/http/client/HttpClientProxyTest.java

Regards,
Violeta

@violetagg violetagg added the status/invalid We don't feel this issue is valid label Feb 25, 2019
@nischit7
Copy link
Author

@violetagg ... i think you didnt see my comment about squid proxy.
Secondly my connection is not https. Let me update my test case

@nischit7
Copy link
Author

nischit7 commented Feb 25, 2019

Updated the test case as below. I installed hoverfly and squid on my local machine. Note the last 3 test cases 'webclientWithWireMockAsProxyServer', 'webclientWithSquidAsProxyServer' and 'webclientWithHoverflyAsProxyServer'. All these test cases will fail with webclient.
Whereas the first 3 test cases using rest template using the same proxy servers will succeed.
All are plain http communication.

import java.net.InetSocketAddress;
import java.net.Proxy;
import java.nio.charset.StandardCharsets;

import com.fasterxml.jackson.databind.JsonNode;
import com.github.tomakehurst.wiremock.client.MappingBuilder;
import com.github.tomakehurst.wiremock.http.RequestMethod;
import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder;

import org.apache.http.conn.HttpHostConnectException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.client.reactive.ClientHttpConnector;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.http.client.reactive.ReactorResourceFactory;
import org.springframework.util.SocketUtils;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.WebClient;
import org.testng.annotations.AfterMethod;

import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;

import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import reactor.netty.tcp.ProxyProvider;

import lombok.extern.slf4j.Slf4j;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;

@Slf4j
public class ProxyServerTest {

    private final String HOST = "localhost";
    private final String MOCK_ENDPOINT = "/my/endpoint";

    private WireMockServer targetServer;
    private WireMockServer proxyServer;
    private WireMock targetWireMock;
    private WireMock proxyWireMock;
    private ReactorResourceFactory reactorResourceFactory;
    private String targetBaseUrl;

    @BeforeMethod (alwaysRun = true)
    public void setup() {
        final int targetPort = SocketUtils.findAvailableTcpPort();
        this.targetServer = new WireMockServer(WireMockConfiguration.wireMockConfig().port(targetPort));
        this.targetServer.start();
        this.targetWireMock = new WireMock(targetPort);
        this.targetWireMock.resetMappings();
        this.targetBaseUrl = "http://" + HOST + ":" + targetPort;

        final int proxyPort = SocketUtils.findAvailableTcpPort();
        this.proxyServer = new WireMockServer(WireMockConfiguration.wireMockConfig().port(proxyPort).enableBrowserProxying(true));
        this.proxyServer.start();
        this.proxyWireMock = new WireMock(proxyPort);
        this.proxyWireMock.resetMappings();

        this.reactorResourceFactory = new ReactorResourceFactory();
        this.reactorResourceFactory.setUseGlobalResources(true);;
        this.reactorResourceFactory.afterPropertiesSet();
    }

    @AfterMethod (alwaysRun = true)
    public void tearDown() throws HttpHostConnectException {
        this.reactorResourceFactory.destroy();
        this.targetWireMock.shutdown();
        this.targetServer.stop();

        try {
            this.proxyWireMock.shutdown();
            this.proxyServer.stop();
        } catch (final Exception ex) {
            log.warn("Proxy server is shutdown already");
        }
    }

    @Test
    public void restTemplateWithWireMockAsProxyServer() {
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();

        Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(HOST, this.proxyServer.port()));
        requestFactory.setProxy(proxy);

        final RequestPatternBuilder reqPatternBuilder = RequestPatternBuilder.newRequestPattern(
                RequestMethod.GET, WireMock.urlEqualTo(MOCK_ENDPOINT));
        final MappingBuilder mappingBuilder = WireMock.get(WireMock.urlEqualTo(reqPatternBuilder.build().getUrl()));

        reqPatternBuilder.withHeader(HttpHeaders.ACCEPT, WireMock.containing(MediaType.APPLICATION_JSON_VALUE))
                .withHeader(HttpHeaders.ACCEPT_CHARSET, WireMock.containing(StandardCharsets.UTF_8.name().toUpperCase()));
        mappingBuilder.willReturn(WireMock.aResponse()
                .withStatus(HttpStatus.OK.value())
                .withBody("{ \"success\": true }")
                .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE));
        this.targetWireMock.register(mappingBuilder);

        ResponseEntity<JsonNode> responseEntity = new RestTemplate(requestFactory).getForEntity(this.targetBaseUrl + MOCK_ENDPOINT, JsonNode.class);
        assertThat(responseEntity.getStatusCode(), is(HttpStatus.OK));
        assertThat(responseEntity.getBody(), notNullValue());
    }

    @Test (expectedExceptions = ResourceAccessException.class)
    public void restTemplateWithWireMockAsProxyServerStopped() {
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();

        Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(HOST, this.proxyServer.port()));
        requestFactory.setProxy(proxy);

        stubServer();

        this.proxyWireMock.shutdown();
        this.proxyServer.stop();

        ResponseEntity<JsonNode> responseEntity = new RestTemplate(requestFactory).getForEntity(this.targetBaseUrl + MOCK_ENDPOINT, JsonNode.class);
        assertThat(responseEntity.getStatusCode(), is(HttpStatus.OK));
        assertThat(responseEntity.getBody(), notNullValue());
    }

    /**
     * Download and install https://squidman.net/, if you are testing on mac.
     */
    @Test
    public void restTemplateWithSquidAsProxyServer() {
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();

        Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(HOST, 8080));
        requestFactory.setProxy(proxy);

        stubServer();

        ResponseEntity<JsonNode> responseEntity = new RestTemplate(requestFactory).getForEntity(this.targetBaseUrl + MOCK_ENDPOINT, JsonNode.class);
        assertThat(responseEntity.getStatusCode(), is(HttpStatus.OK));
        assertThat(responseEntity.getBody(), notNullValue());
    }

    /**
     * Install hoverfly https://hoverfly.io/
     */
    @Test
    public void restTemplateWithHoverflyProxyServer() {
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();

        Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(HOST, 8500));
        requestFactory.setProxy(proxy);

        stubServer();

        ResponseEntity<JsonNode> responseEntity = new RestTemplate(requestFactory).getForEntity(this.targetBaseUrl + MOCK_ENDPOINT, JsonNode.class);
        assertThat(responseEntity.getStatusCode(), is(HttpStatus.OK));
        assertThat(responseEntity.getBody(), notNullValue());
    }

    @Test
    public void webclientWithWireMockAsProxyServer() {

        stubServer();

        final WebClient webClient = WebClient.builder()
                .baseUrl(this.targetBaseUrl)
                .clientConnector(getClientHttpConnector())
                .build();

        webClient.get()
                .uri(MOCK_ENDPOINT).headers(httpHeaders -> {
                    httpHeaders.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
                    httpHeaders.add(HttpHeaders.ACCEPT_CHARSET, StandardCharsets.UTF_8.name());
                })
                .retrieve()
                .bodyToMono(String.class)
                .block();
    }

    /**
     * Download and install https://squidman.net/, if you are testing on mac.
     */
    @Test
    public void webclientWithSquidAsProxyServer() {

        final ClientHttpConnector clientHttpConnector = new ReactorClientHttpConnector(this.reactorResourceFactory, httpClient -> httpClient.tcpConfiguration(tcpClient -> {
            tcpClient = tcpClient.proxy(proxy -> proxy.type(ProxyProvider.Proxy.HTTP).host(HOST).port(8080).build());
            return tcpClient;
        }));
        stubServer();

        final WebClient webClient = WebClient.builder()
                .baseUrl(this.targetBaseUrl)
                .clientConnector(clientHttpConnector)
                .build();

        webClient.get()
                .uri(MOCK_ENDPOINT).headers(httpHeaders -> {
            httpHeaders.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
            httpHeaders.add(HttpHeaders.ACCEPT_CHARSET, StandardCharsets.UTF_8.name());
        })
                .retrieve()
                .bodyToMono(String.class)
                .block();
    }

    /**
     * Install hoverfly https://hoverfly.io/
     */
    @Test
    public void webclientWithHoverflyAsProxyServer() {

        final ClientHttpConnector clientHttpConnector = new ReactorClientHttpConnector(this.reactorResourceFactory, httpClient -> httpClient.tcpConfiguration(tcpClient -> {
            tcpClient = tcpClient.proxy(proxy -> proxy.type(ProxyProvider.Proxy.HTTP).host(HOST).port(8500).build());
            return tcpClient;
        }));
        stubServer();

        final WebClient webClient = WebClient.builder()
                .baseUrl(this.targetBaseUrl)
                .clientConnector(clientHttpConnector)
                .build();

        webClient.get()
                .uri(MOCK_ENDPOINT).headers(httpHeaders -> {
            httpHeaders.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
            httpHeaders.add(HttpHeaders.ACCEPT_CHARSET, StandardCharsets.UTF_8.name());
        })
                .retrieve()
                .bodyToMono(String.class)
                .block();
    }

    private ClientHttpConnector getClientHttpConnector() {
        return new ReactorClientHttpConnector(this.reactorResourceFactory, httpClient -> httpClient.tcpConfiguration(tcpClient -> {
            tcpClient = tcpClient.proxy(proxy -> proxy.type(ProxyProvider.Proxy.HTTP).host(HOST).port(this.proxyServer.port()).build());
            return tcpClient;
        }));
    }

    private void stubServer() {
        final RequestPatternBuilder reqPatternBuilder = RequestPatternBuilder.newRequestPattern(
                RequestMethod.GET, WireMock.urlEqualTo(MOCK_ENDPOINT));
        final MappingBuilder mappingBuilder = WireMock.get(WireMock.urlEqualTo(reqPatternBuilder.build().getUrl()));

        reqPatternBuilder.withHeader(HttpHeaders.ACCEPT, WireMock.containing(MediaType.APPLICATION_JSON_VALUE))
                .withHeader(HttpHeaders.ACCEPT_CHARSET, WireMock.containing(StandardCharsets.UTF_8.name().toUpperCase()));
        mappingBuilder.willReturn(WireMock.aResponse()
                .withStatus(HttpStatus.OK.value())
                .withBody("{ \"success\": true }")
                .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE));
        this.targetWireMock.register(mappingBuilder);
    }
}

@violetagg violetagg reopened this Feb 25, 2019
@violetagg violetagg removed the status/invalid We don't feel this issue is valid label Feb 25, 2019
@violetagg
Copy link
Member

violetagg commented Feb 25, 2019

@nischit7

I ran Hoverfly with the command below

hoverfly -import simulation.json -plain-http-tunneling

More about -plain-http-tunneling here SpectoLabs/hoverfly#650

Then executed ProxyServerTest#webclientWithHoverflyAsProxyServer -> it passed

###################

I ran Squid with the following option set to allow (it is deny by default)

# Deny CONNECT to other than secure SSL ports
http_access allow CONNECT !SSL_ports

Then executed ProxyServerTest#webclientWithSquidAsProxyServer -> it passed

###################

Whereas the first 3 test cases using rest template using the same proxy servers will succeed.

RestTemplate does not use HTTP CONNECT method in these scenarios.

###################

Netty's HTTP proxy handler does CONNECT always because of this you see this issue with WireMock
Again more info here SpectoLabs/hoverfly#650
#159

I'm leaving this opened if you have more questions.

@nischit7
Copy link
Author

@violetagg Thanks a lot for clarifying. In the beginning when you mentioned about CONNECT method, I didnt give enough attention. The moment I saw what you altered Squid proxy config for "allow CONNECT", it enlightened me. I am closing this ticket

@violetagg violetagg added the status/invalid We don't feel this issue is valid label Feb 26, 2019
@devansh-dalal
Copy link

devansh-dalal commented Nov 20, 2020

Any resolution for this now yet?
Is there a way to run wiremock proxy server with https on https? instead of trying to change anything with netty CONNECT calls.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status/invalid We don't feel this issue is valid
Projects
None yet
Development

No branches or pull requests

3 participants