PHP: fixed request body processing.

The implementation of module was based on the assumption that PHP reads request
body and headers in the particular order.  For the POST request the body goes
before headers and vice versa for all other requests.

But as it appeared later, this order is unspecified and depends on many factors,
including the particular code of PHP application.  Among other factors those
can affect ordering:

 - presence of "Content-Type" header;
 - "variables_order" php.ini setting;
 - "enable_post_data_reading" php.ini setting;
 - reading php://input by application;

and this list can be incomplete.

As a temporary workaround, request body now is always put before headers and it
is gracefully skipped whenever PHP wants to get headers.

This closes #144 issue on GitHub.
This commit is contained in:
Valentin Bartenev 2018-07-05 16:43:45 +03:00
parent 234deb51f4
commit 7e3de003c7
2 changed files with 40 additions and 21 deletions

View file

@ -799,10 +799,13 @@ static void
nxt_php_register_variables(zval *track_vars_array TSRMLS_DC)
{
u_char *colon;
size_t rest, size;
nxt_str_t n, v;
nxt_int_t rc;
nxt_str_t host, server_name, server_port;
nxt_buf_t *b, buf;
nxt_task_t *task;
nxt_app_rmsg_t *rmsg, rmsg_tmp;
nxt_php_run_ctx_t *ctx;
nxt_app_request_header_t *h;
@ -904,12 +907,44 @@ nxt_php_register_variables(zval *track_vars_array TSRMLS_DC)
NXT_PHP_SET("REMOTE_ADDR", ctx->r.remote);
NXT_PHP_SET("SERVER_ADDR", ctx->r.local);
while (nxt_app_msg_read_str(task, ctx->rmsg, &n) == NXT_OK) {
rmsg = ctx->rmsg;
rest = ctx->body_preread_size;
if (rest != 0) {
/* Skipping request body. */
b = rmsg->buf;
do {
if (nxt_slow_path(b == NULL)) {
return;
}
size = nxt_buf_mem_used_size(&b->mem);
if (rest < size) {
nxt_memcpy(&buf, b, NXT_BUF_MEM_SIZE);
buf.mem.pos += rest;
b = &buf;
break;
}
rest -= size;
b = b->next;
} while (rest != 0);
rmsg_tmp = *rmsg;
rmsg_tmp.buf = b;
rmsg = &rmsg_tmp;
}
while (nxt_app_msg_read_str(task, rmsg, &n) == NXT_OK) {
if (nxt_slow_path(n.length == 0)) {
break;
}
rc = nxt_app_msg_read_str(task, ctx->rmsg, &v);
rc = nxt_app_msg_read_str(task, rmsg, &v);
if (nxt_slow_path(rc != NXT_OK)) {
break;
}

View file

@ -4375,7 +4375,6 @@ nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
{
nxt_int_t rc;
nxt_buf_t *b;
nxt_bool_t method_is_post;
nxt_http_field_t *field;
nxt_app_request_header_t *h;
@ -4432,17 +4431,9 @@ nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length));
RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size));
method_is_post = h->method.length == 4
&& h->method.start[0] == 'P'
&& h->method.start[1] == 'O'
&& h->method.start[2] == 'S'
&& h->method.start[3] == 'T';
if (method_is_post) {
for (b = r->body.buf; b != NULL; b = b->next) {
RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
nxt_buf_mem_used_size(&b->mem)));
}
for (b = r->body.buf; b != NULL; b = b->next) {
RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
nxt_buf_mem_used_size(&b->mem)));
}
nxt_list_each(field, h->fields) {
@ -4455,13 +4446,6 @@ nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
/* end-of-headers mark */
NXT_WRITE(&eof);
if (!method_is_post) {
for (b = r->body.buf; b != NULL; b = b->next) {
RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
nxt_buf_mem_used_size(&b->mem)));
}
}
#undef NXT_WRITE
#undef RC