Skip to content
Merged
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
4 changes: 2 additions & 2 deletions avaje-jex/src/main/java/io/avaje/jex/Context.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import com.sun.net.httpserver.HttpExchange;

import io.avaje.jex.core.HeaderKeys;
import io.avaje.jex.core.Constants;
import io.avaje.jex.security.BasicAuthCredentials;
import io.avaje.jex.security.Role;

Expand Down Expand Up @@ -232,7 +232,7 @@ default String fullUrl() {
* Return the request user agent, or null.
*/
default String userAgent() {
return header(HeaderKeys.USER_AGENT);
return header(Constants.USER_AGENT);
}

/**
Expand Down
7 changes: 4 additions & 3 deletions avaje-jex/src/main/java/io/avaje/jex/FilterChain.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@

import com.sun.net.httpserver.HttpExchange;

/** Filter chain that contains all subsequent filters that are configured, as well as the final route. */
@FunctionalInterface
public interface FilterChain {

/**
* Calls the next filter in the chain, or else the user's exchange handler, if this is the final
* filter in the chain. The {@link HttpFilter} may decide to terminate the chain, by not
* calling this method. In this case, the filter <b>must</b> send the response to the request,
* because the application's {@linkplain HttpExchange exchange} handler will not be invoked.
* filter in the chain. The {@link HttpFilter} may decide to terminate the chain, by not calling
* this method. In this case, the filter <b>must</b> send the response to the request, because the
* application's {@linkplain HttpExchange exchange} handler will not be invoked.
*
* @throws IOException if an I/O error occurs
*/
Expand Down
2 changes: 0 additions & 2 deletions avaje-jex/src/main/java/io/avaje/jex/Routing.java
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,6 @@ interface Entry {

/** The type of route entry. */
enum Type {
/** Http Filter. */
FILTER,
/** Http GET. */
GET,
/** Http POST. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@
import java.util.Optional;

import io.avaje.jex.Context;
import io.avaje.jex.core.HeaderKeys;
import io.avaje.jex.spi.SpiContext;
import io.avaje.jex.core.Constants;

/**
* CompressedOutputStream class that conditionally compresses the output based on configuration and
* OutputStream implementation that conditionally compresses the output based on configuration and
* request headers.
*/
public class CompressedOutputStream extends OutputStream {
Expand All @@ -24,7 +23,7 @@ public class CompressedOutputStream extends OutputStream {
private boolean compressionDecided;

public CompressedOutputStream(
CompressionConfig compression, SpiContext ctx, OutputStream originStream) {
CompressionConfig compression, Context ctx, OutputStream originStream) {
this.minSizeForCompression = compression.minSizeForCompression();
this.compression = compression;
this.ctx = ctx;
Expand All @@ -33,7 +32,7 @@ public CompressedOutputStream(

private void decideCompression(int length) throws IOException {
if (!compressionDecided) {
var encoding = ctx.responseHeader(HeaderKeys.CONTENT_ENCODING);
var encoding = ctx.responseHeader(Constants.CONTENT_ENCODING);

if (encoding != null) {

Expand All @@ -51,10 +50,10 @@ private void decideCompression(int length) throws IOException {

if (compressionAllowed && length >= minSizeForCompression) {
Optional<Compressor> compressor;
compressor = findMatchingCompressor(ctx.header(HeaderKeys.ACCEPT_ENCODING));
compressor = findMatchingCompressor(ctx.header(Constants.ACCEPT_ENCODING));
if (compressor.isPresent()) {
this.compressedStream = compressor.get().compress(originStream);
ctx.header(HeaderKeys.CONTENT_ENCODING, compressor.get().encoding());
ctx.header(Constants.CONTENT_ENCODING, compressor.get().encoding());
}
}
compressionDecided = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
import java.util.Map;
import java.util.Set;

/** Configuration class for compression settings. */
public class CompressionConfig {

private static final int HTTP_PACKET_SIZE = 1500;

private static final Set<String> excludedMimeTypes =
Set.of(
"application/compress",
Expand All @@ -16,44 +18,72 @@ public class CompressionConfig {
"application/brotli",
"application/x-xz",
"application/x-rar-compressed");

private boolean enabled = true;

private int minSizeForCompression = HTTP_PACKET_SIZE;

private final Map<String, Compressor> compressors =
new HashMap<>(Map.of(GzipCompressor.ENCODING, new GzipCompressor()));

private final Set<String> allowedExcludedTypes = Set.of("image/svg+xml");

/**
* set default gzip compressor level
* Sets the default GZIP compression level.
*
* @param level the new compression level (0-9)
* @param level The new compression level (0-9).
*/
public void gzipCompressionLevel(int level) {
compressors.put(GzipCompressor.ENCODING, new GzipCompressor(level));
}

/** Disables compression. */
public void disableCompression() {
enabled = false;
compressors.clear();
}

/**
* Gets the minimum size for compression.
*
* @return The minimum size for compression.
*/
public int minSizeForCompression() {
return minSizeForCompression;
}

/**
* Sets the minimum size for compression and returns the updated configuration.
*
* @param minSizeForCompression The new minimum size for compression.
* @return The updated configuration.
* @throws IllegalArgumentException If the minimum size is less than a network packet size.
*/
public CompressionConfig minSizeForCompression(int minSizeForCompression) {
this.minSizeForCompression = minSizeForCompression;
if (minSizeForCompression < HTTP_PACKET_SIZE)
if (minSizeForCompression < HTTP_PACKET_SIZE) {
throw new IllegalArgumentException(
"Compression should only happen on payloads bigger than an http packect");
"Compression should only happen on payloads bigger than an http packet");
}
return this;
}

/**
* Checks if compression is enabled.
*
* @return True if compression is enabled, false otherwise.
*/
public boolean compressionEnabled() {
return enabled;
}

/**
* Determines if a given content type is allowed for compression.
*
* @param contentType The content type to check.
* @return True if the content type is allowed for compression, false otherwise.
*/
public boolean allowsForCompression(String contentType) {

return contentType == null
|| allowedExcludedTypes.contains(contentType)
|| !excludedMimeTypes.contains(contentType)
Expand All @@ -62,7 +92,13 @@ public boolean allowsForCompression(String contentType) {
&& !contentType.startsWith("video/");
}

Compressor forType(String type) {
return compressors.get(type.toLowerCase());
/**
* Gets the appropriate compressor for a given encoding type.
*
* @param encoding The Content-Encoding value.
* @return The compressor for the given Content-Encoding value, or null if not found.
*/
Compressor forType(String encoding) {
return compressors.get(encoding.toLowerCase());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/** Classes Governing Http Compression */
package io.avaje.jex.compression;
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package io.avaje.jex.core;

public final class HeaderKeys {
public final class Constants {

private HeaderKeys() {}
private Constants() {}

public static final String ACCEPT = "Accept";
public static final String CONTENT_ENCODING = "Content-Encoding";
Expand All @@ -16,4 +16,12 @@ private HeaderKeys() {}
public static final String HOST = "Host";
public static final String USER_AGENT = "User-Agent";
public static final String ACCEPT_ENCODING = "Accept-Encoding";

public static final String TEXT_HTML = "text/html";
public static final String TEXT_PLAIN = "text/plain";
public static final String TEXT_HTML_UTF8 = "text/html;charset=utf-8";
public static final String TEXT_PLAIN_UTF8 = "text/plain;charset=utf-8";
public static final String APPLICATION_JSON = "application/json";
public static final String APPLICATION_X_JSON_STREAM = "application/x-json-stream";

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
import io.avaje.jex.Routing;
import io.avaje.jex.core.json.JacksonJsonService;
import io.avaje.jex.core.json.JsonbJsonService;
import io.avaje.jex.jdk.JdkContext;
import io.avaje.jex.spi.JsonService;
import io.avaje.jex.spi.SpiContext;
import io.avaje.jex.spi.TemplateRender;

/**
Expand Down Expand Up @@ -90,7 +90,7 @@ public Routing.Type lookupRoutingType(String method) {
}

@Override
public void handleException(SpiContext ctx, Exception e) {
public void handleException(JdkContext ctx, Exception e) {
exceptionHandler.handle(ctx, e);
}

Expand All @@ -102,7 +102,7 @@ public void render(Context ctx, String name, Map<String, Object> model) {

@Override
public String requestCharset(Context ctx) {
return parseCharset(ctx.header(HeaderKeys.CONTENT_TYPE));
return parseCharset(ctx.header(Constants.CONTENT_TYPE));
}

static String parseCharset(String header) {
Expand Down
15 changes: 8 additions & 7 deletions avaje-jex/src/main/java/io/avaje/jex/core/ExceptionManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
import java.util.Map;

import io.avaje.applog.AppLog;
import io.avaje.jex.Context;
import io.avaje.jex.ExceptionHandler;
import io.avaje.jex.http.ErrorCode;
import io.avaje.jex.http.HttpResponseException;
import io.avaje.jex.http.InternalServerErrorException;
import io.avaje.jex.spi.SpiContext;
import io.avaje.jex.jdk.JdkContext;

public final class ExceptionManager {

Expand All @@ -36,7 +37,7 @@ public <T extends Exception> ExceptionHandler<Exception> find(Class<T> exception
return null;
}

void handle(SpiContext ctx, Exception e) {
void handle(JdkContext ctx, Exception e) {
final ExceptionHandler<Exception> handler = find(e.getClass());
if (handler != null) {
try {
Expand All @@ -51,12 +52,12 @@ void handle(SpiContext ctx, Exception e) {
}
}

private void unhandledException(SpiContext ctx, Exception e) {
private void unhandledException(JdkContext ctx, Exception e) {
log.log(WARNING, "Uncaught exception", e);
defaultHandling(ctx, new InternalServerErrorException(ErrorCode.INTERNAL_SERVER_ERROR.message()));
}

private void defaultHandling(SpiContext ctx, HttpResponseException exception) {
private void defaultHandling(JdkContext ctx, HttpResponseException exception) {
ctx.status(exception.getStatus());
if (exception.getStatus() == ErrorCode.REDIRECT.status()) {
ctx.performRedirect();
Expand All @@ -80,9 +81,9 @@ private String jsonEscape(String message) {
return message;
}

private boolean useJson(SpiContext ctx) {
final String acceptHeader = ctx.header(HeaderKeys.ACCEPT);
private boolean useJson(Context ctx) {
final String acceptHeader = ctx.header(Constants.ACCEPT);
return (acceptHeader != null && acceptHeader.contains(APPLICATION_JSON)
|| APPLICATION_JSON.equals(ctx.responseHeader(HeaderKeys.CONTENT_TYPE)));
|| APPLICATION_JSON.equals(ctx.responseHeader(Constants.CONTENT_TYPE)));
}
}
12 changes: 6 additions & 6 deletions avaje-jex/src/main/java/io/avaje/jex/core/SpiServiceManager.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
package io.avaje.jex.core;

import io.avaje.jex.Context;
import io.avaje.jex.Routing;
import io.avaje.jex.jdk.CtxServiceManager;
import io.avaje.jex.spi.SpiContext;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

import io.avaje.jex.Context;
import io.avaje.jex.Routing;
import io.avaje.jex.jdk.CtxServiceManager;
import io.avaje.jex.jdk.JdkContext;

/**
* Core service methods available to Context implementations.
*/
Expand Down Expand Up @@ -50,7 +50,7 @@ public sealed interface SpiServiceManager permits CoreServiceManager, CtxService
/**
* Handle the exception.
*/
void handleException(SpiContext ctx, Exception e);
void handleException(JdkContext ctx, Exception e);

/**
* Render using template manager.
Expand Down
5 changes: 2 additions & 3 deletions avaje-jex/src/main/java/io/avaje/jex/jdk/BaseHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import com.sun.net.httpserver.HttpHandler;

import io.avaje.jex.ExchangeHandler;
import io.avaje.jex.Routing.Type;
import io.avaje.jex.routes.SpiRoutes;

final class BaseHandler implements HttpHandler {
Expand All @@ -27,8 +26,8 @@ public void handle(HttpExchange exchange) throws IOException {
ExchangeHandler handlerConsumer =
(ExchangeHandler) exchange.getAttribute("SpiRoutes.Entry.Handler");

ctx.setMode(null);
ctx.setMode(Mode.EXCHANGE);
handlerConsumer.handle(ctx);
ctx.setMode(Type.FILTER);
ctx.setMode(Mode.AFTER);
}
}
11 changes: 5 additions & 6 deletions avaje-jex/src/main/java/io/avaje/jex/jdk/CtxServiceManager.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
package io.avaje.jex.jdk;

import io.avaje.jex.Context;
import io.avaje.jex.Routing;
import io.avaje.jex.core.SpiServiceManager;
import io.avaje.jex.spi.SpiContext;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

import io.avaje.jex.Context;
import io.avaje.jex.Routing;
import io.avaje.jex.core.SpiServiceManager;

public final class CtxServiceManager implements SpiServiceManager {

private final String scheme;
Expand Down Expand Up @@ -71,7 +70,7 @@ public Routing.Type lookupRoutingType(String method) {
}

@Override
public void handleException(SpiContext ctx, Exception e) {
public void handleException(JdkContext ctx, Exception e) {
delegate.handleException(ctx, e);
}

Expand Down
Loading