Re: PUT и POST module handler

Maxim Dounin mdounin на mdounin.ru
Ср Окт 14 12:58:22 UTC 2015


Hello!

On Tue, Oct 13, 2015 at 02:13:04AM -0400, rba wrote:

> Здравствуйте.
> Почитал форум, посмотрел исходники и сообразил до некоторого порядка
> обработки данных запросов. Остались некоторые вопросы. Понимаю что ответы
> можно найти в исходниках(echo,dav и.т.д.)  но силы и терпение на исходе
> поэтому прошу помощи.

Я бы не рекомендовал ничего искать в исходниках "echo", там у 
автора подход "если оно работает, то и хорошо".  Имеет смысл для 
начала смотреть в исходники самого nginx'а и стандартных модулей.

[...]

> static void
> ngx_http_rbsample_debug(ngx_http_request_t *r, u_char *buffer, int nbytes)
> {//Это заглушка, в будущем некоторая неблокирующая функция отправляющая в
> специфичный бэкенд
> /**********************************************************
> 1. ngx_log_debug1 вроде выводит buffer и без завершения \0 или стоит
> дополнять конструкцией типа
>         u_char       *p;
>         p = ngx_pnalloc(r->pool, nbytes+1);
>         p = ngx_cpymem(p, buffer, nbytes+1);
>         p[nbytes+1]='\0';
>     ...и выводить p
> **********************************************************/
>     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, "RBSAMPLE 2.
> put/post: \"%s\"", buffer);

Стоит переписать на использование %*s или ngx_str_t + %V.
Формат %s подразумевает null-терминированную строку, и без 
завершающего \0 оно рано или поздно развалится.

Очевидно, что просто %s не может работать даже теоретически - 
длину строки вы не передаёте, и если она не null-терминирована, то 
узнать, где она кончается, невозможно.

> }
> 
> static void
> ngx_http_rbsample_post_handler(ngx_http_request_t *r)
> {
>     size_t        len;
>     ngx_buf_t    *buf;
>     ngx_chain_t  *cl;
> 
>     if (r->request_body == NULL && r->request_body->temp_file == NULL) {
>         ngx_log_debug(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, "RBSAMPLE
> 999. error put/post!!!!");
>         ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
>         return;
>     }
>     ngx_log_debug(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, "RBSAMPLE 1.
> put/post!!!!");
> 
> /**********************************************************
>   2. Не блокернёт ли следующий цикл воркер непрерывным чтением большого
> буфера, если ngx_http_rbsample_debug(сейчас заглушка) не блокирующая, 
>         или желательно после каждого cl->next как-то отдавать управление? 

Пока вы не вернёте управление - воркер, по очевидным причинам, 
больше ничего делать не может.  Соответственно, если процесс 
обработки может занимать заметное время - это придётся как-то 
решать (или мириться).

>   3. Будет ли порядок обработки тем же, если nginx положит тело запроса в
> файл?

В этом случае тела запроса, очевидно, не будет в памяти.  В 
r->request_body->bufs будет лежать соответствующий буфер в файле.  
Придётся научиться с ними работать.

>   4. Как можно отдать управление воркеру(что вернуть из текущего хэндлера) и
> отложить обработку ngx_http_rbsample_debug, не трогая буфер, не завершая
> запрос и не передавая обработку остальным хэндлерам в текущем запросе?

Понятия "остальных хендлеров" в случае чтения тела запроса не 
существует, единственный обработчик - ваш.  При этом завершение 
запроса возможно только в том случае, если вы сами позовёте 
ngx_http_finalize_request().  Пока не позвали - вы отвечаете за 
дальнейшую обработку запроса.

Например, в этот момент можно начать что-то делать в другом 
соединении, и возобновлять работу запроса по событиям от него.  
Так, в частности, работает модуль upstream, который используют 
proxy/fastcgi/memcached.

>   4.1. Чтобы в новом витке воркера вернуться к текущему запросу и cl, нужно
> его(cl) выносить в глобальное пространство(есть ли какие-то особенности в
> nginx?) или есть иные принятые в nginx способы?

Для сохранения данных модулей в nginx'е есть контексты модулей, 
см. ngx_http_set_ctx().

[...]

> static ngx_int_t
> ngx_http_rbsample_handler(ngx_http_request_t *r)
> {
>     ngx_int_t                 rc;
>     ngx_log_debug(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, "rbsample 0.
> ngx_http_rbsample_handler!");
> 
>     if(r->method == NGX_HTTP_PUT || r->method == NGX_HTTP_POST) {
>         r->request_body_in_file_only = 0;
>         r->request_body_in_single_buf=1;
> 
> /*********************************************************
> 5. Корректно ли так подключать обработчик POST/PUT в таком контексте, или
> лучше его делать фазовым?
> **********************************************************/

Корректно.

Делать обработчик фазовым нужно в том случае, если вам нужно 
обрабатывать не все запросы и сосуществовать с другими модулями, 
как это делает модуль DAV.  Если такой задачи нет и обработке 
подлежат все запросы - проще и правильнее сделать handler на 
уровне location.

-- 
Maxim Dounin
http://nginx.org/



Подробная информация о списке рассылки nginx-ru