diff options
| author | Andrew Clayton <a.clayton@nginx.com> | 2024-11-29 15:46:11 +0000 |
|---|---|---|
| committer | Andrew Clayton <a.clayton@nginx.com> | 2025-04-14 18:11:53 +0100 |
| commit | adaecb6f9efcf435e09c57ecb095f8109d17a817 (patch) | |
| tree | 3d1b4694da8c9c831ad1f414349fbfb6ac4a5603 | |
| parent | 523d42269ff89490b9dad25565121ea5e7696881 (diff) | |
| download | unit-adaecb6f9efcf435e09c57ecb095f8109d17a817.tar.gz unit-adaecb6f9efcf435e09c57ecb095f8109d17a817.tar.bz2 | |
http: Compress static responses
Signed-off-by: Andrew Clayton <a.clayton@nginx.com>
| -rw-r--r-- | src/nxt_http_compression.c | 99 | ||||
| -rw-r--r-- | src/nxt_http_compression.h | 3 | ||||
| -rw-r--r-- | src/nxt_http_static.c | 31 |
3 files changed, 133 insertions, 0 deletions
diff --git a/src/nxt_http_compression.c b/src/nxt_http_compression.c index 6bd13fc9..96882307 100644 --- a/src/nxt_http_compression.c +++ b/src/nxt_http_compression.c @@ -166,6 +166,105 @@ nxt_http_comp_bound(size_t size) } +nxt_int_t +nxt_http_comp_compress_static_response(nxt_task_t *task, nxt_file_t **f, + nxt_file_info_t *fi, + size_t static_buf_len, + size_t *out_total) +{ + char tmp_path[NXT_MAX_PATH_LEN]; + size_t in_size, out_size, rest; + u_char *p; + uint8_t *in, *out; + nxt_int_t ret; + nxt_file_t tfile; + nxt_runtime_t *rt = task->thread->runtime; + + static const char *template = "unit-compr-XXXXXX"; + + *out_total = 0; + + if (nxt_slow_path(strlen(rt->tmp) + 1 + strlen(template) + 1 + > NXT_MAX_PATH_LEN)) + { + return NXT_ERROR; + } + + p = nxt_cpymem(tmp_path, rt->tmp, strlen(rt->tmp)); + *p++ = '/'; + p = nxt_cpymem(p, template, strlen(template)); + *p = '\0'; + + tfile.fd = mkstemp(tmp_path); + if (nxt_slow_path(tfile.fd == -1)) { + nxt_alert(task, "mkstemp(%s) failed %E", tmp_path, nxt_errno); + return NXT_ERROR; + } + unlink(tmp_path); + + in_size = nxt_file_size(fi); + out_size = nxt_http_comp_bound(in_size); + + ret = ftruncate(tfile.fd, out_size); + if (nxt_slow_path(ret == -1)) { + nxt_alert(task, "ftruncate(%d<%s>, %uz) failed %E", + tfile.fd, tmp_path, out_size, nxt_errno); + nxt_file_close(task, &tfile); + return NXT_ERROR; + } + + in = nxt_mem_mmap(NULL, in_size, PROT_READ, MAP_SHARED, (*f)->fd, 0); + if (nxt_slow_path(in == MAP_FAILED)) { + nxt_file_close(task, &tfile); + return NXT_ERROR; + } + + out = nxt_mem_mmap(NULL, out_size, PROT_READ|PROT_WRITE, MAP_SHARED, + tfile.fd, 0); + if (nxt_slow_path(out == MAP_FAILED)) { + nxt_mem_munmap(in, in_size); + nxt_file_close(task, &tfile); + return NXT_ERROR; + } + + rest = in_size; + + do { + bool last; + size_t n; + ssize_t cbytes; + + n = nxt_min(rest, static_buf_len); + + last = n == rest; + + cbytes = nxt_http_comp_compress(out + *out_total, out_size - *out_total, + in + in_size - rest, n, last); + + *out_total += cbytes; + rest -= n; + } while (rest > 0); + + nxt_mem_munmap(in, in_size); + msync(out, out_size, MS_ASYNC); + nxt_mem_munmap(out, out_size); + + ret = ftruncate(tfile.fd, *out_total); + if (nxt_slow_path(ret == -1)) { + nxt_alert(task, "ftruncate(%d<%s>, %uz) failed %E", + tfile.fd, tmp_path, *out_total, nxt_errno); + nxt_file_close(task, &tfile); + return NXT_ERROR; + } + + nxt_file_close(task, *f); + + **f = tfile; + + return NXT_OK; +} + + bool nxt_http_comp_wants_compression(void) { diff --git a/src/nxt_http_compression.h b/src/nxt_http_compression.h index c2007f8e..9f3567c1 100644 --- a/src/nxt_http_compression.h +++ b/src/nxt_http_compression.h @@ -90,6 +90,9 @@ extern const nxt_http_comp_operations_t nxt_http_comp_brotli_ops; #endif +extern nxt_int_t nxt_http_comp_compress_static_response(nxt_task_t *task, + nxt_file_t **f, nxt_file_info_t *fi, size_t static_buf_len, + size_t *out_total); extern bool nxt_http_comp_wants_compression(void); extern bool nxt_http_comp_compressor_is_valid(const nxt_str_t *token); extern nxt_int_t nxt_http_comp_check_compression(nxt_task_t *task, diff --git a/src/nxt_http_static.c b/src/nxt_http_static.c index d56ec587..78b1f150 100644 --- a/src/nxt_http_static.c +++ b/src/nxt_http_static.c @@ -5,6 +5,7 @@ #include <nxt_router.h> #include <nxt_http.h> +#include <nxt_http_compression.h> typedef struct { @@ -576,7 +577,37 @@ nxt_http_static_send(nxt_task_t *task, nxt_http_request_t *r, field->value_length = mtype->length; } + r->resp.mime_type = mtype; + if (ctx->need_body && nxt_file_size(&fi) > 0) { + ret = nxt_http_comp_check_compression(task, r); + if (ret == NXT_HTTP_NOT_ACCEPTABLE) { + nxt_http_request_error(task, r, NXT_HTTP_NOT_ACCEPTABLE); + return; + } else if (ret != NXT_OK) { + goto fail; + } + + if (nxt_http_comp_wants_compression()) { + size_t out_total; + nxt_int_t ret; + + ret = nxt_http_comp_compress_static_response( + task, &f, &fi, + NXT_HTTP_STATIC_BUF_SIZE, + &out_total); + if (ret == NXT_ERROR) { + goto fail; + } + + ret = nxt_file_info(f, &fi); + if (nxt_slow_path(ret != NXT_OK)) { + goto fail; + } + + r->resp.content_length_n = out_total; + } + fb = nxt_mp_zget(r->mem_pool, NXT_BUF_FILE_SIZE); if (nxt_slow_path(fb == NULL)) { goto fail; |
