Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ plugins {
id 'team.yi.semantic-gitlog' version '0.6.12'
}

import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform

group = 'io.neonbee'
version = '0.37.12-SNAPSHOT'
mainClassName = 'io.neonbee.Launcher'
Expand Down Expand Up @@ -95,6 +97,34 @@ dependencies {
implementation group: 'com.google.guava', name: 'guava', version: guava_version
implementation group: 'com.github.spotbugs', name: 'spotbugs-annotations', version: '4.8.6'


def brotli4j_version = '1.20.0' // https://mvnrepository.com/artifact/com.aayushatharva.brotli4j/brotli4j
def brotli4j_architecture = """${
def operatingSystem = DefaultNativePlatform.getCurrentOperatingSystem()
def currentArchitecture = DefaultNativePlatform.getCurrentArchitecture()
if (operatingSystem.isWindows())
if (currentArchitecture.isX86_64()) "windows-x86_64"
else if (currentArchitecture.isArm()) "windows-aarch64"
else
throw new IllegalStateException("Unsupported architecture: ${currentArchitecture.getName()}");
else if (operatingSystem.isMacOsX())
if (currentArchitecture.isArm()) "osx-aarch64"
else "osx-x86_64"
else if (operatingSystem.isLinux())
if (currentArchitecture.isAARCH64()) "linux-aarch64"
else if (currentArchitecture.isX86_64()) "linux-x86_64"
else if (currentArchitecture.isARM_V7()) "linux-armv7"
else if (currentArchitecture.isPPC64LE()) "linux-ppc64le"
else if (currentArchitecture.isS390X()) "linux-s390x"
else if (currentArchitecture.isRISCV64()) "linux-riscv64"
else
throw new IllegalStateException("Unsupported architecture: ${currentArchitecture.getName()}");
else
throw new IllegalStateException("Unsupported operating system: $operatingSystem");
}"""
implementation group: 'com.aayushatharva.brotli4j', name: 'brotli4j', version: brotli4j_version
runtimeOnly group: 'com.aayushatharva.brotli4j', name: 'native-' + brotli4j_architecture, version: brotli4j_version

// Compile only
compileOnly group: 'io.vertx', name: 'vertx-codegen', version: vertx_version

Expand Down
63 changes: 63 additions & 0 deletions src/test/java/io/neonbee/endpoint/raw/RawEndpointTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Stream;
Expand All @@ -21,6 +23,9 @@
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import com.aayushatharva.brotli4j.encoder.Encoder;

import io.neonbee.NeonBee;
import io.neonbee.NeonBeeDeployable;
import io.neonbee.data.DataAdapter;
import io.neonbee.data.DataContext;
Expand All @@ -35,7 +40,10 @@
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Route;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.client.HttpRequest;
import io.vertx.ext.web.client.HttpResponse;
import io.vertx.ext.web.client.WebClient;
import io.vertx.ext.web.client.WebClientOptions;
import io.vertx.junit5.VertxTestContext;

class RawEndpointTest extends DataVerticleTestBase {
Expand Down Expand Up @@ -173,6 +181,26 @@ void testSettingAdditionalHeaders(VertxTestContext testContext) {
})));
}

@Test
@DisplayName("RawDataEndpointHandler should support Brotli compression")
void testBrotliCompression(VertxTestContext testContext) {

NeonBee neonBee = getNeonBee();
WebClientOptions opts = new WebClientOptions().setDefaultHost("localhost")
.setDefaultPort(neonBee.getOptions().getServerPort()).setDecompressionSupported(true);

HttpRequest<Buffer> request = WebClient.create(neonBee.getVertx(), opts)
.request(HttpMethod.GET, String.format("/raw/%s/%s", NEONBEE_NAMESPACE, "Brotli"))
.putHeader("Accept-Encoding", "br");

deployVerticle(new BrotliResponseVerticle())
.compose(s -> request.send())
.onComplete(testContext.succeeding(response -> testContext.verify(() -> {
assertThat(response.bodyAsString()).isEqualTo("Hello from Vert.x with Brotli4j!");
testContext.completeNow();
})));
}

@NeonBeeDeployable(namespace = NEONBEE_NAMESPACE, autoDeploy = false)
public static class JsonResponseVerticle extends DataVerticle<JsonObject> {

Expand Down Expand Up @@ -210,6 +238,41 @@ public String getName() {
}
}

@NeonBeeDeployable(namespace = NEONBEE_NAMESPACE, autoDeploy = false)
public static class BrotliResponseVerticle extends DataVerticle<Buffer> {

@Override
public Future<Buffer> retrieveData(DataQuery query, DataContext context) {
context.responseData().put(
RESPONSE_HEADERS,
Map.of(
"foo", "bar",
"hodor", "hodor",
"Content-Encoding", "br"));
return Future.succeededFuture(Buffer.buffer(compressResponse()));
}

/**
* Compress a sample response using Brotli4j. The data should be compressed before being put into the Buffer to
* be returned.
*
* @return the compressed byte array
*/
public byte[] compressResponse() {
try {
byte[] input = "Hello from Vert.x with Brotli4j!".getBytes(StandardCharsets.UTF_8);
return Encoder.compress(input); // Compress using Brotli4j
} catch (IOException e) {
throw new RuntimeException("Failed to load Brotli4j native library", e);
}
}

@Override
public String getName() {
return "Brotli";
}
}

private Future<HttpResponse<Buffer>> sendRequest(String verticleName, String path, String query) {
String uriPath = String.format("/raw/%s/%s/%s?%s", NEONBEE_NAMESPACE, verticleName, path, query);
return createRequest(HttpMethod.GET, uriPath).send();
Expand Down
Loading