Skip to content
This repository was archived by the owner on Jun 11, 2024. It is now read-only.

Commit 9a11271

Browse files
authored
Merge pull request #87 from browserup/brotli-support
Bring in brotli support from PR on BrowserMob
2 parents db9abcc + 3f15d3e commit 9a11271

File tree

3 files changed

+50
-3
lines changed

3 files changed

+50
-3
lines changed

browserup-proxy-core/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ dependencies {
7272
implementation 'io.netty:netty-all:4.1.36.Final'
7373
implementation 'org.bouncycastle:bcpkix-jdk15on:1.61'
7474
implementation 'org.bouncycastle:bcprov-jdk15on:1.61'
75+
implementation 'org.brotli:dec:0.1.2'
7576
implementation 'org.javassist:javassist:3.25.0-GA'
7677
implementation 'org.seleniumhq.selenium:selenium-api:3.141.59'
7778
implementation 'org.slf4j:jcl-over-slf4j:1.7.26'

browserup-proxy-core/src/main/java/com/browserup/bup/filters/ServerResponseCaptureFilter.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
*/
3030
public class ServerResponseCaptureFilter extends HttpFiltersAdapter {
3131
private static final Logger log = LoggerFactory.getLogger(ServerResponseCaptureFilter.class);
32+
private static final String BROTLI_COMPRESSION = "br";
3233

3334
/**
3435
* Populated by serverToProxyResponse() when processing the HttpResponse object
@@ -132,7 +133,14 @@ protected void captureFullResponseContents() {
132133
protected void decompressContents() {
133134
if (contentEncoding.equals(HttpHeaders.Values.GZIP)) {
134135
try {
135-
fullResponseContents = BrowserUpHttpUtil.decompressContents(getRawResponseContents());
136+
fullResponseContents = BrowserUpHttpUtil.decompressGZIPContents(getRawResponseContents());
137+
decompressionSuccessful = true;
138+
} catch (RuntimeException e) {
139+
log.warn("Failed to decompress response with encoding type " + contentEncoding + " when decoding request from " + originalRequest.getUri(), e);
140+
}
141+
} else if (contentEncoding.equals(BROTLI_COMPRESSION)) {
142+
try {
143+
fullResponseContents = BrowserUpHttpUtil.decompressBrotliContents(getRawResponseContents());
136144
decompressionSuccessful = true;
137145
} catch (RuntimeException e) {
138146
log.warn("Failed to decompress response with encoding type " + contentEncoding + " when decoding request from " + originalRequest.getUri(), e);

browserup-proxy-core/src/main/java/com/browserup/bup/util/BrowserUpHttpUtil.java

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.google.common.io.BaseEncoding;
88
import com.google.common.net.HostAndPort;
99
import com.google.common.net.MediaType;
10+
import org.brotli.dec.BrotliInputStream;
1011
import io.netty.buffer.ByteBuf;
1112
import io.netty.handler.codec.http.HttpHeaders;
1213
import io.netty.handler.codec.http.HttpRequest;
@@ -16,6 +17,7 @@
1617
import org.slf4j.Logger;
1718
import org.slf4j.LoggerFactory;
1819

20+
import java.io.InputStream;
1921
import java.io.ByteArrayInputStream;
2022
import java.io.ByteArrayOutputStream;
2123
import java.io.IOException;
@@ -79,11 +81,11 @@ public static long getHeaderSize(HttpHeaders headers) {
7981
/**
8082
* Decompresses the gzipped byte stream.
8183
*
82-
* @param fullMessage gzipped byte stream to decomress
84+
* @param fullMessage gzipped byte stream to decompress
8385
* @return decompressed bytes
8486
* @throws DecompressionException thrown if the fullMessage cannot be read or decompressed for any reason
8587
*/
86-
public static byte[] decompressContents(byte[] fullMessage) throws DecompressionException {
88+
public static byte[] decompressGZIPContents(byte[] fullMessage) throws DecompressionException {
8789
InflaterInputStream gzipReader = null;
8890
ByteArrayOutputStream uncompressed;
8991
try {
@@ -113,6 +115,42 @@ public static byte[] decompressContents(byte[] fullMessage) throws Decompression
113115
}
114116

115117
/**
118+
* Decompresses the brotli byte stream
119+
*
120+
* @param fullMessage brotli byte stream to decompress
121+
* @return decompressed bytes
122+
* @throws DecompressionException thrown if the fullMessage cannot be read or decompressed for any reason
123+
*/
124+
public static byte[] decompressBrotliContents(byte[] fullMessage) throws DecompressionException {
125+
InputStream brotliReader = null;
126+
ByteArrayOutputStream uncompressed;
127+
try {
128+
brotliReader = new BrotliInputStream(new ByteArrayInputStream(fullMessage));
129+
130+
uncompressed = new ByteArrayOutputStream(fullMessage.length);
131+
132+
byte[] decompressBuffer = new byte[DECOMPRESS_BUFFER_SIZE];
133+
int bytesRead;
134+
while ((bytesRead = brotliReader.read(decompressBuffer)) > -1) {
135+
uncompressed.write(decompressBuffer, 0, bytesRead);
136+
}
137+
138+
fullMessage = uncompressed.toByteArray();
139+
} catch (IOException e) {
140+
throw new DecompressionException("Unable to decompress response", e);
141+
} finally {
142+
try {
143+
if (brotliReader != null) {
144+
brotliReader.close();
145+
}
146+
} catch (IOException e) {
147+
log.warn("Unable to close brotli stream", e);
148+
}
149+
}
150+
return fullMessage;
151+
}
152+
153+
/**
116154
* Returns true if the content type string indicates textual content. Currently these are any Content-Types that start with one of the
117155
* following:
118156
* <pre>

0 commit comments

Comments
 (0)