package io.dropwizard.jetty;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.Iterables;
import io.dropwizard.util.Size;
import org.eclipse.jetty.server.Handler;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import java.util.HashSet;
import java.util.Set;
import java.util.zip.Deflater;
import static java.util.Objects.requireNonNull;
/**
* Builds GZIP filters.
*
* <p/>
* <b>Configuration Parameters:</b>
* <table>
* <tr>
* <td>Name</td>
* <td>Default</td>
* <td>Description</td>
* </tr>
* <tr>
* <td>{@code enabled}</td>
* <td>true</td>
* <td>If true, all requests with `gzip` or `deflate` in the `Accept-Encoding` header will have their
* response entities compressed and requests with `gzip` or `deflate` in the `Content-Encoding`
* header will have their request entities decompressed.</td>
* </tr>
* <tr>
* <td>{@code minimumEntitySize}</td>
* <td>256 bytes</td>
* <td>All response entities under this size are not compressed.</td>
* </tr>
* <tr>
* <td>{@code bufferSize}</td>
* <td>8KiB</td>
* <td>The size of the buffer to use when compressing.</td>
* </tr>
* <tr>
* <td>{@code excludedUserAgentPatterns}</td>
* <td>(none)</td>
* <td>The set of user agent patterns to exclude from compression. </td>
* </tr>
* <tr>
* <td>{@code compressedMimeTypes}</td>
* <td>(Jetty's default)</td>
* <td>The list of mime types to compress. The default is all types apart the
* commonly known image, video, audio and compressed types.</td>
* </tr>
* <tr>
* <td>{@code includedMethods}</td>
* <td>(Jetty's default)</td>
* <td>The list list of HTTP methods to compress. The default is to compress
* only GET responses.</td>
* </tr>
* <tr>
* <td>{@code deflateCompressionLevel}</td>
* <td>-1</td>
* <td>The compression level used for ZLIB deflation(compression).</td>
* </tr>
* <tr>
* <td>{@code gzipCompatibleInflation}</td>
* <td>true</td>
* <td>If true, then ZLIB inflation(decompression) will be performed in the GZIP-compatible mode.</td>
* </tr>
* </table>
*/
public class GzipHandlerFactory {
private boolean enabled = true;
@NotNull
private Size minimumEntitySize = Size.bytes(256);
@NotNull
private Size bufferSize = Size.kilobytes(8);
// By default compress responses for all user-agents
private Set<String> excludedUserAgentPatterns = new HashSet<>();
private Set<String> compressedMimeTypes;
private Set<String> includedMethods;
@Min(Deflater.DEFAULT_COMPRESSION)
@Max(Deflater.BEST_COMPRESSION)
private int deflateCompressionLevel = Deflater.DEFAULT_COMPRESSION;
private boolean gzipCompatibleInflation = true;
private boolean syncFlush = false;
@JsonProperty
public boolean isEnabled() {
return enabled;
}
@JsonProperty
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
@JsonProperty
public Size getMinimumEntitySize() {
return minimumEntitySize;
}
@JsonProperty
public void setMinimumEntitySize(Size size) {
this.minimumEntitySize = requireNonNull(size);
}
@JsonProperty
public Size getBufferSize() {
return bufferSize;
}
@JsonProperty
public void setBufferSize(Size size) {
this.bufferSize = requireNonNull(size);
}
@JsonProperty
public Set<String> getCompressedMimeTypes() {
return compressedMimeTypes;
}
@JsonProperty
public void setCompressedMimeTypes(Set<String> mimeTypes) {
this.compressedMimeTypes = mimeTypes;
}
@JsonProperty
public int getDeflateCompressionLevel() {
return deflateCompressionLevel;
}
@JsonProperty
public void setDeflateCompressionLevel(int level) {
this.deflateCompressionLevel = level;
}
@JsonProperty
public boolean isGzipCompatibleInflation() {
return gzipCompatibleInflation;
}
@JsonProperty
public void setGzipCompatibleInflation(boolean gzipCompatibleInflation) {
this.gzipCompatibleInflation = gzipCompatibleInflation;
}
public Set<String> getExcludedUserAgentPatterns() {
return excludedUserAgentPatterns;
}
public void setExcludedUserAgentPatterns(Set<String> excludedUserAgentPatterns) {
this.excludedUserAgentPatterns = excludedUserAgentPatterns;
}
@JsonProperty
public Set<String> getIncludedMethods() {
return includedMethods;
}
@JsonProperty
public void setIncludedMethods(Set<String> methods) {
this.includedMethods = methods;
}
@JsonProperty
public boolean isSyncFlush() {
return syncFlush;
}
@JsonProperty
public void setSyncFlush(boolean syncFlush) {
this.syncFlush = syncFlush;
}
public BiDiGzipHandler build(Handler handler) {
final BiDiGzipHandler gzipHandler = new BiDiGzipHandler();
gzipHandler.setHandler(handler);
gzipHandler.setMinGzipSize((int) minimumEntitySize.toBytes());
gzipHandler.setInputBufferSize((int) bufferSize.toBytes());
gzipHandler.setCompressionLevel(deflateCompressionLevel);
gzipHandler.setSyncFlush(syncFlush);
if (compressedMimeTypes != null) {
gzipHandler.setIncludedMimeTypes(Iterables.toArray(compressedMimeTypes, String.class));
}
if (includedMethods != null) {
gzipHandler.setIncludedMethods(Iterables.toArray(includedMethods, String.class));
}
gzipHandler.setExcludedAgentPatterns(Iterables.toArray(excludedUserAgentPatterns, String.class));
gzipHandler.setInflateNoWrap(gzipCompatibleInflation);
return gzipHandler;
}
}