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