Search in sources :

Example 26 with Http

use of io.helidon.common.http.Http in project helidon by oracle.

the class MultiPortTest method compositeFromConfig.

@Test
public void compositeFromConfig() throws Exception {
    Config config = Config.create(ConfigSources.classpath("multiport/application.yaml"));
    webServer = WebServer.builder().host("localhost").routing(Routing.builder().get("/", (req, res) -> res.send("Plain!"))).config(config.get("webserver")).addNamedRouting("secured", Routing.builder().get("/", (req, res) -> res.send("Secured!"))).build();
    webServer.start().toCompletableFuture().join();
    assertResponse("http", webServer.port(), "/", is("Plain!"));
    assertResponse("https", webServer.port("secured"), "/", is("Secured!"));
}
Also used : Assertions.fail(org.junit.jupiter.api.Assertions.fail) BeforeEach(org.junit.jupiter.api.BeforeEach) WebClientTls(io.helidon.webclient.WebClientTls) WebClient(io.helidon.webclient.WebClient) Config(io.helidon.config.Config) Resource(io.helidon.common.configurable.Resource) AllOf(org.hamcrest.core.AllOf) Test(org.junit.jupiter.api.Test) AfterEach(org.junit.jupiter.api.AfterEach) StringContains(org.hamcrest.core.StringContains) BeforeAll(org.junit.jupiter.api.BeforeAll) KeyConfig(io.helidon.common.pki.KeyConfig) Matcher(org.hamcrest.Matcher) Is.is(org.hamcrest.core.Is.is) MatcherAssert.assertThat(org.hamcrest.MatcherAssert.assertThat) Http(io.helidon.common.http.Http) ConfigSources(io.helidon.config.ConfigSources) Config(io.helidon.config.Config) KeyConfig(io.helidon.common.pki.KeyConfig) Test(org.junit.jupiter.api.Test)

Example 27 with Http

use of io.helidon.common.http.Http in project helidon by oracle.

the class BareResponseImpl method writeStatusAndHeaders.

@Override
public void writeStatusAndHeaders(Http.ResponseStatus status, Map<String, List<String>> headers) {
    Objects.requireNonNull(status, "Parameter 'statusCode' was null!");
    if (!statusHeadersSent.compareAndSet(false, true)) {
        throw new IllegalStateException("Status and headers were already sent");
    }
    HttpResponseStatus nettyStatus;
    if (status instanceof Http.Status || status.reasonPhrase() == null) {
        // default reason phrase
        nettyStatus = valueOf(status.code());
    } else {
        // custom reason phrase
        nettyStatus = valueOf(status.code(), status.reasonPhrase());
    }
    response = new DefaultHttpResponse(HTTP_1_1, nettyStatus);
    for (Map.Entry<String, List<String>> headerEntry : headers.entrySet()) {
        response.headers().add(headerEntry.getKey(), headerEntry.getValue());
    }
    // Copy HTTP/2 headers to response for correlation (streamId)
    requestHeaders.names().stream().filter(header -> header.startsWith(HTTP_2_HEADER_PREFIX)).forEach(header -> response.headers().add(header, requestHeaders.get(header)));
    // Check if WebSocket upgrade
    boolean isUpgrade = isWebSocketUpgrade(status, headers);
    if (isUpgrade) {
        isWebSocketUpgrade = true;
    } else {
        // Set chunked if length not set, may switch to length later
        boolean lengthSet = HttpUtil.isContentLengthSet(response);
        if (!lengthSet) {
            lengthOptimization = status.code() == Http.Status.OK_200.code() && !HttpUtil.isTransferEncodingChunked(response) && !isSseEventStream(headers);
            HttpUtil.setTransferEncodingChunked(response, true);
        }
    }
    // if response Connection header is set explicitly to close, we can ignore the following
    if (!keepAlive || HttpHeaderValues.CLOSE.contentEqualsIgnoreCase(response.headers().get(HttpHeaderNames.CONNECTION))) {
        response.headers().remove(HttpHeaderNames.CONNECTION);
        originalEntityAnalyzed.complete(ChannelFutureListener.CLOSE);
    } else {
        if (!requestContext.requestCompleted()) {
            LOGGER.finer(() -> log("Request content not fully read with keep-alive: true", channel));
            if (!isWebSocketUpgrade) {
                if (requestContext.isDataRequested()) {
                    // there are pending requests, we have emitted some data and request was not explicitly canceled
                    // this is a bug in code, where entity is requested and not fully processed
                    // throwing an exception here is a breaking change (also this may be an intermittent problem
                    // as it may depend on thread race)
                    HttpRequest request = requestContext.request();
                    LOGGER.warning("Entity was requested and not fully consumed before a response is sent. " + "This is not supported. Connection will be closed. Please fix your route for " + request.method() + " " + request.uri());
                    // let's close this connection, as it is in an unexpected state
                    response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE);
                    originalEntityAnalyzed.complete(ChannelFutureListener.CLOSE);
                } else {
                    // we want to consume the entity and keep alive
                    // entity must be consumed here, so we do not close connection in forwarding handler
                    // because of unconsumed payload (the following code will only succeed if there is no subscriber)
                    requestContext.publisher().forEach(DataChunk::release).onComplete(() -> {
                        response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
                        originalEntityAnalyzed.complete(ChannelFutureListener.CLOSE_ON_FAILURE);
                    }).onError(t -> {
                        response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE);
                        originalEntityAnalyzed.complete(ChannelFutureListener.CLOSE);
                    }).ignoreElement();
                }
            }
        } else if (!headers.containsKey(HttpHeaderNames.CONNECTION.toString())) {
            response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
        }
    }
    // Content length optimization attempt
    if (!lengthOptimization) {
        requestEntityAnalyzed = requestEntityAnalyzed.thenApply(listener -> {
            LOGGER.fine(() -> log("Writing headers %s", status));
            requestContext.runInScope(() -> orderedWrite(this::initWriteResponse));
            return listener;
        });
    }
}
Also used : Arrays(java.util.Arrays) HttpHeaders(io.netty.handler.codec.http.HttpHeaders) DataChunk(io.helidon.common.http.DataChunk) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) CompletableFuture(java.util.concurrent.CompletableFuture) ArrayList(java.util.ArrayList) Level(java.util.logging.Level) Unpooled(io.netty.buffer.Unpooled) LastHttpContent(io.netty.handler.codec.http.LastHttpContent) ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) ByteBuf(io.netty.buffer.ByteBuf) Flow(java.util.concurrent.Flow) Map(java.util.Map) ChannelFutureListener(io.netty.channel.ChannelFutureListener) Single(io.helidon.common.reactive.Single) HTTP_1_1(io.netty.handler.codec.http.HttpVersion.HTTP_1_1) Http(io.helidon.common.http.Http) HttpResponseStatus.valueOf(io.netty.handler.codec.http.HttpResponseStatus.valueOf) HttpRequest(io.netty.handler.codec.http.HttpRequest) HttpHeaderValues(io.netty.handler.codec.http.HttpHeaderValues) GenericFutureListener(io.netty.util.concurrent.GenericFutureListener) HttpResponseStatus(io.netty.handler.codec.http.HttpResponseStatus) Logger(java.util.logging.Logger) ChannelFuture(io.netty.channel.ChannelFuture) Objects(java.util.Objects) DefaultHttpContent(io.netty.handler.codec.http.DefaultHttpContent) List(java.util.List) DefaultLastHttpContent(io.netty.handler.codec.http.DefaultLastHttpContent) DefaultHttpResponse(io.netty.handler.codec.http.DefaultHttpResponse) HttpHeaderNames(io.netty.handler.codec.http.HttpHeaderNames) Future(io.netty.util.concurrent.Future) HttpUtil(io.netty.handler.codec.http.HttpUtil) HttpRequest(io.netty.handler.codec.http.HttpRequest) HttpResponseStatus(io.netty.handler.codec.http.HttpResponseStatus) DefaultHttpResponse(io.netty.handler.codec.http.DefaultHttpResponse) Http(io.helidon.common.http.Http) ArrayList(java.util.ArrayList) List(java.util.List) Map(java.util.Map)

Aggregations

Http (io.helidon.common.http.Http)27 WebClient (io.helidon.webclient.WebClient)16 DataChunk (io.helidon.common.http.DataChunk)12 Config (io.helidon.config.Config)12 WebClientResponse (io.helidon.webclient.WebClientResponse)12 Routing (io.helidon.webserver.Routing)11 WebServer (io.helidon.webserver.WebServer)10 Test (org.junit.jupiter.api.Test)10 MediaType (io.helidon.common.http.MediaType)9 Optional (java.util.Optional)9 Single (io.helidon.common.reactive.Single)8 WebClientRequestBuilder (io.helidon.webclient.WebClientRequestBuilder)8 Logger (java.util.logging.Logger)8 MatcherAssert.assertThat (org.hamcrest.MatcherAssert.assertThat)8 Json (jakarta.json.Json)7 JsonBuilderFactory (jakarta.json.JsonBuilderFactory)7 Collections (java.util.Collections)7 JsonpSupport (io.helidon.media.jsonp.JsonpSupport)6 SecurityContext (io.helidon.security.SecurityContext)6 JsonObject (jakarta.json.JsonObject)5