[njs] Stream js: js_access, js_preread, js_filter.
Roman Arutyunyan
arut at nginx.com
Wed Sep 28 16:59:23 UTC 2016
details: http://hg.nginx.org/njs/rev/322359ec0913
branches:
changeset: 185:322359ec0913
user: Roman Arutyunyan <arut at nginx.com>
date: Wed Sep 28 19:52:05 2016 +0300
description:
Stream js: js_access, js_preread, js_filter.
diffstat:
README | 100 +++++++-
nginx/ngx_stream_js_module.c | 550 ++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 642 insertions(+), 8 deletions(-)
diffs (792 lines):
diff -r cfa17c3e25da -r 322359ec0913 README
--- a/README Mon Sep 26 18:41:57 2016 +0300
+++ b/README Wed Sep 28 19:52:05 2016 +0300
@@ -144,8 +144,16 @@ Each Stream JavaScript handler receives
The following properties are available in the session object:
- remoteAddress
+ - eof
+ - fromUpstream
+ - buffer
- variables{}
- log()
+ - OK
+ - DECLINED
+ - AGAIN
+ - ERROR
+ - ABORT
Example nginx.conf:
@@ -167,22 +175,60 @@ Example nginx.conf:
server {
listen 8000;
+ # preread data with qux()
+ js_preread qux;
+
# create $foo and $bar variables and set JavaScript
# functions foo() and bar() from the included JavaScript
# file as their handlers
js_set $foo foo;
js_set $bar bar;
- return $foo-$bar;
+ # echo-server: return preread data
+ return foo;
+ }
+
+ server {
+ listen 8001;
+
+ # check access in xyz()
+ js_access xyz;
+
+ proxy_pass 127.0.0.1:9000;
+
+ # add JavaScript filter baz() from the included
+ # JavaScript file
+ js_filter baz;
+ }
+ }
+
+ http {
+ server {
+ listen 9000;
+ location / {
+ return 200 $http_foo\n;
+ }
}
}
stream.js:
+ var req = '';
+ var matched = 0;
+ var line = '';
+
+ function qux(s) {
+ n = s.buffer.indexOf('\n');
+ if (n == -1) {
+ return s.AGAIN;
+ }
+
+ line = s.buffer.substr(0, n);
+ }
+
function foo(s) {
- s.log("hello from foo() handler!");
- return s.remoteAddress;
+ return line;
}
function bar(s) {
@@ -191,6 +237,54 @@ stream.js:
return "foo-var" + v.remote_port + "; pid=" + v.pid;
}
+ // The filter processes one buffer per call.
+ // The buffer is available in s.buffer both for
+ // reading and writing. Called for both directions.
+
+ function baz(s) {
+ if (s.fromUpstream || matched) {
+ return;
+ }
+
+ // Disable certain addresses.
+
+ if (s.remoteAddress.match('^192.*')) {
+ return s.ERROR;
+ }
+
+ // Read HTTP request line.
+ // Collect bytes in 'req' until request
+ // line is read. Clear current buffer to
+ // disable output.
+
+ req = req + s.buffer;
+ s.buffer = '';
+
+ n = req.search('\n');
+
+ if (n != -1) {
+ // Inject a new HTTP header.
+ var rest = req.substr(n + 1);
+ req = req.substr(0, n + 1);
+
+ addr = s.remoteAddress;
+
+ s.log('req:' + req);
+ s.log('rest:' + rest);
+
+ // Output the result and skip further
+ // processing.
+
+ s.buffer = req + 'Foo: addr_' + addr + '\r\n' + rest;
+ matched = 1;
+ }
+ }
+
+ function xyz(s) {
+ if (s.remoteAddress.match('^192.*')) {
+ return s.ABORT;
+ }
+ }
--
NGINX, Inc., http://nginx.com
diff -r cfa17c3e25da -r 322359ec0913 nginx/ngx_stream_js_module.c
--- a/nginx/ngx_stream_js_module.c Mon Sep 26 18:41:57 2016 +0300
+++ b/nginx/ngx_stream_js_module.c Wed Sep 28 19:52:05 2016 +0300
@@ -40,15 +40,30 @@
typedef struct {
njs_vm_t *vm;
njs_opaque_value_t arg;
+ ngx_str_t access;
+ ngx_str_t preread;
+ ngx_str_t filter;
} ngx_stream_js_srv_conf_t;
typedef struct {
njs_vm_t *vm;
njs_opaque_value_t *arg;
+ ngx_buf_t *buf;
+ ngx_chain_t *free;
+ ngx_chain_t *busy;
+ ngx_stream_session_t *session;
+ unsigned from_upstream:1;
+ unsigned filter:1;
} ngx_stream_js_ctx_t;
+static ngx_int_t ngx_stream_js_access_handler(ngx_stream_session_t *s);
+static ngx_int_t ngx_stream_js_preread_handler(ngx_stream_session_t *s);
+static ngx_int_t ngx_stream_js_phase_handler(ngx_stream_session_t *s,
+ ngx_str_t *name);
+static ngx_int_t ngx_stream_js_body_filter(ngx_stream_session_t *s,
+ ngx_chain_t *in, ngx_uint_t from_upstream);
static ngx_int_t ngx_stream_js_variable(ngx_stream_session_t *s,
ngx_stream_variable_value_t *v, uintptr_t data);
static void ngx_stream_js_cleanup_mem_cache_pool(void *data);
@@ -61,10 +76,20 @@ static void ngx_stream_js_free(void *mem
static njs_ret_t ngx_stream_js_ext_get_remote_address(njs_vm_t *vm,
njs_value_t *value, void *obj, uintptr_t data);
-static njs_ret_t ngx_stream_js_ext_log(njs_vm_t *vm, njs_value_t *args,
- nxt_uint_t nargs, njs_index_t unused);
+static njs_ret_t ngx_stream_js_ext_get_eof(njs_vm_t *vm, njs_value_t *value,
+ void *obj, uintptr_t data);
+static njs_ret_t ngx_stream_js_ext_get_from_upstream(njs_vm_t *vm,
+ njs_value_t *value, void *obj, uintptr_t data);
+static njs_ret_t ngx_stream_js_ext_get_buffer(njs_vm_t *vm, njs_value_t *value,
+ void *obj, uintptr_t data);
+static njs_ret_t ngx_stream_js_ext_set_buffer(njs_vm_t *vm, void *obj,
+ uintptr_t data, nxt_str_t *value);
+ static njs_ret_t ngx_stream_js_ext_log(njs_vm_t *vm, njs_value_t *args,
+ nxt_uint_t nargs, njs_index_t unused);
static njs_ret_t ngx_stream_js_ext_get_variable(njs_vm_t *vm,
njs_value_t *value, void *obj, uintptr_t data);
+static njs_ret_t ngx_stream_js_ext_get_code(njs_vm_t *vm,
+ njs_value_t *value, void *obj, uintptr_t data);
static char *ngx_stream_js_include(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
@@ -73,6 +98,7 @@ static char *ngx_stream_js_set(ngx_conf_
static void *ngx_stream_js_create_srv_conf(ngx_conf_t *cf);
static char *ngx_stream_js_merge_srv_conf(ngx_conf_t *cf, void *parent,
void *child);
+static ngx_int_t ngx_stream_js_init(ngx_conf_t *cf);
static ngx_command_t ngx_stream_js_commands[] = {
@@ -91,13 +117,34 @@ static ngx_command_t ngx_stream_js_comm
0,
NULL },
+ { ngx_string("js_access"),
+ NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_str_slot,
+ NGX_STREAM_SRV_CONF_OFFSET,
+ offsetof(ngx_stream_js_srv_conf_t, access),
+ NULL },
+
+ { ngx_string("js_preread"),
+ NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_str_slot,
+ NGX_STREAM_SRV_CONF_OFFSET,
+ offsetof(ngx_stream_js_srv_conf_t, preread),
+ NULL },
+
+ { ngx_string("js_filter"),
+ NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_str_slot,
+ NGX_STREAM_SRV_CONF_OFFSET,
+ offsetof(ngx_stream_js_srv_conf_t, filter),
+ NULL },
+
ngx_null_command
};
static ngx_stream_module_t ngx_stream_js_module_ctx = {
NULL, /* preconfiguration */
- NULL, /* postconfiguration */
+ ngx_stream_js_init, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
@@ -148,6 +195,42 @@ static njs_external_t ngx_stream_js_ext
NULL,
0 },
+ { nxt_string("eof"),
+ NJS_EXTERN_PROPERTY,
+ NULL,
+ 0,
+ ngx_stream_js_ext_get_eof,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0 },
+
+ { nxt_string("fromUpstream"),
+ NJS_EXTERN_PROPERTY,
+ NULL,
+ 0,
+ ngx_stream_js_ext_get_from_upstream,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0 },
+
+ { nxt_string("buffer"),
+ NJS_EXTERN_PROPERTY,
+ NULL,
+ 0,
+ ngx_stream_js_ext_get_buffer,
+ ngx_stream_js_ext_set_buffer,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0 },
+
{ nxt_string("log"),
NJS_EXTERN_METHOD,
NULL,
@@ -171,6 +254,66 @@ static njs_external_t ngx_stream_js_ext
NULL,
NULL,
0 },
+
+ { nxt_string("OK"),
+ NJS_EXTERN_PROPERTY,
+ NULL,
+ 0,
+ ngx_stream_js_ext_get_code,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ -NGX_OK },
+
+ { nxt_string("DECLINED"),
+ NJS_EXTERN_PROPERTY,
+ NULL,
+ 0,
+ ngx_stream_js_ext_get_code,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ -NGX_DECLINED },
+
+ { nxt_string("AGAIN"),
+ NJS_EXTERN_PROPERTY,
+ NULL,
+ 0,
+ ngx_stream_js_ext_get_code,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ -NGX_AGAIN },
+
+ { nxt_string("ERROR"),
+ NJS_EXTERN_PROPERTY,
+ NULL,
+ 0,
+ ngx_stream_js_ext_get_code,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ -NGX_ERROR },
+
+ { nxt_string("ABORT"),
+ NJS_EXTERN_PROPERTY,
+ NULL,
+ 0,
+ ngx_stream_js_ext_get_code,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ -NGX_ABORT },
};
@@ -190,6 +333,224 @@ static njs_external_t ngx_stream_js_ext
};
+static ngx_stream_filter_pt ngx_stream_next_filter;
+
+
+static ngx_int_t
+ngx_stream_js_access_handler(ngx_stream_session_t *s)
+{
+ ngx_int_t rc;
+ ngx_stream_js_srv_conf_t *jscf;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
+ "js access handler");
+
+ jscf = ngx_stream_get_module_srv_conf(s, ngx_stream_js_module);
+
+ rc = ngx_stream_js_phase_handler(s, &jscf->access);
+
+ if (rc == NGX_ABORT) {
+ ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
+ "access forbidden by js");
+ rc = NGX_STREAM_FORBIDDEN;
+ }
+
+ return rc;
+}
+
+
+static ngx_int_t
+ngx_stream_js_preread_handler(ngx_stream_session_t *s)
+{
+ ngx_stream_js_srv_conf_t *jscf;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
+ "js preread handler");
+
+ jscf = ngx_stream_get_module_srv_conf(s, ngx_stream_js_module);
+
+ return ngx_stream_js_phase_handler(s, &jscf->preread);
+}
+
+
+static ngx_int_t
+ngx_stream_js_phase_handler(ngx_stream_session_t *s, ngx_str_t *name)
+{
+ nxt_str_t fname, value, exception;
+ ngx_int_t rc;
+ njs_function_t *func;
+ ngx_connection_t *c;
+ ngx_stream_js_ctx_t *ctx;
+
+ if (name->len == 0) {
+ return NGX_DECLINED;
+ }
+
+ c = s->connection;
+
+ rc = ngx_stream_js_init_vm(s);
+ if (rc != NGX_OK) {
+ return rc;
+ }
+
+ ctx = ngx_stream_get_module_ctx(s, ngx_stream_js_module);
+
+ fname.start = name->data;
+ fname.length = name->len;
+
+ func = njs_vm_function(ctx->vm, &fname);
+
+ if (func == NULL) {
+ ngx_log_error(NGX_LOG_ERR, c->log, 0, "js function \"%V\" not found",
+ name);
+ return NGX_ERROR;
+ }
+
+ if (njs_vm_call(ctx->vm, func, ctx->arg, 1) != NJS_OK) {
+ njs_vm_exception(ctx->vm, &exception);
+
+ ngx_log_error(NGX_LOG_ERR, c->log, 0, "js exception: %*s",
+ exception.length, exception.start);
+
+ return NGX_ERROR;
+ }
+
+ if (ctx->vm->retval.type == NJS_VOID) {
+ return NGX_OK;
+ }
+
+ if (njs_vm_retval(ctx->vm, &value) != NJS_OK) {
+ return NGX_ERROR;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_STREAM, c->log, 0, "js return value: \"%*s\"",
+ value.length, value.start);
+
+ rc = ngx_atoi(value.start, value.length);
+
+ if (rc == NGX_ERROR) {
+ ngx_log_error(NGX_LOG_ERR, c->log, 0,
+ "unexpected js return code: \"%*s\"",
+ value.length, value.start);
+ return NGX_ERROR;
+ }
+
+ return -rc;
+}
+
+
+static ngx_int_t
+ngx_stream_js_body_filter(ngx_stream_session_t *s, ngx_chain_t *in,
+ ngx_uint_t from_upstream)
+{
+ nxt_str_t name, value, exception;
+ ngx_int_t rc;
+ ngx_chain_t *out, *cl, **ll;
+ njs_function_t *func;
+ ngx_connection_t *c;
+ ngx_stream_js_ctx_t *ctx;
+ ngx_stream_js_srv_conf_t *jscf;
+
+ jscf = ngx_stream_get_module_srv_conf(s, ngx_stream_js_module);
+ if (jscf->filter.len == 0) {
+ return ngx_stream_next_filter(s, in, from_upstream);
+ }
+
+ c = s->connection;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, "stream js filter u:%ui",
+ from_upstream);
+
+ rc = ngx_stream_js_init_vm(s);
+
+ if (rc == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+
+ if (rc == NGX_DECLINED) {
+ return ngx_stream_next_filter(s, in, from_upstream);
+ }
+
+ ctx = ngx_stream_get_module_ctx(s, ngx_stream_js_module);
+
+ ctx->filter = 1;
+
+ name.start = jscf->filter.data;
+ name.length = jscf->filter.len;
+
+ func = njs_vm_function(ctx->vm, &name);
+
+ if (func == NULL) {
+ ngx_log_error(NGX_LOG_ERR, c->log, 0, "js function \"%V\" not found",
+ &jscf->filter);
+ return NGX_ERROR;
+ }
+
+ ctx->from_upstream = from_upstream;
+
+ ll = &out;
+
+ while (in) {
+ ctx->buf = in->buf;
+
+ if (njs_vm_call(ctx->vm, func, ctx->arg, 1) != NJS_OK) {
+ njs_vm_exception(ctx->vm, &exception);
+
+ ngx_log_error(NGX_LOG_ERR, c->log, 0, "js exception: %*s",
+ exception.length, exception.start);
+
+ return NGX_ERROR;
+ }
+
+ if (njs_vm_retval(ctx->vm, &value) != NJS_OK) {
+ return NGX_ERROR;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_STREAM, c->log, 0,
+ "js return value: \"%*s\"",
+ value.length, value.start);
+
+ if (value.length) {
+ rc = ngx_atoi(value.start, value.length);
+
+ if (rc != NGX_OK && rc != -NGX_ERROR) {
+ ngx_log_error(NGX_LOG_ERR, c->log, 0,
+ "unexpected js return code: \"%*s\"",
+ value.length, value.start);
+ return NGX_ERROR;
+ }
+
+ rc = -rc;
+
+ if (rc == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+ }
+
+ cl = ngx_alloc_chain_link(c->pool);
+ if (cl == NULL) {
+ return NGX_ERROR;
+ }
+
+ cl->buf = ctx->buf;
+
+ *ll = cl;
+ ll = &cl->next;
+
+ in = in->next;
+ }
+
+ *ll = NULL;
+
+ rc = ngx_stream_next_filter(s, out, from_upstream);
+
+ ngx_chain_update_chains(c->pool, &ctx->free, &ctx->busy, &out,
+ (ngx_buf_tag_t) &ngx_stream_js_module);
+
+ return rc;
+}
+
+
static ngx_int_t
ngx_stream_js_variable(ngx_stream_session_t *s, ngx_stream_variable_value_t *v,
uintptr_t data)
@@ -364,6 +725,137 @@ ngx_stream_js_ext_get_remote_address(njs
static njs_ret_t
+ngx_stream_js_ext_get_eof(njs_vm_t *vm, njs_value_t *value, void *obj,
+ uintptr_t data)
+{
+ ngx_buf_t *b;
+ ngx_connection_t *c;
+ ngx_stream_js_ctx_t *ctx;
+ ngx_stream_session_t *s;
+
+ s = (ngx_stream_session_t *) obj;
+ c = s->connection;
+ ctx = ngx_stream_get_module_ctx(s, ngx_stream_js_module);
+
+ b = ctx->filter ? ctx->buf : c->buffer;
+
+ *value = (b && b->last_buf ? njs_value_true : njs_value_false);
+
+ return NJS_OK;
+}
+
+
+static njs_ret_t
+ngx_stream_js_ext_get_from_upstream(njs_vm_t *vm, njs_value_t *value, void *obj,
+ uintptr_t data)
+{
+ ngx_stream_js_ctx_t *ctx;
+ ngx_stream_session_t *s;
+
+ s = (ngx_stream_session_t *) obj;
+ ctx = ngx_stream_get_module_ctx(s, ngx_stream_js_module);
+
+ *value = (ctx->from_upstream ? njs_value_true : njs_value_false);
+
+ return NJS_OK;
+}
+
+
+static njs_ret_t
+ngx_stream_js_ext_get_buffer(njs_vm_t *vm, njs_value_t *value, void *obj,
+ uintptr_t data)
+{
+ size_t len;
+ u_char *p;
+ ngx_buf_t *b;
+ ngx_connection_t *c;
+ ngx_stream_js_ctx_t *ctx;
+ ngx_stream_session_t *s;
+
+ s = (ngx_stream_session_t *) obj;
+ c = s->connection;
+ ctx = ngx_stream_get_module_ctx(s, ngx_stream_js_module);
+
+ b = ctx->filter ? ctx->buf : c->buffer;
+
+ len = b ? b->last - b->pos : 0;
+
+ p = njs_string_alloc(vm, value, len, 0);
+ if (p == NULL) {
+ return NJS_ERROR;
+ }
+
+ if (len) {
+ ngx_memcpy(p, b->pos, len);
+ }
+
+ return NJS_OK;
+}
+
+
+static njs_ret_t
+ngx_stream_js_ext_set_buffer(njs_vm_t *vm, void *obj, uintptr_t data,
+ nxt_str_t *value)
+{
+ ngx_buf_t *b;
+ ngx_chain_t *cl;
+ ngx_connection_t *c;
+ ngx_stream_js_ctx_t *ctx;
+ ngx_stream_session_t *s;
+
+ s = (ngx_stream_session_t *) obj;
+ c = s->connection;
+ ctx = ngx_stream_get_module_ctx(s, ngx_stream_js_module);
+
+ ngx_log_debug2(NGX_LOG_DEBUG_STREAM, c->log, 0,
+ "stream js set buffer \"%*s\"", value->length, value->start);
+
+ if (!ctx->filter) {
+ ngx_log_error(NGX_LOG_WARN, c->log, 0,
+ "cannot set buffer in this handler");
+ return NJS_OK;
+ }
+
+ cl = ngx_chain_get_free_buf(c->pool, &ctx->free);
+ if (cl == NULL) {
+ return NJS_ERROR;
+ }
+
+ b = cl->buf;
+
+ ngx_free_chain(c->pool, cl);
+
+ b->last_buf = ctx->buf->last_buf;
+ b->memory = (value->length ? 1 : 0);
+ b->sync = (value->length ? 0 : 1);
+ b->tag = (ngx_buf_tag_t) &ngx_stream_js_module;
+
+ b->start = value->start;
+ b->end = value->start + value->length;
+ b->pos = b->start;
+ b->last = b->end;
+
+ if (ctx->buf->tag != (ngx_buf_tag_t) &ngx_stream_js_module) {
+ ctx->buf->pos = ctx->buf->last;
+
+ } else {
+ cl = ngx_alloc_chain_link(c->pool);
+ if (cl == NULL) {
+ return NJS_ERROR;
+ }
+
+ cl->buf = ctx->buf;
+ cl->next = ctx->free;
+ ctx->free = cl;
+ }
+
+ ctx->buf = b;
+
+ return NJS_OK;
+}
+
+
+static njs_ret_t
ngx_stream_js_ext_log(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
njs_index_t unused)
{
@@ -375,8 +867,7 @@ ngx_stream_js_ext_log(njs_vm_t *vm, njs_
s = njs_value_data(njs_argument(args, 0));
c = s->connection;
- if (njs_value_to_ext_string(vm, &msg, njs_argument(args, 1)) == NJS_ERROR)
- {
+ if (njs_value_to_ext_string(vm, &msg, njs_argument(args, 1)) == NJS_ERROR) {
return NJS_ERROR;
}
@@ -418,6 +909,19 @@ ngx_stream_js_ext_get_variable(njs_vm_t
}
+static njs_ret_t
+ngx_stream_js_ext_get_code(njs_vm_t *vm, njs_value_t *value, void *obj,
+ uintptr_t data)
+{
+ ngx_memzero(value, sizeof(njs_value_t));
+
+ value->data.type = NJS_NUMBER;
+ value->data.u.number = data;
+
+ return NJS_OK;
+}
+
+
static char *
ngx_stream_js_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
@@ -606,6 +1110,9 @@ ngx_stream_js_create_srv_conf(ngx_conf_t
*
* conf->vm = NULL;
* conf->arg = NULL;
+ * conf->access = { 0, NULL };
+ * conf->preread = { 0, NULL };
+ * conf->filter = { 0, NULL };
*/
return conf;
@@ -623,5 +1130,38 @@ ngx_stream_js_merge_srv_conf(ngx_conf_t
conf->arg = prev->arg;
}
+ ngx_conf_merge_str_value(conf->access, prev->access, "");
+ ngx_conf_merge_str_value(conf->preread, prev->preread, "");
+ ngx_conf_merge_str_value(conf->filter, prev->filter, "");
+
return NGX_CONF_OK;
}
+
+
+static ngx_int_t
+ngx_stream_js_init(ngx_conf_t *cf)
+{
+ ngx_stream_handler_pt *h;
+ ngx_stream_core_main_conf_t *cmcf;
+
+ ngx_stream_next_filter = ngx_stream_top_filter;
+ ngx_stream_top_filter = ngx_stream_js_body_filter;
+
+ cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
+
+ h = ngx_array_push(&cmcf->phases[NGX_STREAM_ACCESS_PHASE].handlers);
+ if (h == NULL) {
+ return NGX_ERROR;
+ }
+
+ *h = ngx_stream_js_access_handler;
+
+ h = ngx_array_push(&cmcf->phases[NGX_STREAM_PREREAD_PHASE].handlers);
+ if (h == NULL) {
+ return NGX_ERROR;
+ }
+
+ *h = ngx_stream_js_preread_handler;
+
+ return NGX_OK;
+}
More information about the nginx-devel
mailing list