Skip to content

Commit e090929

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 dc4232e commit e090929

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
@@ -58,6 +58,7 @@ typedef struct {
5858
unsigned from_upstream:1;
5959
unsigned filter:1;
6060
unsigned in_progress:1;
61+
unsigned preread:1;
6162
} ngx_stream_js_ctx_t;
6263

6364

@@ -436,14 +437,50 @@ ngx_stream_js_access_handler(ngx_stream_session_t *s)
436437
static ngx_int_t
437438
ngx_stream_js_preread_handler(ngx_stream_session_t *s)
438439
{
440+
ngx_int_t rc;
441+
ngx_chain_t *out;
442+
ngx_connection_t *c;
443+
ngx_stream_js_ctx_t *ctx;
439444
ngx_stream_js_srv_conf_t *jscf;
440445

441446
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
442447
"js preread handler");
443448

449+
rc = ngx_stream_js_init_vm(s);
450+
if (rc != NGX_OK) {
451+
return rc;
452+
}
453+
454+
c = s->connection;
455+
ctx = ngx_stream_get_module_ctx(s, ngx_stream_js_module);
444456
jscf = ngx_stream_get_module_srv_conf(s, ngx_stream_js_module);
445457

446-
return ngx_stream_js_phase_handler(s, &jscf->preread);
458+
ctx->preread = 1;
459+
ctx->last_out = &out;
460+
461+
rc = ngx_stream_js_phase_handler(s, &jscf->preread);
462+
463+
*ctx->last_out = NULL;
464+
465+
if (rc == NGX_ERROR) {
466+
return rc;
467+
}
468+
469+
if (rc != NGX_AGAIN) {
470+
ctx->preread = 0;
471+
}
472+
473+
if (out != NULL || c->buffered) {
474+
if (ngx_stream_top_filter(s, out, 1) == NGX_ERROR) {
475+
return NGX_ERROR;
476+
}
477+
478+
ngx_chain_update_chains(c->pool, &ctx->free, &ctx->busy, &out,
479+
(ngx_buf_tag_t) &ngx_stream_js_module);
480+
481+
}
482+
483+
return rc;
447484
}
448485

449486

@@ -553,6 +590,10 @@ ngx_stream_js_body_filter(ngx_stream_session_t *s, ngx_chain_t *in,
553590

554591
ctx = ngx_stream_get_module_ctx(s, ngx_stream_js_module);
555592

593+
if (ctx->preread) {
594+
return ngx_stream_next_filter(s, in, from_upstream);
595+
}
596+
556597
if (!ctx->filter) {
557598
rc = ngx_js_call(ctx->vm, &jscf->filter, c->log, &ctx->args[0], 1);
558599

@@ -1122,18 +1163,26 @@ ngx_stream_js_ext_send(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
11221163

11231164
ctx = ngx_stream_get_module_ctx(s, ngx_stream_js_module);
11241165

1125-
if (!ctx->filter) {
1166+
if (!ctx->filter && !ctx->preread) {
11261167
njs_vm_error(vm, "cannot send buffer in this handler");
11271168
return NJS_ERROR;
1169+
} else if (ctx->filter && ctx->preread) {
1170+
njs_vm_error(vm, "invalid state, both filter and preread are set");
1171+
return NJS_ERROR;
11281172
}
11291173

11301174
if (ngx_js_string(vm, njs_arg(args, nargs, 1), &buffer) != NGX_OK) {
11311175
njs_vm_error(vm, "failed to get buffer arg");
11321176
return NJS_ERROR;
11331177
}
11341178

1135-
flush = ctx->buf->flush;
1136-
last_buf = ctx->buf->last_buf;
1179+
if(ctx->filter){
1180+
flush = ctx->buf->flush;
1181+
last_buf = ctx->buf->last_buf;
1182+
} else { // ctx->preread == 1
1183+
flush = 1;
1184+
last_buf = 0;
1185+
}
11371186

11381187
flags = njs_arg(args, nargs, 2);
11391188

0 commit comments

Comments
 (0)