Skip to content

Commit df59162

Browse files
committed
Enable GZIP compression.
1 parent 277e8ef commit df59162

2 files changed

Lines changed: 57 additions & 26 deletions

File tree

src/main/java/io/github/hikingc/matrixsdk/api/MatrixAuth.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,12 +159,14 @@ public TokenMetadata performOAuthLogin(String clientName, int port, String devic
159159
// Send the payload using the aforementioned record obtained and get the client_id
160160
var responseBody =
161161
httpTransport.postRequest(metadata.registrationEndpoint(), mappedInput, null);
162-
logger.info("Registration response: {}", responseBody);
162+
String responseBodyString = new String(responseBody);
163+
logger.info("Registration response: {}", responseBodyString);
163164

164165
var clientId = Mapper.getStringValueOfAJsonKey(responseBody, "client_id");
165166
if (clientId.isBlank()) {
166167
throw new MatrixIOException(
167-
"Dynamic client registration failed or returned no client_id. Response: " + responseBody);
168+
"Dynamic client registration failed or returned no client_id. Response: "
169+
+ Arrays.toString(responseBody));
168170
}
169171

170172
// Finish registering client, now we do the login flow

src/main/java/io/github/hikingc/matrixsdk/services/utils/HttpTransport.java

Lines changed: 53 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
package io.github.hikingc.matrixsdk.services.utils;
22

33
import io.github.hikingc.matrixsdk.exceptions.*;
4+
import java.io.ByteArrayInputStream;
45
import java.io.IOException;
56
import java.net.URI;
67
import java.net.URISyntaxException;
78
import java.net.URLEncoder;
89
import java.net.http.HttpClient;
10+
import java.net.http.HttpHeaders;
911
import java.net.http.HttpRequest;
1012
import java.net.http.HttpResponse;
1113
import java.nio.charset.StandardCharsets;
1214
import java.nio.file.Files;
1315
import java.nio.file.Path;
14-
import java.util.Arrays;
1516
import java.util.List;
1617
import java.util.Map;
1718
import java.util.Objects;
1819
import java.util.stream.Collectors;
1920
import java.util.stream.Stream;
21+
import java.util.zip.GZIPInputStream;
2022
import org.jspecify.annotations.NullMarked;
2123
import org.jspecify.annotations.Nullable;
2224
import org.slf4j.Logger;
@@ -52,21 +54,20 @@ public HttpTransport(HttpClient httpClient) {
5254
///
5355
/// @param response the client response.
5456
/// @throws MatrixApiException when the server responds with an unsuccessful HTTP Code.
55-
private void validateResponse(HttpResponse<byte[]> response) {
56-
var code = response.statusCode();
57-
var body = response.body();
58-
var headers = response.headers();
57+
private void validateResponse(byte[] response, int code, HttpHeaders headers) {
58+
var body = new String(response, StandardCharsets.UTF_8);
59+
5960
logger.debug("Validate response code: {}, for body: {} and headers: {}", code, body, headers);
6061
if (code >= 200 && code < 300) {
6162
return;
6263
}
6364

64-
if (Arrays.toString(body).isBlank()) {
65+
if (body.isBlank()) {
6566
throw new MatrixException("Server returned with HTTP Code:" + code);
6667
}
6768
ErrorResponse errorResponse;
6869
try {
69-
errorResponse = Mapper.getObjectFromString(body, ErrorResponse.class);
70+
errorResponse = Mapper.getObjectFromString(response, ErrorResponse.class);
7071
} catch (MatrixSerializationException e) {
7172
throw new MatrixApiException(
7273
"Server returned unparseable error body, HTTP code: " + code, code, e);
@@ -99,13 +100,15 @@ private void validateResponse(HttpResponse<byte[]> response) {
99100
/// @throws MatrixApiException when the response from the server is not successful.
100101
public byte[] getRequest(URI path, @Nullable String authToken) {
101102
var builderRequest =
102-
HttpRequest.newBuilder().uri(path).header(CONTENT_TYPE, APPLICATION_JSON).GET();
103-
103+
HttpRequest.newBuilder()
104+
.uri(path)
105+
.header(CONTENT_TYPE, APPLICATION_JSON)
106+
.header("Accept-Encoding", "gzip")
107+
.GET();
104108
if (authToken != null) {
105109
builderRequest.header(AUTHORIZATION, BEARER + authToken);
106110
}
107111
var request = builderRequest.build();
108-
109112
HttpResponse<byte[]> response;
110113
try {
111114
response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
@@ -116,8 +119,9 @@ public byte[] getRequest(URI path, @Nullable String authToken) {
116119
Thread.currentThread().interrupt();
117120
throw new MatrixInterruptedException("This request has been interrupted", e);
118121
}
119-
this.validateResponse(response);
120-
return response.body();
122+
var uncResponse = decompressIfNeeded(response);
123+
this.validateResponse(uncResponse, response.statusCode(), response.headers());
124+
return uncResponse;
121125
}
122126

123127
/// Sends a `POST` request to the given endpoint.
@@ -130,7 +134,7 @@ public byte[] getRequest(URI path, @Nullable String authToken) {
130134
/// @throws MatrixInterruptedException if the operation has been interrupted.
131135
/// @throws MatrixApiException when the response from the server is not successful.
132136
public byte[] postRequest(URI path, @Nullable String body, @Nullable String authToken) {
133-
var builderRequest = HttpRequest.newBuilder().uri(path);
137+
var builderRequest = HttpRequest.newBuilder().header("Accept-Encoding", "gzip").uri(path);
134138

135139
if (body != null) {
136140
builderRequest.header(CONTENT_TYPE, APPLICATION_JSON);
@@ -156,8 +160,9 @@ public byte[] postRequest(URI path, @Nullable String body, @Nullable String auth
156160
Thread.currentThread().interrupt();
157161
throw new MatrixInterruptedException("This request has been interrupted", e);
158162
}
159-
this.validateResponse(response);
160-
return response.body();
163+
var uncResponse = decompressIfNeeded(response);
164+
this.validateResponse(uncResponse, response.statusCode(), response.headers());
165+
return uncResponse;
161166
}
162167

163168
/// Sends a `POST` request to the given endpoint.
@@ -172,7 +177,7 @@ public byte[] postRequest(URI path, @Nullable String body, @Nullable String auth
172177
/// with unsuccessful HTTP Code.
173178
/// @throws MatrixApiException when the response from the server is not successful.
174179
public byte[] postAuth(URI path, @Nullable String body) {
175-
var builderRequest = HttpRequest.newBuilder().uri(path);
180+
var builderRequest = HttpRequest.newBuilder().header("Accept-Encoding", "gzip").uri(path);
176181

177182
builderRequest.header(CONTENT_TYPE, "application/x-www-form-urlencoded");
178183

@@ -193,8 +198,9 @@ public byte[] postAuth(URI path, @Nullable String body) {
193198
Thread.currentThread().interrupt();
194199
throw new MatrixInterruptedException("This request has been interrupted", e);
195200
}
196-
this.validateResponse(response);
197-
return response.body();
201+
var uncResponse = decompressIfNeeded(response);
202+
this.validateResponse(uncResponse, response.statusCode(), response.headers());
203+
return uncResponse;
198204
}
199205

200206
/// Sends a `PUT` request to the given endpoint.
@@ -211,6 +217,7 @@ public byte[] putRequest(URI path, @Nullable String body, String authToken) {
211217

212218
var builderRequest =
213219
HttpRequest.newBuilder()
220+
.header("Accept-Encoding", "gzip")
214221
.uri(path)
215222
.headers(AUTHORIZATION, BEARER + authToken, CONTENT_TYPE, APPLICATION_JSON);
216223

@@ -230,8 +237,9 @@ public byte[] putRequest(URI path, @Nullable String body, String authToken) {
230237
Thread.currentThread().interrupt();
231238
throw new MatrixInterruptedException("This request has been interrupted", e);
232239
}
233-
this.validateResponse(response);
234-
return response.body();
240+
var uncResponse = decompressIfNeeded(response);
241+
this.validateResponse(uncResponse, response.statusCode(), response.headers());
242+
return uncResponse;
235243
}
236244

237245
/// Sends a `PUT` request to the given endpoint to upload a resource.
@@ -251,6 +259,7 @@ public byte[] putResource(URI path, Path resource, String authToken) {
251259
try {
252260
uploadRequest =
253261
HttpRequest.newBuilder()
262+
.header("Accept-Encoding", "gzip")
254263
.uri(path)
255264
.headers(
256265
AUTHORIZATION, BEARER + authToken, CONTENT_TYPE, Files.probeContentType(resource))
@@ -271,8 +280,9 @@ public byte[] putResource(URI path, Path resource, String authToken) {
271280
Thread.currentThread().interrupt();
272281
throw new MatrixInterruptedException("This request has been interrupted", e);
273282
}
274-
this.validateResponse(response);
275-
return response.body();
283+
var uncResponse = decompressIfNeeded(response);
284+
this.validateResponse(uncResponse, response.statusCode(), response.headers());
285+
return uncResponse;
276286
}
277287

278288
/// Sends a `DELETE` request to the given endpoint.
@@ -287,6 +297,7 @@ public byte[] putResource(URI path, Path resource, String authToken) {
287297
public byte[] deleteRequest(URI path, String authToken) {
288298
HttpRequest deleteRequest =
289299
HttpRequest.newBuilder()
300+
.header("Accept-Encoding", "gzip")
290301
.uri(path)
291302
.header(AUTHORIZATION, BEARER + authToken)
292303
.DELETE()
@@ -302,8 +313,9 @@ public byte[] deleteRequest(URI path, String authToken) {
302313
Thread.currentThread().interrupt();
303314
throw new MatrixInterruptedException("This request has been interrupted", e);
304315
}
305-
this.validateResponse(response);
306-
return response.body();
316+
var uncResponse = decompressIfNeeded(response);
317+
this.validateResponse(uncResponse, response.statusCode(), response.headers());
318+
return uncResponse;
307319
}
308320

309321
/// URL-encodes a string using UTF-8.
@@ -333,6 +345,23 @@ public URI generateEncodedURI(String baseUrl, String path, @Nullable Map<String,
333345
}
334346
}
335347

348+
/// Method to check if the server did return response as GZIP and then decompress it.
349+
///
350+
/// @param response an HTTP Response.
351+
/// @return a `byte` array.
352+
private byte[] decompressIfNeeded(HttpResponse<byte[]> response) {
353+
String encoding = response.headers().firstValue("Content-Encoding").orElse("");
354+
if (!encoding.equalsIgnoreCase("gzip")) {
355+
return response.body();
356+
}
357+
try (var gzip = new GZIPInputStream(new ByteArrayInputStream(response.body()))) {
358+
logger.debug("Server has returned with GZIP compression. Decompressing response");
359+
return gzip.readAllBytes();
360+
} catch (IOException e) {
361+
throw new MatrixIOException("Failed to decompress gzip response body", e);
362+
}
363+
}
364+
336365
/// Builds a [URI] from a base, path, and query parameters. This method WON'T encode to UTF-8 the
337366
/// queries
338367
///

0 commit comments

Comments
 (0)