Skip to content

Commit 9a77a09

Browse files
committed
Add ability to disable compression for thruster by env variable
1 parent 7eb4e76 commit 9a77a09

File tree

6 files changed

+62
-28
lines changed

6 files changed

+62
-28
lines changed

README.md

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -73,25 +73,26 @@ configuration. But if you need to customize its behavior, there are a few
7373
environment variables that you can set.
7474

7575
| Variable Name | Description | Default Value |
76-
|-----------------------|---------------------------------------------------------|---------------|
77-
| `TLS_DOMAIN` | Comma-separated list of domain names to use for TLS provisioning. If not set, TLS will be disabled. | None |
78-
| `TARGET_PORT` | The port that your Puma server should run on. Thruster will set `PORT` to this value when starting your server. | 3000 |
79-
| `CACHE_SIZE` | The size of the HTTP cache in bytes. | 64MB |
80-
| `MAX_CACHE_ITEM_SIZE` | The maximum size of a single item in the HTTP cache in bytes. | 1MB |
81-
| `X_SENDFILE_ENABLED` | Whether to enable X-Sendfile support. Set to `0` or `false` to disable. | Enabled |
82-
| `MAX_REQUEST_BODY` | The maximum size of a request body in bytes. Requests larger than this size will be refused; `0` means no maximum size is enforced. | `0` |
83-
| `STORAGE_PATH` | The path to store Thruster's internal state. Provisioned TLS certificates will be stored here, so that they will not need to be requested every time your application is started. | `./storage/thruster` |
84-
| `BAD_GATEWAY_PAGE` | Path to an HTML file to serve when the backend server returns a 502 Bad Gateway error. If there is no file at the specific path, Thruster will serve an empty 502 response instead. Because Thruster boots very quickly, a custom page can be a useful way to show that your application is starting up. | `./public/502.html` |
85-
| `HTTP_PORT` | The port to listen on for HTTP traffic. | 80 |
86-
| `HTTPS_PORT` | The port to listen on for HTTPS traffic. | 443 |
87-
| `HTTP_IDLE_TIMEOUT` | The maximum time in seconds that a client can be idle before the connection is closed. | 60 |
88-
| `HTTP_READ_TIMEOUT` | The maximum time in seconds that a client can take to send the request headers and body. | 30 |
89-
| `HTTP_WRITE_TIMEOUT` | The maximum time in seconds during which the client must read the response. | 30 |
90-
| `ACME_DIRECTORY` | The URL of the ACME directory to use for TLS certificate provisioning. | `https://acme-v02.api.letsencrypt.org/directory` (Let's Encrypt production) |
91-
| `EAB_KID` | The EAB key identifier to use when provisioning TLS certificates, if required. | None |
92-
| `EAB_HMAC_KEY` | The Base64-encoded EAB HMAC key to use when provisioning TLS certificates, if required. | None |
93-
| `FORWARD_HEADERS` | Whether to forward X-Forwarded-* headers from the client. | Disabled when running with TLS; enabled otherwise |
94-
| `DEBUG` | Set to `1` or `true` to enable debug logging. | Disabled |
76+
|-----------------------------|---------------------------------------------------------|---------------|
77+
| `TLS_DOMAIN` | Comma-separated list of domain names to use for TLS provisioning. If not set, TLS will be disabled. | None |
78+
| `TARGET_PORT` | The port that your Puma server should run on. Thruster will set `PORT` to this value when starting your server. | 3000 |
79+
| `CACHE_SIZE` | The size of the HTTP cache in bytes. | 64MB |
80+
| `MAX_CACHE_ITEM_SIZE` | The maximum size of a single item in the HTTP cache in bytes. | 1MB |
81+
| `GZIP_COMPRESSION_ENABLED` | Whether to enable gzip compression for static assets. Set to `0` or `false` to disable. | Enabled |
82+
| `X_SENDFILE_ENABLED` | Whether to enable X-Sendfile support. Set to `0` or `false` to disable. | Enabled |
83+
| `MAX_REQUEST_BODY` | The maximum size of a request body in bytes. Requests larger than this size will be refused; `0` means no maximum size is enforced. | `0` |
84+
| `STORAGE_PATH` | The path to store Thruster's internal state. Provisioned TLS certificates will be stored here, so that they will not need to be requested every time your application is started. | `./storage/thruster` |
85+
| `BAD_GATEWAY_PAGE` | Path to an HTML file to serve when the backend server returns a 502 Bad Gateway error. If there is no file at the specific path, Thruster will serve an empty 502 response instead. Because Thruster boots very quickly, a custom page can be a useful way to show that your application is starting up. | `./public/502.html` |
86+
| `HTTP_PORT` | The port to listen on for HTTP traffic. | 80 |
87+
| `HTTPS_PORT` | The port to listen on for HTTPS traffic. | 443 |
88+
| `HTTP_IDLE_TIMEOUT` | The maximum time in seconds that a client can be idle before the connection is closed. | 60 |
89+
| `HTTP_READ_TIMEOUT` | The maximum time in seconds that a client can take to send the request headers and body. | 30 |
90+
| `HTTP_WRITE_TIMEOUT` | The maximum time in seconds during which the client must read the response. | 30 |
91+
| `ACME_DIRECTORY` | The URL of the ACME directory to use for TLS certificate provisioning. | `https://acme-v02.api.letsencrypt.org/directory` (Let's Encrypt production) |
92+
| `EAB_KID` | The EAB key identifier to use when provisioning TLS certificates, if required. | None |
93+
| `EAB_HMAC_KEY` | The Base64-encoded EAB HMAC key to use when provisioning TLS certificates, if required. | None |
94+
| `FORWARD_HEADERS` | Whether to forward X-Forwarded-* headers from the client. | Disabled when running with TLS; enabled otherwise |
95+
| `DEBUG` | Set to `1` or `true` to enable debug logging. | Disabled |
9596

9697
To prevent naming clashes with your application's own environment variables,
9798
Thruster's environment variables can optionally be prefixed with `THRUSTER_`.

internal/config.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,11 @@ type Config struct {
4141
UpstreamCommand string
4242
UpstreamArgs []string
4343

44-
CacheSizeBytes int
45-
MaxCacheItemSizeBytes int
46-
XSendfileEnabled bool
47-
MaxRequestBody int
44+
CacheSizeBytes int
45+
MaxCacheItemSizeBytes int
46+
XSendfileEnabled bool
47+
GzipCompressionEnabled bool
48+
MaxRequestBody int
4849

4950
TLSDomains []string
5051
ACMEDirectoryURL string
@@ -79,10 +80,11 @@ func NewConfig() (*Config, error) {
7980
UpstreamCommand: os.Args[1],
8081
UpstreamArgs: os.Args[2:],
8182

82-
CacheSizeBytes: getEnvInt("CACHE_SIZE", defaultCacheSize),
83-
MaxCacheItemSizeBytes: getEnvInt("MAX_CACHE_ITEM_SIZE", defaultMaxCacheItemSizeBytes),
84-
XSendfileEnabled: getEnvBool("X_SENDFILE_ENABLED", true),
85-
MaxRequestBody: getEnvInt("MAX_REQUEST_BODY", defaultMaxRequestBody),
83+
CacheSizeBytes: getEnvInt("CACHE_SIZE", defaultCacheSize),
84+
MaxCacheItemSizeBytes: getEnvInt("MAX_CACHE_ITEM_SIZE", defaultMaxCacheItemSizeBytes),
85+
XSendfileEnabled: getEnvBool("X_SENDFILE_ENABLED", true),
86+
GzipCompressionEnabled: getEnvBool("GZIP_COMPRESSION_ENABLED", true),
87+
MaxRequestBody: getEnvInt("MAX_REQUEST_BODY", defaultMaxRequestBody),
8688

8789
TLSDomains: getEnvStrings("TLS_DOMAIN", []string{}),
8890
ACMEDirectoryURL: getEnvString("ACME_DIRECTORY", defaultACMEDirectoryURL),

internal/config_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ func TestConfig_override_defaults_with_env_vars(t *testing.T) {
113113
usingEnvVar(t, "CACHE_SIZE", "256")
114114
usingEnvVar(t, "HTTP_READ_TIMEOUT", "5")
115115
usingEnvVar(t, "X_SENDFILE_ENABLED", "0")
116+
usingEnvVar(t, "GZIP_COMPRESSION_ENABLED", "0")
116117
usingEnvVar(t, "DEBUG", "1")
117118
usingEnvVar(t, "ACME_DIRECTORY", "https://acme-staging-v02.api.letsencrypt.org/directory")
118119

@@ -123,6 +124,7 @@ func TestConfig_override_defaults_with_env_vars(t *testing.T) {
123124
assert.Equal(t, 256, c.CacheSizeBytes)
124125
assert.Equal(t, 5*time.Second, c.HttpReadTimeout)
125126
assert.Equal(t, false, c.XSendfileEnabled)
127+
assert.Equal(t, false, c.GzipCompressionEnabled)
126128
assert.Equal(t, slog.LevelDebug, c.LogLevel)
127129
assert.Equal(t, "https://acme-staging-v02.api.letsencrypt.org/directory", c.ACMEDirectoryURL)
128130
}

internal/handler.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,17 @@ type HandlerOptions struct {
1515
maxRequestBody int
1616
targetUrl *url.URL
1717
xSendfileEnabled bool
18+
gzipCompressionEnabled bool
1819
forwardHeaders bool
1920
}
2021

2122
func NewHandler(options HandlerOptions) http.Handler {
2223
handler := NewProxyHandler(options.targetUrl, options.badGatewayPage, options.forwardHeaders)
2324
handler = NewCacheHandler(options.cache, options.maxCacheableResponseBody, handler)
2425
handler = NewSendfileHandler(options.xSendfileEnabled, handler)
25-
handler = gzhttp.GzipHandler(handler)
26+
if options.gzipCompressionEnabled {
27+
handler = gzhttp.GzipHandler(handler)
28+
}
2629

2730
if options.maxRequestBody > 0 {
2831
handler = http.MaxBytesHandler(handler, int64(options.maxRequestBody))

internal/handler_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,30 @@ func TestHandlerGzipCompression_when_proxying(t *testing.T) {
3333
assert.Less(t, transferredSize, fixtureLength("loremipsum.txt"))
3434
}
3535

36+
func TestNotHandlerGzipCompression_when_disabled(t *testing.T) {
37+
fixtureLength := strconv.FormatInt(fixtureLength("loremipsum.txt"), 10)
38+
39+
upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
40+
w.Header().Set("Content-Length", fixtureLength)
41+
w.Write(fixtureContent("loremipsum.txt"))
42+
}))
43+
defer upstream.Close()
44+
45+
options := handlerOptions(upstream.URL)
46+
options.gzipCompressionEnabled = false
47+
h := NewHandler(options)
48+
49+
w := httptest.NewRecorder()
50+
r := httptest.NewRequest("GET", "/", nil)
51+
r.Header.Set("Accept-Encoding", "gzip")
52+
h.ServeHTTP(w, r)
53+
54+
assert.Equal(t, http.StatusOK, w.Code)
55+
assert.Contains(t, w.Header().Get("Content-Type"), "text/plain")
56+
assert.Empty(t, w.Header().Get("Content-Encoding"))
57+
assert.Equal(t, fixtureLength, w.Header().Get("Content-Length"))
58+
}
59+
3660
func TestHandlerGzipCompression_is_not_applied_when_not_requested(t *testing.T) {
3761
fixtureLength := strconv.FormatInt(fixtureLength("loremipsum.txt"), 10)
3862

@@ -248,6 +272,7 @@ func handlerOptions(targetUrl string) HandlerOptions {
248272
cache: NewMemoryCache(defaultCacheSize, defaultMaxCacheItemSizeBytes),
249273
targetUrl: url,
250274
xSendfileEnabled: true,
275+
gzipCompressionEnabled: true,
251276
maxCacheableResponseBody: 1024,
252277
badGatewayPage: "",
253278
forwardHeaders: true,

internal/service.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ func (s *Service) Run() int {
2222
cache: s.cache(),
2323
targetUrl: s.targetUrl(),
2424
xSendfileEnabled: s.config.XSendfileEnabled,
25+
gzipCompressionEnabled: s.config.GzipCompressionEnabled,
2526
maxCacheableResponseBody: s.config.MaxCacheItemSizeBytes,
2627
maxRequestBody: s.config.MaxRequestBody,
2728
badGatewayPage: s.config.BadGatewayPage,

0 commit comments

Comments
 (0)