Mark Schäfer
Mark Schäfer

Reputation: 984

Response Stream cancelled in Wiremock-Test

The following test with Wiremock throws an exception when sending an HTTP POST request to a Wiremock server.

import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.common.ConsoleNotifier;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import org.junit.jupiter.api.Test;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;

import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.post;
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;

public class ClientTest {

    private static final int PORT = 27970;

    @Test
    public void myTest() throws IOException, InterruptedException {
        WireMockServer server = new WireMockServer(WireMockConfiguration.options().port(PORT).notifier(new ConsoleNotifier(true)));
        server.start();
        WireMock mock = WireMock.create().host("localhost").port(PORT).build();
        WireMock.configureFor(mock);

        WireMock.stubFor(
                post(urlEqualTo("/foo"))
                        .willReturn(aResponse()
                                .withStatus(201)
                                .withBody("bar")));

        HttpRequest httpRequest = HttpRequest.newBuilder()
                .uri(URI.create("http://localhost:" + PORT + "/foo"))
//                .version(HttpClient.Version.HTTP_1_1)
//                .POST(HttpRequest.BodyPublishers.ofString("stuff"))
                .POST(HttpRequest.BodyPublishers.ofInputStream(() -> new ByteArrayInputStream("stuff".getBytes(StandardCharsets.UTF_8))))
                .build();

        // Here there be Exceptions
        HttpResponse<String> httpResponse = HttpClient.newHttpClient().send(httpRequest, HttpResponse.BodyHandlers.ofString());

        assert httpResponse.body().equals("bar");
    }
}

The following exceptions occurs:

java.io.IOException: Received RST_STREAM: Stream cancelled

    at java.net.http/jdk.internal.net.http.HttpClientImpl.send(HttpClientImpl.java:586)
    at java.net.http/jdk.internal.net.http.HttpClientFacade.send(HttpClientFacade.java:123)
    at ContentStoreConnectorImplTest.myTest(ContentStoreConnectorImplTest.java:44)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
Caused by: java.io.IOException: Received RST_STREAM: Stream cancelled
    at java.net.http/jdk.internal.net.http.Stream.handleReset(Stream.java:534)
    at java.net.http/jdk.internal.net.http.Stream.incoming_reset(Stream.java:505)
    at java.net.http/jdk.internal.net.http.Stream.otherFrame(Stream.java:452)
    at java.net.http/jdk.internal.net.http.Stream.incoming(Stream.java:445)
    at java.net.http/jdk.internal.net.http.Http2Connection.processFrame(Http2Connection.java:812)
    at java.net.http/jdk.internal.net.http.frame.FramesDecoder.decode(FramesDecoder.java:155)
    at java.net.http/jdk.internal.net.http.Http2Connection$FramesController.processReceivedData(Http2Connection.java:232)
    at java.net.http/jdk.internal.net.http.Http2Connection.asyncReceive(Http2Connection.java:674)
    at java.net.http/jdk.internal.net.http.Http2Connection$Http2TubeSubscriber.processQueue(Http2Connection.java:1310)
    at java.net.http/jdk.internal.net.http.common.SequentialScheduler$LockingRestartableTask.run(SequentialScheduler.java:205)
    at java.net.http/jdk.internal.net.http.common.SequentialScheduler$CompleteRestartableTask.run(SequentialScheduler.java:149)
    at java.net.http/jdk.internal.net.http.common.SequentialScheduler$SchedulableTask.run(SequentialScheduler.java:230)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
    at java.base/java.lang.Thread.run(Thread.java:833)

If either HTTP/1.1 or a String BodyPublisher or a GET request is used everything works, see commented lines.

After some debugging we found no solution or obvious problem. We are also not sure if this is a Wiremock problem or a problem with the Java-HTTP-Client.

When we dump the request, the body looks a bit strange though with some additional lines:

POST /foo HTTP/1.1
Connection: Upgrade, HTTP2-Settings
Host: localhost:2727
HTTP2-Settings: AAEAAEAAAAIAAAABAAMAAABkAAQBAAAAAAUAAEAA
Transfer-encoding: chunked
Upgrade: h2c
User-Agent: Java-http-client/17.0.6

5
stuff
0

These lines disappear when using the String-Publisher. They do not disappear when using HTTP/1.1 but then it works regardless.

The dependencies as pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>wiremockhttp2</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.wiremock</groupId>
            <artifactId>wiremock</artifactId>
            <version>3.3.1</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.10.1</version>
            <scope>test</scope>
        </dependency>

    </dependencies>
</project>

Upvotes: 4

Views: 1400

Answers (1)

flup
flup

Reputation: 27103

We ran into this issue today on java 21. Upgrading the jdk from Oracle 21.0.2 to Temurin 21.0.6 fixed it for us.

Upvotes: 0

Related Questions