diff options
Diffstat (limited to 'nginx/t')
-rw-r--r-- | nginx/t/js_fetch.t | 31 | ||||
-rw-r--r-- | nginx/t/js_fetch_https.t | 10 | ||||
-rw-r--r-- | nginx/t/js_fetch_objects.t | 10 | ||||
-rw-r--r-- | nginx/t/js_fetch_resolver.t | 10 | ||||
-rw-r--r-- | nginx/t/js_fetch_timeout.t | 10 | ||||
-rw-r--r-- | nginx/t/js_fetch_verify.t | 10 | ||||
-rw-r--r-- | nginx/t/js_internal_redirect.t | 29 | ||||
-rw-r--r-- | nginx/t/js_periodic.t | 2 | ||||
-rw-r--r-- | nginx/t/js_periodic_fetch.t | 19 | ||||
-rw-r--r-- | nginx/t/js_shared_dict.t | 10 | ||||
-rw-r--r-- | nginx/t/js_shared_dict_state.t | 256 | ||||
-rw-r--r-- | nginx/t/stream_js_fetch.t | 10 | ||||
-rw-r--r-- | nginx/t/stream_js_fetch_https.t | 10 | ||||
-rw-r--r-- | nginx/t/stream_js_fetch_init.t | 10 | ||||
-rw-r--r-- | nginx/t/stream_js_periodic_fetch.t | 10 | ||||
-rw-r--r-- | nginx/t/stream_js_shared_dict.t | 10 | ||||
-rw-r--r-- | nginx/t/stream_js_shared_dict_state.t | 137 |
17 files changed, 459 insertions, 125 deletions
diff --git a/nginx/t/js_fetch.t b/nginx/t/js_fetch.t index 7ee1a602..76d9238d 100644 --- a/nginx/t/js_fetch.t +++ b/nginx/t/js_fetch.t @@ -52,10 +52,6 @@ http { js_content test.njs; } - location /engine { - js_content test.engine; - } - location /broken { js_content test.broken; } @@ -68,6 +64,10 @@ http { js_content test.body; } + location /body_content_length { + js_content test.body_content_length; + } + location /body_special { js_content test.body_special; } @@ -138,10 +138,6 @@ $t->write_file('test.js', <<EOF); r.return(200, njs.version); } - function engine(r) { - r.return(200, njs.engine); - } - function body(r) { var loc = r.args.loc; var getter = r.args.getter; @@ -164,6 +160,13 @@ $t->write_file('test.js', <<EOF); .catch(e => r.return(501, e.message)) } + async function body_content_length(r) { + let resp = await ngx.fetch(`http://127.0.0.1:$p0/loc`, + {headers: {'Content-Length': '100'}, + body: "CONTENT-BODY"}); + r.return(resp.status); + } + function property(r) { var opts = {headers:{}}; @@ -408,12 +411,12 @@ $t->write_file('test.js', <<EOF); export default {njs: test_njs, body, broken, broken_response, body_special, chain, chunked_ok, chunked_fail, header, header_iter, - host_header, multi, loc, property, engine}; + host_header, multi, loc, property, body_content_length }; EOF $t->try_run('no njs.fetch'); -$t->plan(37); +$t->plan(38); $t->run_daemon(\&http_daemon, port(8082)); $t->waitforsocket('127.0.0.1:' . port(8082)); @@ -516,6 +519,14 @@ like(http_get('/body_special?loc=head/large&method=HEAD'), qr/200 OK.*<empty>$/s, 'fetch head method large content-length'); } +TODO: { +local $TODO = 'not yet' unless has_version('0.9.1'); + +like(http_get('/body_content_length'), qr/200 OK/s, + 'fetch body content-length'); + +} + ############################################################################### sub has_version { diff --git a/nginx/t/js_fetch_https.t b/nginx/t/js_fetch_https.t index 8ede1048..42b5acbb 100644 --- a/nginx/t/js_fetch_https.t +++ b/nginx/t/js_fetch_https.t @@ -48,10 +48,6 @@ http { js_content test.njs; } - location /engine { - js_content test.engine; - } - location /https { js_content test.https; } @@ -106,10 +102,6 @@ $t->write_file('test.js', <<EOF); r.return(200, njs.version); } - function engine(r) { - r.return(200, njs.engine); - } - function https(r) { var url = `https://\${r.args.domain}:$p1/loc`; var opt = {}; @@ -124,7 +116,7 @@ $t->write_file('test.js', <<EOF); .catch(e => r.return(501, e.message)) } - export default {njs: test_njs, https, engine}; + export default {njs: test_njs, https}; EOF my $d = $t->testdir(); diff --git a/nginx/t/js_fetch_objects.t b/nginx/t/js_fetch_objects.t index bc5cc7ed..c9d04c49 100644 --- a/nginx/t/js_fetch_objects.t +++ b/nginx/t/js_fetch_objects.t @@ -45,10 +45,6 @@ http { js_content test.njs; } - location /engine { - js_content test.engine; - } - location /headers { js_content test.headers; } @@ -92,10 +88,6 @@ $t->write_file('test.js', <<EOF); r.return(200, njs.version); } - function engine(r) { - r.return(200, njs.engine); - } - function header(r) { r.return(200, r.headersIn.a); } @@ -528,7 +520,7 @@ $t->write_file('test.js', <<EOF); run(r, tests); } - export default {njs: test_njs, engine, body, headers, request, response, + export default {njs: test_njs, body, headers, request, response, fetch, fetch_multi_header}; EOF diff --git a/nginx/t/js_fetch_resolver.t b/nginx/t/js_fetch_resolver.t index 031ff43c..67680283 100644 --- a/nginx/t/js_fetch_resolver.t +++ b/nginx/t/js_fetch_resolver.t @@ -50,10 +50,6 @@ http { js_content test.njs; } - location /engine { - js_content test.engine; - } - location /dns { js_content test.dns; @@ -108,10 +104,6 @@ $t->write_file('test.js', <<EOF); r.return(200, njs.version); } - function engine(r) { - r.return(200, njs.engine); - } - const p0 = $p0; const p1 = $p1; @@ -141,7 +133,7 @@ $t->write_file('test.js', <<EOF); r.return(c, `\${v.host}:\${v.request_method}:\${foo}:\${bar}:\${body}`); } - export default {njs: test_njs, dns, loc, engine}; + export default {njs: test_njs, dns, loc}; EOF $t->try_run('no njs.fetch'); diff --git a/nginx/t/js_fetch_timeout.t b/nginx/t/js_fetch_timeout.t index ab1ba24a..2ca1510f 100644 --- a/nginx/t/js_fetch_timeout.t +++ b/nginx/t/js_fetch_timeout.t @@ -47,10 +47,6 @@ http { js_content test.njs; } - location /engine { - js_content test.engine; - } - location /normal_timeout { js_content test.timeout_test; } @@ -84,10 +80,6 @@ $t->write_file('test.js', <<EOF); r.return(200, njs.version); } - function engine(r) { - r.return(200, njs.engine); - } - async function timeout_test(r) { let rs = await Promise.allSettled([ 'http://127.0.0.1:$p1/normal_reply', @@ -110,7 +102,7 @@ $t->write_file('test.js', <<EOF); setTimeout((r) => { r.return(200); }, 250, r, 0); } - export default {njs: test_njs, engine, timeout_test, normal_reply, + export default {njs: test_njs, timeout_test, normal_reply, delayed_reply}; EOF diff --git a/nginx/t/js_fetch_verify.t b/nginx/t/js_fetch_verify.t index f98b4d8c..8b691a74 100644 --- a/nginx/t/js_fetch_verify.t +++ b/nginx/t/js_fetch_verify.t @@ -48,10 +48,6 @@ http { js_content test.njs; } - location /engine { - js_content test.engine; - } - location /https { js_content test.https; } @@ -80,10 +76,6 @@ $t->write_file('test.js', <<EOF); r.return(200, njs.version); } - function engine(r) { - r.return(200, njs.engine); - } - function https(r) { ngx.fetch(`https://example.com:$p1/loc`) .then(reply => reply.text()) @@ -91,7 +83,7 @@ $t->write_file('test.js', <<EOF); .catch(e => r.return(501, e.message)); } - export default {njs: test_njs, engine, https}; + export default {njs: test_njs, https}; EOF $t->write_file('openssl.conf', <<EOF); diff --git a/nginx/t/js_internal_redirect.t b/nginx/t/js_internal_redirect.t index abfe79f9..721113bb 100644 --- a/nginx/t/js_internal_redirect.t +++ b/nginx/t/js_internal_redirect.t @@ -11,6 +11,7 @@ use warnings; use strict; use Test::More; +use Socket qw/ CRLF /; BEGIN { use FindBin; chdir($FindBin::Bin); } @@ -54,6 +55,10 @@ http { return 200 redirect$arg_b; } + location /destroyed_ctx { + js_content test.destroyed_ctx; + } + location @named { return 200 named; } @@ -87,7 +92,16 @@ $t->write_file('test.js', <<EOF); } } - export default {njs:test_njs, redirect}; + function destroyed_ctx(r) { + try { + r.return(200); + + } catch (e) { + r.internalRedirect("\@sub"); + } + } + + export default {njs:test_njs, redirect, destroyed_ctx}; EOF @@ -103,5 +117,18 @@ like(http_get('/test?unsafe=1'), qr/500 Internal Server/s, 'unsafe redirect'); like(http_get('/test?quoted=1'), qr/200 .*redirect/s, 'quoted redirect'); +get('/destroyed_ctx', 'If-Match: tt'); ############################################################################### + +sub get { + my ($url, @headers) = @_; + return http( + "GET $url HTTP/1.1" . CRLF . + 'Host: localhost' . CRLF . + 'Connection: close' . CRLF . + join(CRLF, @headers) . CRLF . CRLF + ); +} + +################################################################################ diff --git a/nginx/t/js_periodic.t b/nginx/t/js_periodic.t index d6868935..7e134588 100644 --- a/nginx/t/js_periodic.t +++ b/nginx/t/js_periodic.t @@ -56,7 +56,7 @@ http { server_name localhost; location @periodic { - js_periodic test.tick interval=30ms jitter=1ms; + js_periodic test.tick interval=20ms jitter=1ms; js_periodic test.timer interval=1s worker_affinity=all; js_periodic test.overrun interval=30ms; js_periodic test.affinity interval=50ms worker_affinity=0101; diff --git a/nginx/t/js_periodic_fetch.t b/nginx/t/js_periodic_fetch.t index 0231b662..39385132 100644 --- a/nginx/t/js_periodic_fetch.t +++ b/nginx/t/js_periodic_fetch.t @@ -54,10 +54,6 @@ http { js_periodic test.fetch_exception interval=1s; } - location /engine { - js_content test.engine; - } - location /fetch_ok { return 200 'ok'; } @@ -81,10 +77,6 @@ EOF my $p0 = port(8080); $t->write_file('test.js', <<EOF); - function engine(r) { - r.return(200, njs.engine); - } - async function fetch() { let reply = await ngx.fetch('http://127.0.0.1:$p0/fetch_ok'); let body = await reply.text(); @@ -107,16 +99,15 @@ $t->write_file('test.js', <<EOF); } function test_fetch(r) { - r.return(200, ngx.shared.strings.get('fetch').startsWith('okok')); + r.return(200, ngx.shared.strings.get('fetch')); } function test_multiple_fetches(r) { - r.return(200, ngx.shared.strings.get('multiple_fetches') - .startsWith('ok\@foo')); + r.return(200, ngx.shared.strings.get('multiple_fetches')); } export default { fetch, fetch_exception, multiple_fetches, test_fetch, - test_multiple_fetches, engine }; + test_multiple_fetches }; EOF $t->try_run('no js_periodic with fetch'); @@ -127,8 +118,8 @@ $t->plan(3); select undef, undef, undef, 0.1; -like(http_get('/test_fetch'), qr/true/, 'periodic fetch test'); -like(http_get('/test_multiple_fetches'), qr/true/, 'multiple fetch test'); +like(http_get('/test_fetch'), qr/(ok)+/, 'periodic fetch test'); +like(http_get('/test_multiple_fetches'), qr/ok\@foo/, 'multiple fetch test'); $t->stop(); diff --git a/nginx/t/js_shared_dict.t b/nginx/t/js_shared_dict.t index 8be2831f..b27a33ef 100644 --- a/nginx/t/js_shared_dict.t +++ b/nginx/t/js_shared_dict.t @@ -52,10 +52,6 @@ http { js_content test.njs; } - location /engine { - js_content test.engine; - } - location /add { js_content test.add; } @@ -141,10 +137,6 @@ $t->write_file('test.js', <<'EOF'); r.return(200, njs.version); } - function engine(r) { - r.return(200, njs.engine); - } - function convertToValue(dict, v) { if (dict.type == 'number') { return parseInt(v); @@ -337,7 +329,7 @@ $t->write_file('test.js', <<'EOF'); export default { add, capacity, chain, clear, del, free_space, get, has, incr, items, keys, name, njs: test_njs, pop, replace, set, - set_clear, size, zones, engine, overflow }; + set_clear, size, zones, overflow }; EOF $t->try_run('no js_shared_dict_zone'); diff --git a/nginx/t/js_shared_dict_state.t b/nginx/t/js_shared_dict_state.t new file mode 100644 index 00000000..32eef948 --- /dev/null +++ b/nginx/t/js_shared_dict_state.t @@ -0,0 +1,256 @@ +#!/usr/bin/perl + +# (C) Dmitry Volyntsev +# (C) Nginx, Inc. + +# Tests for js_shared_dict_zone directive, state= parameter. + +############################################################################### + +use warnings; +use strict; + +use Test::More; +use Socket qw/ CRLF /; + +BEGIN { use FindBin; chdir($FindBin::Bin); } + +use lib 'lib'; +use Test::Nginx; + +############################################################################### + +select STDERR; $| = 1; +select STDOUT; $| = 1; + +eval { require JSON::PP; }; +plan(skip_all => "JSON::PP not installed") if $@; + +my $t = Test::Nginx->new()->has(qw/http/) + ->write_file_expand('nginx.conf', <<'EOF'); + +%%TEST_GLOBALS%% + +daemon off; + +events { +} + +http { + %%TEST_GLOBALS_HTTP%% + + js_import test.js; + + js_shared_dict_zone zone=bar:64k type=string state=bar.json; + js_shared_dict_zone zone=waka:32k timeout=1000s type=number state=waka.json; + + server { + listen 127.0.0.1:8080; + server_name localhost; + + location /add { + js_content test.add; + } + + location /clear { + js_content test.clear; + } + + location /delete { + js_content test.del; + } + + location /get { + js_content test.get; + } + + location /incr { + js_content test.incr; + } + + location /pop { + js_content test.pop; + } + + location /set { + js_content test.set; + } + } +} + +EOF + +$t->write_file('bar.json', <<EOF); +{"waka":{"value":"foo","expire":0}, + "bar": { "value" :"\\u0061\\u0062\\u0063"}, +"FOO \\n": { "value" : "BAZ", "unexpected_str": "u\\r" }, + "X": { "valu\\u0065" : "\\n" , "unexpected_num": 23.1 } , + "\\u0061\\u0062\\u0063": { "value" : "def" } , +} +EOF + +$t->write_file('test.js', <<'EOF'); + function convertToValue(dict, v) { + if (dict.type == 'number') { + return parseInt(v); + + } else if (v == 'empty') { + v = ''; + } + + return v; + } + + function add(r) { + var dict = ngx.shared[r.args.dict]; + var value = convertToValue(dict, r.args.value); + + if (r.args.timeout) { + var timeout = Number(r.args.timeout); + r.return(200, dict.add(r.args.key, value, timeout)); + + } else { + r.return(200, dict.add(r.args.key, value)); + } + } + + function clear(r) { + var dict = ngx.shared[r.args.dict]; + var result = dict.clear(); + r.return(200, result === undefined ? 'undefined' : result); + } + + function del(r) { + var dict = ngx.shared[r.args.dict]; + r.return(200, dict.delete(r.args.key)); + } + + function get(r) { + var dict = ngx.shared[r.args.dict]; + var val = dict.get(r.args.key); + + if (val == '') { + val = 'empty'; + + } else if (val === undefined) { + val = 'undefined'; + } + + r.return(200, val); + } + + function incr(r) { + var dict = ngx.shared[r.args.dict]; + var def = r.args.def ? parseInt(r.args.def) : 0; + + if (r.args.timeout) { + var timeout = Number(r.args.timeout); + var val = dict.incr(r.args.key, parseInt(r.args.by), def, timeout); + r.return(200, val); + + } else { + var val = dict.incr(r.args.key, parseInt(r.args.by), def); + r.return(200, val); + } + } + + function pop(r) { + var dict = ngx.shared[r.args.dict]; + var val = dict.pop(r.args.key); + if (val == '') { + val = 'empty'; + + } else if (val === undefined) { + val = 'undefined'; + } + + r.return(200, val); + } + + function set(r) { + var dict = ngx.shared[r.args.dict]; + var value = convertToValue(dict, r.args.value); + + if (r.args.timeout) { + var timeout = Number(r.args.timeout); + r.return(200, dict.set(r.args.key, value, timeout) === dict); + + } else { + r.return(200, dict.set(r.args.key, value) === dict); + } + } + + export default { add, clear, del, get, incr, pop, set }; +EOF + +$t->try_run('no js_shared_dict_zone with state=')->plan(11); + +############################################################################### + +like(http_get('/get?dict=bar&key=waka'), qr/foo/, 'get bar.waka'); +like(http_get('/get?dict=bar&key=bar'), qr/abc/, 'get bar.bar'); +like(http_get('/get?dict=bar&key=FOO%20%0A'), qr/BAZ/, 'get bar["FOO \\n"]'); +like(http_get('/get?dict=bar&key=abc'), qr/def/, 'get bar.abc'); + +http_get('/set?dict=bar&key=waka&value=foo2'); +http_get('/delete?dict=bar&key=bar'); + +http_get('/set?dict=waka&key=foo&value=42'); + +select undef, undef, undef, 1.1; + +$t->reload(); + +my $bar_state = read_state($t, 'bar.json'); +my $waka_state = read_state($t, 'waka.json'); + +is($bar_state->{waka}->{value}, 'foo2', 'get bar.waka from state'); +is($bar_state->{bar}, undef, 'no bar.bar in state'); +is($waka_state->{foo}->{value}, '42', 'get waka.foo from state'); +like($waka_state->{foo}->{expire}, qr/^\d+$/, 'waka.foo expire'); + +http_get('/pop?dict=bar&key=FOO%20%0A'); + +http_get('/incr?dict=waka&key=foo&by=1'); + +select undef, undef, undef, 1.1; + +$bar_state = read_state($t, 'bar.json'); +$waka_state = read_state($t, 'waka.json'); + +is($bar_state->{'FOO \\n'}, undef, 'no bar.FOO \\n in state'); +is($waka_state->{foo}->{value}, '43', 'get waka.foo from state'); + +http_get('/clear?dict=bar'); + +select undef, undef, undef, 1.1; + +$bar_state = read_state($t, 'bar.json'); + +is($bar_state->{waka}, undef, 'no bar.waka in state'); + +############################################################################### + +sub decode_json { + my $json; + eval { $json = JSON::PP::decode_json(shift) }; + + if ($@) { + return "<failed to parse JSON>"; + } + + return $json; +} + +sub read_state { + my ($self, $file) = @_; + my $json = $self->read_file($file); + + if ($json) { + $json = decode_json($json); + } + + return $json; +} + +############################################################################### diff --git a/nginx/t/stream_js_fetch.t b/nginx/t/stream_js_fetch.t index 9a42ae29..cb87eec7 100644 --- a/nginx/t/stream_js_fetch.t +++ b/nginx/t/stream_js_fetch.t @@ -46,10 +46,6 @@ http { js_content test.njs; } - location /engine { - js_content test.engine; - } - location /validate { js_content test.validate; } @@ -103,10 +99,6 @@ $t->write_file('test.js', <<EOF); r.return(200, njs.version); } - function engine(r) { - r.return(200, njs.engine); - } - function validate(r) { r.return((r.requestText == 'QZ') ? 200 : 403); } @@ -166,7 +158,7 @@ $t->write_file('test.js', <<EOF); } export default {njs: test_njs, validate, preread_verify, filter_verify, - access_ok, access_nok, engine}; + access_ok, access_nok}; EOF $t->try_run('no stream njs available'); diff --git a/nginx/t/stream_js_fetch_https.t b/nginx/t/stream_js_fetch_https.t index 987a896a..f397ea70 100644 --- a/nginx/t/stream_js_fetch_https.t +++ b/nginx/t/stream_js_fetch_https.t @@ -47,10 +47,6 @@ http { location /njs { js_content test.njs; } - - location /engine { - js_content test.engine; - } } server { @@ -163,10 +159,6 @@ $t->write_file('test.js', <<EOF); r.return(200, njs.version); } - function engine(r) { - r.return(200, njs.engine); - } - function preread(s) { s.on('upload', function (data, flags) { if (data.startsWith('GO')) { @@ -201,7 +193,7 @@ $t->write_file('test.js', <<EOF); (r.status == 200) ? s.allow(): s.deny(); } - export default {njs: test_njs, engine, preread, access_ok, access_nok}; + export default {njs: test_njs, preread, access_ok, access_nok}; EOF my $d = $t->testdir(); diff --git a/nginx/t/stream_js_fetch_init.t b/nginx/t/stream_js_fetch_init.t index f48b9d5e..3980a9ee 100644 --- a/nginx/t/stream_js_fetch_init.t +++ b/nginx/t/stream_js_fetch_init.t @@ -58,10 +58,6 @@ http { js_content test.njs; } - location /engine { - js_content test.engine; - } - location /success { return 200; } @@ -77,17 +73,13 @@ $t->write_file('test.js', <<EOF); r.return(200, njs.version); } - function engine(r) { - r.return(200, njs.engine); - } - async function access_ok(s) { let reply = await ngx.fetch('http://127.0.0.1:$p/success'); (reply.status == 200) ? s.allow(): s.deny(); } - export default {njs: test_njs, engine, access_ok}; + export default {njs: test_njs, access_ok}; EOF $t->try_run('no stream njs available'); diff --git a/nginx/t/stream_js_periodic_fetch.t b/nginx/t/stream_js_periodic_fetch.t index 60599423..4ebec96e 100644 --- a/nginx/t/stream_js_periodic_fetch.t +++ b/nginx/t/stream_js_periodic_fetch.t @@ -67,10 +67,6 @@ http { listen 127.0.0.1:8080; server_name localhost; - location /engine { - js_content test.engine; - } - location /fetch_ok { return 200 'ok'; } @@ -86,10 +82,6 @@ EOF my $p1 = port(8080); $t->write_file('test.js', <<EOF); - function engine(r) { - r.return(200, njs.engine); - } - async function fetch() { let reply = await ngx.fetch('http://127.0.0.1:$p1/fetch_ok'); let body = await reply.text(); @@ -142,7 +134,7 @@ $t->write_file('test.js', <<EOF); }); } - export default { engine, fetch, fetch_exception, test, multiple_fetches }; + export default { fetch, fetch_exception, test, multiple_fetches }; EOF $t->run_daemon(\&stream_daemon, port(8090)); diff --git a/nginx/t/stream_js_shared_dict.t b/nginx/t/stream_js_shared_dict.t index 915cc40b..0435033d 100644 --- a/nginx/t/stream_js_shared_dict.t +++ b/nginx/t/stream_js_shared_dict.t @@ -43,10 +43,6 @@ http { location / { return 200; } - - location /engine { - js_content test.engine; - } } } @@ -75,10 +71,6 @@ EOF $t->write_file('test.js', <<EOF); import qs from 'querystring'; - function engine(r) { - r.return(200, 'engine'); - } - function preread_verify(s) { var collect = Buffer.from([]); @@ -121,7 +113,7 @@ $t->write_file('test.js', <<EOF); }); } - export default { engine, preread_verify, control_access }; + export default { preread_verify, control_access }; EOF diff --git a/nginx/t/stream_js_shared_dict_state.t b/nginx/t/stream_js_shared_dict_state.t new file mode 100644 index 00000000..c2edb63e --- /dev/null +++ b/nginx/t/stream_js_shared_dict_state.t @@ -0,0 +1,137 @@ +#!/usr/bin/perl + +# (C) Dmitry Volyntsev +# (C) Nginx, Inc. + +# Tests for js_shared_dict_zone directive, state= parameter. + +############################################################################### + +use warnings; +use strict; + +use Test::More; + +BEGIN { use FindBin; chdir($FindBin::Bin); } + +use lib 'lib'; +use Test::Nginx; +use Test::Nginx::Stream qw/ stream /; + +############################################################################### + +select STDERR; $| = 1; +select STDOUT; $| = 1; + +my $t = Test::Nginx->new()->has(qw/stream/) + ->write_file_expand('nginx.conf', <<'EOF'); + +%%TEST_GLOBALS%% + +daemon off; + +events { +} + +stream { + %%TEST_GLOBALS_STREAM%% + + js_import test.js; + + js_shared_dict_zone zone=foo:32k state=foo.json; + + server { + listen 127.0.0.1:8081; + js_preread test.preread_verify; + proxy_pass 127.0.0.1:8090; + } +} + +EOF + +$t->write_file('foo.json', <<EOF); +{"QZ":{"value":"1"},"QQ":{"value":"1"}} +EOF + +$t->write_file('test.js', <<EOF); + function preread_verify(s) { + var collect = Buffer.from([]); + + s.on('upstream', function (data, flags) { + collect = Buffer.concat([collect, data]); + + if (collect.length >= 4 && collect.readUInt16BE(0) == 0xabcd) { + let id = collect.slice(2,4); + + ngx.shared.foo.get(id) ? s.done(): s.deny(); + + } else if (collect.length) { + s.deny(); + } + }); + } + + export default { preread_verify }; + +EOF + +$t->try_run('no js_shared_dict_zone with state='); + +$t->plan(2); + +$t->run_daemon(\&stream_daemon, port(8090)); +$t->waitforsocket('127.0.0.1:' . port(8090)); + +############################################################################### + +is(stream('127.0.0.1:' . port(8081))->io("\xAB\xCDQY##"), "", + 'access failed, QY is not in the shared dict'); +is(stream('127.0.0.1:' . port(8081))->io("\xAB\xCDQZ##"), "\xAB\xCDQZ##", + 'access granted'); + +############################################################################### + +sub stream_daemon { + my $server = IO::Socket::INET->new( + Proto => 'tcp', + LocalAddr => '127.0.0.1:' . port(8090), + Listen => 5, + Reuse => 1 + ) + or die "Can't create listening socket: $!\n"; + + local $SIG{PIPE} = 'IGNORE'; + + while (my $client = $server->accept()) { + $client->autoflush(1); + + log2c("(new connection $client)"); + + $client->sysread(my $buffer, 65536) or next; + + log2i("$client $buffer"); + + log2o("$client $buffer"); + + $client->syswrite($buffer); + + close $client; + } +} + +sub log2i { Test::Nginx::log_core('|| <<', @_); } +sub log2o { Test::Nginx::log_core('|| >>', @_); } +sub log2c { Test::Nginx::log_core('||', @_); } + +sub get { + my ($url, %extra) = @_; + + my $s = IO::Socket::INET->new( + Proto => 'tcp', + PeerAddr => '127.0.0.1:' . port(8082) + ) or die "Can't connect to nginx: $!\n"; + + return http_get($url, socket => $s); +} + +############################################################################### |