Merge remote-tracking branch 'eclipse/jetty-10.0.x' into jetty-10.0.x-3170-websocket-proxy
Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
commit
327783e1ce
|
@ -19,6 +19,7 @@ bin/
|
|||
*.backup
|
||||
*.debug
|
||||
*.dump
|
||||
.attach_pid*
|
||||
|
||||
# vim
|
||||
.*.sw[a-p]
|
||||
|
|
|
@ -40,16 +40,6 @@ pipeline {
|
|||
}
|
||||
}
|
||||
|
||||
stage("Build / Test - JDK11") {
|
||||
agent { node { label 'linux' } }
|
||||
options { timeout(time: 120, unit: 'MINUTES') }
|
||||
steps {
|
||||
mavenBuild("jdk11", "-Pmongodb install", "maven3", false)
|
||||
warnings consoleParsers: [[parserName: 'Maven'], [parserName: 'Java']]
|
||||
maven_invoker reportsFilenamePattern: "**/target/invoker-reports/BUILD*.xml", invokerBuildDir: "**/target/it"
|
||||
}
|
||||
}
|
||||
|
||||
stage("Build / Test - JDK12") {
|
||||
agent { node { label 'linux' } }
|
||||
options { timeout(time: 120, unit: 'MINUTES') }
|
||||
|
@ -71,8 +61,37 @@ pipeline {
|
|||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
post {
|
||||
failure {
|
||||
slackNotif()
|
||||
}
|
||||
unstable {
|
||||
slackNotif()
|
||||
}
|
||||
fixed {
|
||||
slackNotif()
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
def slackNotif() {
|
||||
script {
|
||||
if (env.BRANCH_NAME=='jetty-10.0.x' ||
|
||||
env.BRANCH_NAME=='jetty-9.4.x') {
|
||||
//BUILD_USER = currentBuild.rawBuild.getCause(Cause.UserIdCause).getUserId()
|
||||
// by ${BUILD_USER}
|
||||
COLOR_MAP = ['SUCCESS': 'good', 'FAILURE': 'danger', 'UNSTABLE': 'danger', 'ABORTED': 'danger']
|
||||
slackSend channel: '#jenkins',
|
||||
color: COLOR_MAP[currentBuild.currentResult],
|
||||
message: "*${currentBuild.currentResult}:* Job ${env.JOB_NAME} build ${env.BUILD_NUMBER} - ${env.BUILD_URL}"
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* To other developers, if you are using this method above, please use the following syntax.
|
||||
*
|
||||
|
@ -97,7 +116,7 @@ def mavenBuild(jdk, cmdline, mvnName, junitPublishDisabled) {
|
|||
mavenOpts: mavenOpts,
|
||||
mavenLocalRepo: localRepo) {
|
||||
// Some common Maven command line + provided command line
|
||||
sh "mvn -V -B -T3 -e -fae -Dmaven.test.failure.ignore=true -Djetty.testtracker.log=true $cmdline -Dunix.socket.tmp=" + env.JENKINS_HOME
|
||||
sh "mvn -Pci -V -B -T3 -e -fae -Dmaven.test.failure.ignore=true -Djetty.testtracker.log=true $cmdline -Dunix.socket.tmp=" + env.JENKINS_HOME
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,53 +2,49 @@
|
|||
|
||||
def branch = params.get("JETTY_BRANCH" ,"jetty-10.0.x")
|
||||
def owner = params.get("REPO_OWNER", "eclipse")
|
||||
def jdk = params.get("JDK", "jdk11")
|
||||
def jmhJarPath = params.get("jmhJarPath","tests/jetty-jmh/target/benchmarks.jar")
|
||||
currentBuild.description = "Build branch $branch with jdk $jdk"
|
||||
|
||||
node("linux") {
|
||||
// System Dependent Locations
|
||||
def mvntool = tool name: 'maven3.5', type: 'hudson.tasks.Maven$MavenInstallation'
|
||||
def jdktool = tool name: "jdk8", type: 'hudson.model.JDK'
|
||||
def mvnName = 'maven3.5'
|
||||
def localRepo = "${env.JENKINS_HOME}/${env.EXECUTOR_NUMBER}"
|
||||
def settingsName = 'oss-settings.xml'
|
||||
def mavenOpts = '-Xms1g -Xmx4g -Djava.awt.headless=true'
|
||||
|
||||
// Environment
|
||||
List mvnEnv = ["PATH+MVN=${mvntool}/bin", "PATH+JDK=${jdktool}/bin", "JAVA_HOME=${jdktool}/", "MAVEN_HOME=${mvntool}"]
|
||||
mvnEnv.add("MAVEN_OPTS=$mavenOpts")
|
||||
|
||||
|
||||
stage("Checkout") {
|
||||
git url: "https://github.com/$owner/jetty.project.git", branch: "$branch"
|
||||
|
||||
}
|
||||
|
||||
stage("Compile") {
|
||||
withEnv(mvnEnv) {
|
||||
timeout(time: 15, unit: 'MINUTES') {
|
||||
withMaven(
|
||||
maven: mvnName,
|
||||
jdk: "jdk11",
|
||||
publisherStrategy: 'EXPLICIT',
|
||||
globalMavenSettingsConfig: settingsName,
|
||||
mavenOpts: mavenOpts,
|
||||
mavenLocalRepo: localRepo) {
|
||||
sh "mvn -V -B clean install -DskipTests -T6 -e"
|
||||
}
|
||||
|
||||
timeout(time: 15, unit: 'MINUTES') {
|
||||
withMaven(
|
||||
maven: mvnName,
|
||||
jdk: jdk,
|
||||
publisherStrategy: 'EXPLICIT',
|
||||
globalMavenSettingsConfig: settingsName,
|
||||
mavenOpts: mavenOpts,
|
||||
mavenLocalRepo: localRepo) {
|
||||
sh "mvn -V -B clean install -DskipTests -T6 -e -pl :jetty-jmh -am"
|
||||
}
|
||||
stash name: 'perf-tests', includes: 'jetty-jmh/target/benchmarks.jar'
|
||||
}
|
||||
stash name: 'perf-tests', includes: jmhJarPath
|
||||
}
|
||||
}
|
||||
|
||||
// jmh run
|
||||
|
||||
stage("jmh-run") {
|
||||
node( 'jmh-build-node' ) {
|
||||
timeout( time: 120, unit: 'MINUTES' ) {
|
||||
withEnv( ["JAVA_HOME=${tool "jdk8"}"] ) {
|
||||
node( 'jmh-build-node' ) {
|
||||
stage("jmh-run") {
|
||||
timeout( time: 180, unit: 'MINUTES' ) {
|
||||
withEnv( ["JAVA_HOME=${tool "$jdk"}"] ) {
|
||||
unstash name: 'perf-tests'
|
||||
sh "${env.JAVA_HOME}/bin/java -jar jetty-jmh/target/benchmarks.jar -rff jetty-jmh/target/jmh_result.json -rf json"
|
||||
jmhReport 'jetty-jmh/target/jmh_result.json'
|
||||
sh "rm -rf jmh_results"
|
||||
sh "mkdir jmh_results"
|
||||
sh "${env.JAVA_HOME}/bin/java -jar $jmhJarPath -rff jmh_results/jmh_result.json -rf json -foe true"
|
||||
jmhReport 'jmh_results/jmh_result.json'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
7
LICENSE
7
LICENSE
|
@ -1,7 +1,8 @@
|
|||
This program and the accompanying materials are made available under the
|
||||
terms of the Eclipse Public License 2.0 which is available at
|
||||
http://www.eclipse.org/legal/epl-2.0, or the Apache Software License
|
||||
2.0 which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
terms of the Eclipse Public License 1.0 which is available at
|
||||
https://www.eclipse.org/org/documents/epl-1.0/EPL-1.0.txt
|
||||
or the Apache Software License 2.0 which is available at
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
|
||||
|
||||
|
|
77
VERSION.txt
77
VERSION.txt
|
@ -1,5 +1,49 @@
|
|||
jetty-10.0.0-SNAPSHOT
|
||||
|
||||
jetty-9.4.18.v20190429 - 29 April 2019
|
||||
+ 3476 IllegalStateException in WebSocket ConnectionState
|
||||
+ 3550 Server becomes unresponsive after sitting idle from a load spike
|
||||
+ 3563 Update to apache jasper 8.5.40
|
||||
+ 3573 Update jetty-bom for new infinispan artifacts.
|
||||
+ 3582 HeapByteBuffer cleared unexpected
|
||||
+ 3597 Session persistence broken from 9.4.13+
|
||||
+ 3609 Fix infinispan start module dependencies
|
||||
|
||||
jetty-9.4.17.v20190418 - 18 April 2019
|
||||
+ 3464 Split SslContextFactory into Client and Server
|
||||
+ 3549 Directory Listing on Windows reveals Resource Base path
|
||||
+ 3555 DefaultHandler Reveals Base Resource Path of each Context
|
||||
|
||||
jetty-9.4.16.v20190411 - 11 April 2019
|
||||
+ 1861 Limit total bytes pooled by ByteBufferPools
|
||||
+ 3133 Logging of `key.readyOps()` can throw unchecked `CancelledKeyException`
|
||||
+ 3159 WebSocket permessage-deflate RSV1 validity check
|
||||
+ 3274 OSGi versions of java.base classes in
|
||||
org.apache.felix:org.osgi.foundation:jar conflicts with new rules on Java 9+
|
||||
+ 3319 Modernize Directory Listing: HTML5 and Sorting
|
||||
+ 3361 HandlerCollection.addHandler is lacking synchronization
|
||||
+ 3373 OutOfMemoryError: Java heap space in GZIPContentDecoder
|
||||
+ 3389 Websockets jsr356 willDecode not invoked during decoding
|
||||
+ 3394 java.security.acl.Group is deprecated and marked for removal
|
||||
+ 3404 Cleanup QuotedQualityCSV internal use of Double
|
||||
+ 3411 HttpClient does not timeout during multiple redirection
|
||||
+ 3421 Duplicate JSESSIONID sent when invalidating new session
|
||||
+ 3422 CLOSE_WAIT socket status forever after terminating websocket client
|
||||
side
|
||||
+ 3425 Upgrade conscrypt version to 2.0.0 and remove usage of reflection
|
||||
+ 3429 JMX Operation to trigger manual deployment scan in WebAppProvider
|
||||
+ 3440 Stop server if Unavailable thrown
|
||||
+ 3444 org.eclipse.jetty.http.Http1FieldPreEncoder generates an invalid header
|
||||
byte-array if header is null
|
||||
+ 3456 Allow multiple programmatic login/logout in same request
|
||||
+ 3464 Split SslContextFactory into Client and Server
|
||||
+ 3481 TLS close_notify() is not guaranteed
|
||||
+ 3489 Using setExtraClasspath("lib/extra/*") does not work on Microsoft
|
||||
Windows
|
||||
+ 3526 HTTP Request Locale not retained in WebsocketUpgrade Request
|
||||
+ 3540 Use configured Provider in SslContextFactory consistently
|
||||
+ 3545 NullPointerException on ServletOutputStream.print("");
|
||||
|
||||
jetty-9.4.15.v20190215 - 15 February 2019
|
||||
+ 113 Add support for NCSA Extended Log File Format
|
||||
+ 150 extraClasspath() method on WebAppContext dont support dir path
|
||||
|
@ -43,6 +87,25 @@ jetty-9.4.15.v20190215 - 15 February 2019
|
|||
+ 3350 Do not expect to be able to connect to https URLs with the HttpClient
|
||||
created from a parameterless constructor
|
||||
|
||||
jetty-9.3.27.v20190418 - 18 April 2019
|
||||
+ 3549 Directory Listing on Windows reveals Resource Base path
|
||||
+ 3555 DefaultHandler Reveals Base Resource Path of each Context
|
||||
|
||||
jetty-9.3.26.v20190403 - 03 April 2019
|
||||
+ 2954 Improve cause reporting for HttpClient failures
|
||||
+ 3274 OSGi versions of java.base classes in
|
||||
org.apache.felix:org.osgi.foundation:jar conflicts with new rules on Java 9+
|
||||
+ 3302 Support host:port in X-Forwarded-For header in
|
||||
ForwardedRequestCustomizer
|
||||
+ 3319 Allow reverse sort for directory listed files
|
||||
|
||||
jetty-9.2.28.v20190418 - 18 April 2019
|
||||
+ 3549 Directory Listing on Windows reveals Resource Base path
|
||||
+ 3555 DefaultHandler Reveals Base Resource Path of each Context
|
||||
|
||||
jetty-9.2.27.v20190403 - 03 April 2019
|
||||
+ 3319 Refactored Directory Listing to modernize and avoid XSS
|
||||
|
||||
jetty-9.4.14.v20181114 - 14 November 2018
|
||||
+ 3097 Duplicated programmatic Servlet Listeners causing duplicate calls
|
||||
+ 3103 HttpClientLoadTest reports a leak in byte buffer
|
||||
|
@ -90,6 +153,13 @@ jetty-9.4.13.v20181111 - 11 November 2018
|
|||
+ 3090 MBeanContainer throws NPE for arrays
|
||||
+ 3092 Wrong classloader used to load *MBean classes
|
||||
|
||||
jetty-9.3.25.v20180904 - 04 September 2018
|
||||
+ 2135 Android 8.1 needs direct buffers for SSL/TLS to work
|
||||
+ 2777 Workaround for Conscrypt's ssl == null
|
||||
+ 2787 BadMessageException wrapped as ServletException not handled
|
||||
+ 2860 Leakage of HttpDestinations in HttpClient
|
||||
+ 2871 Server reads -1 after client resets HTTP/2 stream
|
||||
|
||||
jetty-9.4.12.v20180830 - 30 August 2018
|
||||
+ 300 Implement Deflater / Inflater Object Pool
|
||||
+ 307 Monitor contention in AbstractNCSARequestLog
|
||||
|
@ -182,13 +252,6 @@ jetty-9.4.12.v20180830 - 30 August 2018
|
|||
+ 2860 Leakage of HttpDestinations in HttpClient
|
||||
+ 2871 Server reads -1 after client resets HTTP/2 stream
|
||||
|
||||
jetty-9.3.25.v20180904 - 04 September 2018
|
||||
+ 2135 Android 8.1 needs direct buffers for SSL/TLS to work
|
||||
+ 2777 Workaround for Conscrypt's ssl == null
|
||||
+ 2787 BadMessageException wrapped as ServletException not handled
|
||||
+ 2860 Leakage of HttpDestinations in HttpClient
|
||||
+ 2871 Server reads -1 after client resets HTTP/2 stream
|
||||
|
||||
jetty-9.2.26.v20180806 - 06 August 2018
|
||||
+ 2777 Workaround for Conscrypt's ssl == null
|
||||
|
||||
|
|
|
@ -209,8 +209,8 @@
|
|||
</dependency>
|
||||
<!-- dependencies that jetty-all needs (some optional) -->
|
||||
<dependency>
|
||||
<groupId>javax.websocket</groupId>
|
||||
<artifactId>javax.websocket-api</artifactId>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-javax-websocket-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
|
|
|
@ -144,8 +144,8 @@
|
|||
</dependency>
|
||||
<!-- dependencies that jetty-all needs (some optional) -->
|
||||
<dependency>
|
||||
<groupId>javax.websocket</groupId>
|
||||
<artifactId>javax.websocket-api</artifactId>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-javax-websocket-api</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
|
@ -119,7 +119,7 @@ public class JettyJspServlet extends JspServlet
|
|||
*/
|
||||
private String addPaths(String servletPath, String pathInfo)
|
||||
{
|
||||
if (servletPath.length()==0)
|
||||
if (servletPath.isEmpty())
|
||||
return pathInfo;
|
||||
|
||||
if (pathInfo==null)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
|
||||
<!--
|
||||
This is the jetty specific web application configuration file. When starting
|
||||
|
@ -9,7 +9,7 @@ org.eclipse.jetty.servlet.WebApplicationContext object
|
|||
-->
|
||||
|
||||
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
|
||||
<Get class="org.eclipse.jetty.util.log.Log" name="rootLogger">
|
||||
<Call name="warn"><Arg>async-rest webapp is deployed. DO NOT USE IN PRODUCTION!</Arg></Call>
|
||||
<Get name="servletContext">
|
||||
<Call name="log"><Arg>The async-rest webapp is deployed. DO NOT USE IN PRODUCTION!</Arg><Arg></Arg></Call>
|
||||
</Get>
|
||||
</Configure>
|
||||
|
|
|
@ -25,7 +25,6 @@ import java.nio.ByteBuffer;
|
|||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.FileChannel.MapMode;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
|
||||
import javax.servlet.AsyncContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -116,7 +115,8 @@ public class FastFileServer
|
|||
}
|
||||
String listing = Resource.newResource(file).getListHTML(
|
||||
request.getRequestURI(),
|
||||
request.getPathInfo().lastIndexOf("/") > 0);
|
||||
request.getPathInfo().lastIndexOf("/") > 0,
|
||||
request.getQueryString());
|
||||
response.setContentType("text/html; charset=utf-8");
|
||||
response.getWriter().println(listing);
|
||||
return;
|
||||
|
|
|
@ -36,9 +36,8 @@ public class FileServerXml
|
|||
{
|
||||
public static void main( String[] args ) throws Exception
|
||||
{
|
||||
Resource fileserverXml = Resource.newSystemResource("fileserver.xml");
|
||||
XmlConfiguration configuration = new XmlConfiguration(
|
||||
fileserverXml.getInputStream());
|
||||
Resource fileServerXml = Resource.newSystemResource("fileserver.xml");
|
||||
XmlConfiguration configuration = new XmlConfiguration(fileServerXml);
|
||||
Server server = (Server) configuration.configure();
|
||||
server.start();
|
||||
server.join();
|
||||
|
|
|
@ -60,10 +60,6 @@ import org.eclipse.jetty.servlet.ServletHolder;
|
|||
import org.eclipse.jetty.servlets.PushCacheFilter;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
*/
|
||||
public class Http2Server
|
||||
{
|
||||
public static void main(String... args) throws Exception
|
||||
|
@ -102,7 +98,7 @@ public class Http2Server
|
|||
String jetty_distro = System.getProperty("jetty.distro","../../jetty-distribution/target/distribution");
|
||||
if (!new File(jetty_distro).exists())
|
||||
jetty_distro = "jetty-distribution/target/distribution";
|
||||
SslContextFactory sslContextFactory = new SslContextFactory();
|
||||
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
|
||||
sslContextFactory.setKeyStorePath(jetty_distro + "/demo-base/etc/keystore");
|
||||
sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
|
||||
sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
|
||||
|
|
|
@ -99,7 +99,7 @@ public class LikeJettyXml
|
|||
Server server = new Server(threadPool);
|
||||
|
||||
// Scheduler
|
||||
server.addBean(new ScheduledExecutorScheduler());
|
||||
server.addBean(new ScheduledExecutorScheduler(null,false));
|
||||
|
||||
// HTTP Configuration
|
||||
HttpConfiguration http_config = new HttpConfiguration();
|
||||
|
@ -139,7 +139,7 @@ public class LikeJettyXml
|
|||
|
||||
// === jetty-https.xml ===
|
||||
// SSL Context Factory
|
||||
SslContextFactory sslContextFactory = new SslContextFactory();
|
||||
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
|
||||
sslContextFactory.setKeyStorePath(jetty_home + "/../../../jetty-server/src/test/config/etc/keystore");
|
||||
sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
|
||||
sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
|
||||
|
|
|
@ -20,9 +20,7 @@ package org.eclipse.jetty.embedded;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.security.Security;
|
||||
|
||||
import org.conscrypt.OpenSSLProvider;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
|
@ -89,7 +87,7 @@ public class ManyConnectors
|
|||
// including things like choosing the particular certificate out of a
|
||||
// keystore to be used.
|
||||
|
||||
SslContextFactory sslContextFactory = new SslContextFactory();
|
||||
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
|
||||
sslContextFactory.setKeyStorePath(keystoreFile.getAbsolutePath());
|
||||
sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
|
||||
sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
|
||||
|
|
|
@ -79,7 +79,7 @@ public class ManyHandlers
|
|||
ServletException
|
||||
{
|
||||
Map<String, String[]> params = request.getParameterMap();
|
||||
if (params.size() > 0)
|
||||
if (!params.isEmpty())
|
||||
{
|
||||
response.setContentType("text/plain");
|
||||
response.getWriter().println(JSON.toString(params));
|
||||
|
|
|
@ -23,7 +23,6 @@ import java.lang.management.ManagementFactory;
|
|||
|
||||
import org.eclipse.jetty.jmx.MBeanContainer;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AllowSymLinkAliasChecker;
|
||||
import org.eclipse.jetty.webapp.Configurations;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
||||
|
@ -65,7 +64,7 @@ public class OneWebApp
|
|||
|
||||
Configurations.setServerDefault(server);
|
||||
|
||||
// Start things up!
|
||||
// Start things up!
|
||||
server.start();
|
||||
|
||||
server.dumpStdErr();
|
||||
|
|
|
@ -24,10 +24,8 @@ import org.eclipse.jetty.servlet.ServletHolder;
|
|||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
||||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||
import org.eclipse.jetty.websocket.core.FrameHandler;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketMapping;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
|
||||
import org.eclipse.jetty.websocket.server.JettyWebSocketServlet;
|
||||
import org.eclipse.jetty.websocket.server.JettyWebSocketServletFactory;
|
||||
|
||||
/**
|
||||
* Example of setting up a Jetty WebSocket server
|
||||
|
@ -53,10 +51,10 @@ public class WebSocketServer
|
|||
* Servlet layer
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public static class EchoServlet extends WebSocketServlet
|
||||
public static class EchoServlet extends JettyWebSocketServlet
|
||||
{
|
||||
@Override
|
||||
public void configure(WebSocketServletFactory factory)
|
||||
public void configure(JettyWebSocketServletFactory factory)
|
||||
{
|
||||
factory.addMapping(factory.parsePathSpec("/"), (req,res)->new EchoSocket());
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
|
||||
<Configure id="ExampleServer" class="org.eclipse.jetty.server.Server">
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
|
||||
<Configure id="FileServer" class="org.eclipse.jetty.server.Server">
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
|
||||
<Configure id="OtherServer" class="org.eclipse.jetty.server.Server">
|
||||
<Set name="handler">
|
||||
|
|
|
@ -19,6 +19,14 @@
|
|||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<configuration>
|
||||
<!-- No point deploying example projects -->
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
|
|
|
@ -48,6 +48,6 @@ public class ALPNClientConnection extends NegotiatingClientConnection
|
|||
if (protocol == null || !protocols.contains(protocol))
|
||||
close();
|
||||
else
|
||||
completed();
|
||||
completed(protocol);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,4 +111,12 @@ public class ALPNClientConnectionFactory extends NegotiatingClientConnectionFact
|
|||
}
|
||||
throw new IllegalStateException("No ALPNProcessor for " + engine);
|
||||
}
|
||||
|
||||
public static class ALPN extends Info
|
||||
{
|
||||
public ALPN(Executor executor, ClientConnectionFactory factory, List<String> protocols)
|
||||
{
|
||||
super(List.of("alpn"), new ALPNClientConnectionFactory(executor, factory, protocols));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,12 +18,10 @@
|
|||
|
||||
package org.eclipse.jetty.alpn.conscrypt.client;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.Security;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
|
||||
import org.conscrypt.Conscrypt;
|
||||
import org.conscrypt.OpenSSLProvider;
|
||||
import org.eclipse.jetty.alpn.client.ALPNClientConnection;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
|
@ -40,7 +38,7 @@ public class ConscryptClientALPNProcessor implements ALPNProcessor.Client
|
|||
@Override
|
||||
public void init()
|
||||
{
|
||||
if (Security.getProvider("Conscrypt")==null)
|
||||
if (Security.getProvider("Conscrypt") == null)
|
||||
{
|
||||
Security.addProvider(new OpenSSLProvider());
|
||||
if (LOG.isDebugEnabled())
|
||||
|
@ -59,11 +57,9 @@ public class ConscryptClientALPNProcessor implements ALPNProcessor.Client
|
|||
{
|
||||
try
|
||||
{
|
||||
Method setAlpnProtocols = sslEngine.getClass().getDeclaredMethod("setApplicationProtocols", String[].class);
|
||||
setAlpnProtocols.setAccessible(true);
|
||||
ALPNClientConnection alpn = (ALPNClientConnection)connection;
|
||||
String[] protocols = alpn.getProtocols().toArray(new String[0]);
|
||||
setAlpnProtocols.invoke(sslEngine, (Object)protocols);
|
||||
Conscrypt.setApplicationProtocols(sslEngine, protocols);
|
||||
((SslConnection.DecryptedEndPoint)connection.getEndPoint()).getSslConnection()
|
||||
.addHandshakeListener(new ALPNListener(alpn));
|
||||
}
|
||||
|
@ -92,9 +88,9 @@ public class ConscryptClientALPNProcessor implements ALPNProcessor.Client
|
|||
try
|
||||
{
|
||||
SSLEngine sslEngine = alpnConnection.getSSLEngine();
|
||||
Method method = sslEngine.getClass().getDeclaredMethod("getApplicationProtocol");
|
||||
method.setAccessible(true);
|
||||
String protocol = (String)method.invoke(sslEngine);
|
||||
String protocol = Conscrypt.getApplicationProtocol(sslEngine);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Selected {} for {}", protocol, alpnConnection);
|
||||
alpnConnection.selected(protocol);
|
||||
}
|
||||
catch (Throwable e)
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.alpn.java.client;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.security.Security;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.conscrypt.OpenSSLProvider;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpURI;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.http.MetaData;
|
||||
import org.eclipse.jetty.http2.api.Session;
|
||||
import org.eclipse.jetty.http2.api.Stream;
|
||||
import org.eclipse.jetty.http2.client.HTTP2Client;
|
||||
import org.eclipse.jetty.http2.frames.DataFrame;
|
||||
import org.eclipse.jetty.http2.frames.HeadersFrame;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.FuturePromise;
|
||||
import org.eclipse.jetty.util.Jetty;
|
||||
import org.eclipse.jetty.util.Promise;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
|
||||
public class ConscryptHTTP2Client
|
||||
{
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
Security.addProvider(new OpenSSLProvider());
|
||||
SslContextFactory sslContextFactory = new SslContextFactory();
|
||||
sslContextFactory.setProvider("Conscrypt");
|
||||
HTTP2Client client = new HTTP2Client();
|
||||
client.addBean(sslContextFactory);
|
||||
client.start();
|
||||
|
||||
String host = "webtide.com";
|
||||
int port = 443;
|
||||
|
||||
FuturePromise<Session> sessionPromise = new FuturePromise<>();
|
||||
client.connect(sslContextFactory, new InetSocketAddress(host, port), new Session.Listener.Adapter(), sessionPromise);
|
||||
Session session = sessionPromise.get(5, TimeUnit.SECONDS);
|
||||
|
||||
HttpFields requestFields = new HttpFields();
|
||||
requestFields.put("User-Agent", client.getClass().getName() + "/" + Jetty.VERSION);
|
||||
MetaData.Request metaData = new MetaData.Request("GET", new HttpURI("https://" + host + ":" + port + "/"), HttpVersion.HTTP_2, requestFields);
|
||||
HeadersFrame headersFrame = new HeadersFrame(metaData, null, true);
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
session.newStream(headersFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public void onHeaders(Stream stream, HeadersFrame frame)
|
||||
{
|
||||
System.err.println(frame);
|
||||
if (frame.isEndStream())
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onData(Stream stream, DataFrame frame, Callback callback)
|
||||
{
|
||||
System.err.println(frame);
|
||||
callback.succeeded();
|
||||
if (frame.isEndStream())
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
latch.await(5, TimeUnit.SECONDS);
|
||||
|
||||
client.stop();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.alpn.java.client;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.security.Security;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.conscrypt.Conscrypt;
|
||||
import org.conscrypt.OpenSSLProvider;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpURI;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.http.MetaData;
|
||||
import org.eclipse.jetty.http2.api.Session;
|
||||
import org.eclipse.jetty.http2.api.Stream;
|
||||
import org.eclipse.jetty.http2.client.HTTP2Client;
|
||||
import org.eclipse.jetty.http2.frames.DataFrame;
|
||||
import org.eclipse.jetty.http2.frames.HeadersFrame;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.FuturePromise;
|
||||
import org.eclipse.jetty.util.Jetty;
|
||||
import org.eclipse.jetty.util.Promise;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.junit.jupiter.api.Assumptions;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class ConscryptHTTP2ClientTest
|
||||
{
|
||||
@Tag("external")
|
||||
@Test
|
||||
@Disabled("issue google/conscrypt#667")
|
||||
public void testConscryptHTTP2Client() throws Exception
|
||||
{
|
||||
String host = "webtide.com";
|
||||
int port = 443;
|
||||
|
||||
Assumptions.assumeTrue(canConnectTo(host, port));
|
||||
|
||||
Security.insertProviderAt(new OpenSSLProvider(), 1);
|
||||
SslContextFactory sslContextFactory = new SslContextFactory.Client();
|
||||
sslContextFactory.setProvider("Conscrypt");
|
||||
Conscrypt.setDefaultHostnameVerifier((hostname, session) -> true);
|
||||
|
||||
HTTP2Client client = new HTTP2Client();
|
||||
try
|
||||
{
|
||||
client.addBean(sslContextFactory);
|
||||
client.start();
|
||||
|
||||
FuturePromise<Session> sessionPromise = new FuturePromise<>();
|
||||
client.connect(sslContextFactory, new InetSocketAddress(host, port), new Session.Listener.Adapter(), sessionPromise);
|
||||
Session session = sessionPromise.get(15, TimeUnit.SECONDS);
|
||||
|
||||
HttpFields requestFields = new HttpFields();
|
||||
requestFields.put("User-Agent", client.getClass().getName() + "/" + Jetty.VERSION);
|
||||
MetaData.Request metaData = new MetaData.Request("GET", new HttpURI("https://" + host + ":" + port + "/"), HttpVersion.HTTP_2, requestFields);
|
||||
HeadersFrame headersFrame = new HeadersFrame(metaData, null, true);
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
session.newStream(headersFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public void onHeaders(Stream stream, HeadersFrame frame)
|
||||
{
|
||||
System.err.println(frame);
|
||||
if (frame.isEndStream())
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onData(Stream stream, DataFrame frame, Callback callback)
|
||||
{
|
||||
System.err.println(frame);
|
||||
callback.succeeded();
|
||||
if (frame.isEndStream())
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
assertTrue(latch.await(15, TimeUnit.SECONDS));
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean canConnectTo(String host, int port)
|
||||
{
|
||||
try
|
||||
{
|
||||
new Socket(host, port).close();
|
||||
return true;
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -38,23 +38,57 @@
|
|||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-alpn-conscrypt-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.http2</groupId>
|
||||
<artifactId>http2-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.http2</groupId>
|
||||
<artifactId>http2-http-client-transport</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-Description>Conscrypt ALPN</Bundle-Description>
|
||||
<Import-Package>org.conscrypt;version="${conscrypt.version}",*</Import-Package>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
|
||||
<Provide-Capability>osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Server</Provide-Capability>
|
||||
<_nouses>true</_nouses>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-Description>Conscrypt ALPN</Bundle-Description>
|
||||
<Import-Package>org.conscrypt;version="${conscrypt.version}",*</Import-Package>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
|
||||
<Provide-Capability>osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Server</Provide-Capability>
|
||||
<_nouses>true</_nouses>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>
|
||||
@{argLine} ${jetty.surefire.argLine}
|
||||
--add-reads org.eclipse.jetty.alpn.conscrypt.server=org.eclipse.jetty.server
|
||||
</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
|
@ -18,13 +18,13 @@
|
|||
|
||||
package org.eclipse.jetty.alpn.conscrypt.server;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.security.Security;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
|
||||
import org.conscrypt.ApplicationProtocolSelector;
|
||||
import org.conscrypt.Conscrypt;
|
||||
import org.conscrypt.OpenSSLProvider;
|
||||
import org.eclipse.jetty.alpn.server.ALPNServerConnection;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
|
@ -41,7 +41,7 @@ public class ConscryptServerALPNProcessor implements ALPNProcessor.Server
|
|||
@Override
|
||||
public void init()
|
||||
{
|
||||
if (Security.getProvider("Conscrypt")==null)
|
||||
if (Security.getProvider("Conscrypt") == null)
|
||||
{
|
||||
Security.addProvider(new OpenSSLProvider());
|
||||
if (LOG.isDebugEnabled())
|
||||
|
@ -56,13 +56,11 @@ public class ConscryptServerALPNProcessor implements ALPNProcessor.Server
|
|||
}
|
||||
|
||||
@Override
|
||||
public void configure(SSLEngine sslEngine,Connection connection)
|
||||
public void configure(SSLEngine sslEngine, Connection connection)
|
||||
{
|
||||
try
|
||||
{
|
||||
Method method = sslEngine.getClass().getMethod("setHandshakeApplicationProtocolSelector", BiFunction.class);
|
||||
method.setAccessible(true);
|
||||
method.invoke(sslEngine,new ALPNCallback((ALPNServerConnection)connection));
|
||||
Conscrypt.setApplicationProtocolSelector(sslEngine, new ALPNCallback((ALPNServerConnection)connection));
|
||||
}
|
||||
catch (RuntimeException x)
|
||||
{
|
||||
|
@ -74,23 +72,31 @@ public class ConscryptServerALPNProcessor implements ALPNProcessor.Server
|
|||
}
|
||||
}
|
||||
|
||||
private final class ALPNCallback implements BiFunction<SSLEngine,List<String>,String>, SslHandshakeListener
|
||||
private final class ALPNCallback extends ApplicationProtocolSelector implements SslHandshakeListener
|
||||
{
|
||||
private final ALPNServerConnection alpnConnection;
|
||||
|
||||
|
||||
private ALPNCallback(ALPNServerConnection connection)
|
||||
{
|
||||
alpnConnection = connection;
|
||||
alpnConnection = connection;
|
||||
((DecryptedEndPoint)alpnConnection.getEndPoint()).getSslConnection().addHandshakeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String apply(SSLEngine engine, List<String> protocols)
|
||||
public String selectApplicationProtocol(SSLEngine engine, List<String> protocols)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("apply {} {}", alpnConnection, protocols);
|
||||
alpnConnection.select(protocols);
|
||||
return alpnConnection.getProtocol();
|
||||
String protocol = alpnConnection.getProtocol();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Selected {} among {} for {}", protocol, protocols, alpnConnection);
|
||||
return protocol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String selectApplicationProtocol(SSLSocket socket, List<String> protocols)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -99,7 +105,7 @@ public class ConscryptServerALPNProcessor implements ALPNProcessor.Server
|
|||
String protocol = alpnConnection.getProtocol();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("TLS handshake succeeded, protocol={} for {}", protocol, alpnConnection);
|
||||
if (protocol ==null)
|
||||
if (protocol == null)
|
||||
alpnConnection.unsupported();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,72 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.alpn.conscrypt.server;
|
||||
|
||||
import java.security.Security;
|
||||
|
||||
import org.conscrypt.OpenSSLProvider;
|
||||
import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory;
|
||||
import org.eclipse.jetty.http2.HTTP2Cipher;
|
||||
import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
import org.eclipse.jetty.server.HttpConnectionFactory;
|
||||
import org.eclipse.jetty.server.SecureRequestCustomizer;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.server.SslConnectionFactory;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
|
||||
/**
|
||||
* Test server that verifies that the Conscrypt ALPN mechanism works.
|
||||
*/
|
||||
public class ConscryptHTTP2Server
|
||||
{
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
Security.addProvider(new OpenSSLProvider());
|
||||
|
||||
Server server = new Server();
|
||||
|
||||
HttpConfiguration httpsConfig = new HttpConfiguration();
|
||||
httpsConfig.setSecureScheme("https");
|
||||
httpsConfig.setSecurePort(8443);
|
||||
httpsConfig.setSendXPoweredBy(true);
|
||||
httpsConfig.setSendServerVersion(true);
|
||||
httpsConfig.addCustomizer(new SecureRequestCustomizer());
|
||||
|
||||
SslContextFactory sslContextFactory = new SslContextFactory();
|
||||
sslContextFactory.setProvider("Conscrypt");
|
||||
sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
|
||||
sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
|
||||
sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
|
||||
sslContextFactory.setCipherComparator(HTTP2Cipher.COMPARATOR);
|
||||
|
||||
HttpConnectionFactory http = new HttpConnectionFactory(httpsConfig);
|
||||
HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(httpsConfig);
|
||||
ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory();
|
||||
alpn.setDefaultProtocol(http.getProtocol());
|
||||
SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory, alpn.getProtocol());
|
||||
|
||||
ServerConnector http2Connector = new ServerConnector(server, ssl, alpn, h2, http);
|
||||
http2Connector.setPort(8443);
|
||||
server.addConnector(http2Connector);
|
||||
|
||||
server.start();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.alpn.conscrypt.server;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.Security;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.conscrypt.OpenSSLProvider;
|
||||
import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.http2.client.HTTP2Client;
|
||||
import org.eclipse.jetty.http2.client.http.HttpClientTransportOverHTTP2;
|
||||
import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
|
||||
import org.eclipse.jetty.io.ClientConnector;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
import org.eclipse.jetty.server.HttpConnectionFactory;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.SecureRequestCustomizer;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.server.SslConnectionFactory;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.util.JavaVersion;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* Test server that verifies that the Conscrypt ALPN mechanism works for both server and client side
|
||||
*/
|
||||
public class ConscryptHTTP2ServerTest
|
||||
{
|
||||
static
|
||||
{
|
||||
Security.addProvider(new OpenSSLProvider());
|
||||
}
|
||||
|
||||
private Server server = new Server();
|
||||
|
||||
private SslContextFactory.Server newServerSslContextFactory()
|
||||
{
|
||||
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
|
||||
configureSslContextFactory(sslContextFactory);
|
||||
return sslContextFactory;
|
||||
}
|
||||
|
||||
private SslContextFactory.Client newClientSslContextFactory()
|
||||
{
|
||||
SslContextFactory.Client sslContextFactory = new SslContextFactory.Client();
|
||||
configureSslContextFactory(sslContextFactory);
|
||||
sslContextFactory.setEndpointIdentificationAlgorithm(null);
|
||||
return sslContextFactory;
|
||||
}
|
||||
|
||||
private void configureSslContextFactory(SslContextFactory sslContextFactory)
|
||||
{
|
||||
Path path = Paths.get("src", "test", "resources");
|
||||
File keys = path.resolve("keystore").toFile();
|
||||
sslContextFactory.setKeyStorePath(keys.getAbsolutePath());
|
||||
sslContextFactory.setKeyManagerPassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
|
||||
sslContextFactory.setTrustStorePath(keys.getAbsolutePath());
|
||||
sslContextFactory.setTrustStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
|
||||
sslContextFactory.setProvider("Conscrypt");
|
||||
if (JavaVersion.VERSION.getPlatform() < 9)
|
||||
{
|
||||
// Conscrypt enables TLSv1.3 by default but it's not supported in Java 8.
|
||||
sslContextFactory.addExcludeProtocols("TLSv1.3");
|
||||
}
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void startServer() throws Exception
|
||||
{
|
||||
HttpConfiguration httpsConfig = new HttpConfiguration();
|
||||
httpsConfig.setSecureScheme("https");
|
||||
|
||||
httpsConfig.setSendXPoweredBy(true);
|
||||
httpsConfig.setSendServerVersion(true);
|
||||
httpsConfig.addCustomizer(new SecureRequestCustomizer());
|
||||
|
||||
HttpConnectionFactory http = new HttpConnectionFactory(httpsConfig);
|
||||
HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(httpsConfig);
|
||||
ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory();
|
||||
alpn.setDefaultProtocol(http.getProtocol());
|
||||
SslConnectionFactory ssl = new SslConnectionFactory(newServerSslContextFactory(), alpn.getProtocol());
|
||||
|
||||
ServerConnector http2Connector = new ServerConnector(server, ssl, alpn, h2, http);
|
||||
http2Connector.setPort(0);
|
||||
server.addConnector(http2Connector);
|
||||
|
||||
server.setHandler(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
response.setStatus(200);
|
||||
baseRequest.setHandled(true);
|
||||
}
|
||||
});
|
||||
|
||||
server.start();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void stopServer() throws Exception
|
||||
{
|
||||
if (server != null)
|
||||
server.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleRequest() throws Exception
|
||||
{
|
||||
ClientConnector clientConnector = new ClientConnector();
|
||||
clientConnector.setSslContextFactory(newClientSslContextFactory());
|
||||
HTTP2Client h2Client = new HTTP2Client(clientConnector);
|
||||
HttpClient client = new HttpClient(new HttpClientTransportOverHTTP2(h2Client));
|
||||
client.start();
|
||||
try
|
||||
{
|
||||
int port = ((ServerConnector)server.getConnectors()[0]).getLocalPort();
|
||||
ContentResponse contentResponse = client.GET("https://localhost:" + port);
|
||||
assertEquals(200, contentResponse.getStatus());
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
|
@ -1,82 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.alpn.java.client;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpURI;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.http.MetaData;
|
||||
import org.eclipse.jetty.http2.api.Session;
|
||||
import org.eclipse.jetty.http2.api.Stream;
|
||||
import org.eclipse.jetty.http2.client.HTTP2Client;
|
||||
import org.eclipse.jetty.http2.frames.DataFrame;
|
||||
import org.eclipse.jetty.http2.frames.HeadersFrame;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.FuturePromise;
|
||||
import org.eclipse.jetty.util.Jetty;
|
||||
import org.eclipse.jetty.util.Promise;
|
||||
|
||||
public class JDK9HTTP2Client
|
||||
{
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
HTTP2Client client = new HTTP2Client();
|
||||
client.start();
|
||||
|
||||
String host = "webtide.com";
|
||||
int port = 443;
|
||||
|
||||
FuturePromise<Session> sessionPromise = new FuturePromise<>();
|
||||
client.connect(client.getClientConnector().getSslContextFactory(), new InetSocketAddress(host, port), new Session.Listener.Adapter(), sessionPromise);
|
||||
Session session = sessionPromise.get(5, TimeUnit.SECONDS);
|
||||
|
||||
HttpFields requestFields = new HttpFields();
|
||||
requestFields.put("User-Agent", client.getClass().getName() + "/" + Jetty.VERSION);
|
||||
MetaData.Request metaData = new MetaData.Request("GET", new HttpURI("https://" + host + ":" + port + "/"), HttpVersion.HTTP_2, requestFields);
|
||||
HeadersFrame headersFrame = new HeadersFrame(metaData, null, true);
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
session.newStream(headersFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public void onHeaders(Stream stream, HeadersFrame frame)
|
||||
{
|
||||
System.err.println(frame);
|
||||
if (frame.isEndStream())
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onData(Stream stream, DataFrame frame, Callback callback)
|
||||
{
|
||||
System.err.println(frame);
|
||||
callback.succeeded();
|
||||
if (frame.isEndStream())
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
latch.await(5, TimeUnit.SECONDS);
|
||||
|
||||
client.stop();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.alpn.java.client;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpURI;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.http.MetaData;
|
||||
import org.eclipse.jetty.http2.api.Session;
|
||||
import org.eclipse.jetty.http2.api.Stream;
|
||||
import org.eclipse.jetty.http2.client.HTTP2Client;
|
||||
import org.eclipse.jetty.http2.frames.DataFrame;
|
||||
import org.eclipse.jetty.http2.frames.HeadersFrame;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.FuturePromise;
|
||||
import org.eclipse.jetty.util.Jetty;
|
||||
import org.eclipse.jetty.util.Promise;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.junit.jupiter.api.Assumptions;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class JDK9HTTP2ClientTest
|
||||
{
|
||||
@Tag("external")
|
||||
@Test
|
||||
public void testJDK9HTTP2Client() throws Exception
|
||||
{
|
||||
String host = "webtide.com";
|
||||
int port = 443;
|
||||
|
||||
Assumptions.assumeTrue(canConnectTo(host, port));
|
||||
|
||||
HTTP2Client client = new HTTP2Client();
|
||||
try
|
||||
{
|
||||
SslContextFactory sslContextFactory = new SslContextFactory.Client();
|
||||
client.addBean(sslContextFactory);
|
||||
client.start();
|
||||
|
||||
FuturePromise<Session> sessionPromise = new FuturePromise<>();
|
||||
client.connect(sslContextFactory, new InetSocketAddress(host, port), new Session.Listener.Adapter(), sessionPromise);
|
||||
Session session = sessionPromise.get(15, TimeUnit.SECONDS);
|
||||
|
||||
HttpFields requestFields = new HttpFields();
|
||||
requestFields.put("User-Agent", client.getClass().getName() + "/" + Jetty.VERSION);
|
||||
MetaData.Request metaData = new MetaData.Request("GET", new HttpURI("https://" + host + ":" + port + "/"), HttpVersion.HTTP_2, requestFields);
|
||||
HeadersFrame headersFrame = new HeadersFrame(metaData, null, true);
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
session.newStream(headersFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public void onHeaders(Stream stream, HeadersFrame frame)
|
||||
{
|
||||
System.err.println(frame);
|
||||
if (frame.isEndStream())
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onData(Stream stream, DataFrame frame, Callback callback)
|
||||
{
|
||||
System.err.println(frame);
|
||||
callback.succeeded();
|
||||
if (frame.isEndStream())
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
latch.await(15, TimeUnit.SECONDS);
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean canConnectTo(String host, int port)
|
||||
{
|
||||
try
|
||||
{
|
||||
new Socket(host, port).close();
|
||||
return true;
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -59,7 +59,7 @@ public class JDK9ALPNTest
|
|||
HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(httpConfiguration);
|
||||
ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory();
|
||||
alpn.setDefaultProtocol(h1.getProtocol());
|
||||
connector = new ServerConnector(server, newSslContextFactory(), alpn, h1, h2);
|
||||
connector = new ServerConnector(server, newServerSslContextFactory(), alpn, h1, h2);
|
||||
server.addConnector(connector);
|
||||
server.setHandler(handler);
|
||||
server.start();
|
||||
|
@ -72,13 +72,12 @@ public class JDK9ALPNTest
|
|||
server.stop();
|
||||
}
|
||||
|
||||
private SslContextFactory newSslContextFactory()
|
||||
private SslContextFactory.Server newServerSslContextFactory()
|
||||
{
|
||||
SslContextFactory sslContextFactory = new SslContextFactory();
|
||||
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
|
||||
sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
|
||||
sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
|
||||
sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
|
||||
sslContextFactory.setIncludeProtocols("TLSv1.2");
|
||||
// The mandatory HTTP/2 cipher.
|
||||
sslContextFactory.setIncludeCipherSuites("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256");
|
||||
return sslContextFactory;
|
||||
|
@ -96,7 +95,7 @@ public class JDK9ALPNTest
|
|||
}
|
||||
});
|
||||
|
||||
SslContextFactory sslContextFactory = new SslContextFactory(true);
|
||||
SslContextFactory sslContextFactory = new SslContextFactory.Client(true);
|
||||
sslContextFactory.start();
|
||||
SSLContext sslContext = sslContextFactory.getSslContext();
|
||||
try (SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket("localhost", connector.getLocalPort()))
|
||||
|
@ -138,7 +137,7 @@ public class JDK9ALPNTest
|
|||
}
|
||||
});
|
||||
|
||||
SslContextFactory sslContextFactory = new SslContextFactory(true);
|
||||
SslContextFactory sslContextFactory = new SslContextFactory.Client(true);
|
||||
sslContextFactory.start();
|
||||
SSLContext sslContext = sslContextFactory.getSslContext();
|
||||
try (SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket("localhost", connector.getLocalPort()))
|
||||
|
|
|
@ -45,7 +45,7 @@ public class JDK9HTTP2Server
|
|||
httpsConfig.setSendServerVersion(true);
|
||||
httpsConfig.addCustomizer(new SecureRequestCustomizer());
|
||||
|
||||
SslContextFactory sslContextFactory = new SslContextFactory();
|
||||
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
|
||||
sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
|
||||
sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
|
||||
sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
|
||||
<Configure id="sslConnector" class="org.eclipse.jetty.server.ServerConnector">
|
||||
|
||||
|
|
|
@ -18,14 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.annotations;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.isIn;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -55,6 +47,15 @@ import org.eclipse.jetty.util.resource.Resource;
|
|||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.in;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@ExtendWith(WorkDirExtension.class)
|
||||
public class TestAnnotationParser
|
||||
{
|
||||
|
@ -142,7 +143,7 @@ public class TestAnnotationParser
|
|||
if (annotation == null || !"org.eclipse.jetty.annotations.Sample".equals(annotation))
|
||||
return;
|
||||
assertEquals("org.eclipse.jetty.annotations.ClassA",info.getClassInfo().getClassName());
|
||||
assertThat(info.getMethodName(), isIn(methods));
|
||||
assertThat(info.getMethodName(), is(in(methods)));
|
||||
assertEquals("org.eclipse.jetty.annotations.Sample",annotation);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ import org.eclipse.jetty.servlet.ServletMapping;
|
|||
import org.eclipse.jetty.servlet.Source;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.resource.PathResource;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.webapp.MetaInfConfiguration;
|
||||
import org.eclipse.jetty.webapp.WebAppClassLoader;
|
||||
|
@ -592,7 +593,7 @@ public class AntWebAppContext extends WebAppContext
|
|||
TaskLog.logWithTimestamp("Starting web application "+this.getDescriptor());
|
||||
|
||||
if (jettyEnvXml != null && jettyEnvXml.exists())
|
||||
getConfiguration(EnvConfiguration.class).setJettyEnvXml(Resource.toURL(jettyEnvXml));
|
||||
getConfiguration(EnvConfiguration.class).setJettyEnvResource(new PathResource(jettyEnvXml));
|
||||
|
||||
ClassLoader parentLoader = this.getClass().getClassLoader();
|
||||
if (parentLoader instanceof AntClassLoader)
|
||||
|
@ -608,7 +609,7 @@ public class AntWebAppContext extends WebAppContext
|
|||
//apply a context xml file if one was supplied
|
||||
if (contextXml != null)
|
||||
{
|
||||
XmlConfiguration xmlConfiguration = new XmlConfiguration(Resource.toURL(contextXml));
|
||||
XmlConfiguration xmlConfiguration = new XmlConfiguration(new PathResource(contextXml));
|
||||
TaskLog.log("Applying context xml file "+contextXml);
|
||||
xmlConfiguration.configure(this);
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
|||
import org.eclipse.jetty.server.handler.DefaultHandler;
|
||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||
import org.eclipse.jetty.util.Scanner;
|
||||
import org.eclipse.jetty.util.resource.PathResource;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
import org.xml.sax.SAXException;
|
||||
|
@ -451,7 +452,7 @@ public class ServerProxyImpl implements ServerProxy
|
|||
XmlConfiguration configuration;
|
||||
try
|
||||
{
|
||||
configuration = new XmlConfiguration(Resource.toURL(jettyXml));
|
||||
configuration = new XmlConfiguration(new PathResource(jettyXml));
|
||||
configuration.configure(server);
|
||||
}
|
||||
catch (MalformedURLException e)
|
||||
|
|
|
@ -186,7 +186,17 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-infinispan</artifactId>
|
||||
<artifactId>infinispan-common</artifactId>
|
||||
<version>10.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>infinispan-remote-query</artifactId>
|
||||
<version>10.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>infinispan-embedded-query</artifactId>
|
||||
<version>10.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
|
||||
<!-- =============================================================== -->
|
||||
<!-- Mixin the Weld / CDI classes to the class loader -->
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
|
||||
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
|
||||
|
||||
<Call name="prependServerClass">
|
||||
<Arg>-org.eclipse.jetty.util.Decorator</Arg>
|
||||
</Call>
|
||||
<Call name="prependServerClass">
|
||||
<Arg>-org.eclipse.jetty.util.DecoratedObjectFactory</Arg>
|
||||
</Call>
|
||||
<Call name="prependServerClass">
|
||||
<Arg>-org.eclipse.jetty.server.handler.ContextHandler.</Arg>
|
||||
</Call>
|
||||
<Call name="prependServerClass">
|
||||
<Arg>-org.eclipse.jetty.server.handler.ContextHandler</Arg>
|
||||
</Call>
|
||||
<Call name="prependServerClass">
|
||||
<Arg>-org.eclipse.jetty.servlet.ServletContextHandler</Arg>
|
||||
</Call>
|
||||
|
||||
<Get name="serverClasspathPattern">
|
||||
<Call name="add">
|
||||
<Arg>-org.eclipse.jetty.util.Decorator</Arg>
|
||||
</Call>
|
||||
<Call name="add">
|
||||
<Arg>-org.eclipse.jetty.util.DecoratedObjectFactory</Arg>
|
||||
</Call>
|
||||
<Call name="add">
|
||||
<Arg>-org.eclipse.jetty.server.handler.ContextHandler.</Arg>
|
||||
</Call>
|
||||
<Call name="add">
|
||||
<Arg>-org.eclipse.jetty.server.handler.ContextHandler</Arg>
|
||||
</Call>
|
||||
<Call name="add">
|
||||
<Arg>-org.eclipse.jetty.servlet.ServletContextHandler</Arg>
|
||||
</Call>
|
||||
</Get>
|
||||
</Configure>
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.cdi.core;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* Unit tests for class {@link NamedLiteral}.
|
||||
*
|
||||
* @see NamedLiteral
|
||||
*/
|
||||
public class NamedLiteralTest
|
||||
{
|
||||
|
||||
@Test
|
||||
public void testCreatesNamedLiteralWithNull()
|
||||
{
|
||||
assertEquals("", new NamedLiteral(null).value());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetValue()
|
||||
{
|
||||
assertEquals("a b", new NamedLiteral("a b").value());
|
||||
}
|
||||
|
||||
}
|
|
@ -112,6 +112,12 @@
|
|||
<artifactId>jetty-io</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-alpn-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-jmx</artifactId>
|
||||
|
|
|
@ -20,8 +20,10 @@ module org.eclipse.jetty.client
|
|||
{
|
||||
exports org.eclipse.jetty.client;
|
||||
exports org.eclipse.jetty.client.api;
|
||||
exports org.eclipse.jetty.client.dynamic;
|
||||
exports org.eclipse.jetty.client.http;
|
||||
exports org.eclipse.jetty.client.jmx to org.eclipse.jetty.jmx;
|
||||
exports org.eclipse.jetty.client.proxy;
|
||||
exports org.eclipse.jetty.client.util;
|
||||
|
||||
requires org.eclipse.jetty.http;
|
||||
|
@ -30,6 +32,8 @@ module org.eclipse.jetty.client
|
|||
|
||||
// Only required if using SPNEGO.
|
||||
requires static java.security.jgss;
|
||||
// Only required if using the dynamic transport.
|
||||
requires static org.eclipse.jetty.alpn.client;
|
||||
// Only required if using JMX.
|
||||
requires static org.eclipse.jetty.jmx;
|
||||
}
|
||||
|
|
|
@ -119,14 +119,14 @@ public abstract class AbstractConnectionPool implements ConnectionPool, Dumpable
|
|||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("newConnection {}/{} connections {}/{} pending", total+1, maxConnections, pending+1, maxPending);
|
||||
|
||||
destination.newConnection(new Promise<Connection>()
|
||||
destination.newConnection(new Promise<>()
|
||||
{
|
||||
@Override
|
||||
public void succeeded(Connection connection)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Connection {}/{} creation succeeded {}", total+1, maxConnections, connection);
|
||||
connections.add(-1,0);
|
||||
LOG.debug("Connection {}/{} creation succeeded {}", total + 1, maxConnections, connection);
|
||||
connections.add(-1, 0);
|
||||
onCreated(connection);
|
||||
proceed();
|
||||
}
|
||||
|
@ -135,8 +135,8 @@ public abstract class AbstractConnectionPool implements ConnectionPool, Dumpable
|
|||
public void failed(Throwable x)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Connection " + (total+1) + "/" + maxConnections + " creation failed", x);
|
||||
connections.add(-1,-1);
|
||||
LOG.debug("Connection " + (total + 1) + "/" + maxConnections + " creation failed", x);
|
||||
connections.add(-1, -1);
|
||||
requester.failed(x);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.util.ArrayList;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
@ -217,6 +218,8 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler
|
|||
path = request.getPath();
|
||||
}
|
||||
Request newRequest = client.copyRequest(request, requestURI);
|
||||
// Disable the timeout so that only the one from the initial request applies.
|
||||
newRequest.timeout(0, TimeUnit.MILLISECONDS);
|
||||
if (path != null)
|
||||
newRequest.path(path);
|
||||
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
/**
|
||||
* <p>A destination for those network transports that are duplex (e.g. HTTP/1.1 and FastCGI).</p>
|
||||
*
|
||||
* @see MultiplexHttpDestination
|
||||
*/
|
||||
public class DuplexHttpDestination extends HttpDestination
|
||||
{
|
||||
public DuplexHttpDestination(HttpClient client, Origin origin)
|
||||
{
|
||||
this(client, new Key(origin, null));
|
||||
}
|
||||
|
||||
public DuplexHttpDestination(HttpClient client, Key key)
|
||||
{
|
||||
super(client, key);
|
||||
}
|
||||
}
|
|
@ -28,6 +28,7 @@ import java.net.SocketAddress;
|
|||
import java.net.URI;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
|
@ -61,6 +62,7 @@ import org.eclipse.jetty.http.HttpParser;
|
|||
import org.eclipse.jetty.http.HttpScheme;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.ClientConnectionFactory;
|
||||
import org.eclipse.jetty.io.ClientConnector;
|
||||
import org.eclipse.jetty.io.MappedByteBufferPool;
|
||||
import org.eclipse.jetty.io.ssl.SslClientConnectionFactory;
|
||||
import org.eclipse.jetty.util.Fields;
|
||||
|
@ -122,19 +124,16 @@ public class HttpClient extends ContainerLifeCycle
|
|||
public static final String USER_AGENT = "Jetty/" + Jetty.VERSION;
|
||||
private static final Logger LOG = Log.getLogger(HttpClient.class);
|
||||
|
||||
private final ConcurrentMap<Origin, HttpDestination> destinations = new ConcurrentHashMap<>();
|
||||
private final ConcurrentMap<HttpDestination.Key, HttpDestination> destinations = new ConcurrentHashMap<>();
|
||||
private final ProtocolHandlers handlers = new ProtocolHandlers();
|
||||
private final List<Request.Listener> requestListeners = new ArrayList<>();
|
||||
private final Set<ContentDecoder.Factory> decoderFactories = new ContentDecoderFactorySet();
|
||||
private final ProxyConfiguration proxyConfig = new ProxyConfiguration();
|
||||
private final HttpClientTransport transport;
|
||||
private final SslContextFactory sslContextFactory;
|
||||
private final ClientConnector connector;
|
||||
private AuthenticationStore authenticationStore = new HttpAuthenticationStore();
|
||||
private CookieManager cookieManager;
|
||||
private CookieStore cookieStore;
|
||||
private Executor executor;
|
||||
private ByteBufferPool byteBufferPool;
|
||||
private Scheduler scheduler;
|
||||
private SocketAddressResolver resolver;
|
||||
private HttpField agentField = new HttpField(HttpHeader.USER_AGENT, USER_AGENT);
|
||||
private boolean followRedirects = true;
|
||||
|
@ -143,48 +142,28 @@ public class HttpClient extends ContainerLifeCycle
|
|||
private int requestBufferSize = 4096;
|
||||
private int responseBufferSize = 16384;
|
||||
private int maxRedirects = 8;
|
||||
private SocketAddress bindAddress;
|
||||
private long connectTimeout = 15000;
|
||||
private long addressResolutionTimeout = 15000;
|
||||
private long idleTimeout;
|
||||
private boolean tcpNoDelay = true;
|
||||
private boolean strictEventOrdering = false;
|
||||
private HttpField encodingField;
|
||||
private boolean removeIdleDestinations = false;
|
||||
private boolean connectBlocking = false;
|
||||
private String name = getClass().getSimpleName() + "@" + Integer.toHexString(hashCode());
|
||||
private HttpCompliance httpCompliance = HttpCompliance.RFC7230;
|
||||
private String defaultRequestContentType = "application/octet-stream";
|
||||
|
||||
/**
|
||||
* Creates a HttpClient instance that can perform requests to non-TLS destinations only
|
||||
* (that is, requests with the "http" scheme only, and not "https").
|
||||
*
|
||||
* @see #HttpClient(SslContextFactory) to perform requests to TLS destinations.
|
||||
* Creates a HttpClient instance that can perform HTTP/1.1 requests to non-TLS and TLS destinations.
|
||||
*/
|
||||
public HttpClient()
|
||||
{
|
||||
this(null);
|
||||
this(new HttpClientTransportOverHTTP());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a HttpClient instance that can perform requests to non-TLS and TLS destinations
|
||||
* (that is, both requests with the "http" scheme and with the "https" scheme).
|
||||
*
|
||||
* @param sslContextFactory the {@link SslContextFactory} that manages TLS encryption
|
||||
* @see #getSslContextFactory()
|
||||
*/
|
||||
public HttpClient(SslContextFactory sslContextFactory)
|
||||
public HttpClient(HttpClientTransport transport)
|
||||
{
|
||||
this(new HttpClientTransportOverHTTP(), sslContextFactory);
|
||||
}
|
||||
|
||||
public HttpClient(HttpClientTransport transport, SslContextFactory sslContextFactory)
|
||||
{
|
||||
this.transport = transport;
|
||||
this.transport = Objects.requireNonNull(transport);
|
||||
addBean(transport);
|
||||
this.sslContextFactory = sslContextFactory;
|
||||
addBean(sslContextFactory);
|
||||
this.connector = ((AbstractHttpClientTransport)transport).getBean(ClientConnector.class);
|
||||
addBean(handlers);
|
||||
addBean(decoderFactories);
|
||||
}
|
||||
|
@ -202,34 +181,34 @@ public class HttpClient extends ContainerLifeCycle
|
|||
|
||||
/**
|
||||
* @return the {@link SslContextFactory} that manages TLS encryption
|
||||
* @see #HttpClient(SslContextFactory)
|
||||
*/
|
||||
public SslContextFactory getSslContextFactory()
|
||||
public SslContextFactory.Client getSslContextFactory()
|
||||
{
|
||||
return sslContextFactory;
|
||||
return connector.getSslContextFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
Executor executor = getExecutor();
|
||||
if (executor == null)
|
||||
{
|
||||
QueuedThreadPool threadPool = new QueuedThreadPool();
|
||||
threadPool.setName(name);
|
||||
setExecutor(threadPool);
|
||||
}
|
||||
|
||||
ByteBufferPool byteBufferPool = getByteBufferPool();
|
||||
if (byteBufferPool == null)
|
||||
setByteBufferPool(new MappedByteBufferPool(2048,
|
||||
executor instanceof ThreadPool.SizedThreadPool
|
||||
? ((ThreadPool.SizedThreadPool)executor).getMaxThreads() / 2
|
||||
: ProcessorUtils.availableProcessors() * 2));
|
||||
|
||||
Scheduler scheduler = getScheduler();
|
||||
if (scheduler == null)
|
||||
setScheduler(new ScheduledExecutorScheduler(name + "-scheduler", false));
|
||||
|
||||
if (resolver == null)
|
||||
setSocketAddressResolver(new SocketAddressResolver.Async(executor, scheduler, getAddressResolutionTimeout()));
|
||||
setSocketAddressResolver(new SocketAddressResolver.Async(getExecutor(), getScheduler(), getAddressResolutionTimeout()));
|
||||
|
||||
handlers.put(new ContinueProtocolHandler());
|
||||
handlers.put(new RedirectProtocolHandler(this));
|
||||
|
@ -291,6 +270,8 @@ public class HttpClient extends ContainerLifeCycle
|
|||
*/
|
||||
public void setCookieStore(CookieStore cookieStore)
|
||||
{
|
||||
if (isStarted())
|
||||
throw new IllegalStateException();
|
||||
this.cookieStore = Objects.requireNonNull(cookieStore);
|
||||
this.cookieManager = newCookieManager();
|
||||
}
|
||||
|
@ -319,6 +300,8 @@ public class HttpClient extends ContainerLifeCycle
|
|||
*/
|
||||
public void setAuthenticationStore(AuthenticationStore authenticationStore)
|
||||
{
|
||||
if (isStarted())
|
||||
throw new IllegalStateException();
|
||||
this.authenticationStore = authenticationStore;
|
||||
}
|
||||
|
||||
|
@ -523,10 +506,11 @@ public class HttpClient extends ContainerLifeCycle
|
|||
*/
|
||||
public Destination getDestination(String scheme, String host, int port)
|
||||
{
|
||||
return destinationFor(scheme, host, port);
|
||||
Origin origin = createOrigin(scheme, host, port);
|
||||
return resolveDestination(new HttpDestination.Key(origin, null));
|
||||
}
|
||||
|
||||
protected HttpDestination destinationFor(String scheme, String host, int port)
|
||||
private Origin createOrigin(String scheme, String host, int port)
|
||||
{
|
||||
if (!HttpScheme.HTTP.is(scheme) && !HttpScheme.HTTPS.is(scheme) &&
|
||||
!HttpScheme.WS.is(scheme) && !HttpScheme.WSS.is(scheme))
|
||||
|
@ -536,13 +520,18 @@ public class HttpClient extends ContainerLifeCycle
|
|||
host = host.toLowerCase(Locale.ENGLISH);
|
||||
port = normalizePort(scheme, port);
|
||||
|
||||
Origin origin = new Origin(scheme, host, port);
|
||||
HttpDestination destination = destinations.get(origin);
|
||||
return new Origin(scheme, host, port);
|
||||
}
|
||||
|
||||
private HttpDestination resolveDestination(HttpDestination.Key key)
|
||||
{
|
||||
HttpDestination destination = destinations.get(key);
|
||||
if (destination == null)
|
||||
{
|
||||
destination = transport.newHttpDestination(origin);
|
||||
destination = getTransport().newHttpDestination(key);
|
||||
// Start the destination before it's published to other threads.
|
||||
addManaged(destination);
|
||||
HttpDestination existing = destinations.putIfAbsent(origin, destination);
|
||||
HttpDestination existing = destinations.putIfAbsent(key, destination);
|
||||
if (existing != null)
|
||||
{
|
||||
removeBean(destination);
|
||||
|
@ -560,7 +549,7 @@ public class HttpClient extends ContainerLifeCycle
|
|||
protected boolean removeDestination(HttpDestination destination)
|
||||
{
|
||||
removeBean(destination);
|
||||
return destinations.remove(destination.getOrigin(), destination);
|
||||
return destinations.remove(destination.getKey(), destination);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -573,7 +562,16 @@ public class HttpClient extends ContainerLifeCycle
|
|||
|
||||
protected void send(final HttpRequest request, List<Response.ResponseListener> listeners)
|
||||
{
|
||||
HttpDestination destination = destinationFor(request.getScheme(), request.getHost(), request.getPort());
|
||||
Origin origin = createOrigin(request.getScheme(), request.getHost(), request.getPort());
|
||||
HttpClientTransport transport = getTransport();
|
||||
HttpDestination.Key destinationKey = null;
|
||||
if (transport instanceof HttpClientTransport.Dynamic)
|
||||
destinationKey = ((HttpClientTransport.Dynamic)transport).newDestinationKey(request, origin);
|
||||
if (destinationKey == null)
|
||||
destinationKey = new HttpDestination.Key(origin, null);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Selected {} for {}", destinationKey, request);
|
||||
HttpDestination destination = resolveDestination(destinationKey);
|
||||
destination.send(request, listeners);
|
||||
}
|
||||
|
||||
|
@ -636,7 +634,7 @@ public class HttpClient extends ContainerLifeCycle
|
|||
*/
|
||||
public ByteBufferPool getByteBufferPool()
|
||||
{
|
||||
return byteBufferPool;
|
||||
return connector.getByteBufferPool();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -644,10 +642,7 @@ public class HttpClient extends ContainerLifeCycle
|
|||
*/
|
||||
public void setByteBufferPool(ByteBufferPool byteBufferPool)
|
||||
{
|
||||
if (isStarted())
|
||||
LOG.warn("Calling setByteBufferPool() while started is deprecated");
|
||||
updateBean(this.byteBufferPool, byteBufferPool);
|
||||
this.byteBufferPool = byteBufferPool;
|
||||
connector.setByteBufferPool(byteBufferPool);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -677,7 +672,7 @@ public class HttpClient extends ContainerLifeCycle
|
|||
@ManagedAttribute("The timeout, in milliseconds, for connect() operations")
|
||||
public long getConnectTimeout()
|
||||
{
|
||||
return connectTimeout;
|
||||
return connector.getConnectTimeout().toMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -686,7 +681,7 @@ public class HttpClient extends ContainerLifeCycle
|
|||
*/
|
||||
public void setConnectTimeout(long connectTimeout)
|
||||
{
|
||||
this.connectTimeout = connectTimeout;
|
||||
connector.setConnectTimeout(Duration.ofMillis(connectTimeout));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -718,7 +713,7 @@ public class HttpClient extends ContainerLifeCycle
|
|||
@ManagedAttribute("The timeout, in milliseconds, to close idle connections")
|
||||
public long getIdleTimeout()
|
||||
{
|
||||
return idleTimeout;
|
||||
return connector.getIdleTimeout().toMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -726,7 +721,7 @@ public class HttpClient extends ContainerLifeCycle
|
|||
*/
|
||||
public void setIdleTimeout(long idleTimeout)
|
||||
{
|
||||
this.idleTimeout = idleTimeout;
|
||||
connector.setIdleTimeout(Duration.ofMillis(idleTimeout));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -735,7 +730,7 @@ public class HttpClient extends ContainerLifeCycle
|
|||
*/
|
||||
public SocketAddress getBindAddress()
|
||||
{
|
||||
return bindAddress;
|
||||
return connector.getBindAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -745,7 +740,7 @@ public class HttpClient extends ContainerLifeCycle
|
|||
*/
|
||||
public void setBindAddress(SocketAddress bindAddress)
|
||||
{
|
||||
this.bindAddress = bindAddress;
|
||||
connector.setBindAddress(bindAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -790,7 +785,7 @@ public class HttpClient extends ContainerLifeCycle
|
|||
*/
|
||||
public Executor getExecutor()
|
||||
{
|
||||
return executor;
|
||||
return connector.getExecutor();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -798,10 +793,7 @@ public class HttpClient extends ContainerLifeCycle
|
|||
*/
|
||||
public void setExecutor(Executor executor)
|
||||
{
|
||||
if (isStarted())
|
||||
LOG.warn("Calling setExecutor() while started is deprecated");
|
||||
updateBean(this.executor, executor);
|
||||
this.executor = executor;
|
||||
connector.setExecutor(executor);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -809,7 +801,7 @@ public class HttpClient extends ContainerLifeCycle
|
|||
*/
|
||||
public Scheduler getScheduler()
|
||||
{
|
||||
return scheduler;
|
||||
return connector.getScheduler();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -817,10 +809,7 @@ public class HttpClient extends ContainerLifeCycle
|
|||
*/
|
||||
public void setScheduler(Scheduler scheduler)
|
||||
{
|
||||
if (isStarted())
|
||||
LOG.warn("Calling setScheduler() while started is deprecated");
|
||||
updateBean(this.scheduler, scheduler);
|
||||
this.scheduler = scheduler;
|
||||
connector.setScheduler(scheduler);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -837,7 +826,7 @@ public class HttpClient extends ContainerLifeCycle
|
|||
public void setSocketAddressResolver(SocketAddressResolver resolver)
|
||||
{
|
||||
if (isStarted())
|
||||
LOG.warn("Calling setSocketAddressResolver() while started is deprecated");
|
||||
throw new IllegalStateException();
|
||||
updateBean(this.resolver, resolver);
|
||||
this.resolver = resolver;
|
||||
}
|
||||
|
@ -929,7 +918,7 @@ public class HttpClient extends ContainerLifeCycle
|
|||
}
|
||||
|
||||
/**
|
||||
* @return the max number of HTTP redirects that are followed
|
||||
* @return the max number of HTTP redirects that are followed in a conversation
|
||||
* @see #setMaxRedirects(int)
|
||||
*/
|
||||
public int getMaxRedirects()
|
||||
|
@ -938,7 +927,7 @@ public class HttpClient extends ContainerLifeCycle
|
|||
}
|
||||
|
||||
/**
|
||||
* @param maxRedirects the max number of HTTP redirects that are followed
|
||||
* @param maxRedirects the max number of HTTP redirects that are followed in a conversation, or -1 for unlimited redirects
|
||||
* @see #setFollowRedirects(boolean)
|
||||
*/
|
||||
public void setMaxRedirects(int maxRedirects)
|
||||
|
@ -1059,7 +1048,7 @@ public class HttpClient extends ContainerLifeCycle
|
|||
@ManagedAttribute("Whether the connect() operation is blocking")
|
||||
public boolean isConnectBlocking()
|
||||
{
|
||||
return connectBlocking;
|
||||
return connector.isConnectBlocking();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1074,7 +1063,7 @@ public class HttpClient extends ContainerLifeCycle
|
|||
*/
|
||||
public void setConnectBlocking(boolean connectBlocking)
|
||||
{
|
||||
this.connectBlocking = connectBlocking;
|
||||
connector.setConnectBlocking(connectBlocking);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1109,7 +1098,7 @@ public class HttpClient extends ContainerLifeCycle
|
|||
|
||||
protected String normalizeHost(String host)
|
||||
{
|
||||
if (host != null && host.matches("\\[.*\\]"))
|
||||
if (host != null && host.matches("\\[.*]"))
|
||||
return host.substring(1, host.length() - 1);
|
||||
return host;
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ public interface HttpClientTransport extends ClientConnectionFactory
|
|||
* Sets the {@link HttpClient} instance on this transport.
|
||||
* <p>
|
||||
* This is needed because of a chicken-egg problem: in order to create the {@link HttpClient}
|
||||
* a {@link HttpClientTransport} is needed, that therefore cannot have a reference yet to the
|
||||
* a HttpClientTransport is needed, that therefore cannot have a reference yet to the
|
||||
* {@link HttpClient}.
|
||||
*
|
||||
* @param client the {@link HttpClient} that uses this transport.
|
||||
|
@ -56,15 +56,15 @@ public interface HttpClientTransport extends ClientConnectionFactory
|
|||
* {@link HttpDestination} controls the destination-connection cardinality: protocols like
|
||||
* HTTP have 1-N cardinality, while multiplexed protocols like HTTP/2 have a 1-1 cardinality.
|
||||
*
|
||||
* @param origin the destination origin
|
||||
* @param key the destination key
|
||||
* @return a new, transport-specific, {@link HttpDestination} object
|
||||
*/
|
||||
public HttpDestination newHttpDestination(Origin origin);
|
||||
public HttpDestination newHttpDestination(HttpDestination.Key key);
|
||||
|
||||
/**
|
||||
* Establishes a physical connection to the given {@code address}.
|
||||
*
|
||||
* @param address the address to connect to
|
||||
* @param address the address to connect to
|
||||
* @param context the context information to establish the connection
|
||||
*/
|
||||
public void connect(InetSocketAddress address, Map<String, Object> context);
|
||||
|
@ -78,4 +78,20 @@ public interface HttpClientTransport extends ClientConnectionFactory
|
|||
* @param factory the factory for ConnectionPool instances
|
||||
*/
|
||||
public void setConnectionPoolFactory(ConnectionPool.Factory factory);
|
||||
|
||||
/**
|
||||
* Specifies whether a {@link HttpClientTransport} is dynamic.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface Dynamic
|
||||
{
|
||||
/**
|
||||
* Creates a new Key with the given request and origin.
|
||||
*
|
||||
* @param request the request that triggers the creation of the Key
|
||||
* @param origin the origin of the server for the request
|
||||
* @return a Key that identifies a destination
|
||||
*/
|
||||
public HttpDestination.Key newDestinationKey(HttpRequest request, Origin origin);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,6 @@ import java.util.concurrent.TimeUnit;
|
|||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.eclipse.jetty.client.api.Authentication;
|
||||
import org.eclipse.jetty.client.api.Connection;
|
||||
import org.eclipse.jetty.client.api.ContentProvider;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.api.Response;
|
||||
|
@ -38,7 +37,7 @@ import org.eclipse.jetty.util.HttpCookieStore;
|
|||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
public abstract class HttpConnection implements Connection
|
||||
public abstract class HttpConnection implements IConnection
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(HttpConnection.class);
|
||||
|
||||
|
@ -80,8 +79,6 @@ public abstract class HttpConnection implements Connection
|
|||
httpRequest.abort(result.failure);
|
||||
}
|
||||
|
||||
protected abstract SendFailure send(HttpExchange exchange);
|
||||
|
||||
protected void normalizeRequest(Request request)
|
||||
{
|
||||
HttpVersion version = request.getVersion();
|
||||
|
|
|
@ -25,9 +25,13 @@ import java.util.concurrent.ConcurrentLinkedDeque;
|
|||
|
||||
import org.eclipse.jetty.client.api.Response;
|
||||
import org.eclipse.jetty.util.AttributesMap;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
public class HttpConversation extends AttributesMap
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(HttpConversation.class);
|
||||
|
||||
private final Deque<HttpExchange> exchanges = new ConcurrentLinkedDeque<>();
|
||||
private volatile List<Response.ResponseListener> listeners;
|
||||
|
||||
|
@ -118,6 +122,7 @@ public class HttpConversation extends AttributesMap
|
|||
HttpExchange lastExchange = exchanges.peekLast();
|
||||
if (firstExchange == lastExchange)
|
||||
{
|
||||
// We don't have a conversation, just a single request.
|
||||
if (overrideListener != null)
|
||||
listeners.add(overrideListener);
|
||||
else
|
||||
|
@ -125,13 +130,16 @@ public class HttpConversation extends AttributesMap
|
|||
}
|
||||
else
|
||||
{
|
||||
// Order is important, we want to notify the last exchange first
|
||||
// We have a conversation (e.g. redirect, authentication).
|
||||
// Order is important, we want to notify the last exchange first.
|
||||
listeners.addAll(lastExchange.getResponseListeners());
|
||||
if (overrideListener != null)
|
||||
listeners.add(overrideListener);
|
||||
else
|
||||
listeners.addAll(firstExchange.getResponseListeners());
|
||||
}
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Exchanges in conversation {}, override={}, listeners={}", exchanges.size(), overrideListener, listeners);
|
||||
this.listeners = listeners;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,20 +23,25 @@ import java.io.IOException;
|
|||
import java.nio.channels.AsynchronousCloseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.eclipse.jetty.client.api.Connection;
|
||||
import org.eclipse.jetty.client.api.Destination;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.api.Response;
|
||||
import org.eclipse.jetty.client.dynamic.HttpClientTransportDynamic;
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.io.ClientConnectionFactory;
|
||||
import org.eclipse.jetty.io.CyclicTimeout;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.util.BlockingArrayQueue;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.HostPort;
|
||||
|
@ -52,12 +57,12 @@ import org.eclipse.jetty.util.thread.Scheduler;
|
|||
import org.eclipse.jetty.util.thread.Sweeper;
|
||||
|
||||
@ManagedObject
|
||||
public abstract class HttpDestination extends ContainerLifeCycle implements Destination, Closeable, Callback, Dumpable
|
||||
public class HttpDestination extends ContainerLifeCycle implements Destination, Closeable, Callback, Dumpable
|
||||
{
|
||||
protected static final Logger LOG = Log.getLogger(HttpDestination.class);
|
||||
|
||||
private final HttpClient client;
|
||||
private final Origin origin;
|
||||
private final Key key;
|
||||
private final Queue<HttpExchange> exchanges;
|
||||
private final RequestNotifier requestNotifier;
|
||||
private final ResponseNotifier responseNotifier;
|
||||
|
@ -67,21 +72,38 @@ public abstract class HttpDestination extends ContainerLifeCycle implements Dest
|
|||
private final TimeoutTask timeout;
|
||||
private ConnectionPool connectionPool;
|
||||
|
||||
public HttpDestination(HttpClient client, Origin origin)
|
||||
public HttpDestination(HttpClient client, Key key)
|
||||
{
|
||||
this(client, key, Function.identity());
|
||||
}
|
||||
|
||||
public HttpDestination(HttpClient client, Key key, Function<ClientConnectionFactory, ClientConnectionFactory> factoryFn)
|
||||
{
|
||||
this.client = client;
|
||||
this.origin = origin;
|
||||
this.key = key;
|
||||
|
||||
this.exchanges = newExchangeQueue(client);
|
||||
|
||||
this.requestNotifier = new RequestNotifier(client);
|
||||
this.responseNotifier = new ResponseNotifier();
|
||||
|
||||
|
||||
this.timeout = new TimeoutTask(client.getScheduler());
|
||||
|
||||
String host = HostPort.normalizeHost(getHost());
|
||||
if (!client.isDefaultPort(getScheme(), getPort()))
|
||||
host += ":" + getPort();
|
||||
hostField = new HttpField(HttpHeader.HOST, host);
|
||||
|
||||
ProxyConfiguration proxyConfig = client.getProxyConfiguration();
|
||||
proxy = proxyConfig.match(origin);
|
||||
ClientConnectionFactory connectionFactory = client.getTransport();
|
||||
this.proxy = proxyConfig.match(getOrigin());
|
||||
|
||||
this.connectionFactory = factoryFn.apply(createClientConnectionFactory());
|
||||
}
|
||||
|
||||
private ClientConnectionFactory createClientConnectionFactory()
|
||||
{
|
||||
ProxyConfiguration.Proxy proxy = getProxy();
|
||||
ClientConnectionFactory connectionFactory = getHttpClient().getTransport();
|
||||
if (proxy != null)
|
||||
{
|
||||
connectionFactory = proxy.newClientConnectionFactory(connectionFactory);
|
||||
|
@ -93,12 +115,7 @@ public abstract class HttpDestination extends ContainerLifeCycle implements Dest
|
|||
if (isSecure())
|
||||
connectionFactory = newSslClientConnectionFactory(connectionFactory);
|
||||
}
|
||||
this.connectionFactory = connectionFactory;
|
||||
|
||||
String host = HostPort.normalizeHost(getHost());
|
||||
if (!client.isDefaultPort(getScheme(), getPort()))
|
||||
host += ":" + getPort();
|
||||
hostField = new HttpField(HttpHeader.HOST, host);
|
||||
return connectionFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -147,9 +164,14 @@ public abstract class HttpDestination extends ContainerLifeCycle implements Dest
|
|||
return client;
|
||||
}
|
||||
|
||||
public Key getKey()
|
||||
{
|
||||
return key;
|
||||
}
|
||||
|
||||
public Origin getOrigin()
|
||||
{
|
||||
return origin;
|
||||
return key.origin;
|
||||
}
|
||||
|
||||
public Queue<HttpExchange> getHttpExchanges()
|
||||
|
@ -181,7 +203,7 @@ public abstract class HttpDestination extends ContainerLifeCycle implements Dest
|
|||
@ManagedAttribute(value = "The destination scheme", readonly = true)
|
||||
public String getScheme()
|
||||
{
|
||||
return origin.getScheme();
|
||||
return getOrigin().getScheme();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -190,14 +212,14 @@ public abstract class HttpDestination extends ContainerLifeCycle implements Dest
|
|||
{
|
||||
// InetSocketAddress.getHostString() transforms the host string
|
||||
// in case of IPv6 addresses, so we return the original host string
|
||||
return origin.getAddress().getHost();
|
||||
return getOrigin().getAddress().getHost();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ManagedAttribute(value = "The destination port", readonly = true)
|
||||
public int getPort()
|
||||
{
|
||||
return origin.getAddress().getPort();
|
||||
return getOrigin().getAddress().getPort();
|
||||
}
|
||||
|
||||
@ManagedAttribute(value = "The number of queued requests", readonly = true)
|
||||
|
@ -208,7 +230,7 @@ public abstract class HttpDestination extends ContainerLifeCycle implements Dest
|
|||
|
||||
public Origin.Address getConnectAddress()
|
||||
{
|
||||
return proxy == null ? origin.getAddress() : proxy.getAddress();
|
||||
return proxy == null ? getOrigin().getAddress() : proxy.getAddress();
|
||||
}
|
||||
|
||||
public HttpField getHostField()
|
||||
|
@ -235,7 +257,7 @@ public abstract class HttpDestination extends ContainerLifeCycle implements Dest
|
|||
}
|
||||
|
||||
protected void send(HttpRequest request, List<Response.ResponseListener> listeners)
|
||||
{
|
||||
{
|
||||
if (!getScheme().equalsIgnoreCase(request.getScheme()))
|
||||
throw new IllegalArgumentException("Invalid request scheme " + request.getScheme() + " for destination " + this);
|
||||
if (!getHost().equalsIgnoreCase(request.getHost()))
|
||||
|
@ -343,7 +365,7 @@ public abstract class HttpDestination extends ContainerLifeCycle implements Dest
|
|||
}
|
||||
else
|
||||
{
|
||||
SendFailure result = send(connection, exchange);
|
||||
SendFailure result = ((IConnection)connection).send(exchange);
|
||||
if (result != null)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
|
@ -358,8 +380,6 @@ public abstract class HttpDestination extends ContainerLifeCycle implements Dest
|
|||
}
|
||||
}
|
||||
|
||||
protected abstract SendFailure send(Connection connection, HttpExchange exchange);
|
||||
|
||||
@Override
|
||||
public void newConnection(Promise<Connection> promise)
|
||||
{
|
||||
|
@ -476,7 +496,7 @@ public abstract class HttpDestination extends ContainerLifeCycle implements Dest
|
|||
|
||||
public String asString()
|
||||
{
|
||||
return origin.asString();
|
||||
return getKey().asString();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -490,8 +510,178 @@ public abstract class HttpDestination extends ContainerLifeCycle implements Dest
|
|||
exchanges.size(),
|
||||
connectionPool);
|
||||
}
|
||||
|
||||
// The TimeoutTask that expires when the next check of expiry is needed
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Multiplexed
|
||||
{
|
||||
void setMaxRequestsPerConnection(int maxRequestsPerConnection);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Class that groups the elements that uniquely identify a destination.</p>
|
||||
* <p>The elements are an {@link Origin}, a {@link Protocol} and an opaque
|
||||
* string that further distinguishes destinations that have the same origin
|
||||
* and protocol.</p>
|
||||
* <p>In general it is possible that, for the same origin, the server can
|
||||
* speak different protocols (for example, clear-text HTTP/1.1 and clear-text
|
||||
* HTTP/2), so the {@link Protocol} makes that distinction.</p>
|
||||
* <p>Furthermore, it may be desirable to have different destinations for
|
||||
* the same origin and protocol (for example, when using the PROXY protocol
|
||||
* in a reverse proxy server, you want to be able to map the client ip:port
|
||||
* to the destination {@code kind}, so that all the connections to the server
|
||||
* associated to that destination can specify the PROXY protocol bytes for
|
||||
* that particular client connection.</p>
|
||||
*/
|
||||
public static class Key
|
||||
{
|
||||
private final Origin origin;
|
||||
private final Protocol protocol;
|
||||
private final String kind;
|
||||
|
||||
/**
|
||||
* Creates a Key with the given origin and protocol and a {@code null} kind.
|
||||
*
|
||||
* @param origin the origin
|
||||
* @param protocol the protocol
|
||||
*/
|
||||
public Key(Origin origin, Protocol protocol)
|
||||
{
|
||||
this(origin, protocol, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Key with the given origin and protocol and kind.
|
||||
*
|
||||
* @param origin the origin
|
||||
* @param protocol the protocol
|
||||
* @param kind the opaque kind
|
||||
*/
|
||||
public Key(Origin origin, Protocol protocol, String kind)
|
||||
{
|
||||
this.origin = origin;
|
||||
this.protocol = protocol;
|
||||
this.kind = kind;
|
||||
}
|
||||
|
||||
public Origin getOrigin()
|
||||
{
|
||||
return origin;
|
||||
}
|
||||
|
||||
public Protocol getProtocol()
|
||||
{
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public String getKind()
|
||||
{
|
||||
return kind;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null || getClass() != obj.getClass())
|
||||
return false;
|
||||
Key that = (Key)obj;
|
||||
return origin.equals(that.origin) &&
|
||||
Objects.equals(protocol, that.protocol) &&
|
||||
Objects.equals(kind, that.kind);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(origin, protocol, kind);
|
||||
}
|
||||
|
||||
public String asString()
|
||||
{
|
||||
return String.format("%s|%s,kind=%s",
|
||||
origin.asString(),
|
||||
protocol == null ? "null" : protocol.asString(),
|
||||
kind);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s@%x[%s]", getClass().getSimpleName(), hashCode(), asString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>The representation of a network protocol.</p>
|
||||
* <p>A network protocol may have multiple protocol <em>names</em>
|
||||
* associated to it, for example {@code ["h2", "h2-17", "h2-16"]}.</p>
|
||||
* <p>A Protocol is then rendered into a {@link ClientConnectionFactory}
|
||||
* chain, for example in
|
||||
* {@link HttpClientTransportDynamic#newConnection(EndPoint, Map)}.</p>
|
||||
*/
|
||||
public static class Protocol
|
||||
{
|
||||
private final List<String> protocols;
|
||||
private final boolean negotiate;
|
||||
|
||||
/**
|
||||
* Creates a Protocol with the given list of protocol names
|
||||
* and whether it should negotiate the protocol.
|
||||
*
|
||||
* @param protocols the protocol names
|
||||
* @param negotiate whether the protocol should be negotiated
|
||||
*/
|
||||
public Protocol(List<String> protocols, boolean negotiate)
|
||||
{
|
||||
this.protocols = protocols;
|
||||
this.negotiate = negotiate;
|
||||
}
|
||||
|
||||
public List<String> getProtocols()
|
||||
{
|
||||
return protocols;
|
||||
}
|
||||
|
||||
public boolean isNegotiate()
|
||||
{
|
||||
return negotiate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null || getClass() != obj.getClass())
|
||||
return false;
|
||||
Protocol that = (Protocol)obj;
|
||||
return protocols.equals(that.protocols) && negotiate == that.negotiate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(protocols, negotiate);
|
||||
}
|
||||
|
||||
public String asString()
|
||||
{
|
||||
return String.format("proto=%s,nego=%b", protocols, negotiate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s@%x[%s]", getClass().getSimpleName(), hashCode(), asString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This class enforces the total timeout for exchanges that are still in the queue.
|
||||
* The total timeout for exchanges that are not in the destination queue is enforced
|
||||
* by {@link HttpChannel}.
|
||||
*/
|
||||
private class TimeoutTask extends CyclicTimeout
|
||||
{
|
||||
private final AtomicLong nextTimeout = new AtomicLong(Long.MAX_VALUE);
|
||||
|
@ -504,10 +694,13 @@ public abstract class HttpDestination extends ContainerLifeCycle implements Dest
|
|||
@Override
|
||||
public void onTimeoutExpired()
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} timeout expired", this);
|
||||
|
||||
nextTimeout.set(Long.MAX_VALUE);
|
||||
long now = System.nanoTime();
|
||||
long nextExpiresAt = Long.MAX_VALUE;
|
||||
|
||||
|
||||
// Check all queued exchanges for those that have expired
|
||||
// and to determine when the next check must be.
|
||||
for (HttpExchange exchange : exchanges)
|
||||
|
@ -521,7 +714,7 @@ public abstract class HttpDestination extends ContainerLifeCycle implements Dest
|
|||
else if (expiresAt < nextExpiresAt)
|
||||
nextExpiresAt = expiresAt;
|
||||
}
|
||||
|
||||
|
||||
if (nextExpiresAt < Long.MAX_VALUE && client.isRunning())
|
||||
schedule(nextExpiresAt);
|
||||
}
|
||||
|
@ -536,12 +729,16 @@ public abstract class HttpDestination extends ContainerLifeCycle implements Dest
|
|||
if (timeoutAt != expiresAt)
|
||||
{
|
||||
long delay = expiresAt - System.nanoTime();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Scheduled timeout in {} ms", TimeUnit.NANOSECONDS.toMillis(delay));
|
||||
if (delay <= 0)
|
||||
{
|
||||
onTimeoutExpired();
|
||||
}
|
||||
else
|
||||
{
|
||||
schedule(delay, TimeUnit.NANOSECONDS);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} scheduled timeout in {} ms", this, TimeUnit.NANOSECONDS.toMillis(delay));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.net.URISyntaxException;
|
|||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
@ -61,10 +62,10 @@ public class HttpRedirector
|
|||
{
|
||||
private static final Logger LOG = Log.getLogger(HttpRedirector.class);
|
||||
private static final String SCHEME_REGEXP = "(^https?)";
|
||||
private static final String AUTHORITY_REGEXP = "([^/\\?#]+)";
|
||||
private static final String AUTHORITY_REGEXP = "([^/?#]+)";
|
||||
// The location may be relative so the scheme://authority part may be missing
|
||||
private static final String DESTINATION_REGEXP = "(" + SCHEME_REGEXP + "://" + AUTHORITY_REGEXP + ")?";
|
||||
private static final String PATH_REGEXP = "([^\\?#]*)";
|
||||
private static final String PATH_REGEXP = "([^?#]*)";
|
||||
private static final String QUERY_REGEXP = "([^#]*)";
|
||||
private static final String FRAGMENT_REGEXP = "(.*)";
|
||||
private static final Pattern URI_PATTERN = Pattern.compile(DESTINATION_REGEXP + PATH_REGEXP + QUERY_REGEXP + FRAGMENT_REGEXP);
|
||||
|
@ -101,11 +102,11 @@ public class HttpRedirector
|
|||
/**
|
||||
* Redirects the given {@code response}, blocking until the redirect is complete.
|
||||
*
|
||||
* @param request the original request that triggered the redirect
|
||||
* @param request the original request that triggered the redirect
|
||||
* @param response the response to the original request
|
||||
* @return a {@link Result} object containing the request to the redirected location and its response
|
||||
* @throws InterruptedException if the thread is interrupted while waiting for the redirect to complete
|
||||
* @throws ExecutionException if the redirect failed
|
||||
* @throws ExecutionException if the redirect failed
|
||||
* @see #redirect(Request, Response, Response.CompleteListener)
|
||||
*/
|
||||
public Result redirect(Request request, Response response) throws InterruptedException, ExecutionException
|
||||
|
@ -144,7 +145,7 @@ public class HttpRedirector
|
|||
/**
|
||||
* Redirects the given {@code response} asynchronously.
|
||||
*
|
||||
* @param request the original request that triggered the redirect
|
||||
* @param request the original request that triggered the redirect
|
||||
* @param response the response to the original request
|
||||
* @param listener the listener that receives response events
|
||||
* @return the request to the redirected location
|
||||
|
@ -292,7 +293,8 @@ public class HttpRedirector
|
|||
Integer redirects = (Integer)conversation.getAttribute(ATTRIBUTE);
|
||||
if (redirects == null)
|
||||
redirects = 0;
|
||||
if (redirects < client.getMaxRedirects())
|
||||
int maxRedirects = client.getMaxRedirects();
|
||||
if (maxRedirects < 0 || redirects < maxRedirects)
|
||||
{
|
||||
++redirects;
|
||||
conversation.setAttribute(ATTRIBUTE, redirects);
|
||||
|
@ -310,19 +312,17 @@ public class HttpRedirector
|
|||
try
|
||||
{
|
||||
Request redirect = client.copyRequest(httpRequest, location);
|
||||
// Disable the timeout so that only the one from the initial request applies.
|
||||
redirect.timeout(0, TimeUnit.MILLISECONDS);
|
||||
|
||||
// Use given method
|
||||
redirect.method(method);
|
||||
|
||||
redirect.onRequestBegin(new Request.BeginListener()
|
||||
redirect.onRequestBegin(request ->
|
||||
{
|
||||
@Override
|
||||
public void onBegin(Request redirect)
|
||||
{
|
||||
Throwable cause = httpRequest.getAbortCause();
|
||||
if (cause != null)
|
||||
redirect.abort(cause);
|
||||
}
|
||||
Throwable cause = httpRequest.getAbortCause();
|
||||
if (cause != null)
|
||||
request.abort(cause);
|
||||
});
|
||||
|
||||
redirect.send(listener);
|
||||
|
|
|
@ -18,10 +18,9 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
public abstract class PoolingHttpDestination extends HttpDestination
|
||||
import org.eclipse.jetty.client.api.Connection;
|
||||
|
||||
public interface IConnection extends Connection
|
||||
{
|
||||
public PoolingHttpDestination(HttpClient client, Origin origin)
|
||||
{
|
||||
super(client, origin);
|
||||
}
|
||||
public SendFailure send(HttpExchange exchange);
|
||||
}
|
|
@ -22,11 +22,10 @@ import java.io.IOException;
|
|||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jetty.client.api.Connection;
|
||||
|
@ -41,11 +40,9 @@ public class MultiplexConnectionPool extends AbstractConnectionPool implements C
|
|||
{
|
||||
private static final Logger LOG = Log.getLogger(MultiplexConnectionPool.class);
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
private final HttpDestination destination;
|
||||
private final Deque<Holder> idleConnections;
|
||||
private final Map<Connection, Holder> muxedConnections;
|
||||
private final Map<Connection, Holder> busyConnections;
|
||||
private final Map<Connection, Holder> activeConnections;
|
||||
private int maxMultiplex;
|
||||
|
||||
public MultiplexConnectionPool(HttpDestination destination, int maxConnections, Callback requester, int maxMultiplex)
|
||||
|
@ -53,8 +50,7 @@ public class MultiplexConnectionPool extends AbstractConnectionPool implements C
|
|||
super(destination, maxConnections, requester);
|
||||
this.destination = destination;
|
||||
this.idleConnections = new ArrayDeque<>(maxConnections);
|
||||
this.muxedConnections = new HashMap<>(maxConnections);
|
||||
this.busyConnections = new HashMap<>(maxConnections);
|
||||
this.activeConnections = new LinkedHashMap<>(maxConnections);
|
||||
this.maxMultiplex = maxMultiplex;
|
||||
}
|
||||
|
||||
|
@ -69,120 +65,73 @@ public class MultiplexConnectionPool extends AbstractConnectionPool implements C
|
|||
connection = activate();
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
|
||||
protected void lock()
|
||||
{
|
||||
lock.lock();
|
||||
}
|
||||
|
||||
protected void unlock()
|
||||
{
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxMultiplex()
|
||||
{
|
||||
lock();
|
||||
try
|
||||
synchronized (this)
|
||||
{
|
||||
return maxMultiplex;
|
||||
}
|
||||
finally
|
||||
{
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxMultiplex(int maxMultiplex)
|
||||
{
|
||||
lock();
|
||||
try
|
||||
synchronized (this)
|
||||
{
|
||||
this.maxMultiplex = maxMultiplex;
|
||||
}
|
||||
finally
|
||||
{
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive(Connection connection)
|
||||
{
|
||||
lock();
|
||||
try
|
||||
synchronized (this)
|
||||
{
|
||||
if (muxedConnections.containsKey(connection))
|
||||
return true;
|
||||
if (busyConnections.containsKey(connection))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
unlock();
|
||||
return activeConnections.containsKey(connection);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreated(Connection connection)
|
||||
{
|
||||
lock();
|
||||
try
|
||||
synchronized (this)
|
||||
{
|
||||
// Use "cold" connections as last.
|
||||
idleConnections.offer(new Holder(connection));
|
||||
}
|
||||
finally
|
||||
{
|
||||
unlock();
|
||||
}
|
||||
|
||||
idle(connection, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Connection activate()
|
||||
{
|
||||
Holder holder;
|
||||
lock();
|
||||
try
|
||||
Holder result = null;
|
||||
synchronized (this)
|
||||
{
|
||||
while (true)
|
||||
for (Holder holder : activeConnections.values())
|
||||
{
|
||||
if (muxedConnections.isEmpty())
|
||||
{
|
||||
holder = idleConnections.poll();
|
||||
if (holder == null)
|
||||
return null;
|
||||
muxedConnections.put(holder.connection, holder);
|
||||
}
|
||||
else
|
||||
{
|
||||
holder = muxedConnections.values().iterator().next();
|
||||
}
|
||||
|
||||
if (holder.count < maxMultiplex)
|
||||
{
|
||||
++holder.count;
|
||||
result = holder;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
muxedConnections.remove(holder.connection);
|
||||
busyConnections.put(holder.connection, holder);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
unlock();
|
||||
}
|
||||
|
||||
return active(holder.connection);
|
||||
if (result == null)
|
||||
{
|
||||
Holder holder = idleConnections.poll();
|
||||
if (holder == null)
|
||||
return null;
|
||||
activeConnections.put(holder.connection, holder);
|
||||
result = holder;
|
||||
}
|
||||
|
||||
++result.count;
|
||||
}
|
||||
return active(result.connection);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -191,16 +140,15 @@ public class MultiplexConnectionPool extends AbstractConnectionPool implements C
|
|||
boolean closed = isClosed();
|
||||
boolean idle = false;
|
||||
Holder holder;
|
||||
lock();
|
||||
try
|
||||
synchronized (this)
|
||||
{
|
||||
holder = muxedConnections.get(connection);
|
||||
holder = activeConnections.get(connection);
|
||||
if (holder != null)
|
||||
{
|
||||
int count = --holder.count;
|
||||
if (count == 0)
|
||||
{
|
||||
muxedConnections.remove(connection);
|
||||
activeConnections.remove(connection);
|
||||
if (!closed)
|
||||
{
|
||||
idleConnections.offerFirst(holder);
|
||||
|
@ -208,32 +156,7 @@ public class MultiplexConnectionPool extends AbstractConnectionPool implements C
|
|||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
holder = busyConnections.remove(connection);
|
||||
if (holder != null)
|
||||
{
|
||||
int count = --holder.count;
|
||||
if (!closed)
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
idleConnections.offerFirst(holder);
|
||||
idle = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
muxedConnections.put(connection, holder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
unlock();
|
||||
}
|
||||
|
||||
if (holder == null)
|
||||
return false;
|
||||
|
||||
|
@ -253,16 +176,13 @@ public class MultiplexConnectionPool extends AbstractConnectionPool implements C
|
|||
{
|
||||
boolean activeRemoved = true;
|
||||
boolean idleRemoved = false;
|
||||
lock();
|
||||
try
|
||||
synchronized (this)
|
||||
{
|
||||
Holder holder = muxedConnections.remove(connection);
|
||||
if (holder == null)
|
||||
holder = busyConnections.remove(connection);
|
||||
Holder holder = activeConnections.remove(connection);
|
||||
if (holder == null)
|
||||
{
|
||||
activeRemoved = false;
|
||||
for (Iterator<Holder> iterator = idleConnections.iterator(); iterator.hasNext();)
|
||||
for (Iterator<Holder> iterator = idleConnections.iterator(); iterator.hasNext(); )
|
||||
{
|
||||
holder = iterator.next();
|
||||
if (holder.connection == connection)
|
||||
|
@ -274,11 +194,6 @@ public class MultiplexConnectionPool extends AbstractConnectionPool implements C
|
|||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
unlock();
|
||||
}
|
||||
|
||||
if (activeRemoved || force)
|
||||
released(connection);
|
||||
boolean removed = activeRemoved || idleRemoved || force;
|
||||
|
@ -291,65 +206,39 @@ public class MultiplexConnectionPool extends AbstractConnectionPool implements C
|
|||
public void close()
|
||||
{
|
||||
super.close();
|
||||
|
||||
List<Connection> connections;
|
||||
lock();
|
||||
try
|
||||
synchronized (this)
|
||||
{
|
||||
connections = idleConnections.stream().map(holder -> holder.connection).collect(Collectors.toList());
|
||||
connections.addAll(muxedConnections.keySet());
|
||||
connections.addAll(busyConnections.keySet());
|
||||
connections.addAll(activeConnections.keySet());
|
||||
}
|
||||
finally
|
||||
{
|
||||
unlock();
|
||||
}
|
||||
|
||||
close(connections);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Appendable out, String indent) throws IOException
|
||||
{
|
||||
DumpableCollection busy;
|
||||
DumpableCollection muxed;
|
||||
DumpableCollection active;
|
||||
DumpableCollection idle;
|
||||
lock();
|
||||
try
|
||||
synchronized (this)
|
||||
{
|
||||
busy = new DumpableCollection("busy", new ArrayList<>(busyConnections.values()));
|
||||
muxed = new DumpableCollection("muxed", new ArrayList<>(muxedConnections.values()));
|
||||
active = new DumpableCollection("active", new ArrayList<>(activeConnections.values()));
|
||||
idle = new DumpableCollection("idle", new ArrayList<>(idleConnections));
|
||||
}
|
||||
finally
|
||||
{
|
||||
unlock();
|
||||
}
|
||||
|
||||
Dumpable.dumpObjects(out, indent, this, busy, muxed, idle);
|
||||
Dumpable.dumpObjects(out, indent, this, active, idle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sweep()
|
||||
{
|
||||
List<Connection> toSweep = new ArrayList<>();
|
||||
lock();
|
||||
try
|
||||
synchronized (this)
|
||||
{
|
||||
busyConnections.values().stream()
|
||||
.map(holder -> holder.connection)
|
||||
.filter(connection -> connection instanceof Sweeper.Sweepable)
|
||||
.collect(Collectors.toCollection(() -> toSweep));
|
||||
muxedConnections.values().stream()
|
||||
activeConnections.values().stream()
|
||||
.map(holder -> holder.connection)
|
||||
.filter(connection -> connection instanceof Sweeper.Sweepable)
|
||||
.collect(Collectors.toCollection(() -> toSweep));
|
||||
}
|
||||
finally
|
||||
{
|
||||
unlock();
|
||||
}
|
||||
|
||||
for (Connection connection : toSweep)
|
||||
{
|
||||
if (((Sweeper.Sweepable)connection).sweep())
|
||||
|
@ -363,34 +252,26 @@ public class MultiplexConnectionPool extends AbstractConnectionPool implements C
|
|||
dump());
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
int busySize;
|
||||
int muxedSize;
|
||||
int activeSize;
|
||||
int idleSize;
|
||||
lock();
|
||||
try
|
||||
synchronized (this)
|
||||
{
|
||||
busySize = busyConnections.size();
|
||||
muxedSize = muxedConnections.size();
|
||||
activeSize = activeConnections.size();
|
||||
idleSize = idleConnections.size();
|
||||
}
|
||||
finally
|
||||
{
|
||||
unlock();
|
||||
}
|
||||
return String.format("%s@%x[c=%d/%d,b=%d,m=%d,i=%d]",
|
||||
return String.format("%s@%x[connections=%d/%d,multiplex=%d,active=%d,idle=%d]",
|
||||
getClass().getSimpleName(),
|
||||
hashCode(),
|
||||
getConnectionCount(),
|
||||
getMaxConnectionCount(),
|
||||
busySize,
|
||||
muxedSize,
|
||||
getMaxMultiplex(),
|
||||
activeSize,
|
||||
idleSize);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,13 +18,33 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
public abstract class MultiplexHttpDestination extends HttpDestination
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.eclipse.jetty.io.ClientConnectionFactory;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
|
||||
/**
|
||||
* <p>A destination for those transports that are multiplex (e.g. HTTP/2).</p>
|
||||
* <p>Transports that negotiate the protocol, and therefore do not know in advance
|
||||
* whether they are duplex or multiplex, should use this class and when the
|
||||
* cardinality is known call {@link #setMaxRequestsPerConnection(int)} with
|
||||
* the proper cardinality.</p>
|
||||
* <p>If the cardinality is {@code 1}, the behavior of this class is similar
|
||||
* to that of {@link DuplexHttpDestination}.</p>
|
||||
*/
|
||||
public class MultiplexHttpDestination extends HttpDestination implements HttpDestination.Multiplexed
|
||||
{
|
||||
protected MultiplexHttpDestination(HttpClient client, Origin origin)
|
||||
public MultiplexHttpDestination(HttpClient client, Key key)
|
||||
{
|
||||
super(client, origin);
|
||||
this(client, key, Function.identity());
|
||||
}
|
||||
|
||||
public MultiplexHttpDestination(HttpClient client, Key key, Function<ClientConnectionFactory, ClientConnectionFactory> factoryFn)
|
||||
{
|
||||
super(client, key, factoryFn);
|
||||
}
|
||||
|
||||
@ManagedAttribute(value = "The maximum number of concurrent requests per connection")
|
||||
public int getMaxRequestsPerConnection()
|
||||
{
|
||||
ConnectionPool connectionPool = getConnectionPool();
|
||||
|
|
|
@ -75,7 +75,7 @@ public class Origin
|
|||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return asString();
|
||||
return String.format("%s@%x[%s]", getClass().getSimpleName(), hashCode(), asString());
|
||||
}
|
||||
|
||||
public static class Address
|
||||
|
|
|
@ -73,7 +73,7 @@ public class ProxyAuthenticationProtocolHandler extends AuthenticationProtocolHa
|
|||
@Override
|
||||
protected URI getAuthenticationURI(Request request)
|
||||
{
|
||||
HttpDestination destination = getHttpClient().destinationFor(request.getScheme(), request.getHost(), request.getPort());
|
||||
HttpDestination destination = (HttpDestination)getHttpClient().getDestination(request.getScheme(), request.getHost(), request.getPort());
|
||||
ProxyConfiguration.Proxy proxy = destination.getProxy();
|
||||
return proxy != null ? proxy.getURI() : request.getURI();
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ import org.eclipse.jetty.client.api.Request;
|
|||
import org.eclipse.jetty.client.api.Response;
|
||||
import org.eclipse.jetty.client.api.Result;
|
||||
import org.eclipse.jetty.io.CyclicTimeout;
|
||||
import org.eclipse.jetty.util.component.Destroyable;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.thread.Scheduler;
|
||||
|
@ -47,7 +46,7 @@ public class TimeoutCompleteListener extends CyclicTimeout implements Response.C
|
|||
{
|
||||
Request request = this.request.getAndSet(null);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Total timeout {} ms elapsed for {}", request.getTimeout(), request);
|
||||
LOG.debug("Total timeout {} ms elapsed for {} on {}", request.getTimeout(), request, this);
|
||||
if (request != null)
|
||||
request.abort(new TimeoutException("Total timeout " + request.getTimeout() + " ms elapsed"));
|
||||
}
|
||||
|
@ -60,7 +59,7 @@ public class TimeoutCompleteListener extends CyclicTimeout implements Response.C
|
|||
{
|
||||
boolean cancelled = cancel();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Cancelled ({}) timeout for {}", cancelled, request);
|
||||
LOG.debug("Cancelled ({}) timeout for {} on {}", cancelled, request, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,12 +68,16 @@ public class TimeoutCompleteListener extends CyclicTimeout implements Response.C
|
|||
if (this.request.compareAndSet(null, request))
|
||||
{
|
||||
long delay = timeoutAt - System.nanoTime();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Scheduled timeout in {} ms for {}", TimeUnit.NANOSECONDS.toMillis(delay), request);
|
||||
if (delay <= 0)
|
||||
{
|
||||
onTimeoutExpired();
|
||||
}
|
||||
else
|
||||
{
|
||||
schedule(delay, TimeUnit.NANOSECONDS);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Scheduled timeout in {} ms for {} on {}", TimeUnit.NANOSECONDS.toMillis(delay), request, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -261,12 +261,14 @@ public interface Request
|
|||
Request idleTimeout(long timeout, TimeUnit unit);
|
||||
|
||||
/**
|
||||
* @return the total timeout for this request, in milliseconds
|
||||
* @return the total timeout for this request, in milliseconds;
|
||||
* zero or negative if the timeout is disabled
|
||||
*/
|
||||
long getTimeout();
|
||||
|
||||
/**
|
||||
* @param timeout the total timeout for the request/response conversation
|
||||
* @param timeout the total timeout for the request/response conversation;
|
||||
* use zero or a negative value to disable the timeout
|
||||
* @param unit the timeout unit
|
||||
* @return this request object
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,201 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client.dynamic;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jetty.alpn.client.ALPNClientConnection;
|
||||
import org.eclipse.jetty.alpn.client.ALPNClientConnectionFactory;
|
||||
import org.eclipse.jetty.client.AbstractConnectorHttpClientTransport;
|
||||
import org.eclipse.jetty.client.HttpClientTransport;
|
||||
import org.eclipse.jetty.client.HttpDestination;
|
||||
import org.eclipse.jetty.client.HttpRequest;
|
||||
import org.eclipse.jetty.client.MultiplexConnectionPool;
|
||||
import org.eclipse.jetty.client.MultiplexHttpDestination;
|
||||
import org.eclipse.jetty.client.Origin;
|
||||
import org.eclipse.jetty.client.http.HttpClientConnectionFactory;
|
||||
import org.eclipse.jetty.http.HttpScheme;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.io.ClientConnectionFactory;
|
||||
import org.eclipse.jetty.io.ClientConnector;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
|
||||
/**
|
||||
* <p>A {@link HttpClientTransport} that can dynamically switch among different application protocols.</p>
|
||||
* <p>Applications create HttpClientTransportDynamic instances specifying all the <em>application protocols</em>
|
||||
* it supports, in order of preference. The typical case is when the server supports both HTTP/1.1 and
|
||||
* HTTP/2, but the client does not know that. In this case, the application will create a
|
||||
* HttpClientTransportDynamic in this way:</p>
|
||||
* <pre>
|
||||
* ClientConnector clientConnector = new ClientConnector();
|
||||
* // Configure the clientConnector.
|
||||
*
|
||||
* // Prepare the application protocols.
|
||||
* HttpClientConnectionFactory.Key h1 = HttpClientConnectionFactory.HTTP;
|
||||
* HTTP2Client http2Client = new HTTP2Client(clientConnector);
|
||||
* ClientConnectionFactory.Key h2 = new ClientConnectionFactoryOverHTTP2.H2(http2Client);
|
||||
*
|
||||
* // Create the HttpClientTransportDynamic, preferring h2 over h1.
|
||||
* HttpClientTransport transport = new HttpClientTransportDynamic(clientConnector, h2, h1);
|
||||
*
|
||||
* // Create the HttpClient.
|
||||
* client = new HttpClient(transport);
|
||||
* </pre>
|
||||
* <p>Note how in the code above the HttpClientTransportDynamic has been created with the <em>application
|
||||
* protocols</em> {@code h2} and {@code h1}, without the need to specify TLS (which is implied by the request
|
||||
* scheme) or ALPN (which is implied by HTTP/2 over TLS).</p>
|
||||
* <p>When a request is first sent, a destination needs to be created, and the {@link org.eclipse.jetty.client.Origin}
|
||||
* {@code (scheme, host, port)} is not enough to identify the destination because the same origin may speak
|
||||
* different protocols.
|
||||
* For example, the Jetty server supports speaking clear-text {@code http/1.1} and {@code h2c} on the same port.
|
||||
* Imagine a client sending a {@code h2c} request to that port; this will create a destination and connections
|
||||
* that speak {@code h2c}; it won't be possible to use the connections from that destination to send
|
||||
* {@code http/1.1} requests.
|
||||
* Therefore a destination is identified by a {@link org.eclipse.jetty.client.HttpDestination.Key} and
|
||||
* applications can customize the creation of the destination key (for example depending on request protocol
|
||||
* version, or request headers, or request attributes, or even request path) by overriding
|
||||
* {@link #newDestinationKey(HttpRequest, Origin)}.</p>
|
||||
*/
|
||||
public class HttpClientTransportDynamic extends AbstractConnectorHttpClientTransport implements HttpClientTransport.Dynamic
|
||||
{
|
||||
private final List<ClientConnectionFactory.Info> factoryInfos;
|
||||
private final List<String> protocols;
|
||||
|
||||
/**
|
||||
* Creates a transport that speaks only HTTP/1.1.
|
||||
*/
|
||||
public HttpClientTransportDynamic()
|
||||
{
|
||||
this(new ClientConnector(), HttpClientConnectionFactory.HTTP11);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a transport with the given {@link ClientConnector} and the given <em>application protocols</em>.
|
||||
*
|
||||
* @param connector the ClientConnector used by this transport
|
||||
* @param factoryInfos the <em>application protocols</em> that this transport can speak
|
||||
*/
|
||||
public HttpClientTransportDynamic(ClientConnector connector, ClientConnectionFactory.Info... factoryInfos)
|
||||
{
|
||||
super(connector);
|
||||
addBean(connector);
|
||||
if (factoryInfos.length == 0)
|
||||
throw new IllegalArgumentException("Missing ClientConnectionFactory");
|
||||
this.factoryInfos = Arrays.asList(factoryInfos);
|
||||
this.protocols = Arrays.stream(factoryInfos)
|
||||
.flatMap(info -> info.getProtocols().stream())
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
for (ClientConnectionFactory.Info factoryInfo : factoryInfos)
|
||||
addBean(factoryInfo);
|
||||
setConnectionPoolFactory(destination ->
|
||||
new MultiplexConnectionPool(destination, destination.getHttpClient().getMaxConnectionsPerDestination(), destination, 1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpDestination.Key newDestinationKey(HttpRequest request, Origin origin)
|
||||
{
|
||||
boolean ssl = HttpScheme.HTTPS.is(request.getScheme());
|
||||
String http2 = ssl ? "h2" : "h2c";
|
||||
List<String> protocols = List.of();
|
||||
if (request.getVersion() == HttpVersion.HTTP_2)
|
||||
{
|
||||
// The application is explicitly asking for HTTP/2, so exclude HTTP/1.1.
|
||||
if (this.protocols.contains(http2))
|
||||
protocols = List.of(http2);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Preserve the order of protocols chosen by the application.
|
||||
protocols = this.protocols.stream()
|
||||
.filter(p -> p.equals("http/1.1") || p.equals(http2))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
if (protocols.isEmpty())
|
||||
return new HttpDestination.Key(origin, null);
|
||||
return new HttpDestination.Key(origin, new HttpDestination.Protocol(protocols, ssl));
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpDestination newHttpDestination(HttpDestination.Key key)
|
||||
{
|
||||
return new MultiplexHttpDestination(getHttpClient(), key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.eclipse.jetty.io.Connection newConnection(EndPoint endPoint, Map<String, Object> context) throws IOException
|
||||
{
|
||||
HttpDestination destination = (HttpDestination)context.get(HTTP_DESTINATION_CONTEXT_KEY);
|
||||
HttpDestination.Protocol protocol = destination.getKey().getProtocol();
|
||||
ClientConnectionFactory.Info factoryInfo;
|
||||
if (protocol == null)
|
||||
{
|
||||
// Use the default ClientConnectionFactory.
|
||||
factoryInfo = factoryInfos.get(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (destination.isSecure() && protocol.isNegotiate())
|
||||
{
|
||||
factoryInfo = new ALPNClientConnectionFactory.ALPN(getClientConnector().getExecutor(), this::newNegotiatedConnection, protocol.getProtocols());
|
||||
}
|
||||
else
|
||||
{
|
||||
factoryInfo = findClientConnectionFactoryInfo(protocol.getProtocols())
|
||||
.orElseThrow(() -> new IOException("Cannot find " + ClientConnectionFactory.class.getSimpleName() + " for " + protocol));
|
||||
}
|
||||
}
|
||||
return factoryInfo.getClientConnectionFactory().newConnection(endPoint, context);
|
||||
}
|
||||
|
||||
protected Connection newNegotiatedConnection(EndPoint endPoint, Map<String, Object> context) throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
ALPNClientConnection alpnConnection = (ALPNClientConnection)endPoint.getConnection();
|
||||
String protocol = alpnConnection.getProtocol();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("ALPN negotiated {} among {}", protocol, alpnConnection.getProtocols());
|
||||
if (protocol == null)
|
||||
throw new IOException("Could not negotiate protocol among " + alpnConnection.getProtocols());
|
||||
List<String> protocols = List.of(protocol);
|
||||
Info factoryInfo = findClientConnectionFactoryInfo(protocols)
|
||||
.orElseThrow(() -> new IOException("Cannot find " + ClientConnectionFactory.class.getSimpleName() + " for negotiated protocol " + protocol));
|
||||
return factoryInfo.getClientConnectionFactory().newConnection(endPoint, context);
|
||||
}
|
||||
catch (Throwable failure)
|
||||
{
|
||||
this.connectFailed(context, failure);
|
||||
throw failure;
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<Info> findClientConnectionFactoryInfo(List<String> protocols)
|
||||
{
|
||||
return factoryInfos.stream()
|
||||
.filter(info -> info.matches(protocols))
|
||||
.findFirst();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client.http;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jetty.client.HttpClientTransport;
|
||||
import org.eclipse.jetty.client.HttpDestination;
|
||||
import org.eclipse.jetty.client.api.Connection;
|
||||
import org.eclipse.jetty.io.ClientConnectionFactory;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.util.Promise;
|
||||
|
||||
public class HttpClientConnectionFactory implements ClientConnectionFactory
|
||||
{
|
||||
public static final Info HTTP11 = new Info(List.of("http/1.1"), new HttpClientConnectionFactory());
|
||||
|
||||
@Override
|
||||
public org.eclipse.jetty.io.Connection newConnection(EndPoint endPoint, Map<String, Object> context)
|
||||
{
|
||||
HttpDestination destination = (HttpDestination)context.get(HttpClientTransport.HTTP_DESTINATION_CONTEXT_KEY);
|
||||
@SuppressWarnings("unchecked")
|
||||
Promise<Connection> promise = (Promise<Connection>)context.get(HttpClientTransport.HTTP_CONNECTION_PROMISE_CONTEXT_KEY);
|
||||
return customize(new HttpConnectionOverHTTP(endPoint, destination, promise), context);
|
||||
}
|
||||
}
|
|
@ -23,8 +23,8 @@ import java.util.Map;
|
|||
|
||||
import org.eclipse.jetty.client.AbstractConnectorHttpClientTransport;
|
||||
import org.eclipse.jetty.client.DuplexConnectionPool;
|
||||
import org.eclipse.jetty.client.DuplexHttpDestination;
|
||||
import org.eclipse.jetty.client.HttpDestination;
|
||||
import org.eclipse.jetty.client.Origin;
|
||||
import org.eclipse.jetty.client.api.Connection;
|
||||
import org.eclipse.jetty.io.ClientConnector;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
|
@ -53,9 +53,9 @@ public class HttpClientTransportOverHTTP extends AbstractConnectorHttpClientTran
|
|||
}
|
||||
|
||||
@Override
|
||||
public HttpDestination newHttpDestination(Origin origin)
|
||||
public HttpDestination newHttpDestination(HttpDestination.Key key)
|
||||
{
|
||||
return new HttpDestinationOverHTTP(getHttpClient(), origin);
|
||||
return new DuplexHttpDestination(getHttpClient(), key);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -28,6 +28,7 @@ import java.util.concurrent.atomic.LongAdder;
|
|||
import org.eclipse.jetty.client.HttpConnection;
|
||||
import org.eclipse.jetty.client.HttpDestination;
|
||||
import org.eclipse.jetty.client.HttpExchange;
|
||||
import org.eclipse.jetty.client.IConnection;
|
||||
import org.eclipse.jetty.client.SendFailure;
|
||||
import org.eclipse.jetty.client.api.Connection;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
|
@ -39,7 +40,7 @@ import org.eclipse.jetty.util.log.Log;
|
|||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.thread.Sweeper;
|
||||
|
||||
public class HttpConnectionOverHTTP extends AbstractConnection implements Connection, org.eclipse.jetty.io.Connection.UpgradeFrom, Sweeper.Sweepable
|
||||
public class HttpConnectionOverHTTP extends AbstractConnection implements IConnection, org.eclipse.jetty.io.Connection.UpgradeFrom, Sweeper.Sweepable
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(HttpConnectionOverHTTP.class);
|
||||
|
||||
|
@ -71,9 +72,9 @@ public class HttpConnectionOverHTTP extends AbstractConnection implements Connec
|
|||
return channel;
|
||||
}
|
||||
|
||||
public HttpDestinationOverHTTP getHttpDestination()
|
||||
public HttpDestination getHttpDestination()
|
||||
{
|
||||
return (HttpDestinationOverHTTP)delegate.getHttpDestination();
|
||||
return delegate.getHttpDestination();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -116,7 +117,8 @@ public class HttpConnectionOverHTTP extends AbstractConnection implements Connec
|
|||
delegate.send(request, listener);
|
||||
}
|
||||
|
||||
protected SendFailure send(HttpExchange exchange)
|
||||
@Override
|
||||
public SendFailure send(HttpExchange exchange)
|
||||
{
|
||||
return delegate.send(exchange);
|
||||
}
|
||||
|
@ -238,7 +240,7 @@ public class HttpConnectionOverHTTP extends AbstractConnection implements Connec
|
|||
}
|
||||
|
||||
@Override
|
||||
protected SendFailure send(HttpExchange exchange)
|
||||
public SendFailure send(HttpExchange exchange)
|
||||
{
|
||||
Request request = exchange.getRequest();
|
||||
normalizeRequest(request);
|
||||
|
|
|
@ -221,6 +221,13 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
|
|||
return 4096;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHeaderCacheCaseSensitive()
|
||||
{
|
||||
// TODO get from configuration
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startResponse(HttpVersion version, int status, String reason)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client.proxy;
|
||||
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.eclipse.jetty.client.HttpClientTransport;
|
||||
import org.eclipse.jetty.client.HttpDestination;
|
||||
import org.eclipse.jetty.client.Origin;
|
||||
import org.eclipse.jetty.client.api.Connection;
|
||||
import org.eclipse.jetty.io.AbstractConnection;
|
||||
import org.eclipse.jetty.io.ClientConnectionFactory;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.Promise;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
public class ProxyProtocolClientConnectionFactory implements ClientConnectionFactory
|
||||
{
|
||||
private final ClientConnectionFactory connectionFactory;
|
||||
private final Supplier<Origin.Address> proxiedAddressSupplier;
|
||||
|
||||
public ProxyProtocolClientConnectionFactory(ClientConnectionFactory connectionFactory, Supplier<Origin.Address> proxiedAddressSupplier)
|
||||
{
|
||||
this.connectionFactory = connectionFactory;
|
||||
this.proxiedAddressSupplier = proxiedAddressSupplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.eclipse.jetty.io.Connection newConnection(EndPoint endPoint, Map<String, Object> context)
|
||||
{
|
||||
HttpDestination destination = (HttpDestination)context.get(HttpClientTransport.HTTP_DESTINATION_CONTEXT_KEY);
|
||||
Executor executor = destination.getHttpClient().getExecutor();
|
||||
ProxyProtocolConnection connection = new ProxyProtocolConnection(endPoint, executor, context);
|
||||
return customize(connection, context);
|
||||
}
|
||||
|
||||
private class ProxyProtocolConnection extends AbstractConnection implements Callback
|
||||
{
|
||||
private final Logger LOG = Log.getLogger(ProxyProtocolConnection.class);
|
||||
private final Map<String, Object> context;
|
||||
|
||||
public ProxyProtocolConnection(EndPoint endPoint, Executor executor, Map<String, Object> context)
|
||||
{
|
||||
super(endPoint, executor);
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen()
|
||||
{
|
||||
super.onOpen();
|
||||
writePROXYLine();
|
||||
}
|
||||
|
||||
protected void writePROXYLine()
|
||||
{
|
||||
Origin.Address proxiedAddress = proxiedAddressSupplier.get();
|
||||
if (proxiedAddress == null)
|
||||
{
|
||||
failed(new IllegalArgumentException("Missing proxied socket address"));
|
||||
return;
|
||||
}
|
||||
String proxiedIP = proxiedAddress.getHost();
|
||||
int proxiedPort = proxiedAddress.getPort();
|
||||
InetSocketAddress serverSocketAddress = getEndPoint().getRemoteAddress();
|
||||
InetAddress serverAddress = serverSocketAddress.getAddress();
|
||||
String serverIP = serverAddress.getHostAddress();
|
||||
int serverPort = serverSocketAddress.getPort();
|
||||
|
||||
boolean ipv6 = serverAddress instanceof Inet6Address;
|
||||
String line = String.format("PROXY %s %s %s %d %d\r\n", ipv6 ? "TCP6" : "TCP4" , proxiedIP, serverIP, proxiedPort, serverPort);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Writing PROXY line: {}", line.trim());
|
||||
ByteBuffer buffer = ByteBuffer.wrap(line.getBytes(StandardCharsets.US_ASCII));
|
||||
getEndPoint().write(this, buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void succeeded()
|
||||
{
|
||||
try
|
||||
{
|
||||
EndPoint endPoint = getEndPoint();
|
||||
org.eclipse.jetty.io.Connection connection = connectionFactory.newConnection(endPoint, context);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Written PROXY line, upgrading to {}", connection);
|
||||
endPoint.upgrade(connection);
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
failed(x);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable x)
|
||||
{
|
||||
close();
|
||||
@SuppressWarnings("unchecked")
|
||||
Promise<Connection> promise = (Promise<Connection>)context.get(HttpClientTransport.HTTP_CONNECTION_PROMISE_CONTEXT_KEY);
|
||||
promise.failed(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InvocationType getInvocationType()
|
||||
{
|
||||
return InvocationType.NON_BLOCKING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFillable()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -20,6 +20,7 @@ package org.eclipse.jetty.client.util;
|
|||
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.api.AuthenticationStore;
|
||||
|
@ -27,7 +28,6 @@ import org.eclipse.jetty.client.api.ContentResponse;
|
|||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.util.Attributes;
|
||||
import org.eclipse.jetty.util.B64Code;
|
||||
|
||||
/**
|
||||
* Implementation of the HTTP "Basic" authentication defined in RFC 2617.
|
||||
|
@ -91,7 +91,8 @@ public class BasicAuthentication extends AbstractAuthentication
|
|||
{
|
||||
this.uri = uri;
|
||||
this.header = header;
|
||||
this.value = "Basic " + B64Code.encode(user + ":" + password, StandardCharsets.ISO_8859_1);
|
||||
byte[] authBytes = (user + ":" + password).getBytes(StandardCharsets.ISO_8859_1);
|
||||
this.value = "Basic " + Base64.getEncoder().encodeToString(authBytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.util.stream.Stream;
|
|||
|
||||
import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
|
||||
import org.eclipse.jetty.http.HttpScheme;
|
||||
import org.eclipse.jetty.io.ClientConnector;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
|
@ -58,7 +59,7 @@ public abstract class AbstractHttpClientServerTest
|
|||
serverThreads.setName("server");
|
||||
server = new Server(serverThreads);
|
||||
}
|
||||
connector = new ServerConnector(server, scenario.newSslContextFactory());
|
||||
connector = new ServerConnector(server, scenario.newServerSslContextFactory());
|
||||
connector.setPort(0);
|
||||
server.addConnector(connector);
|
||||
server.setHandler(handler);
|
||||
|
@ -67,30 +68,30 @@ public abstract class AbstractHttpClientServerTest
|
|||
|
||||
protected void startClient(final Scenario scenario) throws Exception
|
||||
{
|
||||
startClient(scenario, null,null);
|
||||
startClient(scenario, null);
|
||||
}
|
||||
|
||||
protected void startClient(final Scenario scenario, HttpClientTransport transport, Consumer<HttpClient> config) throws Exception
|
||||
protected void startClient(final Scenario scenario, Consumer<HttpClient> config) throws Exception
|
||||
{
|
||||
if (transport==null)
|
||||
transport = new HttpClientTransportOverHTTP(1);
|
||||
|
||||
ClientConnector clientConnector = new ClientConnector();
|
||||
clientConnector.setSelectors(1);
|
||||
clientConnector.setSslContextFactory(scenario.newClientSslContextFactory());
|
||||
HttpClientTransport transport = new HttpClientTransportOverHTTP(clientConnector);
|
||||
QueuedThreadPool executor = new QueuedThreadPool();
|
||||
executor.setName("client");
|
||||
clientConnector.setExecutor(executor);
|
||||
Scheduler scheduler = new ScheduledExecutorScheduler("client-scheduler", false);
|
||||
client = newHttpClient(scenario, transport);
|
||||
client.setExecutor(executor);
|
||||
client.setScheduler(scheduler);
|
||||
clientConnector.setScheduler(scheduler);
|
||||
client = newHttpClient(transport);
|
||||
client.setSocketAddressResolver(new SocketAddressResolver.Sync());
|
||||
if (config!=null)
|
||||
if (config != null)
|
||||
config.accept(client);
|
||||
|
||||
client.start();
|
||||
}
|
||||
|
||||
public HttpClient newHttpClient(Scenario scenario, HttpClientTransport transport)
|
||||
public HttpClient newHttpClient(HttpClientTransport transport)
|
||||
{
|
||||
return new HttpClient(transport, scenario.newSslContextFactory());
|
||||
return new HttpClient(transport);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
|
@ -113,9 +114,10 @@ public abstract class AbstractHttpClientServerTest
|
|||
}
|
||||
}
|
||||
|
||||
public static class ScenarioProvider implements ArgumentsProvider {
|
||||
public static class ScenarioProvider implements ArgumentsProvider
|
||||
{
|
||||
@Override
|
||||
public Stream<? extends Arguments> provideArguments(ExtensionContext context) throws Exception
|
||||
public Stream<? extends Arguments> provideArguments(ExtensionContext context)
|
||||
{
|
||||
return Stream.of(
|
||||
new NormalScenario(),
|
||||
|
@ -125,9 +127,10 @@ public abstract class AbstractHttpClientServerTest
|
|||
}
|
||||
}
|
||||
|
||||
public static class NonSslScenarioProvider implements ArgumentsProvider {
|
||||
public static class NonSslScenarioProvider implements ArgumentsProvider
|
||||
{
|
||||
@Override
|
||||
public Stream<? extends Arguments> provideArguments(ExtensionContext context) throws Exception
|
||||
public Stream<? extends Arguments> provideArguments(ExtensionContext context)
|
||||
{
|
||||
return Stream.of(
|
||||
new NormalScenario()
|
||||
|
@ -138,12 +141,27 @@ public abstract class AbstractHttpClientServerTest
|
|||
|
||||
public interface Scenario
|
||||
{
|
||||
default SslContextFactory newSslContextFactory() { return null; }
|
||||
SslContextFactory.Client newClientSslContextFactory();
|
||||
|
||||
SslContextFactory.Server newServerSslContextFactory();
|
||||
|
||||
String getScheme();
|
||||
}
|
||||
|
||||
public static class NormalScenario implements Scenario
|
||||
{
|
||||
@Override
|
||||
public SslContextFactory.Client newClientSslContextFactory()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SslContextFactory.Server newServerSslContextFactory()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getScheme()
|
||||
{
|
||||
|
@ -160,15 +178,27 @@ public abstract class AbstractHttpClientServerTest
|
|||
public static class SslScenario implements Scenario
|
||||
{
|
||||
@Override
|
||||
public SslContextFactory newSslContextFactory()
|
||||
public SslContextFactory.Client newClientSslContextFactory()
|
||||
{
|
||||
SslContextFactory.Client result = new SslContextFactory.Client();
|
||||
result.setEndpointIdentificationAlgorithm(null);
|
||||
configure(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SslContextFactory.Server newServerSslContextFactory()
|
||||
{
|
||||
SslContextFactory.Server result = new SslContextFactory.Server();
|
||||
configure(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void configure(SslContextFactory ssl)
|
||||
{
|
||||
Path keystorePath = MavenTestingUtils.getTestResourcePath("keystore.jks");
|
||||
|
||||
SslContextFactory ssl = new SslContextFactory();
|
||||
ssl.setEndpointIdentificationAlgorithm("");
|
||||
ssl.setKeyStorePath(keystorePath.toString());
|
||||
ssl.setKeyStorePassword("storepwd");
|
||||
return ssl;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -18,11 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
@ -36,7 +31,6 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.http.HttpConnectionOverHTTP;
|
||||
import org.eclipse.jetty.client.http.HttpDestinationOverHTTP;
|
||||
import org.eclipse.jetty.client.util.DeferredContentProvider;
|
||||
import org.eclipse.jetty.client.util.StringContentProvider;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
|
@ -47,6 +41,11 @@ import org.eclipse.jetty.server.handler.AbstractHandler;
|
|||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ArgumentsSource;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class ClientConnectionCloseTest extends AbstractHttpClientServerTest
|
||||
{
|
||||
@ParameterizedTest
|
||||
|
@ -87,7 +86,7 @@ public class ClientConnectionCloseTest extends AbstractHttpClientServerTest
|
|||
String host = "localhost";
|
||||
int port = connector.getLocalPort();
|
||||
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scenario.getScheme(), host, port);
|
||||
HttpDestination destination = (HttpDestination)client.getDestination(scenario.getScheme(), host, port);
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
|
||||
ContentResponse response = client.newRequest(host, port)
|
||||
|
@ -124,7 +123,7 @@ public class ClientConnectionCloseTest extends AbstractHttpClientServerTest
|
|||
String host = "localhost";
|
||||
int port = connector.getLocalPort();
|
||||
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scenario.getScheme(), host, port);
|
||||
HttpDestination destination = (HttpDestination)client.getDestination(scenario.getScheme(), host, port);
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
|
||||
CountDownLatch resultLatch = new CountDownLatch(1);
|
||||
|
@ -185,7 +184,7 @@ public class ClientConnectionCloseTest extends AbstractHttpClientServerTest
|
|||
String host = "localhost";
|
||||
int port = connector.getLocalPort();
|
||||
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scenario.getScheme(), host, port);
|
||||
HttpDestination destination = (HttpDestination)client.getDestination(scenario.getScheme(), host, port);
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
|
||||
DeferredContentProvider content = new DeferredContentProvider(ByteBuffer.allocate(8));
|
||||
|
@ -240,7 +239,7 @@ public class ClientConnectionCloseTest extends AbstractHttpClientServerTest
|
|||
String host = "localhost";
|
||||
int port = connector.getLocalPort();
|
||||
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scenario.getScheme(), host, port);
|
||||
HttpDestination destination = (HttpDestination)client.getDestination(scenario.getScheme(), host, port);
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
|
||||
ContentResponse response = client.newRequest(host, port)
|
||||
|
|
|
@ -18,9 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -31,7 +28,6 @@ import java.util.concurrent.TimeUnit;
|
|||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
@ -53,6 +49,9 @@ import org.junit.jupiter.params.ParameterizedTest;
|
|||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@Disabled // Disabled by @gregw on issue #2540 - commit 621b946b10884e7308eacca241dcf8b5d6f6cff2
|
||||
public class ConnectionPoolTest
|
||||
{
|
||||
|
@ -83,7 +82,7 @@ public class ConnectionPoolTest
|
|||
transport.setConnectionPoolFactory(factory);
|
||||
server.start();
|
||||
|
||||
client = new HttpClient(transport, null);
|
||||
client = new HttpClient(transport);
|
||||
client.start();
|
||||
}
|
||||
|
||||
|
@ -115,7 +114,7 @@ public class ConnectionPoolTest
|
|||
start(factory, new EmptyServerHandler()
|
||||
{
|
||||
@Override
|
||||
protected void service(String target, org.eclipse.jetty.server.Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
protected void service(String target, org.eclipse.jetty.server.Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
switch (HttpMethod.fromString(request.getMethod()))
|
||||
{
|
||||
|
|
|
@ -18,10 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||
|
||||
import java.net.Socket;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -30,12 +26,16 @@ import org.eclipse.jetty.client.api.ContentResponse;
|
|||
import org.eclipse.jetty.client.api.Response;
|
||||
import org.eclipse.jetty.client.api.Result;
|
||||
import org.eclipse.jetty.http.HttpScheme;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||
|
||||
@Disabled
|
||||
public class ExternalSiteTest
|
||||
{
|
||||
|
@ -44,7 +44,7 @@ public class ExternalSiteTest
|
|||
@BeforeEach
|
||||
public void prepare() throws Exception
|
||||
{
|
||||
client = new HttpClient(new SslContextFactory());
|
||||
client = new HttpClient();
|
||||
client.start();
|
||||
}
|
||||
|
||||
|
@ -54,6 +54,7 @@ public class ExternalSiteTest
|
|||
client.stop();
|
||||
}
|
||||
|
||||
@Tag("external")
|
||||
@Test
|
||||
public void testExternalSite() throws Exception
|
||||
{
|
||||
|
@ -64,39 +65,29 @@ public class ExternalSiteTest
|
|||
assumeCanConnectTo(host, port);
|
||||
|
||||
final CountDownLatch latch1 = new CountDownLatch(1);
|
||||
client.newRequest(host, port).send(new Response.CompleteListener()
|
||||
client.newRequest(host, port).send(result ->
|
||||
{
|
||||
@Override
|
||||
public void onComplete(Result result)
|
||||
{
|
||||
if (!result.isFailed() && result.getResponse().getStatus() == 200)
|
||||
latch1.countDown();
|
||||
}
|
||||
assertTrue(result.isSucceeded());
|
||||
assertEquals(200, result.getResponse().getStatus());
|
||||
latch1.countDown();
|
||||
});
|
||||
assertTrue(latch1.await(10, TimeUnit.SECONDS));
|
||||
assertTrue(latch1.await(15, TimeUnit.SECONDS));
|
||||
|
||||
// Try again the same URI, but without specifying the port
|
||||
final CountDownLatch latch2 = new CountDownLatch(1);
|
||||
client.newRequest("http://" + host).send(new Response.CompleteListener()
|
||||
client.newRequest("http://" + host).send(result ->
|
||||
{
|
||||
@Override
|
||||
public void onComplete(Result result)
|
||||
{
|
||||
assertTrue(result.isSucceeded());
|
||||
assertEquals(200, result.getResponse().getStatus());
|
||||
latch2.countDown();
|
||||
}
|
||||
assertTrue(result.isSucceeded());
|
||||
assertEquals(200, result.getResponse().getStatus());
|
||||
latch2.countDown();
|
||||
});
|
||||
assertTrue(latch2.await(10, TimeUnit.SECONDS));
|
||||
assertTrue(latch2.await(15, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Tag("external")
|
||||
@Test
|
||||
public void testExternalSSLSite() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
client = new HttpClient(new SslContextFactory());
|
||||
client.start();
|
||||
|
||||
String host = "api-3t.paypal.com";
|
||||
int port = 443;
|
||||
|
||||
|
@ -104,18 +95,16 @@ public class ExternalSiteTest
|
|||
assumeCanConnectTo(host, port);
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
client.newRequest(host, port).scheme("https").path("/nvp").send(new Response.CompleteListener()
|
||||
client.newRequest(host, port).scheme("https").path("/nvp").send(result ->
|
||||
{
|
||||
@Override
|
||||
public void onComplete(Result result)
|
||||
{
|
||||
if (result.isSucceeded() && result.getResponse().getStatus() == 200)
|
||||
latch.countDown();
|
||||
}
|
||||
assertTrue(result.isSucceeded());
|
||||
assertEquals(200, result.getResponse().getStatus());
|
||||
latch.countDown();
|
||||
});
|
||||
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
assertTrue(latch.await(15, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Tag("external")
|
||||
@Test
|
||||
public void testExternalSiteWrongProtocol() throws Exception
|
||||
{
|
||||
|
@ -129,14 +118,7 @@ public class ExternalSiteTest
|
|||
{
|
||||
final CountDownLatch latch = new CountDownLatch(3);
|
||||
client.newRequest(host, port)
|
||||
.onResponseFailure(new Response.FailureListener()
|
||||
{
|
||||
@Override
|
||||
public void onFailure(Response response, Throwable failure)
|
||||
{
|
||||
latch.countDown();
|
||||
}
|
||||
})
|
||||
.onResponseFailure((response, failure) -> latch.countDown())
|
||||
.send(new Response.Listener.Adapter()
|
||||
{
|
||||
@Override
|
||||
|
@ -152,10 +134,11 @@ public class ExternalSiteTest
|
|||
latch.countDown();
|
||||
}
|
||||
});
|
||||
assertTrue(latch.await(10, TimeUnit.SECONDS));
|
||||
assertTrue(latch.await(15, TimeUnit.SECONDS));
|
||||
}
|
||||
}
|
||||
|
||||
@Tag("external")
|
||||
@Test
|
||||
public void testExternalSiteRedirect() throws Exception
|
||||
{
|
||||
|
@ -168,6 +151,7 @@ public class ExternalSiteTest
|
|||
ContentResponse response = client.newRequest(host, port)
|
||||
.scheme(HttpScheme.HTTPS.asString())
|
||||
.path("/twitter")
|
||||
.timeout(15, TimeUnit.SECONDS)
|
||||
.send();
|
||||
assertEquals(200, response.getStatus());
|
||||
}
|
||||
|
@ -180,7 +164,7 @@ public class ExternalSiteTest
|
|||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
assumeTrue(x == null, "Unable to connect");
|
||||
assumeTrue(false, "Unable to connect");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,19 +18,16 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
|
||||
import org.eclipse.jetty.io.ClientConnector;
|
||||
import org.eclipse.jetty.server.NetworkConnector;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
|
@ -40,11 +37,14 @@ import org.eclipse.jetty.util.ssl.SslContextFactory;
|
|||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
/**
|
||||
* This test class runs tests to make sure that hostname verification (http://www.ietf.org/rfc/rfc2818.txt
|
||||
* section 3.1) is configurable in SslContextFactory and works as expected.
|
||||
|
@ -52,7 +52,7 @@ import org.junit.jupiter.api.Test;
|
|||
@Disabled
|
||||
public class HostnameVerificationTest
|
||||
{
|
||||
private SslContextFactory clientSslContextFactory = new SslContextFactory();
|
||||
private SslContextFactory.Client clientSslContextFactory = new SslContextFactory.Client();
|
||||
private Server server;
|
||||
private HttpClient client;
|
||||
private NetworkConnector connector;
|
||||
|
@ -64,7 +64,7 @@ public class HostnameVerificationTest
|
|||
serverThreads.setName("server");
|
||||
server = new Server(serverThreads);
|
||||
|
||||
SslContextFactory serverSslContextFactory = new SslContextFactory();
|
||||
SslContextFactory.Server serverSslContextFactory = new SslContextFactory.Server();
|
||||
serverSslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
|
||||
serverSslContextFactory.setKeyStorePassword("storepwd");
|
||||
connector = new ServerConnector(server, serverSslContextFactory);
|
||||
|
@ -72,7 +72,7 @@ public class HostnameVerificationTest
|
|||
server.setHandler(new DefaultHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
response.getWriter().write("foobar");
|
||||
|
@ -80,14 +80,19 @@ public class HostnameVerificationTest
|
|||
});
|
||||
server.start();
|
||||
|
||||
// keystore contains a hostname which doesn't match localhost
|
||||
// The keystore contains a hostname which doesn't match localhost
|
||||
clientSslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
|
||||
clientSslContextFactory.setKeyStorePassword("storepwd");
|
||||
|
||||
ClientConnector clientConnector = new ClientConnector();
|
||||
clientConnector.setSelectors(1);
|
||||
clientConnector.setSslContextFactory(clientSslContextFactory);
|
||||
|
||||
QueuedThreadPool clientThreads = new QueuedThreadPool();
|
||||
clientThreads.setName("client");
|
||||
client = new HttpClient(clientSslContextFactory);
|
||||
client.setExecutor(clientThreads);
|
||||
clientConnector.setExecutor(clientThreads);
|
||||
|
||||
client = new HttpClient(new HttpClientTransportOverHTTP(clientConnector));
|
||||
client.start();
|
||||
}
|
||||
|
||||
|
@ -112,9 +117,7 @@ public class HostnameVerificationTest
|
|||
clientSslContextFactory.setEndpointIdentificationAlgorithm("HTTPS");
|
||||
String uri = "https://localhost:" + connector.getLocalPort() + "/";
|
||||
|
||||
ExecutionException x = assertThrows(ExecutionException.class, ()->{
|
||||
client.GET(uri);
|
||||
});
|
||||
ExecutionException x = assertThrows(ExecutionException.class, ()-> client.GET(uri));
|
||||
Throwable cause = x.getCause();
|
||||
assertThat(cause, Matchers.instanceOf(SSLHandshakeException.class));
|
||||
Throwable root = cause.getCause().getCause();
|
||||
|
|
|
@ -44,9 +44,11 @@ import org.eclipse.jetty.client.api.Request;
|
|||
import org.eclipse.jetty.client.api.Response;
|
||||
import org.eclipse.jetty.client.api.Response.Listener;
|
||||
import org.eclipse.jetty.client.api.Result;
|
||||
import org.eclipse.jetty.client.util.AbstractAuthentication;
|
||||
import org.eclipse.jetty.client.util.BasicAuthentication;
|
||||
import org.eclipse.jetty.client.util.DeferredContentProvider;
|
||||
import org.eclipse.jetty.client.util.DigestAuthentication;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.security.Authenticator;
|
||||
import org.eclipse.jetty.security.ConstraintMapping;
|
||||
|
@ -57,7 +59,6 @@ import org.eclipse.jetty.security.authentication.BasicAuthenticator;
|
|||
import org.eclipse.jetty.security.authentication.DigestAuthenticator;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.Attributes;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
|
@ -67,6 +68,7 @@ import org.junit.jupiter.api.Test;
|
|||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ArgumentsSource;
|
||||
|
||||
import static org.eclipse.jetty.client.api.Authentication.ANY_REALM;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.equalToIgnoringCase;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
@ -137,7 +139,7 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest
|
|||
{
|
||||
startBasic(scenario, new EmptyServerHandler());
|
||||
URI uri = URI.create(scenario.getScheme() + "://localhost:" + connector.getLocalPort());
|
||||
test_Authentication(scenario, new BasicAuthentication(uri, Authentication.ANY_REALM, "basic", "basic"));
|
||||
test_Authentication(scenario, new BasicAuthentication(uri, ANY_REALM, "basic", "basic"));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
|
@ -155,7 +157,7 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest
|
|||
{
|
||||
startDigest(scenario, new EmptyServerHandler());
|
||||
URI uri = URI.create(scenario.getScheme() + "://localhost:" + connector.getLocalPort());
|
||||
test_Authentication(scenario, new DigestAuthentication(uri, Authentication.ANY_REALM, "digest", "digest"));
|
||||
test_Authentication(scenario, new DigestAuthentication(uri, ANY_REALM, "digest", "digest"));
|
||||
}
|
||||
|
||||
private void test_Authentication(final Scenario scenario, Authentication authentication) throws Exception
|
||||
|
@ -227,16 +229,19 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest
|
|||
@ArgumentsSource(ScenarioProvider.class)
|
||||
public void test_BasicAuthentication_ThenRedirect(Scenario scenario) throws Exception
|
||||
{
|
||||
startBasic(scenario, new AbstractHandler()
|
||||
startBasic(scenario, new EmptyServerHandler()
|
||||
{
|
||||
private final AtomicInteger requests = new AtomicInteger();
|
||||
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
protected void service(String target, org.eclipse.jetty.server.Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
if (requests.incrementAndGet() == 1)
|
||||
response.sendRedirect(URIUtil.newURI(scenario.getScheme(), request.getServerName(), request.getServerPort(), request.getRequestURI(), null));
|
||||
int r = requests.incrementAndGet();
|
||||
if (r == 1)
|
||||
{
|
||||
String path = request.getRequestURI() + "/" + r;
|
||||
response.sendRedirect(URIUtil.newURI(scenario.getScheme(), request.getServerName(), request.getServerPort(), path, null));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -269,12 +274,11 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest
|
|||
@ArgumentsSource(ScenarioProvider.class)
|
||||
public void test_Redirect_ThenBasicAuthentication(Scenario scenario) throws Exception
|
||||
{
|
||||
startBasic(scenario, new AbstractHandler()
|
||||
startBasic(scenario, new EmptyServerHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
protected void service(String target, org.eclipse.jetty.server.Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
if (request.getRequestURI().endsWith("/redirect"))
|
||||
response.sendRedirect(URIUtil.newURI(scenario.getScheme(), request.getServerName(), request.getServerPort(), "/secure", null));
|
||||
}
|
||||
|
@ -571,61 +575,57 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest
|
|||
assertTrue(resultLatch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
private static class GeneratingContentProvider implements ContentProvider
|
||||
@ParameterizedTest
|
||||
@ArgumentsSource(ScenarioProvider.class)
|
||||
public void test_InfiniteAuthentication(Scenario scenario) throws Exception
|
||||
{
|
||||
private static final ByteBuffer DONE = ByteBuffer.allocate(0);
|
||||
|
||||
private final IntFunction<ByteBuffer> generator;
|
||||
|
||||
private GeneratingContentProvider(IntFunction<ByteBuffer> generator)
|
||||
String authType = "Authenticate";
|
||||
start(scenario, new EmptyServerHandler()
|
||||
{
|
||||
this.generator = generator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLength()
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReproducible()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<ByteBuffer> iterator()
|
||||
{
|
||||
return new Iterator<ByteBuffer>()
|
||||
@Override
|
||||
protected void service(String target, org.eclipse.jetty.server.Request jettyRequest, HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
private int index;
|
||||
public ByteBuffer current;
|
||||
// Always reply with a 401 to see if the client
|
||||
// can handle an infinite authentication loop.
|
||||
response.setStatus(HttpStatus.UNAUTHORIZED_401);
|
||||
response.setHeader(HttpHeader.WWW_AUTHENTICATE.asString(), authType);
|
||||
}
|
||||
});
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("ReferenceEquality")
|
||||
public boolean hasNext()
|
||||
AuthenticationStore authenticationStore = client.getAuthenticationStore();
|
||||
URI uri = URI.create(scenario.getScheme() + "://localhost:" + connector.getLocalPort());
|
||||
authenticationStore.addAuthentication(new AbstractAuthentication(uri, Authentication.ANY_REALM)
|
||||
{
|
||||
@Override
|
||||
public String getType()
|
||||
{
|
||||
return authType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result authenticate(Request request, ContentResponse response, HeaderInfo headerInfo, Attributes context)
|
||||
{
|
||||
return new Result()
|
||||
{
|
||||
if (current == null)
|
||||
@Override
|
||||
public URI getURI()
|
||||
{
|
||||
current = generator.apply(index++);
|
||||
if (current == null)
|
||||
current = DONE;
|
||||
return uri;
|
||||
}
|
||||
return current != DONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer next()
|
||||
{
|
||||
ByteBuffer result = current;
|
||||
current = null;
|
||||
if (result == null)
|
||||
throw new NoSuchElementException();
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
@Override
|
||||
public void apply(Request request)
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
|
||||
.scheme(scenario.getScheme())
|
||||
.send();
|
||||
|
||||
assertEquals(HttpStatus.UNAUTHORIZED_401, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -801,4 +801,61 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest
|
|||
assertEquals("thermostat", headerInfo.getParameter("realm"));
|
||||
assertEquals(headerInfo.getParameter("nonce"), "1523430383=");
|
||||
}
|
||||
|
||||
private static class GeneratingContentProvider implements ContentProvider
|
||||
{
|
||||
private static final ByteBuffer DONE = ByteBuffer.allocate(0);
|
||||
|
||||
private final IntFunction<ByteBuffer> generator;
|
||||
|
||||
private GeneratingContentProvider(IntFunction<ByteBuffer> generator)
|
||||
{
|
||||
this.generator = generator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLength()
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReproducible()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<ByteBuffer> iterator()
|
||||
{
|
||||
return new Iterator<ByteBuffer>()
|
||||
{
|
||||
private int index;
|
||||
public ByteBuffer current;
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("ReferenceEquality")
|
||||
public boolean hasNext()
|
||||
{
|
||||
if (current == null)
|
||||
{
|
||||
current = generator.apply(index++);
|
||||
if (current == null)
|
||||
current = DONE;
|
||||
}
|
||||
return current != DONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer next()
|
||||
{
|
||||
ByteBuffer result = current;
|
||||
current = null;
|
||||
if (result == null)
|
||||
throw new NoSuchElementException();
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,11 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -31,13 +26,17 @@ import org.eclipse.jetty.client.api.ContentResponse;
|
|||
import org.eclipse.jetty.client.api.Destination;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.http.HttpConnectionOverHTTP;
|
||||
import org.eclipse.jetty.client.http.HttpDestinationOverHTTP;
|
||||
import org.eclipse.jetty.client.util.FutureResponseListener;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.util.FuturePromise;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ArgumentsSource;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class HttpClientExplicitConnectionTest extends AbstractHttpClientServerTest
|
||||
{
|
||||
@ParameterizedTest
|
||||
|
@ -59,7 +58,7 @@ public class HttpClientExplicitConnectionTest extends AbstractHttpClientServerTe
|
|||
assertNotNull(response);
|
||||
assertEquals(200, response.getStatus());
|
||||
|
||||
HttpDestinationOverHTTP httpDestination = (HttpDestinationOverHTTP)destination;
|
||||
HttpDestination httpDestination = (HttpDestination)destination;
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)httpDestination.getConnectionPool();
|
||||
assertTrue(connectionPool.getActiveConnections().isEmpty());
|
||||
assertTrue(connectionPool.getIdleConnections().isEmpty());
|
||||
|
@ -94,7 +93,7 @@ public class HttpClientExplicitConnectionTest extends AbstractHttpClientServerTe
|
|||
HttpConnectionOverHTTP httpConnection = (HttpConnectionOverHTTP)connection;
|
||||
assertFalse(httpConnection.getEndPoint().isOpen());
|
||||
|
||||
HttpDestinationOverHTTP httpDestination = (HttpDestinationOverHTTP)destination;
|
||||
HttpDestination httpDestination = (HttpDestination)destination;
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)httpDestination.getConnectionPool();
|
||||
assertTrue(connectionPool.getActiveConnections().isEmpty());
|
||||
assertTrue(connectionPool.getIdleConnections().isEmpty());
|
||||
|
|
|
@ -18,10 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
@ -40,9 +36,12 @@ import org.eclipse.jetty.util.Callback;
|
|||
import org.eclipse.jetty.util.Promise;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class HttpClientFailureTest
|
||||
{
|
||||
private Server server;
|
||||
|
@ -75,7 +74,7 @@ public class HttpClientFailureTest
|
|||
startServer(new EmptyServerHandler());
|
||||
|
||||
final AtomicReference<HttpConnectionOverHTTP> connectionRef = new AtomicReference<>();
|
||||
client = new HttpClient(new HttpClientTransportOverHTTP()
|
||||
client = new HttpClient(new HttpClientTransportOverHTTP(1)
|
||||
{
|
||||
@Override
|
||||
protected HttpConnectionOverHTTP newHttpConnection(EndPoint endPoint, HttpDestination destination, Promise<Connection> promise)
|
||||
|
@ -84,15 +83,14 @@ public class HttpClientFailureTest
|
|||
connectionRef.set(connection);
|
||||
return connection;
|
||||
}
|
||||
}, null);
|
||||
});
|
||||
client.start();
|
||||
|
||||
assertThrows(ExecutionException.class, ()->{
|
||||
client.newRequest("localhost", connector.getLocalPort())
|
||||
.onRequestHeaders(request -> connectionRef.get().getEndPoint().close())
|
||||
.timeout(5, TimeUnit.SECONDS)
|
||||
.send();
|
||||
});
|
||||
assertThrows(ExecutionException.class, () ->
|
||||
client.newRequest("localhost", connector.getLocalPort())
|
||||
.onRequestHeaders(request -> connectionRef.get().getEndPoint().close())
|
||||
.timeout(5, TimeUnit.SECONDS)
|
||||
.send());
|
||||
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)connectionRef.get().getHttpDestination().getConnectionPool();
|
||||
assertEquals(0, connectionPool.getConnectionCount());
|
||||
|
@ -106,7 +104,7 @@ public class HttpClientFailureTest
|
|||
startServer(new EmptyServerHandler());
|
||||
|
||||
final AtomicReference<HttpConnectionOverHTTP> connectionRef = new AtomicReference<>();
|
||||
client = new HttpClient(new HttpClientTransportOverHTTP()
|
||||
client = new HttpClient(new HttpClientTransportOverHTTP(1)
|
||||
{
|
||||
@Override
|
||||
protected HttpConnectionOverHTTP newHttpConnection(EndPoint endPoint, HttpDestination destination, Promise<Connection> promise)
|
||||
|
@ -115,7 +113,7 @@ public class HttpClientFailureTest
|
|||
connectionRef.set(connection);
|
||||
return connection;
|
||||
}
|
||||
}, null);
|
||||
});
|
||||
client.start();
|
||||
|
||||
final CountDownLatch commitLatch = new CountDownLatch(1);
|
||||
|
@ -155,98 +153,4 @@ public class HttpClientFailureTest
|
|||
assertEquals(0, connectionPool.getActiveConnections().size());
|
||||
assertEquals(0, connectionPool.getIdleConnections().size());
|
||||
}
|
||||
/*
|
||||
@Test
|
||||
public void test_ExchangeIsComplete_WhenRequestFailsMidway_WithResponse() throws Exception
|
||||
{
|
||||
start(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
// Echo back
|
||||
IO.copy(request.getInputStream(), response.getOutputStream());
|
||||
}
|
||||
});
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
client.newRequest("localhost", connector.getLocalPort())
|
||||
.scheme(scheme)
|
||||
// The second ByteBuffer set to null will throw an exception
|
||||
.content(new ContentProvider()
|
||||
{
|
||||
@Override
|
||||
public long getLength()
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<ByteBuffer> iterator()
|
||||
{
|
||||
return new Iterator<ByteBuffer>()
|
||||
{
|
||||
@Override
|
||||
public boolean hasNext()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer next()
|
||||
{
|
||||
throw new NoSuchElementException("explicitly_thrown_by_test");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove()
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
})
|
||||
.send(new Response.Listener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public void onComplete(Result result)
|
||||
{
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_ExchangeIsComplete_WhenRequestFails_WithNoResponse() throws Exception
|
||||
{
|
||||
start(new EmptyServerHandler());
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
final String host = "localhost";
|
||||
final int port = connector.getLocalPort();
|
||||
client.newRequest(host, port)
|
||||
.scheme(scheme)
|
||||
.onRequestBegin(new Request.BeginListener()
|
||||
{
|
||||
@Override
|
||||
public void onBegin(Request request)
|
||||
{
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, host, port);
|
||||
destination.getConnectionPool().getActiveConnections().peek().close();
|
||||
}
|
||||
})
|
||||
.send(new Response.Listener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public void onComplete(Result result)
|
||||
{
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -21,9 +21,9 @@ package org.eclipse.jetty.client;
|
|||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
@ -35,7 +35,6 @@ import org.eclipse.jetty.http.HttpHeader;
|
|||
import org.eclipse.jetty.http.HttpScheme;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.util.B64Code;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ArgumentsSource;
|
||||
|
||||
|
@ -82,7 +81,7 @@ public class HttpClientProxyTest extends AbstractHttpClientServerTest
|
|||
{
|
||||
final String user = "foo";
|
||||
final String password = "bar";
|
||||
final String credentials = B64Code.encode(user + ":" + password, StandardCharsets.ISO_8859_1);
|
||||
final String credentials = Base64.getEncoder().encodeToString((user + ":" + password).getBytes(StandardCharsets.ISO_8859_1));
|
||||
final String serverHost = "server";
|
||||
final String realm = "test_realm";
|
||||
final int status = HttpStatus.NO_CONTENT_204;
|
||||
|
@ -162,7 +161,7 @@ public class HttpClientProxyTest extends AbstractHttpClientServerTest
|
|||
{
|
||||
String user = "foo";
|
||||
String password = "bar";
|
||||
String credentials = B64Code.encode(user + ":" + password, StandardCharsets.ISO_8859_1);
|
||||
String credentials = Base64.getEncoder().encodeToString((user + ":" + password).getBytes(StandardCharsets.ISO_8859_1));
|
||||
String proxyHost = "localhost";
|
||||
String serverHost = "server";
|
||||
int serverPort = HttpScheme.HTTP.is(scenario.getScheme()) ? 80 : 443;
|
||||
|
|
|
@ -18,14 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.ByteBuffer;
|
||||
|
@ -34,7 +26,9 @@ import java.nio.charset.StandardCharsets;
|
|||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -48,13 +42,20 @@ import org.eclipse.jetty.http.HttpHeader;
|
|||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.toolchain.test.IO;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ArgumentsSource;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class HttpClientRedirectTest extends AbstractHttpClientServerTest
|
||||
{
|
||||
@ParameterizedTest
|
||||
|
@ -128,14 +129,13 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest
|
|||
{
|
||||
start(scenario, new RedirectHandler());
|
||||
|
||||
ExecutionException x = assertThrows(ExecutionException.class, ()->{
|
||||
client.newRequest("localhost", connector.getLocalPort())
|
||||
.scheme(scenario.getScheme())
|
||||
.method(HttpMethod.DELETE)
|
||||
.path("/301/localhost/done")
|
||||
.timeout(5, TimeUnit.SECONDS)
|
||||
.send();
|
||||
});
|
||||
ExecutionException x = assertThrows(ExecutionException.class, () ->
|
||||
client.newRequest("localhost", connector.getLocalPort())
|
||||
.scheme(scenario.getScheme())
|
||||
.method(HttpMethod.DELETE)
|
||||
.path("/301/localhost/done")
|
||||
.timeout(5, TimeUnit.SECONDS)
|
||||
.send());
|
||||
HttpResponseException xx = (HttpResponseException)x.getCause();
|
||||
Response response = xx.getResponse();
|
||||
assertNotNull(response);
|
||||
|
@ -170,13 +170,12 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest
|
|||
start(scenario, new RedirectHandler());
|
||||
client.setMaxRedirects(1);
|
||||
|
||||
ExecutionException x = assertThrows(ExecutionException.class, ()->{
|
||||
client.newRequest("localhost", connector.getLocalPort())
|
||||
.scheme(scenario.getScheme())
|
||||
.path("/303/localhost/302/localhost/done")
|
||||
.timeout(5, TimeUnit.SECONDS)
|
||||
.send();
|
||||
});
|
||||
ExecutionException x = assertThrows(ExecutionException.class, () ->
|
||||
client.newRequest("localhost", connector.getLocalPort())
|
||||
.scheme(scenario.getScheme())
|
||||
.path("/303/localhost/302/localhost/done")
|
||||
.timeout(5, TimeUnit.SECONDS)
|
||||
.send());
|
||||
HttpResponseException xx = (HttpResponseException)x.getCause();
|
||||
Response response = xx.getResponse();
|
||||
assertNotNull(response);
|
||||
|
@ -269,12 +268,11 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest
|
|||
@ArgumentsSource(ScenarioProvider.class)
|
||||
public void testRedirectWithWrongScheme(Scenario scenario) throws Exception
|
||||
{
|
||||
start(scenario, new AbstractHandler()
|
||||
start(scenario, new EmptyServerHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
protected void service(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
response.setStatus(303);
|
||||
response.setHeader("Location", "ssh://localhost:" + connector.getLocalPort() + "/path");
|
||||
}
|
||||
|
@ -439,12 +437,11 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest
|
|||
public void testRedirectWithCorruptedBody(Scenario scenario) throws Exception
|
||||
{
|
||||
byte[] bytes = "ok".getBytes(StandardCharsets.UTF_8);
|
||||
start(scenario, new AbstractHandler()
|
||||
start(scenario, new EmptyServerHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
protected void service(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
if (target.startsWith("/redirect"))
|
||||
{
|
||||
response.setStatus(HttpStatus.SEE_OTHER_303);
|
||||
|
@ -471,6 +468,60 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest
|
|||
assertArrayEquals(bytes, response.getContent());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ArgumentsSource(ScenarioProvider.class)
|
||||
public void testRedirectToSameURL(Scenario scenario) throws Exception
|
||||
{
|
||||
start(scenario, new EmptyServerHandler()
|
||||
{
|
||||
@Override
|
||||
protected void service(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
response.setStatus(HttpStatus.SEE_OTHER_303);
|
||||
response.setHeader(HttpHeader.LOCATION.asString(), request.getRequestURI());
|
||||
}
|
||||
});
|
||||
|
||||
ExecutionException x = assertThrows(ExecutionException.class, () ->
|
||||
client.newRequest("localhost", connector.getLocalPort())
|
||||
.scheme(scenario.getScheme())
|
||||
.send());
|
||||
assertThat(x.getCause(), Matchers.instanceOf(HttpResponseException.class));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ArgumentsSource(ScenarioProvider.class)
|
||||
public void testInfiniteRedirectLoopMustTimeout(Scenario scenario) throws Exception
|
||||
{
|
||||
AtomicLong counter = new AtomicLong();
|
||||
start(scenario, new EmptyServerHandler()
|
||||
{
|
||||
@Override
|
||||
protected void service(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.sleep(200);
|
||||
response.setStatus(HttpStatus.SEE_OTHER_303);
|
||||
response.setHeader(HttpHeader.LOCATION.asString(), "/" + counter.getAndIncrement());
|
||||
}
|
||||
catch (InterruptedException x)
|
||||
{
|
||||
throw new RuntimeException(x);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
assertThrows(TimeoutException.class, () ->
|
||||
{
|
||||
client.setMaxRedirects(-1);
|
||||
client.newRequest("localhost", connector.getLocalPort())
|
||||
.scheme(scenario.getScheme())
|
||||
.timeout(1, TimeUnit.SECONDS)
|
||||
.send();
|
||||
});
|
||||
}
|
||||
|
||||
private void testSameMethodRedirect(final Scenario scenario, final HttpMethod method, int redirectCode) throws Exception
|
||||
{
|
||||
testMethodRedirect(scenario, method, method, redirectCode);
|
||||
|
@ -519,10 +570,10 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest
|
|||
assertEquals(200, response.getStatus());
|
||||
}
|
||||
|
||||
private class RedirectHandler extends AbstractHandler
|
||||
private class RedirectHandler extends EmptyServerHandler
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
protected void service(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -551,10 +602,6 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest
|
|||
// Echo content back
|
||||
IO.copy(request.getInputStream(), response.getOutputStream());
|
||||
}
|
||||
finally
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,15 +35,18 @@ import javax.net.ssl.SSLPeerUnverifiedException;
|
|||
import javax.net.ssl.SSLSocket;
|
||||
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpScheme;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.io.ClientConnectionFactory;
|
||||
import org.eclipse.jetty.io.ClientConnector;
|
||||
import org.eclipse.jetty.io.ssl.SslClientConnectionFactory;
|
||||
import org.eclipse.jetty.io.ssl.SslHandshakeListener;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.util.thread.ExecutorThreadPool;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
|
@ -66,7 +69,7 @@ public class HttpClientTLSTest
|
|||
private ServerConnector connector;
|
||||
private HttpClient client;
|
||||
|
||||
private void startServer(SslContextFactory sslContextFactory, Handler handler) throws Exception
|
||||
private void startServer(SslContextFactory.Server sslContextFactory, Handler handler) throws Exception
|
||||
{
|
||||
ExecutorThreadPool serverThreads = new ExecutorThreadPool();
|
||||
serverThreads.setName("server");
|
||||
|
@ -79,22 +82,37 @@ public class HttpClientTLSTest
|
|||
server.start();
|
||||
}
|
||||
|
||||
private void startClient(SslContextFactory sslContextFactory) throws Exception
|
||||
private void startClient(SslContextFactory.Client sslContextFactory) throws Exception
|
||||
{
|
||||
ClientConnector clientConnector = new ClientConnector();
|
||||
clientConnector.setSelectors(1);
|
||||
clientConnector.setSslContextFactory(sslContextFactory);
|
||||
QueuedThreadPool clientThreads = new QueuedThreadPool();
|
||||
clientThreads.setName("client");
|
||||
client = new HttpClient(sslContextFactory);
|
||||
client.setExecutor(clientThreads);
|
||||
clientConnector.setExecutor(clientThreads);
|
||||
client = new HttpClient(new HttpClientTransportOverHTTP(clientConnector));
|
||||
client.start();
|
||||
}
|
||||
|
||||
private SslContextFactory createSslContextFactory()
|
||||
private SslContextFactory.Server createServerSslContextFactory()
|
||||
{
|
||||
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
|
||||
configureSslContextFactory(sslContextFactory);
|
||||
return sslContextFactory;
|
||||
}
|
||||
|
||||
private SslContextFactory.Client createClientSslContextFactory()
|
||||
{
|
||||
SslContextFactory.Client sslContextFactory = new SslContextFactory.Client();
|
||||
configureSslContextFactory(sslContextFactory);
|
||||
sslContextFactory.setEndpointIdentificationAlgorithm(null);
|
||||
return sslContextFactory;
|
||||
}
|
||||
|
||||
private void configureSslContextFactory(SslContextFactory sslContextFactory)
|
||||
{
|
||||
SslContextFactory sslContextFactory = new SslContextFactory();
|
||||
sslContextFactory.setEndpointIdentificationAlgorithm("");
|
||||
sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
|
||||
sslContextFactory.setKeyStorePassword("storepwd");
|
||||
return sslContextFactory;
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
|
@ -109,7 +127,7 @@ public class HttpClientTLSTest
|
|||
@Test
|
||||
public void testNoCommonTLSProtocol() throws Exception
|
||||
{
|
||||
SslContextFactory serverTLSFactory = createSslContextFactory();
|
||||
SslContextFactory.Server serverTLSFactory = createServerSslContextFactory();
|
||||
serverTLSFactory.setIncludeProtocols("TLSv1.3");
|
||||
startServer(serverTLSFactory, new EmptyServerHandler());
|
||||
|
||||
|
@ -123,7 +141,7 @@ public class HttpClientTLSTest
|
|||
}
|
||||
});
|
||||
|
||||
SslContextFactory clientTLSFactory = createSslContextFactory();
|
||||
SslContextFactory.Client clientTLSFactory = createClientSslContextFactory();
|
||||
clientTLSFactory.setIncludeProtocols("TLSv1.2");
|
||||
startClient(clientTLSFactory);
|
||||
|
||||
|
@ -150,7 +168,7 @@ public class HttpClientTLSTest
|
|||
@Test
|
||||
public void testNoCommonTLSCiphers() throws Exception
|
||||
{
|
||||
SslContextFactory serverTLSFactory = createSslContextFactory();
|
||||
SslContextFactory.Server serverTLSFactory = createServerSslContextFactory();
|
||||
serverTLSFactory.setIncludeCipherSuites("TLS_RSA_WITH_AES_128_CBC_SHA");
|
||||
startServer(serverTLSFactory, new EmptyServerHandler());
|
||||
|
||||
|
@ -164,7 +182,7 @@ public class HttpClientTLSTest
|
|||
}
|
||||
});
|
||||
|
||||
SslContextFactory clientTLSFactory = createSslContextFactory();
|
||||
SslContextFactory.Client clientTLSFactory = createClientSslContextFactory();
|
||||
clientTLSFactory.setExcludeCipherSuites(".*_SHA$");
|
||||
startClient(clientTLSFactory);
|
||||
|
||||
|
@ -191,7 +209,7 @@ public class HttpClientTLSTest
|
|||
@Test
|
||||
public void testMismatchBetweenTLSProtocolAndTLSCiphersOnServer() throws Exception
|
||||
{
|
||||
SslContextFactory serverTLSFactory = createSslContextFactory();
|
||||
SslContextFactory.Server serverTLSFactory = createServerSslContextFactory();
|
||||
// TLS 1.1 protocol, but only TLS 1.2 ciphers.
|
||||
serverTLSFactory.setIncludeProtocols("TLSv1.1");
|
||||
serverTLSFactory.setIncludeCipherSuites("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256");
|
||||
|
@ -207,7 +225,7 @@ public class HttpClientTLSTest
|
|||
}
|
||||
});
|
||||
|
||||
SslContextFactory clientTLSFactory = createSslContextFactory();
|
||||
SslContextFactory.Client clientTLSFactory = createClientSslContextFactory();
|
||||
startClient(clientTLSFactory);
|
||||
|
||||
CountDownLatch clientLatch = new CountDownLatch(1);
|
||||
|
@ -236,7 +254,7 @@ public class HttpClientTLSTest
|
|||
@Test
|
||||
public void testMismatchBetweenTLSProtocolAndTLSCiphersOnClient() throws Exception
|
||||
{
|
||||
SslContextFactory serverTLSFactory = createSslContextFactory();
|
||||
SslContextFactory.Server serverTLSFactory = createServerSslContextFactory();
|
||||
startServer(serverTLSFactory, new EmptyServerHandler());
|
||||
|
||||
CountDownLatch serverLatch = new CountDownLatch(1);
|
||||
|
@ -249,7 +267,7 @@ public class HttpClientTLSTest
|
|||
}
|
||||
});
|
||||
|
||||
SslContextFactory clientTLSFactory = createSslContextFactory();
|
||||
SslContextFactory.Client clientTLSFactory = createClientSslContextFactory();
|
||||
// TLS 1.1 protocol, but only TLS 1.2 ciphers.
|
||||
clientTLSFactory.setIncludeProtocols("TLSv1.1");
|
||||
clientTLSFactory.setIncludeCipherSuites("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256");
|
||||
|
@ -278,7 +296,7 @@ public class HttpClientTLSTest
|
|||
@Test
|
||||
public void testHandshakeSucceeded() throws Exception
|
||||
{
|
||||
SslContextFactory serverTLSFactory = createSslContextFactory();
|
||||
SslContextFactory.Server serverTLSFactory = createServerSslContextFactory();
|
||||
startServer(serverTLSFactory, new EmptyServerHandler());
|
||||
|
||||
CountDownLatch serverLatch = new CountDownLatch(1);
|
||||
|
@ -291,7 +309,7 @@ public class HttpClientTLSTest
|
|||
}
|
||||
});
|
||||
|
||||
SslContextFactory clientTLSFactory = createSslContextFactory();
|
||||
SslContextFactory.Client clientTLSFactory = createClientSslContextFactory();
|
||||
startClient(clientTLSFactory);
|
||||
|
||||
CountDownLatch clientLatch = new CountDownLatch(1);
|
||||
|
@ -317,7 +335,7 @@ public class HttpClientTLSTest
|
|||
@Test
|
||||
public void testHandshakeSucceededWithSessionResumption() throws Exception
|
||||
{
|
||||
SslContextFactory serverTLSFactory = createSslContextFactory();
|
||||
SslContextFactory.Server serverTLSFactory = createServerSslContextFactory();
|
||||
startServer(serverTLSFactory, new EmptyServerHandler());
|
||||
|
||||
AtomicReference<byte[]> serverSession = new AtomicReference<>();
|
||||
|
@ -330,7 +348,7 @@ public class HttpClientTLSTest
|
|||
}
|
||||
});
|
||||
|
||||
SslContextFactory clientTLSFactory = createSslContextFactory();
|
||||
SslContextFactory.Client clientTLSFactory = createClientSslContextFactory();
|
||||
startClient(clientTLSFactory);
|
||||
|
||||
AtomicReference<byte[]> clientSession = new AtomicReference<>();
|
||||
|
@ -397,10 +415,10 @@ public class HttpClientTLSTest
|
|||
@Test
|
||||
public void testClientRawCloseDoesNotInvalidateSession() throws Exception
|
||||
{
|
||||
SslContextFactory serverTLSFactory = createSslContextFactory();
|
||||
SslContextFactory.Server serverTLSFactory = createServerSslContextFactory();
|
||||
startServer(serverTLSFactory, new EmptyServerHandler());
|
||||
|
||||
SslContextFactory clientTLSFactory = createSslContextFactory();
|
||||
SslContextFactory clientTLSFactory = createClientSslContextFactory();
|
||||
clientTLSFactory.start();
|
||||
|
||||
String host = "localhost";
|
||||
|
@ -452,13 +470,17 @@ public class HttpClientTLSTest
|
|||
@Test
|
||||
public void testServerRawCloseDetectedByClient() throws Exception
|
||||
{
|
||||
SslContextFactory serverTLSFactory = createSslContextFactory();
|
||||
SslContextFactory serverTLSFactory = createServerSslContextFactory();
|
||||
serverTLSFactory.start();
|
||||
try (ServerSocket server = new ServerSocket(0))
|
||||
{
|
||||
ClientConnector clientConnector = new ClientConnector();
|
||||
clientConnector.setSelectors(1);
|
||||
QueuedThreadPool clientThreads = new QueuedThreadPool();
|
||||
clientThreads.setName("client");
|
||||
client = new HttpClient(createSslContextFactory())
|
||||
clientConnector.setExecutor(clientThreads);
|
||||
clientConnector.setSslContextFactory(createClientSslContextFactory());
|
||||
client = new HttpClient(new HttpClientTransportOverHTTP(clientConnector))
|
||||
{
|
||||
@Override
|
||||
protected ClientConnectionFactory newSslClientConnectionFactory(ClientConnectionFactory connectionFactory)
|
||||
|
@ -468,7 +490,6 @@ public class HttpClientTLSTest
|
|||
return ssl;
|
||||
}
|
||||
};
|
||||
client.setExecutor(clientThreads);
|
||||
client.start();
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
|
@ -488,7 +509,7 @@ public class HttpClientTLSTest
|
|||
while (true)
|
||||
{
|
||||
String line = reader.readLine();
|
||||
if (line == null || line.isEmpty())
|
||||
if (StringUtil.isEmpty(line))
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -522,10 +543,10 @@ public class HttpClientTLSTest
|
|||
@Test
|
||||
public void testHostNameVerificationFailure() throws Exception
|
||||
{
|
||||
SslContextFactory serverTLSFactory = createSslContextFactory();
|
||||
SslContextFactory.Server serverTLSFactory = createServerSslContextFactory();
|
||||
startServer(serverTLSFactory, new EmptyServerHandler());
|
||||
|
||||
SslContextFactory clientTLSFactory = createSslContextFactory();
|
||||
SslContextFactory.Client clientTLSFactory = createClientSslContextFactory();
|
||||
// Make sure the host name is not verified at the TLS level.
|
||||
clientTLSFactory.setEndpointIdentificationAlgorithm(null);
|
||||
// Add host name verification after the TLS handshake.
|
||||
|
|
|
@ -50,7 +50,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -65,7 +64,6 @@ import org.eclipse.jetty.client.api.Response;
|
|||
import org.eclipse.jetty.client.api.Result;
|
||||
import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
|
||||
import org.eclipse.jetty.client.http.HttpConnectionOverHTTP;
|
||||
import org.eclipse.jetty.client.http.HttpDestinationOverHTTP;
|
||||
import org.eclipse.jetty.client.util.BufferingResponseListener;
|
||||
import org.eclipse.jetty.client.util.BytesContentProvider;
|
||||
import org.eclipse.jetty.client.util.DeferredContentProvider;
|
||||
|
@ -79,8 +77,10 @@ import org.eclipse.jetty.http.HttpMethod;
|
|||
import org.eclipse.jetty.http.HttpScheme;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.io.AbstractConnection;
|
||||
import org.eclipse.jetty.io.ClientConnector;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.toolchain.test.Net;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
|
@ -111,7 +111,6 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
{
|
||||
public WorkDir testdir;
|
||||
|
||||
|
||||
@ParameterizedTest
|
||||
@ArgumentsSource(ScenarioProvider.class)
|
||||
public void testStoppingClosesConnections(Scenario scenario) throws Exception
|
||||
|
@ -124,7 +123,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
Response response = client.GET(scenario.getScheme() + "://" + host + ":" + port + path);
|
||||
assertEquals(200, response.getStatus());
|
||||
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scenario.getScheme(), host, port);
|
||||
HttpDestination destination = (HttpDestination)client.getDestination(scenario.getScheme(), host, port);
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
|
||||
long start = System.nanoTime();
|
||||
|
@ -187,7 +186,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
start(scenario, new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
response.getOutputStream().write(data);
|
||||
baseRequest.setHandled(true);
|
||||
|
@ -212,7 +211,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
start(scenario, new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
ServletOutputStream output = response.getOutputStream();
|
||||
|
@ -245,7 +244,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
start(scenario, new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
ServletOutputStream output = response.getOutputStream();
|
||||
|
@ -282,7 +281,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
start(scenario, new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
String value = request.getParameter(paramName);
|
||||
|
@ -315,7 +314,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
start(scenario, new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
String value = request.getParameter(paramName);
|
||||
|
@ -349,7 +348,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
start(scenario, new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
consume(request.getInputStream(), true);
|
||||
|
@ -381,7 +380,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
start(scenario, new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
consume(request.getInputStream(), true);
|
||||
|
@ -412,7 +411,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
start(scenario, new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
consume(request.getInputStream(), true);
|
||||
|
@ -493,7 +492,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
start(scenario, new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
if (target.endsWith("/one"))
|
||||
baseRequest.getHttpChannel().getEndPoint().close();
|
||||
|
@ -612,7 +611,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
start(scenario, new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
// Echo back
|
||||
IO.copy(request.getInputStream(), response.getOutputStream());
|
||||
|
@ -634,7 +633,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
@Override
|
||||
public Iterator<ByteBuffer> iterator()
|
||||
{
|
||||
return new Iterator<ByteBuffer>()
|
||||
return new Iterator<>()
|
||||
{
|
||||
@Override
|
||||
public boolean hasNext()
|
||||
|
@ -681,7 +680,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
.scheme(scenario.getScheme())
|
||||
.onRequestBegin(request ->
|
||||
{
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scenario.getScheme(), host, port);
|
||||
HttpDestination destination = (HttpDestination)client.getDestination(scenario.getScheme(), host, port);
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
connectionPool.getActiveConnections().iterator().next().close();
|
||||
})
|
||||
|
@ -706,7 +705,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
start(scenario, new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws ServletException
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -722,13 +721,12 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
|
||||
final String host = "localhost";
|
||||
final int port = connector.getLocalPort();
|
||||
assertThrows(TimeoutException.class, ()->{
|
||||
client.newRequest(host, port)
|
||||
.scheme(scenario.getScheme())
|
||||
.idleTimeout(idleTimeout, TimeUnit.MILLISECONDS)
|
||||
.timeout(3 * idleTimeout, TimeUnit.MILLISECONDS)
|
||||
.send();
|
||||
});
|
||||
assertThrows(TimeoutException.class, () ->
|
||||
client.newRequest(host, port)
|
||||
.scheme(scenario.getScheme())
|
||||
.idleTimeout(idleTimeout, TimeUnit.MILLISECONDS)
|
||||
.timeout(3 * idleTimeout, TimeUnit.MILLISECONDS)
|
||||
.send());
|
||||
|
||||
// Make another request without specifying the idle timeout, should not fail
|
||||
ContentResponse response = client.newRequest(host, port)
|
||||
|
@ -744,6 +742,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
@ArgumentsSource(ScenarioProvider.class)
|
||||
public void testSendToIPv6Address(Scenario scenario) throws Exception
|
||||
{
|
||||
Assumptions.assumeTrue(Net.isIpv6InterfaceAvailable());
|
||||
start(scenario, new EmptyServerHandler());
|
||||
|
||||
ContentResponse response = client.newRequest("[::1]", connector.getLocalPort())
|
||||
|
@ -763,7 +762,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
start(scenario, new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
response.setHeader(headerName, "X");
|
||||
|
@ -821,7 +820,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
start(scenario, new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
response.getOutputStream().write(new byte[length]);
|
||||
|
@ -882,14 +881,14 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
public void testConnectHostWithMultipleAddresses(Scenario scenario) throws Exception
|
||||
{
|
||||
startServer(scenario, new EmptyServerHandler());
|
||||
startClient(scenario, null, client ->
|
||||
startClient(scenario, client ->
|
||||
{
|
||||
client.setSocketAddressResolver(new SocketAddressResolver.Async(client.getExecutor(), client.getScheduler(), 5000)
|
||||
{
|
||||
@Override
|
||||
public void resolve(String host, int port, Promise<List<InetSocketAddress>> promise)
|
||||
{
|
||||
super.resolve(host, port, new Promise<List<InetSocketAddress>>()
|
||||
super.resolve(host, port, new Promise<>()
|
||||
{
|
||||
@Override
|
||||
public void succeeded(List<InetSocketAddress> result)
|
||||
|
@ -925,7 +924,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
start(scenario, new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
ArrayList<String> userAgents = Collections.list(request.getHeaders("User-Agent"));
|
||||
|
@ -959,7 +958,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
start(scenario, new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
ArrayList<String> userAgents = Collections.list(request.getHeaders("User-Agent"));
|
||||
|
@ -1161,7 +1160,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
start(scenario, new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
response.getOutputStream().write(content);
|
||||
|
@ -1205,7 +1204,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
start(scenario, new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
assertEquals(host, request.getServerName());
|
||||
|
@ -1227,7 +1226,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
start(scenario, new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
// Send the headers at this point, then write the content
|
||||
byte[] content = "TEST".getBytes("UTF-8");
|
||||
|
@ -1255,7 +1254,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
start(scenario, new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
// Send the headers at this point, then write the content
|
||||
response.flushBuffer();
|
||||
|
@ -1313,7 +1312,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
start(scenario, new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
request.startAsync();
|
||||
|
@ -1344,9 +1343,8 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
{
|
||||
Assumptions.assumeTrue(HttpScheme.HTTP.is(scenario.getScheme()));
|
||||
|
||||
ExecutionException e = assertThrows(ExecutionException.class, ()->{
|
||||
testContentDelimitedByEOFWithSlowRequest(scenario, HttpVersion.HTTP_1_0, 1024);
|
||||
});
|
||||
ExecutionException e = assertThrows(ExecutionException.class, () ->
|
||||
testContentDelimitedByEOFWithSlowRequest(scenario, HttpVersion.HTTP_1_0, 1024));
|
||||
|
||||
assertThat(e.getCause(), instanceOf(BadMessageException.class));
|
||||
assertThat(e.getCause().getMessage(), containsString("Unknown content"));
|
||||
|
@ -1356,9 +1354,8 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
@ArgumentsSource(NonSslScenarioProvider.class)
|
||||
public void testBigContentDelimitedByEOFWithSlowRequestHTTP10(Scenario scenario) throws Exception
|
||||
{
|
||||
ExecutionException e = assertThrows(ExecutionException.class, ()->{
|
||||
testContentDelimitedByEOFWithSlowRequest(scenario, HttpVersion.HTTP_1_0, 128 * 1024);
|
||||
});
|
||||
ExecutionException e = assertThrows(ExecutionException.class, () ->
|
||||
testContentDelimitedByEOFWithSlowRequest(scenario, HttpVersion.HTTP_1_0, 128 * 1024));
|
||||
|
||||
assertThat(e.getCause(), instanceOf(BadMessageException.class));
|
||||
assertThat(e.getCause().getMessage(), containsString("Unknown content"));
|
||||
|
@ -1392,7 +1389,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
start(scenario, new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
// Send Connection: close to avoid that the server chunks the content with HTTP 1.1.
|
||||
|
@ -1428,7 +1425,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
start(scenario, new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
int count = requests.incrementAndGet();
|
||||
if (count == maxRetries)
|
||||
|
@ -1457,7 +1454,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
start(scenario, new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
ServletOutputStream output = response.getOutputStream();
|
||||
|
@ -1507,14 +1504,16 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
startServer(scenario, new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
}
|
||||
});
|
||||
|
||||
final AtomicBoolean open = new AtomicBoolean();
|
||||
client = new HttpClient(new HttpClientTransportOverHTTP()
|
||||
ClientConnector clientConnector = new ClientConnector();
|
||||
clientConnector.setSslContextFactory(scenario.newClientSslContextFactory());
|
||||
client = new HttpClient(new HttpClientTransportOverHTTP(clientConnector)
|
||||
{
|
||||
@Override
|
||||
protected HttpConnectionOverHTTP newHttpConnection(EndPoint endPoint, HttpDestination destination, Promise<Connection> promise)
|
||||
|
@ -1529,7 +1528,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
}
|
||||
};
|
||||
}
|
||||
}, scenario.newSslContextFactory());
|
||||
});
|
||||
client.start();
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(2);
|
||||
|
@ -1613,10 +1612,11 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
@ArgumentsSource(ScenarioProvider.class)
|
||||
public void test_IPv6_Host(Scenario scenario) throws Exception
|
||||
{
|
||||
Assumptions.assumeTrue(Net.isIpv6InterfaceAvailable());
|
||||
start(scenario, new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
response.setContentType("text/plain");
|
||||
|
@ -1691,7 +1691,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
start(scenario, new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
assertThat(request.getHeader("Host"), Matchers.notNullValue());
|
||||
|
@ -1717,7 +1717,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
try (ServerSocket server = new ServerSocket(0))
|
||||
{
|
||||
int idleTimeout = 2000;
|
||||
startClient(scenario, null, httpClient ->
|
||||
startClient(scenario, httpClient ->
|
||||
{
|
||||
httpClient.setMaxConnectionsPerDestination(1);
|
||||
httpClient.setIdleTimeout(idleTimeout);
|
||||
|
|
|
@ -18,13 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
|
@ -38,7 +31,6 @@ import java.nio.charset.StandardCharsets;
|
|||
import java.util.Locale;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
@ -50,17 +42,28 @@ import org.eclipse.jetty.http.HttpHeader;
|
|||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.toolchain.test.Net;
|
||||
import org.eclipse.jetty.util.Fields;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.junit.jupiter.api.Assumptions;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ArgumentsSource;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class HttpClientURITest extends AbstractHttpClientServerTest
|
||||
{
|
||||
@ParameterizedTest
|
||||
@ArgumentsSource(ScenarioProvider.class)
|
||||
public void testIPv6Host(Scenario scenario) throws Exception
|
||||
{
|
||||
Assumptions.assumeTrue(Net.isIpv6InterfaceAvailable());
|
||||
start(scenario, new EmptyServerHandler());
|
||||
|
||||
String host = "::1";
|
||||
|
@ -607,7 +610,7 @@ public class HttpClientURITest extends AbstractHttpClientServerTest
|
|||
while (true)
|
||||
{
|
||||
String line = reader.readLine();
|
||||
if (line == null || line.isEmpty())
|
||||
if (StringUtil.isEmpty(line))
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,9 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Random;
|
||||
|
@ -29,7 +26,6 @@ import java.util.concurrent.TimeUnit;
|
|||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
@ -37,7 +33,6 @@ import org.eclipse.jetty.client.api.Connection;
|
|||
import org.eclipse.jetty.client.http.HttpChannelOverHTTP;
|
||||
import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
|
||||
import org.eclipse.jetty.client.http.HttpConnectionOverHTTP;
|
||||
import org.eclipse.jetty.client.http.HttpDestinationOverHTTP;
|
||||
import org.eclipse.jetty.client.util.BytesContentProvider;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
|
@ -46,9 +41,11 @@ import org.eclipse.jetty.server.ServerConnector;
|
|||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.util.Promise;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class HttpClientUploadDuringServerShutdown
|
||||
{
|
||||
/**
|
||||
|
@ -67,7 +64,7 @@ public class HttpClientUploadDuringServerShutdown
|
|||
server.setHandler(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
byte[] buffer = new byte[1024];
|
||||
|
@ -105,7 +102,7 @@ public class HttpClientUploadDuringServerShutdown
|
|||
{
|
||||
QueuedThreadPool clientThreads = new QueuedThreadPool();
|
||||
clientThreads.setName("client");
|
||||
HttpClient client = new HttpClient(new HttpClientTransportOverHTTP(2), null);
|
||||
HttpClient client = new HttpClient(new HttpClientTransportOverHTTP(2));
|
||||
client.setMaxConnectionsPerDestination(2);
|
||||
client.setIdleTimeout(10000);
|
||||
client.setExecutor(clientThreads);
|
||||
|
@ -144,7 +141,7 @@ public class HttpClientUploadDuringServerShutdown
|
|||
server.setHandler(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
endPointRef.set(baseRequest.getHttpChannel().getEndPoint());
|
||||
|
@ -212,7 +209,7 @@ public class HttpClientUploadDuringServerShutdown
|
|||
}
|
||||
};
|
||||
}
|
||||
}, null);
|
||||
});
|
||||
client.setIdleTimeout(10000);
|
||||
client.setExecutor(clientThreads);
|
||||
client.start();
|
||||
|
@ -252,7 +249,7 @@ public class HttpClientUploadDuringServerShutdown
|
|||
|
||||
assertTrue(completeLatch.await(5, TimeUnit.SECONDS));
|
||||
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination("http", "localhost", connector.getLocalPort());
|
||||
HttpDestination destination = (HttpDestination)client.getDestination("http", "localhost", connector.getLocalPort());
|
||||
DuplexConnectionPool pool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
assertEquals(0, pool.getConnectionCount());
|
||||
assertEquals(0, pool.getIdleConnections().size());
|
||||
|
|
|
@ -18,10 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
|
@ -39,7 +35,6 @@ import org.eclipse.jetty.client.api.ContentResponse;
|
|||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.api.Response;
|
||||
import org.eclipse.jetty.client.api.Result;
|
||||
import org.eclipse.jetty.client.http.HttpDestinationOverHTTP;
|
||||
import org.eclipse.jetty.client.util.ByteBufferContentProvider;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
|
@ -51,12 +46,16 @@ import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
|
|||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ArgumentsSource;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
||||
{
|
||||
@Override
|
||||
public HttpClient newHttpClient(Scenario scenario, HttpClientTransport transport)
|
||||
public HttpClient newHttpClient(HttpClientTransport transport)
|
||||
{
|
||||
HttpClient client = super.newHttpClient(scenario, transport);
|
||||
HttpClient client = super.newHttpClient(transport);
|
||||
client.setStrictEventOrdering(false);
|
||||
return client;
|
||||
}
|
||||
|
@ -69,7 +68,7 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
|
||||
String host = "localhost";
|
||||
int port = connector.getLocalPort();
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scenario.getScheme(), host, port);
|
||||
HttpDestination destination = (HttpDestination)client.getDestination(scenario.getScheme(), host, port);
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
|
||||
final Collection<Connection> idleConnections = connectionPool.getIdleConnections();
|
||||
|
@ -120,7 +119,7 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
|
||||
String host = "localhost";
|
||||
int port = connector.getLocalPort();
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scenario.getScheme(), host, port);
|
||||
HttpDestination destination = (HttpDestination)client.getDestination(scenario.getScheme(), host, port);
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
|
||||
final Collection<Connection> idleConnections = connectionPool.getIdleConnections();
|
||||
|
@ -172,7 +171,7 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
|
||||
String host = "localhost";
|
||||
int port = connector.getLocalPort();
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scenario.getScheme(), host, port);
|
||||
HttpDestination destination = (HttpDestination)client.getDestination(scenario.getScheme(), host, port);
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
|
||||
final Queue<Connection> idleConnections = connectionPool.getIdleConnections();
|
||||
|
@ -234,7 +233,7 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
|
||||
String host = "localhost";
|
||||
int port = connector.getLocalPort();
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scenario.getScheme(), host, port);
|
||||
HttpDestination destination = (HttpDestination)client.getDestination(scenario.getScheme(), host, port);
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
|
||||
final Collection<Connection> idleConnections = connectionPool.getIdleConnections();
|
||||
|
@ -308,7 +307,7 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
|
||||
String host = "localhost";
|
||||
int port = connector.getLocalPort();
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scenario.getScheme(), host, port);
|
||||
HttpDestination destination = (HttpDestination)client.getDestination(scenario.getScheme(), host, port);
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
|
||||
final Collection<Connection> idleConnections = connectionPool.getIdleConnections();
|
||||
|
@ -351,7 +350,7 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
|
||||
String host = "localhost";
|
||||
int port = connector.getLocalPort();
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scenario.getScheme(), host, port);
|
||||
HttpDestination destination = (HttpDestination)client.getDestination(scenario.getScheme(), host, port);
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
|
||||
final Collection<Connection> idleConnections = connectionPool.getIdleConnections();
|
||||
|
@ -400,7 +399,7 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
|
||||
String host = "localhost";
|
||||
int port = connector.getLocalPort();
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scenario.getScheme(), host, port);
|
||||
HttpDestination destination = (HttpDestination)client.getDestination(scenario.getScheme(), host, port);
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
|
||||
final Collection<Connection> idleConnections = connectionPool.getIdleConnections();
|
||||
|
@ -448,7 +447,7 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
|
||||
String host = "localhost";
|
||||
int port = connector.getLocalPort();
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scenario.getScheme(), host, port);
|
||||
HttpDestination destination = (HttpDestination)client.getDestination(scenario.getScheme(), host, port);
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
|
||||
final Collection<Connection> idleConnections = connectionPool.getIdleConnections();
|
||||
|
@ -481,7 +480,7 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
|
||||
String host = "localhost";
|
||||
int port = connector.getLocalPort();
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scenario.getScheme(), host, port);
|
||||
HttpDestination destination = (HttpDestination)client.getDestination(scenario.getScheme(), host, port);
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
|
||||
final Collection<Connection> idleConnections = connectionPool.getIdleConnections();
|
||||
|
|
|
@ -18,12 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
@ -39,7 +33,6 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.api.Result;
|
||||
import org.eclipse.jetty.client.http.HttpDestinationOverHTTP;
|
||||
import org.eclipse.jetty.client.util.ByteBufferContentProvider;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
|
@ -47,6 +40,12 @@ import org.eclipse.jetty.util.log.StacklessLogging;
|
|||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ArgumentsSource;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class HttpRequestAbortTest extends AbstractHttpClientServerTest
|
||||
{
|
||||
@ParameterizedTest
|
||||
|
@ -112,7 +111,7 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest
|
|||
assertSame(cause, x.getCause());
|
||||
assertFalse(begin.get());
|
||||
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scenario.getScheme(), "localhost", connector.getLocalPort());
|
||||
HttpDestination destination = (HttpDestination)client.getDestination(scenario.getScheme(), "localhost", connector.getLocalPort());
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
assertEquals(0, connectionPool.getConnectionCount());
|
||||
assertEquals(0, connectionPool.getActiveConnections().size());
|
||||
|
@ -156,7 +155,7 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest
|
|||
assertSame(cause, x.getCause());
|
||||
assertFalse(committed.await(1, TimeUnit.SECONDS));
|
||||
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scenario.getScheme(), "localhost", connector.getLocalPort());
|
||||
HttpDestination destination = (HttpDestination)client.getDestination(scenario.getScheme(), "localhost", connector.getLocalPort());
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
assertEquals(0, connectionPool.getConnectionCount());
|
||||
assertEquals(0, connectionPool.getActiveConnections().size());
|
||||
|
@ -200,7 +199,7 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest
|
|||
assertSame(cause, x.getCause());
|
||||
assertFalse(committed.await(1, TimeUnit.SECONDS));
|
||||
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scenario.getScheme(), "localhost", connector.getLocalPort());
|
||||
HttpDestination destination = (HttpDestination)client.getDestination(scenario.getScheme(), "localhost", connector.getLocalPort());
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
assertEquals(0, connectionPool.getConnectionCount());
|
||||
assertEquals(0, connectionPool.getActiveConnections().size());
|
||||
|
@ -235,7 +234,7 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest
|
|||
if (aborted.get())
|
||||
assertSame(cause, x.getCause());
|
||||
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scenario.getScheme(), "localhost", connector.getLocalPort());
|
||||
HttpDestination destination = (HttpDestination)client.getDestination(scenario.getScheme(), "localhost", connector.getLocalPort());
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
assertEquals(0, connectionPool.getConnectionCount());
|
||||
assertEquals(0, connectionPool.getActiveConnections().size());
|
||||
|
@ -293,7 +292,7 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest
|
|||
if (aborted.get())
|
||||
assertSame(cause, x.getCause());
|
||||
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scenario.getScheme(), "localhost", connector.getLocalPort());
|
||||
HttpDestination destination = (HttpDestination)client.getDestination(scenario.getScheme(), "localhost", connector.getLocalPort());
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
assertEquals(0, connectionPool.getConnectionCount());
|
||||
assertEquals(0, connectionPool.getActiveConnections().size());
|
||||
|
@ -353,7 +352,7 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest
|
|||
|
||||
assertTrue(serverLatch.await(5, TimeUnit.SECONDS));
|
||||
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scenario.getScheme(), "localhost", connector.getLocalPort());
|
||||
HttpDestination destination = (HttpDestination)client.getDestination(scenario.getScheme(), "localhost", connector.getLocalPort());
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
assertEquals(0, connectionPool.getConnectionCount());
|
||||
assertEquals(0, connectionPool.getActiveConnections().size());
|
||||
|
@ -460,7 +459,7 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest
|
|||
assertSame(cause, x.getCause());
|
||||
}
|
||||
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scenario.getScheme(), "localhost", connector.getLocalPort());
|
||||
HttpDestination destination = (HttpDestination)client.getDestination(scenario.getScheme(), "localhost", connector.getLocalPort());
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
assertEquals(0, connectionPool.getConnectionCount());
|
||||
assertEquals(0, connectionPool.getActiveConnections().size());
|
||||
|
|
|
@ -30,7 +30,7 @@ public class InsufficientThreadsDetectionTest
|
|||
public void testInsufficientThreads()
|
||||
{
|
||||
QueuedThreadPool clientThreads = new QueuedThreadPool(1);
|
||||
HttpClient httpClient = new HttpClient(new HttpClientTransportOverHTTP(1), null);
|
||||
HttpClient httpClient = new HttpClient(new HttpClientTransportOverHTTP(1));
|
||||
httpClient.setExecutor(clientThreads);
|
||||
assertThrows(IllegalStateException.class, httpClient::start);
|
||||
}
|
||||
|
@ -39,14 +39,14 @@ public class InsufficientThreadsDetectionTest
|
|||
public void testInsufficientThreadsForMultipleHttpClients() throws Exception
|
||||
{
|
||||
QueuedThreadPool clientThreads = new QueuedThreadPool(3);
|
||||
HttpClient httpClient1 = new HttpClient(new HttpClientTransportOverHTTP(1), null);
|
||||
HttpClient httpClient1 = new HttpClient(new HttpClientTransportOverHTTP(1));
|
||||
httpClient1.setExecutor(clientThreads);
|
||||
httpClient1.start();
|
||||
|
||||
assertThrows(IllegalStateException.class, () ->
|
||||
{
|
||||
// Share the same thread pool with another instance.
|
||||
HttpClient httpClient2 = new HttpClient(new HttpClientTransportOverHTTP(1), null);
|
||||
HttpClient httpClient2 = new HttpClient(new HttpClientTransportOverHTTP(1));
|
||||
httpClient2.setExecutor(clientThreads);
|
||||
httpClient2.start();
|
||||
});
|
||||
|
|
|
@ -93,7 +93,7 @@ public class LivelockTest
|
|||
|
||||
int count = 5;
|
||||
HttpClientTransport transport = new HttpClientTransportOverHTTP(1);
|
||||
client = new HttpClient(transport, null);
|
||||
client = new HttpClient(transport);
|
||||
client.setMaxConnectionsPerDestination(2 * count);
|
||||
client.setMaxRequestsQueuedPerDestination(2 * count);
|
||||
client.setSocketAddressResolver(new SocketAddressResolver.Sync());
|
||||
|
|
|
@ -18,12 +18,13 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.Net;
|
||||
import org.junit.jupiter.api.Assumptions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class ProxyConfigurationTest
|
||||
{
|
||||
@Test
|
||||
|
@ -70,6 +71,7 @@ public class ProxyConfigurationTest
|
|||
@Test
|
||||
public void testProxyMatchesWithIncludesAndExcludesIPv6() throws Exception
|
||||
{
|
||||
Assumptions.assumeTrue(Net.isIpv6InterfaceAvailable());
|
||||
HttpProxy proxy = new HttpProxy("host", 0);
|
||||
proxy.getIncludedAddresses().add("[1::2:3:4]");
|
||||
proxy.getExcludedAddresses().add("[1::2:3:4]:5");
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
@ -30,14 +28,14 @@ import java.util.concurrent.TimeUnit;
|
|||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
|
||||
import org.eclipse.jetty.client.http.HttpDestinationOverHTTP;
|
||||
import org.eclipse.jetty.client.util.FutureResponseListener;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class ServerConnectionCloseTest
|
||||
{
|
||||
private HttpClient client;
|
||||
|
@ -46,7 +44,7 @@ public class ServerConnectionCloseTest
|
|||
{
|
||||
QueuedThreadPool clientThreads = new QueuedThreadPool();
|
||||
clientThreads.setName("client");
|
||||
client = new HttpClient(new HttpClientTransportOverHTTP(1), null);
|
||||
client = new HttpClient(new HttpClientTransportOverHTTP(1));
|
||||
client.setExecutor(clientThreads);
|
||||
client.start();
|
||||
}
|
||||
|
@ -149,7 +147,7 @@ public class ServerConnectionCloseTest
|
|||
Thread.sleep(1000);
|
||||
|
||||
// Connection should have been removed from pool.
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination("http", "localhost", port);
|
||||
HttpDestination destination = (HttpDestination)client.getDestination("http", "localhost", port);
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
assertEquals(0, connectionPool.getConnectionCount());
|
||||
assertEquals(0, connectionPool.getIdleConnectionCount());
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
@ -33,30 +31,37 @@ import javax.net.ssl.SSLSocket;
|
|||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
|
||||
import org.eclipse.jetty.client.http.HttpDestinationOverHTTP;
|
||||
import org.eclipse.jetty.client.util.FutureResponseListener;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.io.ClientConnector;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.EnumSource;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class TLSServerConnectionCloseTest
|
||||
{
|
||||
private HttpClient client;
|
||||
|
||||
private void startClient() throws Exception
|
||||
{
|
||||
SslContextFactory sslContextFactory = new SslContextFactory();
|
||||
sslContextFactory.setEndpointIdentificationAlgorithm("");
|
||||
ClientConnector clientConnector = new ClientConnector();
|
||||
clientConnector.setSelectors(1);
|
||||
|
||||
SslContextFactory.Client sslContextFactory = new SslContextFactory.Client();
|
||||
sslContextFactory.setEndpointIdentificationAlgorithm(null);
|
||||
sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
|
||||
sslContextFactory.setKeyStorePassword("storepwd");
|
||||
clientConnector.setSslContextFactory(sslContextFactory);
|
||||
|
||||
QueuedThreadPool clientThreads = new QueuedThreadPool();
|
||||
clientThreads.setName("client");
|
||||
client = new HttpClient(new HttpClientTransportOverHTTP(1), sslContextFactory);
|
||||
client.setExecutor(clientThreads);
|
||||
clientConnector.setExecutor(clientThreads);
|
||||
|
||||
client = new HttpClient(new HttpClientTransportOverHTTP(clientConnector));
|
||||
client.start();
|
||||
}
|
||||
|
||||
|
@ -168,7 +173,7 @@ public class TLSServerConnectionCloseTest
|
|||
Thread.sleep(1000);
|
||||
|
||||
// Connection should have been removed from pool.
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination("http", "localhost", port);
|
||||
HttpDestination destination = (HttpDestination)client.getDestination("http", "localhost", port);
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
assertEquals(0, connectionPool.getConnectionCount());
|
||||
assertEquals(0, connectionPool.getIdleConnectionCount());
|
||||
|
|
|
@ -42,13 +42,13 @@ import org.junit.jupiter.params.provider.ArgumentsSource;
|
|||
public class ValidatingConnectionPoolTest extends AbstractHttpClientServerTest
|
||||
{
|
||||
@Override
|
||||
public HttpClient newHttpClient(Scenario scenario, HttpClientTransport transport)
|
||||
public HttpClient newHttpClient(HttpClientTransport transport)
|
||||
{
|
||||
long timeout = 1000;
|
||||
transport.setConnectionPoolFactory(destination ->
|
||||
new ValidatingConnectionPool(destination, destination.getHttpClient().getMaxConnectionsPerDestination(), destination, destination.getHttpClient().getScheduler(), timeout));
|
||||
|
||||
return super.newHttpClient(scenario, transport);
|
||||
return super.newHttpClient(transport);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
|
|
|
@ -26,8 +26,10 @@ import java.util.function.Supplier;
|
|||
import org.eclipse.jetty.client.AbstractHttpClientServerTest;
|
||||
import org.eclipse.jetty.client.ConnectionPool;
|
||||
import org.eclipse.jetty.client.DuplexConnectionPool;
|
||||
import org.eclipse.jetty.client.DuplexHttpDestination;
|
||||
import org.eclipse.jetty.client.EmptyServerHandler;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.HttpDestination;
|
||||
import org.eclipse.jetty.client.Origin;
|
||||
import org.eclipse.jetty.client.api.Connection;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
|
@ -56,7 +58,7 @@ public class HttpDestinationOverHTTPTest extends AbstractHttpClientServerTest
|
|||
{
|
||||
start(scenario, new EmptyServerHandler());
|
||||
|
||||
try(HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", connector.getLocalPort())))
|
||||
try(HttpDestination destination = new DuplexHttpDestination(client, new Origin("http", "localhost", connector.getLocalPort())))
|
||||
{
|
||||
destination.start();
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
|
@ -76,7 +78,7 @@ public class HttpDestinationOverHTTPTest extends AbstractHttpClientServerTest
|
|||
{
|
||||
start(scenario, new EmptyServerHandler());
|
||||
|
||||
try(HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", connector.getLocalPort())))
|
||||
try(HttpDestination destination = new DuplexHttpDestination(client, new Origin("http", "localhost", connector.getLocalPort())))
|
||||
{
|
||||
destination.start();
|
||||
|
||||
|
@ -102,7 +104,7 @@ public class HttpDestinationOverHTTPTest extends AbstractHttpClientServerTest
|
|||
|
||||
final CountDownLatch idleLatch = new CountDownLatch(1);
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", connector.getLocalPort()))
|
||||
HttpDestination destination = new DuplexHttpDestination(client, new Origin("http", "localhost", connector.getLocalPort()))
|
||||
{
|
||||
@Override
|
||||
protected ConnectionPool newConnectionPool(HttpClient client)
|
||||
|
@ -126,30 +128,29 @@ public class HttpDestinationOverHTTPTest extends AbstractHttpClientServerTest
|
|||
};
|
||||
}
|
||||
};
|
||||
{
|
||||
destination.start();
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
Connection connection1 = connectionPool.acquire();
|
||||
|
||||
// Make sure we entered idleCreated().
|
||||
assertTrue(idleLatch.await(5, TimeUnit.SECONDS));
|
||||
destination.start();
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
Connection connection1 = connectionPool.acquire();
|
||||
|
||||
// There are no available existing connections, so acquire()
|
||||
// returns null because we delayed idleCreated() above
|
||||
assertNull(connection1);
|
||||
// Make sure we entered idleCreated().
|
||||
assertTrue(idleLatch.await(5, TimeUnit.SECONDS));
|
||||
|
||||
// Second attempt also returns null because we delayed idleCreated() above.
|
||||
Connection connection2 = connectionPool.acquire();
|
||||
assertNull(connection2);
|
||||
// There are no available existing connections, so acquire()
|
||||
// returns null because we delayed idleCreated() above
|
||||
assertNull(connection1);
|
||||
|
||||
latch.countDown();
|
||||
// Second attempt also returns null because we delayed idleCreated() above.
|
||||
Connection connection2 = connectionPool.acquire();
|
||||
assertNull(connection2);
|
||||
|
||||
// There must be 2 idle connections.
|
||||
Connection connection = pollIdleConnection(connectionPool, 5, TimeUnit.SECONDS);
|
||||
assertNotNull(connection);
|
||||
connection = pollIdleConnection(connectionPool, 5, TimeUnit.SECONDS);
|
||||
assertNotNull(connection);
|
||||
}
|
||||
latch.countDown();
|
||||
|
||||
// There must be 2 idle connections.
|
||||
Connection connection = pollIdleConnection(connectionPool, 5, TimeUnit.SECONDS);
|
||||
assertNotNull(connection);
|
||||
connection = pollIdleConnection(connectionPool, 5, TimeUnit.SECONDS);
|
||||
assertNotNull(connection);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
|
@ -158,7 +159,7 @@ public class HttpDestinationOverHTTPTest extends AbstractHttpClientServerTest
|
|||
{
|
||||
start(scenario, new EmptyServerHandler());
|
||||
|
||||
try(HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", connector.getLocalPort())))
|
||||
try(HttpDestination destination = new DuplexHttpDestination(client, new Origin("http", "localhost", connector.getLocalPort())))
|
||||
{
|
||||
destination.start();
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
|
@ -185,9 +186,9 @@ public class HttpDestinationOverHTTPTest extends AbstractHttpClientServerTest
|
|||
{
|
||||
startServer(scenario, new EmptyServerHandler());
|
||||
long idleTimeout = 1000;
|
||||
startClient(scenario, null, httpClient -> httpClient.setIdleTimeout(idleTimeout));
|
||||
startClient(scenario, httpClient -> httpClient.setIdleTimeout(idleTimeout));
|
||||
|
||||
try (HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", connector.getLocalPort())))
|
||||
try(HttpDestination destination = new DuplexHttpDestination(client, new Origin("http", "localhost", connector.getLocalPort())))
|
||||
{
|
||||
destination.start();
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
|
|
|
@ -18,15 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.client.http;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
|
@ -35,15 +26,17 @@ import java.util.concurrent.TimeUnit;
|
|||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jetty.client.DuplexHttpDestination;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.HttpDestination;
|
||||
import org.eclipse.jetty.client.HttpExchange;
|
||||
import org.eclipse.jetty.client.HttpRequest;
|
||||
import org.eclipse.jetty.client.HttpResponseException;
|
||||
import org.eclipse.jetty.client.Origin;
|
||||
import org.eclipse.jetty.client.api.Response;
|
||||
import org.eclipse.jetty.client.util.FutureResponseListener;
|
||||
import org.eclipse.jetty.http.HttpCompliance;
|
||||
import org.eclipse.jetty.http.BadMessageException;
|
||||
import org.eclipse.jetty.http.HttpCompliance;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
|
@ -54,10 +47,19 @@ import org.junit.jupiter.params.ParameterizedTest;
|
|||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class HttpReceiverOverHTTPTest
|
||||
{
|
||||
private HttpClient client;
|
||||
private HttpDestinationOverHTTP destination;
|
||||
private HttpDestination destination;
|
||||
private ByteArrayEndPoint endPoint;
|
||||
private HttpConnectionOverHTTP connection;
|
||||
|
||||
|
@ -77,7 +79,7 @@ public class HttpReceiverOverHTTPTest
|
|||
client = new HttpClient();
|
||||
client.setHttpCompliance(compliance);
|
||||
client.start();
|
||||
destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", 8080));
|
||||
destination = new DuplexHttpDestination(client, new Origin("http", "localhost", 8080));
|
||||
destination.start();
|
||||
endPoint = new ByteArrayEndPoint();
|
||||
connection = new HttpConnectionOverHTTP(endPoint, destination, new Promise.Adapter<>());
|
||||
|
|
|
@ -18,9 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.client.http;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
@ -28,7 +25,9 @@ import java.util.Locale;
|
|||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.client.DuplexHttpDestination;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.HttpDestination;
|
||||
import org.eclipse.jetty.client.Origin;
|
||||
import org.eclipse.jetty.client.api.Connection;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
|
@ -39,11 +38,13 @@ import org.eclipse.jetty.io.ByteArrayEndPoint;
|
|||
import org.eclipse.jetty.util.Promise;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class HttpSenderOverHTTPTest
|
||||
{
|
||||
private HttpClient client;
|
||||
|
@ -65,7 +66,7 @@ public class HttpSenderOverHTTPTest
|
|||
public void test_Send_NoRequestContent() throws Exception
|
||||
{
|
||||
ByteArrayEndPoint endPoint = new ByteArrayEndPoint();
|
||||
HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", 8080));
|
||||
HttpDestination destination = new DuplexHttpDestination(client, new Origin("http", "localhost", 8080));
|
||||
destination.start();
|
||||
HttpConnectionOverHTTP connection = new HttpConnectionOverHTTP(endPoint, destination, new Promise.Adapter<Connection>());
|
||||
Request request = client.newRequest(URI.create("http://localhost/"));
|
||||
|
@ -99,7 +100,7 @@ public class HttpSenderOverHTTPTest
|
|||
public void test_Send_NoRequestContent_IncompleteFlush() throws Exception
|
||||
{
|
||||
ByteArrayEndPoint endPoint = new ByteArrayEndPoint("", 16);
|
||||
HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", 8080));
|
||||
HttpDestination destination = new DuplexHttpDestination(client, new Origin("http", "localhost", 8080));
|
||||
destination.start();
|
||||
HttpConnectionOverHTTP connection = new HttpConnectionOverHTTP(endPoint, destination, new Promise.Adapter<Connection>());
|
||||
Request request = client.newRequest(URI.create("http://localhost/"));
|
||||
|
@ -129,7 +130,7 @@ public class HttpSenderOverHTTPTest
|
|||
ByteArrayEndPoint endPoint = new ByteArrayEndPoint();
|
||||
// Shutdown output to trigger the exception on write
|
||||
endPoint.shutdownOutput();
|
||||
HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", 8080));
|
||||
HttpDestination destination = new DuplexHttpDestination(client, new Origin("http", "localhost", 8080));
|
||||
destination.start();
|
||||
HttpConnectionOverHTTP connection = new HttpConnectionOverHTTP(endPoint, destination, new Promise.Adapter<Connection>());
|
||||
Request request = client.newRequest(URI.create("http://localhost/"));
|
||||
|
@ -159,7 +160,7 @@ public class HttpSenderOverHTTPTest
|
|||
public void test_Send_NoRequestContent_IncompleteFlush_Exception() throws Exception
|
||||
{
|
||||
ByteArrayEndPoint endPoint = new ByteArrayEndPoint("", 16);
|
||||
HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", 8080));
|
||||
HttpDestination destination = new DuplexHttpDestination(client, new Origin("http", "localhost", 8080));
|
||||
destination.start();
|
||||
HttpConnectionOverHTTP connection = new HttpConnectionOverHTTP(endPoint, destination, new Promise.Adapter<Connection>());
|
||||
Request request = client.newRequest(URI.create("http://localhost/"));
|
||||
|
@ -195,7 +196,7 @@ public class HttpSenderOverHTTPTest
|
|||
public void test_Send_SmallRequestContent_InOneBuffer() throws Exception
|
||||
{
|
||||
ByteArrayEndPoint endPoint = new ByteArrayEndPoint();
|
||||
HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", 8080));
|
||||
HttpDestination destination = new DuplexHttpDestination(client, new Origin("http", "localhost", 8080));
|
||||
destination.start();
|
||||
HttpConnectionOverHTTP connection = new HttpConnectionOverHTTP(endPoint, destination, new Promise.Adapter<Connection>());
|
||||
Request request = client.newRequest(URI.create("http://localhost/"));
|
||||
|
@ -230,7 +231,7 @@ public class HttpSenderOverHTTPTest
|
|||
public void test_Send_SmallRequestContent_InTwoBuffers() throws Exception
|
||||
{
|
||||
ByteArrayEndPoint endPoint = new ByteArrayEndPoint();
|
||||
HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", 8080));
|
||||
HttpDestination destination = new DuplexHttpDestination(client, new Origin("http", "localhost", 8080));
|
||||
destination.start();
|
||||
HttpConnectionOverHTTP connection = new HttpConnectionOverHTTP(endPoint, destination, new Promise.Adapter<Connection>());
|
||||
Request request = client.newRequest(URI.create("http://localhost/"));
|
||||
|
@ -266,7 +267,7 @@ public class HttpSenderOverHTTPTest
|
|||
public void test_Send_SmallRequestContent_Chunked_InTwoChunks() throws Exception
|
||||
{
|
||||
ByteArrayEndPoint endPoint = new ByteArrayEndPoint();
|
||||
HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", 8080));
|
||||
HttpDestination destination = new DuplexHttpDestination(client, new Origin("http", "localhost", 8080));
|
||||
destination.start();
|
||||
HttpConnectionOverHTTP connection = new HttpConnectionOverHTTP(endPoint, destination, new Promise.Adapter<Connection>());
|
||||
Request request = client.newRequest(URI.create("http://localhost/"));
|
||||
|
|
|
@ -18,11 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.client.ssl;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -34,7 +29,9 @@ import javax.net.ssl.SSLSession;
|
|||
import org.eclipse.jetty.client.EmptyServerHandler;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.io.ClientConnector;
|
||||
import org.eclipse.jetty.io.ssl.SslHandshakeListener;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
|
@ -43,9 +40,13 @@ import org.eclipse.jetty.util.ssl.SslContextFactory;
|
|||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* In order to work, client authentication needs a certificate
|
||||
* signed by a CA that also signed the server certificate.
|
||||
|
@ -59,7 +60,7 @@ public class NeedWantClientAuthTest
|
|||
private ServerConnector connector;
|
||||
private HttpClient client;
|
||||
|
||||
private void startServer(SslContextFactory sslContextFactory, Handler handler) throws Exception
|
||||
private void startServer(SslContextFactory.Server sslContextFactory, Handler handler) throws Exception
|
||||
{
|
||||
QueuedThreadPool serverThreads = new QueuedThreadPool();
|
||||
serverThreads.setName("server");
|
||||
|
@ -72,19 +73,21 @@ public class NeedWantClientAuthTest
|
|||
server.start();
|
||||
}
|
||||
|
||||
private void startClient(SslContextFactory sslContextFactory) throws Exception
|
||||
private void startClient(SslContextFactory.Client sslContextFactory) throws Exception
|
||||
{
|
||||
ClientConnector clientConnector = new ClientConnector();
|
||||
clientConnector.setSelectors(1);
|
||||
QueuedThreadPool clientThreads = new QueuedThreadPool();
|
||||
clientThreads.setName("client");
|
||||
client = new HttpClient(sslContextFactory);
|
||||
client.setExecutor(clientThreads);
|
||||
clientConnector.setExecutor(clientThreads);
|
||||
clientConnector.setSslContextFactory(sslContextFactory);
|
||||
client = new HttpClient(new HttpClientTransportOverHTTP(clientConnector));
|
||||
client.start();
|
||||
}
|
||||
|
||||
private SslContextFactory createSslContextFactory()
|
||||
private SslContextFactory.Server createServerSslContextFactory()
|
||||
{
|
||||
SslContextFactory sslContextFactory = new SslContextFactory();
|
||||
sslContextFactory.setEndpointIdentificationAlgorithm("");
|
||||
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
|
||||
sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
|
||||
sslContextFactory.setKeyStorePassword("storepwd");
|
||||
return sslContextFactory;
|
||||
|
@ -102,11 +105,11 @@ public class NeedWantClientAuthTest
|
|||
@Test
|
||||
public void testWantClientAuthWithoutAuth() throws Exception
|
||||
{
|
||||
SslContextFactory serverSSL = createSslContextFactory();
|
||||
SslContextFactory.Server serverSSL = createServerSslContextFactory();
|
||||
serverSSL.setWantClientAuth(true);
|
||||
startServer(serverSSL, new EmptyServerHandler());
|
||||
|
||||
SslContextFactory clientSSL = new SslContextFactory(true);
|
||||
SslContextFactory.Client clientSSL = new SslContextFactory.Client(true);
|
||||
startClient(clientSSL);
|
||||
|
||||
ContentResponse response = client.newRequest("https://localhost:" + connector.getLocalPort())
|
||||
|
@ -119,7 +122,7 @@ public class NeedWantClientAuthTest
|
|||
@Test
|
||||
public void testWantClientAuthWithAuth() throws Exception
|
||||
{
|
||||
SslContextFactory serverSSL = createSslContextFactory();
|
||||
SslContextFactory.Server serverSSL = createServerSslContextFactory();
|
||||
serverSSL.setWantClientAuth(true);
|
||||
startServer(serverSSL, new EmptyServerHandler());
|
||||
CountDownLatch handshakeLatch = new CountDownLatch(1);
|
||||
|
@ -143,7 +146,7 @@ public class NeedWantClientAuthTest
|
|||
}
|
||||
});
|
||||
|
||||
SslContextFactory clientSSL = new SslContextFactory(true);
|
||||
SslContextFactory.Client clientSSL = new SslContextFactory.Client(true);
|
||||
clientSSL.setKeyStorePath("src/test/resources/client_keystore.jks");
|
||||
clientSSL.setKeyStorePassword("storepwd");
|
||||
startClient(clientSSL);
|
||||
|
@ -166,11 +169,11 @@ public class NeedWantClientAuthTest
|
|||
// The server still sends bad_certificate to the client, but the client handshake has already
|
||||
// completed successfully its TLS handshake.
|
||||
|
||||
SslContextFactory serverSSL = createSslContextFactory();
|
||||
SslContextFactory.Server serverSSL = createServerSslContextFactory();
|
||||
serverSSL.setNeedClientAuth(true);
|
||||
startServer(serverSSL, new EmptyServerHandler());
|
||||
|
||||
SslContextFactory clientSSL = new SslContextFactory(true);
|
||||
SslContextFactory.Client clientSSL = new SslContextFactory.Client(true);
|
||||
startClient(clientSSL);
|
||||
CountDownLatch handshakeLatch = new CountDownLatch(1);
|
||||
client.addBean(new SslHandshakeListener()
|
||||
|
@ -210,7 +213,7 @@ public class NeedWantClientAuthTest
|
|||
@Test
|
||||
public void testNeedClientAuthWithAuth() throws Exception
|
||||
{
|
||||
SslContextFactory serverSSL = createSslContextFactory();
|
||||
SslContextFactory.Server serverSSL = createServerSslContextFactory();
|
||||
serverSSL.setNeedClientAuth(true);
|
||||
startServer(serverSSL, new EmptyServerHandler());
|
||||
CountDownLatch handshakeLatch = new CountDownLatch(1);
|
||||
|
@ -234,7 +237,7 @@ public class NeedWantClientAuthTest
|
|||
}
|
||||
});
|
||||
|
||||
SslContextFactory clientSSL = new SslContextFactory(true);
|
||||
SslContextFactory.Client clientSSL = new SslContextFactory.Client(true);
|
||||
clientSSL.setKeyStorePath("src/test/resources/client_keystore.jks");
|
||||
clientSSL.setKeyStorePassword("storepwd");
|
||||
startClient(clientSSL);
|
||||
|
|
|
@ -38,9 +38,11 @@ import javax.net.ssl.SSLSocket;
|
|||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
|
||||
import org.eclipse.jetty.client.util.FutureResponseListener;
|
||||
import org.eclipse.jetty.http.HttpScheme;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.io.ClientConnector;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
|
@ -61,7 +63,7 @@ public class SslBytesClientTest extends SslBytesTest
|
|||
{
|
||||
private ExecutorService threadPool;
|
||||
private HttpClient client;
|
||||
private SslContextFactory sslContextFactory;
|
||||
private SslContextFactory.Client sslContextFactory;
|
||||
private SSLServerSocket acceptor;
|
||||
private SimpleProxy proxy;
|
||||
|
||||
|
@ -70,8 +72,11 @@ public class SslBytesClientTest extends SslBytesTest
|
|||
{
|
||||
threadPool = Executors.newCachedThreadPool();
|
||||
|
||||
sslContextFactory = new SslContextFactory(true);
|
||||
client = new HttpClient(sslContextFactory);
|
||||
ClientConnector clientConnector = new ClientConnector();
|
||||
clientConnector.setSelectors(1);
|
||||
sslContextFactory = new SslContextFactory.Client(true);
|
||||
clientConnector.setSslContextFactory(sslContextFactory);
|
||||
client = new HttpClient(new HttpClientTransportOverHTTP(clientConnector));
|
||||
client.setMaxConnectionsPerDestination(1);
|
||||
File keyStore = MavenTestingUtils.getTestResourceFile("keystore.jks");
|
||||
sslContextFactory.setKeyStorePath(keyStore.getAbsolutePath());
|
||||
|
@ -243,7 +248,7 @@ public class SslBytesClientTest extends SslBytesTest
|
|||
|
||||
// Trigger a read to have the server write the final renegotiation steps
|
||||
server.setSoTimeout(100);
|
||||
assertThrows(SocketTimeoutException.class, ()->serverInput.read());
|
||||
assertThrows(SocketTimeoutException.class, () -> serverInput.read());
|
||||
|
||||
// Renegotiation Handshake
|
||||
record = proxy.readFromServer();
|
||||
|
|
|
@ -100,7 +100,7 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
private final int idleTimeout = 2000;
|
||||
private ExecutorService threadPool;
|
||||
private Server server;
|
||||
private SslContextFactory sslContextFactory;
|
||||
private SslContextFactory.Server sslContextFactory;
|
||||
private int serverPort;
|
||||
private SSLContext sslContext;
|
||||
private SimpleProxy proxy;
|
||||
|
@ -119,7 +119,7 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
serverEndPoint.set(null);
|
||||
|
||||
File keyStore = MavenTestingUtils.getTestResourceFile("keystore.jks");
|
||||
sslContextFactory = new SslContextFactory();
|
||||
sslContextFactory = new SslContextFactory.Server();
|
||||
sslContextFactory.setKeyStorePath(keyStore.getAbsolutePath());
|
||||
sslContextFactory.setKeyStorePassword("storepwd");
|
||||
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.client.ssl;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
|
@ -36,16 +34,17 @@ import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
|||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
public class SslConnectionTest
|
||||
{
|
||||
@Test
|
||||
public void testSslConnectionClosedBeforeFill() throws Exception
|
||||
{
|
||||
File keyStore = MavenTestingUtils.getTestResourceFile("keystore.jks");
|
||||
SslContextFactory sslContextFactory = new SslContextFactory();
|
||||
SslContextFactory sslContextFactory = new SslContextFactory.Server();
|
||||
sslContextFactory.setKeyStorePath(keyStore.getAbsolutePath());
|
||||
sslContextFactory.setKeyStorePassword("storepwd");
|
||||
sslContextFactory.start();
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
<argLine>
|
||||
@{argLine} ${jetty.surefire.argLine}
|
||||
--add-modules org.eclipse.jetty.jmx
|
||||
--add-reads org.eclipse.jetty.deploy=org.eclipse.jetty.http
|
||||
--add-reads org.eclipse.jetty.deploy=org.eclipse.jetty.http,jetty.servlet.api
|
||||
</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
|
||||
<!-- =============================================================== -->
|
||||
<!-- Create the deployment manager -->
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue