sunng87 / ring-jetty9-adapter

An enhanced version of jetty adapter for ring, with additional features like websockets, http/2 and http/3

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

example-http2 doesn't work

hukka opened this issue · comments

$ lein with-profile default,example-http2 run
Reflection warning, clojure/tools/nrepl/middleware/load_file.clj:87:38 - reference to field recv on java.lang.Object can't be resolved.
Reflection warning, clojure/tools/nrepl/middleware/load_file.clj:88:46 - call to method recv on java.lang.Object can't be resolved (no such method).
Reflection warning, clojure/tools/nrepl/middleware/load_file.clj:93:27 - call to method send on java.lang.Object can't be resolved (no such method).
Reflection warning, clojure/tools/nrepl/server.clj:142:21 - call to java.net.InetSocketAddress ctor can't be resolved.
Reflection warning, /tmp/form-init3411137679930513902.clj:1:1027 - call to static method invokeStaticMethod on clojure.lang.Reflector can't be resolved (argument types: unknown, java.lang.String, unknown).
Reflection warning, ring/adapter/jetty9/websocket.clj:170:17 - reference to field getWebSocketFactory can't be resolved.
Reflection warning, ring/adapter/jetty9/websocket.clj:171:13 - call to method isUpgradeRequest can't be resolved (target class is unknown).
Reflection warning, ring/adapter/jetty9/websocket.clj:172:15 - call to method acceptWebSocket can't be resolved (target class is unknown).
Reflection warning, ring/adapter/jetty9/websocket.clj:174:19 - reference to field isCommitted can't be resolved.
Reflection warning, ring/adapter/jetty9/websocket.clj:176:11 - call to method handle can't be resolved (target class is unknown).
2018-07-23 10:39:08.341:INFO::main: Logging initialized @2629ms to org.eclipse.jetty.util.log.StdErrLog
Reflection warning, ring/adapter/jetty9.clj:60:35 - reference to field startAsync can't be resolved.
Reflection warning, ring/adapter/jetty9.clj:67:12 - call to method sendError can't be resolved (target class is unknown).
Reflection warning, ring/adapter/jetty9.clj:125:11 - call to org.eclipse.jetty.server.ServerConnector ctor can't be resolved.
Reflection warning, ring/adapter/jetty9.clj:137:11 - call to org.eclipse.jetty.server.ServerConnector ctor can't be resolved.
Exception in thread "main" java.lang.IllegalStateException: No Server ALPNProcessors!, compiling:(/tmp/form-init3411137679930513902.clj:1:73)
	at clojure.lang.Compiler.load(Compiler.java:7526)
	at clojure.lang.Compiler.loadFile(Compiler.java:7452)
	at clojure.main$load_script.invokeStatic(main.clj:278)
	at clojure.main$init_opt.invokeStatic(main.clj:280)
	at clojure.main$init_opt.invoke(main.clj:280)
	at clojure.main$initialize.invokeStatic(main.clj:311)
	at clojure.main$null_opt.invokeStatic(main.clj:345)
	at clojure.main$null_opt.invoke(main.clj:342)
	at clojure.main$main.invokeStatic(main.clj:424)
	at clojure.main$main.doInvoke(main.clj:387)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.lang.Var.applyTo(Var.java:702)
	at clojure.main.main(main.java:37)
Caused by: java.lang.IllegalStateException: No Server ALPNProcessors!
	at org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory.<init>(ALPNServerConnectionFactory.java:53)
	at org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory.<init>(ALPNServerConnectionFactory.java:46)
	at ring.adapter.jetty9$https_connector.invokeStatic(jetty9.clj:123)
	at ring.adapter.jetty9$https_connector.invoke(jetty9.clj:121)
	at ring.adapter.jetty9$create_server.invokeStatic(jetty9.clj:170)
	at ring.adapter.jetty9$create_server.invoke(jetty9.clj:144)
	at ring.adapter.jetty9$run_jetty.invokeStatic(jetty9.clj:219)
	at ring.adapter.jetty9$run_jetty.invoke(jetty9.clj:176)
	at rj9a.http2$_main.invokeStatic(http2.clj:8)
	at rj9a.http2$_main.doInvoke(http2.clj:7)
	at clojure.lang.RestFn.invoke(RestFn.java:397)
	at clojure.lang.Var.invoke(Var.java:377)
	at user$eval3112.invokeStatic(form-init3411137679930513902.clj:1)
	at user$eval3112.invoke(form-init3411137679930513902.clj:1)
	at clojure.lang.Compiler.eval(Compiler.java:7062)
	at clojure.lang.Compiler.eval(Compiler.java:7052)
	at clojure.lang.Compiler.load(Compiler.java:7514)
	... 12 more
Error encountered performing task 'run' with profile(s): 'base,system,user,provided,dev,example-http2'
Suppressed exit
$ java -version
openjdk version "1.8.0_171"
OpenJDK Runtime Environment (build 1.8.0_171-8u171-b11-0ubuntu0.18.04.1-b11)
OpenJDK 64-Bit Server VM (build 25.171-b11, mixed mode)

Updating the alpn-boot to match the exact JDK version according to https://www.eclipse.org/jetty/documentation/9.4.x/alpn-chapter.html doesn't help either:

$ grep alpn-boot project.clj 
                             :boot-dependencies [[org.mortbay.jetty.alpn/alpn-boot "8.1.12.v20180117"

So far I haven't managed to get Jetty working via jetty9 no matter what I put in the project.clj (I've tried using conscrypt too), so a working example would be great!

To get jetty start I've needed either org.eclipse.jetty/jetty-alpn-openjdk-server or both org.eclipse.jetty/jetty-alpn-conscrypt-server and org.conscrypt/conscrypt-openjdk-uber. Then jetty claims it's starting h2 on the TLS port.

2018-07-23 10:48:14.145:INFO:oejs.AbstractConnector:main: Started ServerConnector@6f96dd64{SSL,[ssl, http/1.1, alpn, h2]}{0.0.0.0:5443}
2018-07-23 10:48:14.146:INFO:oejs.AbstractConnector:main: Started ServerConnector@4d7cac24{HTTP/1.1,[http/1.1, h2c]}{0.0.0.0:5000}
2018-07-23 10:48:14.146:INFO:oejs.Server:main: Started @2742ms

But only the h2 on the unencrypted port works (with curl). Neither curl nor chrome can get the ALPN work
with my jetty config (though they work with google, so the client side should be ok).

$ curl -v -I --http2 http://localhost:5000
* Rebuilt URL to: http://localhost:5000/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 5000 (#0)
> HEAD / HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.58.0
> Accept: */*
> Connection: Upgrade, HTTP2-Settings
> Upgrade: h2c
> HTTP2-Settings: AAMAAABkAARAAAAAAAIAAAAA
> 
< HTTP/1.1 101 Switching Protocols
HTTP/1.1 101 Switching Protocols
* Received 101
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0

* Connection state changed (MAX_CONCURRENT_STREAMS updated)!
< HTTP/2 200 
HTTP/2 200 
< server: Jetty(9.4.11.v20180605)
server: Jetty(9.4.11.v20180605)

< 
* Connection #0 to host localhost left intact

$ curl --insecure -v -I --http2 https://localhost:5443
* Rebuilt URL to: https://localhost:5443/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 5443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-SHA384
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: C=Unknown; ST=Unknown; L=Unknown; O=Unknown; OU=Unknown; CN=Unknown
*  start date: Jul 15 13:45:28 2015 GMT
*  expire date: Oct 13 13:45:28 2015 GMT
*  issuer: C=Unknown; ST=Unknown; L=Unknown; O=Unknown; OU=Unknown; CN=Unknown
*  SSL certificate verify result: self signed certificate (18), continuing anyway.
> HEAD / HTTP/1.1
> Host: localhost:5443
> User-Agent: curl/7.58.0
> Accept: */*
> 
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Content-Length: 8
Content-Length: 8
< Server: Jetty(9.4.11.v20180605)
Server: Jetty(9.4.11.v20180605)

< 
* Connection #0 to host localhost left intact

Changing the order of protocols under ALPN

(let [secure-connection-factory [(ALPNServerConnectionFactory. "h2,h2-17,h2-14,http/1.1")
                                   (HTTP2ServerConnectionFactory. http-configuration)
                                   (HttpConnectionFactory. http-configuration)]]

seems to change the behaviour

2018-07-23 11:11:22.071:INFO:oejs.AbstractConnector:main: Started ServerConnector@20a3e10c{SSL,[ssl, alpn, h2, http/1.1]}{0.0.0.0:5443}
2018-07-23 11:11:22.071:INFO:oejs.AbstractConnector:main: Started ServerConnector@426c0486{HTTP/1.1,[http/1.1]}{0.0.0.0:5000}

(note the changed order of protocols, which matches what jetty's start.jar gives when using the jetty uberjar.

However curl still doesn't work, though the error now seems to imply that it wants http/1.1 (this doesn't happen with jetty uberjar):

$ curl --insecure -vvvv -I --http2 https://localhost:5443
* Rebuilt URL to: https://localhost:5443/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 5443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-SHA384
* ALPN, server accepted to use http/1.1
* Server certificate:
*  subject: C=Unknown; ST=Unknown; L=Unknown; O=Unknown; OU=Unknown; CN=Unknown
*  start date: Jul 15 13:45:28 2015 GMT
*  expire date: Oct 13 13:45:28 2015 GMT
*  issuer: C=Unknown; ST=Unknown; L=Unknown; O=Unknown; OU=Unknown; CN=Unknown
*  SSL certificate verify result: self signed certificate (18), continuing anyway.
> HEAD / HTTP/1.1
> Host: localhost:5443
> User-Agent: curl/7.58.0
> Accept: */*
> 
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Content-Length: 8
Content-Length: 8
< Server: Jetty(9.4.11.v20180605)
Server: Jetty(9.4.11.v20180605)

< 
* Connection #0 to host localhost left intact

After running jetty with org.eclipse.jetty.alpn.LEVEL=DEBUG,
I found this nugget: Protocol h2 not acceptable to HTTP2ServerConnectionFactory TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384.

So the ssl module is negotiating a cipher, that won't work with the h2 module!

Forcing a suitable cipher from client makes everything work:

$ curl --insecure -vvvv -I --ciphers ECDHE-RSA-AES256-GCM-SHA384 --http2 https://localhost:5443
* Rebuilt URL to: https://localhost:5443/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 5443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: ECDHE-RSA-AES256-GCM-SHA384
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server accepted to use h2
* Server certificate:
*  subject: C=Unknown; ST=Unknown; L=Unknown; O=Unknown; OU=Unknown; CN=Unknown
*  start date: Jul 23 08:51:14 2018 GMT
*  expire date: Jul 18 08:51:14 2019 GMT
*  issuer: C=Unknown; ST=Unknown; L=Unknown; O=Unknown; OU=Unknown; CN=Unknown
*  SSL certificate verify result: self signed certificate (18), continuing anyway.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x55650f46c8e0)
> HEAD / HTTP/2
> Host: localhost:5443
> User-Agent: curl/7.58.0
> Accept: */*
> 
* Connection state changed (MAX_CONCURRENT_STREAMS updated)!
< HTTP/2 200 
HTTP/2 200 
< server: Jetty(9.4.11.v20180605)
server: Jetty(9.4.11.v20180605)

< 
* Connection #0 to host localhost left intact

I'll see if I can force this from Jetty's end. Though for now I have no idea which ciphers it accepts...

I tried hardcoding the blacklist, which works, and of course is tedious and prone to break whenever the list is updated. Unfortunately the blacklist is private. But looking at the code, I think (based on no documentation whatsoever) that this can be solved by

(let [context (SslContextFactory.)]
    (.setCipherComparator context HTTP2Cipher/COMPARATOR)

I'll make a PR in a moment.