Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[JENKINS-73126] Upgrade Winstone from Jetty 10.x to 12.x (EE 8) #383

Merged
merged 2 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,6 @@ updates:
schedule:
interval: "weekly"
target-branch: "master"
ignore:
# Restrict updates to jetty in the 10.x space
- dependency-name: "org.eclipse.jetty:*"
versions: [ ">=11" ]

- package-ecosystem: "github-actions"
directory: "/"
schedule:
Expand Down
3 changes: 1 addition & 2 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,5 @@
*/
buildPlugin(useContainerAgent: true, configurations: [
[platform: 'linux', jdk: 21],
[platform: 'windows', jdk: 17],
[platform: 'linux', jdk: 11]
[platform: 'windows', jdk: 17]
])
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# What is Winstone?
Winstone is a command line interface around Jetty 10.0.x, which implements
Winstone is a command line interface around Jetty 12.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.
Expand Down
37 changes: 21 additions & 16 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,12 @@
</scm>

<properties>
<revision>6.22</revision>
<revision>7.0</revision>
<changelist>-SNAPSHOT</changelist>
<jetty.version>10.0.22</jetty.version>
<jetty.version>12.0.12</jetty.version>
<slf4j.version>2.0.16</slf4j.version>
<gitHubRepo>jenkinsci/winstone</gitHubRepo>
<spotless.check.skip>false</spotless.check.skip>
<!-- TODO until we are ready to ship Winstone 7 with Jetty 12 EE 8 -->
<maven.compiler.release>11</maven.compiler.release>
</properties>

<dependencyManagement>
Expand All @@ -54,6 +52,13 @@
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.ee8</groupId>
<artifactId>jetty-ee8-bom</artifactId>
<version>${jetty.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- TODO SLF4J-437 use BOM -->
<dependency>
<groupId>org.slf4j</groupId>
Expand Down Expand Up @@ -101,10 +106,6 @@
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-unixdomain-server</artifactId>
Expand All @@ -114,21 +115,25 @@
<artifactId>jetty-util</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<groupId>org.eclipse.jetty.ee8</groupId>
<artifactId>jetty-ee8-servlet</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-hpack</artifactId>
<groupId>org.eclipse.jetty.ee8</groupId>
<artifactId>jetty-ee8-webapp</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.ee8.websocket</groupId>
<artifactId>jetty-ee8-websocket-jetty-server</artifactId>
<!-- or jetty-ee8-websocket-javax-server -->
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-server</artifactId>
<artifactId>jetty-http2-hpack</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-jetty-server</artifactId>
<!-- or websocket-javax-server -->
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>jetty-http2-server</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
Expand Down
33 changes: 15 additions & 18 deletions src/main/java/winstone/HostConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,12 @@
import java.util.jar.JarFile;
import java.util.logging.Level;
import javax.servlet.SessionTrackingMode;
import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.ee8.webapp.WebAppContext;
import org.eclipse.jetty.ee8.websocket.server.config.JettyWebSocketServletContainerInitializer;
import org.eclipse.jetty.security.LoginService;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.RequestLog;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.RequestLogHandler;
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer;
import winstone.cmdline.CompressionScheme;
import winstone.cmdline.Option;

Expand All @@ -55,7 +52,6 @@ public class HostConfiguration {
private Map<String, String> args;
private Map<String, WebAppContext> webapps;
private ClassLoader commonLibCL;
private MimeTypes mimeTypes = new MimeTypes();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that we are no longer replacing the default MIME types, but appending to them. As a result, we have deleted any MIME mappings that are already present in upstream Jetty and added a test to ensure that we are only adding to the existing MIME types rather than attempting to replace them.

private final LoginService loginService;

public HostConfiguration(Server server, String hostname, ClassLoader commonLibCL, @NonNull Map<String, String> args)
Expand Down Expand Up @@ -85,7 +81,11 @@ public HostConfiguration(Server server, String hostname, ClassLoader commonLibCL
// trim off the trailing '/' that Jetty doesn't like
prefix = prefix.substring(0, prefix.length() - 1);
}
Handler handler = configureAccessLog(create(getWebRoot(webroot, warfile), prefix), "webapp");
WebAppContext webAppContext = create(getWebRoot(webroot, warfile), prefix);
RequestLog requestLog = configureAccessLog("webapp");
if (requestLog != null) {
server.setRequestLog(requestLog);
}

{ // load additional mime types
loadBuiltinMimeTypes();
Expand All @@ -100,7 +100,7 @@ public HostConfiguration(Server server, String hostname, ClassLoader commonLibCL
}
String extension = mapping.substring(0, delimPos);
String mimeType = mapping.substring(delimPos + 1);
this.mimeTypes.addMimeMapping(extension.toLowerCase(), mimeType);
server.getMimeTypes().addMimeMapping(extension.toLowerCase(), mimeType);
}
}
}
Expand All @@ -109,11 +109,11 @@ public HostConfiguration(Server server, String hostname, ClassLoader commonLibCL
switch (compressionScheme) {
case GZIP:
GzipHandler gzipHandler = new GzipHandler();
gzipHandler.setHandler(handler);
gzipHandler.setHandler(webAppContext);
server.setHandler(gzipHandler);
break;
case NONE:
server.setHandler(handler);
server.setHandler(webAppContext);
break;
default:
throw new IllegalArgumentException("Unexpected compression scheme: " + compressionScheme);
Expand All @@ -132,7 +132,8 @@ private void loadBuiltinMimeTypes() {
Properties props = new Properties();
props.load(in);
for (Entry<Object, Object> e : props.entrySet()) {
mimeTypes.addMimeMapping(e.getKey().toString(), e.getValue().toString());
server.getMimeTypes()
.addMimeMapping(e.getKey().toString(), e.getValue().toString());
}
} catch (IOException e) {
throw new UncheckedIOException("Failed to load the built-in MIME types", e);
Expand All @@ -143,24 +144,21 @@ private void loadBuiltinMimeTypes() {
* @param webAppName
* Unique name given to the access logger.
*/
private Handler configureAccessLog(Handler handler, String webAppName) {
private RequestLog configureAccessLog(String webAppName) {
try {
Class<? extends RequestLog> loggerClass =
Option.ACCESS_LOGGER_CLASSNAME.get(args, RequestLog.class, commonLibCL);
if (loggerClass != null) {
// Build the realm
Constructor<? extends RequestLog> loggerConstr = loggerClass.getConstructor(String.class, Map.class);
RequestLogHandler rlh = new RequestLogHandler();
rlh.setHandler(handler);
rlh.setRequestLog(loggerConstr.newInstance(webAppName, args));
return rlh;
return loggerConstr.newInstance(webAppName, args);
} else {
Logger.log(Level.FINER, Launcher.RESOURCES, "WebAppConfig.LoggerDisabled");
}
} catch (Throwable err) {
Logger.log(Level.SEVERE, Launcher.RESOURCES, "WebAppConfig.LoggerError", "", err);
}
return handler;
return null;
}

private WebAppContext create(File app, String prefix) {
Expand Down Expand Up @@ -199,7 +197,6 @@ public void postConfigure() throws Exception {
wac.getSecurityHandler().setLoginService(loginService);
wac.setThrowUnavailableOnStartupException(
true); // if boot fails, abort the process instead of letting empty Jetty run
wac.setMimeTypes(mimeTypes);
wac.getSessionHandler().setSessionTrackingModes(Set.of(SessionTrackingMode.COOKIE));
wac.getSessionHandler().setSessionCookie(WinstoneSession.SESSION_COOKIE_NAME);
this.webapps.put(wac.getContextPath(), wac);
Expand Down
12 changes: 3 additions & 9 deletions src/main/java/winstone/HttpsConnectorFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.server.handler.SecuredRedirectHandler;
import winstone.cmdline.Option;

Expand Down Expand Up @@ -40,14 +39,9 @@ public Connector start(Map<String, String> args, Server server) throws IOExcepti
if (currentHandler == null) {
server.setHandler(new SecuredRedirectHandler());
} else {
if (currentHandler instanceof HandlerList) {
((HandlerList) currentHandler).addHandler(new SecuredRedirectHandler());
} else {
HandlerList handlers = new HandlerList();
handlers.addHandler(new SecuredRedirectHandler());
handlers.addHandler(currentHandler);
server.setHandler(handlers);
}
Handler.Wrapper securedRedirectHandler = new SecuredRedirectHandler();
securedRedirectHandler.setHandler(currentHandler);
server.setHandler(securedRedirectHandler);
}
}
configureSsl(args, server);
Expand Down
48 changes: 23 additions & 25 deletions src/main/java/winstone/accesslog/SimpleAccessLogger.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.StandardOpenOption;
import java.security.Principal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.logging.Level;
import org.eclipse.jetty.server.Authentication;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.RequestLog;
import org.eclipse.jetty.server.Response;
Expand Down Expand Up @@ -95,44 +96,41 @@

@Override
public void log(Request request, Response response) {
String uriLine = request.getMethod() + " " + request.getRequestURI() + " " + request.getProtocol();
String uriLine = request.getMethod() + " " + request.getHttpURI().getPath() + " "
+ request.getConnectionMetaData().getProtocol();
int status = response.getStatus();
long size = response.getContentCount();
long size = Response.getContentBytesWritten(response);
String date;
synchronized (DF) {
date = DF.format(new Date());
}

// mimic
// https://github.com/eclipse/jetty.project/blob/jetty-9.4.0.v20161208/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractNCSARequestLog.java#L130
Authentication authentication = request.getAuthentication();
String remoteUser;
if (authentication instanceof Authentication.User) {
Authentication.User user = (Authentication.User) authentication;
remoteUser = user.getUserIdentity().getUserPrincipal().getName();
} else {
remoteUser = null;
}
// https://github.com/jetty/jetty.project/blob/c5b2533fdecce21b54c6fbaf36f79bc3ba909775/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/CustomRequestLog.java#L1093-L1099
Request.AuthenticationState authenticationState = Request.getAuthenticationState(request);
Principal principal = authenticationState == null ? null : authenticationState.getUserPrincipal();

Check warning on line 111 in src/main/java/winstone/accesslog/SimpleAccessLogger.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 111 is only partially covered, one branch is missing
String remoteUser = principal == null ? "-" : principal.getName();

Check warning on line 112 in src/main/java/winstone/accesslog/SimpleAccessLogger.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 112 is only partially covered, one branch is missing

HttpFields httpFields = request.getHeaders();
String logLine = WinstoneResourceBundle.globalReplace(this.pattern, new String[][] {
{"###x-forwarded-for###", nvl(request.getHeader("X-Forwarded-For"))},
{"###x-forwarded-host###", nvl(request.getHeader("X-Forwarded-Host"))},
{"###x-forwarded-proto###", nvl(request.getHeader("X-Forwarded-Proto"))},
{"###x-forwarded-protocol###", nvl(request.getHeader("X-Forwarded-Protocol"))},
{"###x-forwarded-server###", nvl(request.getHeader("X-Forwarded-Server"))},
{"###x-forwarded-ssl###", nvl(request.getHeader("X-Forwarded-Ssl"))},
{"###x-requested-with###", nvl(request.getHeader("X-Requested-With"))},
{"###x-do-not-track###", nvl(request.getHeader("X-Do-Not-Track"))},
{"###dnt###", nvl(request.getHeader("DNT"))},
{"###via###", nvl(request.getHeader("Via"))},
{"###ip###", request.getRemoteHost()},
{"###x-forwarded-for###", nvl(httpFields.get("X-Forwarded-For"))},
{"###x-forwarded-host###", nvl(httpFields.get("X-Forwarded-Host"))},
{"###x-forwarded-proto###", nvl(httpFields.get("X-Forwarded-Proto"))},
{"###x-forwarded-protocol###", nvl(httpFields.get("X-Forwarded-Protocol"))},
{"###x-forwarded-server###", nvl(httpFields.get("X-Forwarded-Server"))},
{"###x-forwarded-ssl###", nvl(httpFields.get("X-Forwarded-Ssl"))},
{"###x-requested-with###", nvl(httpFields.get("X-Requested-With"))},
{"###x-do-not-track###", nvl(httpFields.get("X-Do-Not-Track"))},
{"###dnt###", nvl(httpFields.get("DNT"))},
{"###via###", nvl(httpFields.get("Via"))},
{"###ip###", Request.getRemoteAddr(request)},
{"###user###", nvl(remoteUser)},
{"###time###", "[" + date + "]"},
{"###uriLine###", uriLine},
{"###status###", "" + status},
{"###size###", "" + size},
{"###referer###", nvl(request.getHeader("Referer"))},
{"###userAgent###", nvl(request.getHeader("User-Agent"))}
{"###referer###", nvl(httpFields.get("Referer"))},
{"###userAgent###", nvl(httpFields.get("User-Agent"))}
});
this.outWriter.println(logLine);
}
Expand Down
Loading