Skip to content

Commit afe3a89

Browse files
stream: Allow sending data in the preread phase
There are cases when some interactions should happen between the client and the server before a successful preread. This patch enables sending data to the client in the preread phase. To avoid possible conflict between the preread callback and filtering callbacks, the data sent bypasses `js_body_filter`, but not other filters, if any. This patch introduces a new field in ngx_stream_js_ctx_t named `preread` to indicate if the session is now in the preread phase.
1 parent beba525 commit afe3a89

File tree

1 file changed

+53
-4
lines changed

1 file changed

+53
-4
lines changed

nginx/ngx_stream_js_module.c

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ typedef struct {
5959
unsigned from_upstream:1;
6060
unsigned filter:1;
6161
unsigned in_progress:1;
62+
unsigned preread:1;
6263
} ngx_stream_js_ctx_t;
6364

6465

@@ -440,14 +441,50 @@ ngx_stream_js_access_handler(ngx_stream_session_t *s)
440441
static ngx_int_t
441442
ngx_stream_js_preread_handler(ngx_stream_session_t *s)
442443
{
444+
ngx_int_t rc;
445+
ngx_chain_t *out;
446+
ngx_connection_t *c;
447+
ngx_stream_js_ctx_t *ctx;
443448
ngx_stream_js_srv_conf_t *jscf;
444449

445450
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
446451
"js preread handler");
447452

453+
rc = ngx_stream_js_init_vm(s);
454+
if (rc != NGX_OK) {
455+
return rc;
456+
}
457+
458+
c = s->connection;
459+
ctx = ngx_stream_get_module_ctx(s, ngx_stream_js_module);
448460
jscf = ngx_stream_get_module_srv_conf(s, ngx_stream_js_module);
449461

450-
return ngx_stream_js_phase_handler(s, &jscf->preread);
462+
ctx->preread = 1;
463+
ctx->last_out = &out;
464+
465+
rc = ngx_stream_js_phase_handler(s, &jscf->preread);
466+
467+
*ctx->last_out = NULL;
468+
469+
if (rc == NGX_ERROR) {
470+
return rc;
471+
}
472+
473+
if (rc != NGX_AGAIN) {
474+
ctx->preread = 0;
475+
}
476+
477+
if (out != NULL || c->buffered) {
478+
if (ngx_stream_top_filter(s, out, 1) == NGX_ERROR) {
479+
return NGX_ERROR;
480+
}
481+
482+
ngx_chain_update_chains(c->pool, &ctx->free, &ctx->downstream_busy,
483+
&out, (ngx_buf_tag_t) &ngx_stream_js_module);
484+
485+
}
486+
487+
return rc;
451488
}
452489

453490

@@ -557,6 +594,10 @@ ngx_stream_js_body_filter(ngx_stream_session_t *s, ngx_chain_t *in,
557594

558595
ctx = ngx_stream_get_module_ctx(s, ngx_stream_js_module);
559596

597+
if (ctx->preread) {
598+
return ngx_stream_next_filter(s, in, from_upstream);
599+
}
600+
560601
if (!ctx->filter) {
561602
rc = ngx_js_call(ctx->vm, &jscf->filter, c->log, &ctx->args[0], 1);
562603

@@ -1132,18 +1173,26 @@ ngx_stream_js_ext_send(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
11321173

11331174
ctx = ngx_stream_get_module_ctx(s, ngx_stream_js_module);
11341175

1135-
if (!ctx->filter) {
1176+
if (!ctx->filter && !ctx->preread) {
11361177
njs_vm_error(vm, "cannot send buffer in this handler");
11371178
return NJS_ERROR;
1179+
} else if (ctx->filter && ctx->preread) {
1180+
njs_vm_error(vm, "invalid state, both filter and preread are set");
1181+
return NJS_ERROR;
11381182
}
11391183

11401184
if (ngx_js_string(vm, njs_arg(args, nargs, 1), &buffer) != NGX_OK) {
11411185
njs_vm_error(vm, "failed to get buffer arg");
11421186
return NJS_ERROR;
11431187
}
11441188

1145-
flush = ctx->buf->flush;
1146-
last_buf = ctx->buf->last_buf;
1189+
if(ctx->filter){
1190+
flush = ctx->buf->flush;
1191+
last_buf = ctx->buf->last_buf;
1192+
} else { // ctx->preread == 1
1193+
flush = 1;
1194+
last_buf = 0;
1195+
}
11471196

11481197
flags = njs_arg(args, nargs, 2);
11491198

0 commit comments

Comments
 (0)