ПРОЕКТЫ 


  АРХИВ 


Apache-Talk @lexa.ru 

Inet-Admins @info.east.ru 

Filmscanners @halftone.co.uk 

Security-alerts @yandex-team.ru 

nginx-ru @sysoev.ru 


  СТАТЬИ 


  ПЕРСОНАЛЬНОЕ 


  ПРОГРАММЫ 



ПИШИТЕ
ПИСЬМА












     АРХИВ :: nginx-ru
Nginx-ru mailing list archive (nginx-ru@sysoev.ru)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

ngx_http_subrequest



Здравствуйте!

Я пишу модуль для nginx который принимает и разбирает тело POST-запроса и передает тело бакэнду в несколько измененном виде.

Я хочу, чтобы бакэндом мог быть не только proxy, но и fastcgi или, по возможности, внутренний location nginx. В случае внутреннего location'а тело запроса можно отбросить и использовать метод GET.

Я обаружил, что построение модуля согласно пункту 3.2 руководства Эвана Миллера (http://emiller.info/nginx-modules-guide.html#proxying) для моего случая не подходит, поскольку предполагает реализацию обработки всех возможных типов бакэндов. Я боюсь, что таким образом я задублирую существующий код, который это уже делает и, таким образом, получу кучу ошибок.

Соответственно, я посмотрел ещё раз на функцию ngx_http_subrequest и попытался использовать её таким же образом, каким она используется в ngx_http_ssi_filter_module.c. Я обнаружил, что она несколько не предназначена для работы с запросами, у которых http-метод отличается от GET. А именно, хотя тело и отдается бакэнду, http-метод по-умолчанию устанавливается в GET. Я вынужден был принудительно изменить метод на POST директивой (недокументированной) proxy_method POST.

Хотя я и получил результат (тело отдается бакэнду), но у меня возникла проблема с отображением сообщений об ошибках. А именно если генерируется Bad Gateway или Gateway Timeout, то в ответе nginx отсутствует заголовок (тело передается) и клиент (в моем случае Mozilla) "висит".

Я изучил исходники nginx и обнаружил, что функции ngx_http_subrequest, ngx_http_finalize_request, а так же файл ngx_http_upstream.c содержат сложную многоуровневую логику, которая напрямую с моей задачей не связана, но тем не менее так или иначе в её решение вовлечена. В этом коде, а так же в коде существующих модулей я не нашел примеров, которые могли хотя бы намекнуть на решение. Поэтому я сдался и решил спросить в рассылке.

А именно, я имею вот такой код:

static ngx_int_t
ngx_http_upload_output(ngx_http_request_t *r, void *data, ngx_int_t rc)
{
    if (rc == NGX_ERROR || r->connection->error) {
        return rc;
    }

    r->headers_out.status = r->err_status;

    if (!r->header_sent) {
        if (ngx_http_set_content_type(r) == NGX_ERROR) {
            return NGX_ERROR;
        }

        if (ngx_http_send_header(r) == NGX_ERROR) {
            return NGX_ERROR;
        }
    }

    ngx_http_send_special(r, NGX_HTTP_LAST|NGX_HTTP_FLUSH);

    return rc;
}

static ngx_int_t ngx_http_upload_body_handler(ngx_http_request_t *r) {
ngx_http_upload_loc_conf_t *ulcf = ngx_http_get_module_loc_conf(r, ngx_http_upload_module); ngx_http_upload_ctx_t *ctx = ngx_http_get_module_ctx(r, ngx_http_upload_module);

    ngx_str_t                   args;
    ngx_uint_t                  flags;
    ngx_int_t                   rc;
    ngx_str_t                   *uri;
    ngx_http_post_subrequest_t  *psr;
    ngx_http_request_t          *sr;
    ngx_buf_t                      *b;
    ngx_chain_t                    *cl

    [... Здесь генерируем тело, которое будет отдано бакэнду ...]

    // Изменяем тело запроса
    r->request_body->bufs = ctx->chain;

    // Код обработчика завершения подзапроса см. выше
    psr->handler = ngx_http_upload_output;

    // Здесь посылаем запрос бакэнду
    rc = ngx_http_subrequest(r, uri, &args, &sr, psr, flags);

    if (rc == NGX_ERROR) {
        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
}

ngx_http_upload_body_handler -- это функция, которая вызывается, когда завершается разбор тела исходного запроса. Она несколько аналогична функции ngx_http_upload_body_handler.

Возникают следующие вопросы:

1) Как сгенерировать заголовок?
2) Верно ли я использую функцию ngx_http_subrequest (может вообще так не стоит делать)? 3) Можно ли сделать так, чтобы ngx_http_subrequest копировала http-метод из оригинального или родительского запроса при получении некоторого флажка?

nginx 0.6.13

--
Regards,
Valery Kholodkov



 




Copyright © Lexa Software, 1996-2009.