Skip to content

Commit c8b9ba0

Browse files
committed
Provide working sample for Jetty using HTTP/2
1 parent e3b6c9f commit c8b9ba0

File tree

6 files changed

+254
-0
lines changed

6 files changed

+254
-0
lines changed

spring-boot-samples/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
<module>spring-boot-sample-jetty</module>
5454
<module>spring-boot-sample-jetty-jsp</module>
5555
<module>spring-boot-sample-jetty-ssl</module>
56+
<module>spring-boot-sample-jetty-http2</module>
5657
<module>spring-boot-sample-jooq</module>
5758
<module>spring-boot-sample-jpa</module>
5859
<module>spring-boot-sample-jta-atomikos</module>
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<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/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
<parent>
5+
<!-- Your own application should inherit from spring-boot-starter-parent -->
6+
<groupId>org.springframework.boot</groupId>
7+
<artifactId>spring-boot-samples</artifactId>
8+
<version>2.0.0.BUILD-SNAPSHOT</version>
9+
</parent>
10+
<artifactId>spring-boot-sample-jetty-http2</artifactId>
11+
<name>Spring Boot Jetty HTTP/2 Sample</name>
12+
<description>Spring Boot Jetty HTTP/2 Sample</description>
13+
<url>http://projects.spring.io/spring-boot/</url>
14+
<organization>
15+
<name>Pivotal Software, Inc.</name>
16+
<url>http://www.spring.io</url>
17+
</organization>
18+
<properties>
19+
<main.basedir>${basedir}/../..</main.basedir>
20+
</properties>
21+
<dependencies>
22+
<!-- Compile -->
23+
<dependency>
24+
<groupId>org.springframework.boot</groupId>
25+
<artifactId>spring-boot-starter</artifactId>
26+
</dependency>
27+
<dependency>
28+
<groupId>org.springframework.boot</groupId>
29+
<artifactId>spring-boot-starter-jetty</artifactId>
30+
</dependency>
31+
<dependency>
32+
<groupId>org.springframework</groupId>
33+
<artifactId>spring-webmvc</artifactId>
34+
</dependency>
35+
<dependency>
36+
<groupId>org.eclipse.jetty.alpn</groupId>
37+
<artifactId>alpn-api</artifactId>
38+
</dependency>
39+
<dependency>
40+
<groupId>org.eclipse.jetty</groupId>
41+
<artifactId>jetty-alpn-server</artifactId>
42+
</dependency>
43+
<dependency>
44+
<groupId>org.eclipse.jetty</groupId>
45+
<artifactId>jetty-alpn-java-server</artifactId>
46+
<version>9.4.7.RC0</version>
47+
</dependency>
48+
<!-- Test -->
49+
<dependency>
50+
<groupId>org.springframework.boot</groupId>
51+
<artifactId>spring-boot-starter-test</artifactId>
52+
<scope>test</scope>
53+
</dependency>
54+
<dependency>
55+
<groupId>com.squareup.okhttp3</groupId>
56+
<artifactId>okhttp</artifactId>
57+
<version>3.8.1</version>
58+
<scope>test</scope>
59+
</dependency>
60+
</dependencies>
61+
<build>
62+
<plugins>
63+
<plugin>
64+
<groupId>org.springframework.boot</groupId>
65+
<artifactId>spring-boot-maven-plugin</artifactId>
66+
</plugin>
67+
</plugins>
68+
</build>
69+
</project>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2012-2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package sample.jetty.http2;
18+
19+
import org.springframework.boot.SpringApplication;
20+
import org.springframework.boot.autoconfigure.SpringBootApplication;
21+
import org.springframework.web.bind.annotation.GetMapping;
22+
import org.springframework.web.bind.annotation.RestController;
23+
24+
@SpringBootApplication
25+
@RestController
26+
public class SampleJettyHttp2Application {
27+
28+
public static void main(String[] args) throws Exception {
29+
SpringApplication.run(SampleJettyHttp2Application.class, args);
30+
}
31+
32+
@GetMapping("/")
33+
public String helloWorld() {
34+
return "Hello, world";
35+
}
36+
37+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
server.port = 8443
2+
server.http2.enabled = true
3+
server.ssl.key-store = classpath:sample.jks
4+
server.ssl.key-store-password = secret
5+
server.ssl.key-password = password
Binary file not shown.
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
/*
2+
* Copyright 2012-2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package sample.jetty.http2;
18+
19+
import java.security.KeyManagementException;
20+
import java.security.NoSuchAlgorithmException;
21+
import java.security.SecureRandom;
22+
import java.security.cert.CertificateException;
23+
import java.security.cert.X509Certificate;
24+
import java.util.Arrays;
25+
26+
import javax.net.ssl.HostnameVerifier;
27+
import javax.net.ssl.SSLContext;
28+
import javax.net.ssl.TrustManager;
29+
import javax.net.ssl.X509TrustManager;
30+
31+
import okhttp3.OkHttpClient;
32+
import okhttp3.Protocol;
33+
import okhttp3.Request;
34+
import okhttp3.Response;
35+
import org.junit.Before;
36+
import org.junit.Test;
37+
import org.junit.runner.RunWith;
38+
39+
import org.springframework.boot.test.context.SpringBootTest;
40+
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
41+
import org.springframework.boot.web.server.LocalServerPort;
42+
import org.springframework.http.HttpStatus;
43+
import org.springframework.test.context.junit4.SpringRunner;
44+
45+
import static org.assertj.core.api.Assertions.assertThat;
46+
47+
/**
48+
* Basic integration tests for sample application that verify HTTP/1.1 and HTTP/2 support.
49+
*
50+
* @author Paul Vorbach
51+
*/
52+
@RunWith(SpringRunner.class)
53+
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
54+
public class SampleJettyHttp2ApplicationTests {
55+
56+
@LocalServerPort
57+
private int port;
58+
59+
private OkHttpClient okHttp11Client;
60+
private OkHttpClient okHttp2Client;
61+
62+
@Before
63+
public void setUp() throws Exception {
64+
this.okHttp11Client = createInsecureOkHttpClient(Protocol.HTTP_1_1);
65+
this.okHttp2Client = createInsecureOkHttpClient(Protocol.HTTP_1_1, Protocol.HTTP_2);
66+
}
67+
68+
@Test
69+
public void testHttp11() throws Exception {
70+
final Request request = new Request.Builder()
71+
.url(String.format("https://localhost:%d/", port))
72+
.build();
73+
74+
final Response response = okHttp11Client.newCall(request).execute();
75+
76+
assertThat(response.protocol()).isEqualTo(Protocol.HTTP_1_1);
77+
assertThat(response.code()).isEqualTo(HttpStatus.OK.value());
78+
assertThat(response.body().string()).isEqualTo("Hello, world");
79+
}
80+
81+
/**
82+
* Tests that the server has HTTP/2 enabled.
83+
* <p>
84+
* This only works when both tomcat-native is in PATH <em>and</em> it is running on
85+
* Java 9, since OkHttp makes use of Java 9's support for ALPN.
86+
*/
87+
@Test
88+
public void testHttp2() throws Exception {
89+
final Request request = new Request.Builder()
90+
.url(String.format("https://localhost:%d/", port))
91+
.build();
92+
93+
final Response response = okHttp2Client.newCall(request).execute();
94+
95+
assertThat(response.protocol()).isEqualTo(Protocol.HTTP_2);
96+
assertThat(response.code()).isEqualTo(HttpStatus.OK.value());
97+
assertThat(response.body().string()).isEqualTo("Hello, world");
98+
}
99+
100+
private static OkHttpClient createInsecureOkHttpClient(Protocol... supportedProtocols)
101+
throws NoSuchAlgorithmException, KeyManagementException {
102+
103+
final HostnameVerifier acceptAllHostnamesVerifier = (hostname, sslSession) -> true;
104+
final InsecureTrustManager insecureTrustManager = new InsecureTrustManager();
105+
final SSLContext sslContext = createSslContext(insecureTrustManager);
106+
107+
return new OkHttpClient.Builder()
108+
.protocols(Arrays.asList(supportedProtocols))
109+
.hostnameVerifier(acceptAllHostnamesVerifier)
110+
.sslSocketFactory(sslContext.getSocketFactory(), insecureTrustManager)
111+
.build();
112+
}
113+
114+
private static SSLContext createSslContext(TrustManager trustManager)
115+
throws KeyManagementException, NoSuchAlgorithmException {
116+
117+
final SSLContext sslContext = SSLContext.getInstance("TLSv1");
118+
119+
sslContext.init(null, new TrustManager[] { trustManager }, new SecureRandom());
120+
121+
return sslContext;
122+
}
123+
124+
private static class InsecureTrustManager implements X509TrustManager {
125+
126+
@Override
127+
public void checkClientTrusted(X509Certificate[] chain, String authType)
128+
throws CertificateException {
129+
}
130+
131+
@Override
132+
public void checkServerTrusted(X509Certificate[] chain, String authType)
133+
throws CertificateException {
134+
}
135+
136+
@Override
137+
public X509Certificate[] getAcceptedIssuers() {
138+
return new X509Certificate[] {};
139+
}
140+
}
141+
142+
}

0 commit comments

Comments
 (0)