summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAlejandro Colomar <alx@nginx.com>2023-07-19 14:22:21 +0200
committerAlejandro Colomar <alx@nginx.com>2023-09-04 03:39:54 +0200
commit00801288b07d9d7c9557667b8020bab61375ca1c (patch)
treecce4ce4cdb7d4a0539905fa5737adc5ccc410ee8
parentd3f4e09c9e2e451b047dbfba739d54b6b1c4c9ba (diff)
downloadunit-00801288b07d9d7c9557667b8020bab61375ca1c.tar.gz
unit-00801288b07d9d7c9557667b8020bab61375ca1c.tar.bz2
HTTP: compress: added "encoding": "gzip".
Signed-off-by: Alejandro Colomar <alx@nginx.com>
-rw-r--r--auto/sources1
-rw-r--r--src/nxt_http_compress.c4
-rw-r--r--src/nxt_http_compress_gzip.c179
-rw-r--r--src/nxt_http_compress_gzip.h21
4 files changed, 204 insertions, 1 deletions
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 <stddef.h>
+
+#include <zlib.h>
+
+#include <nxt_unit_cdefs.h>
+
+#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_ */