Giter Site home page Giter Site logo

winstone's Introduction

What is Winstone?

Winstone is a command line interface around Jetty 10.0.x, which implements Servlet 4.0 (JakartaEE 8/javax.servlet.*), WebSocket/JSR-356, and HTTP/2 support. It is used as the default embedded servlet container in Jenkins (via the executable package in the war module) and can be used by any other web applications that wants to be self-contained.

History

Winstone was originally a from-scratch servlet container by Rick Knowles with a good command line interface. Over time, the upstream development has halted, and it became impractical to maintain a from-scratch servlet implementation on our own. To reduce this maintenance burden, the gut of Winstone has been removed and delegated to Jetty, while CLI was preserved, and we called it Winstone 2.0.

License

The license of Winstone inherits its original license by Rick.

The Web-App DTD files (everything in the src/javax/servlet/resources and src/javax/servlet/jsp/resources folders) are covered by the licenses described at the top of each file (usually as licensed by Sun Microsystems).

As of v0.8.1, all other files are dual-licensed, under either the Lesser GNU Public License (LGPL) as described in LICENSE-LGPL.txt, or the Common Development and Distribution License (CDDL) as described in LICENSE-CDDL.txt.

The goal of dual-licensing is to make Winstone as attractive as possible to distributors of commercial webapps, while ensuring everyone benefits from any improvements. The CDDL allows free distribution with any commercial applications, while distribution with a GPL licensed webapp is also possible under the LGPL. If you are unclear about which license applies to an application you wish to distribute or sell, please contact me.

Using Winstone

To run a single war file:

java -jar winstone.jar --warfile=<location of warfile> (+ other options)

To run a directory full of war files:

java -jar winstone.jar --webappsDir=<location of webapps directory> (+ other options)

To run locally exploded web archive:

java -jar winstone.jar --webroot=<location of webroot> (+ other options)

To run different web applications for diffent virtual hosts:

java -jar winstone.jar --hostsDir=<location of hosts directory> (+ other options)

Command-line options

Winstone Servlet Engine, (c) 2003-2006 Rick Knowles
Usage: java winstone.jar [--option=value] [--option=value] [etc]

Required options: either --webroot OR --warfile OR --webappsDir OR --hostsDir
   --webroot                = set document root folder.
   --warfile                = set location of warfile to extract from.
   --webappsDir             = set directory for multiple webapps to be deployed from
Other options:
   --javaHome               = Override the JAVA_HOME variable
   --config                 = load configuration properties from here. Default is ./winstone.properties
   --prefix                 = add this prefix to all URLs (eg http://localhost:8080/prefix/resource). Default is none
   --commonLibFolder        = folder for additional jar files. Default is ./lib

   --extraLibFolder         = folder for additional jar files to add to Jetty classloader

   --logfile                = redirect log messages to this file
   --logThrowingLineNo      = show the line no that logged the message (slow). Default is false
   --logThrowingThread      = show the thread that logged the message. Default is false
   --debug                  = set the level of Winstone debug msgs (1-9). Default is 5 (INFO level)

   --httpPort               = set the http listening port. -1 to disable, Default is 8080
   --httpListenAddress      = set the http listening address. Default is all interfaces
   --httpUnixDomainPath     = set the http unix domain path. Default is no path
   --httpKeepAliveTimeout   = how long idle HTTP keep-alive connections are kept around (in ms; default 30000)?
   --httpsPort              = set the https listening port. -1 to disable, Default is disabled
   --httpsListenAddress     = set the https listening address. Default is all interfaces
   --httpsKeepAliveTimeout  = how long idle HTTPS keep-alive connections are kept around (in ms; default 30000)?
   --httpsKeyStore          = the location of the SSL KeyStore file. Default is ./winstone.ks
   --httpsKeyStorePassword  = the password for the SSL KeyStore file. Default is null
   --httpsKeyManagerType    = the SSL KeyManagerFactory type (eg SunX509, IbmX509). Default is SunX509
   --httpsRedirectHttp      = redirect http requests to https (requires both --httpPort and --httpsPort)
   --http2Port              = set the http2 listening port. -1 to disable, Default is disabled
   --httpsSniHostCheck      = if the SNI Host name must match when there is an SNI certificate. Check disabled per default
   --httpsSniRequired       = if a SNI certificate is required. Disabled per default
   --http2ListenAddress     = set the http2 listening address. Default is all interfaces
   --excludeProtocols       = set protocol versions to exclude. (comma separated list, use blank quote " " to exclude none)
                              (default is "SSL", "SSLv2", "SSLv2Hello", "SSLv3")
   --excludeCipherSuites    = set the ciphers to exclude (comma separated, use blank quote " " to exclude none) (default is 
                           // Exclude weak / insecure ciphers 
                           "^.*_(MD5|SHA|SHA1)$", 
                           // Exclude ciphers that don't support forward secrecy 
                           "^TLS_RSA_.*$", 
                           // The following exclusions are present to cleanup known bad cipher 
                           // suites that may be accidentally included via include patterns. 
                           // The default enabled cipher list in Java will not include these 
                           // (but they are available in the supported list). 
                           "^SSL_.*$", 
                           "^.*_NULL_.*$", 
                           "^.*_anon_.*$" 
   --controlPort            = set the shutdown/control port. -1 to disable, Default disabled

   --sessionTimeout         = set the http session timeout value in minutes. Default to what webapp specifies, and then to 60 minutes
   --sessionEviction        = set the session eviction timeout for idle sessions in seconds. Default value is 180. -1 never evict, 0 evict on exit
   --mimeTypes=ARG          = define additional MIME type mappings. ARG would be EXT=MIMETYPE:EXT=MIMETYPE:...
                              (e.g., xls=application/vnd.ms-excel:wmf=application/x-msmetafile)
   --requestHeaderSize=N    = set the maximum size in bytes of the request header. Default is 8192.
   --responseHeaderSize=N   = set the maximum size in bytes of the response header. Default is 8192.
   --maxParamCount=N        = set the max number of parameters allowed in a form submission to protect
                              against hash DoS attack (oCERT #2011-003). Default is 10000.
   --useJmx                 = Enable Jetty Jmx
   --qtpMaxThreadsCount     = max threads number when using Jetty Queued Thread Pool
   --jettyAcceptorsCount    = Jetty Acceptors number
   --jettySelectorsCount    = Jetty Selectors number
   --usage / --help         = show this message
 Security options:
   --realmClassName               = Set the realm class to use for user authentication. Defaults to ArgumentsRealm class

   --argumentsRealm.passwd.<user> = Password for user <user>. Only valid for the ArgumentsRealm realm class
   --argumentsRealm.roles.<user>  = Roles for user <user> (comma separated). Only valid for the ArgumentsRealm realm class

   --fileRealm.configFile         = File containing users/passwds/roles. Only valid for the FileRealm realm class

 Access logging:
   --accessLoggerClassName        = Set the access logger class to use for user authentication. Defaults to disabled
   --simpleAccessLogger.format    = The log format to use. Supports combined/common/resin/custom (SimpleAccessLogger only)
   --simpleAccessLogger.file      = The location pattern for the log file(SimpleAccessLogger only)

Configuration file

You don't really need a config file, but sometimes it's handy to be able to use the same settings each time without running through the command history.

Winstone looks for a config file winstone.properties in the current directory (or in the location specified with --config) at startup. It loads the properties in this file, overrides them with any supplied command line properties, and then starts itself.

This is just intended as a handy feature for people who want to cache regular startup options, rather than using batch files.

Deployment choices

The simplest way to use winstone is with a single webapp. To do this, just supply the warfile or webroot directory as an argument:

  • java -jar winstone.jar <webroot or warfile>, (this method auto-detects the type) or
  • java -jar winstone.jar --webroot=<webroot>, or
  • java -jar winstone.jar --warfile=<warfile>

If you need to support multiple webapps, use the --webappsDir switch, to which you pass a directory that contains multiple warfiles/webroots.

  • java -jar winstone.jar --webappsDir=<dir containing multiple webroots>

The directory becomes the prefix name for that webapp (so hello becomes /hello, etc). The directory named ROOT becomes the no-prefix webapp.

So, for example, if you had a directory /usr/local/webapps which contained sub-directories ROOT and test, if you executed java -jar winstone.jar --webappsDir=/usr/local/webapps, you would find that the test folder would act as a webroot for requests prefixed with /test, while other requests would go to the webapp in the ROOT folder

If you need multiple hosts (sometimes called name-based virtual hosting), there is an option --hostsDir. This acts in a similar way to the --webappsDir switch, but it defines an extra level of sub-directories, the top being a per-host directory and the second a per-webapp directory as with --webappsDir.

The directory name becomes the host name: that is, a directory named www.blah.com will only serve requests with the host header www.blah.com, unless it is the default host. If a directory named "default" is found, it becomes the default host. If no default directory is found, the first directory in the list (alphabetically) becomes the default host.

  • java -jar winstone.jar --hostsDir=<dir containing multiple host directories>

Development

If you have some unit test failures you may add an interface/ip alias such

sudo ifconfig lo0 alias 127.0.0.2

Changelog

See GitHub releases, or for older versions this page.

winstone's People

Contributors

basil avatar christ66 avatar coco80021 avatar daniel-beck avatar dependabot-preview[bot] avatar dependabot[bot] avatar huggsboson avatar jdsn avatar jglick avatar jlleitschuh avatar jtnord avatar klaussilveira avatar kohsuke avatar lloydchang avatar lrpg avatar markewaite avatar mawinter69 avatar minfrin avatar ndeloof avatar olamy avatar oleg-nenashev avatar pascalschumacher avatar res0nance avatar rutgerva avatar stephenc avatar timja avatar torstens73 avatar vin01 avatar vlad-m-r avatar vlatombe avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

winstone's Issues

`FormSubmissionTest#largeForm` is flaky

Jenkins and plugins versions report

Environment
Paste the output here

What Operating System are you using (both controller, and any agents involved in the problem)?

Ubuntu 22.04.1 LTS x86_64

Reproduction steps

Run FormSubmissionTest#largeForm in a loop.

Expected Results

The test consistently passes.

Actual Results

Observed in build #307 and when running FormSubmissionTest#largeForm in a loop locally: the test occasionally flakes with "HTTP/1.1 header parser received no bytes" and the following stack trace:

java.io.IOException: HTTP/1.1 header parser received no bytes
	at java.net.http/jdk.internal.net.http.HttpClientImpl.send(HttpClientImpl.java:565)
	at java.net.http/jdk.internal.net.http.HttpClientFacade.send(HttpClientFacade.java:119)
	at winstone.FormSubmissionTest.largeForm(FormSubmissionTest.java:38)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
	at org.junit.vintage.engine.execution.RunnerExecutor.execute(RunnerExecutor.java:42)
	at org.junit.vintage.engine.VintageTestEngine.executeAllChildren(VintageTestEngine.java:80)
	at org.junit.vintage.engine.VintageTestEngine.execute(VintageTestEngine.java:72)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:147)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:127)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:90)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:55)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:102)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.apache.maven.surefire.junitplatform.LazyLauncher.execute(LazyLauncher.java:55)
	at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:223)
	at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:175)
	at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:135)
	at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:456)
	at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:169)
	at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:595)
	at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:581)
Caused by: java.io.IOException: HTTP/1.1 header parser received no bytes
	at java.net.http/jdk.internal.net.http.common.Utils.wrapWithExtraDetail(Utils.java:303)
	at java.net.http/jdk.internal.net.http.Http1Response$HeadersReader.onReadError(Http1Response.java:673)
	at java.net.http/jdk.internal.net.http.Http1AsyncReceiver.checkForErrors(Http1AsyncReceiver.java:297)
	at java.net.http/jdk.internal.net.http.Http1AsyncReceiver.flush(Http1AsyncReceiver.java:263)
	at java.net.http/jdk.internal.net.http.common.SequentialScheduler$SynchronizedRestartableTask.run(SequentialScheduler.java:175)
	at java.net.http/jdk.internal.net.http.common.SequentialScheduler$CompleteRestartableTask.run(SequentialScheduler.java:147)
	at java.net.http/jdk.internal.net.http.common.SequentialScheduler$SchedulableTask.run(SequentialScheduler.java:198)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: java.io.IOException: An established connection was aborted by the software in your host machine
	at java.base/sun.nio.ch.SocketDispatcher.read0(Native Method)
	at java.base/sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:43)
	at java.base/sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:276)
	at java.base/sun.nio.ch.IOUtil.read(IOUtil.java:245)
	at java.base/sun.nio.ch.IOUtil.read(IOUtil.java:223)
	at java.base/sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:356)
	at java.net.http/jdk.internal.net.http.SocketTube.readAvailable(SocketTube.java:1153)
	at java.net.http/jdk.internal.net.http.SocketTube$InternalReadPublisher$InternalReadSubscription.read(SocketTube.java:821)
	at java.net.http/jdk.internal.net.http.SocketTube$SocketFlowTask.run(SocketTube.java:175)
	at java.net.http/jdk.internal.net.http.common.SequentialScheduler$SchedulableTask.run(SequentialScheduler.java:198)
	at java.net.http/jdk.internal.net.http.common.SequentialScheduler.runOrSchedule(SequentialScheduler.java:271)
	at java.net.http/jdk.internal.net.http.common.SequentialScheduler.runOrSchedule(SequentialScheduler.java:224)
	at java.net.http/jdk.internal.net.http.SocketTube$InternalReadPublisher$InternalReadSubscription.signalReadable(SocketTube.java:763)
	at java.net.http/jdk.internal.net.http.SocketTube$InternalReadPublisher$ReadEvent.signalEvent(SocketTube.java:941)
	at java.net.http/jdk.internal.net.http.SocketTube$SocketFlowEvent.handle(SocketTube.java:245)
	at java.net.http/jdk.internal.net.http.HttpClientImpl$SelectorManager.handleEvent(HttpClientImpl.java:957)
	at java.net.http/jdk.internal.net.http.HttpClientImpl$SelectorManager.lambda$run$3(HttpClientImpl.java:912)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
	at java.net.http/jdk.internal.net.http.HttpClientImpl$SelectorManager.run(HttpClientImpl.java:912)

Anything else?

I usually see the flake at least once per 500 test invocations; sometimes as early as the first dozen invocations.

Expose setExcludeProtocols as a CLI option

What feature do you want to see added?

The list of disabled SSL(TLS) protocol versions is currently hard-coded as
"SSLv3", "SSLv2", "SSLv2Hello"

It would be nice to have this as a configurable option, for example to disable TLSv1.2 to have only TLS 1.3 enabled

Upstream changes

No response

Logging facilities not available during application shutdown process

Jenkins and plugins versions report

Jenkins 2.343

What Operating System are you using (both controller, and any agents involved in the problem)?

Ubuntu 20.04.4 LTS x86_64

Reproduction steps

  1. Download Jenkins 2.343 or later.
  2. Run java -jar war/target/jenkins.war.
  3. Press Control-C.

Expected Results

The application shutdown process prints the following logs:

2022-04-12 16:55:59.703+0000 [id=26]    INFO    winstone.Logger#logInternal: JVM is terminating. Shutting down Jetty
2022-04-12 16:55:59.710+0000 [id=26]    INFO    o.e.j.server.AbstractConnector#doStop: Stopped ServerConnector@6cd24612{HTTP/1.1, (http/1.1)}{0.0.0.0:8080}
2022-04-12 16:55:59.710+0000 [id=26]    INFO    o.e.j.server.session.HouseKeeper#stopScavenging: node0 Stopped scavenging
2022-04-12 16:55:59.711+0000 [id=26]    INFO    hudson.lifecycle.Lifecycle#onStatusUpdate: Stopping Jenkins
2022-04-12 16:55:59.714+0000 [id=26]    INFO    jenkins.model.Jenkins$16#onAttained: Started termination
2022-04-12 16:55:59.720+0000 [id=26]    INFO    jenkins.model.Jenkins$16#onAttained: Completed termination
2022-04-12 16:55:59.720+0000 [id=26]    INFO    jenkins.model.Jenkins#_cleanUpDisconnectComputers: Starting node disconnection
2022-04-12 16:55:59.723+0000 [id=26]    INFO    jenkins.model.Jenkins#_cleanUpShutdownPluginManager: Stopping plugin manager
2022-04-12 16:55:59.725+0000 [id=26]    INFO    jenkins.model.Jenkins#_cleanUpPersistQueue: Persisting build queue
2022-04-12 16:55:59.737+0000 [id=26]    INFO    jenkins.model.Jenkins#_cleanUpAwaitDisconnects: Waiting for node disconnection completion
2022-04-12 16:55:59.737+0000 [id=26]    INFO    hudson.lifecycle.Lifecycle#onStatusUpdate: Jenkins stopped
2022-04-12 16:55:59.738+0000 [id=26]    INFO    o.e.j.s.handler.ContextHandler#doStop: Stopped w.@652ab8d9{Jenkins v2.344-SNAPSHOT,/,null,STOPPED}{/home/basil/.jenkins/war}

Actual Results

The application shutdown process does not print any logs:

2022-04-12 16:57:31.176+0000 [id=32]    INFO    hudson.lifecycle.Lifecycle#onStatusUpdate: Stopping Jenkins
2022-04-12 16:57:31.176+0000 [id=26]    INFO    winstone.Logger#logInternal: JVM is terminating. Shutting down Jetty

Anything else?

As described in JDK-8161253, there is no way to control the order of execution of shutdown hooks. When the LogManager#Cleaner shutdown hook runs before Winstone's shutdown hook, it shuts down logging facilities. Logging facilities are subsequently unavailable to the application shutdown process, which is invoked from Winstone's shutdown hook.

In the comments to JDK-8161253, Jason Mehrens suggests a workaround: creating a custom log handler and installing it on the root logger before all other log handlers. Since the first action of LogManager#Cleaner is to close all the installed log handlers on the root logger, it will invoke the custom log handler's close() method. At this point, the custom log handler has intercepted control and can delay shutdown of logging facilities until the application has completed its shutdown process.

The following patch implements this workaround:

diff --git a/src/main/java/winstone/Launcher.java b/src/main/java/winstone/Launcher.java
index 843ec11..5522270 100644
--- a/src/main/java/winstone/Launcher.java
+++ b/src/main/java/winstone/Launcher.java
@@ -42,9 +42,11 @@ import java.nio.file.StandardOpenOption;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.logging.ConsoleHandler;
 import java.util.logging.Handler;
 import java.util.logging.Level;
+import java.util.logging.LogRecord;
 
 /**
  * Implements the main launcher daemon thread. This is the class that gets
@@ -74,12 +76,44 @@ public class Launcher implements Runnable {
 
     public final Server server;
 
+    private boolean shutdownComplete;
+
     /**
      * Constructor - initialises the web app, object pools, control port and the
      * available protocol listeners.
      */
     public Launcher(Map<String, String> args) throws IOException {
         boolean success=false;
+        /*
+         * As described in JDK-8161253, there is no way to control the order of execution of
+         * shutdown hooks. When LogManager#Cleaner runs before our custom shutdown hook, logging
+         * facilities are not available to the application shutdown process. In the comments to
+         * JDK-8161253, Jason Mehrens suggests a workaround: creating a custom log handler and
+         * installing it on the root logger before all other log handlers. Since the first action of
+         * LogManager#Cleaner is to close all the installed log handlers on the root logger, it will
+         * invoke the custom log handler's close() method. At this point, we have intercepted
+         * control and can delay shutdown of logging facilities until the application has completed
+         * its shutdown process.
+         *
+         * The installLogHandler() method implements the above workaround, which creates an
+         * obligation to notify the custom log handler, via the Launcher#shutdown() method, that the
+         * application shutdown process is complete and logging facilities may be shut down.
+         *
+         * - In the case of successful launch, we execute the finally portion of the try/finally
+         *   block below, which does not call Launcher#shutdown() in the success case, then we
+         *   install the shutdown hook, then when the user terminates the application the shutdown
+         *   hook shuts down the application, then the shutdown hook calls Launcher#shutdown(), then
+         *   finally the custom log handler is notified.
+         *
+         * - In the case of unsuccessful launch, we execute the finally portion of the try/finally
+         *   block below, which calls Launcher#shutdown() in the failure case, which then notifies
+         *   the custom log handler.
+         *
+         * In either case the obligation is fulfilled and the custom log handler is notified of
+         * application shutdown, at which point it proceeds to shut down logging facilities as the
+         * last action prior to process termination.
+         */
+        installLogHandler();
         try {
             Logger.log(Logger.MAX, RESOURCES, "Launcher.StartupArgs", args + "");
 
@@ -220,6 +254,60 @@ public class Launcher implements Runnable {
         Runtime.getRuntime().addShutdownHook(new ShutdownHook(this));
     }
 
+    private boolean isShutdownComplete() {
+        return shutdownComplete;
+    }
+
+    /**
+     * Install our custom log handler that waits for application shutdown to complete before
+     * running.
+     */
+    private void installLogHandler() {
+        java.util.logging.Logger root = java.util.logging.Logger.getLogger("");
+        /*
+         * By installing our custom log handler before all others, we ensure that logging facilities
+         * are available during the application shutdown process.
+         */
+        Handler[] handlers = root.getHandlers();
+        for (Handler h : handlers) {
+            root.removeHandler(h);
+        }
+        root.addHandler(new LogHandler(this));
+        for (Handler h : handlers) {
+            root.addHandler(h);
+        }
+    }
+
+    /**
+     * Custom log handler that waits for application shutdown to complete before running.
+     */
+    private static class LogHandler extends Handler {
+        private final Launcher launcher;
+
+        LogHandler(Launcher launcher) {
+            this.launcher = Objects.requireNonNull(launcher);
+        }
+
+        @Override
+        public void publish(LogRecord record) {}
+
+        @Override
+        public void flush() {}
+
+        @Override
+        public void close() {
+            try {
+                synchronized (launcher) {
+                    while (!launcher.isShutdownComplete()) {
+                        launcher.wait();
+                    }
+                }
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+            }
+        }
+    }
+
     private void writePortToFileIfNeeded() throws IOException {
         String portFileName = System.getProperty(WINSTONE_PORT_FILE_NAME_PROPERTY);
         if (portFileName != null) {
@@ -355,6 +443,10 @@ public class Launcher implements Runnable {
         } catch (Exception e) {
             Logger.log(Logger.INFO, RESOURCES, "Launcher.FailedShutdown", e);
         }
+        synchronized (this) {
+            shutdownComplete = true;
+            notifyAll();
+        }
 
         if (this.controlThread != null) {
             this.controlThread.interrupt();

EOL `commonLibCLPaths`

Jenkins and plugins versions report

Environment
Paste the output here

What Operating System are you using (both controller, and any agents involved in the problem)?

Winstone 5.22
Jenkins 2.334
Ubuntu 20.04.3 LTS x86_64

Reproduction steps

Run git grep -i commonLibCLPaths.

Expected Results

The search returns zero results.

Actual Results

The search returns a nonzero number of results.

Anything else?

I could find no references to commonLibCLPaths anywhere in the Jenkins ecosystem. In this repository, we populate commonLibCLPaths without ever consuming it, so it is dead code. There are no usages HostConfiguration or HostGroup outside of this repository, either. This dead code seems best left in the rear-view mirror. My suggestion is to remove all references to commonLibCLPaths from this repository.

Support for adjusting permissions on the UNIX domain socket

What feature do you want to see added?

When using a UNIX-domain socket, it’s useful to be able to control access permissions. For example, I want Apache (running as the www-data user) to be able to connect to Jenkins (running under the jenkins user and jenkins group). Since nothing special is done when creating the UNIX-domain socket, with Jenkins running under a typical 0022 umask, I end up with a socket owned by jenkins:jenkins and mode 0755, which Apache can’t connect to (under Linux, you have to have write permission on a socket to connect to it). It would be useful if we could control the file permissions, or ideally even better also the owning group, of the socket. Barring that, just opening the permissions to be writeable by all would be sufficient, since one can also just put tighter controls on a containing directory. But it’s not possible to broaden the permissions using a containing directory, which means AFAICT right now the only options are to (1) run the frontend HTTP server under the jenkins user (which is obviously bad for security) (2) change Jenkins’s umask to 0002 (which is probably bad for security too), or (3) set up some kind of weird service dependency thing to chmod or chgrp the socket file after Jenkins starts up (which is probably really hard to get right in the face of Jenkins restarting itself and presumably recreating the socket file when doing so).

#211 would also fix this nicely since systemd has a fairly rich language for setting file permissions on sockets.

Upstream changes

No response

Are you interested in contributing this feature?

No response

`winstone.realm.FileRealm` subject to XML external entity injection (XXE)

Jenkins and plugins versions report

Winstone 5.23
Jenkins 2.334

What Operating System are you using (both controller, and any agents involved in the problem)?

Ubuntu 20.04.3 LTS x86_64

Reproduction steps

Create a users.xml with, say

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE lolz [
 <!ENTITY lol "lol">
 <!ELEMENT lolz (#PCDATA)>
 <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
 <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
 <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
 <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
 <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
 <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
 <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
 <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
 <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<users>
  <role rolename="admin-gui"/>
  <role rolename="admin-script"/>
  <role rolename="manager-gui"/>
  <role rolename="manager-status"/>
  <role rolename="manager-script"/>
  <role rolename="manager-jmx"/>
  <user name="admin" password="admin" roles="admin-gui,admin-script,manager-gui,manager-status,manager-script,manager-jmx"/>
  <lolz>&lol9;</lolz>
</users>

then run Jenkins with java -jar jenkins.war --realmClassName=winstone.realm.FileRealm --fileRealm.configFile=users.xml.

Expected Results

Jenkins should not attempt to process the XML external entities, failing to start with an error like the following:

$ java -jar jenkins.war --realmClassName=winstone.realm.FileRealm --fileRealm.configFile=users.xml
[…]
[Fatal Error] :2:10: DOCTYPE is disallowed when the feature "http://apache.org/xml/features/disallow-doctype-decl" set to true.
2022-02-10 16:58:33.428+0000 [id=1]     INFO    winstone.Logger#logInternal: Jetty shutdown successfully
java.io.IOException: Failed to setup authentication realm
        at winstone.HostConfiguration.<init>(HostConfiguration.java:71)
        at winstone.HostGroup.initHost(HostGroup.java:66)
        at winstone.HostGroup.<init>(HostGroup.java:45)
        at winstone.Launcher.<init>(Launcher.java:180)
        at winstone.Launcher.main(Launcher.java:376)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at Main._main(Main.java:304)
        at Main.main(Main.java:108)
Caused by: java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
        at winstone.HostConfiguration.<init>(HostConfiguration.java:69)
        ... 10 more
Caused by: winstone.WinstoneException: Error parsing the users XML document
        at winstone.realm.FileRealm.parseStreamToXML(FileRealm.java:128)
        at winstone.realm.FileRealm.<init>(FileRealm.java:59)
        ... 15 more
Caused by: org.xml.sax.SAXParseException; lineNumber: 2; columnNumber: 10; DOCTYPE is disallowed when the feature "http://apache.org/xml/features/disallow-doctype-decl" set to true.
        at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:257)
        at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:339)
        at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:121)
        at winstone.realm.FileRealm.parseStreamToXML(FileRealm.java:125)
        ... 16 more
2022-02-10 16:58:33.429+0000 [id=1]     SEVERE  winstone.Logger#logInternal: Container startup failed
org.xml.sax.SAXParseException; lineNumber: 2; columnNumber: 10; DOCTYPE is disallowed when the feature "http://apache.org/xml/features/disallow-doctype-decl" set to true.
        at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:257)
        at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:339)
        at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:121)
        at winstone.realm.FileRealm.parseStreamToXML(FileRealm.java:125)
Caused: winstone.WinstoneException: Error parsing the users XML document
        at winstone.realm.FileRealm.parseStreamToXML(FileRealm.java:128)
        at winstone.realm.FileRealm.<init>(FileRealm.java:59)
Caused: java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
        at winstone.HostConfiguration.<init>(HostConfiguration.java:69)
Caused: java.io.IOException: Failed to setup authentication realm
        at winstone.HostConfiguration.<init>(HostConfiguration.java:71)
        at winstone.HostGroup.initHost(HostGroup.java:66)
        at winstone.HostGroup.<init>(HostGroup.java:45)
        at winstone.Launcher.<init>(Launcher.java:180)
        at winstone.Launcher.main(Launcher.java:376)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at Main._main(Main.java:304)
        at Main.main(Main.java:108)

Actual Results

Jenkins attempts to process the XML external entities, failing to start with an error like the following:

$ java -jar jenkins.war --realmClassName=winstone.realm.FileRealm --fileRealm.configFile=users.xml
[…]
[Fatal Error] :1:1: JAXP00010001: The parser has encountered more than "64000" entity expansions in this document; this is the limit imposed by the JDK.
2022-02-10 16:50:32.904+0000 [id=1]     INFO    winstone.Logger#logInternal: Jetty shutdown successfully
java.io.IOException: Failed to setup authentication realm
        at winstone.HostConfiguration.<init>(HostConfiguration.java:71)
        at winstone.HostGroup.initHost(HostGroup.java:66)
        at winstone.HostGroup.<init>(HostGroup.java:45)
        at winstone.Launcher.<init>(Launcher.java:180)
        at winstone.Launcher.main(Launcher.java:376)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at Main._main(Main.java:304)
        at Main.main(Main.java:108)
Caused by: java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
        at winstone.HostConfiguration.<init>(HostConfiguration.java:69)
        ... 10 more
Caused by: winstone.WinstoneException: Error parsing the users XML document
        at winstone.realm.FileRealm.parseStreamToXML(FileRealm.java:124)
        at winstone.realm.FileRealm.<init>(FileRealm.java:58)
        ... 15 more
Caused by: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; JAXP00010001: The parser has encountered more than "64000" entity expansions in this document; this is the limit imposed by the JDK.
        at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:257)
        at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:339)
        at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:121)
        at winstone.realm.FileRealm.parseStreamToXML(FileRealm.java:121)
        ... 16 more
2022-02-10 16:50:32.905+0000 [id=1]     SEVERE  winstone.Logger#logInternal: Container startup failed
org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; JAXP00010001: The parser has encountered more than "64000" entity expansions in this document; this is the limit imposed by the JDK.
        at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:257)
        at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:339)
        at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:121)
        at winstone.realm.FileRealm.parseStreamToXML(FileRealm.java:121)
Caused: winstone.WinstoneException: Error parsing the users XML document
        at winstone.realm.FileRealm.parseStreamToXML(FileRealm.java:124)
        at winstone.realm.FileRealm.<init>(FileRealm.java:58)
Caused: java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
        at winstone.HostConfiguration.<init>(HostConfiguration.java:69)
Caused: java.io.IOException: Failed to setup authentication realm
        at winstone.HostConfiguration.<init>(HostConfiguration.java:71)
        at winstone.HostGroup.initHost(HostGroup.java:66)
        at winstone.HostGroup.<init>(HostGroup.java:45)
        at winstone.Launcher.<init>(Launcher.java:180)
        at winstone.Launcher.main(Launcher.java:376)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at Main._main(Main.java:304)
        at Main.main(Main.java:108)

Anything else?

There is no security issue here. For a user to be able to exploit this, they would have to be able to control the arguments to the Jenkins Java process, at which point they could just as easily take down service by e.g. passing in an invalid argument or giving themselves access to an administrative account.

I confirmed with the Security Team that this issue can be discussed in a public forum in SECURITY-2609 prior to raising this issue.

Suggest the following patch:

diff --git a/src/main/java/winstone/realm/FileRealm.java b/src/main/java/winstone/realm/FileRealm.java
index 64e1e14..b5b7904 100644
--- a/src/main/java/winstone/realm/FileRealm.java
+++ b/src/main/java/winstone/realm/FileRealm.java
@@ -16,6 +16,7 @@ import winstone.WinstoneException;
 import winstone.WinstoneResourceBundle;
 import winstone.cmdline.Option;
 
+import javax.xml.XMLConstants;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import java.io.File;
@@ -111,6 +112,9 @@ public class FileRealm extends HashLoginService {
         try {
             // Use JAXP to create a document builder
             DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+            factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+            factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+            factory.setXIncludeAware(false);
             factory.setExpandEntityReferences(false);
             factory.setValidating(false);
             factory.setNamespaceAware(false);

Winstone uses deprecated `git://` protocol

Jenkins and plugins versions report

Jenkins: 2.339
OS: Ubuntu 20.04.4 LTS x86_64

What Operating System are you using (both controller, and any agents involved in the problem)?

Linux

Reproduction steps

Run git grep 'git:\/\/' in this repository.

Expected Results

No usages of the deprecated git:// protocol should be found.

Actual Results

A usage of the deprecated git:// protocol is found:

$ git grep 'git:\/\/'
pom.xml:    <connection>scm:git:git://github.com/${gitHubRepo}.git</connection>

Anything else?

From Improving Git protocol security on GitHub:

If any [URLs] start with git://, you should change the URL to a supported format.

I suggest changing the URL to the non-deprecated version:

<connection>scm:git:https://github.com/${gitHubRepo}.git</connection>

Is PUT supported on Winstone? I receive a 405 when sending requests

Jenkins and plugins versions report

Environment
Paste the output here

What Operating System are you using (both controller, and any agents involved in the problem)?

Ubuntu/JDK17

Reproduction steps

Use RestAssured to send a PUT Request with JSON body to winstone

Expected Results

Statuscode 2xx

Actual Results

Statuscode 405

Anything else?

No response

allow optional clientauth certificate

What feature do you want to see added?

We have a plugin in Jenkins that allows us to login to Jenkins by reading the user from a client certificate, which is very convenient in our environment. We run Jenkins with tomcat where you can configure that a client certificate is optional. So when we access Jenkins via browser, the certificate is sent and we're automatically logged in, but also accessing the REST api with user/token works very well.
Currently there is the option --httpsVerifyClient which is a boolean. true means the client must always include a certificate, which makes it hard access the rest api with curl, false means a client certificate is never requested.
So it would be nice to have --httpsVerifyClient support three value: true, false and optional
Jetty supports optional client certificates via ssl.setWantClientAuth(true);

Upstream changes

No response

Cannot read OpenSSL-style PEM-encoded RSA private key on Java 17

Jenkins and plugins versions report

Apache Maven 3.8.4 (9b656c72d54e5bacbed989b64718c159fe39b537)
Java version: 17.0.2, vendor: Private Build, runtime: /usr/lib/jvm/java-17-openjdk-amd64
OS name: "linux", version: "5.4.0-104-generic", arch: "amd64", family: "unix"

What Operating System are you using (both controller, and any agents involved in the problem)?

Ubuntu 20.04.4 LTS x86_64

Reproduction steps

Run mvn clean verify -Dtest=winstone.HttpsConnectorFactoryTest with Java 17.

Expected Results

Note: These are the actual results when running with Java 8 or Java 11.

The test passes.

Actual Results

The test fails with

[ERROR] Tests run: 3, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.77 s <<< FAILURE! - in winstone.HttpsConnectorFactoryTest
[ERROR] testHttps(winstone.HttpsConnectorFactoryTest)  Time elapsed: 0.255 s  <<< ERROR!
java.io.IOException: Failed to start a listener: winstone.HttpsConnectorFactory
        at winstone.Launcher.spawnListener(Launcher.java:261)
        at winstone.Launcher.<init>(Launcher.java:190)
        at winstone.HttpsConnectorFactoryTest.testHttps(HttpsConnectorFactoryTest.java:42)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:568)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
        at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
        at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
        at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
        at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
        at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
        at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
        at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:365)
        at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:273)
        at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:238)
        at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:159)
        at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:384)
        at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:345)
        at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:126)
        at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:418)
Caused by: winstone.WinstoneException: Cannot load private key; try using a Java keystore instead.
        at winstone.AbstractSecuredConnectorFactory.readPEMRSAPrivateKey(AbstractSecuredConnectorFactory.java:127)
        at winstone.AbstractSecuredConnectorFactory.configureSsl(AbstractSecuredConnectorFactory.java:80)
        at winstone.HttpsConnectorFactory.start(HttpsConnectorFactory.java:54)
        at winstone.Launcher.spawnListener(Launcher.java:255)
        ... 31 more
Caused by: java.lang.IllegalAccessException: class winstone.AbstractSecuredConnectorFactory cannot access class sun.security.util.DerInputStream (in module java.base) because module java.base does not export sun.security.util to unnamed module @53c4a559
        at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:392)
        at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:674)
        at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:489)
        at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
        at winstone.AbstractSecuredConnectorFactory.readPEMRSAPrivateKey(AbstractSecuredConnectorFactory.java:118)
        ... 34 more

Anything else?

No response

Launcher should atomically write port to file

Jenkins and plugins versions report

Environment
jenkins-test-harness-1816.v8138d8056949

What Operating System are you using (both controller, and any agents involved in the problem)?

MacOs

Reproduction steps

To reproduce you could run hundreds of time RemoteArtifactCopyBuilderTest and see them flaky. But keep in mind that you should use jenkins-test-harness <= 1816.v8138d8056949, as jenkins-test-harness going to patch workaround.

Expected Results

Tests should not flake

Actual Results

tests are flaky

Anything else?

private void writePortToFileIfNeeded() throws IOException {
String portFileName = System.getProperty(WINSTONE_PORT_FILE_NAME_PROPERTY);
if (portFileName != null) {
Connector[] connectors = server.getConnectors();
if (connectors.length > 0) {
Connector connector = connectors[0];
if (connector instanceof ServerConnector) {
int port = ((ServerConnector) connector).getLocalPort();
Path portFile = Paths.get(portFileName);
Path portDir = portFile.getParent();
Files.createDirectories(portDir);
try (BufferedWriter writer = Files.newBufferedWriter(portFile, StandardCharsets.UTF_8)) {
writer.write(Integer.toString(port));
}
} else {
throw new IllegalStateException("Only ServerConnector is supported");
}
} else {
throw new IllegalStateException("No connectors found");
}
}
}

should write port value atomically.

For a context related conversation jenkinsci/jenkins-test-harness#465 (comment)

Support for socket activation

What feature do you want to see added?

Steps to reproduce

Install Jenkins 2.335 or later, then create /etc/systemd/system/jenkins.service.d/override.conf with

[Service]
Environment="JENKINS_PORT=80"
StandardInput=socket

but not AmbientCapabilities=CAP_NET_BIND_SERVICE. Also create the corresponding socket in /etc/systemd/system/jenkins.socket with

[Unit]
Description=Jenkins socket

[Socket]
ListenStream=80
Accept=false
NoDelay=true

[Install]
WantedBy=jenkins.target

Run systemctl daemon-reload, then stop Jenkins with systemctl stop jenkins.service and start the socket with systemctl start jenkins.socket. Confirm that Java is not running, then visit http://127.0.0.1 in your web browser.

Expected results

systemd should start jenkins.service, after which Java should be listening on port 80 and the browser's request should be satisfied, even though the service does not have the CAP_NET_BIND_SERVICE capability.

Actual results

The service does not consume the socket provided by systemd and cannot be reached on port 80.

Evaluation

Jetty supports this use case via ServerConnector#setInheritChannel(boolean), which delegates to System#inheritedChannel; however, Winstone provides no way to enable this Jetty functionality. If Winstone provided a command-line interface (CLI) to enable this functionality, plumbing through the user's choice to ServerConnector (e.g. in winstone.ServerConnectorBuilder), this use case could be supported.

Upstream changes

JETTY-496

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.