From d05e2ab887602bb3f3f3020ba14f247f1dd18bef Mon Sep 17 00:00:00 2001 From: Alejandro Colomar Date: Wed, 19 Jul 2023 14:22:21 +0200 Subject: HTTP: compress: added "encoding": "gzip". Signed-off-by: Alejandro Colomar Signed-off-by: Alejandro Colomar --- auto/sources | 1 + src/nxt_http_compress.c | 4 +- src/nxt_http_compress_gzip.c | 179 +++++++++++++++++++++++++++++++++++++++++++ src/nxt_http_compress_gzip.h | 21 +++++ 4 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 src/nxt_http_compress_gzip.c create mode 100644 src/nxt_http_compress_gzip.h diff --git a/auto/sources b/auto/sources index d8884b91..3cf49d4c 100644 --- a/auto/sources +++ b/auto/sources @@ -88,6 +88,7 @@ NXT_LIB_SRCS=" \ src/nxt_h1proto.c \ src/nxt_status.c \ src/nxt_http_compress.c \ + src/nxt_http_compress_gzip.c \ src/nxt_http_request.c \ src/nxt_http_response.c \ src/nxt_http_error.c \ diff --git a/src/nxt_http_compress.c b/src/nxt_http_compress.c index 0f3d8a89..e27dd278 100644 --- a/src/nxt_http_compress.c +++ b/src/nxt_http_compress.c @@ -14,6 +14,7 @@ #include "nxt_conf.h" #include "nxt_errno.h" #include "nxt_http.h" +#include "nxt_http_compress_gzip.h" #include "nxt_list.h" #include "nxt_main.h" #include "nxt_mp.h" @@ -52,7 +53,8 @@ nxt_http_compress_init(nxt_router_conf_t *rtcf, nxt_http_action_t *action, return NXT_ERROR; } - if (0) { + if (nxt_str_eq(&conf->encoding, "gzip", strlen("gzip"))) { + conf->handler = nxt_http_compress_gzip; } else { return NXT_ERROR; diff --git a/src/nxt_http_compress_gzip.c b/src/nxt_http_compress_gzip.c new file mode 100644 index 00000000..75ed9155 --- /dev/null +++ b/src/nxt_http_compress_gzip.c @@ -0,0 +1,179 @@ +/* + * Copyright (C) Alejandro Colomar + * Copyright (C) NGINX, Inc. + */ + + +#include "nxt_http_compress_gzip.h" + +#include + +#include + +#include + +#include "nxt_buf.h" +#include "nxt_clang.h" +#include "nxt_errno.h" +#include "nxt_http.h" +#include "nxt_http_compress.h" +#include "nxt_http_filter.h" +#include "nxt_main.h" +#include "nxt_mp.h" +#include "nxt_router.h" +#include "nxt_string.h" +#include "nxt_types.h" + + +typedef struct nxt_http_compress_gzip_ctx_s nxt_http_compress_gzip_ctx_t; + + +struct nxt_http_compress_gzip_ctx_s { + nxt_http_request_t *r; + nxt_buf_t *b; + + z_stream z; +}; + + +static nxt_http_compress_gzip_ctx_t *nxt_http_compress_gzip_ctx( + nxt_task_t *task, nxt_http_request_t *r, nxt_http_compress_conf_t *conf); + +static void nxt_http_compress_gzip_filter(nxt_task_t *task, void *obj, + void *data); + + +nxt_int_t +nxt_http_compress_gzip(nxt_task_t *task, nxt_http_request_t *r, + nxt_http_compress_conf_t *conf) +{ + nxt_int_t ret; + nxt_http_compress_gzip_ctx_t *ctx; + + static nxt_str_t ce = nxt_string("Content-Encoding"); + static nxt_str_t gzip = nxt_string("gzip"); + + if (r->body_handler == NULL + || r->resp.content_length_n == 0 + || (r->resp.content_length != NULL + && r->resp.content_length->value_length == 1 + && r->resp.content_length->value[0] == '0')) + { + return NXT_OK; + } + + r->resp.content_length = NULL; + r->resp.content_length_n = -1; + + ret = nxt_http_compress_append_field(task, r, &ce, &gzip); + if (nxt_slow_path(ret == NXT_ERROR)) { + return NXT_ERROR; + } + + ctx = nxt_http_compress_gzip_ctx(task, r, conf); + if (nxt_slow_path(ctx == NULL)) { + return NXT_ERROR; + } + + ret = nxt_http_filter_handler_add(r, nxt_http_compress_gzip_filter, ctx); + if (nxt_slow_path(ret == NXT_ERROR)) { + return NXT_ERROR; + } + + return NXT_OK; +} + + +static nxt_http_compress_gzip_ctx_t * +nxt_http_compress_gzip_ctx(nxt_task_t *task, nxt_http_request_t *r, + nxt_http_compress_conf_t *conf) +{ + int ret; + z_stream *z; + nxt_http_compress_gzip_ctx_t *ctx; + + ctx = nxt_mp_zget(r->mem_pool, sizeof(nxt_http_compress_gzip_ctx_t)); + if (nxt_slow_path(ctx == NULL)) { + return NULL; + } + + ctx->r = r; + + z = &ctx->z; + z->zalloc = NULL; + z->zfree = NULL; + z->opaque = NULL; + ret = deflateInit2(z, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WBITS + 16, + MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY); + if (nxt_slow_path(ret != 0)) { + return NULL; + } + + return ctx; +} + + +static void +nxt_http_compress_gzip_filter(nxt_task_t *task, void *obj, void *data) +{ + int ret; + ssize_t size; + z_stream *z; + nxt_buf_t **b, *tmp; + nxt_bool_t is_last; + nxt_http_request_t *r; + nxt_http_compress_gzip_ctx_t *ctx; + + b = obj; + ctx = data; + z = &ctx->z; + + r = ctx->r; + + is_last = ((*b)->next != NULL + && (*b)->next->completion_handler != (*b)->completion_handler); + + z->next_in = (*b)->mem.pos; + z->avail_in = (*b)->mem.free - (*b)->mem.pos; + + size = deflateBound(z, z->avail_in); + + tmp = nxt_buf_mem_alloc(r->mem_pool, size, 0); + if (nxt_slow_path(tmp == NULL)) { + return; + } + + nxt_memcpy(tmp, *b, offsetof(nxt_buf_t, mem)); + tmp->data = r->mem_pool; + + z->next_out = tmp->mem.start; + z->avail_out = tmp->mem.end - tmp->mem.start; + + ret = deflate(z, is_last ? Z_FINISH : Z_SYNC_FLUSH); + if (nxt_slow_path(ret == Z_STREAM_ERROR || ret == Z_BUF_ERROR)) { + goto fail; + } + + tmp->mem.free = tmp->mem.end - z->avail_out; + size = tmp->mem.free - tmp->mem.start; + + if ((*b)->mem.end - (*b)->mem.pos >= size) { + (*b)->mem.free = nxt_cpymem((*b)->mem.pos, tmp->mem.start, size); + + } else { + nxt_swap(b, &tmp); + } + +fail: + + nxt_mp_free(tmp->data, tmp); + + if (is_last) { + ret = deflateEnd(z); + if (ret != Z_OK) { + return; + } + } + + return; +} diff --git a/src/nxt_http_compress_gzip.h b/src/nxt_http_compress_gzip.h new file mode 100644 index 00000000..15facc69 --- /dev/null +++ b/src/nxt_http_compress_gzip.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) Alejandro Colomar + * Copyright (C) NGINX, Inc. + */ + +#ifndef NXT_HTTP_COMPRESS_GZIP_H_INCLUDED_ +#define NXT_HTTP_COMPRESS_GZIP_H_INCLUDED_ + + +#include "nxt_router.h" + +#include "nxt_http.h" +#include "nxt_main.h" +#include "nxt_types.h" + + +nxt_int_t nxt_http_compress_gzip(nxt_task_t *task, nxt_http_request_t *r, + nxt_http_compress_conf_t *conf); + + +#endif /* NXT_HTTP_COMPRESS_GZIP_H_INCLUDED_ */ -- cgit