Giter VIP home page Giter VIP logo

quarkus-http's Introduction

Quarkus HTTP

Version GitHub Actions Status

A Vert.x based Servlet implementation.

Release

# Bump version and create the tag
mvn release:prepare -Prelease -DskipTests -Darguments=-DskipTests
# Build the tag and push to OSSRH
mvn release:perform -Prelease -DskipTests -Darguments=-DskipTests

The staging repository is automatically closed. The sync with Maven Central should take ~30 minutes.

quarkus-http's People

Contributors

andreipet avatar billoneil avatar carterkozak avatar cescoffier avatar chrisruffalo avatar ctomc avatar darranl avatar dependabot[bot] avatar dmlloyd avatar dreis2211 avatar ecki avatar efraimgentil avatar elopteryx avatar fl4via avatar frapex avatar gastaldi avatar golovnin avatar gsmet avatar jaikiran avatar jharting avatar jstourac avatar msfm avatar n1hility avatar pferraro avatar ppalaga avatar rhusar avatar ropalka avatar rovanion avatar stuartwdouglas avatar tomashofman avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

quarkus-http's Issues

The left-most IP address from X-Forwarded-For is not the most recent one

At https://github.com/quarkusio/quarkus-http/blob/main/core/src/main/java/io/undertow/server/handlers/ProxyPeerAddressHandler.java#L118, the following method extract the left-most IP address in case X-Forwarded-For contains a comma-separated list of addresses:

    private String mostRecent(String header) {
        int index = header.indexOf(',');
        if (index == -1) {
            return header;
        } else {
            return header.substring(0, index);
        }
    }

Based on the method name (mostRecent), my understanding is that it's actually the right-most address that should be used in this case.
Judging from information contained in the following links, the X-Forwarded-For header is a real hornet's nest:

This code is obviously not going to solve the complexity around this header, but at least it should return the actually most recent address in the path.

For the record, I ran into this while trying to get Keycloak display the IP address of HTTP clients, when sitting behind Cloudflare.
In this case, Cloudflare guarantees that the right-most value in X-Forwarded-For can be trusted as they append the origin IP address at the end of the list (https://developers.cloudflare.com/fundamentals/reference/http-request-headers/#x-forwarded-for).

Classes can't implement multiple Decoder/Encoder interfaces

When implementing a class like this:

public class UuidDecoder implements Decoder.TextStream<UUID>, Decoder, Decoder.Binary<UUID>, Decoder.Text<UUID> {
    public UuidDecoder() {
        System.out.println("OK!");
    }

    @Override
    public void init(EndpointConfig config) {

    }

    @Override
    public void destroy() {

    }

    @Override
    public UUID decode(Reader reader) throws DecodeException, IOException {
        return UUID.fromString(CharStreams.toString(reader));
    }

    @Override
    public UUID decode(ByteBuffer bytes) throws DecodeException {
        return UUID.fromString(new String(bytes.array()));
    }

    @Override
    public boolean willDecode(ByteBuffer bytes) {
        try {
            UUID.fromString(new String(bytes.array()));
            return true;
        } catch (IllegalArgumentException e) {
            return false;
        }
    }

    @Override
    public UUID decode(String s) throws DecodeException {
        return UUID.fromString(s);
    }

    @Override
    public boolean willDecode(String s) {
        try {
            UUID.fromString(s);
            return true;
        } catch (IllegalArgumentException e) {
            return false;
        }
    }
}

And using it like this:

@ServerEndpoint(value = "/api/ws/search/{id}", decoders = UuidDecoder.class)
public class SearchResource {
}

Only the binary encoder/decoder is registered, since EncodingFactory checks for interface implementations using else-if.

See https://stackoverflow.com/questions/60134388/how-to-use-custom-encoder-and-decoder-in-quarkus

I'll submit a PR to fix this.

Encoders/Decoders are ignored

When implementing a class like this:

public class UuidDecoder implements Decoder.Text<UUID> {
    public UuidDecoder() {
        System.out.println("OK!");
    }

    @Override
    public void init(EndpointConfig config) {

    }

    @Override
    public void destroy() {

    }

    @Override
    public UUID decode(String s) throws DecodeException {
        return UUID.fromString(s);
    }

    @Override
    public boolean willDecode(String s) {
        try {
            UUID.fromString(s);
            return true;
        } catch (IllegalArgumentException e) {
            return false;
        }
    }
}

And using it like this:

@ServerEndpoint(value = "/api/ws/search/{id}", decoders = UuidDecoder.class)
public class SearchResource {
}

The decoder isn't registered and the application fails with:

14:14:58,113 ERROR [io.qua.dev.DevModeMain] Failed to start Quarkus: java.lang.ExceptionInInitializerError
    at java.base/java.lang.J9VMInternals.ensureError(J9VMInternals.java:193)
    at java.base/java.lang.J9VMInternals.recordInitializationFailure(J9VMInternals.java:182)
    at java.base/java.lang.Class.forNameImpl(Native Method)
    at java.base/java.lang.Class.forName(Class.java:417)
    at io.quarkus.runner.RuntimeRunner.run(RuntimeRunner.java:153)
    at io.quarkus.dev.DevModeMain.doStart(DevModeMain.java:178)
    at io.quarkus.dev.DevModeMain.start(DevModeMain.java:96)
    at io.quarkus.dev.DevModeMain.main(DevModeMain.java:67)
Caused by: java.lang.RuntimeException: Failed to start quarkus
    at io.quarkus.runner.ApplicationImpl.<clinit>(ApplicationImpl.zig:390)
    ... 6 more
Caused by: java.lang.RuntimeException: java.lang.RuntimeException: javax.websocket.DeploymentException: UT003028: Could not find decoder for type class java.util.UUID on method public void org.siretch.kafka.entrypoint.SearchResource.onOpen(javax.websocket.Session,java.util.UUID)
    at io.quarkus.undertow.runtime.UndertowDeploymentRecorder.bootServletContainer(UndertowDeploymentRecorder.java:445)
    at io.quarkus.deployment.steps.UndertowBuildStep$build32.deploy_0(UndertowBuildStep$build32.zig:171)
    at io.quarkus.deployment.steps.UndertowBuildStep$build32.deploy(UndertowBuildStep$build32.zig:196)
    at io.quarkus.runner.ApplicationImpl.<clinit>(ApplicationImpl.zig:376)
    ... 6 more
Caused by: java.lang.RuntimeException: javax.websocket.DeploymentException: UT003028: Could not find decoder for type class java.util.UUID on method public void org.siretch.kafka.entrypoint.SearchResource.onOpen(javax.websocket.Session,java.util.UUID)
    at io.undertow.websockets.jsr.Bootstrap.handleDeployment(Bootstrap.java:101)
    at io.undertow.servlet.core.DeploymentManagerImpl.handleExtensions(DeploymentManagerImpl.java:278)
    at io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:155)
    at io.quarkus.undertow.runtime.UndertowDeploymentRecorder.bootServletContainer(UndertowDeploymentRecorder.java:434)
    ... 9 more
Caused by: javax.websocket.DeploymentException: UT003028: Could not find decoder for type class java.util.UUID on method public void org.siretch.kafka.entrypoint.SearchResource.onOpen(javax.websocket.Session,java.util.UUID)
    at io.undertow.websockets.jsr.annotated.AnnotatedEndpointFactory$BoundPathParameters.<init>(AnnotatedEndpointFactory.java:399)
    at io.undertow.websockets.jsr.annotated.AnnotatedEndpointFactory.createBoundPathParameters(AnnotatedEndpointFactory.java:258)
    at io.undertow.websockets.jsr.annotated.AnnotatedEndpointFactory.create(AnnotatedEndpointFactory.java:100)
    at io.undertow.websockets.jsr.ServerWebSocketContainer.addEndpointInternal(ServerWebSocketContainer.java:681)
    at io.undertow.websockets.jsr.ServerWebSocketContainer.addEndpoint(ServerWebSocketContainer.java:654)
    at io.undertow.websockets.jsr.Bootstrap.handleDeployment(Bootstrap.java:95)
    ... 12 more

See https://stackoverflow.com/questions/60134388/how-to-use-custom-encoder-and-decoder-in-quarkus

I'll submit a PR to fix this.

WebSocket - No Pong for Ping

Describe the bug
Server (or Client) sends WebSocket Ping. Other end should Pong automatically but does not.

This prevents proper management of slow/dead consumers etc.

Quarkus 1.4.2

To Reproduce
Modified websockets-quickstart attached.

websockets-quickstart.zip

Too Many Vert.x Instances?

The Vert.x Undertow Engine creates its own Vert.x instance using Vertx.vertx().
The Vert.x Quarkus extension creates another one.

That's 2, we need one.

`getUserPrincipal` is not implemented on VertxWebSocketHttpExchange

Related to the discussion we are having on OIDC authentication for websockets doesn't work in 1.13.*
, getUserPrincipal is not yet implemented which is a useful functionality. This is the comment I left originally there:

Playing around with the code, inside VertxWebSocketHttpExchange we do have access to the original RoutingContext in the class attribute exchange.

image

Upon closer inspection, I can see the principal is correctly populated inside the exchange.data() map like we can see below:

image

Is it safe to assume that we can return directly that object in method getUserPrincipal? Or is there any other implication I'm not taking into account (which will be probably)?

Something like:

image

If needed I can prepare the PR with proper guidance.

[Websocket] Url without port is not supported

I use OpenShift. URLs in routes do not have ports. They look like https://domain-a.corp.org. So in java URL object port is -1. But netty does not support this .

Caused by: java.lang.IllegalArgumentException: port out of range:-1
        at java.net.InetSocketAddress.checkPort(InetSocketAddress.java:143)
        at java.net.InetSocketAddress.createUnresolved(InetSocketAddress.java:254)
        at io.netty.bootstrap.Bootstrap.connect(Bootstrap.java:123)
        at io.undertow.websockets.jsr.WebsocketConnectionBuilder.connect(WebsocketConnectionBuilder.java:202)
        at io.undertow.websockets.jsr.ServerWebSocketContainer.connectToServerInternal(ServerWebSocketContainer.java:543)
        at io.undertow.websockets.jsr.ServerWebSocketContainer.connectToServerInternal(ServerWebSocketContainer.java:520)
        at io.undertow.websockets.jsr.ServerWebSocketContainer.connectToServer(ServerWebSocketContainer.java:279)
        at mapackage.TestWebSocketService.connect(TestWebSocketService.java:32)

I found some mapping in undertow(original):

https://github.com/undertow-io/undertow/blob/master/core/src/main/java/io/undertow/websockets/client/WebSocketClient.java#L218

But it seems in quarkus there is no similar code

SameSite=None cookie attribute is not supported

Since undertow version 2.1.0.Final (feature UNDERTOW-1600), Undertow supports SameSite=None attributes in cookies, through the SameSiteCookieHandler.
Unfortunately, it seems that quarkus-http has been left behind with undertow's latest developments.

Are there any plans to catch up with undertow's latest versions, or otherwise is there any other way to enable the SameSite=None cookie attribute with Quarkus when using Undertow?

Ability to set MAX_PARAMETERS in Undertow

When using Undertow, a request with more than 1,000 parameters triggers a io.undertow.util.ParameterLimitException. While that's a reasonable default, I have a need to configure it. (A JSF application I am porting to Quarkus via the MyFaces Quarkus extension generates very large requests.)

Undertow provides a way of providing it with an UndertowOptionMap, one key of which is MAX_PARAMETERS. It would be nice if there were a way of setting it through application.properties.

451 Status Code

Is it possible in this time to add a 451 status code? here's my scenario.

Scenario:

As a consultant that create an application for a legal system, we may want to submit a status code of 451 for API calls that isn't allowed at this time due to a governance policy/restriction. For a better status code, I'm proposing this one.

I'm seeing that a 401 Unauthorized doesn't seem right for my use-case. Let me know for any suggestion.

NOTE: Seeing that this is supported in Spring Framework, existing Legal-based APIs that want to migrate to Quarkus could have a breaking change or will use another inappropriate code for this use-case.

SNI Support in Quarkus's Undertow websocket

Hello, I am not a specialist in this question, but It seemed I have a problem because Quarkus does not support SNI extension in SSL. Although I tested it with HTTP rest-client and there were no problems.

Details:
*I have a the same problem, the same message and the same difference between rest's logs and websocket's logs:

*** ClientHello, TLSv1.2
RandomCookie:  GMT: 1571238552 bytes = { 125, 241, 169, 6, 39, 103, 208, 112, 16, 73, 146, 115, 185, 122, 155, 35, 69, 225, 103, 209, 161, 159, 5, 137, 54, 165, 78, 99 }
Session ID:  {}
Cipher Suites: [TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
Compression Methods:  { 0 }
Extension elliptic_curves, curve names: {secp256r1, secp384r1, secp521r1, sect283k1, sect283r1, sect409k1, sect409r1, sect571k1, sect571r1, secp256k1}
Extension ec_point_formats, formats: [uncompressed]
Extension signature_algorithms, signature_algorithms: SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, SHA256withECDSA, SHA256withRSA, SHA256withDSA, SHA1withECDSA, SHA1withRSA, SHA1withDSA
***

vs

*** ClientHello, TLSv1.2
RandomCookie:  GMT: 1571238202 bytes = { 191, 255, 75, 40, 82, 20, 198, 108, 27, 89, 101, 152, 184, 97, 12, 203, 201, 86, 244, 33, 33, 22, 183, 124, 59, 107, 104, 109 }
Session ID:  {}
Cipher Suites: [TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
Compression Methods:  { 0 }
Extension elliptic_curves, curve names: {secp256r1, secp384r1, secp521r1, sect283k1, sect283r1, sect409k1, sect409r1, sect571k1, sect571r1, secp256k1}
Extension ec_point_formats, formats: [uncompressed]
Extension signature_algorithms, signature_algorithms: SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, SHA256withECDSA, SHA256withRSA, SHA256withDSA, SHA1withECDSA, SHA1withRSA, SHA1withDSA
Extension server_name, server_name: [type=host_name (0), value=myhost.com]
***

I decided to find where this extension is set in vertex (because HTTP rest-client works):

But in websockets-jsr I can't see any mentions of SNI and SSLEngine is created without host and port:

But I decided to check how things are going here: https://github.com/undertow-io/undertow/
And found that they suggest some SNISSLContextSpi

Could you help with an answer if it is a bug, or not?

Websocket connection kept alive when Netty channel was closed by responding to pings

Hello,

in the Websocket Undertow adoption when an underlying Netty channel is (half) closed it is still possible to receive Websocket messages.
This is a known problem (see https://issues.redhat.com/browse/UNDERTOW-617) and the solution for messages passed on is to drop them in this case (fixed in f145e9c).

However Ping messages are still responded to (See https://github.com/quarkusio/quarkus-http/blob/main/websocket/core/src/main/java/io/undertow/websockets/FrameHandler.java#L139). In this case the Websocket connection is kept alive by the response but the implementation here drops other messages leading to a broken inconsistent state.

To be consistent pings should not be responded to as well.
I would propose a similar private handler method, that uses the same drop message mechanism.
This way the behavior is consistent and a client may even detect broken connections.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.