Jetty HTTP/2 client receive server push example
Asked Answered
D

2

6

Jetty's HTTP/2 client with server push support has been implemented in Jetty 9.3 RC (Link). However, I have not found any documentation or example code related to this. Could any one provide an example code for example to receive the pushed resource from this site : https://nghttp2.org (public server which has enabled http2 server push)

---UPDATE 1--- I have tried to test this file as sbordet has said. However, after executing this line

mvn compile exec:java

I ran onto this error

[INFO] --- exec-maven-plugin:1.4.0:java (default-cli) @ http2client ---
2015-05-05 01:52:47.808:INFO::com.example.Client.main(): Logging initialized @3096ms
[WARNING]
java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:293)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.util.concurrent.TimeoutException
    at org.eclipse.jetty.util.FuturePromise.get(FuturePromise.java:130)
    at com.example.Client.main(Client.java:55)
    ... 6 more

Here is my pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>http2client</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>http2client</name>
<url>http://maven.apache.org</url>
<dependencies>
    <dependency>
        <groupId>org.eclipse.jetty.http2</groupId>
        <artifactId>http2-client</artifactId>
        <version>9.3.0.M2</version>
    </dependency>
    <dependency>
        <groupId>org.mortbay.jetty.alpn</groupId>
        <artifactId>alpn-boot</artifactId>
        <version>8.1.3.v20150130</version>
        <scope>runtime</scope>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>exec-maven-plugin</artifactId>
            <version>1.4.0</version>
            <executions>
                <execution>
                    <goals>
                        <goal>java</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <mainClass>com.example.Client</mainClass>
            </configuration>
        </plugin>
    </plugins>
</build>

And here is my project directory

|-- pom.xml
|-- src
|   `-- main
|       `-- java
|           `-- com
|               `-- example
|                   `-- Client.java
`-- target
    |-- classes
    |   `-- com
    |       `-- example
    |           |-- Client$1.class
    |           `-- Client.class
    `-- maven-status
        `-- maven-compiler-plugin
            `-- compile
                `-- default-compile
                    |-- createdFiles.lst
                    `-- inputFiles.lst

---UPDATE 2---

Changed my pom.xml <build> tag to this: (explicitly use JDK 8 and add -Xbootclasspath to point to the alpn-boot.jar provided by Jetty). I am using Java 8 update 31

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>exec-maven-plugin</artifactId>
            <version>1.4.0</version>
            <executions>
                <execution>
                    <goals>
                        <goal>exec</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <executable>java</executable>
                <arguments>
                    <argument>-Xbootclasspath/p:/path/to/alpn-boot-8.1.3.v20150130.jar</argument>
                    <argument>-classpath</argument>
                    <classpath/>
                    <argument>com.example.Client</argument>
                </arguments>
            </configuration>
        </plugin>
    </plugins>
</build>

After I execute this command:

mvn clean compile exec:exec

I got this error when trying to connect to https://webtide.com/ (the default host in Client.java file)

[INFO] --- exec-maven-plugin:1.4.0:exec (default-cli) @ http2client ---
2015-05-05 13:19:25.499:INFO::main: Logging initialized @153ms
Exception in thread "main" java.util.concurrent.TimeoutException
    at org.eclipse.jetty.util.FuturePromise.get(FuturePromise.java:130)
    at com.example.Client.main(Client.java:55)

And this error when connecting to https://nghttp2.org/

[INFO] --- exec-maven-plugin:1.4.0:exec (default-cli) @ http2client ---
2015-05-05 13:29:12.106:INFO::main: Logging initialized @196ms
Exception in thread "main" java.util.concurrent.TimeoutException
    at java.util.concurrent.Phaser.awaitAdvanceInterruptibly(Phaser.java:800)
    at com.example.Client.main(Client.java:90)

---UPDATE 3---

Take a different approach: When I pull all the master branch of the whole jetty project, and then create an Intellij project at jetty.project/jetty-http2/http2-client then it works for public servers https://webtide.com and https://nghttp2.org . But when I test it on my self-signed certificate http2 server (using nghttp2 + nginx, resided in my virtual machine) then I get this error

2015-05-05 19:05:25.094:INFO::main: Logging initialized @220ms
Exception in thread "main" java.util.concurrent.ExecutionException: java.nio.channels.ClosedChannelException
    at org.eclipse.jetty.util.FuturePromise.get(FuturePromise.java:138)
    at org.eclipse.jetty.http2.client.Client.main(Client.java:55)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Caused by: java.nio.channels.ClosedChannelException
    at org.eclipse.jetty.http2.HTTP2Flusher.append(HTTP2Flusher.java:110)
    at org.eclipse.jetty.http2.HTTP2Session.frame(HTTP2Session.java:577)
    at org.eclipse.jetty.http2.HTTP2Session.frames(HTTP2Session.java:559)
    at org.eclipse.jetty.http2.client.HTTP2ClientConnectionFactory$HTTP2ClientConnection.onOpen(HTTP2ClientConnectionFactory.java:121)
Duda answered 3/5, 2015 at 3:45 Comment(0)
A
3

The link reported in the question presents a HTTP/2 transport for Jetty's HttpClient.

Jetty's HttpClient exposes a generic HTTP API to applications that has to work with HTTP 1.0, 1.1 and 2.0 and as such HttpClient does not expose any API to receive HTTP/2 push resources, since these are a peculiar mechanism of HTTP/2 only.

If you really want to interact with a HTTP/2 API, you can use Jetty's HTTP2Client, which exposes a lower-level API, HTTP/2 specific, to applications.

You can find a full fledged example of connecting to a website that pushes resources (in this case https://webtide.com) here.

Alston answered 4/5, 2015 at 10:39 Comment(9)
Thank you, I have tried the file but keep getting error. Please see my updated answerVexation
You must put the ALPN boot jar into the bootclasspath, as specified here. Have you done that ? You must also use JDK 8. If you did, what server are you trying to hit ?Alston
Yes I am using JDK 8 and now I have added the ALPN boot jar, but still get error. I was trying to connect to webtide.com and nghttp2.org Please check my update 2.Vexation
Are you using the latest code from the Jetty master branch ?Alston
I just use the maven dependency of version 9.3.0.M2, and copy the Client.java in the master branch into my project (after changing package to package com.example and add import org.eclipse.jetty.http2.client.* Is that the right way or not?Vexation
If I truly use the master branch, that means to pull all the code and create a project in http2-client folder, then it works for public servers, but not for my self-signed certificate http2 server (see update 3).Vexation
Self signed certificates are not good for HTTP/2 because they don't met the security requirements required by HTTP/2 so there is little chance to get that working, unless you completely override the server behaviour and allow any certificate and any cipher. If you do that, on the client side you need to configure the keystore with the self-signed certificate.Alston
Would there be another way of making this example work? I don't understand why this cannot work as a standalone class as far as the jars have been correctly referenced.Sabir
The example has been reported to work fine, you need to detail what is not working for you. Jetty 9.3.0 has been released so be sure to use the right jars. Feel free to join the Jetty mailing list to explain your issues in greater details.Alston
C
1

Answer for UPDATE 3:

Use another constructor of SslContextFactory, which has a boolean argument trustAll certificates:

SslContextFactory sslContextFactory = new SslContextFactory(true);

The whole code:

HTTP2Client client = new HTTP2Client();
SslContextFactory sslContextFactory = new SslContextFactory();
client.addBean(sslContextFactory);
client.start();
Campaign answered 18/8, 2015 at 22:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.