[ 
https://issues.apache.org/jira/browse/CXF-8936?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Andriy Redko updated CXF-8936:
------------------------------
    Fix Version/s:     (was: 3.5.8)

> Fix h2 protocol negotiation in Jetty Transport
> ----------------------------------------------
>
>                 Key: CXF-8936
>                 URL: https://issues.apache.org/jira/browse/CXF-8936
>             Project: CXF
>          Issue Type: Bug
>          Components: Transports
>    Affects Versions: 4.0.3
>         Environment: CXF latest and CXF 4.0.3 on Java 11 and 17 both show 
> this issue.
>            Reporter: Huw Ayling-Miller
>            Priority: Minor
>              Labels: Jetty
>             Fix For: 3.6.3, 4.0.4
>
>         Attachments: output-jetty-original.txt, output-netty.txt
>
>
> h1. Summary 
> I have been trying to update one of our apps using the Jetty backend to use 
> http2. While doing this I've noticed that the protocol negotiation is in the 
> wrong order which results in http/1.1 always being preferred where the client 
> includes this in the ALPN handshake. This means that both browsers and cURL 
> will never successfully negotiate h2/http2.
> ---
> h1. The problem
> The issue can be shown using curl.
> {{curl -ikv https://localhost:9000}}
> I've attached the full output of this command when running curl against the 
> CXF sample {{jax_rs_basic_http2_jetty}}.
> The important lines are:
> {code}
> * ALPN: offers h2,http/1.1
> * ALPN: server accepted http/1.1
> {code}
> Compare this with the attached curl output from the CXF sample 
> {{jax_rs_basic_http2_netty}}.
> The important lines here are:
> {code}
> * ALPN: offers h2,http/1.1
> * ALPN: server accepted h2
> {code}
> ---
> h1. The solution
> The ALPN takes place within {{ALPNServerConnection}}, which is part of the 
> {{jetty-alpn-server}} module.
> {code:java}
>         // RFC 7301 states that the server picks the protocol
>         // that it prefers that is also supported by the client.
>         for (String serverProtocol : serverProtocols)
>         {
>             if (clientProtocols.contains(serverProtocol))
>             {
>                 ConnectionFactory factory = 
> getConnector().getConnectionFactory(serverProtocol);
>                 if (factory instanceof CipherDiscriminator && 
> !((CipherDiscriminator)factory).isAcceptable(serverProtocol, tlsProtocol, 
> tlsCipher))
>                 {
>                     if (LOG.isDebugEnabled())
>                         LOG.debug("Protocol {} not acceptable to {} for {}/{} 
> on {}", serverProtocol, factory, tlsProtocol, tlsCipher, getEndPoint());
>                     continue;
>                 }
>                 negotiated = serverProtocol;
>                 break;
>             }
>         }
> {code}
> As the code states, the server is responsible for picking the protocol and 
> Jetty picks the first match in the server's list. From the log output of the 
> same app the first in the list is http/1.1
> {code}
> INFO: Started ServerConnector@11eadcba\{ssl, (http/1.1, ssl, alpn, 
> h2)}{0.0.0.0:9000}}
> {code}
> Therefore the solution is to ensure that when h2 is enabled inside 
> {{JettyHTTPServerEngine}} -> {{createConnectorJetty}}, the 
> HTTP2ServerConnectionFactory should always be added at the start of the list.
> With this change, curl then successfully negotiates with h2.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to