From c6c8111082ff01a9c95a581832c9166d7a2bb58b Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Fri, 17 May 2024 09:46:58 +0530 Subject: [PATCH 01/11] Add brotli compression support --- ballerina/build.gradle | 36 ++++++++++ build-config/resources/Ballerina.toml | 66 +++++++++++++++++++ gradle.properties | 1 + native/build.gradle | 11 ++++ .../client/actions/AbstractHTTPAction.java | 4 +- .../http/transport/contract/Constants.java | 1 + .../Http2OutboundRespListener.java | 45 ++++++++++--- .../listener/CustomHttpContentCompressor.java | 4 +- .../message/HttpMessageDataStreamer.java | 5 ++ native/src/main/java/module-info.java | 1 + 10 files changed, 164 insertions(+), 10 deletions(-) diff --git a/ballerina/build.gradle b/ballerina/build.gradle index 8a3d06ae47..c4dd91f5a9 100644 --- a/ballerina/build.gradle +++ b/ballerina/build.gradle @@ -147,6 +147,40 @@ dependencies { externalJars(group: 'com.google.protobuf', name: 'protobuf-java', version: "${protobufVersion}") { transitive = false } + + externalJars(group: 'com.aayushatharva.brotli4j', name: 'brotli4j', version: "${brotli4jVersion}") { + transitive = false + } + externalJars(group: 'com.aayushatharva.brotli4j', name: 'service', version: "${brotli4jVersion}") { + transitive = false + } + externalJars(group: 'com.aayushatharva.brotli4j', name: 'native-linux-ppc64le', version: "${brotli4jVersion}") { + transitive = false + } + externalJars(group: 'com.aayushatharva.brotli4j', name: 'native-linux-x86_64', version: "${brotli4jVersion}") { + transitive = false + } + externalJars(group: 'com.aayushatharva.brotli4j', name: 'native-linux-aarch64', version: "${brotli4jVersion}") { + transitive = false + } + externalJars(group: 'com.aayushatharva.brotli4j', name: 'native-linux-armv7', version: "${brotli4jVersion}") { + transitive = false + } + externalJars(group: 'com.aayushatharva.brotli4j', name: 'native-linux-riscv64', version: "${brotli4jVersion}") { + transitive = false + } + externalJars(group: 'com.aayushatharva.brotli4j', name: 'native-osx-x86_64', version: "${brotli4jVersion}") { + transitive = false + } + externalJars(group: 'com.aayushatharva.brotli4j', name: 'native-osx-aarch64', version: "${brotli4jVersion}") { + transitive = false + } + externalJars(group: 'com.aayushatharva.brotli4j', name: 'native-windows-x86_64', version: "${brotli4jVersion}") { + transitive = false + } + externalJars(group: 'com.aayushatharva.brotli4j', name: 'native-windows-aarch64', version: "${brotli4jVersion}") { + transitive = false + } } task updateTomlFiles { @@ -164,6 +198,7 @@ task updateTomlFiles { def stdlibDependentLz4Version = project.lz4Version def stdlibDependentMarshallingVersion = project.marshallingVersion def stdlibDependentProtobufVersion = project.protobufVersion + def stdlibDependentBrotli4jVersion = project.brotli4jVersion def newBallerinaToml = ballerinaTomlFilePlaceHolder.text.replace("@project.version@", project.version) newBallerinaToml = newBallerinaToml.replace("@toml.version@", tomlVersion) @@ -180,6 +215,7 @@ task updateTomlFiles { newBallerinaToml = newBallerinaToml.replace("@lz4.version@", stdlibDependentLz4Version) newBallerinaToml = newBallerinaToml.replace("@marshalling.version@", stdlibDependentMarshallingVersion) newBallerinaToml = newBallerinaToml.replace("@protobuf.version@", stdlibDependentProtobufVersion) + newBallerinaToml = newBallerinaToml.replace("@brotli4j.version@", stdlibDependentBrotli4jVersion) ballerinaTomlFile.text = newBallerinaToml def newCompilerPluginToml = compilerPluginTomlFilePlaceHolder.text.replace("@project.version@", project.version) diff --git a/build-config/resources/Ballerina.toml b/build-config/resources/Ballerina.toml index efc9e20756..d3547b5aaa 100644 --- a/build-config/resources/Ballerina.toml +++ b/build-config/resources/Ballerina.toml @@ -171,3 +171,69 @@ groupId = "com.google.protobufl" artifactId = "protobuf-java" version = "@protobuf.version@" path = "./lib/protobuf-java-@protobuf.version@.jar" + +[[platform.java17.dependency]] +groupId = "com.aayushatharva.brotli4j" +artifactId = "brotli4j" +version = "@brotli4j.version@" +path = "./lib/brotli4j-@brotli4j.version@.jar" + +[[platform.java17.dependency]] +groupId = "com.aayushatharva.brotli4j" +artifactId = "service" +version = "@brotli4j.version@" +path = "./lib/service-@brotli4j.version@.jar" + +[[platform.java17.dependency]] +groupId = "com.aayushatharva.brotli4j" +artifactId = "native-linux-ppc64le" +version = "@brotli4j.version@" +path = "./lib/native-linux-ppc64le-@brotli4j.version@.jar" + +[[platform.java17.dependency]] +groupId = "com.aayushatharva.brotli4j" +artifactId = "native-linux-x86_64" +version = "@brotli4j.version@" +path = "./lib/native-linux-x86_64-@brotli4j.version@.jar" + +[[platform.java17.dependency]] +groupId = "com.aayushatharva.brotli4j" +artifactId = "native-linux-aarch64" +version = "@brotli4j.version@" +path = "./lib/native-linux-aarch64-@brotli4j.version@.jar" + +[[platform.java17.dependency]] +groupId = "com.aayushatharva.brotli4j" +artifactId = "native-linux-armv7" +version = "@brotli4j.version@" +path = "./lib/native-linux-armv7-@brotli4j.version@.jar" + +[[platform.java17.dependency]] +groupId = "com.aayushatharva.brotli4j" +artifactId = "native-linux-riscv64" +version = "@brotli4j.version@" +path = "./lib/native-linux-riscv64-@brotli4j.version@.jar" + +[[platform.java17.dependency]] +groupId = "com.aayushatharva.brotli4j" +artifactId = "native-osx-x86_64" +version = "@brotli4j.version@" +path = "./lib/native-osx-x86_64-@brotli4j.version@.jar" + +[[platform.java17.dependency]] +groupId = "com.aayushatharva.brotli4j" +artifactId = "native-osx-aarch64" +version = "@brotli4j.version@" +path = "./lib/native-osx-aarch64-@brotli4j.version@.jar" + +[[platform.java17.dependency]] +groupId = "com.aayushatharva.brotli4j" +artifactId = "native-windows-x86_64" +version = "@brotli4j.version@" +path = "./lib/native-windows-x86_64-@brotli4j.version@.jar" + +[[platform.java17.dependency]] +groupId = "com.aayushatharva.brotli4j" +artifactId = "native-windows-aarch64" +version = "@brotli4j.version@" +path = "./lib/native-windows-aarch64-@brotli4j.version@.jar" diff --git a/gradle.properties b/gradle.properties index 8010139ba7..d40425133b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -23,6 +23,7 @@ lz4Version=1.3.0 marshallingVersion=2.0.5.Final protobufVersion=3.20.3 jacocoVersion=0.8.10 +brotli4jVersion=1.16.0 stdlibIoVersion=1.6.0 stdlibTimeVersion=2.4.0 diff --git a/native/build.gradle b/native/build.gradle index 64d9a6aea1..3fd96eb3d4 100644 --- a/native/build.gradle +++ b/native/build.gradle @@ -65,6 +65,17 @@ dependencies { implementation group: 'org.bouncycastle', name: 'bcutil-jdk18on', version: "${bouncycastleVersion}" implementation group: 'org.bouncycastle', name: 'bcpkix-jdk18on', version: "${bouncycastleVersion}" implementation group: 'jakarta.xml.bind', name: 'jakarta.xml.bind-api', version: "${jakartaXmlBindVersion}" + implementation group: 'com.aayushatharva.brotli4j', name: 'brotli4j', version: "${brotli4jVersion}" + implementation group: 'com.aayushatharva.brotli4j', name: 'service', version: "${brotli4jVersion}" + implementation group: 'com.aayushatharva.brotli4j', name: 'native-linux-ppc64le', version: "${brotli4jVersion}" + implementation group: 'com.aayushatharva.brotli4j', name: 'native-linux-x86_64', version: "${brotli4jVersion}" + implementation group: 'com.aayushatharva.brotli4j', name: 'native-linux-aarch64', version: "${brotli4jVersion}" + implementation group: 'com.aayushatharva.brotli4j', name: 'native-linux-armv7', version: "${brotli4jVersion}" + implementation group: 'com.aayushatharva.brotli4j', name: 'native-linux-riscv64', version: "${brotli4jVersion}" + implementation group: 'com.aayushatharva.brotli4j', name: 'native-osx-x86_64', version: "${brotli4jVersion}" + implementation group: 'com.aayushatharva.brotli4j', name: 'native-osx-aarch64', version: "${brotli4jVersion}" + implementation group: 'com.aayushatharva.brotli4j', name: 'native-windows-x86_64', version: "${brotli4jVersion}" + implementation group: 'com.aayushatharva.brotli4j', name: 'native-windows-aarch64', version: "${brotli4jVersion}" testImplementation group: 'org.mock-server', name: 'mockserver-netty', version:"${mockserverNettyVersion}" testImplementation group: 'com.mashape.unirest', name: 'unirest-java', version:"${unirestVersion}" diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/client/actions/AbstractHTTPAction.java b/native/src/main/java/io/ballerina/stdlib/http/api/client/actions/AbstractHTTPAction.java index b4b718cf24..2941eb97cd 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/client/actions/AbstractHTTPAction.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/client/actions/AbstractHTTPAction.java @@ -73,6 +73,7 @@ import static io.ballerina.stdlib.http.api.HttpConstants.SET_HOST_HEADER; import static io.ballerina.stdlib.http.api.HttpUtil.extractEntity; import static io.ballerina.stdlib.http.api.HttpUtil.getCompressionState; +import static io.ballerina.stdlib.http.transport.contract.Constants.ENCODING_BR; import static io.ballerina.stdlib.http.transport.contract.Constants.ENCODING_DEFLATE; import static io.ballerina.stdlib.http.transport.contract.Constants.ENCODING_GZIP; import static io.netty.handler.codec.http.HttpHeaderNames.ACCEPT_ENCODING; @@ -109,7 +110,8 @@ static void handleAcceptEncodingHeader(HttpCarbonMessage outboundRequest, String if (compressionState == CompressionConfigState.ALWAYS && (outboundRequest.getHeader( ACCEPT_ENCODING.toString()) == null)) { - outboundRequest.setHeader(ACCEPT_ENCODING.toString(), ENCODING_DEFLATE + ", " + ENCODING_GZIP); + outboundRequest.setHeader(ACCEPT_ENCODING.toString(), ENCODING_DEFLATE + ", " + ENCODING_GZIP + ", " + + ENCODING_BR); } else if (compressionState == CompressionConfigState.NEVER && (outboundRequest.getHeader( ACCEPT_ENCODING.toString()) != null)) { outboundRequest.removeHeader(ACCEPT_ENCODING.toString()); diff --git a/native/src/main/java/io/ballerina/stdlib/http/transport/contract/Constants.java b/native/src/main/java/io/ballerina/stdlib/http/transport/contract/Constants.java index 5f9f282e7a..82a62ce98a 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/transport/contract/Constants.java +++ b/native/src/main/java/io/ballerina/stdlib/http/transport/contract/Constants.java @@ -119,6 +119,7 @@ public final class Constants { public static final String ENCODING_GZIP = "gzip"; public static final String ENCODING_DEFLATE = "deflate"; + public static final String ENCODING_BR = "br"; public static final String HTTP_TRANSFER_ENCODING_IDENTITY = "identity"; // TODO: Move string constants for HTTP headers and header values to their own class diff --git a/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/Http2OutboundRespListener.java b/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/Http2OutboundRespListener.java index db4737c739..81aca08da3 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/Http2OutboundRespListener.java +++ b/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/Http2OutboundRespListener.java @@ -40,6 +40,11 @@ import io.ballerina.stdlib.http.transport.message.PassthroughBackPressureListener; import io.ballerina.stdlib.http.transport.message.ServerRemoteFlowControlListener; import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.compression.Brotli; +import io.netty.handler.codec.compression.BrotliOptions; +import io.netty.handler.codec.compression.DeflateOptions; +import io.netty.handler.codec.compression.GzipOptions; +import io.netty.handler.codec.compression.StandardCompressionOptions; import io.netty.handler.codec.http.HttpContent; import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http2.Http2Connection; @@ -52,6 +57,7 @@ import java.util.Calendar; import java.util.concurrent.atomic.AtomicBoolean; +import static io.ballerina.stdlib.http.transport.contract.Constants.ENCODING_BR; import static io.ballerina.stdlib.http.transport.contract.Constants.ENCODING_DEFLATE; import static io.ballerina.stdlib.http.transport.contract.Constants.ENCODING_GZIP; import static io.ballerina.stdlib.http.transport.contract.Constants.PROMISED_STREAM_REJECTED_ERROR; @@ -80,6 +86,10 @@ public class Http2OutboundRespListener implements HttpConnectorListener { private ResponseWriter defaultResponseWriter; private Http2ServerChannel http2ServerChannel; + private final BrotliOptions brotliOptions; + private final GzipOptions gzipOptions; + private final DeflateOptions deflateOptions; + public Http2OutboundRespListener(HttpServerChannelInitializer serverChannelInitializer, HttpCarbonMessage inboundRequestMsg, ChannelHandlerContext ctx, Http2Connection conn, Http2ConnectionEncoder encoder, int streamId, @@ -101,6 +111,10 @@ public Http2OutboundRespListener(HttpServerChannelInitializer serverChannelIniti http2MessageStateContext = inboundRequestMsg.getHttp2MessageStateContext(); this.remoteFlowControlListener = remoteFlowControlListener; this.http2ServerChannel = http2ServerChannel; + + this.gzipOptions = StandardCompressionOptions.gzip(); + this.deflateOptions = StandardCompressionOptions.deflate(); + this.brotliOptions = Brotli.isAvailable() ? StandardCompressionOptions.brotli() : null; } @Override @@ -178,7 +192,7 @@ private void setContentEncoding(HttpCarbonMessage outboundResponseMsg) { if (contentEncoding == null) { String acceptEncoding = inboundRequestMsg.getHeader(HttpHeaderNames.ACCEPT_ENCODING.toString()); if (acceptEncoding != null) { - String targetContentEncoding = determineScheme(acceptEncoding); + String targetContentEncoding = determineEncoding(acceptEncoding); if (targetContentEncoding != null) { outboundResponseMsg.setHeader(HttpHeaderNames.CONTENT_ENCODING.toString(), targetContentEncoding); } @@ -188,16 +202,18 @@ private void setContentEncoding(HttpCarbonMessage outboundResponseMsg) { /*** * This function is to determine one encoding scheme from the request's `accept-encoding` header. The logic to - * determine the scheme is similar to the logic used in Netty's `determineWrapper()` function in the + * determine the scheme is similar to the logic used in Netty's `determineEncoding()` function in the * `HttpContentCompressor` class which is used to do the same, when doing the HTTP1.1 compression. * * @param acceptEncoding `accept-encoding` header value * @return the chosen encoding scheme */ - private String determineScheme(String acceptEncoding) { + private String determineEncoding(String acceptEncoding) { float starQ = -1.0f; float gzipQ = -1.0f; float deflateQ = -1.0f; + float brQ = -1.0f; + for (String encoding : acceptEncoding.split(",")) { float qValue = 1.0f; int equalsPos = encoding.indexOf('='); @@ -211,6 +227,8 @@ private String determineScheme(String acceptEncoding) { } if (encoding.contains("*")) { starQ = qValue; + } else if (encoding.contains(ENCODING_BR) && qValue > brQ) { + brQ = qValue; } else if (encoding.contains(ENCODING_GZIP) && qValue > gzipQ) { gzipQ = qValue; } else if (encoding.contains(ENCODING_DEFLATE) && qValue > deflateQ) { @@ -219,18 +237,29 @@ private String determineScheme(String acceptEncoding) { LOG.debug("Server does not support the requested encoding scheme: {}", encoding); } } - if (gzipQ > 0.0f || deflateQ > 0.0f) { - if (gzipQ >= deflateQ) { + if (gzipQ > 0.0f || deflateQ > 0.0f || brQ > 0.0f) { + if (brQ != -1.0f && brQ >= gzipQ && this.brotliOptions != null) { + return ENCODING_BR; + } + + if (gzipQ != -1.0f && gzipQ >= deflateQ && this.gzipOptions != null) { return ENCODING_GZIP; - } else { + } + + if (deflateQ != -1.0f && this.deflateOptions != null) { return ENCODING_DEFLATE; } } if (starQ > 0.0f) { - if (gzipQ == -1.0f) { + if (brQ == -1.0f && this.brotliOptions != null) { + return ENCODING_BR; + } + + if (gzipQ == -1.0f && this.gzipOptions != null) { return ENCODING_GZIP; } - if (deflateQ == -1.0f) { + + if (deflateQ == -1.0f && this.deflateOptions != null) { return ENCODING_DEFLATE; } } diff --git a/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/listener/CustomHttpContentCompressor.java b/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/listener/CustomHttpContentCompressor.java index c7ee6e3667..2f742e16a7 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/listener/CustomHttpContentCompressor.java +++ b/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/listener/CustomHttpContentCompressor.java @@ -1,6 +1,7 @@ package io.ballerina.stdlib.http.transport.contractimpl.listener; import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.compression.StandardCompressionOptions; import io.netty.handler.codec.http.HttpContentCompressor; import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpMethod; @@ -17,7 +18,8 @@ public class CustomHttpContentCompressor extends HttpContentCompressor { private HttpMethod method; public CustomHttpContentCompressor() { - super(); + super(StandardCompressionOptions.gzip(), StandardCompressionOptions.deflate(), + StandardCompressionOptions.brotli()); } @Override diff --git a/native/src/main/java/io/ballerina/stdlib/http/transport/message/HttpMessageDataStreamer.java b/native/src/main/java/io/ballerina/stdlib/http/transport/message/HttpMessageDataStreamer.java index 6ea0b3e0e3..265bfc5f59 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/transport/message/HttpMessageDataStreamer.java +++ b/native/src/main/java/io/ballerina/stdlib/http/transport/message/HttpMessageDataStreamer.java @@ -18,6 +18,8 @@ package io.ballerina.stdlib.http.transport.message; +import com.aayushatharva.brotli4j.Brotli4jLoader; +import com.aayushatharva.brotli4j.decoder.BrotliInputStream; import io.ballerina.stdlib.http.transport.contract.Constants; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; @@ -210,6 +212,9 @@ public InputStream getInputStream() { return new GZIPInputStream(createInputStreamIfNull()); } else if (contentEncodingHeader.equalsIgnoreCase(Constants.ENCODING_DEFLATE)) { return new InflaterInputStream(createInputStreamIfNull()); + } else if (contentEncodingHeader.equalsIgnoreCase(Constants.ENCODING_BR)) { + Brotli4jLoader.ensureAvailability(); + return new BrotliInputStream(createInputStreamIfNull()); } else if (!contentEncodingHeader.equalsIgnoreCase(Constants.HTTP_TRANSFER_ENCODING_IDENTITY)) { LOG.warn("Unknown Content-Encoding: {}", contentEncodingHeader); } diff --git a/native/src/main/java/module-info.java b/native/src/main/java/module-info.java index 775a814f2d..7d23ccd78b 100644 --- a/native/src/main/java/module-info.java +++ b/native/src/main/java/module-info.java @@ -41,6 +41,7 @@ requires io.netty.handler; requires commons.pool; requires io.netty.handler.proxy; + requires com.aayushatharva.brotli4j; exports io.ballerina.stdlib.http.api; exports io.ballerina.stdlib.http.transport.contract.websocket; exports io.ballerina.stdlib.http.transport.contract; From 3be5f578d6a37d570c5e7fd2184599e0a80dc098 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Fri, 17 May 2024 10:20:45 +0530 Subject: [PATCH 02/11] Fix compression test case --- .../ResponseBodyCompressionTestCase.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/native/src/test/java/io/ballerina/stdlib/http/transport/http2/compression/ResponseBodyCompressionTestCase.java b/native/src/test/java/io/ballerina/stdlib/http/transport/http2/compression/ResponseBodyCompressionTestCase.java index 7c1636d160..561eedbee1 100644 --- a/native/src/test/java/io/ballerina/stdlib/http/transport/http2/compression/ResponseBodyCompressionTestCase.java +++ b/native/src/test/java/io/ballerina/stdlib/http/transport/http2/compression/ResponseBodyCompressionTestCase.java @@ -86,9 +86,19 @@ public void testResponseBodyCompression() throws Exception { streamId = streamId + 2; responseHandler = h2ClientWithoutDecompressor.sendPostRequest(PAYLOAD, streamId, "deflate;q=1.0, gzip;q=0.8"); - assertCompressedResults("deflate", responseHandler.getFullResponse(streamId), + assertCompressedResults(Constants.ENCODING_DEFLATE, responseHandler.getFullResponse(streamId), responseHandler.getResponsePayload(streamId)); + streamId = streamId + 2; + responseHandler = h2ClientWithoutDecompressor.sendPostRequest(PAYLOAD, streamId, "br"); + assertCompressedResults(Constants.ENCODING_BR, responseHandler.getFullResponse(streamId), + responseHandler.getResponsePayload(streamId)); + + streamId = streamId + 2; + responseHandler = h2ClientWithoutDecompressor.sendPostRequest(PAYLOAD, streamId, "br, deflate"); + assertCompressedResults(Constants.ENCODING_BR, responseHandler.getFullResponse(streamId), + responseHandler.getResponsePayload(streamId)); + streamId = streamId + 2; responseHandler = h2ClientWithoutDecompressor.sendPostRequest(PAYLOAD, streamId, null); assertPlainResults(responseHandler.getFullResponse(streamId), responseHandler.getResponsePayload(streamId)); @@ -99,11 +109,11 @@ public void testResponseBodyCompression() throws Exception { assertPlainResults(responseHandler.getFullResponse(streamId), responseHandler.getResponsePayload(streamId)); streamId = streamId + 2; - responseHandler = h2ClientWithoutDecompressor.sendPostRequest(PAYLOAD, streamId, "sdch, br"); + responseHandler = h2ClientWithoutDecompressor.sendPostRequest(PAYLOAD, streamId, "sdch, snappy"); assertPlainResults(responseHandler.getFullResponse(streamId), responseHandler.getResponsePayload(streamId)); streamId = streamId + 2; - responseHandler = h2ClientWithoutDecompressor.sendPostRequest(PAYLOAD, streamId, "sdch, br, deflate"); + responseHandler = h2ClientWithoutDecompressor.sendPostRequest(PAYLOAD, streamId, "sdch, snappy, deflate"); assertCompressedResults("deflate", responseHandler.getFullResponse(streamId), responseHandler.getResponsePayload(streamId)); } From 89915a8d170f11e976e7002a4d6d8202fc43c7e0 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Fri, 17 May 2024 10:39:58 +0530 Subject: [PATCH 03/11] [Automated] Update the native jar versions --- ballerina/Ballerina.toml | 72 +++++++++++++++++++++++++++++++++-- ballerina/CompilerPlugin.toml | 2 +- ballerina/Dependencies.toml | 4 +- 3 files changed, 72 insertions(+), 6 deletions(-) diff --git a/ballerina/Ballerina.toml b/ballerina/Ballerina.toml index 26dc5190d7..79f0eaf981 100644 --- a/ballerina/Ballerina.toml +++ b/ballerina/Ballerina.toml @@ -1,7 +1,7 @@ [package] org = "ballerina" name = "http" -version = "2.11.0" +version = "2.11.1" authors = ["Ballerina"] keywords = ["http", "network", "service", "listener", "client"] repository = "https://github.com/ballerina-platform/module-ballerina-http" @@ -16,8 +16,8 @@ graalvmCompatible = true [[platform.java17.dependency]] groupId = "io.ballerina.stdlib" artifactId = "http-native" -version = "2.11.0" -path = "../native/build/libs/http-native-2.11.0.jar" +version = "2.11.1" +path = "../native/build/libs/http-native-2.11.1-SNAPSHOT.jar" [[platform.java17.dependency]] groupId = "io.ballerina.stdlib" @@ -171,3 +171,69 @@ groupId = "com.google.protobufl" artifactId = "protobuf-java" version = "3.20.3" path = "./lib/protobuf-java-3.20.3.jar" + +[[platform.java17.dependency]] +groupId = "com.aayushatharva.brotli4j" +artifactId = "brotli4j" +version = "1.16.0" +path = "./lib/brotli4j-1.16.0.jar" + +[[platform.java17.dependency]] +groupId = "com.aayushatharva.brotli4j" +artifactId = "service" +version = "1.16.0" +path = "./lib/service-1.16.0.jar" + +[[platform.java17.dependency]] +groupId = "com.aayushatharva.brotli4j" +artifactId = "native-linux-ppc64le" +version = "1.16.0" +path = "./lib/native-linux-ppc64le-1.16.0.jar" + +[[platform.java17.dependency]] +groupId = "com.aayushatharva.brotli4j" +artifactId = "native-linux-x86_64" +version = "1.16.0" +path = "./lib/native-linux-x86_64-1.16.0.jar" + +[[platform.java17.dependency]] +groupId = "com.aayushatharva.brotli4j" +artifactId = "native-linux-aarch64" +version = "1.16.0" +path = "./lib/native-linux-aarch64-1.16.0.jar" + +[[platform.java17.dependency]] +groupId = "com.aayushatharva.brotli4j" +artifactId = "native-linux-armv7" +version = "1.16.0" +path = "./lib/native-linux-armv7-1.16.0.jar" + +[[platform.java17.dependency]] +groupId = "com.aayushatharva.brotli4j" +artifactId = "native-linux-riscv64" +version = "1.16.0" +path = "./lib/native-linux-riscv64-1.16.0.jar" + +[[platform.java17.dependency]] +groupId = "com.aayushatharva.brotli4j" +artifactId = "native-osx-x86_64" +version = "1.16.0" +path = "./lib/native-osx-x86_64-1.16.0.jar" + +[[platform.java17.dependency]] +groupId = "com.aayushatharva.brotli4j" +artifactId = "native-osx-aarch64" +version = "1.16.0" +path = "./lib/native-osx-aarch64-1.16.0.jar" + +[[platform.java17.dependency]] +groupId = "com.aayushatharva.brotli4j" +artifactId = "native-windows-x86_64" +version = "1.16.0" +path = "./lib/native-windows-x86_64-1.16.0.jar" + +[[platform.java17.dependency]] +groupId = "com.aayushatharva.brotli4j" +artifactId = "native-windows-aarch64" +version = "1.16.0" +path = "./lib/native-windows-aarch64-1.16.0.jar" diff --git a/ballerina/CompilerPlugin.toml b/ballerina/CompilerPlugin.toml index 6e6d0a2804..94ed7849c8 100644 --- a/ballerina/CompilerPlugin.toml +++ b/ballerina/CompilerPlugin.toml @@ -3,4 +3,4 @@ id = "http-compiler-plugin" class = "io.ballerina.stdlib.http.compiler.HttpCompilerPlugin" [[dependency]] -path = "../compiler-plugin/build/libs/http-compiler-plugin-2.11.0.jar" +path = "../compiler-plugin/build/libs/http-compiler-plugin-2.11.1-SNAPSHOT.jar" diff --git a/ballerina/Dependencies.toml b/ballerina/Dependencies.toml index f160e6f988..2d75978fdb 100644 --- a/ballerina/Dependencies.toml +++ b/ballerina/Dependencies.toml @@ -50,7 +50,7 @@ modules = [ [[package]] org = "ballerina" name = "crypto" -version = "2.7.0" +version = "2.7.1" dependencies = [ {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "time"} @@ -76,7 +76,7 @@ modules = [ [[package]] org = "ballerina" name = "http" -version = "2.11.0" +version = "2.11.1" dependencies = [ {org = "ballerina", name = "auth"}, {org = "ballerina", name = "cache"}, From 30a4e1afaeb44f74fe47ddd9c500b254f7c8e9c9 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Fri, 17 May 2024 10:51:17 +0530 Subject: [PATCH 04/11] [Automated] Update the native jar versions --- ballerina-tests/http-advanced-tests/Ballerina.toml | 6 +++--- ballerina-tests/http-client-tests/Ballerina.toml | 6 +++--- ballerina-tests/http-dispatching-tests/Ballerina.toml | 6 +++--- ballerina-tests/http-interceptor-tests/Ballerina.toml | 6 +++--- ballerina-tests/http-misc-tests/Ballerina.toml | 6 +++--- ballerina-tests/http-resiliency-tests/Ballerina.toml | 6 +++--- ballerina-tests/http-security-tests/Ballerina.toml | 6 +++--- ballerina-tests/http-service-tests/Ballerina.toml | 6 +++--- ballerina-tests/http-test-common/Ballerina.toml | 2 +- ballerina-tests/http-test-common/Dependencies.toml | 2 +- ballerina-tests/http2-tests/Ballerina.toml | 6 +++--- ballerina-tests/http2-tests/Dependencies.toml | 8 ++++---- 12 files changed, 33 insertions(+), 33 deletions(-) diff --git a/ballerina-tests/http-advanced-tests/Ballerina.toml b/ballerina-tests/http-advanced-tests/Ballerina.toml index b1ec75e241..72d5caca67 100644 --- a/ballerina-tests/http-advanced-tests/Ballerina.toml +++ b/ballerina-tests/http-advanced-tests/Ballerina.toml @@ -1,17 +1,17 @@ [package] org = "ballerina" name = "http_advanced_tests" -version = "2.11.0" +version = "2.11.1" [[dependency]] org = "ballerina" name = "http_test_common" repository = "local" -version = "2.11.0" +version = "2.11.1" [platform.java17] graalvmCompatible = true [[platform.java17.dependency]] scope = "testOnly" -path = "../../test-utils/build/libs/http-test-utils-2.11.0.jar" +path = "../../test-utils/build/libs/http-test-utils-2.11.1-SNAPSHOT.jar" diff --git a/ballerina-tests/http-client-tests/Ballerina.toml b/ballerina-tests/http-client-tests/Ballerina.toml index 5cb5a402e5..eb14d27cb5 100644 --- a/ballerina-tests/http-client-tests/Ballerina.toml +++ b/ballerina-tests/http-client-tests/Ballerina.toml @@ -1,17 +1,17 @@ [package] org = "ballerina" name = "http_client_tests" -version = "2.11.0" +version = "2.11.1" [[dependency]] org = "ballerina" name = "http_test_common" repository = "local" -version = "2.11.0" +version = "2.11.1" [platform.java17] graalvmCompatible = true [[platform.java17.dependency]] scope = "testOnly" -path = "../../test-utils/build/libs/http-test-utils-2.11.0.jar" +path = "../../test-utils/build/libs/http-test-utils-2.11.1-SNAPSHOT.jar" diff --git a/ballerina-tests/http-dispatching-tests/Ballerina.toml b/ballerina-tests/http-dispatching-tests/Ballerina.toml index 93aa2c861c..29ade01652 100644 --- a/ballerina-tests/http-dispatching-tests/Ballerina.toml +++ b/ballerina-tests/http-dispatching-tests/Ballerina.toml @@ -1,17 +1,17 @@ [package] org = "ballerina" name = "http_dispatching_tests" -version = "2.11.0" +version = "2.11.1" [[dependency]] org = "ballerina" name = "http_test_common" repository = "local" -version = "2.11.0" +version = "2.11.1" [platform.java17] graalvmCompatible = true [[platform.java17.dependency]] scope = "testOnly" -path = "../../test-utils/build/libs/http-test-utils-2.11.0.jar" +path = "../../test-utils/build/libs/http-test-utils-2.11.1-SNAPSHOT.jar" diff --git a/ballerina-tests/http-interceptor-tests/Ballerina.toml b/ballerina-tests/http-interceptor-tests/Ballerina.toml index 3da3988af0..0d5fabd411 100644 --- a/ballerina-tests/http-interceptor-tests/Ballerina.toml +++ b/ballerina-tests/http-interceptor-tests/Ballerina.toml @@ -1,17 +1,17 @@ [package] org = "ballerina" name = "http_interceptor_tests" -version = "2.11.0" +version = "2.11.1" [[dependency]] org = "ballerina" name = "http_test_common" repository = "local" -version = "2.11.0" +version = "2.11.1" [platform.java17] graalvmCompatible = true [[platform.java17.dependency]] scope = "testOnly" -path = "../../test-utils/build/libs/http-test-utils-2.11.0.jar" +path = "../../test-utils/build/libs/http-test-utils-2.11.1-SNAPSHOT.jar" diff --git a/ballerina-tests/http-misc-tests/Ballerina.toml b/ballerina-tests/http-misc-tests/Ballerina.toml index 678be821b7..66279c6f92 100644 --- a/ballerina-tests/http-misc-tests/Ballerina.toml +++ b/ballerina-tests/http-misc-tests/Ballerina.toml @@ -1,17 +1,17 @@ [package] org = "ballerina" name = "http_misc_tests" -version = "2.11.0" +version = "2.11.1" [[dependency]] org = "ballerina" name = "http_test_common" repository = "local" -version = "2.11.0" +version = "2.11.1" [platform.java17] graalvmCompatible = true [[platform.java17.dependency]] scope = "testOnly" -path = "../../test-utils/build/libs/http-test-utils-2.11.0.jar" +path = "../../test-utils/build/libs/http-test-utils-2.11.1-SNAPSHOT.jar" diff --git a/ballerina-tests/http-resiliency-tests/Ballerina.toml b/ballerina-tests/http-resiliency-tests/Ballerina.toml index 5e045f5f2a..c991a7f9ad 100644 --- a/ballerina-tests/http-resiliency-tests/Ballerina.toml +++ b/ballerina-tests/http-resiliency-tests/Ballerina.toml @@ -1,17 +1,17 @@ [package] org = "ballerina" name = "http_resiliency_tests" -version = "2.11.0" +version = "2.11.1" [[dependency]] org = "ballerina" name = "http_test_common" repository = "local" -version = "2.11.0" +version = "2.11.1" [platform.java17] graalvmCompatible = true [[platform.java17.dependency]] scope = "testOnly" -path = "../../test-utils/build/libs/http-test-utils-2.11.0.jar" +path = "../../test-utils/build/libs/http-test-utils-2.11.1-SNAPSHOT.jar" diff --git a/ballerina-tests/http-security-tests/Ballerina.toml b/ballerina-tests/http-security-tests/Ballerina.toml index 2d16dd19ad..b1fbe2d86c 100644 --- a/ballerina-tests/http-security-tests/Ballerina.toml +++ b/ballerina-tests/http-security-tests/Ballerina.toml @@ -1,17 +1,17 @@ [package] org = "ballerina" name = "http_security_tests" -version = "2.11.0" +version = "2.11.1" [[dependency]] org = "ballerina" name = "http_test_common" repository = "local" -version = "2.11.0" +version = "2.11.1" [platform.java17] graalvmCompatible = true [[platform.java17.dependency]] scope = "testOnly" -path = "../../test-utils/build/libs/http-test-utils-2.11.0.jar" +path = "../../test-utils/build/libs/http-test-utils-2.11.1-SNAPSHOT.jar" diff --git a/ballerina-tests/http-service-tests/Ballerina.toml b/ballerina-tests/http-service-tests/Ballerina.toml index 6fafd82909..79c4763805 100644 --- a/ballerina-tests/http-service-tests/Ballerina.toml +++ b/ballerina-tests/http-service-tests/Ballerina.toml @@ -1,17 +1,17 @@ [package] org = "ballerina" name = "http_service_tests" -version = "2.11.0" +version = "2.11.1" [[dependency]] org = "ballerina" name = "http_test_common" repository = "local" -version = "2.11.0" +version = "2.11.1" [platform.java17] graalvmCompatible = true [[platform.java17.dependency]] scope = "testOnly" -path = "../../test-utils/build/libs/http-test-utils-2.11.0.jar" +path = "../../test-utils/build/libs/http-test-utils-2.11.1-SNAPSHOT.jar" diff --git a/ballerina-tests/http-test-common/Ballerina.toml b/ballerina-tests/http-test-common/Ballerina.toml index e7b61366b7..58f1cb03ab 100644 --- a/ballerina-tests/http-test-common/Ballerina.toml +++ b/ballerina-tests/http-test-common/Ballerina.toml @@ -1,4 +1,4 @@ [package] org = "ballerina" name = "http_test_common" -version = "2.11.0" +version = "2.11.1" diff --git a/ballerina-tests/http-test-common/Dependencies.toml b/ballerina-tests/http-test-common/Dependencies.toml index acfa2c1956..fcb61bbb2e 100644 --- a/ballerina-tests/http-test-common/Dependencies.toml +++ b/ballerina-tests/http-test-common/Dependencies.toml @@ -10,7 +10,7 @@ distribution-version = "2201.9.0" [[package]] org = "ballerina" name = "http_test_common" -version = "2.11.0" +version = "2.11.1" dependencies = [ {org = "ballerina", name = "lang.string"}, {org = "ballerina", name = "mime"}, diff --git a/ballerina-tests/http2-tests/Ballerina.toml b/ballerina-tests/http2-tests/Ballerina.toml index bb03dca848..a2206a5486 100644 --- a/ballerina-tests/http2-tests/Ballerina.toml +++ b/ballerina-tests/http2-tests/Ballerina.toml @@ -1,17 +1,17 @@ [package] org = "ballerina" name = "http2_tests" -version = "2.11.0" +version = "2.11.1" [[dependency]] org = "ballerina" name = "http_test_common" repository = "local" -version = "2.11.0" +version = "2.11.1" [platform.java17] graalvmCompatible = true [[platform.java17.dependency]] scope = "testOnly" -path = "../../test-utils/build/libs/http-test-utils-2.11.0.jar" +path = "../../test-utils/build/libs/http-test-utils-2.11.1-SNAPSHOT.jar" diff --git a/ballerina-tests/http2-tests/Dependencies.toml b/ballerina-tests/http2-tests/Dependencies.toml index 1cc1e0aa10..eb76a56238 100644 --- a/ballerina-tests/http2-tests/Dependencies.toml +++ b/ballerina-tests/http2-tests/Dependencies.toml @@ -44,7 +44,7 @@ dependencies = [ [[package]] org = "ballerina" name = "crypto" -version = "2.7.0" +version = "2.7.1" scope = "testOnly" dependencies = [ {org = "ballerina", name = "jballerina.java"}, @@ -69,7 +69,7 @@ modules = [ [[package]] org = "ballerina" name = "http" -version = "2.11.0" +version = "2.11.1" scope = "testOnly" dependencies = [ {org = "ballerina", name = "auth"}, @@ -102,7 +102,7 @@ modules = [ [[package]] org = "ballerina" name = "http2_tests" -version = "2.11.0" +version = "2.11.1" dependencies = [ {org = "ballerina", name = "file"}, {org = "ballerina", name = "http"}, @@ -121,7 +121,7 @@ modules = [ [[package]] org = "ballerina" name = "http_test_common" -version = "2.11.0" +version = "2.11.1" scope = "testOnly" dependencies = [ {org = "ballerina", name = "lang.string"}, From da6e6ed0f74a008f52602fe403488676482d2db7 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Fri, 17 May 2024 14:42:57 +0530 Subject: [PATCH 05/11] Update changelog --- changelog.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/changelog.md b/changelog.md index 223f928814..32e5686a4a 100644 --- a/changelog.md +++ b/changelog.md @@ -5,6 +5,12 @@ This file contains all the notable changes done to the Ballerina HTTP package th The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Added + +- [Add compression/decompression support for `brotli` compression format](https://github.com/ballerina-platform/ballerina-library/issues/6547) + ## [2.11.0] - 2024-05-03 ### Added From 5ee556ba61ab39e6537efdde92f94fdbec7fda41 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Fri, 17 May 2024 18:37:08 +0530 Subject: [PATCH 06/11] Add native image configurations --- .../http-native/native-image.properties | 2 ++ .../http-native/resource-config.json | 30 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/native/src/main/resources/META-INF/native-image/io.ballerina.stdlib/http-native/native-image.properties b/native/src/main/resources/META-INF/native-image/io.ballerina.stdlib/http-native/native-image.properties index bffdde3712..c278e79bee 100644 --- a/native/src/main/resources/META-INF/native-image/io.ballerina.stdlib/http-native/native-image.properties +++ b/native/src/main/resources/META-INF/native-image/io.ballerina.stdlib/http-native/native-image.properties @@ -29,4 +29,6 @@ Args = --enable-url-protocols=http,https \ --initialize-at-run-time=io.netty.internal.tcnative.CertificateVerifier \ --initialize-at-run-time=io.netty.internal.tcnative.SSL \ --initialize-at-run-time=io.netty.internal.tcnative.SSLPrivateKeyMethod \ + --initialize-at-run-time=io.netty.handler.codec.compression.Brotli \ + --initialize-at-run-time=io.netty.handler.codec.compression.BrotliOptions \ -J--add-opens=java.base/java.nio=ALL-UNNAMED diff --git a/native/src/main/resources/META-INF/native-image/io.ballerina.stdlib/http-native/resource-config.json b/native/src/main/resources/META-INF/native-image/io.ballerina.stdlib/http-native/resource-config.json index 4d2de3167f..75b4520994 100644 --- a/native/src/main/resources/META-INF/native-image/io.ballerina.stdlib/http-native/resource-config.json +++ b/native/src/main/resources/META-INF/native-image/io.ballerina.stdlib/http-native/resource-config.json @@ -18,6 +18,36 @@ }, { "pattern": "\\Qlogging.properties\\E" + }, + { + "pattern":"\\Qlib/linux-aarch64/libbrotli.so\\E" + }, + { + "pattern":"\\Qlib/linux-armv7/libbrotli.so\\E" + }, + { + "pattern":"\\Qlib/linux-ppc64le/libbrotli.so\\E" + }, + { + "pattern":"\\Qlib/linux-riscv64/libbrotli.so\\E" + }, + { + "pattern":"\\Qlib/linux-s390x/brotli.dll\\E" + }, + { + "pattern":"\\Qlib/linux-x86_64/libbrotli.so\\E" + }, + { + "pattern":"\\Qlib/osx-aarch64/libbrotli.dylib\\E" + }, + { + "pattern":"\\Qlib/osx-x86_64/libbrotli.dylib\\E" + }, + { + "pattern":"\\Qlib/windows-aarch64/brotli.dll\\E" + }, + { + "pattern":"\\Qlib/windows-x86_64/brotli.dll\\E" } ] } From 8ef5d5cc6d18981d0989be9b08d083a55e20596f Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Thu, 15 Aug 2024 16:57:21 +0530 Subject: [PATCH 07/11] Add brotli encoder support for HTTP2 --- .../http2/Http2SourceConnectionHandlerBuilder.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/listener/http2/Http2SourceConnectionHandlerBuilder.java b/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/listener/http2/Http2SourceConnectionHandlerBuilder.java index bb6117f7fc..f3f85fb382 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/listener/http2/Http2SourceConnectionHandlerBuilder.java +++ b/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/listener/http2/Http2SourceConnectionHandlerBuilder.java @@ -23,6 +23,7 @@ import io.ballerina.stdlib.http.transport.contractimpl.common.FrameLogger; import io.ballerina.stdlib.http.transport.contractimpl.listener.HttpServerChannelInitializer; import io.netty.channel.group.ChannelGroup; +import io.netty.handler.codec.compression.Brotli; import io.netty.handler.codec.compression.StandardCompressionOptions; import io.netty.handler.codec.http2.AbstractHttp2ConnectionHandlerBuilder; import io.netty.handler.codec.http2.CompressorHttp2ConnectionEncoder; @@ -84,12 +85,20 @@ public Http2SourceConnectionHandler build() { @Override public Http2SourceConnectionHandler build(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder, Http2Settings initialSettings) { - Http2ConnectionEncoder compressEncoder = new CompressorHttp2ConnectionEncoder( - encoder, StandardCompressionOptions.gzip(), StandardCompressionOptions.deflate()); + Http2ConnectionEncoder compressEncoder = getCompressEncoder(encoder); Http2SourceConnectionHandler sourceConnectionHandler = new Http2SourceConnectionHandler( serverChannelInitializer, decoder, compressEncoder, initialSettings, interfaceId, serverConnectorFuture, serverName, allChannels, listenerChannels); frameListener(sourceConnectionHandler.getHttp2FrameListener()); return sourceConnectionHandler; } + + private static Http2ConnectionEncoder getCompressEncoder(Http2ConnectionEncoder encoder) { + return Brotli.isAvailable() ? + new CompressorHttp2ConnectionEncoder(encoder, StandardCompressionOptions.gzip(), + StandardCompressionOptions.deflate(), + StandardCompressionOptions.brotli()) : + new CompressorHttp2ConnectionEncoder(encoder, StandardCompressionOptions.gzip(), + StandardCompressionOptions.deflate()); + } } From a8005ce6e450b9b29b6ff7d618730361076496d4 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Thu, 15 Aug 2024 17:30:42 +0530 Subject: [PATCH 08/11] Update the test case with brotli encoding support --- .../tests/configuration_accept_encoding_test.bal | 2 +- .../tests/http2_configuration_accept_encoding_test.bal | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ballerina-tests/http-misc-tests/tests/configuration_accept_encoding_test.bal b/ballerina-tests/http-misc-tests/tests/configuration_accept_encoding_test.bal index 8aebded714..2cdf9bb1d4 100644 --- a/ballerina-tests/http-misc-tests/tests/configuration_accept_encoding_test.bal +++ b/ballerina-tests/http-misc-tests/tests/configuration_accept_encoding_test.bal @@ -53,7 +53,7 @@ function testAcceptEncodingEnabled() { http:Response|error response = acceptEncodingEnableEP->post("/", req); if response is http:Response { test:assertEquals(response.statusCode, 200, msg = "Found unexpected output"); - common:assertJsonValue(response.getJsonPayload(), "acceptEncoding", "deflate, gzip"); + common:assertJsonValue(response.getJsonPayload(), "acceptEncoding", "deflate, gzip, br"); common:assertHeaderValue(response.server, "Mysql"); } else { test:assertFail(msg = "Found unexpected output type: " + response.message()); diff --git a/ballerina-tests/http2-tests/tests/http2_configuration_accept_encoding_test.bal b/ballerina-tests/http2-tests/tests/http2_configuration_accept_encoding_test.bal index d4af4f5e78..aea4e7288e 100644 --- a/ballerina-tests/http2-tests/tests/http2_configuration_accept_encoding_test.bal +++ b/ballerina-tests/http2-tests/tests/http2_configuration_accept_encoding_test.bal @@ -55,7 +55,7 @@ function testHttp2AcceptEncodingEnabled() { http:Response|error response = http2AcceptEncodingEnableEP->post("/", req); if response is http:Response { test:assertEquals(response.statusCode, 200, msg = "Found unexpected output"); - common:assertJsonValue(response.getJsonPayload(), "acceptEncoding", "deflate, gzip"); + common:assertJsonValue(response.getJsonPayload(), "acceptEncoding", "deflate, gzip, br"); common:assertHeaderValue(response.server, "Mysql"); } else { test:assertFail(msg = "Found unexpected output type: " + response.message()); From eb758ed21b856c155aff9c054c7add2391a91c05 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Wed, 21 Aug 2024 14:12:30 +0530 Subject: [PATCH 09/11] Add ballerina client tests --- ...figuration_compression_annotation_test.bal | 123 ++++++++++++++++-- .../http-test-common/constants.bal | 1 + 2 files changed, 116 insertions(+), 8 deletions(-) diff --git a/ballerina-tests/http-advanced-tests/tests/service_configuration_compression_annotation_test.bal b/ballerina-tests/http-advanced-tests/tests/service_configuration_compression_annotation_test.bal index 863ae98fcd..7cd14b84b1 100644 --- a/ballerina-tests/http-advanced-tests/tests/service_configuration_compression_annotation_test.bal +++ b/ballerina-tests/http-advanced-tests/tests/service_configuration_compression_annotation_test.bal @@ -112,25 +112,103 @@ function testAutoCompress() { test:assertFalse(response.hasHeader(common:CONTENT_ENCODING), msg = "The content-encoding header should be null and the identity which means no compression " + "should be done to the response"); + common:assertTextPayload(response.getTextPayload(), "Hello World!!!"); } else { test:assertFail(msg = "Found unexpected output type: " + response.message()); } } -//Test Compression.AUTO, with Accept-Encoding header. +//Test Compression.AUTO, with Accept-Encoding header - gzip. //The response here means the one that should be sent to transport, not to end user. @test:Config {} -function testAutoCompressWithAcceptEncoding() { +function testAutoCompressWithAcceptEncoding1() { http:Response|error response = compressionClient->get("/autoCompress", {[common:ACCEPT_ENCODING] : [common:ENCODING_GZIP]}); if response is http:Response { test:assertFalse(response.hasHeader(common:CONTENT_ENCODING), msg = "The content-encoding header should be null and the original value of Accept-Encoding should " + "be used for compression from the backend"); + common:assertTextPayload(response.getTextPayload(), "Hello World!!!"); } else { test:assertFail(msg = "Found unexpected output type: " + response.message()); } } +//Test Compression.AUTO, with Accept-Encoding header - br. +//The response here means the one that should be sent to transport, not to end user. +@test:Config {} +function testAutoCompressWithAcceptEncoding2() { + http:Response|error response = compressionClient->get("/autoCompress", {[common:ACCEPT_ENCODING] : [common:ENCODING_BR]}); + if response is http:Response { + test:assertFalse(response.hasHeader(common:CONTENT_ENCODING), + msg = "The content-encoding header should be null and the original value of Accept-Encoding should " + + "be used for compression from the backend"); + common:assertTextPayload(response.getTextPayload(), "Hello World!!!"); + } else { + test:assertFail(msg = "Found unexpected output type: " + response.message()); + } +} + +//Test Compression.AUTO, with Accept-Encoding header - deflate. +//The response here means the one that should be sent to transport, not to end user. +@test:Config {} +function testAutoCompressWithAcceptEncoding3() { + http:Response|error response = compressionClient->get("/autoCompress", {[common:ACCEPT_ENCODING] : [common:ENCODING_DEFLATE]}); + if response is http:Response { + test:assertFalse(response.hasHeader(common:CONTENT_ENCODING), + msg = "The content-encoding header should be null and the original value of Accept-Encoding should " + + "be used for compression from the backend"); + common:assertTextPayload(response.getTextPayload(), "Hello World!!!"); + } else { + test:assertFail(msg = "Found unexpected output type: " + response.message()); + } +} + +//Test Compression.AUTO, with Accept-Encoding header - gzip, deflate. +//The response here means the one that should be sent to transport, not to end user. +@test:Config {} +function testAutoCompressWithAcceptEncoding4() { + http:Response|error response = compressionClient->get("/autoCompress", {[common:ACCEPT_ENCODING] : [common:ENCODING_GZIP, common:ENCODING_DEFLATE]}); + if response is http:Response { + test:assertFalse(response.hasHeader(common:CONTENT_ENCODING), + msg = "The content-encoding header should be null and the original value of Accept-Encoding should " + + "be used for compression from the backend"); + common:assertTextPayload(response.getTextPayload(), "Hello World!!!"); + } else { + test:assertFail(msg = "Found unexpected output type: " + response.message()); + } +} + +//Test Compression.AUTO, with Accept-Encoding header - gzip, br. +//The response here means the one that should be sent to transport, not to end user. +@test:Config {} +function testAutoCompressWithAcceptEncoding5() { + http:Response|error response = compressionClient->get("/autoCompress", {[common:ACCEPT_ENCODING] : [common:ENCODING_GZIP, common:ENCODING_BR]}); + if response is http:Response { + test:assertFalse(response.hasHeader(common:CONTENT_ENCODING), + msg = "The content-encoding header should be null and the original value of Accept-Encoding should " + + "be used for compression from the backend"); + common:assertTextPayload(response.getTextPayload(), "Hello World!!!"); + } else { + test:assertFail(msg = "Found unexpected output type: " + response.message()); + } +} + +//Test Compression.AUTO, with Accept-Encoding header - gzip, deflate, br. +//The response here means the one that should be sent to transport, not to end user. +@test:Config {} +function testAutoCompressWithAcceptEncoding6() { + http:Response|error response = compressionClient->get("/autoCompress", {[common:ACCEPT_ENCODING] : [common:ENCODING_GZIP, common:ENCODING_DEFLATE, common:ENCODING_BR]}); + if response is http:Response { + test:assertFalse(response.hasHeader(common:CONTENT_ENCODING), + msg = "The content-encoding header should be null and the original value of Accept-Encoding should " + + "be used for compression from the backend"); + common:assertTextPayload(response.getTextPayload(), "Hello World!!!"); + } else { + test:assertFail(msg = "Found unexpected output type: " + response.message()); + } +} + + //Test Compression.AUTO, with contentTypes and without Accept-Encoding header. //The response here means the one that should be sent to transport, not to end user. @test:Config {} @@ -154,23 +232,52 @@ function testAlwaysCompress() returns error? { if response is http:Response { test:assertEquals(check response.getHeader(common:CONTENT_ENCODING), common:ENCODING_GZIP, msg = "The content-encoding header should be gzip."); + common:assertTextPayload(response.getTextPayload(), "Hello World!!!"); } else { test:assertFail(msg = "Found unexpected output type: " + response.message()); } } -//Test Compression.ALWAYS, with Accept-Encoding header. +//Test Compression.ALWAYS, with Accept-Encoding header - deflate. //The response here means the one that should be sent to transport, not to end user. @test:Config {} -function testAlwaysCompressWithAcceptEncoding() { - http:Request req = new; - req.setTextPayload("hello"); - req.setHeader(common:ACCEPT_ENCODING, common:ENCODING_DEFLATE); - http:Response|error response = compressionClient->post("/alwaysCompress", req); +function testAlwaysCompressWithAcceptEncoding1() { + http:Response|error response = compressionClient->get("/alwaysCompress", {[common:ACCEPT_ENCODING]: common:ENCODING_DEFLATE}); + if response is http:Response { + test:assertFalse(response.hasHeader(common:CONTENT_ENCODING), + msg = "The content-encoding header should be set to null and the transport will use the original" + + "Accept-Encoding value for compression."); + common:assertTextPayload(response.getTextPayload(), "Hello World!!!"); + } else { + test:assertFail(msg = "Found unexpected output type: " + response.message()); + } +} + +//Test Compression.ALWAYS, with Accept-Encoding header - br. +//The response here means the one that should be sent to transport, not to end user. +@test:Config {} +function testAlwaysCompressWithAcceptEncoding2() { + http:Response|error response = compressionClient->get("/alwaysCompress", {[common:ACCEPT_ENCODING]: common:ENCODING_BR}); + if response is http:Response { + test:assertFalse(response.hasHeader(common:CONTENT_ENCODING), + msg = "The content-encoding header should be set to null and the transport will use the original" + + "Accept-Encoding value for compression."); + common:assertTextPayload(response.getTextPayload(), "Hello World!!!"); + } else { + test:assertFail(msg = "Found unexpected output type: " + response.message()); + } +} + +//Test Compression.ALWAYS, with Accept-Encoding header - deflate, br. +//The response here means the one that should be sent to transport, not to end user. +@test:Config {} +function testAlwaysCompressWithAcceptEncoding3() { + http:Response|error response = compressionClient->get("/alwaysCompress", {[common:ACCEPT_ENCODING]: [common:ENCODING_DEFLATE + "," + common:ENCODING_BR]}); if response is http:Response { test:assertFalse(response.hasHeader(common:CONTENT_ENCODING), msg = "The content-encoding header should be set to null and the transport will use the original" + "Accept-Encoding value for compression."); + common:assertTextPayload(response.getTextPayload(), "Hello World!!!"); } else { test:assertFail(msg = "Found unexpected output type: " + response.message()); } diff --git a/ballerina-tests/http-test-common/constants.bal b/ballerina-tests/http-test-common/constants.bal index 054c9c7525..45df4fc944 100644 --- a/ballerina-tests/http-test-common/constants.bal +++ b/ballerina-tests/http-test-common/constants.bal @@ -56,6 +56,7 @@ public const string SERVER = "server"; public const string ENCODING_GZIP = "gzip"; public const string ENCODING_DEFLATE = "deflate"; +public const string ENCODING_BR = "br"; public const string HTTP_TRANSFER_ENCODING_IDENTITY = "identity"; public const string HTTP_METHOD_GET = "GET"; From 0c3a35235e37855492290d03152f4a99a77f76a0 Mon Sep 17 00:00:00 2001 From: Krishnananthalingam Tharmigan <63336800+TharmiganK@users.noreply.github.com> Date: Tue, 12 Nov 2024 11:24:16 +0530 Subject: [PATCH 10/11] Update changelog --- changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 2d75c96aab..b33ed0e972 100644 --- a/changelog.md +++ b/changelog.md @@ -16,6 +16,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - [Introduce util functions to convert query and header record with the `http:Query` and the `http:Header` annotations](https://github.com/ballerina-platform/ballerina-library/issues/7019) - [Migrate client and service data binding lang utils usage into data.jsondata module utils `toJson` and `parserAsType`] (https://github.com/ballerina-platform/ballerina-library/issues/6747) - [Add static code rules](https://github.com/ballerina-platform/ballerina-library/issues/7283) +- [Add compression/decompression support for `brotli` compression format](https://github.com/ballerina-platform/ballerina-library/issues/6547) ### Fixed @@ -26,7 +27,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Added -- [Add compression/decompression support for `brotli` compression format](https://github.com/ballerina-platform/ballerina-library/issues/6547) - [Add support for Server-Sent Events](https://github.com/ballerina-platform/ballerina-library/issues/6687) - [Introduce default status code response record](https://github.com/ballerina-platform/ballerina-library/issues/6491) - [Add connection eviction feature to handle connections that receive GO_AWAY from the client](https://github.com/ballerina-platform/ballerina-library/issues/6734) From 7fb41dc315fec97996a59cc48820125d8105f8b8 Mon Sep 17 00:00:00 2001 From: Krishnananthalingam Tharmigan <63336800+TharmiganK@users.noreply.github.com> Date: Tue, 12 Nov 2024 11:24:55 +0530 Subject: [PATCH 11/11] Remove new line --- changelog.md | 1 - 1 file changed, 1 deletion(-) diff --git a/changelog.md b/changelog.md index b33ed0e972..1fa38028ea 100644 --- a/changelog.md +++ b/changelog.md @@ -26,7 +26,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [2.12.0] - 2024-08-20 ### Added - - [Add support for Server-Sent Events](https://github.com/ballerina-platform/ballerina-library/issues/6687) - [Introduce default status code response record](https://github.com/ballerina-platform/ballerina-library/issues/6491) - [Add connection eviction feature to handle connections that receive GO_AWAY from the client](https://github.com/ballerina-platform/ballerina-library/issues/6734)