From 9c7d872e34f1e98c8d1c3903261a23b3ac9d34dd Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Tue, 29 Oct 2024 09:54:41 -0700 Subject: [PATCH] Making gzip compression work It's a little too much work to have the necessary server support on our own to do mime/multipart decoding, so instead, just compress one part, on our own. --- .../plugins/launchable/GzipFileMimePart.java | 51 +++++++++++++++++++ .../jenkins/plugins/launchable/Ingester.java | 12 ++--- 2 files changed, 57 insertions(+), 6 deletions(-) create mode 100644 src/main/java/io/jenkins/plugins/launchable/GzipFileMimePart.java diff --git a/src/main/java/io/jenkins/plugins/launchable/GzipFileMimePart.java b/src/main/java/io/jenkins/plugins/launchable/GzipFileMimePart.java new file mode 100644 index 0000000..ffd8978 --- /dev/null +++ b/src/main/java/io/jenkins/plugins/launchable/GzipFileMimePart.java @@ -0,0 +1,51 @@ +package io.jenkins.plugins.launchable; + +import org.apache.commons.io.output.CloseShieldOutputStream; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.mime.MIME; +import org.apache.http.entity.mime.content.AbstractContentBody; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.zip.GZIPOutputStream; + +final class GzipFileMimePart extends AbstractContentBody { + private final File file; + private final String filename; + + public GzipFileMimePart(File file, ContentType contentType, String filename) { + super(contentType); + this.file = file; + this.filename = filename == null ? file.getName() : filename; + } + + @Override + public void writeTo(OutputStream out) throws IOException { + try (OutputStream o = new GZIPOutputStream(new CloseShieldOutputStream(out)); + InputStream in = new FileInputStream(this.file)) { + final byte[] tmp = new byte[4096]; + int l; + while ((l = in.read(tmp)) != -1) { + o.write(tmp, 0, l); + } + } + } + + @Override + public String getTransferEncoding() { + return MIME.ENC_BINARY; + } + + @Override + public long getContentLength() { + return this.file.length(); + } + + @Override + public String getFilename() { + return filename; + } +} diff --git a/src/main/java/io/jenkins/plugins/launchable/Ingester.java b/src/main/java/io/jenkins/plugins/launchable/Ingester.java index 6946006..a5a054f 100644 --- a/src/main/java/io/jenkins/plugins/launchable/Ingester.java +++ b/src/main/java/io/jenkins/plugins/launchable/Ingester.java @@ -5,11 +5,8 @@ import hudson.util.Secret; import jenkins.model.GlobalConfiguration; import net.sf.json.JSONObject; -import org.apache.http.HttpHeaders; -import org.apache.http.client.entity.GzipCompressingEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.ContentType; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; @@ -20,6 +17,9 @@ import java.util.logging.Level; import java.util.logging.Logger; +import static org.apache.http.entity.ContentType.APPLICATION_JSON; +import static org.apache.http.entity.ContentType.APPLICATION_OCTET_STREAM; + @Extension public class Ingester extends GlobalConfiguration { private Secret apiKey; @@ -66,10 +66,10 @@ public boolean configure(StaplerRequest req, JSONObject json) throws FormExcepti HttpPost hc = new HttpPost(String.format("%s/intake/organizations/%s/workspaces/%s/events/jenkins", endpoint, orgWs.getOrganization(), orgWs.getWorkspace())); MultipartEntityBuilder builder = MultipartEntityBuilder.create(); - builder.addTextBody("metadata", properties.build().toString(), ContentType.APPLICATION_JSON); - builder.addBinaryBody("file", report, ContentType.APPLICATION_XML, "junitResult.xml"); + builder.addTextBody("metadata", properties.build().toString(), APPLICATION_JSON); + builder.addPart("file", new GzipFileMimePart(report, APPLICATION_OCTET_STREAM, "junitResult.xml.gz")); - hc.setEntity(new GzipCompressingEntity(builder.build())); + hc.setEntity(builder.build()); hc.addHeader("Authorization", "Bearer " + apiKey.getPlainText()); try (CloseableHttpResponse response = httpClient.execute(hc)) {