Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gzip filter #914

Closed
wants to merge 14 commits into from
Closed

gzip filter #914

wants to merge 14 commits into from

Conversation

alejandro-colomar
Copy link
Contributor

@alejandro-colomar alejandro-colomar commented Aug 2, 2023

This implements a compression filter which can be applied to any actions to compress their body.

The feature is not yet finished, and has some known limitations which haven't been decided, or that have been accepted for the initial implementation but haven't been implemented yet:

  • Parse the Accept-Encoding request header, and skip the compression if gzip is not supported by the client. Currently, it compresses unconditionally.
  • Validation of JSON configuration. While the current validation just works, the error message for unsupported encodings could be improved. We could also detect when a compression level is unsupported.
  • A configuration that attempts to compress a response from a "return" action will succeed, and silently do nothing; it's a no-op. We may want to reject such a config. [discarded: in the future we may add bodies in return, and so gzip will be useful; let's keep it a noop]
  • Allow specifying which MIME types should be compressed. Currently it's all or nothing.
  • Allow specifying the minimum size of a response so that it gets compressed. Currently, all responses are compressed (except if the size is 0).
  • Conditionally compile compression module.

And some limitations that we decided to defer for a future improvement release:

  • Currently, we only support gzip. However, the design is easy to extend to support other encodings.
  • Setting the Vary response header field.
  • Conditional compression based on the HTTP request (e.g., Cache-Control, Expires, ETag)

Here's an example configuration that can be used for trying this feature:

{
	"settings": {
		"http": { "log_route": true }
	},
	"listeners": {
		"*:8080": { "pass": "routes/di" },
		"*:8081": { "pass": "routes/n" },
		"*:81":   { "pass": "routes/o" },
		"*:82":   { "pass": "routes/s" },
		"*:83":   { "pass": "routes/a" },
		"*:84":   { "pass": "routes/u" },
		"*:85":   { "pass": "routes/r" }
	},
	"routes": {
		"di": [{
			"action": {
				"share": "/srv/www/readme"
			}
		}],
		"n": [{
			"action": {
				"share": "/srv/www/empty"
			}
		}],
		"o": [{
			"action": {
				"proxy": "http://127.0.0.1:8081",
				"compress": { "encoding": "gzip" }
			}
		}],
		"s": [{
			"action": {
				"share": "/srv/www/unit/index.html",
				"compress": { "encoding": "gzip" }
			}
		}],
		"a": [{
			"action": {
				"pass": "applications/perl",
				"compress": { "encoding": "gzip" }
			}
		}],
		"u": [{
			"action": {
				"proxy": "http://127.0.0.1:8080",
				"compress": { "encoding": "gzip" }
			}
		}],
		"r": [{
			"action": {
				"return": 321,
				"compress": { "encoding": "gzip" }
			}
		}]
	},
	"applications": {
		"perl": {
			"type": "perl",
			"working_directory": "/home/alx/srv/www/perl/",
			"script": "./sock.psgi"
		}
	}
}
$ cat /home/alx/srv/www/perl/sock.psgi 
my $app = sub {
    return [
        "200",
        [ "Content-Type" => "text/plain" ],
        [ "Hello, Perl on Unit!\n" ],
    ];
};

@alejandro-colomar alejandro-colomar linked an issue Aug 2, 2023 that may be closed by this pull request
@alejandro-colomar
Copy link
Contributor Author

alejandro-colomar commented Aug 2, 2023

v2 changes:

  • Remove "header" action.
  • Remove "chunked" action.
  • Remove support for multiple body handlers. (It was unused.)
  • Remove nxt_list_remove_first(). (It was unused.)
$ git range-diff ngx/master gh/gzip gzip 
 1:  b7a72a92 =  1:  b7a72a92 HTTP: refactor: inverted conditional to reduce nesting.
 2:  913661c1 =  2:  913661c1 Router: refactor: factored out application creation loop.
 3:  db7afc3c =  3:  db7afc3c Router: refactor: factored out listeners creation loop.
 4:  6dea49ea =  4:  6dea49ea Refactor: inverted conditional to reduce nesting.
 5:  5b28e284 =  5:  5b28e284 Refactor: using a temporary variable in a macro.
 6:  e3d90163 =  6:  e3d90163 Var: refactor: removed dead code.
 7:  9562fc1d =  7:  9562fc1d Var: refactor: removed dead code.
 8:  2c5ba36c =  8:  2c5ba36c Var: refactor: removed dead code.
 9:  c5795ebd =  9:  c5795ebd Refactor: storing the body_handler as part of r.
10:  f77c8d95 = 10:  f77c8d95 HTTP: refactor: transformed loop into recursive call.
11:  cd975ee8 = 11:  cd975ee8 HTTP: using an array of actions (of size 1).
12:  e5a7d522 = 12:  e5a7d522 HTTP: refactor: differentiated actions array from action element.
13:  1cc53ebf = 13:  1cc53ebf HTTP: refactor: using dynamic allocation for nxt_http_actions_t elements.
14:  88a1a4aa = 14:  88a1a4aa HTTP: using an array of actions.
15:  9c0bdeb4 = 15:  9c0bdeb4 HTTP: logging actions taken.
16:  681efb26 = 16:  681efb26 HTTP: implemented rewrite as a standalone action.
17:  fa08ba22 = 17:  fa08ba22 Added nxt_sizeof_member().
18:  927b283d = 18:  927b283d Added macro that unlinks current element in a list loop.
19:  ba1b269a <  -:  -------- HTTP: introduced action "header" for modifying a header field.
20:  57d73162 <  -:  -------- HTTP: supporting variables in the "header" action.
21:  1052c10f <  -:  -------- HTTP: header: refactor: renamed functions in preparation for supporting response headers.
22:  605b0424 <  -:  -------- HTTP: header: supporting response headers.
23:  506b7b24 = 19:  e1621fb3 HTTP: refactor: requesting the fallback actions from the action itself.
24:  fef131e5 = 20:  82f0eb78 HTTP: refactor: requesting the actions from the route handler.
25:  625e5ef5 = 21:  a0361b46 HTTP: refactor: failing in the route handler.
26:  bf3a21ff = 22:  2b8ffbc1 Configuration: refactor: made "fallback" an object.
27:  76b94e15 = 23:  a1717f4a HTTP: pass: refactor: using a ctx.
28:  6e8a89b1 = 24:  d8b35fc6 HTTP: return: refactor: using 'add_header' member in ctx.
29:  0279594e = 25:  bd5ff8cd HTTP: refactor: transformed loop into recursive call.
30:  4cfee9db ! 26:  213384e1 WIP: running each action after the previous action has succeeded.
    [squash the following commit]
31:  51280492 <  -:  -------- f: WIP: running each action after the previous...
32:  c66ab490 ! 27:  ac5a2231 WIP: send headers at the end
    [squash the following commit]
33:  d54dbfd6 <  -:  -------- f_WIP_send_headers_at_the_...
34:  5db3e126 = 28:  637e78a9 HTTP: refactor: moved setting of route->name to route creation.
35:  4683babb = 29:  21f1250d HTTP: refactor: made function static.
36:  ebd7a28c = 30:  e2e0633d HTTP: refactor: storing actions route path at configuration.
37:  b6fde090 = 31:  79211bf4 HTTP: refactor: added nxt_http_fallback_create().
38:  d06a6d07 = 32:  3553e9f7 HTTP: refactor: merged nxt_memzero() call into nxt_mp_zalloc().
39:  f16dc684 = 33:  bd5ab86b HTTP: logging full path of actions.
40:  7905477f = 34:  317a12de Proxy: refactor: using goto fail.
41:  d48ef32e <  -:  -------- HTTP: refactor: supporting a list of body_handlers
42:  fa310ae5 = 35:  6f60fc32 Static: refactor: transformed goto into do-while loop.
43:  2facd584 ! 36:  d538ac08 HTTP: supporting a list of filter_handlers
    [...]
44:  d5232a26 <  -:  -------- Added macro that removes first element in a list loop.
45:  16c7c7be = 37:  e03347c1 Auto: compiling with zlib.
46:  b88f5c59 ! 38:  609cc576 HTTP: added "compress" action
    [...]
47:  d5e99cd5 <  -:  -------- HTTP: added "chunk" action.

@alejandro-colomar
Copy link
Contributor Author

v3 changes:

  • Fix glitch of rebasing (patch 33).
  • Don't log full path of actions. (This feature will be interesting, but as a separate feature.)
$ git range-diff master gh/gzip gzip 
 1:  b7a72a92 =  1:  b7a72a92 HTTP: refactor: inverted conditional to reduce nesting.
 2:  913661c1 =  2:  913661c1 Router: refactor: factored out application creation loop.
 3:  db7afc3c =  3:  db7afc3c Router: refactor: factored out listeners creation loop.
 4:  6dea49ea =  4:  6dea49ea Refactor: inverted conditional to reduce nesting.
 5:  5b28e284 =  5:  5b28e284 Refactor: using a temporary variable in a macro.
 6:  e3d90163 =  6:  e3d90163 Var: refactor: removed dead code.
 7:  9562fc1d =  7:  9562fc1d Var: refactor: removed dead code.
 8:  2c5ba36c =  8:  2c5ba36c Var: refactor: removed dead code.
 9:  c5795ebd =  9:  c5795ebd Refactor: storing the body_handler as part of r.
10:  f77c8d95 = 10:  f77c8d95 HTTP: refactor: transformed loop into recursive call.
11:  cd975ee8 = 11:  cd975ee8 HTTP: using an array of actions (of size 1).
12:  e5a7d522 = 12:  e5a7d522 HTTP: refactor: differentiated actions array from action element.
13:  1cc53ebf = 13:  1cc53ebf HTTP: refactor: using dynamic allocation for nxt_http_actions_t elements.
14:  88a1a4aa = 14:  88a1a4aa HTTP: using an array of actions.
15:  9c0bdeb4 = 15:  9c0bdeb4 HTTP: logging actions taken.
16:  681efb26 = 16:  681efb26 HTTP: implemented rewrite as a standalone action.
17:  fa08ba22 = 17:  fa08ba22 Added nxt_sizeof_member().
18:  927b283d = 18:  927b283d Added macro that unlinks current element in a list loop.
19:  e1621fb3 = 19:  e1621fb3 HTTP: refactor: requesting the fallback actions from the action itself.
20:  82f0eb78 = 20:  82f0eb78 HTTP: refactor: requesting the actions from the route handler.
21:  a0361b46 = 21:  a0361b46 HTTP: refactor: failing in the route handler.
22:  2b8ffbc1 = 22:  2b8ffbc1 Configuration: refactor: made "fallback" an object.
23:  a1717f4a = 23:  a1717f4a HTTP: pass: refactor: using a ctx.
24:  d8b35fc6 = 24:  d8b35fc6 HTTP: return: refactor: using 'add_header' member in ctx.
25:  bd5ff8cd = 25:  bd5ff8cd HTTP: refactor: transformed loop into recursive call.
26:  213384e1 = 26:  213384e1 WIP: running each action after the previous action has succeeded.
27:  ac5a2231 = 27:  ac5a2231 WIP: send headers at the end
28:  637e78a9 <  -:  -------- HTTP: refactor: moved setting of route->name to route creation.
29:  21f1250d ! 28:  5097a09b HTTP: refactor: made function static.
    [...]
30:  e2e0633d <  -:  -------- HTTP: refactor: storing actions route path at configuration.
31:  79211bf4 <  -:  -------- HTTP: refactor: added nxt_http_fallback_create().
32:  3553e9f7 <  -:  -------- HTTP: refactor: merged nxt_memzero() call into nxt_mp_zalloc().
33:  bd5ab86b <  -:  -------- HTTP: logging full path of actions.
34:  317a12de = 29:  ef025bcb Proxy: refactor: using goto fail.
35:  6f60fc32 = 30:  97140f05 Static: refactor: transformed goto into do-while loop.
36:  d538ac08 = 31:  c93013f9 HTTP: supporting a list of filter_handlers
37:  e03347c1 = 32:  c04c92a1 Auto: compiling with zlib.
38:  609cc576 ! 33:  16653940 HTTP: added "compress" action
    @@ src/nxt_http_compress.c (new)
     +
     +    conf = action->u.conf;
     +
    -+    if (nxt_list_nelts(r->body_handlers) == 0) {
    ++    if (r->body_handler == NULL) {
     +        goto skip;
     +    }
     +

@alejandro-colomar
Copy link
Contributor Author

alejandro-colomar commented Aug 2, 2023

v4 changes:

  • Don't use action-chaining syntax. Use syntax similar to how "rewrite" works today.

    Now the syntax is like this:

    "action": {
        ...
        "compress": { "encoding": "gzip", "level": 9 }
    }
  • Remove support for action-chaining syntax. There's still some action-chaining infrastructure that should be removed in a future rebase, but I wanted this rebase to be as small as possible.

$ git range-diff ngx/master gh/gzip gzip 
 1:  b7a72a92 =  1:  b7a72a92 HTTP: refactor: inverted conditional to reduce nesting.
 2:  913661c1 =  2:  913661c1 Router: refactor: factored out application creation loop.
 3:  db7afc3c =  3:  db7afc3c Router: refactor: factored out listeners creation loop.
 4:  6dea49ea =  4:  6dea49ea Refactor: inverted conditional to reduce nesting.
 5:  5b28e284 =  5:  5b28e284 Refactor: using a temporary variable in a macro.
 6:  e3d90163 =  6:  e3d90163 Var: refactor: removed dead code.
 7:  9562fc1d =  7:  9562fc1d Var: refactor: removed dead code.
 8:  2c5ba36c =  8:  2c5ba36c Var: refactor: removed dead code.
 9:  c5795ebd =  9:  c5795ebd Refactor: storing the body_handler as part of r.
10:  f77c8d95 = 10:  f77c8d95 HTTP: refactor: transformed loop into recursive call.
11:  cd975ee8 = 11:  cd975ee8 HTTP: using an array of actions (of size 1).
12:  e5a7d522 = 12:  e5a7d522 HTTP: refactor: differentiated actions array from action element.
13:  1cc53ebf = 13:  1cc53ebf HTTP: refactor: using dynamic allocation for nxt_http_actions_t elements.
14:  88a1a4aa = 14:  88a1a4aa HTTP: using an array of actions.
15:  9c0bdeb4 = 15:  9c0bdeb4 HTTP: logging actions taken.
16:  681efb26 <  -:  -------- HTTP: implemented rewrite as a standalone action.
17:  fa08ba22 = 16:  c4f5e9e4 Added nxt_sizeof_member().
18:  927b283d = 17:  e8ea2e16 Added macro that unlinks current element in a list loop.
19:  e1621fb3 = 18:  e3d14cb9 HTTP: refactor: requesting the fallback actions from the action itself.
20:  82f0eb78 ! 19:  5cd6a085 HTTP: refactor: requesting the actions from the route handler.
    [...]
21:  a0361b46 ! 20:  a8a0e9ba HTTP: refactor: failing in the route handler.
    [...]
22:  2b8ffbc1 ! 21:  7405dc59 Configuration: refactor: made "fallback" an object.
    [...]
23:  a1717f4a ! 22:  d628b052 HTTP: pass: refactor: using a ctx.
    [...]
24:  d8b35fc6 = 23:  b6fcd7fa HTTP: return: refactor: using 'add_header' member in ctx.
25:  bd5ff8cd <  -:  -------- HTTP: refactor: transformed loop into recursive call.
26:  213384e1 <  -:  -------- WIP: running each action after the previous action has succeeded.
27:  ac5a2231 <  -:  -------- WIP: send headers at the end
28:  5097a09b = 24:  a8c8b350 HTTP: refactor: made function static.
29:  ef025bcb ! 25:  3b899078 Proxy: refactor: using goto fail.
    [...]
30:  97140f05 = 26:  4e2826ec Static: refactor: transformed goto into do-while loop.
31:  c93013f9 = 27:  030b5a3b HTTP: supporting a list of filter_handlers
32:  c04c92a1 = 28:  17bde4ff Auto: compiling with zlib.
33:  16653940 ! 29:  29cab2c1 HTTP: added "compress" action
    [... change the accepted configuration syntax ...]

@alejandro-colomar
Copy link
Contributor Author

v5 changes:

  • Remove the 'actions' internal object. This removes part of the action-chaining infrastructure.
$ git range-diff master gh/gzip gzip 
 1:  b7a72a92 =  1:  b7a72a92 HTTP: refactor: inverted conditional to reduce nesting.
 2:  913661c1 =  2:  913661c1 Router: refactor: factored out application creation loop.
 3:  db7afc3c =  3:  db7afc3c Router: refactor: factored out listeners creation loop.
 4:  6dea49ea =  4:  6dea49ea Refactor: inverted conditional to reduce nesting.
 5:  5b28e284 =  5:  5b28e284 Refactor: using a temporary variable in a macro.
 6:  e3d90163 =  6:  e3d90163 Var: refactor: removed dead code.
 7:  9562fc1d =  7:  9562fc1d Var: refactor: removed dead code.
 8:  2c5ba36c =  8:  2c5ba36c Var: refactor: removed dead code.
 9:  c5795ebd =  9:  c5795ebd Refactor: storing the body_handler as part of r.
10:  f77c8d95 = 10:  f77c8d95 HTTP: refactor: transformed loop into recursive call.
11:  cd975ee8 = 11:  cd975ee8 HTTP: using an array of actions (of size 1).
12:  e5a7d522 <  -:  -------- HTTP: refactor: differentiated actions array from action element.
13:  1cc53ebf <  -:  -------- HTTP: refactor: using dynamic allocation for nxt_http_actions_t elements.
14:  88a1a4aa <  -:  -------- HTTP: using an array of actions.
15:  9c0bdeb4 <  -:  -------- HTTP: logging actions taken.
16:  c4f5e9e4 = 12:  27015477 Added nxt_sizeof_member().
17:  e8ea2e16 = 13:  b42ebb71 Added macro that unlinks current element in a list loop.
18:  e3d14cb9 = 14:  a0f4e091 HTTP: refactor: requesting the fallback actions from the action itself.
19:  5cd6a085 ! 15:  ca0e393c HTTP: refactor: requesting the actions from the route handler.
    [...]
20:  a8a0e9ba ! 16:  120e923e HTTP: refactor: failing in the route handler.
    [...]
21:  7405dc59 <  -:  -------- Configuration: refactor: made "fallback" an object.
 -:  -------- > 17:  98f0eae0 Configuration: refactor: made "fallback" an object.
22:  d628b052 ! 18:  c8dc2638 HTTP: pass: refactor: using a ctx.
    [...]
23:  b6fcd7fa = 19:  544c1c1e HTTP: return: refactor: using 'add_header' member in ctx.
24:  a8c8b350 <  -:  -------- HTTP: refactor: made function static.
25:  3b899078 = 20:  674d2c16 Proxy: refactor: using goto fail.
26:  4e2826ec = 21:  78b57cf8 Static: refactor: transformed goto into do-while loop.
27:  030b5a3b = 22:  c0f9c9ab HTTP: supporting a list of filter_handlers
28:  17bde4ff = 23:  2441331a Auto: compiling with zlib.
29:  29cab2c1 = 24:  722bccfe HTTP: added "compress" action.

@alejandro-colomar
Copy link
Contributor Author

v6 changes:

  • Fix use of undeclared variable. Reported by @lcrilly .
$ git range-diff master gh/gzip gzip 
 1:  b7a72a92 =  1:  b7a72a92 HTTP: refactor: inverted conditional to reduce nesting.
 2:  913661c1 =  2:  913661c1 Router: refactor: factored out application creation loop.
 3:  db7afc3c !  3:  82d67893 Router: refactor: factored out listeners creation loop.
    @@ src/nxt_router.c: nxt_router_conf_create_applications(nxt_task_t *task,
     +    nxt_uint_t                  n, i;
     +    nxt_tls_init_t              *tls_init;
     +    nxt_conf_value_t            *certificate;
    ++    nxt_conf_value_t            *value;
     +#endif
     +    nxt_conf_value_t            *conf, *http, *websocket;
     +    nxt_conf_value_t            *listener;
 4:  6dea49ea =  4:  4a57864f Refactor: inverted conditional to reduce nesting.
 5:  5b28e284 =  5:  dbd6772f Refactor: using a temporary variable in a macro.
 6:  e3d90163 =  6:  d7e155ee Var: refactor: removed dead code.
 7:  9562fc1d =  7:  876cdb39 Var: refactor: removed dead code.
 8:  2c5ba36c =  8:  3f6df0b0 Var: refactor: removed dead code.
 9:  c5795ebd =  9:  8a8b9fb9 Refactor: storing the body_handler as part of r.
10:  f77c8d95 = 10:  07738d11 HTTP: refactor: transformed loop into recursive call.
11:  cd975ee8 = 11:  25bb20b8 HTTP: using an array of actions (of size 1).
12:  27015477 = 12:  9015aff5 Added nxt_sizeof_member().
13:  b42ebb71 = 13:  8eb7864c Added macro that unlinks current element in a list loop.
14:  a0f4e091 = 14:  7f07a904 HTTP: refactor: requesting the fallback actions from the action itself.
15:  ca0e393c = 15:  b0f273a4 HTTP: refactor: requesting the actions from the route handler.
16:  120e923e = 16:  af88ec98 HTTP: refactor: failing in the route handler.
17:  98f0eae0 = 17:  8e2cfccd Configuration: refactor: made "fallback" an object.
18:  c8dc2638 = 18:  d65f8b8b HTTP: pass: refactor: using a ctx.
19:  544c1c1e = 19:  12abf196 HTTP: return: refactor: using 'add_header' member in ctx.
20:  674d2c16 = 20:  2b7435bd Proxy: refactor: using goto fail.
21:  78b57cf8 = 21:  9740dbe9 Static: refactor: transformed goto into do-while loop.
22:  c0f9c9ab = 22:  ef039bfe HTTP: supporting a list of filter_handlers
23:  2441331a = 23:  dc02653c Auto: compiling with zlib.
24:  722bccfe = 24:  d337d0cc HTTP: added "compress" action.

@alejandro-colomar
Copy link
Contributor Author

v7 changes:

  • Remove last remnants of action chaining.
$ git range-diff master gh/gzip gzip 
 1:  b7a72a92 =  1:  b7a72a92 HTTP: refactor: inverted conditional to reduce nesting.
 2:  913661c1 =  2:  913661c1 Router: refactor: factored out application creation loop.
 3:  82d67893 =  3:  82d67893 Router: refactor: factored out listeners creation loop.
 4:  4a57864f =  4:  4a57864f Refactor: inverted conditional to reduce nesting.
 5:  dbd6772f =  5:  dbd6772f Refactor: using a temporary variable in a macro.
 6:  d7e155ee =  6:  d7e155ee Var: refactor: removed dead code.
 7:  876cdb39 =  7:  876cdb39 Var: refactor: removed dead code.
 8:  3f6df0b0 =  8:  3f6df0b0 Var: refactor: removed dead code.
 9:  8a8b9fb9 <  -:  -------- Refactor: storing the body_handler as part of r.
10:  07738d11 =  9:  ca4b663c HTTP: refactor: transformed loop into recursive call.
11:  25bb20b8 <  -:  -------- HTTP: using an array of actions (of size 1).
12:  9015aff5 <  -:  -------- Added nxt_sizeof_member().
13:  8eb7864c <  -:  -------- Added macro that unlinks current element in a list loop.
14:  7f07a904 ! 10:  171883e4 HTTP: refactor: requesting the fallback actions from the action itself.
    [...squash "Configuration: refactor: made "fallback" an object." into it...]
15:  b0f273a4 = 11:  75e5c5f0 HTTP: refactor: requesting the actions from the route handler.
16:  af88ec98 = 12:  b3bfebfe HTTP: refactor: failing in the route handler.
17:  8e2cfccd <  -:  -------- Configuration: refactor: made "fallback" an object.
18:  d65f8b8b = 13:  26a42cf7 HTTP: pass: refactor: using a ctx.
19:  12abf196 = 14:  3dc42dc2 HTTP: return: refactor: using 'add_header' member in ctx.
20:  2b7435bd ! 15:  00f0f060 Proxy: refactor: using goto fail.
    [...]
21:  9740dbe9 = 16:  19753a09 Static: refactor: transformed goto into do-while loop.
22:  ef039bfe ! 17:  4b2c077f HTTP: supporting a list of filter_handlers
    [...]
23:  dc02653c = 18:  f32099d6 Auto: compiling with zlib.
24:  d337d0cc ! 19:  c915ec90 HTTP: added "compress" action.
    [...]

@alejandro-colomar
Copy link
Contributor Author

alejandro-colomar commented Aug 2, 2023

v8 changes:

  • Fix NJS build. [reported by @lcrilly ]
$ git range-diff master gh/gzip gzip 
 1:  b7a72a92 =  1:  b7a72a92 HTTP: refactor: inverted conditional to reduce nesting.
 2:  913661c1 !  2:  866b88f9 Router: refactor: factored out application creation loop.
    [...]
 3:  82d67893 !  3:  9ae189dd Router: refactor: factored out listeners creation loop.
    [...]
 4:  4a57864f =  4:  3103c425 Refactor: inverted conditional to reduce nesting.
 5:  dbd6772f =  5:  6cd85c10 Refactor: using a temporary variable in a macro.
 6:  d7e155ee =  6:  2ff2a2ef Var: refactor: removed dead code.
 7:  876cdb39 =  7:  c75b2664 Var: refactor: removed dead code.
 8:  3f6df0b0 =  8:  41614c37 Var: refactor: removed dead code.
 9:  ca4b663c =  9:  13267383 HTTP: refactor: transformed loop into recursive call.
10:  171883e4 = 10:  297b7a81 HTTP: refactor: requesting the fallback action from the action itself.
11:  75e5c5f0 = 11:  fc8288f3 HTTP: refactor: requesting the actions from the route handler.
12:  b3bfebfe = 12:  70239041 HTTP: refactor: failing in the route handler.
13:  26a42cf7 = 13:  a22acc17 HTTP: pass: refactor: using a ctx.
14:  3dc42dc2 = 14:  c6392f7a HTTP: return: refactor: using 'add_header' member in ctx.
15:  00f0f060 = 15:  b72c3efb Proxy: refactor: using goto fail.
16:  19753a09 = 16:  f9c1e0d2 Static: refactor: transformed goto into do-while loop.
17:  4b2c077f = 17:  f79b5268 HTTP: supporting a list of filter_handlers
18:  f32099d6 = 18:  2e4ab1f8 Auto: compiling with zlib.
19:  c915ec90 = 19:  63bfeaf5 HTTP: added "compress" action.

@alejandro-colomar
Copy link
Contributor Author

alejandro-colomar commented Aug 3, 2023

v9 changes:

  • Make it work for all actions. It now works for "proxy" (thanks to @hongzhidao )
  • Fix memory leak with zero-length responses.
$ git range-diff master gh/gzip gzip 
 1:  b7a72a92 =  1:  b7a72a92 HTTP: refactor: inverted conditional to reduce nesting.
 2:  866b88f9 =  2:  866b88f9 Router: refactor: factored out application creation loop.
 3:  9ae189dd =  3:  9ae189dd Router: refactor: factored out listeners creation loop.
 4:  3103c425 =  4:  3103c425 Refactor: inverted conditional to reduce nesting.
 5:  6cd85c10 =  5:  6cd85c10 Refactor: using a temporary variable in a macro.
 6:  2ff2a2ef =  6:  2ff2a2ef Var: refactor: removed dead code.
 7:  c75b2664 =  7:  c75b2664 Var: refactor: removed dead code.
 8:  41614c37 =  8:  41614c37 Var: refactor: removed dead code.
 -:  -------- >  9:  ba7f3cfd Refactor: storing the body_handler as part of r.
    [removed in v7, but reintroduced here, as it was necessary for generalizing for all actions]
 9:  13267383 = 10:  65f86310 HTTP: refactor: transformed loop into recursive call.
10:  297b7a81 = 11:  33490c4e HTTP: refactor: requesting the fallback action from the action itself.
11:  fc8288f3 = 12:  2df64200 HTTP: refactor: requesting the actions from the route handler.
12:  70239041 = 13:  5c45ac0d HTTP: refactor: failing in the route handler.
13:  a22acc17 = 14:  933dd00d HTTP: pass: refactor: using a ctx.
14:  c6392f7a = 15:  274c7e19 HTTP: return: refactor: using 'add_header' member in ctx.
15:  b72c3efb ! 16:  50f3d937 Proxy: refactor: using goto fail.
    [...]
16:  f9c1e0d2 = 17:  df4767a5 Static: refactor: transformed goto into do-while loop.
17:  f79b5268 ! 18:  207ba314 HTTP: supporting a list of filter_handlers
    [...]
 -:  -------- > 19:  e76084d0 HTTP: storing 'action' within 'r'.
    [extracted from @hongzhidao 's implementation of controlling response headers]
18:  2e4ab1f8 = 20:  5176181a Auto: compiling with zlib.
19:  63bfeaf5 ! 21:  daab9217 HTTP: added "compress" action.
    [make generic for any action; fix memory leak with zero-length responses]

@alejandro-colomar
Copy link
Contributor Author

alejandro-colomar commented Aug 3, 2023

Testing:

$ cat gzip-v9.json 
{
	"settings": {
		"http": { "log_route": true }
	},
	"listeners": {
		"*:8080": { "pass": "routes/di" },
		"*:8081": { "pass": "routes/n" },
		"*:81":   { "pass": "routes/o" },
		"*:82":   { "pass": "routes/s" },
		"*:83":   { "pass": "routes/a" },
		"*:84":   { "pass": "routes/u" },
		"*:85":   { "pass": "routes/r" }
	},
	"routes": {
		"di": [{
			"action": {
				"share": "/srv/www/readme"
			}
		}],
		"n": [{
			"action": {
				"share": "/srv/www/empty"
			}
		}],
		"o": [{
			"action": {
				"proxy": "http://127.0.0.1:8081",
				"compress": { "encoding": "gzip" }
			}
		}],
		"s": [{
			"action": {
				"share": "/srv/www/unit/index.html",
				"compress": { "encoding": "gzip" }
			}
		}],
		"a": [{
			"action": {
				"pass": "applications/perl",
				"compress": { "encoding": "gzip" }
			}
		}],
		"u": [{
			"action": {
				"proxy": "http://127.0.0.1:8080",
				"compress": { "encoding": "gzip" }
			}
		}],
		"r": [{
			"action": {
				"return": 321,
				"compress": { "encoding": "gzip" }
			}
		}]
	},
	"applications": {
		"perl": {
			"type": "perl",
			"working_directory": "/home/alx/srv/www/perl/",
			"script": "./sock.psgi"
		}
	}
}
$ cat /home/alx/srv/www/perl/sock.psgi
my $app = sub {
    return [
        "200",
        [ "Content-Type" => "text/plain" ],
        [ "Hello, Perl on Unit!\n" ],
    ];
};
$ curl localhost:8080
rdm
$ curl localhost:8081
$ curl localhost:81
$ curl localhost:82
Warning: Binary output can mess up your terminal. Use "--output -" to tell 
Warning: curl to output it to your terminal anyway, or consider "--output 
Warning: <FILE>" to save to a file.
$ curl localhost:82 --compressed
idx
$ curl localhost:83
Warning: Binary output can mess up your terminal. Use "--output -" to tell 
Warning: curl to output it to your terminal anyway, or consider "--output 
Warning: <FILE>" to save to a file.
$ curl localhost:83 --compressed
Hello, Perl on Unit!
$ curl localhost:84
Warning: Binary output can mess up your terminal. Use "--output -" to tell 
Warning: curl to output it to your terminal anyway, or consider "--output 
Warning: <FILE>" to save to a file.
$ curl localhost:84 --compressed
rdm

This round of testing found some bug, triggered only by requests received on port 83, that is, the application. I'll need to fix that:

2023/08/03 13:50:27 [alert] 10291#10294 freed pointer is out of pool: 7F8D38043400

@alejandro-colomar
Copy link
Contributor Author

v10 changes:

Rebase to master.

$ git range-diff b7a72a92^..gh/actions master..actions
 1:  b7a72a92 !  1:  28777b66 HTTP: refactor: inverted conditional to reduce nesting.
    [...]
 2:  866b88f9 =  2:  e448d40f Router: refactor: factored out application creation loop.
 3:  9ae189dd =  3:  10b128f3 Router: refactor: factored out listeners creation loop.
 4:  3103c425 =  4:  9315fc4f Refactor: inverted conditional to reduce nesting.
 5:  6cd85c10 =  5:  23504762 Refactor: using a temporary variable in a macro.
 6:  2ff2a2ef =  6:  6ae38deb Var: refactor: removed dead code.
 7:  c75b2664 =  7:  7ddcfe4f Var: refactor: removed dead code.
 8:  41614c37 =  8:  4146802b Var: refactor: removed dead code.
 9:  ba7f3cfd !  9:  3d96d043 Refactor: storing the body_handler as part of r.
    [...]
10:  65f86310 ! 10:  c8d6b131 HTTP: refactor: transformed loop into recursive call.
    [...]
11:  33490c4e = 11:  419ab3a9 HTTP: refactor: requesting the fallback action from the action itself.
12:  2df64200 ! 12:  f2e16c33 HTTP: refactor: requesting the actions from the route handler.
    [...]
13:  5c45ac0d = 13:  872a5315 HTTP: refactor: failing in the route handler.
14:  933dd00d = 14:  96f26a32 HTTP: pass: refactor: using a ctx.
15:  274c7e19 = 15:  39d9d8c6 HTTP: return: refactor: using 'add_header' member in ctx.
16:  50f3d937 = 16:  1c9a0910 Proxy: refactor: using goto fail.
17:  df4767a5 = 17:  4bbbe719 Static: refactor: transformed goto into do-while loop.
18:  207ba314 = 18:  d6bbbd9a HTTP: supporting a list of filter_handlers
19:  e76084d0 ! 19:  12742806 HTTP: storing 'action' within 'r'.
    [...]
20:  5176181a = 20:  cb553985 Auto: compiling with zlib.
21:  daab9217 ! 21:  ab539acb HTTP: added "compress" action.
    [...]

@alejandro-colomar
Copy link
Contributor Author

v11 changes:

Drop patch that's unnecessary after the rebase.

$ git range-diff master..gh/actions master..actions
 1:  28777b66 =  1:  28777b66 HTTP: refactor: inverted conditional to reduce nesting.
 2:  e448d40f =  2:  e448d40f Router: refactor: factored out application creation loop.
 3:  10b128f3 =  3:  10b128f3 Router: refactor: factored out listeners creation loop.
 4:  9315fc4f =  4:  9315fc4f Refactor: inverted conditional to reduce nesting.
 5:  23504762 =  5:  23504762 Refactor: using a temporary variable in a macro.
 6:  6ae38deb =  6:  6ae38deb Var: refactor: removed dead code.
 7:  7ddcfe4f =  7:  7ddcfe4f Var: refactor: removed dead code.
 8:  4146802b =  8:  4146802b Var: refactor: removed dead code.
 9:  3d96d043 =  9:  3d96d043 Refactor: storing the body_handler as part of r.
10:  c8d6b131 = 10:  c8d6b131 HTTP: refactor: transformed loop into recursive call.
11:  419ab3a9 = 11:  419ab3a9 HTTP: refactor: requesting the fallback action from the action itself.
12:  f2e16c33 = 12:  f2e16c33 HTTP: refactor: requesting the actions from the route handler.
13:  872a5315 = 13:  872a5315 HTTP: refactor: failing in the route handler.
14:  96f26a32 = 14:  96f26a32 HTTP: pass: refactor: using a ctx.
15:  39d9d8c6 = 15:  39d9d8c6 HTTP: return: refactor: using 'add_header' member in ctx.
16:  1c9a0910 = 16:  1c9a0910 Proxy: refactor: using goto fail.
17:  4bbbe719 = 17:  4bbbe719 Static: refactor: transformed goto into do-while loop.
18:  d6bbbd9a = 18:  d6bbbd9a HTTP: supporting a list of filter_handlers
19:  12742806 <  -:  -------- HTTP: storing 'action' within 'r'.
20:  cb553985 = 19:  2eaa09c2 Auto: compiling with zlib.
21:  ab539acb = 20:  0a43b800 HTTP: added "compress" action.

@alejandro-colomar
Copy link
Contributor Author

v12 changes:

$ git range-diff master..gh/actions master..actions
 1:  28777b66 =  1:  28777b66 HTTP: refactor: inverted conditional to reduce nesting.
 2:  e448d40f =  2:  e448d40f Router: refactor: factored out application creation loop.
 3:  10b128f3 =  3:  10b128f3 Router: refactor: factored out listeners creation loop.
 4:  9315fc4f =  4:  9315fc4f Refactor: inverted conditional to reduce nesting.
 5:  23504762 =  5:  23504762 Refactor: using a temporary variable in a macro.
 6:  6ae38deb =  6:  6ae38deb Var: refactor: removed dead code.
 7:  7ddcfe4f =  7:  7ddcfe4f Var: refactor: removed dead code.
 8:  4146802b =  8:  4146802b Var: refactor: removed dead code.
 9:  3d96d043 =  9:  3d96d043 Refactor: storing the body_handler as part of r.
10:  c8d6b131 = 10:  c8d6b131 HTTP: refactor: transformed loop into recursive call.
11:  419ab3a9 = 11:  419ab3a9 HTTP: refactor: requesting the fallback action from the action itself.
12:  f2e16c33 = 12:  f2e16c33 HTTP: refactor: requesting the actions from the route handler.
13:  872a5315 = 13:  872a5315 HTTP: refactor: failing in the route handler.
14:  96f26a32 = 14:  96f26a32 HTTP: pass: refactor: using a ctx.
15:  39d9d8c6 = 15:  39d9d8c6 HTTP: return: refactor: using 'add_header' member in ctx.
16:  1c9a0910 = 16:  1c9a0910 Proxy: refactor: using goto fail.
17:  4bbbe719 = 17:  4bbbe719 Static: refactor: transformed goto into do-while loop.
18:  d6bbbd9a = 18:  d6bbbd9a HTTP: supporting a list of filter_handlers
19:  12742806 <  -:  -------- HTTP: storing 'action' within 'r'.
20:  cb553985 = 19:  2eaa09c2 Auto: compiling with zlib.
21:  ab539acb ! 20:  da877cbe HTTP: added "compress" action.
    @@ src/nxt_http_compress.c (new)
     +    }
     +
     +    out->mem.free = out->mem.end - z->avail_out;
    ++    size = out->mem.free - out->mem.start;
     +
    -+    *b = out;
    ++    if (in->mem.end - in->mem.pos >= size) {
    ++        in->mem.free = nxt_cpymem(in->mem.pos, out->mem.start, size);
    ++
    ++        nxt_mp_free(r->mem_pool, out);
    ++    } else {
    ++        *b = out;
    ++
    ++        nxt_mp_free(in->data, in);
    ++    }
     +
     +    if (is_last) {
     +        ret = deflateEnd(z);

New round of testing:

$ curl localhost:8080/8080
rdm
$ curl localhost:8081/8081
$ curl localhost:81/81
$ curl localhost:82/82
Warning: Binary output can mess up your terminal. Use "--output -" to tell 
Warning: curl to output it to your terminal anyway, or consider "--output 
Warning: <FILE>" to save to a file.
$ curl --compressed localhost:82/82
idx
$ curl localhost:83/83
Warning: Binary output can mess up your terminal. Use "--output -" to tell 
Warning: curl to output it to your terminal anyway, or consider "--output 
Warning: <FILE>" to save to a file.
$ curl --compressed localhost:83/83
Hello, Perl on Unit!
$ curl localhost:84/84
Warning: Binary output can mess up your terminal. Use "--output -" to tell 
Warning: curl to output it to your terminal anyway, or consider "--output 
Warning: <FILE>" to save to a file.
$ curl --compressed localhost:84/84
rdm

Which results in a clean log:

$ sudo cat /opt/local/unit/gzip/var/log/unit/unit.log 
2023/08/22 13:38:17 [info] 17094#17094 discovery started
2023/08/22 13:38:17 [notice] 17094#17094 module: perl 5.36.0 "/opt/local/unit/gzip//lib/unit/modules/perl.unit.so"
2023/08/22 13:38:17 [info] 17093#17093 controller started
2023/08/22 13:38:17 [notice] 17093#17093 process 17094 exited with code 0
2023/08/22 13:38:17 [info] 17096#17096 router started
2023/08/22 13:38:17 [info] 17097#17097 "perl" prototype started
2023/08/22 13:38:17 [info] 17098#17098 "perl" application started
2023/08/22 13:38:24 [notice] 17096#17099 *31 http request line "GET /8080 HTTP/1.1"
2023/08/22 13:38:24 [notice] 17096#17099 *31 "routes/di/0" selected
2023/08/22 13:38:36 [notice] 17096#17099 *27 http request line "GET /8081 HTTP/1.1"
2023/08/22 13:38:36 [notice] 17096#17099 *27 "routes/n/0" selected
2023/08/22 13:38:49 [notice] 17096#17099 *23 http request line "GET /81 HTTP/1.1"
2023/08/22 13:38:49 [notice] 17096#17099 *23 "routes/o/0" selected
2023/08/22 13:38:49 [notice] 17096#17099 *63 http request line "GET /81 HTTP/1.1"
2023/08/22 13:38:49 [notice] 17096#17099 *63 "routes/n/0" selected
2023/08/22 13:38:53 [notice] 17096#17099 *19 http request line "GET /82 HTTP/1.1"
2023/08/22 13:38:53 [notice] 17096#17099 *19 "routes/s/0" selected
2023/08/22 13:39:01 [notice] 17096#17099 *66 http request line "GET /82 HTTP/1.1"
2023/08/22 13:39:01 [notice] 17096#17099 *66 "routes/s/0" selected
2023/08/22 13:39:06 [notice] 17096#17099 *15 http request line "GET /83 HTTP/1.1"
2023/08/22 13:39:06 [notice] 17096#17099 *15 "routes/a/0" selected
2023/08/22 13:39:10 [notice] 17096#17099 *68 http request line "GET /83 HTTP/1.1"
2023/08/22 13:39:10 [notice] 17096#17099 *68 "routes/a/0" selected
2023/08/22 13:39:16 [notice] 17096#17099 *11 http request line "GET /84 HTTP/1.1"
2023/08/22 13:39:16 [notice] 17096#17099 *11 "routes/u/0" selected
2023/08/22 13:39:16 [notice] 17096#17099 *62 http request line "GET /84 HTTP/1.1"
2023/08/22 13:39:16 [notice] 17096#17099 *62 "routes/di/0" selected
2023/08/22 13:39:20 [notice] 17096#17099 *70 http request line "GET /84 HTTP/1.1"
2023/08/22 13:39:20 [notice] 17096#17099 *70 "routes/u/0" selected
2023/08/22 13:39:20 [notice] 17096#17099 *71 http request line "GET /84 HTTP/1.1"
2023/08/22 13:39:20 [notice] 17096#17099 *71 "routes/di/0" selected

@alejandro-colomar
Copy link
Contributor Author

v13 changes:

  • Set correct memory pool in buffer.
$ git range-diff master..gh/actions master..actions
 1:  28777b66 =  1:  28777b66 HTTP: refactor: inverted conditional to reduce nesting.
 2:  e448d40f =  2:  e448d40f Router: refactor: factored out application creation loop.
 3:  10b128f3 =  3:  10b128f3 Router: refactor: factored out listeners creation loop.
 4:  9315fc4f =  4:  9315fc4f Refactor: inverted conditional to reduce nesting.
 5:  23504762 =  5:  23504762 Refactor: using a temporary variable in a macro.
 6:  6ae38deb =  6:  6ae38deb Var: refactor: removed dead code.
 7:  7ddcfe4f =  7:  7ddcfe4f Var: refactor: removed dead code.
 8:  4146802b =  8:  4146802b Var: refactor: removed dead code.
 9:  3d96d043 =  9:  3d96d043 Refactor: storing the body_handler as part of r.
10:  c8d6b131 = 10:  c8d6b131 HTTP: refactor: transformed loop into recursive call.
11:  419ab3a9 = 11:  419ab3a9 HTTP: refactor: requesting the fallback action from the action itself.
12:  f2e16c33 = 12:  f2e16c33 HTTP: refactor: requesting the actions from the route handler.
13:  872a5315 = 13:  872a5315 HTTP: refactor: failing in the route handler.
14:  96f26a32 = 14:  96f26a32 HTTP: pass: refactor: using a ctx.
15:  39d9d8c6 = 15:  39d9d8c6 HTTP: return: refactor: using 'add_header' member in ctx.
16:  1c9a0910 = 16:  1c9a0910 Proxy: refactor: using goto fail.
17:  4bbbe719 = 17:  4bbbe719 Static: refactor: transformed goto into do-while loop.
18:  d6bbbd9a = 18:  d6bbbd9a HTTP: supporting a list of filter_handlers
19:  2eaa09c2 = 19:  2eaa09c2 Auto: compiling with zlib.
20:  da877cbe ! 20:  96a44536 HTTP: added "compress" action.
    @@ src/nxt_http_compress.c (new)
     +    }
     +
     +    nxt_memcpy(out, in, offsetof(nxt_buf_t, mem));
    ++    out->data = r->mem_pool;
     +
     +    z->next_out = out->mem.start;
     +    z->avail_out = out->mem.end - out->mem.start;
    @@ src/nxt_http_compress.c (new)
     +    out->mem.free = out->mem.end - z->avail_out;
     +    size = out->mem.free - out->mem.start;
     +
    -+    if (in->mem.end - in->mem.pos >= size) {
    -+        in->mem.free = nxt_cpymem(in->mem.pos, out->mem.start, size);
    ++    if ((*b)->mem.end - (*b)->mem.pos >= size) {
    ++        (*b)->mem.free = nxt_cpymem((*b)->mem.pos, out->mem.start, size);
     +
    -+        nxt_mp_free(r->mem_pool, out);
    ++        in = out;
     +    } else {
     +        *b = out;
    -+
    -+        nxt_mp_free(in->data, in);
     +    }
     +
    ++    nxt_mp_free(in->data, in);
    ++
     +    if (is_last) {
     +        ret = deflateEnd(z);
     +        if (ret != Z_OK) {

All tests pass as in v12

@alejandro-colomar
Copy link
Contributor Author

alejandro-colomar commented Aug 22, 2023

v14 changes:

  • Add --no-zlib to compile without zlib support.
$ git range-diff master..gh/actions master..actions
 1:  28777b66 =  1:  28777b66 HTTP: refactor: inverted conditional to reduce nesting.
 2:  e448d40f =  2:  e448d40f Router: refactor: factored out application creation loop.
 3:  10b128f3 =  3:  10b128f3 Router: refactor: factored out listeners creation loop.
 4:  9315fc4f =  4:  9315fc4f Refactor: inverted conditional to reduce nesting.
 5:  23504762 =  5:  23504762 Refactor: using a temporary variable in a macro.
 6:  6ae38deb =  6:  6ae38deb Var: refactor: removed dead code.
 7:  7ddcfe4f =  7:  7ddcfe4f Var: refactor: removed dead code.
 8:  4146802b =  8:  4146802b Var: refactor: removed dead code.
 9:  3d96d043 =  9:  3d96d043 Refactor: storing the body_handler as part of r.
10:  c8d6b131 = 10:  c8d6b131 HTTP: refactor: transformed loop into recursive call.
11:  419ab3a9 = 11:  419ab3a9 HTTP: refactor: requesting the fallback action from the action itself.
12:  f2e16c33 = 12:  f2e16c33 HTTP: refactor: requesting the actions from the route handler.
13:  872a5315 = 13:  872a5315 HTTP: refactor: failing in the route handler.
14:  96f26a32 = 14:  96f26a32 HTTP: pass: refactor: using a ctx.
15:  39d9d8c6 = 15:  39d9d8c6 HTTP: return: refactor: using 'add_header' member in ctx.
16:  1c9a0910 = 16:  1c9a0910 Proxy: refactor: using goto fail.
17:  4bbbe719 = 17:  4bbbe719 Static: refactor: transformed goto into do-while loop.
18:  d6bbbd9a = 18:  d6bbbd9a HTTP: supporting a list of filter_handlers
19:  2eaa09c2 <  -:  -------- Auto: compiling with zlib.
 -:  -------- > 19:  96fc4aa4 Auto: compiling with zlib.
20:  96a44536 ! 20:  47db8fcd HTTP: added "compress" action.
    @@ src/nxt_http_compress.c (new)
     + * Copyright (C) NGINX, Inc.
     + */
     +
    ++
     +#include <nxt_router.h>
     +#include <nxt_http.h>
     +
    ++#if __has_include(<zlib.h>)
     +#include <zlib.h>
    ++#endif
    ++
    ++
    ++#if defined(NXT_HAVE_ZLIB)
    ++#define NXT_WITH_ZLIB  1
    ++#else
    ++#define NXT_WITH_ZLIB  0
    ++#endif
    ++
    ++
    ++#define NXT_DEFAULT_COMPRESSION  (-1)
     +
     +
     +typedef struct nxt_http_compress_gzip_ctx_s  nxt_http_compress_gzip_ctx_t;
    @@ src/nxt_http_compress.c (new)
     +
     +    int8_t              level;
     +
    ++#if (NXT_WITH_ZLIB)
     +    z_stream            z;
    ++#endif
     +};
     +
     +
    @@ src/nxt_http_compress.c (new)
     +        return NXT_ERROR;
     +    }
     +
    -+    conf->level = Z_DEFAULT_COMPRESSION;
    ++    conf->level = NXT_DEFAULT_COMPRESSION;
     +
     +    ret = nxt_conf_map_object(mp, acf->compress, nxt_http_compress_conf,
     +                              nxt_nitems(nxt_http_compress_conf), conf);
    @@ src/nxt_http_compress.c (new)
     +    }
     +
     +    if (nxt_str_eq(&conf->encoding, "gzip", nxt_length("gzip"))) {
    ++        if (!NXT_WITH_ZLIB) {
    ++            return NXT_ERROR;
    ++        }
    ++
     +        conf->handler = nxt_http_compress_gzip;
     +
     +    } else {
    @@ src/nxt_http_compress.c (new)
     +nxt_http_compress_gzip_ctx(nxt_task_t *task, nxt_http_request_t *r,
     +    nxt_http_compress_conf_t *conf)
     +{
    ++#if (!NXT_WITH_ZLIB)
    ++    return NULL;
    ++#else
     +    int                           ret;
     +    z_stream                      *z;
     +    nxt_http_compress_gzip_ctx_t  *ctx;
    @@ src/nxt_http_compress.c (new)
     +    }
     +
     +    return ctx;
    ++#endif
     +}
     +
     +
    @@ src/nxt_http_compress.c (new)
     +static void
     +nxt_http_compress_gzip_filter(nxt_task_t *task, void *obj, void *data)
     +{
    ++#if (NXT_WITH_ZLIB)
     +    int                           ret;
     +    ssize_t                       size;
     +    z_stream                      *z;
    @@ src/nxt_http_compress.c (new)
     +
     +    // TODO(alx): What to do here?
     +    return;
    ++#endif
     +}
     
      ## src/nxt_http_request.c ##

@alejandro-colomar
Copy link
Contributor Author

v14b changes:

  • rebase to master
$ git range-diff 28777b66^..gh/actions master..actions
 1:  28777b66 =  1:  0884d72b HTTP: refactor: inverted conditional to reduce nesting.
 2:  e448d40f =  2:  0f2b5347 Router: refactor: factored out application creation loop.
 3:  10b128f3 =  3:  7131891c Router: refactor: factored out listeners creation loop.
 4:  9315fc4f =  4:  82292ffb Refactor: inverted conditional to reduce nesting.
 5:  23504762 =  5:  6d28d62c Refactor: using a temporary variable in a macro.
 6:  6ae38deb =  6:  eeec6d6b Var: refactor: removed dead code.
 7:  7ddcfe4f =  7:  436ffec5 Var: refactor: removed dead code.
 8:  4146802b =  8:  e8bd5854 Var: refactor: removed dead code.
 9:  3d96d043 =  9:  7745594e Refactor: storing the body_handler as part of r.
10:  c8d6b131 = 10:  57725356 HTTP: refactor: transformed loop into recursive call.
11:  419ab3a9 = 11:  83e19a9f HTTP: refactor: requesting the fallback action from the action itself.
12:  f2e16c33 = 12:  98e8c241 HTTP: refactor: requesting the actions from the route handler.
13:  872a5315 = 13:  2418eb28 HTTP: refactor: failing in the route handler.
14:  96f26a32 = 14:  5a4ef200 HTTP: pass: refactor: using a ctx.
15:  39d9d8c6 = 15:  d817b478 HTTP: return: refactor: using 'add_header' member in ctx.
16:  1c9a0910 = 16:  7cef35e6 Proxy: refactor: using goto fail.
17:  4bbbe719 = 17:  1a22f4b9 Static: refactor: transformed goto into do-while loop.
18:  d6bbbd9a = 18:  c9e8bc7a HTTP: supporting a list of filter_handlers
19:  96fc4aa4 = 19:  cf17314f Auto: compiling with zlib.
20:  47db8fcd = 20:  dddf4d8f HTTP: added "compress" action.

@alejandro-colomar
Copy link
Contributor Author

v15 changes:

  • Split addition of --no-zlib configuration option to separate commit.
  • Minor fixes
$ git range-diff master..gh/actions master..actions
 1:  28777b66 =  1:  0884d72b HTTP: refactor: inverted conditional to reduce nesting.
 2:  e448d40f =  2:  0f2b5347 Router: refactor: factored out application creation loop.
 3:  10b128f3 =  3:  7131891c Router: refactor: factored out listeners creation loop.
 4:  9315fc4f =  4:  82292ffb Refactor: inverted conditional to reduce nesting.
 5:  23504762 =  5:  6d28d62c Refactor: using a temporary variable in a macro.
 6:  6ae38deb =  6:  eeec6d6b Var: refactor: removed dead code.
 7:  7ddcfe4f =  7:  436ffec5 Var: refactor: removed dead code.
 8:  4146802b =  8:  e8bd5854 Var: refactor: removed dead code.
 9:  3d96d043 =  9:  7745594e Refactor: storing the body_handler as part of r.
10:  c8d6b131 = 10:  57725356 HTTP: refactor: transformed loop into recursive call.
11:  419ab3a9 = 11:  83e19a9f HTTP: refactor: requesting the fallback action from the action itself.
12:  f2e16c33 = 12:  98e8c241 HTTP: refactor: requesting the actions from the route handler.
13:  872a5315 = 13:  2418eb28 HTTP: refactor: failing in the route handler.
14:  96f26a32 = 14:  5a4ef200 HTTP: pass: refactor: using a ctx.
15:  39d9d8c6 = 15:  d817b478 HTTP: return: refactor: using 'add_header' member in ctx.
16:  1c9a0910 = 16:  7cef35e6 Proxy: refactor: using goto fail.
17:  4bbbe719 = 17:  1a22f4b9 Static: refactor: transformed goto into do-while loop.
18:  d6bbbd9a = 18:  c9e8bc7a HTTP: supporting a list of filter_handlers
19:  96fc4aa4 <  -:  -------- Auto: compiling with zlib.
 -:  -------- > 19:  60509d22 Auto: compiling with zlib.
20:  47db8fcd ! 20:  6ba7aa20 HTTP: added "compress" action.
    [...]
 -:  -------- > 21:  bc457bfd Auto: added --no-zlib.

@alejandro-colomar
Copy link
Contributor Author

v16 changes:

  • Simplify some code.
$ git range-diff master..gh/actions master..actions
 1:  0884d72b =  1:  0884d72b HTTP: refactor: inverted conditional to reduce nesting.
 2:  0f2b5347 =  2:  0f2b5347 Router: refactor: factored out application creation loop.
 3:  7131891c =  3:  7131891c Router: refactor: factored out listeners creation loop.
 4:  82292ffb =  4:  82292ffb Refactor: inverted conditional to reduce nesting.
 5:  6d28d62c =  5:  6d28d62c Refactor: using a temporary variable in a macro.
 6:  eeec6d6b =  6:  eeec6d6b Var: refactor: removed dead code.
 7:  436ffec5 =  7:  436ffec5 Var: refactor: removed dead code.
 8:  e8bd5854 =  8:  e8bd5854 Var: refactor: removed dead code.
 9:  7745594e =  9:  7745594e Refactor: storing the body_handler as part of r.
10:  57725356 = 10:  57725356 HTTP: refactor: transformed loop into recursive call.
11:  83e19a9f = 11:  83e19a9f HTTP: refactor: requesting the fallback action from the action itself.
12:  98e8c241 = 12:  98e8c241 HTTP: refactor: requesting the actions from the route handler.
13:  2418eb28 = 13:  2418eb28 HTTP: refactor: failing in the route handler.
14:  5a4ef200 = 14:  5a4ef200 HTTP: pass: refactor: using a ctx.
15:  d817b478 = 15:  d817b478 HTTP: return: refactor: using 'add_header' member in ctx.
16:  7cef35e6 = 16:  7cef35e6 Proxy: refactor: using goto fail.
17:  1a22f4b9 = 17:  1a22f4b9 Static: refactor: transformed goto into do-while loop.
18:  c9e8bc7a = 18:  c9e8bc7a HTTP: supporting a list of filter_handlers
19:  60509d22 = 19:  60509d22 Auto: compiling with zlib.
20:  6ba7aa20 ! 20:  29fdcf23 HTTP: added "compress" action.
    @@ src/nxt_http_compress.c (new)
     +        return NXT_ERROR;
     +    }
     +
    -+    if (nxt_str_eq(&conf->encoding, "gzip", nxt_length("gzip"))) {
    ++    if (nxt_str_eq(&conf->encoding, "gzip", strlen("gzip"))) {
     +        conf->handler = nxt_http_compress_gzip;
     +
     +    } else {
21:  bc457bfd ! 21:  a7f224a2 Auto: added --no-zlib.
    @@ src/nxt_http_compress.c: nxt_http_compress_init(nxt_router_conf_t *rtcf, nxt_htt
          ret = nxt_conf_map_object(mp, acf->compress, nxt_http_compress_conf,
                                    nxt_nitems(nxt_http_compress_conf), conf);
     @@ src/nxt_http_compress.c: nxt_http_compress_init(nxt_router_conf_t *rtcf, nxt_http_action_t *action,
    +         return NXT_ERROR;
          }
      
    -     if (nxt_str_eq(&conf->encoding, "gzip", nxt_length("gzip"))) {
    -+        if (!NXT_WITH_ZLIB) {
    -+            return NXT_ERROR;
    -+        }
    -+
    +-    if (nxt_str_eq(&conf->encoding, "gzip", strlen("gzip"))) {
    ++    if (NXT_WITH_ZLIB && nxt_str_eq(&conf->encoding, "gzip", strlen("gzip"))) {
              conf->handler = nxt_http_compress_gzip;
      
          } else {

@alejandro-colomar
Copy link
Contributor Author

v17 changes:

  • Improve error handling.
  • Add safe macros to libunit. (Needed for nxt_swap().)
$ git range-diff master gh/actions actions
 -:  -------- >  1:  4f1bac72 Libunit: added macros that enhance type safety.
 1:  0884d72b =  2:  fbc02b60 HTTP: refactor: inverted conditional to reduce nesting.
 2:  0f2b5347 =  3:  eb1e4825 Router: refactor: factored out application creation loop.
 3:  7131891c =  4:  80efaac9 Router: refactor: factored out listeners creation loop.
 4:  82292ffb =  5:  3e3c2920 Refactor: inverted conditional to reduce nesting.
 5:  6d28d62c =  6:  0f46a270 Refactor: using a temporary variable in a macro.
 6:  eeec6d6b =  7:  7205b664 Var: refactor: removed dead code.
 7:  436ffec5 =  8:  8e7a06ab Var: refactor: removed dead code.
 8:  e8bd5854 =  9:  c9e21957 Var: refactor: removed dead code.
 9:  7745594e = 10:  392ffc42 Refactor: storing the body_handler as part of r.
10:  57725356 = 11:  81a408ce HTTP: refactor: transformed loop into recursive call.
11:  83e19a9f = 12:  36caadcf HTTP: refactor: requesting the fallback action from the action itself.
12:  98e8c241 = 13:  268449c2 HTTP: refactor: requesting the actions from the route handler.
13:  2418eb28 = 14:  aca3bb0f HTTP: refactor: failing in the route handler.
14:  5a4ef200 = 15:  d41a0780 HTTP: pass: refactor: using a ctx.
15:  d817b478 = 16:  4caf41ca HTTP: return: refactor: using 'add_header' member in ctx.
16:  7cef35e6 = 17:  d2de42ea Proxy: refactor: using goto fail.
17:  1a22f4b9 = 18:  16a67076 Static: refactor: transformed goto into do-while loop.
18:  c9e8bc7a = 19:  d21860e6 HTTP: supporting a list of filter_handlers
19:  60509d22 = 20:  81c7ade8 Auto: compiling with zlib.
20:  29fdcf23 ! 21:  c5cbcc32 HTTP: added "compress" action.
    @@ src/nxt_http_compress.c (new)
     +
     +#include <zlib.h>
     +
    ++#include <nxt_unit_cdefs.h>
    ++
     +
     +typedef struct nxt_http_compress_gzip_ctx_s  nxt_http_compress_gzip_ctx_t;
     +
    @@ src/nxt_http_compress.c (new)
     +    int                           ret;
     +    ssize_t                       size;
     +    z_stream                      *z;
    -+    nxt_buf_t                     **b, *in, *out;
    ++    nxt_buf_t                     **b, *tmp;
     +    nxt_bool_t                    is_last;
     +    nxt_http_request_t            *r;
     +    nxt_http_compress_gzip_ctx_t  *ctx;
    @@ src/nxt_http_compress.c (new)
     +    ctx = data;
     +    z = &ctx->z;
     +
    -+    in = *b;
     +    r = ctx->r;
     +
    -+    is_last = (in->next == NULL
    -+               || in->next->completion_handler != in->completion_handler);
    ++    is_last = ((*b)->next == NULL
    ++               || (*b)->next->completion_handler != (*b)->completion_handler);
     +
    -+    z->next_in = in->mem.pos;
    -+    z->avail_in = in->mem.free - in->mem.pos;
    ++    z->next_in = (*b)->mem.pos;
    ++    z->avail_in = (*b)->mem.free - (*b)->mem.pos;
     +
     +    size = deflateBound(z, z->avail_in);
     +
    -+    out = nxt_buf_mem_alloc(r->mem_pool, size, 0);
    -+    if (nxt_slow_path(out == NULL)) {
    ++    tmp = nxt_buf_mem_alloc(r->mem_pool, size, 0);
    ++    if (nxt_slow_path(tmp == NULL)) {
     +        return;
     +    }
     +
    -+    nxt_memcpy(out, in, offsetof(nxt_buf_t, mem));
    -+    out->data = r->mem_pool;
    ++    nxt_memcpy(tmp, *b, offsetof(nxt_buf_t, mem));
    ++    tmp->data = r->mem_pool;
     +
    -+    z->next_out = out->mem.start;
    -+    z->avail_out = out->mem.end - out->mem.start;
    ++    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;
     +    }
     +
    -+    out->mem.free = out->mem.end - z->avail_out;
    -+    size = out->mem.free - out->mem.start;
    ++    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, out->mem.start, size);
    ++        (*b)->mem.free = nxt_cpymem((*b)->mem.pos, tmp->mem.start, size);
     +
    -+        in = out;
     +    } else {
    -+        *b = out;
    ++        nxt_swap(b, &tmp);
     +    }
     +
    -+    nxt_mp_free(in->data, in);
    ++fail:
    ++
    ++    nxt_mp_free(tmp->data, tmp);
     +
     +    if (is_last) {
     +        ret = deflateEnd(z);
     +        if (ret != Z_OK) {
    -+            goto fail;
    ++            return;
     +        }
     +    }
     +
     +    return;
    -+
    -+fail:
    -+
    -+    // TODO(alx): What to do here?
    -+    return;
     +}
     
      ## src/nxt_http_request.c ##
21:  a7f224a2 ! 22:  5dfb8e72 Auto: added --no-zlib.
    [...]

@alejandro-colomar
Copy link
Contributor Author

alejandro-colomar commented Aug 24, 2023

v18 changes:

  • Minor alignment fixes.
  • Split addition of configurable compression level to separate commit.
  • Add nxt_ustrto[u]l(); wrappers around strto[u]l(3) for nxt_str_t.
  • Add configurable threshold for Content-Length to enable compression.
$ git range-diff master gh/actions actions
 1:  4f1bac72 =  1:  4f1bac72 Libunit: added macros that enhance type safety.
 2:  fbc02b60 =  2:  fbc02b60 HTTP: refactor: inverted conditional to reduce nesting.
 3:  eb1e4825 =  3:  eb1e4825 Router: refactor: factored out application creation loop.
 4:  80efaac9 =  4:  80efaac9 Router: refactor: factored out listeners creation loop.
 5:  3e3c2920 =  5:  3e3c2920 Refactor: inverted conditional to reduce nesting.
 6:  0f46a270 =  6:  0f46a270 Refactor: using a temporary variable in a macro.
 7:  7205b664 =  7:  7205b664 Var: refactor: removed dead code.
 8:  8e7a06ab =  8:  8e7a06ab Var: refactor: removed dead code.
 9:  c9e21957 =  9:  c9e21957 Var: refactor: removed dead code.
10:  392ffc42 = 10:  392ffc42 Refactor: storing the body_handler as part of r.
11:  81a408ce = 11:  81a408ce HTTP: refactor: transformed loop into recursive call.
12:  36caadcf = 12:  36caadcf HTTP: refactor: requesting the fallback action from the action itself.
13:  268449c2 = 13:  268449c2 HTTP: refactor: requesting the actions from the route handler.
14:  aca3bb0f = 14:  aca3bb0f HTTP: refactor: failing in the route handler.
15:  d41a0780 = 15:  d41a0780 HTTP: pass: refactor: using a ctx.
16:  4caf41ca = 16:  4caf41ca HTTP: return: refactor: using 'add_header' member in ctx.
17:  d2de42ea = 17:  d2de42ea Proxy: refactor: using goto fail.
18:  16a67076 = 18:  16a67076 Static: refactor: transformed goto into do-while loop.
19:  d21860e6 = 19:  d21860e6 HTTP: supporting a list of filter_handlers
20:  81c7ade8 = 20:  81c7ade8 Auto: compiling with zlib.
21:  c5cbcc32 ! 21:  3a2afd72 HTTP: added "compress" action.
    [...]
 -:  -------- > 22:  fe811581 HTTP: compress: added configurable "level" of compression.
22:  5dfb8e72 = 23:  38301c59 Auto: added --no-zlib.
 -:  -------- > 24:  700ce57d String: added strto[u]l(3) variants for nxt_str_t.
 -:  -------- > 25:  24c0579e HTTP: compress: added configurable threshold for Content-Length.

Tested with different compression levels (-1, 0, 3, 6, 7, 9).
Tested with different thresholds (0, 2, 3, 4, 9, 99).

Example of compression config:

					"compress": {
						"encoding": "gzip",
						"level": 0,
						"content_length_threshold": 3
					}

@alejandro-colomar
Copy link
Contributor Author

alejandro-colomar commented Aug 29, 2023

v19 changes:

  • Add extra (--debug) route logging. This was rescued from the old patch set for adding route logging. It still works without changing. We'll need to check the format, to see if we still like it. I needed it to debug the MIME types matching.
  • Add "mime_types" array to select which MIME types should be compressed. (If the MIME type is not known, the tests are not performed.)

Tested with:

				"compress": {
					"encoding": "gzip"
					,"mime_types": [
						"!text/javascript",
						"!text/css",
						"!text/*",
						"~video/3gpp2?"
					]
				}

and

				"compress": {
					"encoding": "gzip"
					,"mime_types": [
						"!text/javascript",
						"!text/css",
						"text/*",
						"~video/3gpp2?"
					]
				}

Changes:

$ git range-diff master gh/actions actions 
 1:  4f1bac72 =  1:  4f1bac72 Libunit: added macros that enhance type safety.
 2:  fbc02b60 =  2:  fbc02b60 HTTP: refactor: inverted conditional to reduce nesting.
 3:  eb1e4825 =  3:  eb1e4825 Router: refactor: factored out application creation loop.
 4:  80efaac9 =  4:  80efaac9 Router: refactor: factored out listeners creation loop.
 5:  3e3c2920 =  5:  3e3c2920 Refactor: inverted conditional to reduce nesting.
 6:  0f46a270 =  6:  0f46a270 Refactor: using a temporary variable in a macro.
 7:  7205b664 =  7:  7205b664 Var: refactor: removed dead code.
 8:  8e7a06ab =  8:  8e7a06ab Var: refactor: removed dead code.
 9:  c9e21957 =  9:  c9e21957 Var: refactor: removed dead code.
10:  392ffc42 = 10:  392ffc42 Refactor: storing the body_handler as part of r.
11:  81a408ce = 11:  81a408ce HTTP: refactor: transformed loop into recursive call.
12:  36caadcf = 12:  36caadcf HTTP: refactor: requesting the fallback action from the action itself.
13:  268449c2 = 13:  268449c2 HTTP: refactor: requesting the actions from the route handler.
14:  aca3bb0f = 14:  aca3bb0f HTTP: refactor: failing in the route handler.
15:  d41a0780 = 15:  d41a0780 HTTP: pass: refactor: using a ctx.
16:  4caf41ca = 16:  4caf41ca HTTP: return: refactor: using 'add_header' member in ctx.
17:  d2de42ea = 17:  d2de42ea Proxy: refactor: using goto fail.
18:  16a67076 = 18:  16a67076 Static: refactor: transformed goto into do-while loop.
19:  d21860e6 = 19:  d21860e6 HTTP: supporting a list of filter_handlers
20:  81c7ade8 = 20:  81c7ade8 Auto: compiling with zlib.
21:  3a2afd72 = 21:  3a2afd72 HTTP: added "compress" action.
22:  fe811581 = 22:  fe811581 HTTP: compress: added configurable "level" of compression.
23:  38301c59 = 23:  38301c59 Auto: added --no-zlib.
24:  700ce57d = 24:  700ce57d String: added strto[u]l(3) variants for nxt_str_t.
25:  24c0579e = 25:  24c0579e HTTP: compress: added configurable threshold for Content-Length.
 -:  -------- > 26:  ea3c1128 Router: moved structure definition to header.
 -:  -------- > 27:  62f1cf40 PCRE: moved structure definition to header.
 -:  -------- > 28:  547398d0 HTTP: refactored code.
 -:  -------- > 29:  b5608ea7 HTTP: logging when control is "pass"ed.
 -:  -------- > 30:  8bcad90f HTTP: logging the kind of element tried for a match.
 -:  -------- > 31:  e3c8b70b HTTP: logging pattern-matching decissions.
 -:  -------- > 32:  e264d36e HTTP: moved typedefs to top of file.
 -:  -------- > 33:  84a8364d HTTP: compress: added mime_types.

@alejandro-colomar
Copy link
Contributor Author

Here goes some trivial sanity check that nothing blows up times (far from being a performance test, though):

$ time curl localhost:8080
rdm

real	0m0.007s
user	0m0.000s
sys	0m0.007s
$ time curl localhost:8081

real	0m0.006s
user	0m0.000s
sys	0m0.006s
$ time curl localhost:81

real	0m0.007s
user	0m0.003s
sys	0m0.003s
$ time curl localhost:82
idx

real	0m0.007s
user	0m0.000s
sys	0m0.006s
$ time curl localhost:83
Warning: Binary output can mess up your terminal. Use "--output -" to tell 
Warning: curl to output it to your terminal anyway, or consider "--output 
Warning: <FILE>" to save to a file.

real	0m0.007s
user	0m0.003s
sys	0m0.003s
$ time curl localhost:84
Warning: Binary output can mess up your terminal. Use "--output -" to tell 
Warning: curl to output it to your terminal anyway, or consider "--output 
Warning: <FILE>" to save to a file.

real	0m0.007s
user	0m0.006s
sys	0m0.000s
$ time curl localhost:85

real	0m0.007s
user	0m0.007s
sys	0m0.000s

@alejandro-colomar
Copy link
Contributor Author

alejandro-colomar commented Aug 29, 2023

Performance test:

$ sudo unit ctl http GET /config </dev/null
{
  "settings": {
    "http": {
      "log_route": false
    }
  },
  "listeners": {
    "*:8080": {
      "pass": "routes/d"
    },
    "*:8081": {
      "pass": "routes/n"
    },
    "*:8082": {
      "pass": "routes/i"
    },
    "*:81": {
      "pass": "routes/o"
    },
    "*:82": {
      "pass": "routes/s"
    },
    "*:83": {
      "pass": "routes/a"
    },
    "*:84": {
      "pass": "routes/u"
    },
    "*:85": {
      "pass": "routes/r"
    }
  },
  "routes": {
    "d": [
      {
        "action": {
          "share": "/srv/www/readme"
        }
      }
    ],
    "n": [
      {
        "action": {
          "share": "/srv/www/empty"
        }
      }
    ],
    "i": [
      {
        "action": {
          "pass": "applications/perl"
        }
      }
    ],
    "o": [
      {
        "action": {
          "proxy": "http://127.0.0.1:8081",
          "compress": {
            "encoding": "gzip"
          }
        }
      }
    ],
    "s": [
      {
        "action": {
          "share": "/srv/www/unit/index.html",
          "compress": {
            "encoding": "gzip"
          }
        }
      }
    ],
    "a": [
      {
        "action": {
          "pass": "applications/perl",
          "compress": {
            "encoding": "gzip"
          }
        }
      }
    ],
    "u": [
      {
        "action": {
          "proxy": "http://127.0.0.1:8080",
          "compress": {
            "encoding": "gzip"
          }
        }
      }
    ],
    "r": [
      {
        "action": {
          "return": 321,
          "compress": {
            "encoding": "gzip"
          }
        }
      }
    ]
  },
  "applications": {
    "perl": {
      "type": "perl",
      "working_directory": "/home/alx/srv/www/perl/",
      "script": "./sock.psgi"
    }
  }
}
alx@asus5775:~/etc/unitd$ wrk -t2 -c100 -d5s http://localhost:8080
Running 5s test @ http://localhost:8080
  2 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   406.23us  264.82us   5.12ms   74.57%
    Req/Sec    87.62k    15.33k  128.37k    64.00%
  871886 requests in 5.00s, 138.03MB read
Requests/sec: 174359.62
Transfer/sec:     27.60MB
alx@asus5775:~/etc/unitd$ wrk -t2 -c1000 -d10s http://localhost:8080
Running 10s test @ http://localhost:8080
  2 threads and 1000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    10.39ms   49.59ms 791.17ms   97.76%
    Req/Sec   108.33k    16.07k  136.13k    70.35%
  2156437 requests in 10.10s, 395.04MB read
  Socket errors: connect 0, read 392, write 0, timeout 0
  Non-2xx or 3xx responses: 1939968
Requests/sec: 213596.65
Transfer/sec:     39.13MB
alx@asus5775:~/etc/unitd$ wrk -t2 -c10000 -d20s http://localhost:8080
Running 20s test @ http://localhost:8080
  2 threads and 10000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     5.84ms   40.49ms   1.30s    99.58%
    Req/Sec   106.24k    27.19k  142.85k    47.99%
  4219373 requests in 20.06s, 772.94MB read
  Socket errors: connect 8981, read 799, write 0, timeout 0
  Non-2xx or 3xx responses: 3795696
Requests/sec: 210312.61
Transfer/sec:     38.53MB
alx@asus5775:~/etc/unitd$ wrk -t2 -c100 -d5s http://localhost:8081
Running 5s test @ http://localhost:8081
  2 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   413.17us  348.52us   8.76ms   94.84%
    Req/Sec    84.23k    21.41k  146.61k    78.00%
  837638 requests in 5.00s, 129.41MB read
Requests/sec: 167474.18
Transfer/sec:     25.87MB
alx@asus5775:~/etc/unitd$ wrk -t2 -c1000 -d10s http://localhost:8081
Running 10s test @ http://localhost:8081
  2 threads and 1000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     9.56ms   46.44ms 609.56ms   98.11%
    Req/Sec   107.27k    21.72k  141.48k    55.50%
  2142163 requests in 10.09s, 345.32MB read
  Socket errors: connect 0, read 403, write 0, timeout 0
  Non-2xx or 3xx responses: 456438
Requests/sec: 212344.06
Transfer/sec:     34.23MB
alx@asus5775:~/etc/unitd$ wrk -t2 -c10000 -d20s http://localhost:8081
Running 20s test @ http://localhost:8081
  2 threads and 10000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     5.66ms   39.26ms   1.10s    99.61%
    Req/Sec   103.62k    32.66k  143.12k    32.16%
  4118041 requests in 20.06s, 657.44MB read
  Socket errors: connect 8981, read 800, write 0, timeout 0
  Non-2xx or 3xx responses: 674340
Requests/sec: 205314.20
Transfer/sec:     32.78MB
alx@asus5775:~/etc/unitd$ wrk -t2 -c100 -d5s http://localhost:8082
Running 5s test @ http://localhost:8082
  2 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   700.32us  285.79us   4.63ms   73.81%
    Req/Sec    63.03k     6.17k   71.40k    70.00%
  627179 requests in 5.00s, 97.49MB read
Requests/sec: 125417.41
Transfer/sec:     19.50MB
alx@asus5775:~/etc/unitd$ wrk -t2 -c1000 -d10s http://localhost:8082
Running 10s test @ http://localhost:8082
  2 threads and 1000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    13.44ms   47.79ms 703.84ms   98.31%
    Req/Sec    57.92k     7.30k   74.08k    65.00%
  1157093 requests in 10.09s, 179.87MB read
  Socket errors: connect 0, read 399, write 0, timeout 0
Requests/sec: 114639.78
Transfer/sec:     17.82MB
alx@asus5775:~/etc/unitd$ wrk -t2 -c10000 -d20s http://localhost:8082
Running 20s test @ http://localhost:8082
  2 threads and 10000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     9.42ms   37.51ms   1.11s    99.67%
    Req/Sec    60.96k     6.99k   74.54k    64.57%
  2421044 requests in 20.03s, 376.35MB read
  Socket errors: connect 8981, read 800, write 0, timeout 0
Requests/sec: 120859.31
Transfer/sec:     18.79MB
alx@asus5775:~/etc/unitd$ wrk -t2 -c100 -d5s http://localhost:81
Running 5s test @ http://localhost:81
  2 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     2.75ms    1.31ms  13.38ms   68.99%
    Req/Sec    18.38k     1.40k   20.72k    65.00%
  182849 requests in 5.00s, 28.25MB read
Requests/sec:  36564.68
Transfer/sec:      5.65MB
alx@asus5775:~/etc/unitd$ wrk -t2 -c1000 -d10s http://localhost:81
Running 10s test @ http://localhost:81
  2 threads and 1000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     8.70ms    8.45ms 613.41ms   84.71%
    Req/Sec    15.75k     8.00k   32.03k    77.00%
  313409 requests in 10.04s, 66.65MB read
  Socket errors: connect 0, read 386, write 0, timeout 1
  Non-2xx or 3xx responses: 313398
Requests/sec:  31217.89
Transfer/sec:      6.64MB
alx@asus5775:~/etc/unitd$ wrk -t2 -c10000 -d20s http://localhost:81
Running 20s test @ http://localhost:81
  2 threads and 10000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     8.12ms    5.92ms 782.23ms   55.91%
    Req/Sec     9.81k    12.40k   31.53k    70.45%
  370256 requests in 20.07s, 78.74MB read
  Socket errors: connect 8981, read 966, write 0, timeout 490
  Non-2xx or 3xx responses: 370222
Requests/sec:  18446.00
Transfer/sec:      3.92MB
alx@asus5775:~/etc/unitd$ wrk -t2 -c100 -d5s http://localhost:82
Running 5s test @ http://localhost:82
  2 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.99ms    1.79ms  14.49ms   72.06%
    Req/Sec    28.95k    16.50k   46.36k    51.00%
  288113 requests in 5.00s, 66.49MB read
Requests/sec:  57598.73
Transfer/sec:     13.29MB
alx@asus5775:~/etc/unitd$ wrk -t2 -c1000 -d10s http://localhost:82
Running 10s test @ http://localhost:82
  2 threads and 1000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    19.25ms   64.28ms   1.03s    97.92%
    Req/Sec    47.14k     4.51k   61.54k    74.00%
  938916 requests in 10.06s, 209.40MB read
  Socket errors: connect 0, read 400, write 0, timeout 0
  Non-2xx or 3xx responses: 849107
Requests/sec:  93373.84
Transfer/sec:     20.82MB
alx@asus5775:~/etc/unitd$ wrk -t2 -c10000 -d20s http://localhost:82
Running 20s test @ http://localhost:82
  2 threads and 10000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    11.24ms   50.91ms   1.72s    99.59%
    Req/Sec    57.26k     6.28k  107.89k    78.70%
  2276873 requests in 20.10s, 507.63MB read
  Socket errors: connect 8981, read 699, write 0, timeout 0
  Non-2xx or 3xx responses: 2079380
Requests/sec: 113296.21
Transfer/sec:     25.26MB
alx@asus5775:~/etc/unitd$ wrk -t2 -c100 -d5s http://localhost:83
Running 5s test @ http://localhost:83
  2 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    11.00ms    5.11ms  32.96ms   71.84%
    Req/Sec     4.58k   501.63     5.69k    76.00%
  45553 requests in 5.00s, 8.47MB read
Requests/sec:   9107.15
Transfer/sec:      1.69MB
alx@asus5775:~/etc/unitd$ wrk -t2 -c1000 -d10s http://localhost:83
Running 10s test @ http://localhost:83
  2 threads and 1000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   109.09ms   57.42ms 951.18ms   95.01%
    Req/Sec     4.72k     1.30k    9.68k    76.00%
  93939 requests in 10.06s, 17.47MB read
  Socket errors: connect 0, read 361, write 0, timeout 0
Requests/sec:   9334.29
Transfer/sec:      1.74MB
alx@asus5775:~/etc/unitd$ wrk -t2 -c10000 -d20s http://localhost:83
Running 20s test @ http://localhost:83
  2 threads and 10000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   124.36ms   85.91ms   1.70s    84.62%
    Req/Sec     4.06k     2.28k    7.05k    58.16%
  161099 requests in 20.08s, 29.96MB read
  Socket errors: connect 8981, read 670, write 0, timeout 0
Requests/sec:   8021.46
Transfer/sec:      1.49MB
alx@asus5775:~/etc/unitd$ wrk -t2 -c100 -d5s http://localhost:84
Running 5s test @ http://localhost:84
  2 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     0.00us    0.00us   0.00us    -nan%
    Req/Sec     0.00      0.00     0.00      -nan%
  0 requests in 5.01s, 0.00B read
  Socket errors: connect 0, read 31983, write 0, timeout 0
Requests/sec:      0.00
Transfer/sec:       0.00B
alx@asus5775:~/etc/unitd$ wrk -t2 -c1000 -d10s http://localhost:84
Running 10s test @ http://localhost:84
  2 threads and 1000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     4.51ms    7.59ms 790.51ms   96.36%
    Req/Sec    10.96k     9.94k   31.89k    53.40%
  208512 requests in 10.05s, 44.34MB read
  Socket errors: connect 0, read 374, write 0, timeout 110
  Non-2xx or 3xx responses: 208512
Requests/sec:  20745.97
Transfer/sec:      4.41MB
alx@asus5775:~/etc/unitd$ wrk -t2 -c10000 -d20s http://localhost:84
Running 20s test @ http://localhost:84
  2 threads and 10000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     7.43ms    6.56ms  47.70ms   62.76%
    Req/Sec    11.63k    11.51k   32.04k    41.91%
  437320 requests in 20.08s, 93.00MB read
  Socket errors: connect 8981, read 920, write 0, timeout 409
  Non-2xx or 3xx responses: 437320
Requests/sec:  21775.63
Transfer/sec:      4.63MB
alx@asus5775:~/etc/unitd$ wrk -t2 -c100 -d5s http://localhost:85
Running 5s test @ http://localhost:85
  2 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   265.33us  470.58us   8.84ms   97.52%
    Req/Sec   142.29k    13.51k  149.88k    91.00%
  1414962 requests in 5.00s, 126.84MB read
Requests/sec: 282937.45
Transfer/sec:     25.36MB
alx@asus5775:~/etc/unitd$ wrk -t2 -c1000 -d10s http://localhost:85
Running 10s test @ http://localhost:85
  2 threads and 1000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     8.58ms   47.70ms 704.78ms   97.73%
    Req/Sec   132.41k    11.25k  141.19k    93.00%
  2647160 requests in 10.09s, 237.31MB read
  Socket errors: connect 0, read 396, write 0, timeout 0
Requests/sec: 262259.88
Transfer/sec:     23.51MB
alx@asus5775:~/etc/unitd$ wrk -t2 -c10000 -d20s http://localhost:85
Running 20s test @ http://localhost:85
  2 threads and 10000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     4.31ms   38.40ms   1.10s    99.61%
    Req/Sec   128.32k    14.97k  139.48k    90.45%
  5103994 requests in 20.07s, 457.55MB read
  Socket errors: connect 8981, read 800, write 0, timeout 0
Requests/sec: 254306.35
Transfer/sec:     22.80MB
alx@asus5775:~/etc/unitd$ curl localhost:8080
rdm
alx@asus5775:~/etc/unitd$ curl localhost:8081
alx@asus5775:~/etc/unitd$ curl localhost:8082
Hello, Perl on Unit!
alx@asus5775:~/etc/unitd$ curl localhost:81
alx@asus5775:~/etc/unitd$ curl localhost:82
Warning: Binary output can mess up your terminal. Use "--output -" to tell 
Warning: curl to output it to your terminal anyway, or consider "--output 
Warning: <FILE>" to save to a file.
alx@asus5775:~/etc/unitd$ curl localhost:83
Warning: Binary output can mess up your terminal. Use "--output -" to tell 
Warning: curl to output it to your terminal anyway, or consider "--output 
Warning: <FILE>" to save to a file.
alx@asus5775:~/etc/unitd$ curl localhost:84
Warning: Binary output can mess up your terminal. Use "--output -" to tell 
Warning: curl to output it to your terminal anyway, or consider "--output 
Warning: <FILE>" to save to a file.
alx@asus5775:~/etc/unitd$ curl localhost:85
alx@asus5775:~/etc/unitd$ curl --compressed localhost:82
idx
alx@asus5775:~/etc/unitd$ curl --compressed localhost:83
Hello, Perl on Unit!
alx@asus5775:~/etc/unitd$ curl --compressed localhost:84
rdm

Compressing a share seems to be quite fast.
Compressing a proxy is not significantly slower than the proxy itself.
However, compressing applications seems to be quite slow. Not sure if it's due to the text being longer than in the other two cases (I don't think so, as they are both very small) or why. Maybe it's just the CPU getting outnumbered by the processes.

There's also the weirdness that port 84 (the compressed proxy) has weird (0) numbers for a lowish number of connections.

Here's a peak at the errors thrown by this test:

$ sudo wc -l /opt/local/unit/gzip/var/log/unit/unit.log
11158695 /opt/local/unit/gzip/var/log/unit/unit.log
alx@asus5775:~/etc/unitd$ sudo cat /opt/local/unit/gzip/var/log/unit/unit.log | grep -o 'failed.*' | uniq -c
     77 failed (104: Connection reset by peer)
1940842 failed (24: Too many open files)
    523 failed (104: Connection reset by peer)
3797184 failed (24: Too many open files)
    798 failed (104: Connection reset by peer)
 457016 failed (24: Too many open files)
    638 failed (104: Connection reset by peer)
 675167 failed (24: Too many open files)
    833 failed (104: Connection reset by peer)
    404 failed (24: Too many open files)
    872 failed (104: Connection reset by peer)
    800 failed (24: Too many open files)
    907 failed (104: Connection reset by peer)
 314227 failed (24: Too many open files)
     14 failed (104: Connection reset by peer)
    198 failed (24: Too many open files)
      2 failed (32: Broken pipe)
 371694 failed (24: Too many open files)
     47 failed (104: Connection reset by peer)
 849979 failed (24: Too many open files)
      2 failed (104: Connection reset by peer)
      1 failed (24: Too many open files)
      1 failed (104: Connection reset by peer)
      1 failed (24: Too many open files)
      4 failed (104: Connection reset by peer)
     11 failed (24: Too many open files)
      1 failed (104: Connection reset by peer)
      1 failed (24: Too many open files)
      1 failed (104: Connection reset by peer)
     20 failed (24: Too many open files)
    628 failed (104: Connection reset by peer)
2080960 failed (24: Too many open files)
    880 failed (104: Connection reset by peer)
   1036 failed (24: Too many open files)
     72 failed (104: Connection reset by peer)
      4 failed (32: Broken pipe)
 209253 failed (24: Too many open files)
      2 failed (32: Broken pipe)
 438645 failed (24: Too many open files)
      2 failed (32: Broken pipe)
     55 failed (104: Connection reset by peer)
    396 failed (24: Too many open files)
    435 failed (104: Connection reset by peer)
    804 failed (24: Too many open files)
    570 failed (104: Connection reset by peer)

To clarify, I think it's more appropriate to perform this tests with small files, because we don't try to measure the performance of zlib, but of the wrapping that we do in unit. Having the compression be virtually instantaneous helps not hide our numbers with those of zlib.

@alejandro-colomar
Copy link
Contributor Author

alejandro-colomar commented Aug 30, 2023

Memory test:

alx@asus5775:~$ # idle
alx@asus5775:~$ ps aux | head -n1
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
alx@asus5775:~$ ps aux | grep unit
root      344912  0.0  0.0   5548  2184 ?        Ss   00:32   0:00 unit: main v1.31.0 [/opt/local/unit/gzip/sbin/unitd]
nobody    344914  0.0  0.0   4904  1664 ?        S    00:32   0:00 unit: controller
nobody    344915  0.0  0.0 308956  3460 ?        Sl   00:32   0:00 unit: router
nobody    344916  0.0  0.0   9764  2060 ?        S    00:32   0:00 unit: "perl" prototype
nobody    344917  0.0  0.0  15692  5392 ?        S    00:32   0:00 unit: "perl" application
alx       344923  0.0  0.0   6868  2176 pts/3    S+   00:33   0:00 grep unit
$ wrk -t2 -c10000 -d30m http://localhost:82
[...the results were accidentally lost...]
alx@asus5775:~$ ps aux | head -n1
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
alx@asus5775:~$ # 5 s
alx@asus5775:~$ ps aux | grep unit
root      344912  0.0  0.0   5548  2184 ?        Ss   00:32   0:00 unit: main v1.31.0 [/opt/local/unit/gzip/sbin/unitd]
nobody    344914  0.0  0.0   4904  1664 ?        S    00:32   0:00 unit: controller
nobody    344915 20.7  0.1 308956 38476 ?        Sl   00:32   0:14 unit: router
nobody    344916  0.0  0.0   9764  2060 ?        S    00:32   0:00 unit: "perl" prototype
nobody    344917  0.0  0.0  15692  5392 ?        S    00:32   0:00 unit: "perl" application
alx       344929  0.0  0.0   6868  2048 pts/3    S+   00:34   0:00 grep unit
alx@asus5775:~$ # 1 min
alx@asus5775:~$ ps aux | grep unit
root      344912  0.0  0.0   5548  2184 ?        Ss   00:32   0:00 unit: main v1.31.0 [/opt/local/unit/gzip/sbin/unitd]
nobody    344914  0.0  0.0   4904  1664 ?        S    00:32   0:00 unit: controller
nobody    344915  138  0.1 308956 39812 ?        Sl   00:32   2:52 unit: router
nobody    344916  0.0  0.0   9764  2060 ?        S    00:32   0:00 unit: "perl" prototype
nobody    344917  0.0  0.0  15692  5392 ?        S    00:32   0:00 unit: "perl" application
alx       344932  0.0  0.0   6868  2048 pts/3    S+   00:35   0:00 grep unit
alx@asus5775:~$ # 5 min
alx@asus5775:~$ ps aux | grep unit
root      344912  0.0  0.0   5548  2184 ?        Ss   00:32   0:00 unit: main v1.31.0 [/opt/local/unit/gzip/sbin/unitd]
nobody    344914  0.0  0.0   4904  1664 ?        S    00:32   0:00 unit: controller
nobody    344915  210  0.1 308956 39916 ?        Sl   00:32  13:11 unit: router
nobody    344916  0.0  0.0   9764  2060 ?        S    00:32   0:00 unit: "perl" prototype
nobody    344917  0.0  0.0  15692  5392 ?        S    00:32   0:00 unit: "perl" application
alx       344972  0.0  0.0   6868  2048 pts/3    S+   00:39   0:00 grep unit
alx@asus5775:~$ # 15 min
alx@asus5775:~$ ps aux | grep unit
root      344912  0.0  0.0   5548  2184 ?        Ss   00:32   0:00 unit: main v1.31.0 [/opt/local/unit/gzip/sbin/unitd]
nobody    344914  0.0  0.0   4904  1664 ?        S    00:32   0:00 unit: controller
nobody    344915  213  0.1 308956 40624 ?        Sl   00:32  34:15 unit: router
nobody    344916  0.0  0.0   9764  2060 ?        S    00:32   0:00 unit: "perl" prototype
nobody    344917  0.0  0.0  15692  5392 ?        S    00:32   0:00 unit: "perl" application
alx       345097  0.0  0.0   6868  2048 pts/3    S+   00:49   0:00 grep unit
alx@asus5775:~$ # 29 min
alx@asus5775:~$ ps aux | grep unit
root      344912  0.0  0.0   5548  2184 ?        Ss   00:32   0:00 unit: main v1.31.0 [/opt/local/unit/gzip/sbin/unitd]
nobody    344914  0.0  0.0   4904  1664 ?        S    00:32   0:00 unit: controller
nobody    344915  211  0.1 308956 41120 ?        Sl   00:32  63:35 unit: router
nobody    344916  0.0  0.0   9764  2060 ?        S    00:32   0:00 unit: "perl" prototype
nobody    344917  0.0  0.0  15692  5392 ?        S    00:32   0:00 unit: "perl" application
alx       345242  0.0  0.0   6868  1920 pts/3    S+   01:03   0:00 grep unit
alx@asus5775:~$ # 1 min idle
alx@asus5775:~$ ps aux | head -n1
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
alx@asus5775:~$ ps aux | grep unit
root      344912  0.0  0.0   5548  2184 ?        Ss   00:32   0:00 unit: main v1.31.0 [/opt/local/unit/gzip/sbin/unitd]
nobody    344914  0.0  0.0   4904  1664 ?        S    00:32   0:00 unit: controller
nobody    344915  204  0.1 308956 39388 ?        Sl   00:32  65:38 unit: router
nobody    344916  0.0  0.0   9764  2060 ?        S    00:32   0:00 unit: "perl" prototype
nobody    344917  0.0  0.0  15692  5392 ?        S    00:32   0:00 unit: "perl" application
alx       345248  0.0  0.0   6868  2048 pts/3    S+   01:05   0:00 grep unit
alx@asus5775:~$ wrk -t2 -c10000 -d30m http://localhost:83
Running 30m test @ http://localhost:83
  2 threads and 10000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    93.43ms   82.73ms   1.70s    98.44%
    Req/Sec     5.37k     5.55k   27.42k    89.33%
  19228780 requests in 30.00m, 3.49GB read
  Socket errors: connect 8981, read 59535, write 0, timeout 0
Requests/sec:  10682.57
Transfer/sec:      1.99MB
alx@asus5775:~$ # 5 s
alx@asus5775:~$ ps aux | grep unit
root      344912  0.0  0.0   5548  2184 ?        Ss   00:32   0:00 unit: main v1.31.0 [/opt/local/unit/gzip/sbin/unitd]
nobody    344914  0.0  0.0   4904  1664 ?        S    00:32   0:00 unit: controller
nobody    344915  192  0.1 8149264 59728 ?       Sl   00:32  65:46 unit: router
nobody    344916  0.0  0.0   9764  2060 ?        S    00:32   0:00 unit: "perl" prototype
nobody    344917  0.0  0.0  38900 17296 ?        S    00:32   0:01 unit: "perl" application
alx       345313  0.0  0.0   6868  2048 pts/3    S+   01:07   0:00 grep unit
alx@asus5775:~$ # 1 min
alx@asus5775:~$ ps aux | grep unit
root      344912  0.0  0.0   5548  2184 ?        Ss   00:32   0:00 unit: main v1.31.0 [/opt/local/unit/gzip/sbin/unitd]
nobody    344914  0.0  0.0   4904  1664 ?        S    00:32   0:00 unit: controller
nobody    344915  191  0.1 329444 64484 ?        Sl   00:32  67:20 unit: router
nobody    344916  0.0  0.0   9764  2060 ?        S    00:32   0:00 unit: "perl" prototype
nobody    344917  0.8  0.0  38900 17296 ?        S    00:32   0:17 unit: "perl" application
alx       345315  0.0  0.0   6868  2048 pts/3    S+   01:08   0:00 grep unit
alx@asus5775:~$ # 5 min
alx@asus5775:~$ ps aux | grep unit
root      344912  0.0  0.0   5548  2184 ?        Ss   00:32   0:00 unit: main v1.31.0 [/opt/local/unit/gzip/sbin/unitd]
nobody    344914  0.0  0.0   4904  1664 ?        S    00:32   0:00 unit: controller
nobody    344915  187  0.2 3677564 74244 ?       Sl   00:32  73:14 unit: router
nobody    344916  0.0  0.0   9764  2060 ?        S    00:32   0:00 unit: "perl" prototype
nobody    344917  2.7  0.0  38900 17296 ?        S    00:32   1:03 unit: "perl" application
alx       345615  0.0  0.0   6868  2048 pts/3    S+   01:12   0:00 grep unit
alx@asus5775:~$ # 15 min
alx@asus5775:~$ ps aux | grep unit
root      344912  0.0  0.0   5548  2184 ?        Ss   00:32   0:00 unit: main v1.31.0 [/opt/local/unit/gzip/sbin/unitd]
nobody    344914  0.0  0.0   4904  1664 ?        S    00:32   0:00 unit: controller
nobody    344915  173  0.2 329444 73580 ?        Sl   00:32  85:20 unit: router
nobody    344916  0.0  0.0   9764  2060 ?        S    00:32   0:00 unit: "perl" prototype
nobody    344917  3.2  0.0  38900 17296 ?        S    00:32   1:34 unit: "perl" application
alx       345824  0.0  0.0   6868  2048 pts/3    S+   01:22   0:00 grep unit
alx@asus5775:~$ # 29 min
alx@asus5775:~$ ps aux | grep unit
root      344912  0.0  0.0   5548  2184 ?        Ss   00:32   0:00 unit: main v1.31.0 [/opt/local/unit/gzip/sbin/unitd]
nobody    344914  0.0  0.0   4904  1664 ?        S    00:32   0:00 unit: controller
nobody    344915  161  0.2 4190172 75944 ?       Sl   00:32 102:09 unit: router
nobody    344916  0.0  0.0   9764  2060 ?        S    00:32   0:00 unit: "perl" prototype
nobody    344917  3.6  0.0  38900 17296 ?        S    00:32   2:17 unit: "perl" application
alx       345859  0.0  0.0   6868  2176 pts/3    S+   01:36   0:00 grep unit
alx@asus5775:~$ # 1 min idle
alx@asus5775:~$ ps aux | grep unit
root      344912  0.0  0.0   5548  2184 ?        Ss   00:32   0:00 unit: main v1.31.0 [/opt/local/unit/gzip/sbin/unitd]
nobody    344914  0.0  0.0   4904  1664 ?        S    00:32   0:00 unit: controller
nobody    344915  158  0.2 329444 75960 ?        Sl   00:32 103:22 unit: router
nobody    344916  0.0  0.0   9764  2060 ?        S    00:32   0:00 unit: "perl" prototype
nobody    344917  3.5  0.0  38900 17296 ?        S    00:32   2:20 unit: "perl" application
alx       345864  0.0  0.0   6868  2048 pts/3    S+   01:38   0:00 grep unit
alx@asus5775:~$ # 10 min idle
alx@asus5775:~$ ps aux | grep unit
root      344912  0.0  0.0   5548  2184 ?        Ss   00:32   0:00 unit: main v1.31.0 [/opt/local/unit/gzip/sbin/unitd]
nobody    344914  0.0  0.0   4904  1664 ?        S    00:32   0:00 unit: controller
nobody    344915  139  0.2 329444 89656 ?        Sl   00:32 103:22 unit: router
nobody    344916  0.0  0.0   9764  1932 ?        S    00:32   0:00 unit: "perl" prototype
nobody    344917  3.1  0.0  38900 16656 ?        S    00:32   2:20 unit: "perl" application
alx       346030  0.0  0.0   6868  2048 pts/3    S+   01:47   0:00 grep unit
alx@asus5775:~$ # all night idle
alx@asus5775:~$ ps aux | grep unit
root      344912  0.0  0.0   5548  2184 ?        Ss   00:32   0:00 unit: main v1.31.0 [/opt/local/unit/gzip/sbin/unitd]
nobody    344914  0.0  0.0   4904  1664 ?        S    00:32   0:00 unit: controller
nobody    344915 16.9  0.2 329444 91832 ?        Sl   00:32 103:22 unit: router
nobody    344916  0.0  0.0   9764  1932 ?        S    00:32   0:00 unit: "perl" prototype
nobody    344917  0.3  0.0  38900 16656 ?        S    00:32   2:20 unit: "perl" application
alx       350183  0.0  0.0   6868  2176 pts/3    S+   10:43   0:00 grep unit
alx@asus5775:~$ wrk -t2 -c10000 -d5m http://localhost:82
Running 5m test @ http://localhost:82
  2 threads and 10000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    10.93ms   53.94ms   1.99s    99.63%
    Req/Sec    58.83k     7.51k   88.93k    81.46%
  35122975 requests in 5.00m, 7.64GB read
  Socket errors: connect 8981, read 9045, write 0, timeout 8
  Non-2xx or 3xx responses: 33199513
Requests/sec: 117043.18
Transfer/sec:     26.06MB
alx@asus5775:~$ # 5 s
alx@asus5775:~$ ps aux | grep unit
root      344912  0.0  0.0   5548  2184 ?        Ss   00:32   0:00 unit: main v1.31.0 [/opt/local/unit/gzip/sbin/unitd]
nobody    344914  0.0  0.0   4904  1664 ?        S    00:32   0:00 unit: controller
nobody    344915 16.9  0.2 329444 91832 ?        Sl   00:32 103:34 unit: router
nobody    344916  0.0  0.0   9764  1932 ?        S    00:32   0:00 unit: "perl" prototype
nobody    344917  0.3  0.0  38900 16656 ?        S    00:32   2:20 unit: "perl" application
alx       350192  0.0  0.0   6868  2048 pts/3    S+   10:44   0:00 grep unit
alx@asus5775:~$ # 1 min
alx@asus5775:~$ ps aux | grep unit
root      344912  0.0  0.0   5548  2184 ?        Ss   00:32   0:00 unit: main v1.31.0 [/opt/local/unit/gzip/sbin/unitd]
nobody    344914  0.0  0.0   4904  1664 ?        S    00:32   0:00 unit: controller
nobody    344915 17.4  0.2 329444 94004 ?        Sl   00:32 106:38 unit: router
nobody    344916  0.0  0.0   9764  1932 ?        S    00:32   0:00 unit: "perl" prototype
nobody    344917  0.3  0.0  38900 16656 ?        S    00:32   2:20 unit: "perl" application
alx       350196  0.0  0.0   6868  2048 pts/3    S+   10:45   0:00 grep unit
alx@asus5775:~$ # 1 min idle
alx@asus5775:~$ ps aux | grep unit
root      344912  0.0  0.0   5548  2184 ?        Ss   00:32   0:00 unit: main v1.31.0 [/opt/local/unit/gzip/sbin/unitd]
nobody    344914  0.0  0.0   4904  1664 ?        S    00:32   0:00 unit: controller
nobody    344915 18.5  0.2 329444 94004 ?        Sl   00:32 114:20 unit: router
nobody    344916  0.0  0.0   9764  1932 ?        S    00:32   0:00 unit: "perl" prototype
nobody    344917  0.3  0.0  38900 16656 ?        S    00:32   2:20 unit: "perl" application
alx       350274  0.0  0.0   6868  1920 pts/3    S+   10:49   0:00 grep unit
alx@asus5775:~$ wrk -t2 -c10000 -d5m http://localhost:83
Running 5m test @ http://localhost:83
  2 threads and 10000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   123.18ms   78.02ms   1.69s    87.48%
    Req/Sec     4.08k     1.53k    8.03k    56.10%
  2435842 requests in 5.00m, 452.98MB read
  Socket errors: connect 8981, read 10014, write 0, timeout 0
Requests/sec:   8117.14
Transfer/sec:      1.51MB
alx@asus5775:~$ # 5 s
alx@asus5775:~$ ps aux | grep unit
root      344912  0.0  0.0   5548  2184 ?        Ss   00:32   0:00 unit: main v1.31.0 [/opt/local/unit/gzip/sbin/unitd]
nobody    344914  0.0  0.0   4904  1664 ?        S    00:32   0:00 unit: controller
nobody    344915 18.5  0.3 2003504 102572 ?      Sl   00:32 114:23 unit: router
nobody    344916  0.0  0.0   9764  1932 ?        S    00:32   0:00 unit: "perl" prototype
nobody    344917  0.3  0.0  38900 16656 ?        S    00:32   2:20 unit: "perl" application
alx       350279  0.0  0.0   6868  2048 pts/3    S+   10:50   0:00 grep unit
alx@asus5775:~$ # 1 min
alx@asus5775:~$ ps aux | grep unit
root      344912  0.0  0.0   5548  2184 ?        Ss   00:32   0:00 unit: main v1.31.0 [/opt/local/unit/gzip/sbin/unitd]
nobody    344914  0.0  0.0   4904  1664 ?        S    00:32   0:00 unit: controller
nobody    344915 18.8  0.3 2003504 104916 ?      Sl   00:32 116:22 unit: router
nobody    344916  0.0  0.0   9764  1932 ?        S    00:32   0:00 unit: "perl" prototype
nobody    344917  0.3  0.0  38900 16656 ?        R    00:32   2:26 unit: "perl" application
alx       350282  0.0  0.0   6868  2048 pts/3    S+   10:51   0:00 grep unit
alx@asus5775:~$ # 1 min idle
alx@asus5775:~$ ps aux | grep unit
root      344912  0.0  0.0   5548  2184 ?        Ss   00:32   0:00 unit: main v1.31.0 [/opt/local/unit/gzip/sbin/unitd]
nobody    344914  0.0  0.0   4904  1664 ?        S    00:32   0:00 unit: controller
nobody    344915 19.3  0.3 329444 105572 ?       Sl   00:32 120:28 unit: router
nobody    344916  0.0  0.0   9764  1932 ?        S    00:32   0:00 unit: "perl" prototype
nobody    344917  0.4  0.0  38900 16656 ?        S    00:32   2:38 unit: "perl" application
alx       350346  0.0  0.0   6868  2048 pts/3    S+   10:56   0:00 grep unit
alx@asus5775:~$ echo '{}' | sudo unit ctl http PUT /config
[sudo] password for alx: 
{
	"success": "Reconfiguration done."
}
alx@asus5775:~$ ps aux | grep unit
root      344912  0.0  0.0   4904  2184 ?        Ss   00:32   0:00 unit: main v1.31.0 [/opt/local/unit/gzip/sbin/unitd]
nobody    344914  0.0  0.0   4904  1664 ?        S    00:32   0:00 unit: controller
nobody    344915 19.3  0.2 302676 96036 ?        Sl   00:32 120:28 unit: router
alx       350382  0.0  0.0   6868  2048 pts/3    S+   10:56   0:00 grep unit
alx@asus5775:~$ sudo unit ctl http PUT /config </home/alx/etc/unitd/gzip-v19-2.json 
{
	"success": "Reconfiguration done."
}
alx@asus5775:~$ ps aux | grep unit
root      344912  0.0  0.0   5548  2184 ?        Ss   00:32   0:00 unit: main v1.31.0 [/opt/local/unit/gzip/sbin/unitd]
nobody    344914  0.0  0.0   5036  1664 ?        S    00:32   0:00 unit: controller
nobody    344915 18.8  0.2 308956 97060 ?        Sl   00:32 120:28 unit: router
nobody    350599  0.0  0.0   9764  2192 ?        S    11:10   0:00 unit: "perl" prototype
nobody    350600  0.0  0.0  15692  5140 ?        S    11:10   0:00 unit: "perl" application
alx       350602  0.0  0.0   6868  2048 pts/3    S+   11:10   0:00 grep unit

The VSZ field has some peaks, but in the long term stays stable, so there seem to be no memory leaks.

Here are the errors of this test session:

alx@asus5775:~$ sudo wc -l /opt/local/unit/gzip/var/log/unit/unit.log
212237370 /opt/local/unit/gzip/var/log/unit/unit.log
alx@asus5775:~$ sudo cat /opt/local/unit/gzip/var/log/unit/unit.log | grep -o 'failed.*' | uniq -c
178787443 failed (24: Too many open files)
   1001 failed (104: Connection reset by peer)
  59694 failed (24: Too many open files)
    131 failed (104: Connection reset by peer)
33212401 failed (24: Too many open files)
    973 failed (104: Connection reset by peer)
  10035 failed (24: Too many open files)

@hongzhidao
Copy link
Contributor

hongzhidao commented Aug 30, 2023

About the QPS and memory test on the feature, maybe it's helpful to do the wrk test on NGINX with the same file size.
It's to know how much difference gzip encoding makes if it's on or off between the two oss.

@alejandro-colomar
Copy link
Contributor Author

About the QPS and memory test on the feature, maybe it's helpful to do the wrk test on NGINX with the same file size. It's to know how much difference gzip encoding makes if it's on or off between the two oss.

Makes sense.

Of course, I'll only do the share (so skip the perl app), since it's the only thing comparable to nginx.

@alejandro-colomar
Copy link
Contributor Author

v20 changes:

  • Split addition of "compress" and "gzip" to separate commits.
  • [DEBUG] log at start of compression handler.
  • Unknown MIME type is handled as empty string (as in "share").
  • Add headers for compress and compress_gzip.
  • iwyu(1) as much as possible in the newly added files.
$ git range-diff master gh/actions actions
 1:  4f1bac72 =  1:  4f1bac72 Libunit: added macros that enhance type safety.
 2:  fbc02b60 =  2:  fbc02b60 HTTP: refactor: inverted conditional to reduce nesting.
 3:  eb1e4825 =  3:  eb1e4825 Router: refactor: factored out application creation loop.
 4:  80efaac9 =  4:  80efaac9 Router: refactor: factored out listeners creation loop.
 5:  3e3c2920 =  5:  3e3c2920 Refactor: inverted conditional to reduce nesting.
 6:  0f46a270 =  6:  0f46a270 Refactor: using a temporary variable in a macro.
 7:  7205b664 =  7:  7205b664 Var: refactor: removed dead code.
 8:  8e7a06ab =  8:  8e7a06ab Var: refactor: removed dead code.
 9:  c9e21957 =  9:  c9e21957 Var: refactor: removed dead code.
10:  392ffc42 = 10:  392ffc42 Refactor: storing the body_handler as part of r.
11:  81a408ce = 11:  81a408ce HTTP: refactor: transformed loop into recursive call.
12:  36caadcf = 12:  36caadcf HTTP: refactor: requesting the fallback action from the action itself.
13:  268449c2 = 13:  268449c2 HTTP: refactor: requesting the actions from the route handler.
14:  aca3bb0f = 14:  aca3bb0f HTTP: refactor: failing in the route handler.
15:  d41a0780 = 15:  d41a0780 HTTP: pass: refactor: using a ctx.
16:  4caf41ca = 16:  4caf41ca HTTP: return: refactor: using 'add_header' member in ctx.
17:  d2de42ea = 17:  d2de42ea Proxy: refactor: using goto fail.
18:  16a67076 = 18:  16a67076 Static: refactor: transformed goto into do-while loop.
19:  d21860e6 = 19:  d21860e6 HTTP: supporting a list of filter_handlers
21:  3a2afd72 ! 20:  979f115a HTTP: added "compress" action.
    [...]
20:  81c7ade8 = 21:  ec8ffd0b Auto: compiling with zlib.
 -:  -------- > 22:  fc1747cc HTTP: compress: added "gzip" encoding.
22:  fe811581 ! 23:  8c572b73 HTTP: compress: added configurable "level" of compression.
    [...]
23:  38301c59 ! 24:  1fd2f14f Auto: added --no-zlib.
    [...]
24:  700ce57d = 25:  97d5e79f String: added strto[u]l(3) variants for nxt_str_t.
25:  24c0579e <  -:  -------- HTTP: compress: added configurable threshold for Content-Length.
 -:  -------- > 26:  cc461411 HTTP: compress: added configurable threshold for Content-Length.
26:  ea3c1128 = 27:  42f945e6 Router: moved structure definition to header.
27:  62f1cf40 = 28:  7e4f73a4 PCRE: moved structure definition to header.
28:  547398d0 = 29:  56c2e8bb HTTP: refactored code.
29:  b5608ea7 ! 30:  77d83855 HTTP: logging when control is "pass"ed.
    @@ Commit message
     
         -  HTTP: printing the application name in the debug log.
     
    +    -  HTTP: compress: gzip: logging when running the compression handler.
    +
         Link: <https://github.com/nginx/unit/issues/758>
         Link: <https://github.com/nginx/unit/pull/824>
         Link: <https://github.com/nginx/unit/pull/839>
         Suggested-by: Liam Crilly <[email protected]>
    -    Reviewed-by: Andrew Clayton <[email protected]>
    +    Cc: Andrew Clayton <[email protected]>
         Signed-off-by: Alejandro Colomar <[email protected]>
     
    + ## src/nxt_http_compress_gzip.c ##
    +@@ src/nxt_http_compress_gzip.c: nxt_http_compress_gzip(nxt_task_t *task, nxt_http_request_t *r,
    +     static nxt_str_t  ce = nxt_string("Content-Encoding");
    +     static nxt_str_t  gzip = nxt_string("gzip");
    + 
    ++    nxt_debug(task, "http compress: gzip");
    ++
    +     if (nxt_http_compress_resp_content_length_is_small(&r->resp, conf->thresh)
    +         || r->body_handler == NULL)
    +     {
    +
      ## src/nxt_http_request.c ##
     @@ src/nxt_http_request.c: nxt_http_action_t *
      nxt_http_application_handler(nxt_task_t *task, nxt_http_request_t *r,
30:  8bcad90f = 31:  6cf81aba HTTP: logging the kind of element tried for a match.
31:  e3c8b70b = 32:  330af699 HTTP: logging pattern-matching decissions.
32:  e264d36e = 33:  326c165c HTTP: moved typedefs to top of file.
33:  84a8364d ! 34:  04642896 HTTP: compress: added mime_types.
    [...]

@alejandro-colomar
Copy link
Contributor Author

alejandro-colomar commented Aug 30, 2023

v20b changes:

  • Fix include guard.
$ git range-diff master gh/actions actions
 1:  4f1bac72 =  1:  4f1bac72 Libunit: added macros that enhance type safety.
 2:  fbc02b60 =  2:  fbc02b60 HTTP: refactor: inverted conditional to reduce nesting.
 3:  eb1e4825 =  3:  eb1e4825 Router: refactor: factored out application creation loop.
 4:  80efaac9 =  4:  80efaac9 Router: refactor: factored out listeners creation loop.
 5:  3e3c2920 =  5:  3e3c2920 Refactor: inverted conditional to reduce nesting.
 6:  0f46a270 =  6:  0f46a270 Refactor: using a temporary variable in a macro.
 7:  7205b664 =  7:  7205b664 Var: refactor: removed dead code.
 8:  8e7a06ab =  8:  8e7a06ab Var: refactor: removed dead code.
 9:  c9e21957 =  9:  c9e21957 Var: refactor: removed dead code.
10:  392ffc42 = 10:  392ffc42 Refactor: storing the body_handler as part of r.
11:  81a408ce = 11:  81a408ce HTTP: refactor: transformed loop into recursive call.
12:  36caadcf = 12:  36caadcf HTTP: refactor: requesting the fallback action from the action itself.
13:  268449c2 = 13:  268449c2 HTTP: refactor: requesting the actions from the route handler.
14:  aca3bb0f = 14:  aca3bb0f HTTP: refactor: failing in the route handler.
15:  d41a0780 = 15:  d41a0780 HTTP: pass: refactor: using a ctx.
16:  4caf41ca = 16:  4caf41ca HTTP: return: refactor: using 'add_header' member in ctx.
17:  d2de42ea = 17:  d2de42ea Proxy: refactor: using goto fail.
18:  16a67076 = 18:  16a67076 Static: refactor: transformed goto into do-while loop.
19:  d21860e6 = 19:  d21860e6 HTTP: supporting a list of filter_handlers
20:  979f115a = 20:  979f115a HTTP: added "compress" action.
21:  ec8ffd0b = 21:  ec8ffd0b Auto: compiling with zlib.
22:  fc1747cc ! 22:  54f257ca HTTP: compress: added "gzip" encoding.
    @@ src/nxt_http_compress_gzip.h (new)
     + * Copyright (C) NGINX, Inc.
     + */
     +
    -+#ifndef NXT_HTTP_COMPRESS_GZIP_INCLUDED_
    -+#define NXT_HTTP_COMPRESS_GZIP_INCLUDED_
    ++#ifndef NXT_HTTP_COMPRESS_GZIP_H_INCLUDED_
    ++#define NXT_HTTP_COMPRESS_GZIP_H_INCLUDED_
     +
     +
     +#include "nxt_router.h"
    @@ src/nxt_http_compress_gzip.h (new)
     +    nxt_http_compress_conf_t *conf);
     +
     +
    -+#endif  /* NXT_HTTP_COMPRESS_GZIP_INCLUDED_ */
    ++#endif  /* NXT_HTTP_COMPRESS_GZIP_H_INCLUDED_ */
23:  8c572b73 = 23:  411f591a HTTP: compress: added configurable "level" of compression.
24:  1fd2f14f ! 24:  711bacb3 Auto: added --no-zlib.
    [...]
25:  97d5e79f = 25:  f9856782 String: added strto[u]l(3) variants for nxt_str_t.
26:  cc461411 = 26:  e8a5a02e HTTP: compress: added configurable threshold for Content-Length.
27:  42f945e6 = 27:  622f2c49 Router: moved structure definition to header.
28:  7e4f73a4 = 28:  f86c7df1 PCRE: moved structure definition to header.
29:  56c2e8bb = 29:  2a68181a HTTP: refactored code.
30:  77d83855 = 30:  457ec7a2 HTTP: logging when control is "pass"ed.
31:  6cf81aba = 31:  38800187 HTTP: logging the kind of element tried for a match.
32:  330af699 = 32:  3a44451d HTTP: logging pattern-matching decissions.
33:  326c165c = 33:  2b7b6b7b HTTP: moved typedefs to top of file.
34:  04642896 = 34:  24b80c8b HTTP: compress: added "mime_types" rule.

@hongzhidao
Copy link
Contributor

Hi,
There are more than 20+ refactoring patches, so I would suggest only doing the required patches for the gzip feature.
I'm afraid I can't approve those patches that belong to a separate topic.

@alejandro-colomar
Copy link
Contributor Author

Hi, There are more than 20+ refactoring patches, so I would suggest only doing the required patches for the gzip feature. I'm afraid I can't approve those patches that belong to a separate topic.

Hi,

Most of those refactors are necessary for the feature. But I still need to do a review to see if some can be removed. I'll open for review when it's ready for review.

@alejandro-colomar
Copy link
Contributor Author

Re-run tests after v33:

Unit, compression 1:

alx@asus5775:~/src/nginx/unit/actions$ sudo /opt/local/unit/gzip/sbin/unitd 
2023/09/04 03:43:24 [info] 226248#226248 unit 1.31.0 started
alx@asus5775:~/src/nginx/unit/actions$ sudo unit ctl http GET /config </dev/null
{
	"listeners": {
		"*:80": {
			"pass": "routes"
		}
	},

	"routes": [
		{
			"action": {
				"share": "/srv/www/unit/",
				"index": "index.html",
				"compress": {
					"encoding": "gzip",
					"level": 1,
					"min_length": 1
				}
			}
		}
	]
}
alx@asus5775:~/src/nginx/unit/actions$ makepasswd --char 10 | sudo tee /srv/www/unit/index.html >/dev/null
alx@asus5775:~/src/nginx/unit/actions$ wrk -t 1 -d 1m -H 'Accept-Encoding: gzip' http://localhost
Running 1m test @ http://localhost
  1 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   201.11us  324.79us  26.06ms   97.29%
    Req/Sec    55.79k     4.43k   66.87k    82.53%
  3336413 requests in 1.00m, 833.65MB read
Requests/sec:  55514.36
Transfer/sec:     13.87MB
alx@asus5775:~/src/nginx/unit/actions$ makepasswd --char 1000 | sudo tee /srv/www/unit/index.html >/dev/null
alx@asus5775:~/src/nginx/unit/actions$ wrk -t 1 -d 1m -H 'Accept-Encoding: gzip' http://localhost
Running 1m test @ http://localhost
  1 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   177.71us  149.59us  12.97ms   96.93%
    Req/Sec    55.88k     3.55k   58.78k    79.67%
  3336698 requests in 1.00m, 3.17GB read
Requests/sec:  55611.37
Transfer/sec:     54.10MB
alx@asus5775:~/src/nginx/unit/actions$ makepasswd --char 1000111 | sudo tee /srv/www/unit/index.html >/dev/null
alx@asus5775:~/src/nginx/unit/actions$ wrk -t 1 -d 1m -H 'Accept-Encoding: gzip' http://localhost
Running 1m test @ http://localhost
  1 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    84.19ms   55.01ms 262.56ms   74.98%
    Req/Sec   119.09     21.43   151.00     59.50%
  7124 requests in 1.00m, 4.93GB read
Requests/sec:    118.70
Transfer/sec:     84.18MB
alx@asus5775:~/src/nginx/unit/actions$ makepasswd --char 122000111 | sudo tee /srv/www/unit/index.html >/dev/null
alx@asus5775:~/src/nginx/unit/actions$ wrk -t 1 -d 1m -H 'Accept-Encoding: gzip' http://localhost
Running 1m test @ http://localhost
  1 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     0.00us    0.00us   0.00us    -nan%
    Req/Sec     4.88      8.44    40.00     90.91%
  56 requests in 1.00m, 4.93GB read
  Socket errors: connect 0, read 0, write 0, timeout 56
Requests/sec:      0.93
Transfer/sec:     84.19MB

Unit, compression level 9:

alx@asus5775:~/src/nginx/unit/actions$ sudo unit ctl edit /config 
{
	"success": "Reconfiguration done."
}
alx@asus5775:~/src/nginx/unit/actions$ sudo unit ctl http GET /config </dev/null
{
	"listeners": {
		"*:80": {
			"pass": "routes"
		}
	},

	"routes": [
		{
			"action": {
				"share": "/srv/www/unit/",
				"index": "index.html",
				"compress": {
					"encoding": "gzip",
					"level": 9,
					"min_length": 1
				}
			}
		}
	]
}
alx@asus5775:~/src/nginx/unit/actions$ makepasswd --char 10 | sudo tee /srv/www/unit/index.html >/dev/null
alx@asus5775:~/src/nginx/unit/actions$ wrk -t 1 -d 1m -H 'Accept-Encoding: gzip' http://localhost
Running 1m test @ http://localhost
  1 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   218.91us  323.27us  19.22ms   98.02%
    Req/Sec    49.26k     1.79k   51.24k    90.85%
  2946431 requests in 1.00m, 736.20MB read
Requests/sec:  49025.47
Transfer/sec:     12.25MB
alx@asus5775:~/src/nginx/unit/actions$ makepasswd --char 1000 | sudo tee /srv/www/unit/index.html >/dev/null
alx@asus5775:~/src/nginx/unit/actions$ wrk -t 1 -d 1m -H 'Accept-Encoding: gzip' http://localhost
Running 1m test @ http://localhost
  1 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   349.57us  115.71us   4.06ms   86.04%
    Req/Sec    28.66k   707.92    32.08k    87.67%
  1710740 requests in 1.00m, 1.63GB read
Requests/sec:  28512.04
Transfer/sec:     27.74MB
alx@asus5775:~/src/nginx/unit/actions$ makepasswd --char 1000111 | sudo tee /srv/www/unit/index.html >/dev/null
alx@asus5775:~/src/nginx/unit/actions$ wrk -t 1 -d 1m -H 'Accept-Encoding: gzip' http://localhost
Running 1m test @ http://localhost
  1 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   109.20ms   57.07ms 267.13ms   64.87%
    Req/Sec    92.07     24.73   131.00     61.50%
  5513 requests in 1.00m, 3.82GB read
Requests/sec:     91.80
Transfer/sec:     65.08MB
alx@asus5775:~/src/nginx/unit/actions$ makepasswd --char 122000111 | sudo tee /srv/www/unit/index.html >/dev/null
alx@asus5775:~/src/nginx/unit/actions$ wrk -t 1 -d 1m -H 'Accept-Encoding: gzip' http://localhost
Running 1m test @ http://localhost
  1 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     0.00us    0.00us   0.00us    -nan%
    Req/Sec     5.19      8.32    20.00     81.25%
  37 requests in 1.00m, 3.79GB read
  Socket errors: connect 0, read 0, write 0, timeout 37
Requests/sec:      0.62
Transfer/sec:     64.65MB

The performance dropped too much for small files, so we should tune the parameters a little bit.

A curiosity is that very large files (100M) seem to benefit of larger compression levels, but small files get worse performance.

With this, short responses, that is, responses with a body of up to
content_length_threshold bytes, won't be compressed.  The default value
is 20, as in NGINX.

Signed-off-by: Alejandro Colomar <[email protected]>
@alejandro-colomar
Copy link
Contributor Author

v34 changes:

  • Refactor patch 10.
$ git range-diff ngx/master 7d995a60 actions
 1:  de56ec61 =  1:  de56ec61 Libunit: added macros that enhance type safety.
 2:  ecc27ab1 =  2:  ecc27ab1 HTTP: refactor: storing the body_handler as part of r.
 3:  4977d280 =  3:  4977d280 HTTP: filter: supporting a list of filter_handlers
 4:  6e164a36 =  4:  6e164a36 HTTP: compress: added "compress" action.
 5:  d3f4e09c =  5:  d3f4e09c Auto: zlib: compiling with zlib.
 6:  00801288 =  6:  00801288 HTTP: compress: added "encoding": "gzip".
 7:  7ecdc3d1 =  7:  7ecdc3d1 HTTP: compress: added configurable "level" of compression.
 8:  39db8691 =  8:  39db8691 Auto: zlib: added --no-zlib.
 9:  3dfab08a =  9:  3dfab08a String: added strto[u]l(3) variants for nxt_str_t.
10:  9523e380 ! 10:  33480420 HTTP: compress: added configurable threshold for Content-Length.
    @@ src/nxt_http_compress.c: nxt_http_compress_append_field(nxt_task_t *task, nxt_ht
      }
     +
     +
    -+nxt_bool_t
    -+nxt_http_compress_resp_content_length_is_small(nxt_http_response_t *resp,
    -+    size_t min_len)
    ++ssize_t
    ++nxt_http_compress_resp_content_length(nxt_http_response_t *resp)
     +{
     +    size_t     cl;
     +    nxt_int_t  err;
     +    nxt_str_t  str;
     +
    -+    min_len = nxt_max(1, min_len);
    -+
     +    if (resp->content_length_n != -1) {
    -+        cl = resp->content_length_n;
    -+        return cl < min_len;
    ++        return resp->content_length_n;
     +    }
     +
     +    if (resp->content_length == NULL) {
    -+        return 0;
    ++        return -1;
     +    }
     +
     +    str.length = resp->content_length->value_length;
    @@ src/nxt_http_compress.c: nxt_http_compress_append_field(nxt_task_t *task, nxt_ht
     +
     +    cl = nxt_ustrtoul(&str, &err);
     +    if (err == NXT_ERROR) {
    -+        return 0;
    ++        return -1;
     +    }
     +
    -+    return cl < min_len;
    ++    return cl;
     +}
     
      ## src/nxt_http_compress.h ##
    @@ src/nxt_http_compress.h: struct nxt_http_compress_conf_s {
      nxt_int_t nxt_http_compress_init(nxt_router_conf_t *rtcf,
          nxt_http_action_t *action, nxt_http_action_conf_t *acf);
      
    -+nxt_bool_t nxt_http_compress_resp_content_length_is_small(
    -+    nxt_http_response_t *resp, size_t min_len);
    ++ssize_t nxt_http_compress_resp_content_length(nxt_http_response_t *resp);
      nxt_int_t nxt_http_compress_append_field(nxt_task_t *task,
          nxt_http_request_t *r, nxt_str_t *field, nxt_str_t *value);
      
     
      ## src/nxt_http_compress_gzip.c ##
    -@@ src/nxt_http_compress_gzip.c: nxt_http_compress_gzip(nxt_task_t *task, nxt_http_request_t *r,
    +@@ src/nxt_http_compress_gzip.c: nxt_int_t
    + nxt_http_compress_gzip(nxt_task_t *task, nxt_http_request_t *r,
    +     nxt_http_compress_conf_t *conf)
    + {
    ++    size_t                        clen;
    +     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");
      
    @@ src/nxt_http_compress_gzip.c: nxt_http_compress_gzip(nxt_task_t *task, nxt_http_
     -        || (r->resp.content_length != NULL
     -            && r->resp.content_length->value_length == 1
     -            && r->resp.content_length->value[0] == '0'))
    -+    if (nxt_http_compress_resp_content_length_is_small(&r->resp, conf->min_len)
    -+        || r->body_handler == NULL)
    -     {
    +-    {
    ++    clen = nxt_http_compress_resp_content_length(&r->resp);
    ++    if (clen < nxt_max(1u, conf->min_len) || r->body_handler == NULL) {
              return NXT_OK;
          }
    + 
11:  eba78e72 ! 11:  77bda113 HTTP: compress: added "mime_types" rule.
    [...]
12:  7d995a60 ! 12:  861bc494 HTTP: compress: checking $header_accept_encoding.
    [...]

These are based on C23's <stdbit.h>.

Signed-off-by: Alejandro Colomar <[email protected]>
@alejandro-colomar
Copy link
Contributor Author

v35 changes:

  • Optimization: Dynamically calculate wbits and memlevel (zlib parameters)

    So that we use an amount of memory that is comparable to the memory already used by that request. This ensures that we use a high value (for better compression), but don't use insane memory amounts.

$ git range-diff ngx/master gh/actions actions
 1:  de56ec61 =  1:  de56ec61 Libunit: added macros that enhance type safety.
 2:  ecc27ab1 =  2:  ecc27ab1 HTTP: refactor: storing the body_handler as part of r.
 3:  4977d280 =  3:  4977d280 HTTP: filter: supporting a list of filter_handlers
 4:  6e164a36 =  4:  6e164a36 HTTP: compress: added "compress" action.
 5:  d3f4e09c =  5:  d3f4e09c Auto: zlib: compiling with zlib.
 6:  00801288 =  6:  00801288 HTTP: compress: added "encoding": "gzip".
 7:  7ecdc3d1 =  7:  7ecdc3d1 HTTP: compress: added configurable "level" of compression.
 8:  39db8691 =  8:  39db8691 Auto: zlib: added --no-zlib.
 9:  3dfab08a =  9:  3dfab08a String: added strto[u]l(3) variants for nxt_str_t.
10:  33480420 = 10:  33480420 HTTP: compress: added configurable threshold for Content-Length.
11:  77bda113 = 11:  77bda113 HTTP: compress: added "mime_types" rule.
12:  861bc494 = 12:  861bc494 HTTP: compress: checking $header_accept_encoding.
 -:  -------- > 13:  04e8bdfd Libunit: added bit functions.
 -:  -------- > 14:  8a0801c6 HTTP: compress: gzip: calculating wbits and memlevel dynamically.

src/nxt_http_compress.c Outdated Show resolved Hide resolved
@alejandro-colomar
Copy link
Contributor Author

alejandro-colomar commented Sep 5, 2023 via email

@alejandro-colomar
Copy link
Contributor Author

alejandro-colomar commented Sep 5, 2023

Test:

Unit:

alx@asus5775:~/src/nginx/unit/actions$ sudo unit ctl http GET /config </dev/null
{
	"listeners": {
		"*:80": {
			"pass": "routes"
		}
	},

	"routes": [
		{
			"action": {
				"share": "/srv/www/unit$uri",
				"index": "index.html",
				"compress": {
					"encoding": "gzip",
					"level": 9,
					"min_length": 1
				}
			}
		}
	]
}
alx@asus5775:~/src/nginx/unit/actions$ wrk -t 1 -d 1m -H 'Accept-Encoding: gzip' http://localhost/10.html
Running 1m test @ http://localhost/10.html
  1 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    70.29us  126.30us  11.14ms   99.78%
    Req/Sec   130.97k     3.93k  133.38k    97.34%
  7831737 requests in 1.00m, 1.91GB read
Requests/sec: 130312.14
Transfer/sec:     32.56MB
alx@asus5775:~/src/nginx/unit/actions$ wrk -t 1 -d 1m -H 'Accept-Encoding: gzip' http://localhost/1k.html
Running 1m test @ http://localhost/1k.html
  1 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   226.23us   84.83us   3.70ms   63.90%
    Req/Sec    43.86k     2.43k   47.10k    49.25%
  2623826 requests in 1.00m, 2.70GB read
Requests/sec:  43657.76
Transfer/sec:     46.01MB
alx@asus5775:~/src/nginx/unit/actions$ wrk -t 1 -d 1m -H 'Accept-Encoding: gzip' http://localhost/1M.html
Running 1m test @ http://localhost/1M.html
  1 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    82.36ms   28.96ms 165.86ms   74.64%
    Req/Sec   121.82      4.56   141.00     83.00%
  7283 requests in 1.00m, 5.04GB read
Requests/sec:    121.32
Transfer/sec:     86.03MB
alx@asus5775:~/src/nginx/unit/actions$ wrk -t 1 -d 1m -H 'Accept-Encoding: gzip' http://localhost/100M.html
Running 1m test @ http://localhost/100M.html
  1 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     0.00us    0.00us   0.00us    -nan%
    Req/Sec     5.76     11.07    40.00     82.35%
  54 requests in 1.00m, 5.03GB read
  Socket errors: connect 0, read 0, write 0, timeout 54
Requests/sec:      0.90
Transfer/sec:     85.77MB
alx@asus5775:~/src/nginx/unit/actions$ sudo unit ctl edit /config/routes/0/action/compress/level
{
	"success": "Reconfiguration done."
}
alx@asus5775:~/src/nginx/unit/actions$ sudo unit ctl http GET /config/routes/0/action/compress </dev/null
{
	"encoding": "gzip",
	"level": 1,
	"min_length": 1
}
alx@asus5775:~/src/nginx/unit/actions$ wrk -t 1 -d 1m -H 'Accept-Encoding: gzip' http://localhost/10.html
Running 1m test @ http://localhost/10.html
  1 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    68.76us   70.97us  10.82ms   99.39%
    Req/Sec   130.04k     1.93k  132.65k    85.33%
  7762900 requests in 1.00m, 1.89GB read
Requests/sec: 129381.29
Transfer/sec:     32.33MB
alx@asus5775:~/src/nginx/unit/actions$ wrk -t 1 -d 1m -H 'Accept-Encoding: gzip' http://localhost/1k.html
Running 1m test @ http://localhost/1k.html
  1 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   232.91us   99.65us   3.23ms   67.55%
    Req/Sec    43.33k     4.24k   50.27k    70.00%
  2587472 requests in 1.00m, 2.66GB read
Requests/sec:  43124.35
Transfer/sec:     45.44MB
alx@asus5775:~/src/nginx/unit/actions$ wrk -t 1 -d 1m -H 'Accept-Encoding: gzip' http://localhost/1M.html
Running 1m test @ http://localhost/1M.html
  1 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    82.60ms   37.21ms 211.76ms   50.17%
    Req/Sec   121.40     17.09   161.00     55.67%
  7259 requests in 1.00m, 5.03GB read
Requests/sec:    120.94
Transfer/sec:     85.78MB
alx@asus5775:~/src/nginx/unit/actions$ wrk -t 1 -d 1m -H 'Accept-Encoding: gzip' http://localhost/100M.html
Running 1m test @ http://localhost/100M.html
  1 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     0.00us    0.00us   0.00us    -nan%
    Req/Sec     6.43     10.92    30.00     80.95%
  54 requests in 1.00m, 5.02GB read
  Socket errors: connect 0, read 0, write 0, timeout 54
Requests/sec:      0.90
Transfer/sec:     85.69MB
alx@asus5775:~/src/nginx/unit/actions$ wrk -t 1 -d 1m http://localhost/10.html
Running 1m test @ http://localhost/10.html
  1 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    88.85us  196.19us  10.05ms   98.07%
    Req/Sec   122.65k     3.44k  126.12k    95.01%
  7333995 requests in 1.00m, 1.36GB read
Requests/sec: 122031.02
Transfer/sec:     23.16MB
alx@asus5775:~/src/nginx/unit/actions$ wrk -t 1 -d 1m http://localhost/1k.html
Running 1m test @ http://localhost/1k.html
  1 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    91.55us  202.33us  12.67ms   97.53%
    Req/Sec   128.35k     2.07k  130.91k    82.20%
  7675379 requests in 1.00m, 8.53GB read
Requests/sec: 127710.17
Transfer/sec:    145.30MB
alx@asus5775:~/src/nginx/unit/actions$ wrk -t 1 -d 1m http://localhost/1M.html
Running 1m test @ http://localhost/1M.html
  1 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.51ms  573.02us  16.66ms   76.10%
    Req/Sec     4.16k    60.99     4.23k    95.17%
  248757 requests in 1.00m, 231.74GB read
Requests/sec:   4141.87
Transfer/sec:      3.86GB
alx@asus5775:~/src/nginx/unit/actions$ wrk -t 1 -d 1m http://localhost/100M.html
Running 1m test @ http://localhost/100M.html
  1 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   250.30ms  118.12ms   1.15s    76.93%
    Req/Sec    30.92     12.95    78.00     68.62%
  1847 requests in 1.00m, 210.22GB read
Requests/sec:     30.76
Transfer/sec:      3.50GB

NGINX:

alx@asus5775:~/src/nginx/unit/actions$ cat /etc/nginx/sites-enabled/default 
server {
	listen 80;
	gzip on;
	gzip_http_version 1.0;
	gzip_comp_level 1;
	gzip_min_length 1;
	gzip_types *;
	root /srv/www/unit/;
	index index.html;
	server_name _;
	location / {
		try_files $uri $uri/ =404;
	}
	access_log off;
	sendfile off;
}
alx@asus5775:~/src/nginx/unit/actions$ sudo systemctl restart nginx
alx@asus5775:~/src/nginx/unit/actions$ wrk -t 1 -d 1m -H 'Accept-Encoding: gzip' http://localhost/10.html
Running 1m test @ http://localhost/10.html
  1 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   503.27us    1.59ms  22.61ms   92.91%
    Req/Sec   109.23k     4.95k  114.12k    91.51%
  6531889 requests in 1.00m, 1.76GB read
Requests/sec: 108683.50
Transfer/sec:     29.95MB
alx@asus5775:~/src/nginx/unit/actions$ wrk -t 1 -d 1m -H 'Accept-Encoding: gzip' http://localhost/1k.html
Running 1m test @ http://localhost/1k.html
  1 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   157.91us  389.54us  16.12ms   98.81%
    Req/Sec    73.74k     4.43k   76.01k    97.33%
  4402820 requests in 1.00m, 4.28GB read
Requests/sec:  73379.97
Transfer/sec:     73.06MB
alx@asus5775:~/src/nginx/unit/actions$ wrk -t 1 -d 1m -H 'Accept-Encoding: gzip' http://localhost/1M.html
Running 1m test @ http://localhost/1M.html
  1 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   264.39ms    8.90ms 273.76ms   99.56%
    Req/Sec    37.73      4.19    40.00     77.33%
  2264 requests in 1.00m, 1.60GB read
Requests/sec:     37.73
Transfer/sec:     27.30MB
alx@asus5775:~/src/nginx/unit/actions$ wrk -t 1 -d 1m -H 'Accept-Encoding: gzip' http://localhost/100M.html
Running 1m test @ http://localhost/100M.html
  1 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     0.00us    0.00us   0.00us    -nan%
    Req/Sec     3.67      4.54    10.00     70.00%
  34 requests in 1.00m, 3.05GB read
  Socket errors: connect 0, read 0, write 0, timeout 34
Requests/sec:      0.57
Transfer/sec:     51.99MB
alx@asus5775:~/src/nginx/unit/actions$ wrk -t 1 -d 1m http://localhost/10.html
Running 1m test @ http://localhost/10.html
  1 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   119.14us  469.62us  16.34ms   98.55%
    Req/Sec   122.59k     6.96k  130.23k    94.01%
  7330615 requests in 1.00m, 1.68GB read
Requests/sec: 121973.24
Transfer/sec:     28.61MB
alx@asus5775:~/src/nginx/unit/actions$ wrk -t 1 -d 1m http://localhost/1k.html
Running 1m test @ http://localhost/1k.html
  1 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   101.18us  339.17us  18.28ms   98.96%
    Req/Sec   122.04k     5.66k  130.26k    88.69%
  7296767 requests in 1.00m, 8.43GB read
Requests/sec: 121411.11
Transfer/sec:    143.57MB
alx@asus5775:~/src/nginx/unit/actions$ wrk -t 1 -d 1m http://localhost/1M.html
Running 1m test @ http://localhost/1M.html
  1 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.52ms  620.71us  12.45ms   75.09%
    Req/Sec     4.19k    51.09     4.39k    85.17%
  250373 requests in 1.00m, 233.26GB read
Requests/sec:   4169.37
Transfer/sec:      3.88GB
alx@asus5775:~/src/nginx/unit/actions$ wrk -t 1 -d 1m http://localhost/100M.html
Running 1m test @ http://localhost/100M.html
  1 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   298.80ms  115.08ms 820.32ms   81.78%
    Req/Sec    31.05     15.82    80.00     67.74%
  1859 requests in 1.00m, 211.82GB read
Requests/sec:     30.94
Transfer/sec:      3.53GB

  req/s (%)        
  Nginx 0 Nginx 1 Unit 0 Unit 1 Unit 9
10B 123k 109k (-11%) 123k 130k (+6%) 131k (+7%)
1k 122k 74k (-39%) 128k 43k (-66%) 44k (-66%)
1M 4.2k 38 (-99%) 4.2k 121 (-97%) 122 (-97%)
100M 31 3.7 (-88%) 31 6.4 (-79%) 5.8 (-81%)

@ac000
Copy link
Member

ac000 commented Sep 5, 2023 via email

@alejandro-colomar
Copy link
Contributor Author

alejandro-colomar commented Sep 5, 2023 via email

@ac000
Copy link
Member

ac000 commented Sep 5, 2023 via email

When the content length is small, optimize zlib for low memory usage.
Conversely, when the content length is large, use a similar amount of
memory within zlib, as it will improve compression, and won't hurt
significantly.

Signed-off-by: Alejandro Colomar <[email protected]>
@alejandro-colomar
Copy link
Contributor Author

alejandro-colomar commented Sep 5, 2023

v36 changes:

  • Remove unnecessary +1 in optimization. This will reduce the size that zlib uses by half, and the performance is mostly not noticeable (and if any, it improves speeds slightly).

I'm satisfied with the optimizations, and can't improve it further from other things I've tried. Unless/until I get more ideas, I'm done.
If anyone has a setup that's not just localhost, and wants to test how this goes in real world connections, it would be interesting.

$ git range-diff ngx/master gh/actions actions
 1:  de56ec61 =  1:  de56ec61 Libunit: added macros that enhance type safety.
 2:  ecc27ab1 =  2:  ecc27ab1 HTTP: refactor: storing the body_handler as part of r.
 3:  4977d280 =  3:  4977d280 HTTP: filter: supporting a list of filter_handlers
 4:  6e164a36 =  4:  6e164a36 HTTP: compress: added "compress" action.
 5:  d3f4e09c =  5:  d3f4e09c Auto: zlib: compiling with zlib.
 6:  00801288 =  6:  00801288 HTTP: compress: added "encoding": "gzip".
 7:  7ecdc3d1 =  7:  7ecdc3d1 HTTP: compress: added configurable "level" of compression.
 8:  39db8691 =  8:  39db8691 Auto: zlib: added --no-zlib.
 9:  3dfab08a =  9:  3dfab08a String: added strto[u]l(3) variants for nxt_str_t.
10:  33480420 = 10:  33480420 HTTP: compress: added configurable threshold for Content-Length.
11:  77bda113 = 11:  77bda113 HTTP: compress: added "mime_types" rule.
12:  861bc494 = 12:  861bc494 HTTP: compress: checking $header_accept_encoding.
13:  04e8bdfd = 13:  04e8bdfd Libunit: added bit functions.
14:  8a0801c6 ! 14:  993533a1 HTTP: compress: gzip: calculating wbits and memlevel dynamically.
    @@ src/nxt_http_compress_gzip.c: nxt_http_compress_gzip_ctx(nxt_task_t *task, nxt_h
     +{
     +    int  w;
     +
    -+    w = nxt_bit_width_ul(content_length) + 1;
    ++    w = nxt_bit_width_ul(content_length);
     +
     +    return nxt_min(MAX_MEM_LEVEL, nxt_max(2, w - 9));
     +}
    @@ src/nxt_http_compress_gzip.c: nxt_http_compress_gzip_ctx(nxt_task_t *task, nxt_h
     +{
     +    int  w;
     +
    -+    w = nxt_bit_width_ul(content_length) + 1;
    ++    w = nxt_bit_width_ul(content_length);
     +
     +    return 16 + nxt_min(MAX_WBITS, nxt_max(9, w - 2));
     +}

@alejandro-colomar alejandro-colomar changed the title [WIP] gzip filter gzip filter Sep 5, 2023
@alejandro-colomar
Copy link
Contributor Author

alejandro-colomar commented Sep 5, 2023

BTW, we could add support for zlib compression, if that's something clients understand. curl(1) seemed to understand it. The thing is that the numbers were much faster when I was accidentally using zlib, and the implementation is just a few lines of code away, so it may be worth it.

Although it doesn't have any checksum, so maybe not worth for most.

@ac000
Copy link
Member

ac000 commented Sep 5, 2023 via email

@alejandro-colomar
Copy link
Contributor Author

Here's a stable way to pull this patch set.

$ git request-pull ngx/master git://www.alejandro-colomar.es/src/alx/nginx/unit.git gzip-v36
The following changes since commit 9b22b6957bc87b3df002d0bc691fdae6a20abdac:

  Fixed tag for 1.31.0 release. (2023-08-30 09:07:24 -0700)

are available in the Git repository at:

  git://www.alejandro-colomar.es/src/alx/nginx/unit.git tags/gzip-v36

for you to fetch changes up to 993533a112a36cdd7afe704565e11e0dda5845f8:

  HTTP: compress: gzip: calculating wbits and memlevel dynamically. (2023-09-05 04:36:56 +0200)

----------------------------------------------------------------
gzip filter for Unit

Better optimized for medium and large files than NGINX's gzip filter.  ;)

----------------------------------------------------------------
Alejandro Colomar (14):
      Libunit: added macros that enhance type safety.
      HTTP: refactor: storing the body_handler as part of r.
      HTTP: filter: supporting a list of filter_handlers
      HTTP: compress: added "compress" action.
      Auto: zlib: compiling with zlib.
      HTTP: compress: added "encoding": "gzip".
      HTTP: compress: added configurable "level" of compression.
      Auto: zlib: added --no-zlib.
      String: added strto[u]l(3) variants for nxt_str_t.
      HTTP: compress: added configurable threshold for Content-Length.
      HTTP: compress: added "mime_types" rule.
      HTTP: compress: checking $header_accept_encoding.
      Libunit: added bit functions.
      HTTP: compress: gzip: calculating wbits and memlevel dynamically.

 auto/make                    |   4 +
 auto/options                 |   4 +
 auto/sources                 |   2 +
 auto/summary                 |   1 +
 auto/zlib                    |  34 ++++++++
 configure                    |   5 +-
 src/nxt_clang.h              |  17 +---
 src/nxt_conf_validation.c    |  26 ++++++
 src/nxt_h1proto.c            |  12 ++-
 src/nxt_http.h               |  17 +++-
 src/nxt_http_compress.c      | 199 ++++++++++++++++++++++++++++++++++++++++++++++
 src/nxt_http_compress.h      |  50 ++++++++++++
 src/nxt_http_compress_gzip.c | 239 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/nxt_http_compress_gzip.h |  30 +++++++
 src/nxt_http_error.c         |   4 +-
 src/nxt_http_filter.h        |  53 +++++++++++++
 src/nxt_http_proxy.c         |   4 +-
 src/nxt_http_request.c       |  36 +++++++--
 src/nxt_http_return.c        |   2 +-
 src/nxt_http_route.c         |  13 +++
 src/nxt_http_static.c        |  10 +--
 src/nxt_router.c             |   3 +-
 src/nxt_string.c             |  36 +++++++++
 src/nxt_string.h             |  11 +++
 src/nxt_unit.h               |   1 +
 src/nxt_unit_bit.h           |  64 +++++++++++++++
 src/nxt_unit_cdefs.h         |  87 +++++++++++++++++++++
 27 files changed, 921 insertions(+), 43 deletions(-)
 create mode 100644 auto/zlib
 create mode 100644 src/nxt_http_compress.c
 create mode 100644 src/nxt_http_compress.h
 create mode 100644 src/nxt_http_compress_gzip.c
 create mode 100644 src/nxt_http_compress_gzip.h
 create mode 100644 src/nxt_http_filter.h
 create mode 100644 src/nxt_unit_bit.h
 create mode 100644 src/nxt_unit_cdefs.h

@alejandro-colomar alejandro-colomar closed this by deleting the head repository Sep 6, 2023
@razvanphp
Copy link

Why is this PR closed?

@alejandro-colomar
Copy link
Contributor Author

alejandro-colomar commented Oct 25, 2023

Hi @razvanphp,

I don't work anymore at NGINX/F5.

Since I don't agree with GitHub's abusive policies, I closed (removed) most of my repositories on GitHub, including the Unit one.

Nevertheless, AFAIK, this code will be merged to Unit eventually (after code review), and I support it in my personal git server, which you can access here https://www.alejandro-colomar.es/src/alx/nginx/unit.git/tag/?h=gzip-v36 if you want to get the code. I know that @ac000 will be fine pulling from my personal git server.

Maybe someone from the NGINX Unit team can tell about the status of the review.

About the status of this code, I'm very confident of its quality, so if you need it, you can build Unit with the patches. I'll rebase in a moment on top of the 1.31.1 release, so you can build it with gzip.

P.S.: If in the link above you're greeted by your browser with a warning, read here: https://www.alejandro-colomar.es/ssl and https://www.alejandro-colomar.es/random/trust.

@alejandro-colomar
Copy link
Contributor Author

alejandro-colomar commented Oct 25, 2023

v37:

Changes:

  • Rebase on top of 1.31.1
  • Signed-off-by
$ git range-diff 9b22b695..gzip-v36 ngx/master..gzip
 1:  de56ec61 !  1:  a084e2bc Libunit: added macros that enhance type safety.
    @@ Commit message
         Cc: Andrew Clayton <[email protected]>
         Cc: Zhidao Hong <[email protected]>
         Signed-off-by: Alejandro Colomar <[email protected]>
    +    Signed-off-by: Alejandro Colomar <[email protected]>
     
      ## auto/make ##
     @@ auto/make: libunit-install: $NXT_BUILD_DIR/lib/$NXT_LIB_UNIT_STATIC
 2:  ecc27ab1 !  2:  9be4b16f HTTP: refactor: storing the body_handler as part of r.
    @@ Commit message
         there is no body handler installed.
     
         Signed-off-by: Alejandro Colomar <[email protected]>
    +    Signed-off-by: Alejandro Colomar <[email protected]>
     
      ## src/nxt_h1proto.c ##
     @@ src/nxt_h1proto.c: static void nxt_h1p_request_body_read(nxt_task_t *task, nxt_http_request_t *r);
 3:  4977d280 !  3:  ddb7d61f HTTP: filter: supporting a list of filter_handlers
    @@ Commit message
         applied in a loop.
     
         Signed-off-by: Alejandro Colomar <[email protected]>
    +    Signed-off-by: Alejandro Colomar <[email protected]>
     
      ## src/nxt_http.h ##
     @@ src/nxt_http.h: struct nxt_http_request_s {
 4:  6e164a36 !  4:  fd4f4e4c HTTP: compress: added "compress" action.
    @@ Commit message
         the next commits, which will add gzip compression.
     
         Signed-off-by: Alejandro Colomar <[email protected]>
    +    Signed-off-by: Alejandro Colomar <[email protected]>
     
      ## auto/sources ##
     @@ auto/sources: NXT_LIB_SRCS=" \
 5:  d3f4e09c !  5:  2549de1f Auto: zlib: compiling with zlib.
    @@ Commit message
         Auto: zlib: compiling with zlib.
     
         Signed-off-by: Alejandro Colomar <[email protected]>
    +    Signed-off-by: Alejandro Colomar <[email protected]>
     
      ## auto/zlib (new) ##
     @@
 6:  00801288 !  6:  d05e2ab8 HTTP: compress: added "encoding": "gzip".
    @@ Commit message
         HTTP: compress: added "encoding": "gzip".
     
         Signed-off-by: Alejandro Colomar <[email protected]>
    +    Signed-off-by: Alejandro Colomar <[email protected]>
     
      ## auto/sources ##
     @@ auto/sources: NXT_LIB_SRCS=" \
 7:  7ecdc3d1 !  7:  0569065a HTTP: compress: added configurable "level" of compression.
    @@ Metadata
      ## Commit message ##
         HTTP: compress: added configurable "level" of compression.
     
    +    Signed-off-by: Alejandro Colomar <[email protected]>
    +    Signed-off-by: Alejandro Colomar <[email protected]>
    +
      ## src/nxt_conf_validation.c ##
     @@ src/nxt_conf_validation.c: static nxt_conf_vldt_object_t  nxt_conf_vldt_compress_members[] = {
          {
 8:  39db8691 !  8:  3630425f Auto: zlib: added --no-zlib.
    @@ Commit message
             HTTP: compress: gzip
     
         Signed-off-by: Alejandro Colomar <[email protected]>
    +    Signed-off-by: Alejandro Colomar <[email protected]>
     
      ## auto/options ##
     @@ auto/options: NXT_PCRE_LIB=
 9:  3dfab08a !  9:  e357f665 String: added strto[u]l(3) variants for nxt_str_t.
    @@ Commit message
         strtol(3), I called them like it.
     
         Signed-off-by: Alejandro Colomar <[email protected]>
    +    Signed-off-by: Alejandro Colomar <[email protected]>
     
      ## src/nxt_string.c ##
     @@
10:  33480420 ! 10:  d5906fc0 HTTP: compress: added configurable threshold for Content-Length.
    @@ Commit message
         is 20, as in NGINX.
     
         Signed-off-by: Alejandro Colomar <[email protected]>
    +    Signed-off-by: Alejandro Colomar <[email protected]>
     
      ## src/nxt_conf_validation.c ##
     @@ src/nxt_conf_validation.c: static nxt_conf_vldt_object_t  nxt_conf_vldt_compress_members[] = {
11:  77bda113 ! 11:  75e9535a HTTP: compress: added "mime_types" rule.
    @@ Commit message
         HTTP: compress: added "mime_types" rule.
     
         Signed-off-by: Alejandro Colomar <[email protected]>
    +    Signed-off-by: Alejandro Colomar <[email protected]>
     
      ## src/nxt_conf_validation.c ##
     @@ src/nxt_conf_validation.c: static nxt_conf_vldt_object_t  nxt_conf_vldt_compress_members[] = {
12:  861bc494 ! 12:  c2788b8a HTTP: compress: checking $header_accept_encoding.
    @@ Commit message
         HTTP: compress: checking $header_accept_encoding.
     
         Signed-off-by: Alejandro Colomar <[email protected]>
    +    Signed-off-by: Alejandro Colomar <[email protected]>
     
      ## src/nxt_http_compress.c ##
     @@
13:  04e8bdfd ! 13:  0313eff0 Libunit: added bit functions.
    @@ Commit message
         These are based on C23's <stdbit.h>.
     
         Signed-off-by: Alejandro Colomar <[email protected]>
    +    Signed-off-by: Alejandro Colomar <[email protected]>
     
      ## auto/make ##
     @@ auto/make: libunit-install: $NXT_BUILD_DIR/lib/$NXT_LIB_UNIT_STATIC
14:  993533a1 ! 14:  5a4e6732 HTTP: compress: gzip: calculating wbits and memlevel dynamically.
    @@ Commit message
         significantly.
     
         Signed-off-by: Alejandro Colomar <[email protected]>
    +    Signed-off-by: Alejandro Colomar <[email protected]>
     
      ## src/nxt_http_compress_gzip.c ##
     @@

Pull from here:

$ git request-pull ngx/master git://www.alejandro-colomar.es/src/alx/nginx/unit.git gzip-v37
The following changes since commit fb33ec86a3b6ca6a844dfa6980bb9e083094abec:

  Unit 1.31.1 release. (2023-10-19 11:47:22 +0100)

are available in the Git repository at:

  git://www.alejandro-colomar.es/src/alx/nginx/unit.git tags/gzip-v37

for you to fetch changes up to 5a4e673259b22418dfeb929a1e39ee40427cdd6e:

  HTTP: compress: gzip: calculating wbits and memlevel dynamically. (2023-10-25 13:38:57 +0200)

----------------------------------------------------------------
gzip filter for Unit

Better optimized for medium and large files than NGINX's gzip filter.  ;)

v37:

-  Rebase on top of '1.31.1'.
-  Signed-off-by: <[email protected]>

----------------------------------------------------------------
Alejandro Colomar (14):
      Libunit: added macros that enhance type safety.
      HTTP: refactor: storing the body_handler as part of r.
      HTTP: filter: supporting a list of filter_handlers
      HTTP: compress: added "compress" action.
      Auto: zlib: compiling with zlib.
      HTTP: compress: added "encoding": "gzip".
      HTTP: compress: added configurable "level" of compression.
      Auto: zlib: added --no-zlib.
      String: added strto[u]l(3) variants for nxt_str_t.
      HTTP: compress: added configurable threshold for Content-Length.
      HTTP: compress: added "mime_types" rule.
      HTTP: compress: checking $header_accept_encoding.
      Libunit: added bit functions.
      HTTP: compress: gzip: calculating wbits and memlevel dynamically.

 auto/make                    |   4 +
 auto/options                 |   4 +
 auto/sources                 |   2 +
 auto/summary                 |   1 +
 auto/zlib                    |  34 ++++++++
 configure                    |   5 +-
 src/nxt_clang.h              |  17 +---
 src/nxt_conf_validation.c    |  26 ++++++
 src/nxt_h1proto.c            |  12 ++-
 src/nxt_http.h               |  17 +++-
 src/nxt_http_compress.c      | 199 +++++++++++++++++++++++++++++++++++++++++++
 src/nxt_http_compress.h      |  50 +++++++++++
 src/nxt_http_compress_gzip.c | 239 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/nxt_http_compress_gzip.h |  30 +++++++
 src/nxt_http_error.c         |   4 +-
 src/nxt_http_filter.h        |  53 ++++++++++++
 src/nxt_http_proxy.c         |   4 +-
 src/nxt_http_request.c       |  36 ++++++--
 src/nxt_http_return.c        |   2 +-
 src/nxt_http_route.c         |  13 +++
 src/nxt_http_static.c        |  10 +--
 src/nxt_router.c             |   3 +-
 src/nxt_string.c             |  36 ++++++++
 src/nxt_string.h             |  11 +++
 src/nxt_unit.h               |   1 +
 src/nxt_unit_bit.h           |  64 ++++++++++++++
 src/nxt_unit_cdefs.h         |  87 +++++++++++++++++++
 27 files changed, 921 insertions(+), 43 deletions(-)
 create mode 100644 auto/zlib
 create mode 100644 src/nxt_http_compress.c
 create mode 100644 src/nxt_http_compress.h
 create mode 100644 src/nxt_http_compress_gzip.c
 create mode 100644 src/nxt_http_compress_gzip.h
 create mode 100644 src/nxt_http_filter.h
 create mode 100644 src/nxt_unit_bit.h
 create mode 100644 src/nxt_unit_cdefs.h

Also available via HTTPS:

  https://www.alejandro-colomar.es/src/alx/nginx/unit.git tags/gzip-v37

@alejandro-colomar
Copy link
Contributor Author

v38 changes:

  • Add nxt_strtoul_noneg(). strtoul(3) is bogus, as it silently accepts
    negative numbers and wraps them as positive numbers. Our wrapper
    does what one would expect strtoul(3) should have done.

  • Report errors in nxt_ustrtoul() exactly like strtou(3bsd) does. This
    reduces the chances of making mistakes using this function, as it's
    quite simple to use.

  • Use stpcpy(..., ""), instead of manually setting the terminating NUL.
    stpcpy(3) can be protected by _FORTIFY_SOURCE, which makes this copy
    safer, and also easier to read, IMO. See string_copying(7).

  • Update copyright.

$ git range-diff a084e2bc^ gzip-v37 gzip-v38
 1:  a084e2bc =  1:  a084e2bc Libunit: added macros that enhance type safety.
 2:  9be4b16f =  2:  9be4b16f HTTP: refactor: storing the body_handler as part of r.
 3:  ddb7d61f =  3:  ddb7d61f HTTP: filter: supporting a list of filter_handlers
 4:  fd4f4e4c =  4:  fd4f4e4c HTTP: compress: added "compress" action.
 5:  2549de1f =  5:  2549de1f Auto: zlib: compiling with zlib.
 6:  d05e2ab8 =  6:  d05e2ab8 HTTP: compress: added "encoding": "gzip".
 7:  0569065a =  7:  0569065a HTTP: compress: added configurable "level" of compression.
 8:  3630425f =  8:  3630425f Auto: zlib: added --no-zlib.
 9:  e357f665 <  -:  -------- String: added strto[u]l(3) variants for nxt_str_t.
 -:  -------- >  9:  13dedafc String: added nxt_strtoul_noneg().
 -:  -------- > 10:  22dc158a String: added nxt_atoul().
10:  d5906fc0 ! 11:  04e9f235 HTTP: compress: added configurable threshold for Content-Length.
    @@ Commit message
         content_length_threshold bytes, won't be compressed.  The default value
         is 20, as in NGINX.
     
    -    Signed-off-by: Alejandro Colomar <[email protected]>
         Signed-off-by: Alejandro Colomar <[email protected]>
     
      ## src/nxt_conf_validation.c ##
    @@ src/nxt_conf_validation.c: static nxt_conf_vldt_object_t  nxt_conf_vldt_compress
          NXT_CONF_VLDT_END
     
      ## src/nxt_http_compress.c ##
    +@@
    + 
    + #include "nxt_http_compress.h"
    + 
    ++#include <errno.h>
    + #include <stddef.h>
    + 
    + #include <nxt_unit_cdefs.h>
     @@ src/nxt_http_compress.c: static nxt_conf_map_t  nxt_http_compress_conf[] = {
              NXT_CONF_MAP_INT8,
              offsetof(nxt_http_compress_conf_t, level),
    @@ src/nxt_http_compress.c: nxt_http_compress_append_field(nxt_task_t *task, nxt_ht
     +nxt_http_compress_resp_content_length(nxt_http_response_t *resp)
     +{
     +    size_t     cl;
    -+    nxt_int_t  err;
     +    nxt_str_t  str;
     +
     +    if (resp->content_length_n != -1) {
    @@ src/nxt_http_compress.c: nxt_http_compress_append_field(nxt_task_t *task, nxt_ht
     +    str.length = resp->content_length->value_length;
     +    str.start = resp->content_length->value;
     +
    -+    cl = nxt_ustrtoul(&str, &err);
    -+    if (err == NXT_ERROR) {
    ++    errno = 0;
    ++    cl = nxt_atoul(&str);
    ++    if (errno != 0) {
     +        return -1;
     +    }
     +
11:  75e9535a = 12:  9ec5c601 HTTP: compress: added "mime_types" rule.
12:  c2788b8a = 13:  4d84fe7e HTTP: compress: checking $header_accept_encoding.
13:  0313eff0 = 14:  f9761247 Libunit: added bit functions.
14:  5a4e6732 = 15:  9479559d HTTP: compress: gzip: calculating wbits and memlevel dynamically.

Pull from here:

$ git request-pull ngx/master https://www.alejandro-colomar.es/src/alx/nginx/unit.git gzip-v38
warn: No match for commit 9479559dc08ab13adc4c60e198d5e4d9d289ee02 found at https://www.alejandro-colomar.es/src/alx/nginx/unit.git
warn: Are you sure you pushed 'gzip-v38' there?
The following changes since commit fb33ec86a3b6ca6a844dfa6980bb9e083094abec:

  Unit 1.31.1 release. (2023-10-19 11:47:22 +0100)

are available in the Git repository at:

  https://www.alejandro-colomar.es/src/alx/nginx/unit.git gzip-v38

for you to fetch changes up to 9479559dc08ab13adc4c60e198d5e4d9d289ee02:

  HTTP: compress: gzip: calculating wbits and memlevel dynamically. (2023-12-19 15:02:42 +0100)

----------------------------------------------------------------
gzip filter for Unit

Better optimized for medium and large files than NGINX's gzip filter.  ;)

v38:

-  Add nxt_strtoul_noneg().  strtoul(3) is bogus, as it silently accepts
   negative numbers and wraps them as positive numbers.  Our wrapper
   does what one would expect strtoul(3) should have done.

-  Report errors in nxt_ustrtoul() like strtou(3bsd) does.  This reduces
   the chances of making mistakes using this function, as it's quite
   simple to use.

   However, use errno to report them, instead of an int*, which makes it
   even simpler.  This converts the API in what atoi(3) should have
   been, if done right.  Thus, rename it to nxt_atoul().

-  Use stpcpy(..., ""), instead of manually setting the terminating NUL.
   stpcpy(3) can be protected by _FORTIFY_SOURCE, which makes this copy
   safer, and also easier to read, IMO.  See string_copying(7).

-  Update copyright.

v37:

-  Rebase on top of '1.31.1'.
-  Signed-off-by: <[email protected]>

----------------------------------------------------------------
Alejandro Colomar (15):
      Libunit: added macros that enhance type safety.
      HTTP: refactor: storing the body_handler as part of r.
      HTTP: filter: supporting a list of filter_handlers
      HTTP: compress: added "compress" action.
      Auto: zlib: compiling with zlib.
      HTTP: compress: added "encoding": "gzip".
      HTTP: compress: added configurable "level" of compression.
      Auto: zlib: added --no-zlib.
      String: added nxt_strtoul_noneg().
      String: added nxt_atoul().
      HTTP: compress: added configurable threshold for Content-Length.
      HTTP: compress: added "mime_types" rule.
      HTTP: compress: checking $header_accept_encoding.
      Libunit: added bit functions.
      HTTP: compress: gzip: calculating wbits and memlevel dynamically.

 auto/make                    |   4 +
 auto/options                 |   4 +
 auto/sources                 |   2 +
 auto/summary                 |   1 +
 auto/zlib                    |  34 ++++++
 configure                    |   5 +-
 src/nxt_clang.h              |  17 +--
 src/nxt_conf_validation.c    |  26 +++++
 src/nxt_h1proto.c            |  12 +--
 src/nxt_http.h               |  17 ++-
 src/nxt_http_compress.c      | 200 ++++++++++++++++++++++++++++++++++++
 src/nxt_http_compress.h      |  50 +++++++++
 src/nxt_http_compress_gzip.c | 239 +++++++++++++++++++++++++++++++++++++++++++
 src/nxt_http_compress_gzip.h |  30 ++++++
 src/nxt_http_error.c         |   4 +-
 src/nxt_http_filter.h        |  53 ++++++++++
 src/nxt_http_proxy.c         |   4 +-
 src/nxt_http_request.c       |  36 +++++--
 src/nxt_http_return.c        |   2 +-
 src/nxt_http_route.c         |  13 +++
 src/nxt_http_static.c        |  10 +-
 src/nxt_router.c             |   3 +-
 src/nxt_string.c             |  57 +++++++++++
 src/nxt_string.h             |   3 +
 src/nxt_unit.h               |   1 +
 src/nxt_unit_bit.h           |  64 ++++++++++++
 src/nxt_unit_cdefs.h         |  87 ++++++++++++++++
 27 files changed, 935 insertions(+), 43 deletions(-)
 create mode 100644 auto/zlib
 create mode 100644 src/nxt_http_compress.c
 create mode 100644 src/nxt_http_compress.h
 create mode 100644 src/nxt_http_compress_gzip.c
 create mode 100644 src/nxt_http_compress_gzip.h
 create mode 100644 src/nxt_http_filter.h
 create mode 100644 src/nxt_unit_bit.h
 create mode 100644 src/nxt_unit_cdefs.h

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants