Заметки об исходном коде Nginx — очки знаний

задняя часть сервер HTTP Nginx

Примечания к исходному коду Nginx — предварительное условие

В этой статье обобщаются отрывочные сведения об части исходного кода Nginx, обрабатывающей протокол HTTP, для дальнейшего использования.

Путь долгий и есть много экспертов.Мы должны проявлять настойчивость и иметь отношение к постоянному обучению.

Содержание этой статьи

инструменты отладки

  • Тестовый пример — Test::Nginx (perl)

  • Проверка на утечку памяти - valgrind (worker_processes 1; daemon off; master_process off;), no-pool-patch

    valgrind --log-file=valgrid.log --leak-check=full --leak-resolution=high \
             --track-origins=yes --show-reachable=yes
    
    root@laptop:/usr/local/src/nginx-1.4.3# patch -p1 <../no-pool-nginx/nginx-1.4.3-no_pool.patch
    
  • файл стресса valgrind — Автоматизируйте тестирование valgrind.

  • Одношаговая отладка — gdb, cgdb

  • стек вызовов - pstack, strace, lstrace, systemtap, -finstrument-functions, valgrind --tool=callgrind

  • Стресс-тест - ab, httperf, wrk

  • Измерение реального трафика — tcpcopy, goreplay, ngx-http-mirror-module

просто несколько слов

  • Функция обратного вызова синтаксического анализа инструкций, которая может возвращать строку, описывающую сообщение об ошибке ("дублируется"). Это сообщение об ошибке будет объединено Nginx в полное сообщение и распечатано в терминале:

    nginx: [emerg] "spent_prefix" directive is duplicate in /usr/local/nginx/conf/nginx.conf:101
    
  • Функция создания структуры конфигурации, возвратNULLИли фактическая структура. вернутьNULL, Nginx не будет печатать никаких сообщений об ошибках. Итак, лучше всего использоватьngx_conf_log_errorФункция печатает сообщение об ошибке вручную.

  • Преобразователи типов, предоставляемые Nginx%VСоответствующий типngx_str_t *, вместоngx_str_t.

  • ngx_cpystrn(u_char *dst, u_char *src, size_t n)третий параметр функцииnинструктироватьdstМаксимальная длина соответствующего блока памяти (включая завершающий нулевой байт, см. функциюsnprintfопределение функции).

  • ngx_str_tТип имеет только два члена, из которыхngx_str_t::dataУказатель указывает на начальный адрес строки,ngx_str_t::lenУказывает эффективную длину строки.ngx_str_t::dataможет не указывать на обычную строку и не может начинаться с\0конец, так что используйтеngx_str_tдолжно быть основано на длинеngx_str_t::lenЗначение определяет длину строки.

  • ngx_buf_tа такжеngx_chain_t
    • ngx_buf_tОбъекты, которые могут быть представлены: блоки памяти, файлы на диске и специальные флаги;
    • ngx_buf_tобычно иngx_chain_tПарное использование:ngx_chain_tБудуngx_buf_tУпаковывается в односвязный узел списка, а затем Nginx используетngx_chain_tСформировать односвязный список для представления логически непрерывных данных;
  • Различайте функции следующих четырех функций обратного вызова, которые являются ключом к пониманию потока обработки запроса:

    c->read->handler = ngx_http_request_handler;
    c->write->handler = ngx_http_request_handler;
    r->read_event_handler = ngx_http_block_reading;
    r->write_event_handler = ngx_http_block_reading;
    

этап запроса

Nginx делит процесс обработки HTTP-запроса на несколько этапов (PHASE), каждому этапу соответствуетphase checkerВызовите функции обратного вызова, предоставляемые каждым модулем, одну за другой в порядке регистрации, то естьphase handler. для всех запросовphase checkerа такжеphase handlerПорядок выполнения — когда процесс Nginx запускается, вngx_http_init_phase_handlersопределяется в функции.

Этапы, определенные Nginx, перечислены ниже, аphase checkerможно справитьсяphase handlerвозвращаемое значение.

POST_READ

на данном этапеphase checkerфункцияngx_http_core_generic_phase. Каждый модуль регистрируется на этом этапеphase handlerПоток обработки запроса можно контролировать с помощью следующих возвращаемых значений:

код ошибки Как обращаться
NGX_OK Переместить запрос на следующий этап обработки (пропустить обработчик фазы, который не был вызван на этом этапе)
NGX_DECLINED Вызвать обработчик следующей фазы для запроса (может быть, этой фазы или следующей фазы)
NGX_AGAIN/NGX_DONE Текущий обработчик фазы должен быть вызван снова для запроса
разное код ошибкиNGX_ERRORилиNGX_HTTP_*При ожидании завершить текущий запрос досрочно

Зарегистрирован на данном этапе в собственном модуле Nginxphase handlerМодули:

  • ngx_http_realip_module - Change the client address to the one sent in the specificed header field.

SERVER_REWRITE

на данном этапеphase checkerФункцияngx_http_core_rewrite_phase. Каждый модуль регистрируется на этом этапеphase handlerПоток обработки запроса можно контролировать с помощью следующих возвращаемых значений:

код ошибки Как обращаться
NGX_DECLINED Вызвать обработчик следующей фазы для запроса (может быть, этой фазы или следующей фазы)
NGX_DONE Текущий обработчик фазы должен быть вызван снова для запроса
разное код ошибкиNGX_OK, NGX_AGAIN, NGX_ERRORилиNGX_HTTP_xxждать, завершить текущий запрос досрочно

Зарегистрирован на данном этапе в собственном модуле Nginxphase handlerМодули:

  • ngx_http_rewrite_module- реализация определена вserver {}изrewrite, set, ifи другие инструкции.

FIND_CONFIG

на данном этапеphase checkerФункцияngx_http_core_find_config_phase. Этот этап относится к внутреннему процессу Nginx и не позволяет регистрировать модули.phase handler.

ngx_http_core_find_config_phaseфункция по запросуuriсоответствовать соответствующемуlocation {}блок конфигурации.

REWRITE

на данном этапеphase checkerФункцияngx_http_core_rewrite_phase. Каждый модуль регистрируется на этом этапеphase handlerВозвращаемые значения, которые можно использовать, и то, как Nginx обрабатывает эти возвращаемые значения иSERVER_REWRITEФазы одинаковые.

Зарегистрирован на данном этапе в собственном модуле Nginxphase handlerМодули:

  • ngx_http_rewrite_module- реализация определена вlocation {}изrewrite, set, ifи другие инструкции.

POST_REWRITE

на данном этапеphase checkerФункцияngx_http_core_post_rewrite_phase. Этот этап относится к внутреннему процессу Nginx и не позволяет регистрировать модули.phase handler.

Проверить на этом этапеREWRITEРезультат выполнения этапа и выполнение разной логики: если запросuriЕсли изменено предыдущим этапом (r->uri_changed = 1), этот запрос направляетсяFIND_CONFIGэтап, переделатьlocation {}Найдите и сопоставьте; если требуетсяuriЕсли не было изменено на предыдущем этапе, продолжайте вызывать запросPREACCESSсценаphase handler.

PREACCESS

на данном этапеphase checkerФункцияngx_http_core_generic_phase. Каждый модуль регистрируется на этом этапеphase handlerВозвращаемые значения, которые можно использовать, и то, как Nginx обрабатывает эти возвращаемые значения иPOST_READФазы одинаковые.

Зарегистрирован на данном этапе в собственном модуле Nginxphase handlerМодули:

  • ngx_http_limit_conn_module - limits the number of connections per the defined key, in particular, the number of of connections from a single IP address.
  • ngx_http_limit_req_module - limits the request processing rate per the defined key, in particular, the processing rate of requests coming from a single IP address.
  • ngx_http_degradation_module - returns 204 or 444 code for some locations on low memory condition.
  • ngx_http_realip_module - Change the client address to the one sent in the specificed header field.

ACCESS

на данном этапеphase checkerФункцияngx_http_core_access_phase. Каждый модуль регистрируется на этом этапеphase handlerПоток обработки запроса можно контролировать с помощью следующих возвращаемых значений:

код ошибки Как обращаться
r != r->main Текущий запрос является подзапросом и напрямую передается на следующий этап обработки.
NGX_DECLINED Вызвать обработчик следующей фазы для запроса (может быть, этой фазы или следующей фазы)
NGX_AGAIN/NGX_DONE Текущий обработчик фазы должен быть вызван снова для запроса
NGX_OK
  • SATISFY_ALL: вызвать обработчик следующей фазы для запроса (может быть эта фаза или следующая фаза)
  • SATISFY_ANY: r->access_codeнаделять0значение и перенаправить запрос на следующий этап обработки
NGX_HTTP_FORBIDDEN
  • SATISFY_ALL: досрочно завершить текущий запрос
  • SATISFY_ANY: присвоить код ошибкиr->access_codeпеременную и вызовите обработчик следующей фазы для запроса.
NGX_HTTP_UNAUTHORIZED логика обработки иNGX_HTTP_FORBIDDENтакой же
разное код ошибкиNGX_ERRORилиNGX_HTTP_*При ожидании завершить текущий запрос досрочно

Зарегистрирован на данном этапе в собственном модуле Nginxphase handlerМодули:

  • ngx_http_auth_basic_module - limits access to resources by validating the user name and password using the "HTTP Basic Authentication" protocol.
  • ngx_http_access_module - limits access to certain client addresses.

POST_ACCESS

на данном этапеphase checkerФункцияngx_http_core_post_access_phase. Этот этап относится к внутреннему процессу Nginx и не позволяет регистрировать модули.phase handler.

Проверить на этом этапеACCESSобработать результат этапа и выполнить другую логику: еслиr->access_code == NGX_HTTP_FORBIDDENзатем завершите обработку запроса досрочно (используяNGX_HTTP_FORBIDDENкак код ответа HTTP); еслиr->access_codeдля других не0значение, завершить обработку запроса досрочно; еслиr->access_code == 0значение, вызовите следующий запросphase handler.

TRY_FILES (PRECONTENT)

ПРИМЕЧАНИЯ. Начиная с Nginx 1.13.4, этот этап был переименованPRECONTENTи использоватьngx_http_core_generic_phaseтак какphase checker.try_filesФункция инструкции контролируется модулемngx_http_try_files_moduleпоставка.

commit 129b06dc5dfab7b4513a4f274b3778cd9b8a6a22
Author: Roman Arutyunyan <arut@nginx.com>
Date:   Thu Jul 20 15:51:11 2017 +0300

    Precontent phase.

    The phase is added instead of the try_files phase.  Unlike the old phase, the
    new one supports registering multiple handlers.  The try_files implementation is
    moved to a separate ngx_http_try_files_module, which now registers a precontent
    phase handler.

В версиях до Nginx 1.13.4phase checkerФункцияngx_http_core_try_files_phase. Этот этап относится к внутреннему процессу Nginx и не позволяет регистрировать модули.phase handler.

Если предлагается использоватьlocation {}блок не настроенtry_filesуказание переадресовать запрос следующемуphase handler.

Если предлагается использоватьlocation {}используется вtry_filesкоманду, то продолжить проверку параметров команды: если файл статического диска, соответствующий параметру (кроме последнего параметра), существует, вернуть клиенту содержимое статического файла; если файл статического диска, соответствующий параметру, существует не существует, используйте функциюngx_http_internal_redirectперенаправить запрос наtry_filesуказывается последним параметром командыlocationПосле этого повторно обработайте запрос.

CONTENT

на данном этапеphase checkerФункцияngx_http_core_content_phase. Каждый модуль регистрируется на этом этапеphase handlerПоток обработки запроса можно контролировать с помощью следующих возвращаемых значений:

код ошибки Как обращаться
r->content_handler еслиlocation {}Настроено сcontent handler, использовать его для обработки запросов и игнорировать другиеphase handler
NGX_DECLINED Вызов обработчика следующей фазы для запроса. Если все обработчики фазы были вызваны, завершите обработку запроса (используя код ответа:NGX_HTTP_FORBIDDEN(URI запроса заканчивается на '/') илиNGX_HTTP_NOT_FOUND(URI запроса не заканчивается на '/'))
разное Завершите поток обработки запроса (код ошибки какngx_http_finalize_requestпараметры функции)

Как видно из вышеприведенного анализа, данные ответа на запрос можно определить поcontent handlerфункция илиphase handlerпредусмотрена функция.content handlerсоотношение приоритетовphase handlerвысокий и эксклюзивный.phase handlerможно рассматривать какCONTENTStage обеспечивает общую логику обработки запросов, аcontent handlerэтоlocation {}Блоки обеспечивают специальную логику обработки запросов.

Зарегистрирован на данном этапе в собственном модуле Nginxphase handlerМодули:

  • ngx_http_random_index_module - processes requests ending with the slash character ('/') and picks a random file in a directory to serve as an index file.
  • ngx_http_index_module - processes requests ending with the slash character ('/').
  • ngx_http_autoindex_module - processes requests ending with the slash character ('/') and produces a directory listings.
  • ngx_http_dav_module - intended for file management automation via the WebDAV protocol. The module processes HTTP and WebDAV methods PUT, DELETE, MKCOL, COPY, and MOVE.
  • ngx_http_gzip_static_module - allows sending precompressed files with the ".gz" filename extension instead of regular files.
  • ngx_http_static_module- Статический модуль ответа файла

Собственный модуль Nginx предоставляетcontent handlerиз них:

  • ngx_http_fastcgi_module
  • ngx_http_scgi_module
  • ngx_http_memcached_module
  • ngx_http_proxy_module
  • ngx_http_stub_status_module
  • ngx_http_flv_module
  • ngx_http_mp4_module
  • ngx_http_empty_gif_module
  • ngx_http_perl_module
  • ngx_http_uwsgi_module

LOG

Эта стадия особенная, она не соответствуетphase checker, на данном этапеphase handlerПо окончании обработки запроса,ngx_http_log_requestфункция вызывается напрямую.

Зарегистрирован на данном этапе в собственном модуле Nginxphase handlerМодули:

  • ngx_http_log_module

заказ модуля

В стандартной конфигурации,filterПорядок вызова модулей (обратный порядку инициализации модулей) следующий:

последовательность вызовов имя модуля предоставленный фильтр
1 ngx_http_not_modified_filter_module header
2 ngx_http_range_body_filter_module body
3 ngx_http_copy_filter_module body
4 ngx_http_headers_filter_module header
third party filter goes here
6 ngx_http_userid_filter_module header
7 ngx_http_ssi_filter_module header and body
8 ngx_http_charset_filter_module header and body
9 ngx_http_postpone_filter_module body
10 ngx_http_gzip_filter_module header and body
11 ngx_http_range_header_filter_module header
12 ngx_http_chunked_filter_module header and body
13 ngx_http_header_filter_module header
14 ngx_http_write_filter_module body

поле данных

ngx_connection_t::data

Это поле имеет множество применений, оно должно бытьngx_connection_tСостояние изменяется для представления различных значений:

  • Когда соединение повторно используется в пуле незанятых соединений Nginx (односвязный список), это поле указателя действует как указатель для узлов односвязного списка.nextуказатель:
  • После того, как клиент и Nginx установят TCP-соединение, прежде чем Nginx начнет считывать и обрабатывать данные HTTP-запроса в TCP-соединении, поле указателя указывает наngx_http_connection_tпеременная типа. В этой переменной хранится информация, относящаяся к «HTTP-соединению», например виртуальный хост, соответствующий HTTP-запросу, структура конфигурации виртуального хоста и имя хоста SSL.
  • При последующей обработке HTTP-запроса (прием данных запроса, формирование данных ответа и т. д.) это поле всегда указывает на текущий активный запрос по TCP-соединению (из-за технологии HTTP Pipeline, механизма подзапросов Nginx и т. д., текущее TCP-соединение может соответствовать нескольким экземплярам запроса). Данные ответа на этот запрос могут быть немедленно отправлены клиенту.

ngx_connection_t::buffered

TODO: More explanation needed.

ngx_http_request_t::postponed

когда значение поля указателя неNULLпри указании на тип узла, которыйngx_http_postponed_request_tодносвязный список. Узлы этого односвязного списка содержат подзапросы, созданные запросом (ngx_http_postponed_request_t::request), или данные ответа, сгенерированные запросом, который временно не может быть отправлен (ngx_http_postponed_request_t::out).

Когда значение поля указателяNULL, у запроса нет отложенных подзапросов.

ngx_http_request_t::posted_requests

Это поле указывает на тип узла,ngx_http_posted_request_tодносвязный список. Этот односвязный список содержит «готовые» запросы по запросу (основной запрос), и эти запросы могут быть запланированы и обработаны Nginx в любое время.

Nginx поддерживает список «готовых» запросов только для «основного запроса», а «готовые» запросы могут быть основными запросами, подзапросами, подзапросами и так далее. функцияngx_http_post_requestИспользуется для добавления «готового» запроса в список, функцияngx_http_run_posted_requestsИспользуется для планирования «готовых» запросов.

ngx_http_request_t::valid_location

TODO: More explanation needed.

когдаrewriteИспользование инструкцииbreakотредактированоr->uriПосле запроса эта переменная флага устанавливается в 0; если запросngx_http_internal_redirectЕсли функция перенаправляется внутрь Nginx, этот флаг сбрасывается в 1.

ngx_http_request_t::uri_changed

TODO: More explanation needed.

когдаrewriteВ инструкции используется не-breakотредактированоr->uriПосле этого эта переменная флага устанавливается в 1;

ngx_http_request_t::count

Запросить подсчет ссылок. Что касается его роли, он был представлен в разделе 11.8 «Углубленное понимание Nginx: разработка модулей и анализ архитектуры», 1-е издание:

> 在 HTTP 模块中每进行一类新的(异步)操作,包括为一个请求添加新的事件,或者把一些已经
> 由定时器、epoll 中移除事件重新加放其中,都需要把这个请求的引用计数加 1.这是因为需要让
> HTTP 框架知道,HTTP 模块对于该请求有独立的异步处理机制,将由该 HTTP 模块决定这个操作
> 什么时候结束,防止在这个操作还未结束时 HTTP 框架却把这个请求销毁了(如其它 HTTP 模块通
> 过调用 ngx_http_finalize_request 方法要求 HTTP 框架结束请求),异致请求出现不可知的
> 严重错误。这就要求每个操作在 “认为” 自身的动作结束时,都得最终调用
> ngx_http_close_request 方法,该方法会自动检查引用计数,当引用计数为 0 时才真正地销销
> 毁请求。

Резюме: чтобы добавить ветвь асинхронного выполнения к текущему процессу выполнения запроса, необходимо увеличить счетчик ссылок для основного запроса. Например, когда тело пакета запроса необходимо прочитать через «читаемое событие», когда создается подзапрос;

ngx_http_requeste_t::out

использоватьngx_chain_tнатянутыйngx_buf_tСвязанный список, используемый для сохранения отправляемых данных ответа.

Кроме того, модуль Nginx вызывает функциюngx_http_output_filterОтправьте данные ответа через цепочку выходных фильтров. Если данные ответа были обработаны выходным фильтром, но не полностью отправлены по сетевым причинам, они могут быть переданы после того, как произойдет «событие, доступное для записи» соединения.ngx_http_output_filter(r, NULL)Форма вызова продолжает отправлять.

ngx_event_t::active

Управляет ли модуль событий, используемый Nginx, структурой событий.

ngx_event_t::ready

Готова ли структура события (с необработанными событиями).

вызов функции

ngx_http_close_connection

Эта функция используется для закрытия соединения.

подпись функции:
void
ngx_http_close_connection(ngx_connect_t *c);
Основная функция:

функцияngx_close_connectionПосле очистки всех событий (сетевых событий, событий тайм-аута), зарегистрированных соединением из модуля событий, закройте базовый дескриптор сокета. При этом звонитеngx_free_connectionФункция сохраняет связанную структуру в односвязном списке.ngx_cycle->free_connectionsдля следующего использования.

Эта функция очищает связанную с SSL структуру, соответствующую соединению, закрывает пул памяти, соответствующий соединению, а затем вызываетngx_close_connectionФункция выполняет другую работу по очистке.

ngx_http_finalize_connection

Эта функция вызывается после завершения обычной обработки запроса.ngx_http_close_requestЗакройте запрос (количество ссылок запроса минус один) и определите, следует ли закрыть соединение или оставить его (поддерживать активное соединение).

подпись функции:
static void
ngx_http_finalize_connection(ngx_http_request_t *r);

ngx_http_termniate_request

Принудительная очистка и уничтожение запроса.

подпись функции:
static void
ngx_http_terminate_request(ngx_http_request_t *r, ngx_int_t rc);
Основная функция:
Эта функция вызывает обработчик очистки, зарегистрированный в запросе, и устанавливает счетчик ссылок равным 1, а затем используетnxx_http_close_requestФункция уничтожает запрос.

ngx_http_free_request

Эта функция очищает и уничтожает запрос.

подпись функции:
void
ngx_http_free_request(ngx_http_request_t *r, ngx_int_t rc);
Основная функция:
Эта функция вызывается как обработчик очистки, зарегистрированный в запросе, и вызывается для запроса.LOGсценаphase handler, а затем уничтожьте пул памяти запроса.

ngx_http_close_request

Эта функция закрывает ссылку на запрос.

подпись функции:
static void
ngx_http_close_request(ngx_http_request_t *r, ngx_int_t rc);
Основная функция:
Функция будет запрашиватьrосновной запрос (r->main) количество ссылок (r->main->count) минус 1. Если счетчик ссылок основного запроса равен 0, вызовитеngx_http_free_requestФункция очищает и уничтожает основной запрос, вызываяngx_http_close_connectionФункция очищает и уничтожает соединение, используемое запросом.

ngx_http_finalize_request

Эта функция определяет следующий поток обработки запроса в соответствии с результатом обработки запроса.

подпись функции:
void
ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc);
Основная функция:
Функция этой функции более сложная, и есть много логических ответвлений. Далее устанавливаем параметры согласноrcЗначение и текущий статус запроса обобщают основной поток ветвей и метод обработки этой функции (используя номер версии исходного кода: 1.13.6):
заказ условие перехода Как обращаться
запуск функции
1 rc == NGX_DONE Текущее действие запроса было обработано, но над запросом выполняются другие асинхронные действия. передачаngx_http_finalize_connectionФункция уменьшает счетчик ссылок запроса на единицу.RETURN
2 rc == DECLINED Обработчик содержимого не может обработать запрос, поэтому он будет обработан обработчиком фазы в фазе СОДЕРЖИМОЕ.RETURN
3 значение rcNGX_ERROR,NGX_HTTP_REQUEST_TIMEOUT,NGX_HTTP_CLIENT_CLOSE_REQUESTодин из кодов ошибок илиc->error == 1 Произошла ошибка в соединении, по которому был сделан запрос, вызываяngx_http_terminate_requestПринудительная очистка Уничтожает запрос.RETURN
4 rc >= NGX_HTTP_SPECIAL_RESPONSEили значение rc равноNGX_HTTP_CREATED,NGX_HTTP_NO_CONTENTодин из Если значение rc равноNGX_HTTP_CLOSE(больше, чемNGX_HTTP_SPECIAL_RESPONSE), срочно звонитеngx_http_terminate_requestУничтожить запрос; в противном случае вызвать функциюngx_http_special_response_handlerВосстановите данные ответа для этого запроса. Затем вам нужно снова вызвать функциюngx_http_finalize_requestиметь дело сngx_http_special_response_handlerВозвращаемое значение.RETURN
Ответ на запрос отправлен, данные ответа на запрос не отправлены, запрос является подзапросом и т. д. Нормальный бизнес-процесс продолжает разветвляться.
5 r != r->main

Когда текущий запрос является «подзапросом», функция продолжает следующий поток обработки:

  1. Если подзапрос является «фоновым подзапросом», Nginx считает, что подзапрос уже обработан. установить егоr->doneЗначение равно 1, затем вызывается функцияngx_http_finalize_connectionОчищает счетчик ссылок, который он занимает.RETURN
    • «Фоновый подзапрос» не участвует в процессе генерации ответа, поэтому не повлияет на время ответа основного запроса. Но он сохранит ссылку на основной запрос. Из текущей реализации Nginx этот тип запроса может быть вызван только один раз.ngx_http_finalize_request.
  2. Если подзапрос не является "фоновым подзапросом" и данные ответа отправлены не полностью (r->buffered == 1) или не все подзапросы, созданные этим подзапросом, выполнены (r->postponed != NULL), используя функциюngx_http_set_write_handlerНапишите обработчик события для его регистрацииngx_http_writerПродолжить обработку запроса при возникновении события.RETURN
    • Если данные не отправлены полностью из-за того, что буфер отправки сокета заполнен, то естьr->buffered == 1, то, как только буфер освободится, «событие, доступное для записи», снова вызовет логику обработки подзапроса;
    • Если подзапрос не является «активным запросом на соединение», то естьr->postponed != NULL, цикл обработки событий не будет повторно выдавать «события, доступные для записи», чтобы вызвать повторное выполнение логики.
  3. Для обычного подзапроса, который был обработан, если это «активный запрос на соединение» (c->data == r), затем отметьте это как выполненное (r->done = 1) и его родительский запрос (r->parent) установлено значение «Активный запрос соединения». затем вызовите функциюngx_http_post_requestДобавьте родительский запрос к основному запросуposted_requestсвязанный список, так что функцияngx_http_run_posted_requestsвызовите его функцию обратного вызова записиwrite_event_handler, запустите поток его обработки.RETURN
6 r == r->main

Текущий запрос является «основным запросом», и функция продолжает следующий поток обработки:

  1. Если данные запроса не были отправлены (r->buffered || c->buffered) или есть ожидающие подзапросы (r->postponed) с помощью функцииngx_http_set_write_handlerНапишите обработчик события для его регистрацииngx_http_writerПродолжить обработку запроса при возникновении события.RETURN
  2. Что, если запрос не является «активным запросом на подключение» (r != c->data), чтобы приостановить поток обработки запросов.
  3. Когда запрос обработан, вызовите функциюngx_http_finalize_connectionЗакройте запрос и базовое соединение.RETURN
функция заканчивается

ngx_event_t::handler

Функция обратного вызова события, вызываемая непосредственно циклом событий.

подпись функции:
typedef void (*ngx_event_handler_pt)(ngx_event_t *ev);

Для HTTP-модуля Nginx после того, как Nginx обращается к клиентскому соединению, соединение выделяетсяngx_connection_tструктура. Структура содержит два соответствующих «события для чтения» и «события для записи».ngx_event_tчлен типаreadа такжеwrite, функции обратного вызова этих двух элементов будут вызываться при возникновении события. Ниже мы кратко перечисляем изменения значений этих двух функций обратного вызова по мере изменения статуса запроса:

  1. Функция вызова Nginxngx_event_acceptполучать доступ к соединениям и назначать ихngx_connection_tструктура:

    void
    ngx_event_accept(ngx_event_t *ev)
    {
        ...
        c = ngx_get_connection(s, ev->log);
        ...
        ls->handler(c);
        ...
    }
    
  2. Впоследствии Nginx вызывает функциюngx_http_init_connectionУстановите функцию обратного вызова «чтение события», чтобы подготовиться к получению данных запроса:

    void
    ngx_http_init_connection(ngx_connection_t *c)
    {
        ...
        rev = c->read;
        rev->handler = ngx_http_wait_request_handler;
        c->write->handler = ngx_http_empty_handler;
        ...
        if (rev->ready) {
            ...
            rev->handler(rev);
            return;
        }
        ...
        if (ngx_handle_read_event(rev, 0) != NGX_OK) {
            ...
        }
    }
    
  3. функцияngx_http_wait_request_handlerПрочитайте некоторые данные из соединения, затем создайте структуру запроса.ngx_request_t. Затем настройте функцию обратного вызова «читаемое событие» наngx_http_process_request_line, который используется для получения и анализа строки состояния запроса. В течение этого периода, если полученных данных недостаточно для создания полной строки состояния, Nginx зарегистрирует «читаемое событие» для соединения и продолжит выполнение при поступлении новых данных.

    void
    ngx_http_wait_request_handler(ngx_event_t *rev)
    {
        ...
        c->data = ngx_http_create_request(c);
        rev->handler = ngx_http_process_request_line;
        ngx_http_process_request_line(rev);
    }
    
    void
    ngx_http_process_request_line(ngx_event_t *rev)
    {
        ...
        for (;;) {
            if (rc == NGX_AGAIN) {
                n = ngx_http_read_request_header(r);
                if (n == NGX_AGAIN || n == NGX_ERROR) {
                    return;
                }
                ...
            }
            ...
            rev->handler = ngx_http_process_request_headers;
            ngx_http_process_request_headers(rev);
        }
    
    }
    
  4. После обработки строки состояния запроса Nginx настраивает функцию «прочитать событие».ngx_http_process_request_headers, для получения и разбора заголовков запросов. В течение этого периода, если полученных данных недостаточно для формирования полного заголовка, Nginx зарегистрирует «читаемое событие» для соединения и продолжит выполнение вниз при поступлении новых данных.

    void
    ngx_http_process_request_headers(ngx_event_t *ev)
    {
        ...
        n = ngx_http_read_request_header(r);
        if (n == NGX_AGAIN || n == NGX_ERROR) {
            return;
        }
        ...
        if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
            ...
            ngx_http_process_request(r);
            return;
        }
        ...
    }
    
  5. После того, как данные заголовка запроса получены и проанализированы, вызывается функцияngx_http_process_requestЗапустите процесс обработки запросов и формирования ответных данных. На этом этапе Nginx устанавливает действительную функцию обратного вызова «событие, доступное для записи» для соединения.

    • Затем и «события, доступные для чтения», и «события, доступные для записи» обрабатываются функцией обратного вызова.ngx_http_request_handlerобработка, он вызовет структуру запроса на основе типа событияngx_request_tсерединаread_event_handlerа такжеwrite_event_handlerФункция, на которую указывает член.
    • Поскольку Nginx уже получил требуемые данные запроса, при возникновении «читаемого события» он использует функциюngx_http_blocking_readingВременно заблокируйте это мероприятие.
    • Перед этим шагом нет необходимости обрабатывать «событие, доступное для записи» в соединении, а после этого нам нужно использовать этот управляемый событием запрос для завершения потока обработки PHASE (ngx_http_core_run_phases).
    • При этом каждый раз, когда происходит событие, Nginx также будет вызывать функциюngx_http_run_posted_requestsТриггер "готов" (posted, имеет значение "размещения" и "публикации", то есть этот тип запроса уже находится в состоянии готовности, ожидая запланированной обработки) Поток обработки запроса.
    void
    ngx_http_process_request(ngx_event_t *ev)
    {
        ...
        c->read->handler = ngx_http_request_handler
        c->write->handler = ngx_http_request_handler;
        r->read_event_handler = ngx_http_block_reading;
    
        ngx_http_handler(r);
        ngx_http_run_posted_requests(c);
    }
    
    void
    ngx_http_handler(ngx_http_request_t *r)
    {
        ...
        r->write_event_handler = ngx_http_core_run_phases;
        ngx_http_core_run_phases(r);
    }
    
    void
    ngx_http_request_handler(ngx_event_t *ev)
    {
        ...
        if (ev->write) {
            r->write_event_handler(r);
        } else {
            r->read_event_handler(r);
        }
    
        ngx_http_run_posted_requests(c);
    }
    
  6. С тех пор функции обратного вызова «событие для чтения» и «событие для записи» запроса практически не изменились. Поток обработки запросов на разных этапах определяетсяngx_request_t::read_event_handlerа такжеwrite_event_handlerЭти две функции решают.

ngx_request_t::read_event_handlerа такжеwrite_event_handler

После того, как данные запроса получены, обработка запроса переходит к этапам генерации ответа и отправки ответа. Эти две функции используются для управления потоком обработки запроса на разных этапах обработки.

write_event_handler:
    ngx_http_core_run_phases
    ngx_http_writer
    ngx_http_request_finalizer
    ngx_http_terminate_handler

read_event_handler:
    ngx_http_block_reading
    ngx_http_read_client_request_body_handler
    ngx_http_discarded_request_body_handler
    ngx_http_upstream_process_header

ngx_http_read_client_request_body

Прочтите тело запроса и сохраните его вngx_http_request_t::request_bodyсреди членов.

Эта функция увеличивает счетчик ссылок основного запроса по следующим причинам:

Функция вызова Nginxngx_http_read_client_request_bodyПри чтении тела пакета запроса может потребоваться отслеживать «читаемое событие» в соединении с помощью механизма обработки событий и использовать функцию обратного вызова чтения для продолжения чтения данных. Когда другие процессы запроса обрабатывают процесс «событие, доступное для записи», если запрос необходимо уничтожить из-за нормального процесса или исключения обработки, без защиты подсчета ссылок, запрос, используемый процессом «событие, доступное для чтения», будет недействительным. , и весь процесс будет недействителен.Процесс имеет серьезные последствия.

ngx_http_send_headerа такжеngx_http_output_filter

Используется для начала отправки заголовков и тел ответа.ngx_http_send_headerможно вызвать только один раз иngx_http_output_filterМожно вызывать несколько раз. но каждый разngx_http_output_filterРазличные части тела ответа должны быть отправлены, и данные ответа, которые не были отправлены в прошлый раз, будут временно сохранены вngx_http_request_tсередина. передачаngx_http_output_filter(r, NULL)Вы можете попробовать отправить данные ответа еще раз.

ngx_handle_read_eventа такжеngx_handle_write_event

Зарегистрируйте «события, доступные для чтения» и «события, доступные для записи» в цикле событий и убедитесь, что события не регистрируются повторно (еслиngx_event_tЕсли соответствующее событие отслеживается циклом обработки событий, функция возвращается напрямую).

переменная запроса

$request_body

Она содержит тело запроса, эта переменная может получить из нее данные тела тогда и только тогда, когда Nginx прочитал тело запроса и тело запроса не было записано во временный файл.