From bec2a38dec55ae1a113d80872411f4f5476246a0 Mon Sep 17 00:00:00 2001 From: Tomas Langer Date: Wed, 11 Jan 2023 17:09:57 +0100 Subject: [PATCH 1/4] Throw an exception when route does not finish, reroute, or next a response. --- .../io/helidon/common/http/HttpPrologue.java | 4 +- .../server/UnsentResponseTest.java | 74 +++++++++++++++++++ .../nima/webserver/http/HttpRouting.java | 20 +++-- 3 files changed, 91 insertions(+), 7 deletions(-) create mode 100644 nima/tests/integration/webserver/webserver/src/test/java/io/helidon/nima/tests/integration/server/UnsentResponseTest.java diff --git a/common/http/src/main/java/io/helidon/common/http/HttpPrologue.java b/common/http/src/main/java/io/helidon/common/http/HttpPrologue.java index 16dd4ad6645..a4819ae6b60 100644 --- a/common/http/src/main/java/io/helidon/common/http/HttpPrologue.java +++ b/common/http/src/main/java/io/helidon/common/http/HttpPrologue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Oracle and/or its affiliates. + * Copyright (c) 2022, 2023 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -248,7 +248,7 @@ public boolean equals(Object obj) { @Override public String toString() { - return "HttpPrologueRecord[" + return "HttpPrologue[" + "protocol=" + protocol + ", " + "protocolVersion=" + protocolVersion + ", " + "method=" + method + ", " diff --git a/nima/tests/integration/webserver/webserver/src/test/java/io/helidon/nima/tests/integration/server/UnsentResponseTest.java b/nima/tests/integration/webserver/webserver/src/test/java/io/helidon/nima/tests/integration/server/UnsentResponseTest.java new file mode 100644 index 00000000000..f53705f1557 --- /dev/null +++ b/nima/tests/integration/webserver/webserver/src/test/java/io/helidon/nima/tests/integration/server/UnsentResponseTest.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2021, 2023 Oracle and/or its affiliates. + * + * 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. + */ + +package io.helidon.nima.tests.integration.server; + +import io.helidon.common.http.Http; +import io.helidon.nima.testing.junit5.webserver.DirectClient; +import io.helidon.nima.testing.junit5.webserver.RoutingTest; +import io.helidon.nima.testing.junit5.webserver.SetUpRoute; +import io.helidon.nima.webclient.http1.Http1ClientResponse; +import io.helidon.nima.webserver.http.Handler; +import io.helidon.nima.webserver.http.HttpRules; +import io.helidon.nima.webserver.http.ServerRequest; +import io.helidon.nima.webserver.http.ServerResponse; + +import org.junit.jupiter.api.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +@RoutingTest +class UnsentResponseTest { + @SetUpRoute + static void routing(HttpRules rules) { + rules.get("/no-response", new NoResponseHandler()) + .get("/response", (req, res) -> { + res.send(); + }); + } + + @Test + void testUnsentResponseThrowsException(DirectClient client) { + try (Http1ClientResponse response = client.get("/no-response") + .request()) { + + assertThat(response.status(), is(Http.Status.INTERNAL_SERVER_ERROR_500)); + assertThat(response.entity().as(String.class), is("Internal Server Error")); + } + } + + @Test + void testNormalResponse(DirectClient client) { + try (Http1ClientResponse response = client.get("/response") + .request()) { + + assertThat(response.status(), is(Http.Status.OK_200)); + } + } + + // to have a bit nicer error output for the internal server error + private static final class NoResponseHandler implements Handler { + @Override + public void handle(ServerRequest req, ServerResponse res) { + } + + @Override + public String toString() { + return "NoResponseHandler"; + } + } +} diff --git a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http/HttpRouting.java b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http/HttpRouting.java index 905127cb8d1..ff7fdab3df9 100644 --- a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http/HttpRouting.java +++ b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http/HttpRouting.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Oracle and/or its affiliates. + * Copyright (c) 2022, 2023 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,12 +27,14 @@ import java.util.function.Supplier; import io.helidon.common.Weights; +import io.helidon.common.http.DirectHandler; import io.helidon.common.http.Http; import io.helidon.common.http.HttpException; import io.helidon.common.http.HttpPrologue; import io.helidon.common.http.NotFoundException; import io.helidon.common.http.PathMatcher; import io.helidon.common.http.PathMatchers; +import io.helidon.common.http.RequestException; import io.helidon.nima.webserver.ConnectionContext; import io.helidon.nima.webserver.Routing; import io.helidon.nima.webserver.ServerLifecycle; @@ -476,10 +478,18 @@ private RoutingResult doRoute(ConnectionContext ctx, RoutingRequest request, Rou return RoutingResult.FINISH; } - // not nexted, not rerouted - just send it! - response.send(); - - return RoutingResult.FINISH; + // not nexted, not rerouted - invalid state + // user must send a response within the current thread + LOGGER.log(System.Logger.Level.WARNING, + "A route MUST call either send, reroute, or next on ServerResponse on the request thread. " + + "Neither of these was called for request: " + request.prologue() + + "; Handler: " + next.handler()); + + throw RequestException.builder() + // we cannot share the information above with a client + .message("Internal Server Error") + .type(DirectHandler.EventType.INTERNAL_ERROR) + .build(); } return RoutingResult.NONE; From fc4e4d5bb2cbecd124687b1276d66bd1c60659ea Mon Sep 17 00:00:00 2001 From: Tomas Langer Date: Thu, 12 Jan 2023 16:57:06 +0100 Subject: [PATCH 2/4] WebClient fix to use content length from the supplied entity (when not using streaming) Related test fixes. --- microprofile/lra/jax-rs/pom.xml | 5 ++ .../lra/CoordinatorHeaderPropagationTest.java | 62 +++++++++++-------- .../http2/webclient/ClientRequestImpl.java | 14 ++++- .../server/accesslog/AccessLogTest.java | 18 ++++-- .../test/resources/logging-test.properties | 4 +- .../server/MaxPayloadSizeTest.java | 5 +- .../helidon/nima/webclient/ClientRequest.java | 14 ++++- .../webclient/http1/ClientRequestImpl.java | 14 ++++- 8 files changed, 93 insertions(+), 43 deletions(-) diff --git a/microprofile/lra/jax-rs/pom.xml b/microprofile/lra/jax-rs/pom.xml index 63bc29f81d1..4e6e2e975ee 100644 --- a/microprofile/lra/jax-rs/pom.xml +++ b/microprofile/lra/jax-rs/pom.xml @@ -90,6 +90,11 @@ hamcrest-all test + + helidon-nima-webclient + io.helidon.nima.webclient + test + diff --git a/microprofile/lra/jax-rs/src/test/java/io/helidon/microprofile/lra/CoordinatorHeaderPropagationTest.java b/microprofile/lra/jax-rs/src/test/java/io/helidon/microprofile/lra/CoordinatorHeaderPropagationTest.java index 8cc76d08a4e..fa316fbb24b 100644 --- a/microprofile/lra/jax-rs/src/test/java/io/helidon/microprofile/lra/CoordinatorHeaderPropagationTest.java +++ b/microprofile/lra/jax-rs/src/test/java/io/helidon/microprofile/lra/CoordinatorHeaderPropagationTest.java @@ -43,8 +43,9 @@ import io.helidon.microprofile.tests.junit5.AddExtension; import io.helidon.microprofile.tests.junit5.DisableDiscovery; import io.helidon.microprofile.tests.junit5.HelidonTest; +import io.helidon.nima.webclient.http1.Http1Client; +import io.helidon.nima.webclient.http1.Http1ClientResponse; import io.helidon.nima.webserver.http.HttpService; -import io.helidon.reactive.webclient.WebClient; import jakarta.annotation.Priority; import jakarta.enterprise.context.ApplicationScoped; @@ -104,6 +105,7 @@ class CoordinatorHeaderPropagationTest { private static final String PROPAGATED_HEADER = "xxx-tmm-propagated-header"; private static final String EXTRA_COORDINATOR_PROPAGATED_HEADER = "xBb-tmm-extra-start-header"; private static final String NOT_PROPAGATED_HEADER = "non-propagated-header"; + private static final Http.HeaderName LRA_HTTP_CONTEXT_HEADER_NAME = Http.Header.create(LRA_HTTP_CONTEXT_HEADER); private static volatile int port = -1; @@ -135,14 +137,14 @@ HttpService mockCoordinator() { .post("/start", (req, res) -> { startHeadersCoordinator.putAll(req.headers().toMap()); String lraId = URI.create("http://localhost:" - + port - + "/lra-coordinator/xxx-xxx-" - + lraIndex.incrementAndGet()).toASCIIString(); + + port + + "/lra-coordinator/xxx-xxx-" + + lraIndex.incrementAndGet()).toASCIIString(); lraMap.put(lraId, new ConcurrentHashMap<>()); res.status(Http.Status.CREATED_201) - .header(LRA_HTTP_CONTEXT_HEADER, lraId) + .header(LRA_HTTP_CONTEXT_HEADER_NAME, lraId) .header(NOT_PROPAGATED_HEADER, "not this extra one!") .header(EXTRA_COORDINATOR_PROPAGATED_HEADER, "yes extra start header!") .send(); @@ -160,21 +162,22 @@ HttpService mockCoordinator() { //no complete resource // after lra if (lraMap.get(lraId).get("after") != null) { - WebClient.builder() + try (Http1ClientResponse clientResponse = Http1Client.builder() .baseUri(lraMap.get(lraId).get("after").toASCIIString()) .build() - .put() - .addHeader(LRA_HTTP_CONTEXT_HEADER, lraId) + .method(Http.Method.PUT) + .header(LRA_HTTP_CONTEXT_HEADER_NAME, lraId) .headers(reqHeaders -> { // relay all incoming headers req.headers().forEach(reqHeaders::add); return reqHeaders; }) - .submit(LRAStatus.Closing.name()) - .onError(res::send) - .forSingle(wcr2 -> { - res.send(); - }); + .submit(LRAStatus.Closing.name())) { + if (clientResponse.status().family() != Http.Status.Family.SUCCESSFUL) { + res.status(clientResponse.status()); + } + res.send(); + } } else { res.send(); } @@ -182,38 +185,45 @@ HttpService mockCoordinator() { return; } - WebClient.builder() + try (Http1ClientResponse clientResponse = Http1Client.builder() .baseUri(lraMap.get(lraId).get("complete").toASCIIString()) .build() - .put() - .addHeader(LRA_HTTP_CONTEXT_HEADER, lraId) + .method(Http.Method.PUT) + .header(LRA_HTTP_CONTEXT_HEADER_NAME, lraId) .headers(reqHeaders -> { // relay all incoming headers req.headers().forEach(reqHeaders::add); return reqHeaders; }) - .submit() - .onError(res::send) - .forSingle(wcr1 -> res.send()); + .request()) { + if (clientResponse.status().family() != Http.Status.Family.SUCCESSFUL) { + res.status(clientResponse.status()); + } + res.send(); + } }) .put("/{lraId}/cancel", (req, res) -> { closeHeadersCoordinator.putAll(req.headers().toMap()); String lraId = "http://localhost:" + port + "/lra-coordinator/" + req.path() .pathParameters() .value("lraId"); - WebClient.builder() + + try (Http1ClientResponse clientResponse = Http1Client.builder() .baseUri(lraMap.get(lraId).get("compensate").toASCIIString()) .build() - .put() - .addHeader(LRA_HTTP_CONTEXT_HEADER, lraId) + .method(Http.Method.PUT) + .header(LRA_HTTP_CONTEXT_HEADER_NAME, lraId) .headers(reqHeaders -> { // relay all incoming headers req.headers().forEach(reqHeaders::add); return reqHeaders; }) - .submit() - .onError(res::send) - .forSingle(wcResponse -> res.send()); + .request()) { + if (clientResponse.status().family() != Http.Status.Family.SUCCESSFUL) { + res.status(clientResponse.status()); + } + res.send(); + } }) //join .put("/{lraId}", (req, res) -> { @@ -232,6 +242,7 @@ HttpService mockCoordinator() { lraMap.get(lraId).put(uriType.trim(), uri); } + res.send(); }); } @@ -241,6 +252,7 @@ private void ready( @Initialized(ApplicationScoped.class) Object event, BeanManager bm) { port = bm.getExtension(ServerCdiExtension.class).port(); + // Provide LRA client with coordinator loadbalancer url coordinatorLocatorService.overrideCoordinatorUriSupplier(() -> URI.create("http://localhost:" + port + "/lra-coordinator")); diff --git a/nima/http2/webclient/src/main/java/io/helidon/nima/http2/webclient/ClientRequestImpl.java b/nima/http2/webclient/src/main/java/io/helidon/nima/http2/webclient/ClientRequestImpl.java index 17819a5c993..d1c4e456e47 100644 --- a/nima/http2/webclient/src/main/java/io/helidon/nima/http2/webclient/ClientRequestImpl.java +++ b/nima/http2/webclient/src/main/java/io/helidon/nima/http2/webclient/ClientRequestImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Oracle and/or its affiliates. + * Copyright (c) 2022, 2023 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,8 +24,10 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.function.Consumer; +import java.util.function.Function; import io.helidon.common.buffers.BufferData; +import io.helidon.common.http.ClientRequestHeaders; import io.helidon.common.http.Http; import io.helidon.common.http.Http.Header; import io.helidon.common.http.Http.HeaderValue; @@ -42,7 +44,7 @@ class ClientRequestImpl implements Http2ClientRequest { private static final Map CHANNEL_CACHE = new ConcurrentHashMap<>(); - private final WritableHeaders explicitHeaders = WritableHeaders.create(); + private WritableHeaders explicitHeaders = WritableHeaders.create(); private final Http2ClientImpl client; @@ -89,6 +91,12 @@ public Http2ClientRequest header(HeaderValue header) { return this; } + @Override + public Http2ClientRequest headers(Function> headersConsumer) { + this.explicitHeaders = headersConsumer.apply(ClientRequestHeaders.create(explicitHeaders)); + return this; + } + @Override public Http2ClientRequest pathParam(String name, String value) { throw new UnsupportedOperationException("Not implemented"); @@ -118,7 +126,7 @@ public Http2ClientResponse submit(Object entity) { } else { entityBytes = entityBytes(entity); } - headers.setIfAbsent(Header.create(Header.CONTENT_LENGTH, String.valueOf(entityBytes.length))); + headers.set(Header.create(Header.CONTENT_LENGTH, entityBytes.length)); Http2Headers http2Headers = prepareHeaders(headers); stream.write(http2Headers, entityBytes.length == 0); diff --git a/nima/tests/integration/webserver/access-log/src/test/java/io/helidon/nima/tests/integration/server/accesslog/AccessLogTest.java b/nima/tests/integration/webserver/access-log/src/test/java/io/helidon/nima/tests/integration/server/accesslog/AccessLogTest.java index def18eac34c..94f88a73ff4 100644 --- a/nima/tests/integration/webserver/access-log/src/test/java/io/helidon/nima/tests/integration/server/accesslog/AccessLogTest.java +++ b/nima/tests/integration/webserver/access-log/src/test/java/io/helidon/nima/tests/integration/server/accesslog/AccessLogTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Oracle and/or its affiliates. + * Copyright (c) 2022, 2023 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,11 +22,13 @@ import java.time.Clock; import java.time.Instant; import java.time.ZoneId; +import java.util.List; import java.util.concurrent.atomic.AtomicReference; import java.util.logging.LogRecord; import java.util.logging.StreamHandler; import io.helidon.common.http.Http; +import io.helidon.common.testing.http.junit5.SocketHttpClient; import io.helidon.nima.testing.junit5.webserver.ServerTest; import io.helidon.nima.testing.junit5.webserver.SetUpRoute; import io.helidon.nima.webclient.http1.Http1Client; @@ -44,6 +46,7 @@ import static io.helidon.common.testing.junit5.MatcherWithRetry.assertThatWithRetry; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.startsWith; import static org.hamcrest.MatcherAssert.assertThat; @ServerTest @@ -51,9 +54,11 @@ class AccessLogTest { private static final AtomicReference LOG_HANDLER = new AtomicReference<>(); private final Http1Client client; + private final SocketHttpClient socketClient; - AccessLogTest(Http1Client client) { + AccessLogTest(Http1Client client, SocketHttpClient socketClient) { this.client = client; + this.socketClient = socketClient; } @SetUpRoute @@ -83,10 +88,11 @@ void testRequestsAndValidateAccessLog() { response = client.get("/wrong").request(); assertThat(response.status(), is(Http.Status.NOT_FOUND_404)); - response = client.get("/access") - .header(Http.Header.create(Http.Header.CONTENT_LENGTH, "47a")) - .request(); - assertThat(response.status(), is(Http.Status.BAD_REQUEST_400)); + String socketResponse = socketClient.sendAndReceive("/access", + Http.Method.GET, + null, + List.of("Content-Length: 47a")); + assertThat(socketResponse, startsWith("HTTP/1.1 " + Http.Status.BAD_REQUEST_400.text())); // Use retry since no happens-before relationship between log entry and assertion assertThatWithRetry("Check log entry for /access exist", diff --git a/nima/tests/integration/webserver/access-log/src/test/resources/logging-test.properties b/nima/tests/integration/webserver/access-log/src/test/resources/logging-test.properties index 23b4e4f3730..6cc63d28c91 100644 --- a/nima/tests/integration/webserver/access-log/src/test/resources/logging-test.properties +++ b/nima/tests/integration/webserver/access-log/src/test/resources/logging-test.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2022 Oracle and/or its affiliates. +# Copyright (c) 2022, 2023 Oracle and/or its affiliates. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -19,7 +19,7 @@ java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter java.util.logging.SimpleFormatter.format=%1$tH:%1$tM:%1$tS %4$s %3$s %5$s%6$s%n # Global logging level. Can be overridden by specific loggers .level=INFO -io.helidon.nima.level=FINEST + io.helidon.nima.webserver.accesslog.MemoryLogHandler.level=FINEST io.helidon.nima.webserver.accesslog.MemoryLogHandler.append=false io.helidon.nima.webserver.AccessLog.level=INFO diff --git a/nima/tests/integration/webserver/webserver/src/test/java/io/helidon/nima/tests/integration/server/MaxPayloadSizeTest.java b/nima/tests/integration/webserver/webserver/src/test/java/io/helidon/nima/tests/integration/server/MaxPayloadSizeTest.java index d9c02d16706..7a0eb5a9c79 100644 --- a/nima/tests/integration/webserver/webserver/src/test/java/io/helidon/nima/tests/integration/server/MaxPayloadSizeTest.java +++ b/nima/tests/integration/webserver/webserver/src/test/java/io/helidon/nima/tests/integration/server/MaxPayloadSizeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022 Oracle and/or its affiliates. + * Copyright (c) 2020, 2023 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -77,10 +77,9 @@ static void startServer(HttpRules rules) { @Test void testContentLengthExceeded() { try (Http1ClientResponse response = client.method(Http.Method.POST) - .header(Header.CONTENT_LENGTH, "512") .path("/maxpayload") .header(HeaderValues.CONTENT_TYPE_OCTET_STREAM) - .request()) { + .submit(new byte[512])) { assertThat(response.status(), is(Http.Status.REQUEST_ENTITY_TOO_LARGE_413)); assertThat(response.headers(), hasHeader(HeaderValues.CONNECTION_CLOSE)); } diff --git a/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/ClientRequest.java b/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/ClientRequest.java index 1ff5f244fb8..60873c7502e 100644 --- a/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/ClientRequest.java +++ b/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/ClientRequest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Oracle and/or its affiliates. + * Copyright (c) 2022, 2023 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,8 +19,12 @@ import java.io.IOException; import java.io.OutputStream; import java.net.URI; +import java.util.function.Consumer; +import java.util.function.Function; +import io.helidon.common.http.ClientRequestHeaders; import io.helidon.common.http.Http; +import io.helidon.common.http.WritableHeaders; import io.helidon.common.uri.UriEncoding; import io.helidon.nima.common.tls.Tls; @@ -87,6 +91,14 @@ default B header(Http.HeaderName name, String value) { return header(Http.Header.create(name, true, false, value)); } + /** + * Update headers. + * + * @param headersConsumer consumer of client request headers + * @return updated request + */ + B headers(Function> headersConsumer); + /** * Replace a placeholder in URI with an actual value. * diff --git a/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/http1/ClientRequestImpl.java b/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/http1/ClientRequestImpl.java index 1b811a262ed..a19e682c6d3 100644 --- a/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/http1/ClientRequestImpl.java +++ b/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/http1/ClientRequestImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Oracle and/or its affiliates. + * Copyright (c) 2022, 2023 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,6 +26,8 @@ import java.util.Queue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedDeque; +import java.util.function.Consumer; +import java.util.function.Function; import io.helidon.common.GenericType; import io.helidon.common.buffers.BufferData; @@ -60,7 +62,7 @@ class ClientRequestImpl implements Http1ClientRequest { private static final String HTTPS = "https"; private static final Map> CHANNEL_CACHE = new ConcurrentHashMap<>(); - private final WritableHeaders explicitHeaders = WritableHeaders.create(); + private WritableHeaders explicitHeaders = WritableHeaders.create(); private final UriQueryWriteable query; private final Map pathParams = new HashMap<>(); @@ -120,6 +122,12 @@ public Http1ClientRequest header(HeaderValue header) { return this; } + @Override + public Http1ClientRequest headers(Function> headersConsumer) { + this.explicitHeaders = headersConsumer.apply(ClientRequestHeaders.create(explicitHeaders)); + return this; + } + @Override public Http1ClientRequest pathParam(String name, String value) { pathParams.put(name, value); @@ -164,7 +172,7 @@ public Http1ClientResponse submit(Object entity) { entityBytes = entityBytes(entity, headers); } - headers.setIfAbsent(Header.create(Header.CONTENT_LENGTH, String.valueOf(entityBytes.length))); + headers.set(Header.create(Header.CONTENT_LENGTH, entityBytes.length)); writeHeaders(headers, writeBuffer); if (entityBytes.length > 0) { From 1b76e3959a0d180f0bd04e373fa58ebd23ca4b0e Mon Sep 17 00:00:00 2001 From: Tomas Langer Date: Thu, 12 Jan 2023 17:18:23 +0100 Subject: [PATCH 3/4] Checkstyle fix. --- .../java/io/helidon/nima/webclient/http1/ClientRequestImpl.java | 1 - 1 file changed, 1 deletion(-) diff --git a/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/http1/ClientRequestImpl.java b/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/http1/ClientRequestImpl.java index a19e682c6d3..21959ea38d5 100644 --- a/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/http1/ClientRequestImpl.java +++ b/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/http1/ClientRequestImpl.java @@ -26,7 +26,6 @@ import java.util.Queue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedDeque; -import java.util.function.Consumer; import java.util.function.Function; import io.helidon.common.GenericType; From e68e20e1e4ec5d821de98fd62e74378980dca6cf Mon Sep 17 00:00:00 2001 From: Tomas Langer Date: Thu, 12 Jan 2023 17:24:45 +0100 Subject: [PATCH 4/4] Checkstyle fix. --- .../src/main/java/io/helidon/nima/webclient/ClientRequest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/ClientRequest.java b/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/ClientRequest.java index 60873c7502e..d871e573058 100644 --- a/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/ClientRequest.java +++ b/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/ClientRequest.java @@ -19,7 +19,6 @@ import java.io.IOException; import java.io.OutputStream; import java.net.URI; -import java.util.function.Consumer; import java.util.function.Function; import io.helidon.common.http.ClientRequestHeaders;