From ede6c5f82a283fd482dabe82050612503724edb6 Mon Sep 17 00:00:00 2001 From: jansupol Date: Thu, 12 Oct 2023 11:13:20 +0200 Subject: [PATCH] Support multipart by Jetty & Netty Signed-off-by: jansupol --- .../jetty/connector/JettyConnector.java | 17 ++- .../JerseyExpectContinueHandler.java | 6 + .../netty/connector/NettyConnector.java | 53 ++++--- .../jersey/netty/connector/BufferedTest.java | 2 - .../netty/connector/HttpHeadersTest.java | 21 ++- .../MultiPartHeaderModificationTest.java | 4 +- .../e2e/client/connector/MultiPartTest.java | 133 ++++++++++++++++++ .../RequestHeaderModificationsTest.java | 50 ++++--- 8 files changed, 237 insertions(+), 49 deletions(-) create mode 100644 tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/MultiPartTest.java diff --git a/connectors/jetty-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyConnector.java b/connectors/jetty-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyConnector.java index c8df611304..ffd1ffd454 100644 --- a/connectors/jetty-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyConnector.java +++ b/connectors/jetty-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyConnector.java @@ -26,11 +26,13 @@ import java.net.URI; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -274,10 +276,13 @@ public CookieStore getCookieStore() { @Override public ClientResponse apply(final ClientRequest jerseyRequest) throws ProcessingException { final Request jettyRequest = translateRequest(jerseyRequest); - final Map clientHeadersSnapshot = writeOutBoundHeaders(jerseyRequest.getHeaders(), jettyRequest); - final ContentProvider entity = getBytesProvider(jerseyRequest); + final Map clientHeadersSnapshot = new HashMap<>(); + final ContentProvider entity = + getBytesProvider(jerseyRequest, jerseyRequest.getHeaders(), clientHeadersSnapshot, jettyRequest); if (entity != null) { jettyRequest.content(entity); + } else { + clientHeadersSnapshot.putAll(writeOutBoundHeaders(jerseyRequest.getHeaders(), jettyRequest)); } try { @@ -362,12 +367,15 @@ private Map writeOutBoundHeaders(final MultivaluedMap e : stringHeaders.entrySet()) { - request.getHeaders().add(e.getKey(), e.getValue()); + request.getHeaders().put(e.getKey(), e.getValue()); } return stringHeaders; } - private ContentProvider getBytesProvider(final ClientRequest clientRequest) { + private ContentProvider getBytesProvider(final ClientRequest clientRequest, + final MultivaluedMap headers, + final Map snapshot, + final Request request) { final Object entity = clientRequest.getEntity(); if (entity == null) { @@ -378,6 +386,7 @@ private ContentProvider getBytesProvider(final ClientRequest clientRequest) { clientRequest.setStreamProvider(new OutboundMessageContext.StreamProvider() { @Override public OutputStream getOutputStream(final int contentLength) throws IOException { + snapshot.putAll(writeOutBoundHeaders(headers, request)); return outputStream; } }); diff --git a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/JerseyExpectContinueHandler.java b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/JerseyExpectContinueHandler.java index 6fc026ff15..3c03a8c1a3 100644 --- a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/JerseyExpectContinueHandler.java +++ b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/JerseyExpectContinueHandler.java @@ -21,6 +21,7 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.handler.codec.http.DefaultFullHttpRequest; +import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpResponse; import io.netty.handler.codec.http.HttpResponseStatus; @@ -77,6 +78,11 @@ CompletableFuture processExpect100ContinueRequest(HttpReques final DefaultFullHttpRequest nettyRequestHeaders = new DefaultFullHttpRequest(nettyRequest.protocolVersion(), nettyRequest.method(), nettyRequest.uri()); nettyRequestHeaders.headers().setAll(nettyRequest.headers()); + + if (!nettyRequestHeaders.headers().contains(HttpHeaderNames.HOST)) { + nettyRequestHeaders.headers().add(HttpHeaderNames.HOST, jerseyRequest.getUri().getHost()); + } + //If Expect:100-continue feature is enabled and client supports it, the nettyRequestHeaders will be //enriched with the 'Expect:100-continue' header. expect100ContinueExtension.invoke(jerseyRequest, nettyRequestHeaders); diff --git a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java index e98d982801..26e4699c52 100644 --- a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java +++ b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; @@ -31,6 +32,7 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -38,6 +40,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.function.Supplier; +import java.util.stream.Stream; import javax.net.ssl.SSLContext; import javax.ws.rs.ProcessingException; @@ -383,11 +386,13 @@ protected void initChannel(SocketChannel ch) throws Exception { } // headers - setHeaders(jerseyRequest, nettyRequest.headers(), false); + if (!jerseyRequest.hasEntity()) { + setHeaders(jerseyRequest, nettyRequest.headers(), false); - // host header - http 1.1 - if (!nettyRequest.headers().contains(HttpHeaderNames.HOST)) { - nettyRequest.headers().add(HttpHeaderNames.HOST, jerseyRequest.getUri().getHost()); + // host header - http 1.1 + if (!nettyRequest.headers().contains(HttpHeaderNames.HOST)) { + nettyRequest.headers().add(HttpHeaderNames.HOST, jerseyRequest.getUri().getHost()); + } } if (jerseyRequest.hasEntity()) { @@ -428,25 +433,22 @@ public void operationComplete(io.netty.util.concurrent.Future futu } } - if (!expect100ContinueHandler.isExpected()) { - // Send the HTTP request. Expect:100-continue processing is not applicable - // in this case. - entityWriter.writeAndFlush(nettyRequest); - } + final CountDownLatch headersSet = new CountDownLatch(1); + final CountDownLatch contentLengthSet = new CountDownLatch(1); jerseyRequest.setStreamProvider(new OutboundMessageContext.StreamProvider() { @Override public OutputStream getOutputStream(int contentLength) throws IOException { + replaceHeaders(jerseyRequest, nettyRequest.headers()); // WriterInterceptor changes + if (!nettyRequest.headers().contains(HttpHeaderNames.HOST)) { + nettyRequest.headers().add(HttpHeaderNames.HOST, jerseyRequest.getUri().getHost()); + } + headersSet.countDown(); + return entityWriter.getOutputStream(); } }); - if (HttpUtil.isTransferEncodingChunked(nettyRequest)) { - entityWriter.write(new HttpChunkedInput(entityWriter.getChunkedInput())); - } else { - entityWriter.write(entityWriter.getChunkedInput()); - } - executorService.execute(new Runnable() { @Override public void run() { @@ -457,9 +459,8 @@ public void run() { jerseyRequest.writeEntity(); if (entityWriter.getType() == NettyEntityWriter.Type.DELAYED) { - replaceHeaders(jerseyRequest, nettyRequest.headers()); // WriterInterceptor changes nettyRequest.headers().set(HttpHeaderNames.CONTENT_LENGTH, entityWriter.getLength()); - entityWriter.flush(); + contentLengthSet.countDown(); } } catch (IOException e) { @@ -468,9 +469,23 @@ public void run() { } }); - if (entityWriter.getType() != NettyEntityWriter.Type.DELAYED) { - entityWriter.flush(); + headersSet.await(); + if (!expect100ContinueHandler.isExpected()) { + // Send the HTTP request. Expect:100-continue processing is not applicable + // in this case. + entityWriter.writeAndFlush(nettyRequest); + } + + if (HttpUtil.isTransferEncodingChunked(nettyRequest)) { + entityWriter.write(new HttpChunkedInput(entityWriter.getChunkedInput())); + } else { + entityWriter.write(entityWriter.getChunkedInput()); + } + + if (entityWriter.getType() == NettyEntityWriter.Type.DELAYED) { + contentLengthSet.await(); } + entityWriter.flush(); } else { // Send the HTTP request. ch.writeAndFlush(nettyRequest); diff --git a/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/BufferedTest.java b/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/BufferedTest.java index fdaf5bed9a..46d6608b93 100644 --- a/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/BufferedTest.java +++ b/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/BufferedTest.java @@ -51,12 +51,10 @@ public class BufferedTest extends JerseyTest { public static class BufferedTestResource { @POST public String post(@Context HttpHeaders headers, String entity) { - System.out.println("Remote"); String ret = headers.getHeaderString(HEADER_1) + headers.getHeaderString(HEADER_2) + headers.getHeaderString(HEADER_3) + entity; - System.out.println(ret); return ret; } } diff --git a/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/HttpHeadersTest.java b/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/HttpHeadersTest.java index 905e155973..c3a9c1bfd0 100644 --- a/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/HttpHeadersTest.java +++ b/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/HttpHeadersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2023 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -16,6 +16,7 @@ package org.glassfish.jersey.netty.connector; +import javax.ws.rs.GET; import javax.ws.rs.HeaderParam; import javax.ws.rs.POST; import javax.ws.rs.Path; @@ -46,6 +47,15 @@ public String post( assertEquals("client", xClient); return "POST"; } + + @GET + public String get( + @HeaderParam("Transfer-Encoding") String transferEncoding, + @HeaderParam("X-CLIENT") String xClient, + @HeaderParam("X-WRITER") String xWriter) { + assertEquals("client", xClient); + return "GET"; + } } @Override @@ -66,4 +76,13 @@ public void testPost() { assertTrue(response.hasEntity()); response.close(); } + + @Test + public void testGet() { + Response response = target("test").request().header("X-CLIENT", "client").get(); + + assertEquals(200, response.getStatus()); + assertTrue(response.hasEntity()); + response.close(); + } } diff --git a/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/MultiPartHeaderModificationTest.java b/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/MultiPartHeaderModificationTest.java index c37065b75f..c4ac11fdd6 100644 --- a/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/MultiPartHeaderModificationTest.java +++ b/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/MultiPartHeaderModificationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2023 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -64,7 +64,7 @@ public static List testData() { return Arrays.asList(new Object[][] { {new HttpUrlConnectorProvider(), false}, {new GrizzlyConnectorProvider(), true}, - {new JettyConnectorProvider(), true}, + {new JettyConnectorProvider(), false}, {new ApacheConnectorProvider(), true}, }); } diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/MultiPartTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/MultiPartTest.java new file mode 100644 index 0000000000..613925cd31 --- /dev/null +++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/MultiPartTest.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.e2e.client.connector; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.client.HttpUrlConnectorProvider; +import org.glassfish.jersey.client.spi.ConnectorProvider; +import org.glassfish.jersey.jdk.connector.JdkConnectorProvider; +import org.glassfish.jersey.jetty.connector.JettyConnectorProvider; +import org.glassfish.jersey.netty.connector.NettyConnectorProvider; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.media.multipart.BodyPart; +import org.glassfish.jersey.media.multipart.BodyPartEntity; +import org.glassfish.jersey.media.multipart.MultiPart; +import org.glassfish.jersey.media.multipart.MultiPartFeature; +import org.glassfish.jersey.message.internal.ReaderWriter; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.glassfish.jersey.test.TestProperties; +import org.glassfish.jersey.test.spi.TestHelper; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DynamicContainer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestFactory; + +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class MultiPartTest { + + private static final Logger LOGGER = Logger.getLogger(RequestHeaderModificationsTest.class.getName()); + + public static List testData() { + return Arrays.asList( + new HttpUrlConnectorProvider(), + new JettyConnectorProvider(), + new NettyConnectorProvider(), + new JdkConnectorProvider() + ); + } + + @TestFactory + public Collection generateTests() { + Collection tests = new ArrayList<>(); + for (ConnectorProvider provider : testData()) { + HttpMultipartTest test = new HttpMultipartTest(provider) {}; + DynamicContainer container = TestHelper.toTestContainer(test, + String.format("MultiPartTest (%s)", provider.getClass().getSimpleName())); + tests.add(container); + } + return tests; + } + + public abstract static class HttpMultipartTest extends JerseyTest { + private final ConnectorProvider connectorProvider; + private static final String ENTITY = "hello"; + + public HttpMultipartTest(ConnectorProvider connectorProvider) { + this.connectorProvider = connectorProvider; + } + + @Override + protected Application configure() { + set(TestProperties.RECORD_LOG_LEVEL, Level.WARNING.intValue()); + enable(TestProperties.LOG_TRAFFIC); + return new ResourceConfig(MultipartResource.class) + .register(MultiPartFeature.class) + .register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.HEADERS_ONLY)); + } + + @Override + protected void configureClient(ClientConfig clientConfig) { + clientConfig.connectorProvider(connectorProvider); + clientConfig.register(MultiPartFeature.class); + } + + @Path("/") + public static class MultipartResource { + @POST + @Path("/upload") + @Consumes(MediaType.MULTIPART_FORM_DATA) + public String upload(@Context HttpHeaders headers, MultiPart multiPart) throws IOException { + return ReaderWriter.readFromAsString( + ((BodyPartEntity) multiPart.getBodyParts().get(0).getEntity()).getInputStream(), + multiPart.getMediaType()); + } + } + + @Test + public void testMultipart() { + MultiPart multipart = new MultiPart().bodyPart(new BodyPart().entity(ENTITY)); + multipart.setMediaType(MediaType.MULTIPART_FORM_DATA_TYPE); + + for (int i = 0; i != 5; i++) { + try (Response r = target().register(MultiPartFeature.class) + .path("upload") + .request() + .post(Entity.entity(multipart, multipart.getMediaType()))) { + Assertions.assertEquals(Response.Status.OK.getStatusCode(), r.getStatus()); + Assertions.assertEquals(ENTITY, r.readEntity(String.class)); + } + } + } + } +} diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/RequestHeaderModificationsTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/RequestHeaderModificationsTest.java index 3d63a59c3b..dc9f18dd04 100644 --- a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/RequestHeaderModificationsTest.java +++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/RequestHeaderModificationsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2023 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -101,16 +101,16 @@ public class RequestHeaderModificationsTest { public static List testData() { return Arrays.asList(new Object[][] { - {new HttpUrlConnectorProvider(), true, false}, - {new GrizzlyConnectorProvider(), false, false}, // change to true when JERSEY-2341 fixed - {new JettyConnectorProvider(), false, false}, // change to true when JERSEY-2341 fixed - {new ApacheConnectorProvider(), false, false}, // change to true when JERSEY-2341 fixed - {new Apache5ConnectorProvider(), false, false}, // change to true when JERSEY-2341 fixed - {new HttpUrlConnectorProvider(), true, true}, - {new GrizzlyConnectorProvider(), false, true}, // change to true when JERSEY-2341 fixed - {new JettyConnectorProvider(), false, true}, // change to true when JERSEY-2341 fixed - {new ApacheConnectorProvider(), false, true}, // change to true when JERSEY-2341 fixed - {new Apache5ConnectorProvider(), false, true}, // change to true when JERSEY-2341 fixed + {new HttpUrlConnectorProvider(), true, true, false, false}, + {new GrizzlyConnectorProvider(), false, false, false, false}, // change to true when JERSEY-2341 fixed + {new JettyConnectorProvider(), true, false, false, false}, // change to true when JERSEY-2341 fixed + {new ApacheConnectorProvider(), false, false, false, false}, // change to true when JERSEY-2341 fixed + {new Apache5ConnectorProvider(), false, false, false, false}, // change to true when JERSEY-2341 fixed + {new HttpUrlConnectorProvider(), true, true, true, true}, + {new GrizzlyConnectorProvider(), false, false, true, true}, // change to true when JERSEY-2341 fixed + {new JettyConnectorProvider(), true, false, true, false}, // change to true when JERSEY-2341 fixed + {new ApacheConnectorProvider(), false, false, true, true}, // change to true when JERSEY-2341 fixed + {new Apache5ConnectorProvider(), false, false, true, true}, // change to true when JERSEY-2341 fixed }); } @@ -119,7 +119,7 @@ public Collection generateTests() { Collection tests = new ArrayList<>(); testData().forEach(arr -> { RequestHeaderModificationsTemplateTest test = new RequestHeaderModificationsTemplateTest( - (ConnectorProvider) arr[0], (boolean) arr[1], (boolean) arr[2]) {}; + (ConnectorProvider) arr[0], (boolean) arr[1], (boolean) arr[2], (boolean) arr[3], (boolean) arr[4]) {}; tests.add(TestHelper.toTestContainer(test, String.format("%s (%s, %s, %s)", RequestHeaderModificationsTemplateTest.class.getSimpleName(), arr[0].getClass().getSimpleName(), arr[1], arr[2]))); @@ -130,13 +130,21 @@ public Collection generateTests() { public abstract static class RequestHeaderModificationsTemplateTest extends JerseyTest { private final ConnectorProvider connectorProvider; private final boolean modificationSupported; // remove when JERSEY-2341 fixed + private final boolean modificationSupportedAsync; // remove when JERSEY-2341 fixed + private final boolean addHeader; + private final boolean addHeaderAsync; public RequestHeaderModificationsTemplateTest(ConnectorProvider connectorProvider, - boolean modificationSupported, boolean addHeader) { + boolean modificationSupported, + boolean modificationSupportedAsync, + boolean addHeader, + boolean addHeaderAsync) { this.connectorProvider = connectorProvider; this.modificationSupported = modificationSupported; + this.modificationSupportedAsync = modificationSupportedAsync; this.addHeader = addHeader; + this.addHeaderAsync = addHeaderAsync; } @Override @@ -154,27 +162,27 @@ protected Application configure() { @Override protected void configureClient(ClientConfig clientConfig) { clientConfig.register(MyClientRequestFilter.class); - clientConfig.register(new MyWriterInterceptor(addHeader)); - clientConfig.register(new MyMessageBodyWriter(addHeader)); clientConfig.connectorProvider(connectorProvider); } @Test public void testWarningLogged() throws Exception { - Response response = requestBuilder().post(requestEntity()); - assertResponse(response); + Response response = requestBuilder(addHeader).post(requestEntity()); + assertResponse(response, modificationSupported, addHeader); } @Test public void testWarningLoggedAsync() throws Exception { - AsyncInvoker asyncInvoker = requestBuilder().async(); + AsyncInvoker asyncInvoker = requestBuilder(addHeaderAsync).async(); Future responseFuture = asyncInvoker.post(requestEntity()); Response response = responseFuture.get(); - assertResponse(response); + assertResponse(response, modificationSupportedAsync, addHeaderAsync); } - private Invocation.Builder requestBuilder() { + private Invocation.Builder requestBuilder(boolean addHeader) { return target(PATH) + .register(new MyWriterInterceptor(addHeader)) + .register(new MyMessageBodyWriter(addHeader)) .request() .header(REQUEST_HEADER_NAME_CLIENT, REQUEST_HEADER_VALUE_CLIENT) .header(REQUEST_HEADER_MODIFICATION_SUPPORTED, modificationSupported && addHeader) @@ -185,7 +193,7 @@ private Entity requestEntity() { return Entity.text(new MyEntity(QUESTION)); } - private void assertResponse(Response response) { + private void assertResponse(Response response, boolean modificationSupported, boolean addHeader) { if (!modificationSupported) { final String UNSENT_HEADER_CHANGES = "Unsent header changes"; LogRecord logRecord = findLogRecord(UNSENT_HEADER_CHANGES);