2009-04-05

исправляем проблему с Transfer-encoding:chunked в nginx

Пока Игорь Сысоев думает над тем, как правильно (т.е. надежно и быстродейственно) реализовать обработку Content-encoding:chunked при не заданной Content-Length в nginx, мне пришлось сделать workaround (для тех, кому это нужно "здесь и сейчас"). Решил его выложить, может, кому-то кроме меня это тоже будет нужно:

--- old/ngx_http_request.c 2009-04-05 20:41:18.000000000 +0300
+++ new/ngx_http_request.c 2009-04-05 20:38:33.000000000 +0300
@@ -1403,16 +1403,6 @@
return NGX_ERROR;
}

- if (r->headers_in.transfer_encoding
- && ngx_strcasestrn(r->headers_in.transfer_encoding->value.data,
- "chunked", 7 - 1))
- {
- ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
- "client sent \"Transfer-Encoding: chunked\" header");
- ngx_http_finalize_request(r, NGX_HTTP_LENGTH_REQUIRED);
- return NGX_ERROR;
- }
-
if (r->headers_in.connection_type == NGX_HTTP_CONNECTION_KEEP_ALIVE) {
if (r->headers_in.keep_alive) {
r->headers_in.keep_alive_n =


--- old/ngx_http_request_body.c 2009-04-05 20:41:39.000000000 +0300
+++ new/ngx_http_request_body.c 2009-04-05 20:34:45.000000000 +0300
@@ -54,11 +54,6 @@

r->request_body = rb;

- if (r->headers_in.content_length_n < 0) {
- post_handler(r);
- return NGX_OK;
- }
-
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

if (r->headers_in.content_length_n == 0) {
@@ -180,7 +175,8 @@

} else {
b = NULL;
- rb->rest = r->headers_in.content_length_n;
+ rb->rest = r->headers_in.content_length_n >= 0 ? r->headers_in.content_length_n
+ : NGX_MAX_SIZE_T_VALUE;
next = &rb->bufs;
}


Мимоходом, разобрался немного во внутренностях этого сервера. Что можно сказать? Во-первых, event-driven архитектура — это сложно. Особенно, когда нет общего описания, кто кого вызывает. И особенно при почти полном отсутствии комментариев в коде.

Ну и про С и Lisp (по итогам копания в коде двух HTTP-серверов: nginx и Hunchentoot). Lisp — это глина, лепи себе, что заблагорассудится, со всеми вытекающими плюсами и минусами. C... Есть такие конструторы из металлических планок и уголков. Интересно с ними играться. И, в общем-то, довольно понятно все, можно собрать хорошие, надежные конструкции. Но вот сделать из этого какую-нибудь вазу с закругленными углами — это для фанатов...

1 comment:

  1. К сожалению, радость оказалась преждевременной, поскольку это решение работало за счет обработки предпрочитанных данных nginx'ом (которая актуальна только для быстрых соединений, которые были в моей тестовой среде -- на loclhost'e :).

    Вот более адекватное решение:
    --- old/ngx_http_request_body.c 2009-04-05 20:44:46.000000000 +0300
    +++ new/ngx_http_request_body.c 2009-04-09 12:03:56.000000000 +0300
    @@ -54,7 +54,7 @@

    r->request_body = rb;

    - if (r->headers_in.content_length_n < 0) {
    + if (r->headers_in.content_length_n < 0 && !(r->method & NGX_HTTP_POST)) {
    post_handler(r);
    return NGX_OK;
    }
    @@ -137,7 +137,8 @@

    rb->buf = b;

    - if ((off_t) preread >= r->headers_in.content_length_n) {
    + if (r->headers_in.content_length_n >= 0 &&
    + (off_t) preread >= r->headers_in.content_length_n) {

    /* the whole request body was pre-read */

    @@ -163,9 +164,12 @@

    r->request_length += preread;

    - rb->rest = r->headers_in.content_length_n - preread;
    + if (r->headers_in.content_length_n >= 0) {
    + rb->rest = r->headers_in.content_length_n - preread;
    + }

    - if (rb->rest <= (off_t) (b->end - b->last)) {
    + if (r->headers_in.content_length_n >= 0 &&
    + rb->rest <= (off_t) (b->end - b->last)) {

    /* the whole request body may be placed in r->header_in */

    @@ -180,14 +184,14 @@

    } else {
    b = NULL;
    - rb->rest = r->headers_in.content_length_n;
    + rb->rest = r->headers_in.content_length_n >= 0 ?r->headers_in.content_length_n : 1024;
    next = &rb->bufs;
    }

    size = clcf->client_body_buffer_size;
    size += size >> 2;

    - if (rb->rest < size) {
    + if (rb->rest >=0 && rb->rest < size) {
    size = (ssize_t) rb->rest;

    if (r->request_body_in_single_buf) {
    @@ -224,13 +228,15 @@

    *next = cl;

    - if (r->request_body_in_file_only || r->request_body_in_single_buf) {
    + if (r->request_body_in_file_only || r->request_body_in_single_buf || r->headers_in.content_length_n < 0) {
    rb->to_write = rb->bufs;

    } else {
    rb->to_write = rb->bufs->next ? rb->bufs->next : rb->bufs;
    }

    + // if (r->headers_in.content_length_n < 0) {
    +
    r->read_event_handler = ngx_http_read_client_request_body_handler;

    return ngx_http_do_read_client_request_body(r);
    @@ -310,7 +316,13 @@
    }

    rb->buf->last += n;
    - rb->rest -= n;
    +
    + if ( ngx_memcmp(rb->buf->last - 7, (u_char *) CRLF "0" CRLF CRLF, sizeof(u_char)) ) {
    + rb->rest -= n;
    + } else {
    + rb->rest = 0;
    + }
    +
    r->request_length += n;

    if (rb->rest == 0) {

    April 9, 2009 12:10 PM

    ReplyDelete