Merge remote-tracking branch 'origin/jetty-9.4.x' into issue-207
This commit is contained in:
commit
04b6afe879
|
@ -37,8 +37,8 @@ node {
|
|||
{
|
||||
stage('Javadoc') {
|
||||
withEnv(mvnEnv) {
|
||||
timeout(time: 15, unit: 'MINUTES') {
|
||||
sh "mvn -B javadoc:javadoc"
|
||||
timeout(time: 20, unit: 'MINUTES') {
|
||||
sh "mvn --offline -B javadoc:javadoc"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
40
VERSION.txt
40
VERSION.txt
|
@ -1,4 +1,37 @@
|
|||
jetty-9.4.5-SNAPSHOT
|
||||
jetty-9.4.6-SNAPSHOT
|
||||
|
||||
jetty-9.4.5.v20170502 - 02 May 2017
|
||||
+ 304 Review dead code - StringUtil.sidBytesToString
|
||||
+ 1235 DNS lookup in newSSLEngine(InetSocketAddress address)
|
||||
+ 1348 Add a BOM artifact
|
||||
+ 1390 HashLoginService and "this.web-inf.url" property are incompatible
|
||||
+ 1404 Jetty 9.4.2 does not support constructors with varargs in XML config
|
||||
files
|
||||
+ 1448 StackOverflowError when using URLStreamHandlerFactory in
|
||||
WebAppClassloader
|
||||
+ 1475 SIOOBE in ContextHandler startup
|
||||
+ 1480 Expand URIUtil.canonicalPath() testing
|
||||
+ 1481 Add convenient method to add user to Realm
|
||||
+ 1486 redirect to welcome file broken for sub directory
|
||||
+ 1487 add decoded paths
|
||||
+ 1492 Unable to override logback.version
|
||||
+ 1493 Response.sendError should preserve cookies
|
||||
+ 1494 Module resolution ignores alternate providers where a .mod file of the
|
||||
same name exists
|
||||
+ 1500 HttpServletResponse.sendError() should commit and close
|
||||
+ 1502 WebSocket endpoints cannot be mapped when the session id is url encoded
|
||||
+ 1504 Improve defaults for HTTP/2 flow control
|
||||
+ 1505 jetty.base.uri and jetty.home.uri
|
||||
+ 1506 Make HttpChannels recycling configurable for HTTP/2
|
||||
+ 1507 Negative delay Timer.schedule exception due to mismatched local and
|
||||
_logTimeZone values
|
||||
+ 1508 Update to gcloud datastore 1.0.0
|
||||
+ 1510 Look for SessionHandlers instead of ContextHandlers in
|
||||
DefaultSessionIdManager
|
||||
+ 1513 RolloverFileOutputStream can't handle multiple instances
|
||||
+ 1517 Review JMX's ConnectorServer
|
||||
+ 1521 Prevent copy of jetty jars to lib/gcloud
|
||||
+ 1523 Update ALPN support for Java 8u131
|
||||
|
||||
jetty-9.4.4.v20170414 - 14 April 2017
|
||||
+ 612 Support HTTP Trailer
|
||||
|
@ -13,7 +46,8 @@ jetty-9.4.4.v20170414 - 14 April 2017
|
|||
+ 1423 Update to gcloud datastore 0.10.0-beta
|
||||
+ 1433 Wrong status message for code 417
|
||||
+ 1434 Improve properties in jetty-gzip.xml
|
||||
+ 1435 Apply setCharacterEncoding to static content without an assumed encoding
|
||||
+ 1435 Apply setCharacterEncoding to static content without an assumed
|
||||
encoding
|
||||
+ 1436 NullPointerException when calling changeSessionId
|
||||
+ 1439 Allow UNC paths to function as Resource bases
|
||||
+ 1440 Improve lock contention for low resources scheduling strategy
|
||||
|
@ -30,7 +64,7 @@ jetty-9.4.4.v20170414 - 14 April 2017
|
|||
3.0
|
||||
+ 1467 Change default for WebAppContext.isConfiguredDiscovered to false
|
||||
+ 1469 IllegalStateException in RolloverFileOutputStream
|
||||
+ 1472 Broken *.gz symlinks cause NPE in DefaultServlet.
|
||||
+ 1472 Broken *.gz symlinks cause NPE in DefaultServlet
|
||||
+ 1475 SIOOBE in ContextHandler startup
|
||||
|
||||
jetty-9.4.3.v20170317 - 17 March 2017
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -99,7 +99,7 @@
|
|||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<configuration>
|
||||
<additionalparam>-Xdoclint:none</additionalparam>
|
||||
<additionalparam>-Xdoclint:none --allow-script-in-comments</additionalparam>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>apache-jsp</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>apache-jstl</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>example-async-rest</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty.example-async-rest</groupId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>example-async-rest</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty.example-async-rest</groupId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.examples</groupId>
|
||||
<artifactId>examples-parent</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.examples</groupId>
|
||||
<artifactId>examples-parent</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<groupId>org.eclipse.jetty.examples</groupId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-alpn-parent</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-alpn-client</artifactId>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-alpn-parent</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-alpn-parent</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-alpn-parent</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-alpn-server</artifactId>
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
[name]
|
||||
protonego-boot
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.11.v20170118/alpn-boot-8.1.11.v20170118.jar|lib/alpn/alpn-boot-8.1.11.v20170118.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.11.v20170118.jar
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-alpn-parent</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-annotations</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-ant</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-bom</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.cdi</groupId>
|
||||
<artifactId>jetty-cdi-parent</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>cdi-core</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.cdi</groupId>
|
||||
<artifactId>jetty-cdi-parent</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>cdi-full-servlet</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.cdi</groupId>
|
||||
<artifactId>jetty-cdi-parent</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>cdi-servlet</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.cdi</groupId>
|
||||
<artifactId>jetty-cdi-parent</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>cdi-websocket</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty.cdi</groupId>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.cdi</groupId>
|
||||
<artifactId>jetty-cdi-parent</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>test-cdi-webapp</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-continuation</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-deploy</artifactId>
|
||||
|
|
|
@ -605,13 +605,20 @@ public class DeploymentManager extends ContainerLifeCycle
|
|||
xmlc.getIdMap().put("Server", getServer());
|
||||
Resource home = Resource.newResource(System.getProperty("jetty.home","."));
|
||||
xmlc.getProperties().put("jetty.home",home.toString());
|
||||
xmlc.getProperties().put("jetty.home.uri",home.getURI().toString());
|
||||
xmlc.getProperties().put("jetty.home.uri",normalizeURI(home.getURI().toString()));
|
||||
|
||||
Resource base = Resource.newResource(System.getProperty("jetty.base",home.toString()));
|
||||
xmlc.getProperties().put("jetty.base",base.toString());
|
||||
xmlc.getProperties().put("jetty.base.uri",base.getURI().toString());
|
||||
xmlc.getProperties().put("jetty.base.uri",normalizeURI(base.getURI().toString()));
|
||||
|
||||
xmlc.getProperties().put("jetty.webapp",webapp.toString());
|
||||
xmlc.getProperties().put("jetty.webapps",webapp.getFile().toPath().getParent().toString());
|
||||
}
|
||||
|
||||
private String normalizeURI(String uri)
|
||||
{
|
||||
if (uri.endsWith("/"))
|
||||
return uri.substring(0,uri.length()-1);
|
||||
return uri;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-distribution</artifactId>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>jetty-documentation</artifactId>
|
||||
<name>Jetty :: Documentation</name>
|
||||
|
|
|
@ -244,6 +244,7 @@ The ALPN implementation, relying on modifications of OpenJDK classes, updates ev
|
|||
|1.8.0u111 |8.1.9.v20160720
|
||||
|1.8.0u112 |8.1.10.v20161026
|
||||
|1.8.0u121 |8.1.11.v20170118
|
||||
|1.8.0u131 |8.1.11.v20170118
|
||||
|=============================
|
||||
|
||||
[[alpn-build]]
|
||||
|
|
|
@ -17,93 +17,93 @@
|
|||
[[using-jmx]]
|
||||
=== Using JMX with Jetty
|
||||
|
||||
Jetty JMX integration uses the platform MBean server implementation that Java VM provides.
|
||||
The integration is based on the `ObjectMBean` implementation of `DynamicMBean`.
|
||||
This implementation allows you to wrap an arbitrary POJO in an MBean and annotate it appropriately to expose it via JMX.
|
||||
See xref:jetty-jmx-annotations[].
|
||||
Jetty's architecture is based on POJO components (see xref:basic-architecture[]).
|
||||
These components are organized in a tree and each component may have a lifecycle
|
||||
that spans the `Server` lifetime, or a web application lifetime, or even shorter
|
||||
lifetimes such as that of a TCP connection.
|
||||
|
||||
The `MBeanContainer` implementation of the `Container.Listener` interface coordinates creation of MBeans.
|
||||
The Jetty Server and it's components use a link:{JDURL}/org/eclipse/jetty/util/component/Container.html[Container] to maintain a containment tree of components and to support notification of changes to that tree.
|
||||
The `MBeanContainer` class listens for Container events and creates and destroys MBeans as required to wrap all Jetty components.
|
||||
Every time a component is added or removed from the component tree, an event is
|
||||
emitted, and link:{JDURL}/org/eclipse/jetty/util/component/Container.html[`Container.Listener`]
|
||||
implementations can listen to those events and perform additional actions.
|
||||
|
||||
You can access the MBeans that Jetty publishes both through built-in Java VM connector via JConsole or JMC, or by registering a remote JMX connector and using a remote JMX agent to monitor Jetty.
|
||||
One such `Container.Listener` is `MBeanContainer` that uses `ObjectMBean` to
|
||||
create an MBean from an arbitrary POJO, and register/unregister the MBean to/from
|
||||
the platform `MBeanServer`.
|
||||
|
||||
Jetty components are annotated with <<jetty-jmx-annotations,JMX annotations>>
|
||||
and provide specific JMX details so that `ObjectMBean` can build a more
|
||||
precise representation of the JMX metadata associated with the component POJO.
|
||||
|
||||
Therefore, when a component is added to the component tree, `MBeanContainer` is
|
||||
notified, it creates the MBean from the component POJO and registers it to
|
||||
the `MBeanServer`.
|
||||
Similarly, when a component is removed from the tree, `MBeanContainer` is
|
||||
notified, and unregisters the MBean from the `MBeanServer`.
|
||||
|
||||
The Jetty MBeans can be accessed via any JMX console such as Java Mission Control
|
||||
(JMC), VisualVM, JConsole or others.
|
||||
|
||||
[[configuring-jmx]]
|
||||
==== Configuring JMX
|
||||
|
||||
This guide describes how to initialize and configure the Jetty JMX integration.
|
||||
This guide describes the various ways to initialize and configure the Jetty JMX integration.
|
||||
Configuring the Jetty JMX integration only registers the Jetty MBeans into the platform
|
||||
`MBeanServer`, and therefore the MBeans can only be accessed locally (from the same machine),
|
||||
not from remote machines.
|
||||
|
||||
To monitor an application using JMX, perform the following steps:
|
||||
|
||||
* Configure the application to instantiate an MBean container.
|
||||
* Instrument objects to be MBeans.
|
||||
* Provide access for JMX agents to MBeans.
|
||||
|
||||
[[accessing-jetty-mbeans]]
|
||||
===== Using JConsole to Access Jetty MBeans
|
||||
|
||||
The simplest way to access the MBeans that Jetty publishes is to use the http://java.sun.com/developer/technicalArticles/J2SE/jconsole.html[JConsole utility] the Java Virtual Machine supplies.
|
||||
See xref:jetty-jconsole[] for instructions on how to configure JVM for use with JConsole or JMC.
|
||||
|
||||
To access Jetty MBeans via JConsole or JMC, you must:
|
||||
|
||||
* Enable the registration of Jetty MBeans into the platform MBeanServer.
|
||||
* Enable a `JMXConnectorServer` so that JConsole/JMC can connect and visualize the MBeans.
|
||||
|
||||
[[registering-jetty-mbeans]]
|
||||
===== Registering Jetty MBeans
|
||||
|
||||
Configuring Jetty JMX integration differs for standalone and embedded Jetty.
|
||||
This means that this configuration is enough for development, where you have easy access
|
||||
(with graphical user interface) to the machine where Jetty runs, but it is typically not
|
||||
enough when the machine Jetty where runs is remote, or only accessible via SSH or otherwise
|
||||
without graphical user interface support.
|
||||
In these cases, you have to enable <<jmx-remote-access,JMX remote access>>.
|
||||
|
||||
[[jmx-standalone-jetty]]
|
||||
====== Standalone Jetty
|
||||
===== Standalone Jetty Server
|
||||
|
||||
JMX is not enabled by default in the Jetty distribution.
|
||||
To enable JMX in the Jetty distribution, run the following, where `{$jetty.home}` is the directory where you have the Jetty distribution located (see link:#startup-base-and-home[the documentation for Jetty base vs. home examples]):
|
||||
To enable JMX in the Jetty distribution run the following, where `{$jetty.home}`
|
||||
is the directory where you have the Jetty distribution installed, and
|
||||
`${jetty.base}` is the directory where you have your Jetty configuration
|
||||
(see link:#startup-base-and-home[the documentation for Jetty base vs. home examples]):
|
||||
|
||||
[source, screen, subs="{sub-order}"]
|
||||
....
|
||||
----
|
||||
$ cd ${jetty.base}
|
||||
$ java -jar {$jetty.home}/start.jar --add-to-start=jmx
|
||||
....
|
||||
----
|
||||
|
||||
Running the above command will append the available configurable elements of the JMX module to the `{$jetty.base}/start.ini` file.
|
||||
If you are managing separate ini files for your modules in the distribution, use `--add-to-start.d=jmx` instead.
|
||||
|
||||
If you wish to add remote access for JMX, you will also need to enable the JMX-Remote module:
|
||||
|
||||
[source, screen, subs="{sub-order}"]
|
||||
....
|
||||
$ java -jar {$jetty.home}/start.jar --add-to-start=jmx-remote
|
||||
....
|
||||
Running the above command will append the available configurable elements of the `jmx` module
|
||||
to the `{$jetty.base}/start.ini` file, or create the `${jetty.base}/start.d/jmx.ini` file.
|
||||
|
||||
[[jmx-embedded-jetty]]
|
||||
====== Embedded Jetty
|
||||
===== Embedded Jetty Server
|
||||
|
||||
When running Jetty embedded into an application, create and configure an MBeanContainer instance as follows:
|
||||
When running Jetty embedded into an application, create and configure an `MBeanContainer`
|
||||
instance as follows:
|
||||
|
||||
[source, java]
|
||||
----
|
||||
|
||||
Server server = new Server();
|
||||
|
||||
// Setup JMX
|
||||
MBeanContainer mbContainer=new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
|
||||
server.addEventListener(mbContainer);
|
||||
server.addBean(mbContainer);
|
||||
// Setup JMX.
|
||||
MBeanContainer mbeanContainer = new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
|
||||
server.addBean(mbeanContainer);
|
||||
|
||||
// Add loggers MBean to server (will be picked up by MBeanContainer above)
|
||||
// Export the loggers as MBeans.
|
||||
server.addBean(Log.getLog());
|
||||
|
||||
----
|
||||
|
||||
Notice that Jetty creates the `MBeanContainer` immediately after creating the Server, and immediately after registering it as an `EventListener` of the Server object (which is also a Container object).
|
||||
Because logging is initialized prior to the `MBeanContainer` (even before the `Server` itself),
|
||||
it is necessary to register the logger manually via `server.addBean()` so that the loggers may
|
||||
show up in the JMX tree as MBeans.
|
||||
|
||||
Because logging is initialized prior to the `MBeanContainer` (even before the Server itself), it is necessary to register the logger manually via `server.addBean()` so that the loggers may show up in the JMX tree.
|
||||
|
||||
[[jmx-using-jetty-maven-plugin]]
|
||||
[[jmx-jetty-maven-plugin]]
|
||||
===== Using the Jetty Maven Plugin with JMX
|
||||
|
||||
If you are using the link:#jetty-maven-plugin[Jetty Maven plugin] you should copy the `/etc/jetty-jmx.xml` file into your webapp project somewhere, such as `/src/etc,` then add a `<jettyconfig>` element to the plugin `<configuration>`:
|
||||
If you are using the link:#jetty-maven-plugin[Jetty Maven plugin] you should copy the
|
||||
`${jetty.home}/etc/jetty-jmx.xml` file into your webapp project somewhere, such as
|
||||
`src/main/config/etc/`, then add a
|
||||
`<jettyXml>` element to the `<configuration>` element of the Jetty Maven Plugin:
|
||||
|
||||
[source, xml, subs="{sub-order}"]
|
||||
----
|
||||
|
@ -113,21 +113,159 @@ If you are using the link:#jetty-maven-plugin[Jetty Maven plugin] you should cop
|
|||
<version>{VERSION}</version>
|
||||
<configuration>
|
||||
<scanintervalseconds>10</scanintervalseconds>
|
||||
<jettyXml>src/etc/jetty-jmx.xml</jettyXml>
|
||||
<jettyXml>src/main/config/etc/jetty-jmx.xml</jettyXml>
|
||||
</configuration>
|
||||
</plugin>
|
||||
----
|
||||
|
||||
[[accessing-jetty-mbeans]]
|
||||
==== Using JConsole or Java Mission Control to Access Jetty MBeans
|
||||
|
||||
[[enabling-jmxconnectorserver-for-remote-access]]
|
||||
==== Enabling JMXConnectorServer for Remote Access
|
||||
The simplest way to access the MBeans that Jetty publishes is to use
|
||||
<<jetty-jconsole,Java Mission Control (JMC) or JConsole>>.
|
||||
|
||||
There are two ways of enabling remote connectivity so that JConsole or JMC can connect to visualize MBeans.
|
||||
Both these tools can connect to local or remote JVMs to display the MBeans.
|
||||
|
||||
For local access, you just need to start JConsole or JMC and then choose
|
||||
from their user interface the local JVM you want to connect to.
|
||||
|
||||
For remote access, you need first to enable <<jmx-remote-access,JMX remote access>>
|
||||
in Jetty.
|
||||
|
||||
[[jmx-remote-access]]
|
||||
==== Enabling JMX Remote Access
|
||||
|
||||
There are two ways of enabling remote connectivity so that JConsole or JMC can connect
|
||||
to the remote JVM to visualize MBeans.
|
||||
|
||||
* Use the `com.sun.management.jmxremote` system property on the command line.
|
||||
Unfortunately, this solution does not work well with firewalls and is not flexible.
|
||||
* Use Jetty's `ConnectorServer` class.
|
||||
To enable use of this class, uncomment the correspondent portion in `/etc/jetty-jmx.xml,` like this:
|
||||
* Use Jetty's `jmx-remote` module or - equivalently - the `ConnectorServer` class.
|
||||
|
||||
`ConnectorServer` will use by default RMI to allow connection from remote clients,
|
||||
and it is a wrapper around the standard JDK class `JMXConnectorServer`, which is
|
||||
the class that provides remote access to JMX clients.
|
||||
|
||||
Connecting to the remote JVM is a two step process:
|
||||
|
||||
* First, the client will connect to the RMI _registry_ to download the RMI stub for
|
||||
the `JMXConnectorServer`; this RMI stub contains the IP address and port to connect
|
||||
to the RMI server, i.e. the remote `JMXConnectorServer`.
|
||||
* Second, the client uses the RMI stub to connect to the RMI _server_ (i.e. the
|
||||
remote `JMXConnectorServer`) typically on an address and port that may be different
|
||||
from the RMI registry address and port.
|
||||
|
||||
The configuration for the RMI registry and the RMI server is specified by a `JMXServiceURL`.
|
||||
The string format of an RMI `JMXServiceURL` is:
|
||||
|
||||
[source, screen, subs="{sub-order}"]
|
||||
----
|
||||
service:jmx:rmi://<rmi_server_host>:<rmi_server_port>/jndi/rmi://<rmi_registry_host>:<rmi_registry_port>/jmxrmi
|
||||
----
|
||||
|
||||
Default values are:
|
||||
|
||||
[source, screen, subs="{sub-order}"]
|
||||
----
|
||||
rmi_server_host = localhost
|
||||
rmi_server_port = 1099
|
||||
rmi_registry_host = localhost
|
||||
rmi_registry_port = 1099
|
||||
----
|
||||
|
||||
With the default configuration, only clients that are local to the server machine can connect
|
||||
to the RMI registry and RMI server - this is done for security reasons.
|
||||
With this configuration it would still be possible to access the MBeans from remote using
|
||||
a <<jmx-remote-access-ssh-tunnel,SSH tunnel>>.
|
||||
|
||||
By specifying an appropriate `JMXServiceURL`, you can fine tune the network interfaces the
|
||||
RMI registry and the RMI server bind to, and the ports that the RMI registry and the RMI server
|
||||
listen to.
|
||||
The RMI server and RMI registry hosts and ports can be the same (as in the default configuration)
|
||||
because RMI is able to multiplex traffic arriving to a port to multiple RMI objects.
|
||||
|
||||
If you need to allow JMX remote access through a firewall, you must open both the RMI registry
|
||||
and the RMI server ports.
|
||||
|
||||
Examples:
|
||||
|
||||
[source, screen, subs="{sub-order}"]
|
||||
----
|
||||
service:jmx:rmi:///jndi/rmi:///jmxrmi
|
||||
rmi_server_host = local host address
|
||||
rmi_server_port = randomly chosen
|
||||
rmi_registry_host = local host address
|
||||
rmi_registry_port = 1099
|
||||
|
||||
service:jmx:rmi://0.0.0.0:1099/jndi/rmi://0.0.0.0:1099/jmxrmi
|
||||
rmi_server_host = any address
|
||||
rmi_server_port = 1099
|
||||
rmi_registry_host = any address
|
||||
rmi_registry_port = 1099
|
||||
|
||||
service:jmx:rmi://localhost:1100/jndi/rmi://localhost:1099/jmxrmi
|
||||
rmi_server_host = loopback address
|
||||
rmi_server_port = 1100
|
||||
rmi_registry_host = loopback address
|
||||
rmi_registry_port = 1099
|
||||
----
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
When `ConnectorServer` is started, its RMI stub is exported to the RMI registry.
|
||||
The RMI stub contains the IP address and port to connect to the RMI object, but
|
||||
the IP address is typically the machine host name, not the host specified in the
|
||||
`JMXServiceURL`.
|
||||
|
||||
To control the IP address stored in the RMI stub you need to set the system
|
||||
property `java.rmi.server.hostname` with the desired value.
|
||||
This is especially important when binding the RMI server host to the loopback
|
||||
address for security reasons. See also
|
||||
<<jmx-remote-access-ssh-tunnel,JMX Remote Access via SSH Tunnel>>.
|
||||
====
|
||||
|
||||
===== Enabling JMX Remote Access in Standalone Jetty Server
|
||||
|
||||
Similarly to <<jmx-standalone-jetty,enabling JMX in a standalone Jetty server>>, you
|
||||
enable the `jmx-remote` module:
|
||||
|
||||
[source, screen, subs="{sub-order}"]
|
||||
----
|
||||
$ cd ${jetty.base}
|
||||
$ java -jar {$jetty.home}/start.jar --add-to-start=jmx-remote
|
||||
----
|
||||
|
||||
===== Enabling JMX Remote Access in Embedded Jetty
|
||||
|
||||
When running Jetty embedded into an application, create and configure a `ConnectorServer`:
|
||||
|
||||
[source, java, subs="{sub-order}"]
|
||||
----
|
||||
Server server = new Server();
|
||||
|
||||
// Setup JMX
|
||||
MBeanContainer mbeanContainer = new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
|
||||
server.addBean(mbeanContainer);
|
||||
|
||||
// Setup ConnectorServer
|
||||
JMXServiceURL jmxURL = new JMXServiceURL("rmi", null, 1999, "/jndi/rmi:///jmxrmi");
|
||||
ConnectorServer jmxServer = new ConnectorServer(jmxURL, "org.eclipse.jetty.jmx:name=rmiconnectorserver");
|
||||
server.addBean(jmxServer);
|
||||
----
|
||||
|
||||
The `JMXServiceURL` above specifies that the RMI server binds to the wildcard address
|
||||
on port 1999, while the RMI registry binds to the wildcard address on port 1099 (the
|
||||
default RMI registry port).
|
||||
|
||||
[[jmx-remote-access-authorization]]
|
||||
===== JMX Remote Access Authorization
|
||||
|
||||
The standard `JMXConnectorServer` provides several options to authorize access.
|
||||
For a complete guide to controlling authentication and authorization in JMX, see
|
||||
https://blogs.oracle.com/lmalventosa/entry/jmx_authentication_authorization[Authentication and Authorization in JMX RMI connectors].
|
||||
|
||||
To authorize access to the `JMXConnectorServer` you can use this configuration,
|
||||
where the `jmx.password` and `jmx.access` files have the format specified in the blog entry above:
|
||||
|
||||
[source, xml, subs="{sub-order}"]
|
||||
----
|
||||
|
@ -136,50 +274,22 @@ To enable use of this class, uncomment the correspondent portion in `/etc/jetty-
|
|||
<New class="javax.management.remote.JMXServiceURL">
|
||||
<Arg type="java.lang.String">rmi</Arg>
|
||||
<Arg type="java.lang.String" />
|
||||
<Arg type="java.lang.Integer"><SystemProperty name="jetty.jmxrmiport" default="1099"/></Arg>
|
||||
<Arg type="java.lang.String">/jndi/rmi://<SystemProperty name="jetty.jmxrmihost" default="localhost"/>:<SystemProperty name="jetty.jmxrmiport" default="1099"/>/jmxrmi</Arg>
|
||||
</New>
|
||||
</Arg>
|
||||
<Arg>org.eclipse.jetty.jmx:name=rmiconnectorserver</Arg>
|
||||
<Call name="start" />
|
||||
</New>
|
||||
|
||||
----
|
||||
|
||||
This configuration snippet starts an `RMIRegistry` and a `JMXConnectorServer` both on port 1099 (by default), so that firewalls should open just that one port to allow connections from JConsole or JMC.
|
||||
|
||||
[[securing-remote-access]]
|
||||
==== Securing Remote Access
|
||||
|
||||
`JMXConnectorServer` several options to restrict access.
|
||||
For a complete guide to controlling authentication and authorization in JMX, see https://blogs.oracle.com/lmalventosa/entry/jmx_authentication_authorization[Authentication and Authorization in JMX RMI connectors] in Luis-Miguel Alventosa's blog.
|
||||
|
||||
To restrict access to the `JMXConnectorServer`, you can use this configuration, where the `jmx.password` and `jmx.access` files have the format specified in the blog entry above:
|
||||
|
||||
[source, xml, subs="{sub-order}"]
|
||||
----
|
||||
|
||||
<New id="ConnectorServer" class="org.eclipse.jetty.jmx.ConnectorServer">
|
||||
<Arg>
|
||||
<New class="javax.management.remote.JMXServiceURL">
|
||||
<Arg type="java.lang.String">rmi</Arg>
|
||||
<Arg type="java.lang.String" />
|
||||
<Arg type="java.lang.Integer"><SystemProperty name="jetty.jmxrmiport" default="1099"/></Arg>
|
||||
<Arg type="java.lang.String">/jndi/rmi://<SystemProperty name="jetty.jmxrmihost" default="localhost"/>:<SystemProperty name="jetty.jmxrmiport" default="1099"/>/jmxrmi</Arg>
|
||||
<Arg type="java.lang.Integer">1099</Arg>
|
||||
<Arg type="java.lang.String">/jndi/rmi:///jmxrmi</Arg>
|
||||
</New>
|
||||
</Arg>
|
||||
<Arg>
|
||||
<Map>
|
||||
<Entry>
|
||||
<Item>jmx.remote.x.password.file</Item>
|
||||
<Item>jmx.remote.x.access.file</Item>
|
||||
<Item>
|
||||
<New class="java.lang.String"><Arg><Property name="jetty.home" default="." />/resources/jmx.password</Arg></New>
|
||||
<New class="java.lang.String"><Arg><Property name="jetty.base" default="." />/resources/jmx.access</Arg></New>
|
||||
</Item>
|
||||
</Entry>
|
||||
<Entry>
|
||||
<Item>jmx.remote.x.access.file</Item>
|
||||
<Item>jmx.remote.x.password.file</Item>
|
||||
<Item>
|
||||
<New class="java.lang.String"><Arg><Property name="jetty.home" default="." />/resources/jmx.access</Arg></New>
|
||||
<New class="java.lang.String"><Arg><Property name="jetty.base" default="." />/resources/jmx.password</Arg></New>
|
||||
</Item>
|
||||
</Entry>
|
||||
</Map>
|
||||
|
@ -187,17 +297,141 @@ To restrict access to the `JMXConnectorServer`, you can use this configuration,
|
|||
<Arg>org.eclipse.jetty.jmx:name=rmiconnectorserver</Arg>
|
||||
<Call name="start" />
|
||||
</New>
|
||||
|
||||
|
||||
----
|
||||
|
||||
[[custom-monitor-applcation]]
|
||||
==== Custom Monitor Application
|
||||
Similarly, in code:
|
||||
|
||||
Using the JMX API, you can also write a custom application to monitor your Jetty server.
|
||||
To allow this application to connect to your Jetty server, you need to uncomment the last section of the `/etc/jetty-jmx.xml` configuration file and optionally modify the endpoint name.
|
||||
Doing so creates a JMX HTTP connector and registers a JMX URL that outputs to the `Stderr` log.
|
||||
[source, java, subs="{sub-order}"]
|
||||
----
|
||||
JMXServiceURL jmxURL = new JMXServiceURL("rmi", null, 1099, "/jndi/rmi:///jmxrmi");
|
||||
Map<String, Object> env = new HashMap<>();
|
||||
env.put("jmx.remote.x.access.file", "resources/jmx.access");
|
||||
env.put("jmx.remote.x.password.file", "resources/jmx.password");
|
||||
ConnectorServer jmxServer = new ConnectorServer(jmxURL, env, "org.eclipse.jetty.jmx:name=rmiconnectorserver");
|
||||
jmxServer.start();
|
||||
----
|
||||
|
||||
You should provide the URL that appears in the log to your monitor application in order to create an `MBeanServerConnection.`
|
||||
You can use the same URL to connect to your Jetty instance from a remote machine using JConsole or JMC.
|
||||
See the link:{GITBROWSEURL}/jetty-jmx/src/main/config/etc/jetty-jmx.xml[configuration file] for more details.
|
||||
Calling `ConnectorServer.start()` may be explicit as in the examples above,
|
||||
or can be skipped when adding the `ConnectorServer` as a bean to the `Server`,
|
||||
so that starting the `Server` will also start the `ConnectorServer`.
|
||||
|
||||
===== Securing JMX Remote Access with TLS
|
||||
|
||||
The JMX communication via RMI happens by default in clear-text.
|
||||
|
||||
It is possible to configure the `ConnectorServer` with a `SslContextFactory` so
|
||||
that the JMX communication via RMI is encrypted:
|
||||
|
||||
[source, xml, subs="{sub-order}"]
|
||||
----
|
||||
<New id="ConnectorServer" class="org.eclipse.jetty.jmx.ConnectorServer">
|
||||
<Arg>
|
||||
<New class="javax.management.remote.JMXServiceURL">
|
||||
<Arg type="java.lang.String">rmi</Arg>
|
||||
<Arg type="java.lang.String" />
|
||||
<Arg type="java.lang.Integer">1099</Arg>
|
||||
<Arg type="java.lang.String">/jndi/rmi:///jmxrmi</Arg>
|
||||
</New>
|
||||
</Arg>
|
||||
<Arg />
|
||||
<Arg>org.eclipse.jetty.jmx:name=rmiconnectorserver</Arg>
|
||||
<Arg><Ref refid="sslContextFactory" /></Arg>
|
||||
</New>
|
||||
----
|
||||
|
||||
Similarly, in code:
|
||||
|
||||
[source, java, subs="{sub-order}"]
|
||||
----
|
||||
SslContextFactory sslContextFactory = new SslContextFactory();
|
||||
sslContextFactory.setKeyStorePath();
|
||||
sslContextFactory.setKeyStorePassword("secret");
|
||||
|
||||
JMXServiceURL jmxURL = new JMXServiceURL("rmi", null, 1099, "/jndi/rmi:///jmxrmi");
|
||||
ConnectorServer jmxServer = new ConnectorServer(jmxURL, null, "org.eclipse.jetty.jmx:name=rmiconnectorserver", sslContextFactory);
|
||||
----
|
||||
|
||||
It is possible to use the same `SslContextFactory` used to configure the
|
||||
Jetty `ServerConnector` that supports TLS for the HTTP protocol.
|
||||
This is used in the XML example above: the `SslContextFactory` configured
|
||||
for the TLS `ServerConnector` is registered with an id of `sslContextFactory`
|
||||
which is referenced in the XML via the `Ref` element.
|
||||
|
||||
The keystore must contain a valid certificate signed by a Certification Authority.
|
||||
|
||||
The RMI mechanic is the usual one: the RMI client (typically a monitoring console)
|
||||
will connect first to the RMI registry (using TLS), download the RMI server stub
|
||||
that contains the address and port of the RMI server to connect to, then connect
|
||||
to the RMI server (using TLS).
|
||||
|
||||
This also mean that if the RMI registry and the RMI server are on different hosts,
|
||||
the RMI client must have available the cryptographic material to validate both
|
||||
hosts.
|
||||
|
||||
Having certificates signed by a Certification Authority simplifies by a lot the
|
||||
configuration needed to get the JMX communication over TLS working properly.
|
||||
|
||||
If that is not the case (for example the certificate is self-signed), then you
|
||||
need to specify the required system properties that allow RMI (especially when
|
||||
acting as an RMI client) to retrieve the cryptographic material necessary to
|
||||
establish the TLS connection.
|
||||
|
||||
For example, trying to connect using the JDK standard `JMXConnector` with both
|
||||
the RMI server and the RMI registry to `domain.com`:
|
||||
|
||||
[source, java, subs="{sub-order}"]
|
||||
----
|
||||
// System properties necessary for an RMI client to trust a self-signed certificate.
|
||||
System.setProperty("javax.net.ssl.trustStore", "/path/to/trustStore");
|
||||
System.setProperty("javax.net.ssl.trustStorePassword", "secret");
|
||||
|
||||
JMXServiceURL jmxURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://domain.com:1100/jmxrmi")
|
||||
Map<String, Object> clientEnv = new HashMap<>();
|
||||
// Required to connect to the RMI registry via TLS.
|
||||
clientEnv.put(ConnectorServer.RMI_REGISTRY_CLIENT_SOCKET_FACTORY_ATTRIBUTE, new SslRMIClientSocketFactory());
|
||||
try (JMXConnector client = JMXConnectorFactory.connect(jmxURL, clientEnv))
|
||||
{
|
||||
Set<ObjectName> names = client.getMBeanServerConnection().queryNames(null, null);
|
||||
}
|
||||
----
|
||||
|
||||
Similarly, to launch JMC:
|
||||
|
||||
[source, java, subs="{sub-order}"]
|
||||
----
|
||||
$ jmc -vmargs -Djavax.net.ssl.trustStore=/path/to/trustStore -Djavax.net.ssl.trustStorePassword=secret
|
||||
----
|
||||
|
||||
Note that these system properties are required when launching the `ConnectorServer` too,
|
||||
on the server, because it acts as an RMI client with respect to the RMI registry.
|
||||
|
||||
[[jmx-remote-access-ssh-tunnel]]
|
||||
===== JMX Remote Access with Port Forwarding via SSH Tunnel
|
||||
|
||||
You can access JMX MBeans on a remote machine when the RMI ports are not open,
|
||||
for example because of firewall policies, but you have SSH access to the machine
|
||||
using local port forwarding via a SSH tunnel.
|
||||
|
||||
In this case you want to configure the `ConnectorServer` with a `JMXServiceURL`
|
||||
that binds the RMI server and the RMI registry to the loopback interface only:
|
||||
`service:jmx:rmi://localhost:1099/jndi/rmi://localhost:1099/jmxrmi`.
|
||||
|
||||
Then you setup the local port forwarding with the SSH tunnel:
|
||||
|
||||
[source, screen, subs="{sub-order}"]
|
||||
----
|
||||
$ ssh -L 1099:localhost:1099 <user>@<machine_host>
|
||||
----
|
||||
|
||||
Now you can use JConsole or JMC to connect to `localhost:1099` on your local
|
||||
computer. The traffic will be forwarded to `machine_host` and when there,
|
||||
SSH will forward the traffic to `localhost:1099`, which is exactly where
|
||||
the `ConnectorServer` listens.
|
||||
|
||||
When you configure `ConnectorServer` in this way, you must set the system
|
||||
property `-Djava.rmi.server.hostname=localhost`, on the server.
|
||||
|
||||
This is required because when the RMI server is exported, its address and
|
||||
port are stored in the RMI stub. You want the address in the RMI stub to be
|
||||
`localhost` so that when the RMI stub is downloaded to the remote client,
|
||||
the RMI communication will go through the SSH tunnel.
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.fcgi</groupId>
|
||||
<artifactId>fcgi-parent</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.fcgi</groupId>
|
||||
<artifactId>fcgi-parent</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.gcloud</groupId>
|
||||
<artifactId>gcloud-parent</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -95,6 +95,7 @@
|
|||
<appendOutput>false</appendOutput>
|
||||
<outputFile>${project.build.directory}/deps.txt</outputFile>
|
||||
<sort>true</sort>
|
||||
<excludeGroupIds>org.eclipse.jetty</excludeGroupIds>
|
||||
<prependGroupId>true</prependGroupId>
|
||||
<includeScope>runtime</includeScope>
|
||||
</configuration>
|
||||
|
|
|
@ -13,6 +13,6 @@ GCloudDatastore is an open source project hosted on Github and released under th
|
|||
https://github.com/GoogleCloudPlatform/gcloud-java
|
||||
http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
[ini-template]
|
||||
[ini]
|
||||
## Hide the gcloud libraries from deployed webapps
|
||||
jetty.webapp.addServerClasses+=,${jetty.base.uri}/lib/gcloud/
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-home</artifactId>
|
||||
|
|
|
@ -41,5 +41,5 @@ http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
||||
[ini-template]
|
||||
## Jminix Configuration
|
||||
jminix.port=8088
|
||||
# jminix.port=8088
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-http-spi</artifactId>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-http</artifactId>
|
||||
|
|
|
@ -117,7 +117,7 @@ public class ResourceHttpContent implements HttpContent
|
|||
{
|
||||
return _contentType==null?null:MimeTypes.CACHE.get(MimeTypes.getContentTypeWithoutCharset(_contentType));
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public HttpField getLastModified()
|
||||
|
@ -227,7 +227,7 @@ public class ResourceHttpContent implements HttpContent
|
|||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s@%x{r=%s,c=%b}",this.getClass().getSimpleName(),hashCode(),_resource,_precompressedContents!=null);
|
||||
return String.format("%s@%x{r=%s,ct=%s,c=%b}",this.getClass().getSimpleName(),hashCode(),_resource,_contentType,_precompressedContents!=null);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.http2</groupId>
|
||||
<artifactId>http2-parent</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.http2</groupId>
|
||||
<artifactId>http2-parent</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.http2</groupId>
|
||||
<artifactId>http2-parent</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.http2</groupId>
|
||||
<artifactId>http2-parent</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.http2</groupId>
|
||||
<artifactId>http2-parent</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.http2</groupId>
|
||||
<artifactId>http2-parent</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-infinispan</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-io</artifactId>
|
||||
|
|
|
@ -388,9 +388,13 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable
|
|||
SelectableChannel channel = null;
|
||||
try
|
||||
{
|
||||
channel = _selectorManager.doAccept(server);
|
||||
if (channel!=null)
|
||||
while(true)
|
||||
{
|
||||
channel = _selectorManager.doAccept(server);
|
||||
if (channel==null)
|
||||
break;
|
||||
_selectorManager.accepted(channel);
|
||||
}
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
|
@ -534,7 +538,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable
|
|||
{
|
||||
try
|
||||
{
|
||||
SelectionKey key = _channel.register(_selector, SelectionKey.OP_ACCEPT, null);
|
||||
SelectionKey key = _channel.register(_selector, SelectionKey.OP_ACCEPT, "Acceptor");
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} acceptor={}", this, key);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-jaas</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-jaspi</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-jmx</artifactId>
|
||||
|
|
|
@ -13,14 +13,14 @@
|
|||
</Call>
|
||||
-->
|
||||
|
||||
<!-- Add a remote JMX connector. The parameters of the constructor
|
||||
below specify the JMX service URL, and the object name string for the
|
||||
connector server bean. The parameters of the JMXServiceURL constructor
|
||||
<!-- Adds a remote JMXConnectorServer. The parameters of the constructor
|
||||
below specify the JMXServiceURL, and the ObjectName string for the
|
||||
JMXConnectorServer. The parameters of the JMXServiceURL constructor
|
||||
specify the protocol that clients will use to connect to the remote JMX
|
||||
connector (RMI), the hostname of the server (local hostname), port number
|
||||
(automatically assigned), and the URL path. Note that URL path contains
|
||||
the RMI registry hostname and port number, that may need to be modified
|
||||
in order to comply with the firewall requirements.
|
||||
connector (rmi), the hostname and port number of the RMI server, and the
|
||||
URL path. Note that URL path contains the RMI registry hostname and port
|
||||
number. Modify the port numbers if you need to comply with the firewall
|
||||
requirements.
|
||||
-->
|
||||
<Call name="addBean">
|
||||
<Arg>
|
||||
|
@ -28,9 +28,9 @@
|
|||
<Arg>
|
||||
<New class="javax.management.remote.JMXServiceURL">
|
||||
<Arg type="java.lang.String">rmi</Arg>
|
||||
<Arg type="java.lang.String"><Property name="jetty.jmxremote.rmihost" deprecated="jetty.jmxrmihost" default="localhost"/></Arg>
|
||||
<Arg type="java.lang.Integer"><Property name="jetty.jmxremote.rmiport" deprecated="jetty.jmxrmiport" default="1099"/></Arg>
|
||||
<Arg type="java.lang.String">/jndi/rmi://<Property name="jetty.jmxremote.rmihost" deprecated="jetty.jmxrmihost" default="localhost"/>:<Property name="jetty.jmxremote.rmiport" deprecated="jetty.jmxrmiport" default="1099"/>/jmxrmi</Arg>
|
||||
<Arg type="java.lang.String"><Property name="jetty.jmxremote.rmiserverhost" deprecated="jetty.jmxremote.rmihost,jetty.jmxrmihost" default="localhost"/></Arg>
|
||||
<Arg type="java.lang.Integer"><Property name="jetty.jmxremote.rmiserverport" deprecated="jetty.jmxremote.rmiport,jetty.jmxrmiport" default="1099"/></Arg>
|
||||
<Arg type="java.lang.String">/jndi/rmi://<Property name="jetty.jmxremote.rmiregistryhost" deprecated="jetty.jmxremote.rmihost,jetty.jmxrmihost" default="localhost"/>:<Property name="jetty.jmxremote.rmiregistryport" deprecated="jetty.jmxremote.rmiport,jetty.jmxrmiport" default="1099"/>/jmxrmi</Arg>
|
||||
</New>
|
||||
</Arg>
|
||||
<Arg>org.eclipse.jetty.jmx:name=rmiconnectorserver</Arg>
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Get the platform mbean server -->
|
||||
<!-- Get the platform MBeanServer -->
|
||||
<!-- =========================================================== -->
|
||||
<Call id="MBeanServer" class="java.lang.management.ManagementFactory"
|
||||
name="getPlatformMBeanServer" />
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Initialize the Jetty MBean container -->
|
||||
<!-- Initialize the Jetty MBeanContainer -->
|
||||
<!-- =========================================================== -->
|
||||
<Call name="addBean">
|
||||
<Arg>
|
||||
|
@ -25,7 +25,7 @@
|
|||
<!-- Add the static log -->
|
||||
<Call name="addBean">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.util.log.Log" />
|
||||
<Get class="org.eclipse.jetty.util.log.Log" name="Log" />
|
||||
</Arg>
|
||||
</Call>
|
||||
</Configure>
|
||||
|
|
|
@ -8,8 +8,14 @@ jmx
|
|||
etc/jetty-jmx-remote.xml
|
||||
|
||||
[ini-template]
|
||||
## The host/address to bind RMI to
|
||||
# jetty.jmxremote.rmihost=localhost
|
||||
## The host/address to bind the RMI server to.
|
||||
# jetty.jmxremote.rmiserverhost=localhost
|
||||
|
||||
## The port RMI listens to
|
||||
# jetty.jmxremote.rmiport=1099
|
||||
## The port the RMI server listens to (0 means a random port is chosen).
|
||||
# jetty.jmxremote.rmiserverport=1099
|
||||
|
||||
## The host/address to bind the RMI registry to.
|
||||
# jetty.jmxremote.rmiregistryhost=localhost
|
||||
|
||||
## The port the RMI registry listens to.
|
||||
# jetty.jmxremote.rmiregistryport=1099
|
||||
|
|
|
@ -18,160 +18,185 @@
|
|||
|
||||
package org.eclipse.jetty.jmx;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.UnknownHostException;
|
||||
import java.rmi.registry.LocateRegistry;
|
||||
import java.rmi.registry.Registry;
|
||||
import java.rmi.server.RMIClientSocketFactory;
|
||||
import java.rmi.server.RMIServerSocketFactory;
|
||||
import java.rmi.server.UnicastRemoteObject;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.IntConsumer;
|
||||
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.remote.JMXConnectorServer;
|
||||
import javax.management.remote.JMXConnectorServerFactory;
|
||||
import javax.management.remote.JMXServiceURL;
|
||||
import javax.management.remote.rmi.RMIConnectorServer;
|
||||
import javax.rmi.ssl.SslRMIClientSocketFactory;
|
||||
|
||||
import org.eclipse.jetty.util.HostPort;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.util.thread.ShutdownThread;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* AbstractLifeCycle wrapper for JMXConnector Server
|
||||
* <p>LifeCycle wrapper for JMXConnectorServer.</p>
|
||||
* <p>This class provides the following facilities:</p>
|
||||
* <ul>
|
||||
* <li>participates in the {@code Server} lifecycle</li>
|
||||
* <li>starts the RMI registry if not there already</li>
|
||||
* <li>allows to bind the RMI registry and the RMI server to the loopback interface</li>
|
||||
* <li>makes it easy to use TLS for the JMX communication</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class ConnectorServer extends AbstractLifeCycle
|
||||
{
|
||||
public static final String RMI_REGISTRY_CLIENT_SOCKET_FACTORY_ATTRIBUTE = "com.sun.jndi.rmi.factory.socket";
|
||||
private static final Logger LOG = Log.getLogger(ConnectorServer.class);
|
||||
|
||||
JMXConnectorServer _connectorServer;
|
||||
Registry _registry;
|
||||
private JMXServiceURL _jmxURL;
|
||||
private final Map<String, Object> _environment;
|
||||
private final String _objectName;
|
||||
private final SslContextFactory _sslContextFactory;
|
||||
private int _registryPort;
|
||||
private int _rmiPort;
|
||||
private JMXConnectorServer _connectorServer;
|
||||
private Registry _registry;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Constructs connector server
|
||||
* Constructs a ConnectorServer
|
||||
*
|
||||
* @param serviceURL the address of the new connector server.
|
||||
* The actual address of the new connector server, as returned
|
||||
* by its getAddress method, will not necessarily be exactly the same.
|
||||
* @param name object name string to be assigned to connector server bean
|
||||
* @throws Exception if unable to setup connector server
|
||||
* @param serviceURL the address of the new ConnectorServer
|
||||
* @param name object name string to be assigned to ConnectorServer bean
|
||||
*/
|
||||
public ConnectorServer(JMXServiceURL serviceURL, String name)
|
||||
throws Exception
|
||||
{
|
||||
this(serviceURL, null, name);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Constructs connector server
|
||||
* Constructs a ConnectorServer
|
||||
*
|
||||
* @param svcUrl the address of the new connector server.
|
||||
* The actual address of the new connector server, as returned
|
||||
* by its getAddress method, will not necessarily be exactly the same.
|
||||
* @param environment a set of attributes to control the new connector
|
||||
* server's behavior. This parameter can be null. Keys in this map must
|
||||
* be Strings. The appropriate type of each associated value depends on
|
||||
* the attribute. The contents of environment are not changed by this call.
|
||||
* @param name object name string to be assigned to connector server bean
|
||||
* @throws Exception if unable to create connector server
|
||||
* @param svcUrl the address of the new ConnectorServer
|
||||
* @param environment a set of attributes to control the new ConnectorServer's behavior.
|
||||
* This parameter can be null. Keys in this map must
|
||||
* be Strings. The appropriate type of each associated value depends on
|
||||
* the attribute. The contents of environment are not changed by this call.
|
||||
* @param name object name string to be assigned to ConnectorServer bean
|
||||
*/
|
||||
public ConnectorServer(JMXServiceURL svcUrl, Map<String,?> environment, String name)
|
||||
throws Exception
|
||||
public ConnectorServer(JMXServiceURL svcUrl, Map<String, ?> environment, String name)
|
||||
{
|
||||
String urlPath = svcUrl.getURLPath();
|
||||
int idx = urlPath.indexOf("rmi://");
|
||||
if (idx > 0)
|
||||
this(svcUrl, environment, name, null);
|
||||
}
|
||||
|
||||
public ConnectorServer(JMXServiceURL svcUrl, Map<String, ?> environment, String name, SslContextFactory sslContextFactory)
|
||||
{
|
||||
this._jmxURL = svcUrl;
|
||||
this._environment = environment == null ? new HashMap<>() : new HashMap<>(environment);
|
||||
this._objectName = name;
|
||||
this._sslContextFactory = sslContextFactory;
|
||||
}
|
||||
|
||||
public JMXServiceURL getAddress()
|
||||
{
|
||||
return _jmxURL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doStart() throws Exception
|
||||
{
|
||||
boolean rmi = "rmi".equals(_jmxURL.getProtocol());
|
||||
if (rmi)
|
||||
{
|
||||
String hostPort = urlPath.substring(idx+6, urlPath.indexOf('/', idx+6));
|
||||
String regHostPort = startRegistry(hostPort);
|
||||
if (regHostPort != null) {
|
||||
urlPath = urlPath.replace(hostPort,regHostPort);
|
||||
svcUrl = new JMXServiceURL(svcUrl.getProtocol(), svcUrl.getHost(), svcUrl.getPort(), urlPath);
|
||||
if (!_environment.containsKey(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE))
|
||||
_environment.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, new JMXRMIServerSocketFactory(_jmxURL.getHost(), port -> _rmiPort = port));
|
||||
if (_sslContextFactory != null)
|
||||
{
|
||||
SslRMIClientSocketFactory csf = new SslRMIClientSocketFactory();
|
||||
if (!_environment.containsKey(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE))
|
||||
_environment.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, csf);
|
||||
if (!_environment.containsKey(RMI_REGISTRY_CLIENT_SOCKET_FACTORY_ATTRIBUTE))
|
||||
_environment.put(RMI_REGISTRY_CLIENT_SOCKET_FACTORY_ATTRIBUTE, csf);
|
||||
}
|
||||
}
|
||||
MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
|
||||
_connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(svcUrl, environment, mbeanServer);
|
||||
mbeanServer.registerMBean(_connectorServer,new ObjectName(name));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
|
||||
*/
|
||||
@Override
|
||||
public void doStart()
|
||||
throws Exception
|
||||
{
|
||||
String urlPath = _jmxURL.getURLPath();
|
||||
String jndiRMI = "/jndi/rmi://";
|
||||
if (urlPath.startsWith(jndiRMI))
|
||||
{
|
||||
int startIndex = jndiRMI.length();
|
||||
int endIndex = urlPath.indexOf('/', startIndex);
|
||||
HostPort hostPort = new HostPort(urlPath.substring(startIndex, endIndex));
|
||||
String registryHost = startRegistry(hostPort);
|
||||
// If the RMI registry was already started, use the existing port.
|
||||
if (_registryPort == 0)
|
||||
_registryPort = hostPort.getPort();
|
||||
urlPath = jndiRMI + registryHost + ":" + _registryPort + urlPath.substring(endIndex);
|
||||
// Rebuild JMXServiceURL to use it for the creation of the JMXConnectorServer.
|
||||
_jmxURL = new JMXServiceURL(_jmxURL.getProtocol(), _jmxURL.getHost(), _jmxURL.getPort(), urlPath);
|
||||
}
|
||||
|
||||
MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
|
||||
_connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(_jmxURL, _environment, mbeanServer);
|
||||
mbeanServer.registerMBean(_connectorServer, new ObjectName(_objectName));
|
||||
_connectorServer.start();
|
||||
String rmiHost = normalizeHost(_jmxURL.getHost());
|
||||
// If _rmiPort is still zero, it's using the same port as the RMI registry.
|
||||
if (_rmiPort == 0)
|
||||
_rmiPort = _registryPort;
|
||||
_jmxURL = new JMXServiceURL(_jmxURL.getProtocol(), rmiHost, _rmiPort, urlPath);
|
||||
|
||||
ShutdownThread.register(0, this);
|
||||
|
||||
LOG.info("JMX Remote URL: {}", _connectorServer.getAddress().toString());
|
||||
LOG.info("JMX URL: {}", _jmxURL);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop()
|
||||
*/
|
||||
@Override
|
||||
public void doStop()
|
||||
throws Exception
|
||||
public void doStop() throws Exception
|
||||
{
|
||||
ShutdownThread.deregister(this);
|
||||
_connectorServer.stop();
|
||||
MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
|
||||
mbeanServer.unregisterMBean(new ObjectName(_objectName));
|
||||
stopRegistry();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that local RMI registry is used, and ensure it is started. If local RMI registry is being used and not started, start it.
|
||||
*
|
||||
* @param hostPath
|
||||
* hostname and port number of RMI registry
|
||||
* @throws Exception
|
||||
*/
|
||||
private String startRegistry(String hostPath) throws Exception
|
||||
private String startRegistry(HostPort hostPort) throws Exception
|
||||
{
|
||||
HostPort hostPort = new HostPort(hostPath);
|
||||
String host = hostPort.getHost();
|
||||
int port = hostPort.getPort(1099);
|
||||
|
||||
String rmiHost = hostPort.getHost();
|
||||
int rmiPort = hostPort.getPort(1099);
|
||||
|
||||
// Verify that local registry is being used
|
||||
InetAddress hostAddress = InetAddress.getByName(rmiHost);
|
||||
if(hostAddress.isLoopbackAddress())
|
||||
try
|
||||
{
|
||||
if (rmiPort == 0)
|
||||
{
|
||||
ServerSocket socket = new ServerSocket(0);
|
||||
rmiPort = socket.getLocalPort();
|
||||
socket.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
// Check if a local registry is already running
|
||||
LocateRegistry.getRegistry(rmiPort).list();
|
||||
return null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LOG.ignore(ex);
|
||||
}
|
||||
}
|
||||
|
||||
_registry = LocateRegistry.createRegistry(rmiPort);
|
||||
Thread.sleep(1000);
|
||||
|
||||
rmiHost = HostPort.normalizeHost(InetAddress.getLocalHost().getCanonicalHostName());
|
||||
return rmiHost + ':' + Integer.toString(rmiPort);
|
||||
// Check if a local registry is already running.
|
||||
LocateRegistry.getRegistry(host, port).list();
|
||||
return normalizeHost(host);
|
||||
}
|
||||
catch (Throwable ex)
|
||||
{
|
||||
LOG.ignore(ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
RMIClientSocketFactory csf = _sslContextFactory == null ? null : new SslRMIClientSocketFactory();
|
||||
RMIServerSocketFactory ssf = new JMXRMIServerSocketFactory(host, p -> _registryPort = p);
|
||||
_registry = LocateRegistry.createRegistry(port, csf, ssf);
|
||||
|
||||
return normalizeHost(host);
|
||||
}
|
||||
|
||||
private String normalizeHost(String host) throws UnknownHostException
|
||||
{
|
||||
return host == null || host.isEmpty() ? InetAddress.getLocalHost().getHostName() : host;
|
||||
}
|
||||
|
||||
private void stopRegistry()
|
||||
|
@ -180,12 +205,69 @@ public class ConnectorServer extends AbstractLifeCycle
|
|||
{
|
||||
try
|
||||
{
|
||||
UnicastRemoteObject.unexportObject(_registry,true);
|
||||
UnicastRemoteObject.unexportObject(_registry, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LOG.ignore(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_registry = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class JMXRMIServerSocketFactory implements RMIServerSocketFactory
|
||||
{
|
||||
private final String _host;
|
||||
private final IntConsumer _portConsumer;
|
||||
|
||||
private JMXRMIServerSocketFactory(String host, IntConsumer portConsumer)
|
||||
{
|
||||
this._host = host;
|
||||
this._portConsumer = portConsumer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerSocket createServerSocket(int port) throws IOException
|
||||
{
|
||||
InetAddress address = _host == null || _host.isEmpty() ? InetAddress.getLocalHost() : InetAddress.getByName(_host);
|
||||
ServerSocket server = createServerSocket(address, port);
|
||||
_portConsumer.accept(server.getLocalPort());
|
||||
return server;
|
||||
}
|
||||
|
||||
private ServerSocket createServerSocket(InetAddress address, int port) throws IOException
|
||||
{
|
||||
// A null address binds to the wildcard address.
|
||||
if (_sslContextFactory == null)
|
||||
{
|
||||
ServerSocket server = new ServerSocket();
|
||||
server.bind(new InetSocketAddress(address, port));
|
||||
return server;
|
||||
}
|
||||
else
|
||||
{
|
||||
return _sslContextFactory.newSslServerSocket(address == null ? null : address.getHostName(), port, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return _host != null ? _host.hashCode() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null || getClass() != obj.getClass())
|
||||
return false;
|
||||
JMXRMIServerSocketFactory that = (JMXRMIServerSocketFactory)obj;
|
||||
return Objects.equals(_host, that._host);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,95 +18,273 @@
|
|||
|
||||
package org.eclipse.jetty.jmx;
|
||||
|
||||
import java.net.ConnectException;
|
||||
import java.net.InetAddress;
|
||||
import java.rmi.registry.LocateRegistry;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.management.remote.JMXConnector;
|
||||
import javax.management.remote.JMXConnectorFactory;
|
||||
import javax.management.remote.JMXServiceURL;
|
||||
import javax.rmi.ssl.SslRMIClientSocketFactory;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import static org.hamcrest.core.Is.is;
|
||||
import static org.hamcrest.core.AnyOf.anyOf;
|
||||
|
||||
/**
|
||||
* Running the tests of this class in the same JVM results often in
|
||||
* <pre>
|
||||
* Caused by: java.rmi.NoSuchObjectException: no such object in table
|
||||
* at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:276)
|
||||
* at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:253)
|
||||
* at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:379)
|
||||
* at sun.rmi.registry.RegistryImpl_Stub.bind(Unknown Source)
|
||||
* </pre>
|
||||
* Running each test method in a forked JVM makes these tests all pass,
|
||||
* therefore the issue is likely caused by use of stale stubs cached by the JDK.
|
||||
*/
|
||||
@Ignore
|
||||
public class ConnectorServerTest
|
||||
{
|
||||
|
||||
private String objectName = "org.eclipse.jetty:name=rmiconnectorserver";
|
||||
private ConnectorServer connectorServer;
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception
|
||||
{
|
||||
if (connectorServer != null)
|
||||
{
|
||||
connectorServer.doStop();
|
||||
}
|
||||
connectorServer.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void randomPortTest() throws Exception
|
||||
public void testAddressAfterStart() throws Exception
|
||||
{
|
||||
// given
|
||||
connectorServer = new ConnectorServer(new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:0/jettytest"),
|
||||
"org.eclipse.jetty:name=rmiconnectorserver");
|
||||
// if port is not available then the server value is null
|
||||
if (connectorServer != null)
|
||||
{
|
||||
// when
|
||||
connectorServer.start();
|
||||
|
||||
// then
|
||||
assertThat("Server status must be in started or starting",connectorServer.getState(),
|
||||
anyOf(is(ConnectorServer.STARTED),is(ConnectorServer.STARTING)));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore // collides on ci server
|
||||
public void testConnServerWithRmiDefaultPort() throws Exception
|
||||
{
|
||||
// given
|
||||
LocateRegistry.createRegistry(1099);
|
||||
JMXServiceURL serviceURLWithOutPort = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi");
|
||||
connectorServer = new ConnectorServer(serviceURLWithOutPort," domain: key3 = value3");
|
||||
|
||||
// when
|
||||
connectorServer = new ConnectorServer(new JMXServiceURL("service:jmx:rmi:///jndi/rmi:///jmxrmi"), objectName);
|
||||
connectorServer.start();
|
||||
|
||||
// then
|
||||
assertThat("Server status must be in started or starting",connectorServer.getState(),anyOf(is(ConnectorServer.STARTED),is(ConnectorServer.STARTING)));
|
||||
JMXServiceURL address = connectorServer.getAddress();
|
||||
Assert.assertTrue(address.toString().matches("service:jmx:rmi://[^:]+:\\d+/jndi/rmi://[^:]+:\\d+/jmxrmi"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnServerWithRmiRandomPort() throws Exception
|
||||
public void testNoRegistryHostBindsToHost() throws Exception
|
||||
{
|
||||
// given
|
||||
JMXServiceURL serviceURLWithOutPort = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:1199/jmxrmi");
|
||||
connectorServer = new ConnectorServer(serviceURLWithOutPort," domain: key4 = value4");
|
||||
// if port is not available then the server value is null
|
||||
if (connectorServer != null)
|
||||
{
|
||||
// when
|
||||
connectorServer.start();
|
||||
connectorServer.stop();
|
||||
connectorServer = new ConnectorServer(new JMXServiceURL("service:jmx:rmi:///jndi/rmi:///jmxrmi"), objectName);
|
||||
connectorServer.start();
|
||||
|
||||
// then
|
||||
assertThat("Server status must be in started or starting",connectorServer.getState(),
|
||||
anyOf(is(ConnectorServer.STOPPING),is(ConnectorServer.STOPPED)));
|
||||
// Verify that I can connect to the RMI registry using a non-loopback address.
|
||||
new Socket(InetAddress.getLocalHost(), 1099).close();
|
||||
try
|
||||
{
|
||||
// Verify that I cannot connect to the RMI registry using the loopback address.
|
||||
new Socket(InetAddress.getLoopbackAddress(), 1099).close();
|
||||
Assert.fail();
|
||||
}
|
||||
catch (ConnectException ignored)
|
||||
{
|
||||
// Ignored.
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testIsLoopbackAddressWithWrongValue() throws Exception
|
||||
public void testNoRegistryHostNonDefaultRegistryPort() throws Exception
|
||||
{
|
||||
// given
|
||||
JMXServiceURL serviceURLWithOutPort = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + InetAddress.getLocalHost() + ":1199/jmxrmi");
|
||||
ServerSocket serverSocket = new ServerSocket(0);
|
||||
int registryPort = serverSocket.getLocalPort();
|
||||
serverSocket.close();
|
||||
connectorServer = new ConnectorServer(new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:" + registryPort + "/jmxrmi"), objectName);
|
||||
connectorServer.start();
|
||||
|
||||
// when
|
||||
connectorServer = new ConnectorServer(serviceURLWithOutPort," domain: key5 = value5");
|
||||
// Verify that I can connect to the RMI registry using a non-loopback address.
|
||||
new Socket(InetAddress.getLocalHost(), registryPort).close();
|
||||
try
|
||||
{
|
||||
// Verify that I cannot connect to the RMI registry using the loopback address.
|
||||
new Socket(InetAddress.getLoopbackAddress(), registryPort).close();
|
||||
Assert.fail();
|
||||
}
|
||||
catch (ConnectException ignored)
|
||||
{
|
||||
// Ignored.
|
||||
}
|
||||
}
|
||||
|
||||
// then
|
||||
assertNull("As loopback address returns false...registry must be null",connectorServer._registry);
|
||||
@Test
|
||||
public void testAnyRegistryHostBindsToAny() throws Exception
|
||||
{
|
||||
ServerSocket serverSocket = new ServerSocket(0);
|
||||
int registryPort = serverSocket.getLocalPort();
|
||||
serverSocket.close();
|
||||
connectorServer = new ConnectorServer(new JMXServiceURL("service:jmx:rmi:///jndi/rmi://0.0.0.0:" + registryPort + "/jmxrmi"), objectName);
|
||||
connectorServer.start();
|
||||
|
||||
// Verify that I can connect to the RMI registry using a non-loopback address.
|
||||
new Socket(InetAddress.getLocalHost(), registryPort).close();
|
||||
// Verify that I can connect to the RMI registry using the loopback address.
|
||||
new Socket(InetAddress.getLoopbackAddress(), registryPort).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalhostRegistryBindsToLoopback() throws Exception
|
||||
{
|
||||
connectorServer = new ConnectorServer(new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi"), objectName);
|
||||
connectorServer.start();
|
||||
|
||||
InetAddress localHost = InetAddress.getLocalHost();
|
||||
if (!localHost.isLoopbackAddress())
|
||||
{
|
||||
try
|
||||
{
|
||||
// Verify that I cannot connect to the RMIRegistry using a non-loopback address.
|
||||
new Socket(localHost, 1099);
|
||||
Assert.fail();
|
||||
}
|
||||
catch (ConnectException ignored)
|
||||
{
|
||||
// Ignored.
|
||||
}
|
||||
}
|
||||
|
||||
InetAddress loopback = InetAddress.getLoopbackAddress();
|
||||
new Socket(loopback, 1099).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoRMIHostBindsToHost() throws Exception
|
||||
{
|
||||
connectorServer = new ConnectorServer(new JMXServiceURL("service:jmx:rmi:///jndi/rmi:///jmxrmi"), objectName);
|
||||
connectorServer.start();
|
||||
|
||||
// Verify that I can connect to the RMI server using a non-loopback address.
|
||||
new Socket(InetAddress.getLocalHost(), connectorServer.getAddress().getPort()).close();
|
||||
try
|
||||
{
|
||||
// Verify that I cannot connect to the RMI server using the loopback address.
|
||||
new Socket(InetAddress.getLoopbackAddress(), connectorServer.getAddress().getPort()).close();
|
||||
Assert.fail();
|
||||
}
|
||||
catch (ConnectException ignored)
|
||||
{
|
||||
// Ignored.
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnyRMIHostBindsToAny() throws Exception
|
||||
{
|
||||
connectorServer = new ConnectorServer(new JMXServiceURL("service:jmx:rmi://0.0.0.0/jndi/rmi:///jmxrmi"), objectName);
|
||||
connectorServer.start();
|
||||
|
||||
// Verify that I can connect to the RMI server using a non-loopback address.
|
||||
new Socket(InetAddress.getLocalHost(), connectorServer.getAddress().getPort()).close();
|
||||
// Verify that I can connect to the RMI server using the loopback address.
|
||||
new Socket(InetAddress.getLoopbackAddress(), connectorServer.getAddress().getPort()).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalhostRMIBindsToLoopback() throws Exception
|
||||
{
|
||||
connectorServer = new ConnectorServer(new JMXServiceURL("service:jmx:rmi://localhost/jndi/rmi://localhost:1099/jmxrmi"), objectName);
|
||||
connectorServer.start();
|
||||
JMXServiceURL address = connectorServer.getAddress();
|
||||
|
||||
InetAddress localHost = InetAddress.getLocalHost();
|
||||
if (!localHost.isLoopbackAddress())
|
||||
{
|
||||
try
|
||||
{
|
||||
// Verify that I cannot connect to the RMIRegistry using a non-loopback address.
|
||||
new Socket(localHost, address.getPort());
|
||||
Assert.fail();
|
||||
}
|
||||
catch (ConnectException ignored)
|
||||
{
|
||||
// Ignored.
|
||||
}
|
||||
}
|
||||
|
||||
InetAddress loopback = InetAddress.getLoopbackAddress();
|
||||
new Socket(loopback, address.getPort()).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRMIServerPort() throws Exception
|
||||
{
|
||||
ServerSocket server = new ServerSocket(0);
|
||||
int port = server.getLocalPort();
|
||||
server.close();
|
||||
|
||||
connectorServer = new ConnectorServer(new JMXServiceURL("service:jmx:rmi://localhost:" + port + "/jndi/rmi:///jmxrmi"), objectName);
|
||||
connectorServer.start();
|
||||
|
||||
JMXServiceURL address = connectorServer.getAddress();
|
||||
Assert.assertEquals(port, address.getPort());
|
||||
|
||||
InetAddress loopback = InetAddress.getLoopbackAddress();
|
||||
new Socket(loopback, port).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRMIServerAndRMIRegistryOnSameHostAndSamePort() throws Exception
|
||||
{
|
||||
// RMI can multiplex connections on the same address and port for different
|
||||
// RMI objects, in this case the RMI registry and the RMI server. In this
|
||||
// case, the RMIServerSocketFactory will be invoked only once.
|
||||
// The case with different address and same port is already covered by TCP,
|
||||
// that can listen to 192.168.0.1:1099 and 127.0.0.1:1099 without problems.
|
||||
|
||||
String host = "localhost";
|
||||
ServerSocket serverSocket = new ServerSocket(0);
|
||||
int port = serverSocket.getLocalPort();
|
||||
serverSocket.close();
|
||||
|
||||
connectorServer = new ConnectorServer(new JMXServiceURL("rmi", host, port, "/jndi/rmi://" + host + ":" + port + "/jmxrmi"), objectName);
|
||||
connectorServer.start();
|
||||
|
||||
JMXServiceURL address = connectorServer.getAddress();
|
||||
Assert.assertEquals(port, address.getPort());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJMXOverTLS() throws Exception
|
||||
{
|
||||
SslContextFactory sslContextFactory = new SslContextFactory();
|
||||
String keyStorePath = MavenTestingUtils.getTestResourcePath("keystore.jks").toString();
|
||||
String keyStorePassword = "storepwd";
|
||||
sslContextFactory.setKeyStorePath(keyStorePath);
|
||||
sslContextFactory.setKeyStorePassword(keyStorePassword);
|
||||
sslContextFactory.start();
|
||||
|
||||
// The RMIClientSocketFactory is stored within the RMI stub.
|
||||
// When using TLS, the stub is deserialized in a possibly different
|
||||
// JVM that does not have access to the server keystore, and there
|
||||
// is no way to provide TLS configuration during the deserialization
|
||||
// of the stub. Therefore the client must provide system properties
|
||||
// to specify the TLS configuration. For this test it needs the
|
||||
// trustStore because the server certificate is self-signed.
|
||||
// The server needs to contact the RMI registry and therefore also
|
||||
// needs these system properties.
|
||||
System.setProperty("javax.net.ssl.trustStore", keyStorePath);
|
||||
System.setProperty("javax.net.ssl.trustStorePassword", keyStorePassword);
|
||||
|
||||
connectorServer = new ConnectorServer(new JMXServiceURL("rmi", null, 1100, "/jndi/rmi://localhost:1100/jmxrmi"), null, objectName, sslContextFactory);
|
||||
connectorServer.start();
|
||||
|
||||
// The client needs to talk TLS to the RMI registry to download
|
||||
// the RMI server stub, and this is independent from JMX.
|
||||
// The RMI server stub then contains the SslRMIClientSocketFactory
|
||||
// needed to talk to the RMI server.
|
||||
Map<String, Object> clientEnv = new HashMap<>();
|
||||
clientEnv.put(ConnectorServer.RMI_REGISTRY_CLIENT_SOCKET_FACTORY_ATTRIBUTE, new SslRMIClientSocketFactory());
|
||||
try (JMXConnector client = JMXConnectorFactory.connect(connectorServer.getAddress(), clientEnv))
|
||||
{
|
||||
client.getMBeanServerConnection().queryNames(null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
||||
org.eclipse.jetty.jmx.LEVEL=WARN
|
||||
org.eclipse.jetty.jmx.LEVEL=INFO
|
||||
|
|
Binary file not shown.
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-jndi</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-jspc-maven-plugin</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-maven-plugin</artifactId>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.memcached</groupId>
|
||||
<artifactId>memcached-parent</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-nosql</artifactId>
|
||||
|
|
|
@ -409,7 +409,7 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore
|
|||
BasicDBList list = new BasicDBList();
|
||||
list.add(gt);
|
||||
list.add(lt);
|
||||
query.append("and", list);
|
||||
query.append("$and", list);
|
||||
|
||||
DBCursor oldExpiredSessions = null;
|
||||
try
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-osgi-alpn</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-osgi-boot-jsp</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-osgi-boot</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-httpservice</artifactId>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>test-jetty-osgi-context</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>test-jetty-osgi-server</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-plus</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-proxy</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
|
|
|
@ -22,14 +22,11 @@ package org.eclipse.jetty.quickstart;
|
|||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.toolchain.test.FS;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -90,7 +87,7 @@ public class TestQuickStart
|
|||
server.start();
|
||||
|
||||
//verify that FooServlet is now mapped to / and not the DefaultServlet
|
||||
ServletHolder sh = webapp.getServletHandler().getHolderEntry("/").getResource();
|
||||
ServletHolder sh = webapp.getServletHandler().getMappedServlet("/").getResource();
|
||||
assertNotNull(sh);
|
||||
assertEquals("foo", sh.getName());
|
||||
server.stop();
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-rewrite</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-runner</artifactId>
|
||||
|
@ -15,7 +15,6 @@
|
|||
<url>http://www.eclipse.org/jetty</url>
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-security</artifactId>
|
||||
|
|
|
@ -50,8 +50,7 @@ public class HashLoginService extends AbstractLoginService
|
|||
{
|
||||
private static final Logger LOG = Log.getLogger(HashLoginService.class);
|
||||
|
||||
private File _configFile;
|
||||
private Resource _configResource;
|
||||
private String _config;
|
||||
private boolean hotReload = false; // default is not to reload
|
||||
private UserStore _userStore;
|
||||
private boolean _userStoreAutoCreate = false;
|
||||
|
@ -78,28 +77,15 @@ public class HashLoginService extends AbstractLoginService
|
|||
/* ------------------------------------------------------------ */
|
||||
public String getConfig()
|
||||
{
|
||||
if(_configFile == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return _configFile.getAbsolutePath();
|
||||
return _config;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #setConfig(String)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void getConfig(String config)
|
||||
{
|
||||
setConfig(config);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Resource getConfigResource()
|
||||
{
|
||||
return _configResource;
|
||||
return null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -109,12 +95,11 @@ public class HashLoginService extends AbstractLoginService
|
|||
* The property file maps usernames to password specs followed by an optional comma separated list of role names.
|
||||
* </p>
|
||||
*
|
||||
* @param configFile
|
||||
* Filename of user properties file.
|
||||
* @param config uri or url or path to realm properties file
|
||||
*/
|
||||
public void setConfig(String configFile)
|
||||
public void setConfig(String config)
|
||||
{
|
||||
_configFile = new File(configFile);
|
||||
_config=config;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -200,11 +185,10 @@ public class HashLoginService extends AbstractLoginService
|
|||
if (_userStore == null)
|
||||
{
|
||||
if(LOG.isDebugEnabled())
|
||||
LOG.debug("doStart: Starting new PropertyUserStore. PropertiesFile: " + _configFile + " hotReload: " + hotReload);
|
||||
|
||||
LOG.debug("doStart: Starting new PropertyUserStore. PropertiesFile: " + _config + " hotReload: " + hotReload);
|
||||
PropertyUserStore propertyUserStore = new PropertyUserStore();
|
||||
propertyUserStore.setHotReload(hotReload);
|
||||
propertyUserStore.setConfigPath(_configFile);
|
||||
propertyUserStore.setConfigPath(_config);
|
||||
propertyUserStore.start();
|
||||
_userStore = propertyUserStore;
|
||||
_userStoreAutoCreate = true;
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.eclipse.jetty.util.security.Credential;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
|
@ -73,18 +74,30 @@ public class PropertyUserStore extends UserStore implements PathWatcher.Listener
|
|||
@Deprecated
|
||||
public String getConfig()
|
||||
{
|
||||
return _configPath.toString();
|
||||
if (_configPath != null)
|
||||
return _configPath.toString();
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Config Path from a String reference to a file
|
||||
* @param configFile the config file
|
||||
* @deprecated use {@link #setConfigPath(String)} instead
|
||||
* @param config the config file
|
||||
*/
|
||||
@Deprecated
|
||||
public void setConfig(String configFile)
|
||||
public void setConfig(String config)
|
||||
{
|
||||
setConfigPath(configFile);
|
||||
try
|
||||
{
|
||||
Resource configResource = Resource.newResource(config);
|
||||
if (configResource.getFile() != null)
|
||||
setConfigPath(configResource.getFile());
|
||||
else
|
||||
throw new IllegalArgumentException(config+" is not a file");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
|
|
|
@ -11,5 +11,5 @@ server
|
|||
[xml]
|
||||
etc/jetty-stats.xml
|
||||
|
||||
[ini-template]
|
||||
[ini]
|
||||
jetty.webapp.addServerClasses+=,-org.eclipse.jetty.servlet.StatisticsServlet
|
||||
|
|
|
@ -23,7 +23,6 @@ import java.util.Locale;
|
|||
|
||||
import javax.servlet.http.Cookie;
|
||||
|
||||
import org.eclipse.jetty.http.QuotedCSV;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
@ -115,6 +114,8 @@ public class CookieCutter
|
|||
while (_fieldList.size()>_fields)
|
||||
_fieldList.remove(_fields);
|
||||
|
||||
StringBuilder unquoted=null;
|
||||
|
||||
// For each cookie field
|
||||
for (String hdr : _fieldList)
|
||||
{
|
||||
|
@ -126,45 +127,46 @@ public class CookieCutter
|
|||
|
||||
boolean invalue=false;
|
||||
boolean quoted=false;
|
||||
boolean unquotedToken=false;
|
||||
boolean escaped=false;
|
||||
int tokenstart=-1;
|
||||
int tokenend=-1;
|
||||
for (int i = 0, length = hdr.length(), last=length-1; i < length; i++)
|
||||
{
|
||||
char c = hdr.charAt(i);
|
||||
|
||||
|
||||
// Handle quoted values for name or value
|
||||
if (quoted)
|
||||
{
|
||||
if (escaped)
|
||||
{
|
||||
escaped=false;
|
||||
unquoted.append(c);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '"':
|
||||
tokenend=i;
|
||||
quoted=false;
|
||||
|
||||
// handle quote as last character specially
|
||||
if (i==last)
|
||||
{
|
||||
if (invalue)
|
||||
value = hdr.substring(tokenstart, tokenend+1);
|
||||
else
|
||||
{
|
||||
name = hdr.substring(tokenstart, tokenend+1);
|
||||
value = "";
|
||||
}
|
||||
value = unquoted.toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
unquotedToken=true;
|
||||
tokenstart=i;
|
||||
tokenend=-1;
|
||||
}
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
escaped=true;
|
||||
continue;
|
||||
|
||||
default:
|
||||
unquoted.append(c);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -180,30 +182,42 @@ public class CookieCutter
|
|||
case '\t':
|
||||
continue;
|
||||
|
||||
case ';':
|
||||
if (unquotedToken)
|
||||
{
|
||||
value = unquoted.toString();
|
||||
unquoted.setLength(0);
|
||||
unquotedToken = false;
|
||||
}
|
||||
else if(tokenstart>=0 && tokenend>=0)
|
||||
value = hdr.substring(tokenstart, tokenend+1);
|
||||
else
|
||||
value="";
|
||||
|
||||
tokenstart = -1;
|
||||
invalue=false;
|
||||
break;
|
||||
|
||||
case '"':
|
||||
if (tokenstart<0)
|
||||
{
|
||||
quoted=true;
|
||||
tokenstart=i;
|
||||
if (unquoted==null)
|
||||
unquoted=new StringBuilder();
|
||||
continue;
|
||||
}
|
||||
tokenend=i;
|
||||
if (i==last)
|
||||
{
|
||||
value = hdr.substring(tokenstart, tokenend+1);
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
// fall through to default case
|
||||
|
||||
case ';':
|
||||
if (tokenstart>=0)
|
||||
value = hdr.substring(tokenstart, tokenend+1);
|
||||
else
|
||||
value="";
|
||||
tokenstart = -1;
|
||||
invalue=false;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (unquotedToken)
|
||||
{
|
||||
// must have been a bad internal quote. let's fix as best we can
|
||||
unquoted.append(hdr.substring(tokenstart,i));
|
||||
quoted = true;
|
||||
unquotedToken = false;
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
if (tokenstart<0)
|
||||
tokenstart=i;
|
||||
tokenend=i;
|
||||
|
@ -223,39 +237,49 @@ public class CookieCutter
|
|||
case ' ':
|
||||
case '\t':
|
||||
continue;
|
||||
|
||||
case '"':
|
||||
if (tokenstart<0)
|
||||
{
|
||||
quoted=true;
|
||||
tokenstart=i;
|
||||
}
|
||||
tokenend=i;
|
||||
if (i==last)
|
||||
{
|
||||
name = hdr.substring(tokenstart, tokenend+1);
|
||||
value = "";
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
|
||||
case ';':
|
||||
if (tokenstart>=0)
|
||||
if (unquotedToken)
|
||||
{
|
||||
name = unquoted.toString();
|
||||
unquoted.setLength(0);
|
||||
unquotedToken = false;
|
||||
}
|
||||
else if(tokenstart>=0 && tokenend>=0)
|
||||
{
|
||||
name = hdr.substring(tokenstart, tokenend+1);
|
||||
value = "";
|
||||
}
|
||||
|
||||
value = "";
|
||||
tokenstart = -1;
|
||||
break;
|
||||
|
||||
case '=':
|
||||
if (tokenstart>=0)
|
||||
if (unquotedToken)
|
||||
{
|
||||
name = unquoted.toString();
|
||||
unquoted.setLength(0);
|
||||
unquotedToken = false;
|
||||
}
|
||||
else if(tokenstart>=0 && tokenend>=0)
|
||||
{
|
||||
name = hdr.substring(tokenstart, tokenend+1);
|
||||
}
|
||||
|
||||
tokenstart = -1;
|
||||
invalue=true;
|
||||
continue;
|
||||
|
||||
|
||||
default:
|
||||
if (unquotedToken)
|
||||
{
|
||||
// must have been a bad internal quote. let's fix as best we can
|
||||
unquoted.append(hdr.substring(tokenstart,i));
|
||||
quoted = true;
|
||||
unquotedToken = false;
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
if (tokenstart<0)
|
||||
tokenstart=i;
|
||||
tokenend=i;
|
||||
|
@ -272,11 +296,7 @@ public class CookieCutter
|
|||
|
||||
// If after processing the current character we have a value and a name, then it is a cookie
|
||||
if (value!=null && name!=null)
|
||||
{
|
||||
|
||||
name=QuotedCSV.unquote(name);
|
||||
value=QuotedCSV.unquote(value);
|
||||
|
||||
{
|
||||
try
|
||||
{
|
||||
if (name.startsWith("$"))
|
||||
|
@ -301,6 +321,13 @@ public class CookieCutter
|
|||
{
|
||||
version = Integer.parseInt(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
cookie = new Cookie(name, value);
|
||||
if (version > 0)
|
||||
cookie.setVersion(version);
|
||||
cookies.add(cookie);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -1430,9 +1430,10 @@ public class Response implements HttpServletResponse
|
|||
{
|
||||
if (_characterEncoding!=null &&
|
||||
content.getCharacterEncoding()==null &&
|
||||
content.getContentTypeValue()!=null &&
|
||||
__explicitCharset.contains(_encodingFrom))
|
||||
{
|
||||
setContentType(content.getMimeType().getBaseType().asString());
|
||||
setContentType(MimeTypes.getContentTypeWithoutCharset(content.getContentTypeValue()));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -0,0 +1,197 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2017 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.server;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
public class CookieCutterTest
|
||||
{
|
||||
private Cookie[] parseCookieHeaders(String... headers)
|
||||
{
|
||||
CookieCutter cutter = new CookieCutter();
|
||||
for (String header : headers)
|
||||
{
|
||||
cutter.addCookieField(header);
|
||||
}
|
||||
return cutter.getCookies();
|
||||
}
|
||||
|
||||
private void assertCookie(String prefix, Cookie cookie,
|
||||
String expectedName,
|
||||
String expectedValue,
|
||||
int expectedVersion,
|
||||
String expectedPath)
|
||||
{
|
||||
assertThat(prefix + ".name", cookie.getName(), is(expectedName));
|
||||
assertThat(prefix + ".value", cookie.getValue(), is(expectedValue));
|
||||
assertThat(prefix + ".version", cookie.getVersion(), is(expectedVersion));
|
||||
assertThat(prefix + ".path", cookie.getPath(), is(expectedPath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Example from RFC2109 and RFC2965
|
||||
*/
|
||||
@Test
|
||||
public void testRFC_Single()
|
||||
{
|
||||
String rawCookie = "$Version=\"1\"; Customer=\"WILE_E_COYOTE\"; $Path=\"/acme\"";
|
||||
|
||||
Cookie cookies[] = parseCookieHeaders(rawCookie);
|
||||
|
||||
assertThat("Cookies.length", cookies.length, is(1));
|
||||
assertCookie("Cookies[0]", cookies[0], "Customer", "WILE_E_COYOTE", 1, "/acme");
|
||||
}
|
||||
|
||||
/**
|
||||
* Example from RFC2109 and RFC2965
|
||||
*/
|
||||
@Test
|
||||
public void testRFC_Double()
|
||||
{
|
||||
String rawCookie = "$Version=\"1\"; " +
|
||||
"Customer=\"WILE_E_COYOTE\"; $Path=\"/acme\"; " +
|
||||
"Part_Number=\"Rocket_Launcher_0001\"; $Path=\"/acme\"";
|
||||
|
||||
Cookie cookies[] = parseCookieHeaders(rawCookie);
|
||||
|
||||
assertThat("Cookies.length", cookies.length, is(2));
|
||||
assertCookie("Cookies[0]", cookies[0], "Customer", "WILE_E_COYOTE", 1, "/acme");
|
||||
assertCookie("Cookies[1]", cookies[1], "Part_Number", "Rocket_Launcher_0001", 1, "/acme");
|
||||
}
|
||||
|
||||
/**
|
||||
* Example from RFC2109 and RFC2965
|
||||
*/
|
||||
@Test
|
||||
public void testRFC_Triple()
|
||||
{
|
||||
String rawCookie = "$Version=\"1\"; " +
|
||||
"Customer=\"WILE_E_COYOTE\"; $Path=\"/acme\"; " +
|
||||
"Part_Number=\"Rocket_Launcher_0001\"; $Path=\"/acme\"; " +
|
||||
"Shipping=\"FedEx\"; $Path=\"/acme\"";
|
||||
|
||||
Cookie cookies[] = parseCookieHeaders(rawCookie);
|
||||
|
||||
assertThat("Cookies.length", cookies.length, is(3));
|
||||
assertCookie("Cookies[0]", cookies[0], "Customer", "WILE_E_COYOTE", 1, "/acme");
|
||||
assertCookie("Cookies[1]", cookies[1], "Part_Number", "Rocket_Launcher_0001", 1, "/acme");
|
||||
assertCookie("Cookies[2]", cookies[2], "Shipping", "FedEx", 1, "/acme");
|
||||
}
|
||||
|
||||
/**
|
||||
* Example from RFC2109 and RFC2965
|
||||
*/
|
||||
@Test
|
||||
public void testRFC_PathExample()
|
||||
{
|
||||
String rawCookie = "$Version=\"1\"; " +
|
||||
"Part_Number=\"Riding_Rocket_0023\"; $Path=\"/acme/ammo\"; " +
|
||||
"Part_Number=\"Rocket_Launcher_0001\"; $Path=\"/acme\"";
|
||||
|
||||
Cookie cookies[] = parseCookieHeaders(rawCookie);
|
||||
|
||||
assertThat("Cookies.length", cookies.length, is(2));
|
||||
assertCookie("Cookies[0]", cookies[0], "Part_Number", "Riding_Rocket_0023", 1, "/acme/ammo");
|
||||
assertCookie("Cookies[1]", cookies[1], "Part_Number", "Rocket_Launcher_0001", 1, "/acme");
|
||||
}
|
||||
|
||||
/**
|
||||
* Example from RFC2109
|
||||
*/
|
||||
@Test
|
||||
public void testRFC2109_CookieSpoofingExample()
|
||||
{
|
||||
String rawCookie = "$Version=\"1\"; " +
|
||||
"session_id=\"1234\"; " +
|
||||
"session_id=\"1111\"; $Domain=\".cracker.edu\"";
|
||||
|
||||
Cookie cookies[] = parseCookieHeaders(rawCookie);
|
||||
|
||||
assertThat("Cookies.length", cookies.length, is(2));
|
||||
assertCookie("Cookies[0]", cookies[0], "session_id", "1234", 1, null);
|
||||
assertCookie("Cookies[1]", cookies[1], "session_id", "1111", 1, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Example from RFC2965
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testRFC2965_CookieSpoofingExample()
|
||||
{
|
||||
// Ignored because comma separation no longer supported by RFC6265
|
||||
String rawCookie = "$Version=\"1\"; session_id=\"1234\", " +
|
||||
"$Version=\"1\"; session_id=\"1111\"; $Domain=\".cracker.edu\"";
|
||||
|
||||
Cookie cookies[] = parseCookieHeaders(rawCookie);
|
||||
|
||||
assertThat("Cookies.length", cookies.length, is(2));
|
||||
assertCookie("Cookies[0]", cookies[0], "session_id", "1234", 1, null);
|
||||
assertCookie("Cookies[1]", cookies[1], "session_id", "1111", 1, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Example from RFC6265
|
||||
*/
|
||||
@Test
|
||||
public void testRFC6265_SidExample()
|
||||
{
|
||||
String rawCookie = "SID=31d4d96e407aad42";
|
||||
|
||||
Cookie cookies[] = parseCookieHeaders(rawCookie);
|
||||
|
||||
assertThat("Cookies.length", cookies.length, is(1));
|
||||
assertCookie("Cookies[0]", cookies[0], "SID", "31d4d96e407aad42", 0, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Example from RFC6265
|
||||
*/
|
||||
@Test
|
||||
public void testRFC6265_SidLangExample()
|
||||
{
|
||||
String rawCookie = "SID=31d4d96e407aad42; lang=en-US";
|
||||
|
||||
Cookie cookies[] = parseCookieHeaders(rawCookie);
|
||||
|
||||
assertThat("Cookies.length", cookies.length, is(2));
|
||||
assertCookie("Cookies[0]", cookies[0], "SID", "31d4d96e407aad42", 0, null);
|
||||
assertCookie("Cookies[1]", cookies[1], "lang", "en-US", 0, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic key=value, following RFC6265 rules
|
||||
*/
|
||||
@Test
|
||||
public void testKeyValue()
|
||||
{
|
||||
String rawCookie = "key=value";
|
||||
|
||||
Cookie cookies[] = parseCookieHeaders(rawCookie);
|
||||
|
||||
assertThat("Cookies.length", cookies.length, is(1));
|
||||
assertCookie("Cookies[0]", cookies[0], "key", "value", 0, null);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2017 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.server;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
||||
/**
|
||||
* Tests of poor various name=value scenarios and expectations of results
|
||||
* due to our efforts at being lenient with what we receive.
|
||||
*/
|
||||
@RunWith(Parameterized.class)
|
||||
public class CookieCutter_LenientTest
|
||||
{
|
||||
@Parameterized.Parameters(name = "{0}")
|
||||
public static List<String[]> data()
|
||||
{
|
||||
List<String[]> ret = new ArrayList<>();
|
||||
|
||||
// Simple test to verify behavior
|
||||
ret.add(new String[]{"key=value", "key", "value"});
|
||||
|
||||
// Tests that conform to RFC2109
|
||||
// RFC2109 - token values
|
||||
// token = 1*<any CHAR except CTLs or tspecials>
|
||||
// CHAR = <any US-ASCII character (octets 0 - 127)>
|
||||
// CTL = <any US-ASCII control character
|
||||
// (octets 0 - 31) and DEL (127)>
|
||||
// SP = <US-ASCII SP, space (32)>
|
||||
// HT = <US-ASCII HT, horizontal-tab (9)>
|
||||
// tspecials = "(" | ")" | "<" | ">" | "@"
|
||||
// | "," | ";" | ":" | "\" | <">
|
||||
// | "/" | "[" | "]" | "?" | "="
|
||||
// | "{" | "}" | SP | HT
|
||||
ret.add(new String[]{"abc=xyz", "abc", "xyz"});
|
||||
ret.add(new String[]{"abc=!bar", "abc", "!bar"});
|
||||
ret.add(new String[]{"abc=#hash", "abc", "#hash"});
|
||||
ret.add(new String[]{"abc=#hash", "abc", "#hash"});
|
||||
// RFC2109 - quoted-string values
|
||||
// quoted-string = ( <"> *(qdtext) <"> )
|
||||
// qdtext = <any TEXT except <">>
|
||||
// The backslash character ("\") may be used as a single-character quoting
|
||||
// mechanism only within quoted-string and comment constructs.
|
||||
// quoted-pair = "\" CHAR
|
||||
ret.add(new String[]{"abc=\"xyz\"", "abc", "xyz"});
|
||||
ret.add(new String[]{"abc=\"!bar\"", "abc", "!bar"});
|
||||
ret.add(new String[]{"abc=\"#hash\"", "abc", "#hash"});
|
||||
// RFC2109 - other valid name types that conform to 'attr'/'token' syntax
|
||||
ret.add(new String[]{"!f!o!o!=wat", "!f!o!o!", "wat"});
|
||||
ret.add(new String[]{"__MyHost=Foo", "__MyHost", "Foo"});
|
||||
ret.add(new String[]{"some-thing-else=to-parse", "some-thing-else", "to-parse"});
|
||||
// RFC2109 - names with attr/token syntax starting with '$' (and not a cookie reserved word)
|
||||
// See https://tools.ietf.org/html/draft-ietf-httpbis-cookie-prefixes-00#section-5.2
|
||||
// Cannot pass names through as Cookie class does not allow them
|
||||
ret.add(new String[]{"$foo=bar", null, null});
|
||||
|
||||
// Tests that conform to RFC6265
|
||||
ret.add(new String[]{"abc=foobar!", "abc", "foobar!"});
|
||||
ret.add(new String[]{"abc=\"foobar!\"", "abc", "foobar!"});
|
||||
|
||||
// Internal quotes
|
||||
ret.add(new String[]{"foo=bar\"baz", "foo", "bar\"baz"});
|
||||
ret.add(new String[]{"foo=\"bar\"baz\"", "foo", "bar\"baz"});
|
||||
ret.add(new String[]{"foo=\"bar\"-\"baz\"", "foo", "bar\"-\"baz"});
|
||||
ret.add(new String[]{"foo=\"bar'-\"baz\"", "foo", "bar'-\"baz"});
|
||||
ret.add(new String[]{"foo=\"bar''-\"baz\"", "foo", "bar''-\"baz"});
|
||||
// These seem dubious until you realize the "lots of equals signs" below works
|
||||
ret.add(new String[]{"foo=\"bar\"=\"baz\"", "foo", "bar\"=\"baz"});
|
||||
ret.add(new String[]{"query=\"?b=c\"&\"d=e\"", "query", "?b=c\"&\"d=e"});
|
||||
// Escaped quotes
|
||||
ret.add(new String[]{"foo=\"bar\\\"=\\\"baz\"", "foo", "bar\"=\"baz"});
|
||||
|
||||
// UTF-8 values
|
||||
ret.add(new String[]{"2sides=\u262F", "2sides", "\u262f"}); // 2 byte
|
||||
ret.add(new String[]{"currency=\"\u20AC\"", "currency", "\u20AC"}); // 3 byte
|
||||
ret.add(new String[]{"gothic=\"\uD800\uDF48\"", "gothic", "\uD800\uDF48"}); // 4 byte
|
||||
|
||||
// Lots of equals signs
|
||||
ret.add(new String[]{"query=b=c&d=e", "query", "b=c&d=e"});
|
||||
|
||||
// Escaping
|
||||
ret.add(new String[]{"query=%7B%22sessionCount%22%3A5%2C%22sessionTime%22%3A14151%7D", "query", "%7B%22sessionCount%22%3A5%2C%22sessionTime%22%3A14151%7D"});
|
||||
|
||||
// Google cookies (seen in wild, has `tspecials` of ':' in value)
|
||||
ret.add(new String[]{"GAPS=1:A1aaaAaAA1aaAAAaa1a11a:aAaaAa-aaA1-", "GAPS", "1:A1aaaAaAA1aaAAAaa1a11a:aAaaAa-aaA1-"});
|
||||
|
||||
// Strong abuse of cookie spec (lots of tspecials)
|
||||
ret.add(new String[]{"$Version=0; rToken=F_TOKEN''!--\"</a>=&{()}", "rToken", "F_TOKEN''!--\"</a>=&{()}"});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Parameterized.Parameter
|
||||
public String rawHeader;
|
||||
|
||||
@Parameterized.Parameter(1)
|
||||
public String expectedName;
|
||||
|
||||
@Parameterized.Parameter(2)
|
||||
public String expectedValue;
|
||||
|
||||
@Test
|
||||
public void testLenientBehavior()
|
||||
{
|
||||
CookieCutter cutter = new CookieCutter();
|
||||
cutter.addCookieField(rawHeader);
|
||||
Cookie[] cookies = cutter.getCookies();
|
||||
if (expectedName==null)
|
||||
assertThat("Cookies.length", cookies.length, is(0));
|
||||
else
|
||||
{
|
||||
assertThat("Cookies.length", cookies.length, is(1));
|
||||
assertThat("Cookie.name", cookies[0].getName(), is(expectedName));
|
||||
assertThat("Cookie.value", cookies[0].getValue(), is(expectedValue));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -44,7 +44,6 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
|
@ -123,9 +122,8 @@ public class RequestTest
|
|||
{
|
||||
try
|
||||
{
|
||||
Map<String, String[]> map = null;
|
||||
// do the parse
|
||||
map = request.getParameterMap();
|
||||
request.getParameterMap();
|
||||
return false;
|
||||
}
|
||||
catch(BadMessageException e)
|
||||
|
@ -952,7 +950,7 @@ public class RequestTest
|
|||
_server.setHandler(handler);
|
||||
_server.start();
|
||||
|
||||
String request="GET / HTTP/1.1\r\n"+
|
||||
String requests="GET / HTTP/1.1\r\n"+
|
||||
"Host: whatever\r\n"+
|
||||
"Content-Type: text/plane\r\n"+
|
||||
"Content-Length: "+10+"\r\n"+
|
||||
|
@ -966,7 +964,9 @@ public class RequestTest
|
|||
"\r\n"+
|
||||
"ABCDEFGHIJ\r\n";
|
||||
|
||||
String responses = _connector.getResponses(request);
|
||||
|
||||
LocalEndPoint endp = _connector.executeRequest(requests);
|
||||
String responses = endp.getResponse() + endp.getResponse();
|
||||
|
||||
int index=responses.indexOf("read="+(int)'0');
|
||||
assertTrue(index>0);
|
||||
|
@ -1240,14 +1240,14 @@ public class RequestTest
|
|||
response=_connector.getResponse(
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: whatever\n"+
|
||||
"Cookie: name=quoted=\"\\\"value\\\"\"\n" +
|
||||
"Cookie: name=quoted=\"\\\"badly\\\"\"\n" +
|
||||
"Connection: close\n"+
|
||||
"\n"
|
||||
);
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertEquals(1,cookies.size());
|
||||
assertEquals("name", cookies.get(0).getName());
|
||||
assertEquals("quoted=\"value\"", cookies.get(0).getValue());
|
||||
assertEquals("quoted=\"\\\"badly\\\"\"", cookies.get(0).getValue());
|
||||
|
||||
cookies.clear();
|
||||
response=_connector.getResponse(
|
||||
|
@ -1325,7 +1325,7 @@ public class RequestTest
|
|||
response=_connector.getResponse(
|
||||
"POST / HTTP/1.1\r\n"+
|
||||
"Host: whatever\r\n"+
|
||||
"Cookie: name0=value0; name1 = value1 ; \"name2\" = \"\\\"value2\\\"\" \n" +
|
||||
"Cookie: name0=value0; name1 = value1 ; name2 = \"\\\"value2\\\"\" \n" +
|
||||
"Cookie: $Version=2; name3=value3=value3;$path=/path;$domain=acme.com;$port=8080; name4=; name5 = ; name6\n" +
|
||||
"Cookie: name7=value7;\n" +
|
||||
"Connection: close\r\n"+
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<version>9.4.5-SNAPSHOT</version>
|
||||
<version>9.4.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-servlet</artifactId>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue