From 982a8faf5a853129039ba2babe2a8cb35d9aca1f Mon Sep 17 00:00:00 2001 From: James Nord Date: Fri, 22 Sep 2017 12:05:53 +0100 Subject: [PATCH] [JENKINS-37062] incorporate changes from stapler servlet 3.1 Downstream updates from stapler/stapler#131 The stapler API was built using servlet 2.5 and yet Jenkins uses 3.1. This meant some of the code that stapler used was missing new methods that where part of the updated spec and if a plugin happened to call them you would end up with a LinkageError or some other crazyness. This also make Jenkins depend on a dummy version of the old serlet-api maven co-ordinates such that if any plugin gets aa dependency on it transitivly (e.g. Jenkins test harness) they will get a version with no code so the classpath should always be clean (this was more an issue for eclipse than an mvn command) --- core/pom.xml | 8 +-- .../slaves/EncryptedSlaveAgentJnlpFile.java | 64 +++++++++++++++++-- pom.xml | 23 ++++++- war/pom.xml | 8 +-- 4 files changed, 86 insertions(+), 17 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index 4cb16854f9..f67057e4e7 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -39,7 +39,7 @@ THE SOFTWARE. true - 1.252 + 1.253-SNAPSHOT 2.5.6.SEC03 2.4.11 @@ -472,9 +472,9 @@ THE SOFTWARE. test - javax.servlet - jstl - 1.1.0 + javax.servlet.jsp.jstl + javax.servlet.jsp.jstl-api + 1.2.1 org.slf4j diff --git a/core/src/main/java/jenkins/slaves/EncryptedSlaveAgentJnlpFile.java b/core/src/main/java/jenkins/slaves/EncryptedSlaveAgentJnlpFile.java index 9d152a68f0..6da6932054 100644 --- a/core/src/main/java/jenkins/slaves/EncryptedSlaveAgentJnlpFile.java +++ b/core/src/main/java/jenkins/slaves/EncryptedSlaveAgentJnlpFile.java @@ -4,12 +4,12 @@ import hudson.security.AccessControlled; import hudson.security.Permission; import hudson.slaves.SlaveComputer; import hudson.util.Secret; + import hudson.Util; import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.ResponseImpl; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; -import org.kohsuke.stapler.compression.FilterServletOutputStream; import javax.crypto.Cipher; import javax.crypto.SecretKey; @@ -18,12 +18,15 @@ import javax.crypto.spec.SecretKeySpec; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; +import javax.servlet.WriteListener; import javax.servlet.http.HttpServletResponseWrapper; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.security.GeneralSecurityException; import java.security.SecureRandom; +import java.util.logging.Level; +import java.util.logging.Logger; /** * Serves the JNLP file. @@ -35,6 +38,9 @@ import java.security.SecureRandom; * @since 1.560 */ public class EncryptedSlaveAgentJnlpFile implements HttpResponse { + + private static final Logger LOG = Logger.getLogger(EncryptedSlaveAgentJnlpFile.class.getName()); + /** * The object that owns the Jelly view that renders JNLP file. * This is typically a {@link SlaveComputer} and if so we'll use {@link SlaveComputer#getJnlpMac()} @@ -64,13 +70,13 @@ public class EncryptedSlaveAgentJnlpFile implements HttpResponse { } @Override - public void generateResponse(StaplerRequest req, StaplerResponse res, Object node) throws IOException, ServletException { + public void generateResponse(StaplerRequest req, final StaplerResponse res, Object node) throws IOException, ServletException { RequestDispatcher view = req.getView(it, viewName); if ("true".equals(req.getParameter("encrypt"))) { - final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final CapturingServletOutputStream csos = new CapturingServletOutputStream(); StaplerResponse temp = new ResponseImpl(req.getStapler(), new HttpServletResponseWrapper(res) { @Override public ServletOutputStream getOutputStream() throws IOException { - return new FilterServletOutputStream(baos); + return csos; } @Override public PrintWriter getWriter() throws IOException { throw new IllegalStateException(); @@ -92,7 +98,7 @@ public class EncryptedSlaveAgentJnlpFile implements HttpResponse { try { Cipher c = Secret.getCipher("AES/CFB8/NoPadding"); c.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv)); - encrypted = c.doFinal(baos.toByteArray()); + encrypted = c.doFinal(csos.getBytes()); } catch (GeneralSecurityException x) { throw new IOException(x); } @@ -104,4 +110,52 @@ public class EncryptedSlaveAgentJnlpFile implements HttpResponse { view.forward(req, res); } } + + + /** + * A {@link ServletOutputStream} that captures all the data rather than writing to a client. + */ + private static class CapturingServletOutputStream extends ServletOutputStream { + + private ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setWriteListener(WriteListener writeListener) { + // we are always ready to write so we just call once to say we are ready. + try { + // should we do this on a separate thread to avoid deadlocaks? + writeListener.onWritePossible(); + } catch (IOException e) { + LOG.log(Level.WARNING, "Failed to notify WriteListener.onWritePossible", e); + } + } + + @Override + public void write(int b) throws IOException { + baos.write(b); + } + + @Override + public void write(byte[] b) throws IOException { + baos.write(b); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + baos.write(b, off, len); + } + + /** + * Get the data that has been written to this ServletOutputStream. + * @return the data that has been written to this ServletOutputStream. + */ + byte[] getBytes() { + return baos.toByteArray(); + } + } } diff --git a/pom.xml b/pom.xml index c3a70bb174..78e12f42ad 100644 --- a/pom.xml +++ b/pom.xml @@ -230,6 +230,19 @@ THE SOFTWARE. access-modifier-annotation ${access-modifier-annotation.version} + + + + + + javax.servlet + + servlet-api + [0-SNAPSHOT] + provided + true + + @@ -246,6 +259,12 @@ THE SOFTWARE. test-annotations test + + + javax.servlet + + servlet-api + @@ -324,8 +343,8 @@ THE SOFTWARE. javax.servlet - servlet-api - 2.4 + javax.servlet-api + 3.1.0 org.codehaus.gmaven.runtime diff --git a/war/pom.xml b/war/pom.xml index dace1a2fc1..f89dd39670 100644 --- a/war/pom.xml +++ b/war/pom.xml @@ -61,12 +61,8 @@ THE SOFTWARE. jars that are not needed in war. most of the exclusions should happen in the core, to make IDEs happy, not here. --> - javax.servlet - servlet-api - - - javax.servlet - jsp-api + javax.servlet.jsp + javax.servlet.jsp-api -- GitLab