nginx-0.7.68/ 000755 001750 001750 00000000000 11501744771 012036 5 ustar 00is is 000000 000000 nginx-0.7.68/contrib/ 000755 001750 001750 00000000000 11501744765 013501 5 ustar 00is is 000000 000000 nginx-0.7.68/conf/ 000755 001750 001750 00000000000 11501744765 012766 5 ustar 00is is 000000 000000 nginx-0.7.68/src/ 000755 001750 001750 00000000000 11501744766 012631 5 ustar 00is is 000000 000000 nginx-0.7.68/auto/ 000755 001750 001750 00000000000 11501744766 013012 5 ustar 00is is 000000 000000 nginx-0.7.68/configure 000755 001750 001750 00000004277 11201627672 013754 0 ustar 00is is 000000 000000 #!/bin/sh
# Copyright (C) Igor Sysoev
. auto/options
. auto/init
. auto/sources
test -d $NGX_OBJS || mkdir $NGX_OBJS
echo > $NGX_AUTO_HEADERS_H
echo > $NGX_AUTOCONF_ERR
echo "#define NGX_CONFIGURE \"$NGX_CONFIGURE\"" > $NGX_AUTO_CONFIG_H
if [ $NGX_DEBUG = YES ]; then
have=NGX_DEBUG . auto/have
fi
if test -z "$NGX_PLATFORM"; then
echo "checking for OS"
NGX_SYSTEM=`uname -s 2>/dev/null`
NGX_RELEASE=`uname -r 2>/dev/null`
NGX_MACHINE=`uname -m 2>/dev/null`
echo " + $NGX_SYSTEM $NGX_RELEASE $NGX_MACHINE"
NGX_PLATFORM="$NGX_SYSTEM:$NGX_RELEASE:$NGX_MACHINE";
case "$NGX_SYSTEM" in
MINGW32_*)
NGX_PLATFORM=win32
;;
esac
else
echo "building for $NGX_PLATFORM"
NGX_SYSTEM=$NGX_PLATFORM
fi
. auto/cc/conf
if [ "$NGX_PLATFORM" != win32 ]; then
. auto/headers
fi
. auto/os/conf
if [ "$NGX_PLATFORM" != win32 ]; then
. auto/os/features
. auto/threads
fi
. auto/modules
. auto/lib/conf
case ".$NGX_PREFIX" in
.)
NGX_PREFIX=${NGX_PREFIX:-/usr/local/nginx}
have=NGX_PREFIX value="\"$NGX_PREFIX/\"" . auto/define
;;
.!)
NGX_PREFIX=
;;
*)
have=NGX_PREFIX value="\"$NGX_PREFIX/\"" . auto/define
;;
esac
if [ ".$NGX_CONF_PREFIX" != "." ]; then
have=NGX_CONF_PREFIX value="\"$NGX_CONF_PREFIX/\"" . auto/define
fi
have=NGX_SBIN_PATH value="\"$NGX_SBIN_PATH\"" . auto/define
have=NGX_CONF_PATH value="\"$NGX_CONF_PATH\"" . auto/define
have=NGX_PID_PATH value="\"$NGX_PID_PATH\"" . auto/define
have=NGX_LOCK_PATH value="\"$NGX_LOCK_PATH\"" . auto/define
have=NGX_ERROR_LOG_PATH value="\"$NGX_ERROR_LOG_PATH\"" . auto/define
have=NGX_HTTP_LOG_PATH value="\"$NGX_HTTP_LOG_PATH\"" . auto/define
have=NGX_HTTP_CLIENT_TEMP_PATH value="\"$NGX_HTTP_CLIENT_TEMP_PATH\""
. auto/define
have=NGX_HTTP_PROXY_TEMP_PATH value="\"$NGX_HTTP_PROXY_TEMP_PATH\""
. auto/define
have=NGX_HTTP_FASTCGI_TEMP_PATH value="\"$NGX_HTTP_FASTCGI_TEMP_PATH\""
. auto/define
. auto/make
. auto/lib/make
. auto/install
if [ "$NGX_PLATFORM" != win32 ]; then
. auto/unix
fi
# STUB
. auto/stubs
have=NGX_USER value="\"$NGX_USER\"" . auto/define
have=NGX_GROUP value="\"$NGX_GROUP\"" . auto/define
. auto/summary
nginx-0.7.68/LICENSE 000644 001750 001750 00000002456 11331556312 013043 0 ustar 00is is 000000 000000 /*
* Copyright (C) 2002-2010 Igor Sysoev
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
nginx-0.7.68/README 000644 001750 001750 00000000177 10513407122 012707 0 ustar 00is is 000000 000000
The Russian documentation is available at http://sysoev.ru/nginx/
The English documentation is available at http://nginx.net
nginx-0.7.68/html/ 000755 001750 001750 00000000000 11501744766 013006 5 ustar 00is is 000000 000000 nginx-0.7.68/CHANGES.ru 000644 001750 001750 00000514170 11501744770 013465 0 ustar 00is is 000000 000000
Изменения в nginx 0.7.68 14.12.2010
*) Исправление: если для пары IPv6-адрес:порт описан только один
сервер, то выделения в регулярных выражениях в директиве server_name
не работали.
*) Исправление: при использовании директивы auth_basic в рабочем
процессе мог произойти segmentation fault.
Спасибо Михаилу Лалетину.
*) Исправление: ответ SSI модуля мог передаваться не полностью после
команды include с параметром wait="yes"; ошибка появилась в 0.7.25.
Спасибо Максиму Дунину.
*) Исправление: директива sub_filter могла изменять регистр букв при
частичном совпадении.
*) Исправление: nginx считал большие пакеты SSLv2 как обычные текстовые
запросы.
Спасибо Miroslaw Jaworski.
*) Исправление: nginx мог закрывать IPv6 listen сокет во время
переконфигурации.
Спасибо Максиму Дунину.
Изменения в nginx 0.7.67 15.06.2010
*) Безопасность: рабочий процесс nginx/Windows мог завершаться аварийно
при запросе файла с неверной кодировкой UTF-8.
Изменения в nginx 0.7.66 07.06.2010
*) Безопасность: теперь nginx/Windows игнорирует имя потока файла по
умолчанию.
Спасибо Jose Antonio Vazquez Gonzalez.
*) Изменение: теперь charset-фильтр работает до SSI-фильтра.
*) Изменение: теперь в лог ошибок не пишется сообщение, если переменная
не найдена с помощью метода $r->variable().
*) Изменение: теперь keepalive соединения после запросов POST не
запрещаются для MSIE 7.0+.
Спасибо Adam Lounds.
*) Добавление: директивы proxy_no_cache и fastcgi_no_cache.
*) Добавление: теперь при использовании переменной $scheme в директиве
rewrite автоматически делается редирект.
Спасибо Piotr Sikora.
*) Добавление: директива chunked_transfer_encoding.
*) Добавление: переменные $geoip_city_continent_code, $geoip_latitude и
$geoip_longitude.
Спасибо Arvind Sundararajan.
*) Добавление: модуль ngx_http_image_filter_module теперь всегда
удаляет EXIF и другие данные, если они занимают больше 5% в
JPEG-файле.
*) Добавление: теперь директива msie_padding работает и для Chrome.
*) Изменение: теперь keepalive соединения запрещены для Safari.
Спасибо Joshua Sierles.
*) Исправление: nginx игнорировал значения "private" и "no-store" в
строке "Cache-Control" в заголовке ответа бэкенда.
*) Исправление: символ "&" при копировании в аргументы в правилах
rewrite не экранировался.
*) Исправление: nginx мог завершаться аварийно во время обработки
сигнала или при использовании директивы timer_resolution на
платформах, не поддерживающих методы kqueue или eventport.
Спасибо George Xie и Максиму Дунину.
*) Исправление: если временные файлы и постоянное место хранения
располагались на разных файловых системах, то у постоянных файлов
время изменения было неверным.
Спасибо Максиму Дунину.
*) Исправление: модуль ngx_http_memcached_module мог выдавать ошибку
"memcached sent invalid trailer".
Спасибо Максиму Дунину.
*) Исправление: nginx не мог собрать библиотеку zlib-1.2.4 из исходных
текстов.
Спасибо Максиму Дунину.
*) Исправление: модуль SSI в подзапросах использовал закэшированные в
основном запросе значения переменных $query_string, $arg_... и им
подобных.
*) Исправление: nginx не поддерживал HTTPS-рефереры.
*) Исправление: nginx/Windows мог не находить файлы, если путь в
конфигурации был задан в другом регистре; ошибка появилась в 0.7.65.
*) Исправление: переменная $date_local выдавала неверное время, если
использовался формат "%s".
Спасибо Максиму Дунину.
*) Исправление: nginx не поддерживал все шифры, используемые в
клиентских сертификатах.
Спасибо Иннокентию Еникееву.
*) Исправление: если ssl_session_cache не был установлен или установлен
в none, то при проверке клиентского сертификаты могла происходить
ошибка "session id context uninitialized"; ошибка появилась в 0.7.1.
*) Исправление: совместимость с OpenSSL-1.0.0 на 64-битном Linux.
Спасибо Максиму Дунину.
*) Исправление: geo-диапазон возвращал значение по умолчанию, если
диапазон включал в себя одну и более сетей размером /16 и не
начинался на границе сети размером /16.
*) Исправление: переменную $uid_got нельзя было использовать в SSI и
перловом модулях.
*) Исправление: рабочий процесс зависал при запросе файла FIFO.
Спасибо Vicente Aguilar и Максиму Дунину.
*) Исправление: значение переменной повторно экранировалось после
каждого вывода SSI-команды echo; ошибка появилась в 0.6.14.
*) Исправление: параметр stub в SSI-директиве include не использовался,
если пустой ответ имел код 200.
*) Исправление: блок, используемый в параметре stub в SSI-директиве
include, выводился с MIME-типом "text/plain".
*) Исправление: если проксированный или FastCGI запрос внутренне
перенаправлялся в другой проксированный или FastCGI location, то в
рабочем процессе мог произойти segmentation fault; ошибка появилась
в 0.7.65.
Спасибо Yichun Zhang.
*) Исправление: соединения IMAP к серверу Zimbra могло зависнуть до
таймаута.
Спасибо Alan Batie.
*) Исправление: nginx не поддерживал передачу chunk'ами для 201-ых
ответов.
Спасибо Julian Reich.
Изменения в nginx 0.7.65 01.02.2010
*) Безопасность: теперь nginx/Windows игнорирует пробелы в конце URI.
Спасибо Dan Crowley, Core Security Technologies.
*) Безопасность: теперь nginx/Windows игнорирует короткие имена файлов.
Спасибо Dan Crowley, Core Security Technologies.
*) Изменение: теперь для проксируемых ответов HTTP/0.9 в лог пишется
код ответа "009".
*) Изменение: теперь по умолчанию размер буфера директивы
large_client_header_buffers равен 8K.
Спасибо Andrew Cholakian.
*) Изменение: теперь по умолчанию используются следующие шифры SSL:
"HIGH:!ADH:!MD5".
*) Изменение: теперь протокол SSLv2 по умолчанию запрещён.
*) Изменение: теперь значение переменной $host всегда в нижнем регистре.
*) Добавление: файл conf/fastcgi.conf для простых конфигураций FastCGI.
*) Добавление: теперь при использовании переменных в директиве
proxy_pass не требуется задавать URI.
*) Добавление: переменная $ssl_session_id.
*) Исправление: если проксированный или FastCGI запрос внутренне
перенаправлялся в другой проксированный или FastCGI location, то
переменная $upstream_response_time могла иметь ненормально большое
значение; ошибка появилась в 0.7.63.
*) Исправление: если директива "expires modified" выставляла дату в
прошлом, то в строке заголовка ответа "Cache-Control" выдавалось
отрицательное число.
Спасибо Алексею Капранову.
*) Исправление: nginx закрывал соединение при запросе закэшированного
ответа с пустым телом.
Спасибо Piotr Sikora.
*) Исправление: nginx кэшировал 304 ответ, если в заголовке
проксируемого запроса была строка "If-None-Match".
Спасибо Tim Dettrick и David Kostal.
*) Исправление: nginx не считал запятую разделителем в строке
"Cache-Control" в строке заголовка бэкенда.
*) Исправление: закэшированные ответы ответов HTTP/0.9 неправильно
обрабатывались.
*) Исправление: nginx передавал сжатые ответы клиентам, не
поддерживающим сжатие, при настройках gzip_static on и gzip_vary
off; ошибка появилась в 0.8.16.
*) Исправление: nginx всегда добавлял строку "Content-Encoding: gzip" в
заголовок 304-ых ответов модуля ngx_http_gzip_static_module.
*) Исправление: оператор "!-x" не работал.
Спасибо Максиму Дунину.
*) Исправление: в рабочем процессе мог произойти segmentation fault при
использовании limit_rate в HTTPS сервере.
Спасибо Максиму Дунину.
*) Исправление: при записи в лог переменной $limit_rate в рабочем
процессе происходил segmentation fault.
Спасибо Максиму Дунину.
*) Исправление: nginx не поддерживал даты в 2038 году на 32-битных
платформах;
*) Исправление: nginx/Windows пытался дважды удалить временный файл при
перезаписи уже существующего файла.
*) Исправление: nginx/Windows пытался дважды переименовать временный
файл при перезаписи уже существующего файла.
*) Исправление: nginx/Windows мог не создать временный файл, файл в
кэше или файл с помощью директив proxy/fastcgi_store, если рабочий
процесс не имел достаточно прав для работы с каталогами верхнего
уровня.
*) Исправление: в поддержке кодировки UTF-8 директивой try_files в
nginx/Windows.
*) Исправление: ошибки при использовании кодировки UTF-8 в
ngx_http_autoindex_module.
Спасибо Максиму Дунину.
*) Исправление: модуль ngx_http_autoindex_module не показывал последний
слэш для линков на каталоги; ошибка появилась в 0.7.15.
*) Исправление: nginx не закрывал лог, заданный параметром конфигурации
--error-log-path; ошибка появилась в 0.7.53.
*) Исправление: директива "addition_types" была неверно названа
"addtion_types".
*) Исправление: неверная строка запроса в переменной $request
записывалась в access_log только при использовании error_log на
уровне info или debug.
Изменения в nginx 0.7.64 16.11.2009
*) Безопасность: теперь SSL/TLS renegotiation запрещён.
Спасибо Максиму Дунину.
*) Исправление: nginx передавал сжатые ответы клиентам, не
поддерживающим сжатие, при настройках gzip_static on и gzip_vary
off; ошибка появилась в 0.7.63.
*) Исправление: если были описаны имена .domain.tld, .sub.domain.tld и
.domain-some.tld, то имя .sub.domain.tld попадало под маску
.domain.tld.
*) Исправление: segmentation fault и зацикливания в resolver'е.
*) Исправление: в resolver'е.
Спасибо Артёму Бохану.
*) Исправление: порчи кэша resolver'а.
Спасибо Matthew Dempsky.
*) Исправление: утечки памяти в resolver'е.
Спасибо Matthew Dempsky.
Изменения в nginx 0.7.63 26.10.2009
*) Безопасность: теперь символы "/../" запрещены в строке "Destination"
в заголовке запроса.
*) Изменение: минимальная поддерживаемая версия OpenSSL - 0.9.7.
*) Изменение: параметр ask директивы ssl_verify_client изменён на
параметр optional и теперь он проверяет клиентский сертификат, если
он был предложен.
Спасибо Brice Figureau.
*) Добавление: теперь ключ -V показывает статус поддержки TLS SNI.
*) Добавление: переменная $ssl_client_verify.
Спасибо Brice Figureau.
*) Добавление: директива ssl_crl.
Спасибо Brice Figureau.
*) Исправление: использование переменной $ssl_client_cert портило
память; ошибка появилась в 0.7.7.
Спасибо Сергею Журавлёву.
*) Добавление: теперь стартовый загрузчик кэша работает в отдельном
процесс; это должно улучшить обработку больших кэшей.
*) Добавление: теперь временные файлы и постоянное место хранения могут
располагаться на разных файловых системах.
*) Исправление: nginx неверно считал размер кэша на диске.
*) Изменение: теперь директива "gzip_disable msie6" не запрещает сжатие
для MSIE 6.0 SV1.
*) Исправление: nginx всегда добавлял строку "Vary: Accept-Encoding" в
заголовок ответа, если обе директивы gzip_static и gzip_vary были
включены.
*) Добавление: параметр proxy директивы geo.
*) Добавление: модуль ngx_http_geoip_module.
*) Добавление: директива limit_rate_after.
Спасибо Ivan Debnar.
*) Добавление: директивы limit_req_log_level и limit_conn_log_level.
*) Исправление: теперь директива limit_req соответствует алгоритму
leaky bucket.
Спасибо Максиму Дунину.
*) Исправление: в модуле ngx_http_limit_req_module.
Спасибо Максиму Дунину.
*) Исправление: теперь nginx разрешает подчёркивания в методе запроса.
*) Исправление: директивы proxy_pass_header и fastcgi_pass_header" не
передавали клиенту строки "X-Accel-Redirect", "X-Accel-Limit-Rate",
"X-Accel-Buffering" и "X-Accel-Charset" из заголовка ответа
бэкенда.
Спасибо Максиму Дунину.
*) Исправление: в обработке строк "Last-Modified" и "Accept-Ranges" в
заголовке ответа бэкенда; ошибка появилась в 0.7.44.
Спасибо Максиму Дунину.
*) Добавление: директива image_filter_transparency.
*) Добавление: директива image_filter поддерживает переменные для
задания размеров.
*) Исправление: в поддержке альфа-канала PNG в модуле
ngx_http_image_filter_module.
*) Исправление: в поддержке прозрачности в модуле
ngx_http_image_filter_module.
*) Добавление: теперь можно использовать несколько директив
perl_modules.
*) Исправление: ответы модуля ngx_http_perl_module не работали в
подзапросах.
*) Исправление: nginx слал символ '\0' в строке "Location" в заголовке
в ответе на запрос MKCOL.
Спасибо Xie Zhenye.
*) Исправление: директива error_page не перенаправляла ошибку 413;
ошибка появилась в 0.6.10.
*) Исправление: в обработке ошибок выделения памяти.
Спасибо Максиму Дунину и Кириллу Коринскому.
Изменения в nginx 0.7.62 14.09.2009
*) Безопасность: при обработке специально созданного запроса в рабочем
процессе мог произойти segmentation fault.
Спасибо Chris Ries.
*) Добавление: переменная $upstream_cache_status.
*) Исправление: устаревший закэшированный запрос мог залипнуть в
состоянии "UPDATING".
*) Исправление: при использовании error_log на уровне info или debug в
рабочем процессе мог произойти segmentation fault.
Спасибо Сергею Боченкову.
*) Исправление: в обработке заголовков ответа, разделённых в
FastCGI-записях.
*) Исправление: XSLT-фильтр мог выдавать ошибку "not well formed XML
document" для правильного документа.
Спасибо Kuramoto Eiji.
*) Исправление: в MacOSX, Cygwin и nginx/Windows при проверке
location'ов, заданных регулярным выражением, теперь всегда делается
сравнение без учёта регистра символов.
*) Исправление: теперь nginx/Windows игнорирует точки в конце URI.
Спасибо Hugo Leisink.
*) Исправление: имя файла указанного в --conf-path игнорировалось при
установке; ошибка появилась в 0.6.6.
Спасибо Максиму Дунину.
*) Исправление: при использовании HTTP Basic-аутентификации на Windows
для неверных имени/пароля возвращалась 500-ая ошибка.
Изменения в nginx 0.7.61 22.06.2009
*) Исправление: nginx не собирался на MacOSX 10.6.
*) Исправление: nginx не собирался с параметром --without-http-cache;
ошибка появилась в 0.7.60.
*) Исправление: если использовался перехват 401 ошибки от бэкенда и
бэкенд не возвращал строку "WWW-Authenticate" в заголовке ответа, то
в рабочем процессе происходил segmentation fault.
Спасибо Евгению Мычло.
Изменения в nginx 0.7.60 15.06.2009
*) Добавление: параметр updating в директивах proxy_cache_use_stale и
fastcgi_cache_use_stale.
*) Добавление: директива keepalive_requests.
*) Исправление: во взаимодействии open_file_cache и proxy/fastcgi кэша
на старте.
*) Исправление: open_file_cache мог кэшировать открытые файлы очень
долго; ошибка появилась в 0.7.4.
*) Исправление: строки "If-Modified-Since", "If-Range" и им подобные в
заголовке запроса клиента передавались бэкенду при кэшировании, если
не использовалась директива proxy_set_header с любыми параметрами.
*) Исправление: строки "Set-Cookie" и "P3P" в заголовке ответа бэкенда
не скрывались при кэшировании, если не использовались директивы
proxy_hide_header/fastcgi_hide_header с любыми параметрами.
*) Исправление: модуль ngx_http_image_filter_module не понимал формат
GIF87a.
Спасибо Денису Ильиных.
*) Исправление: nginx не собирался на Solaris 10 и более ранних; ошибка
появилась в 0.7.56.
*) Исправление: XSLT-фильтр не работал в подзапросах.
*) Исправление: обработке относительных путей в nginx/Windows.
*) Исправление: в proxy_store, fastcgi_store, proxy_cache и
fastcgi_cache в nginx/Windows.
Изменения в nginx 0.7.59 25.05.2009
*) Добавление: директивы proxy_cache_methods и fastcgi_cache_methods.
*) Исправление: утечки сокетов; ошибка появилась в 0.7.25.
Спасибо Максиму Дунину.
*) Исправление: при использовании переменной $request_body в рабочем
процессе происходил segmentation fault, если в запросе не было тела;
ошибка появилась в 0.7.58.
*) Исправление: SSL-модули могли не собираться на Solaris и Linux;
ошибка появилась в 0.7.56.
*) Исправление: ответы модуля ngx_http_xslt_filter_module не
обрабатывались SSI-, charset- и gzip-фильтрами.
*) Исправление: директива charset не ставила кодировку для ответов
модуля ngx_http_gzip_static_module.
Изменения в nginx 0.7.58 18.05.2009
*) Добавление: директива listen почтового прокси-сервера поддерживает
IPv6.
*) Добавление: директива image_filter_jpeg_quality.
*) Добавление: директива client_body_in_single_buffer.
*) Добавление: переменная $request_body.
*) Исправление: в модуле ngx_http_autoindex_module в ссылках на имена
файлов, содержащих символ ":".
*) Исправление: процедура "make upgrade" не работала; ошибка появилась
в 0.7.53.
Спасибо Денису Латыпову.
Изменения в nginx 0.7.57 12.05.2009
*) Исправление: при перенаправлении ошибок модуля
ngx_http_image_filter_module в именованный location в рабочем
процессе происходил floating-point fault; ошибка появилась в 0.7.56.
Изменения в nginx 0.7.56 11.05.2009
*) Добавление: nginx/Windows поддерживает IPv6 в директиве listen
модуля HTTP.
*) Исправление: в модуле ngx_http_image_filter_module.
Изменения в nginx 0.7.55 06.05.2009
*) Исправление: параметры http_XXX в директивах proxy_cache_use_stale и
fastcgi_cache_use_stale не работали.
*) Исправление: fastcgi кэш не кэшировал ответы, состоящие только из
заголовка.
*) Исправление: ошибки "select() failed (9: Bad file descriptor)" в
nginx/Unix и "select() failed (10038: ...)" в nginx/Windows.
*) Исправление: при использовании директивы debug_connection в рабочем
процессе мог произойти segmentation fault; ошибка появилась в 0.7.54.
*) Исправление: в сборке модуля ngx_http_image_filter_module.
*) Исправление: файлы больше 2G не передавались с использованием
$r->sendfile.
Спасибо Максиму Дунину.
Изменения в nginx 0.7.54 01.05.2009
*) Добавление: модуль ngx_http_image_filter_module.
*) Добавление: директивы proxy_ignore_headers и fastcgi_ignore_headers.
*) Исправление: при использовании переменных "open_file_cache_errors
on" в рабочем процессе мог произойти segmentation fault; ошибка
появилась в 0.7.53.
*) Исправление: директива "port_in_redirect off" не работала; ошибка
появилась в 0.7.39.
*) Исправление: улучшение обработки ошибок метода select.
*) Исправление: ошибки "select() failed (10022: ...)" в nginx/Windows.
*) Исправление: в текстовых сообщениях об ошибках в nginx/Windows;
ошибка появилась в 0.7.53.
Изменения в nginx 0.7.53 27.04.2009
*) Изменение: теперь лог, указанный в --error-log-path, создаётся с
самого начала работы.
*) Добавление: теперь ошибки и предупреждения при старте записываются в
error_log и выводятся на stderr.
*) Добавление: при сборке с пустым параметром --prefix= nginx
использует как префикс каталог, в котором он был запущен.
*) Добавление: ключ -p.
*) Добавление: ключ -s на Unix-платформах.
*) Добавление: ключи -? и -h.
Спасибо Jerome Loyet.
*) Добавление: теперь ключи можно задавать в сжатой форме.
*) Исправление: nginx/Windows не работал, если файл конфигурации был
задан ключом -c.
*) Исправление: при использовании директив proxy_store, fastcgi_store,
proxy_cache или fastcgi_cache временные файлы могли не удаляться.
Спасибо Максиму Дунину.
*) Исправление: в заголовке Auth-Method запроса серверу аутентификации
почтового прокси-сервера передавалось неверное значение; ошибка
появилась в 0.7.34.
Спасибо Simon Lecaille.
*) Исправление: при логгировании на Linux не писались текстовые
описания системных ошибок; ошибка появилась в 0.7.45.
*) Исправление: директива fastcgi_cache_min_uses не работала.
Спасибо Андрею Воробьёву.
Изменения в nginx 0.7.52 20.04.2009
*) Добавление: первая бинарная версия под Windows.
*) Исправление: корректная обработка метода HEAD при кэшировании.
*) Исправление: корректная обработка строк "If-Modified-Since",
"If-Range" и им подобных в заголовке запроса клиента при кэшировании.
*) Исправление: теперь строки "Set-Cookie" и "P3P" скрываются в
заголовке ответа для закэшированных ответов.
*) Исправление: если nginx был собран с модулем ngx_http_perl_module и
perl поддерживал потоки, то при выходе основного процесса могла
выдаваться ошибка "panic: MUTEX_LOCK".
*) Исправление: nginx не собирался с параметром --without-http-cache;
ошибка появилась в 0.7.48.
*) Исправление: nginx не собирался на платформах, отличных от i386,
amd64, sparc и ppc; ошибка появилась в 0.7.42.
Изменения в nginx 0.7.51 12.04.2009
*) Добавление: директива try_files поддерживает код ответа в последнем
параметре.
*) Добавление: теперь в директиве return можно использовать любой код
ответа.
*) Исправление: директива error_page делала внешний редирект без строки
запроса; ошибка появилась в 0.7.44.
*) Исправление: если сервера слушали на нескольких явно описанных
адресах, то виртуальные сервера могли не работать; ошибка появилась
в 0.7.39.
Изменения в nginx 0.7.50 06.04.2009
*) Исправление: переменные $arg_... не работали; ошибка появилась в
0.7.49.
Изменения в nginx 0.7.49 06.04.2009
*) Исправление: при использовании переменных $arg_... в рабочем
процессе мог произойти segmentation fault; ошибка появилась в 0.7.48.
Изменения в nginx 0.7.48 06.04.2009
*) Добавление: директива proxy_cache_key.
*) Исправление: теперь nginx учитывает при кэшировании строки
"X-Accel-Expires", "Expires" и "Cache-Control" в заголовке ответа
бэкенда.
*) Исправление: теперь nginx кэширует только ответы на запросы GET.
*) Исправление: директива fastcgi_cache_key не наследовалась.
*) Исправление: переменные $arg_... не работали с SSI-подзапросами.
Спасибо Максиму Дунину.
*) Исправление: nginx не собирался с библиотекой uclibc.
Спасибо Timothy Redaelli.
*) Исправление: nginx не собирался на OpenBSD; ошибка появилась
в 0.7.46.
Изменения в nginx 0.7.47 01.04.2009
*) Исправление: nginx не собирался на FreeBSD 6 и более ранних версиях;
ошибка появилась в 0.7.46.
*) Исправление: nginx не собирался на MacOSX; ошибка появилась в 0.7.46.
*) Исправление: если использовался параметр max_size, то cache manager
мог удалить весь кэш; ошибка появилась в 0.7.46.
*) Изменение: в рабочем процессе мог произойти segmentation fault, если
директивы proxy_cache/fastcgi_cache и proxy_cache_valid/
fastcgi_cache_valid не были заданы на одном уровне; ошибка появилась
в 0.7.46.
*) Исправление: в рабочем процессе мог произойти segmentation fault при
перенаправлении запроса проксированному или FastCGI-серверу с
помощью error_page или try_files; ошибка появилась в 0.7.44.
Изменения в nginx 0.7.46 30.03.2009
*) Исправление: архив предыдущего релиза был неверным.
Изменения в nginx 0.7.45 30.03.2009
*) Изменение: теперь директивы proxy_cache и proxy_cache_valid можно
задавать на разных уровнях.
*) Изменение: параметр clean_time в директиве proxy_cache_path удалён.
*) Добавление: параметр max_size в директиве proxy_cache_path.
*) Добавление: предварительная поддержка кэширования в модуле
ngx_http_fastcgi_module.
*) Добавление: теперь при ошибках выделения в разделяемой памяти в логе
указываются названия директивы и зоны.
*) Исправление: директива "add_header last-modified ''" не удаляла в
заголовке ответа строку "Last-Modified"; ошибка появилась в 0.7.44.
*) Исправление: в директиве auth_basic_user_file не работал
относительный путь, заданный строкой без переменных; ошибка
появилась в 0.7.44.
Спасибо Jerome Loyet.
*) Исправление: в директиве alias, заданной переменными без ссылок на
выделения в регулярных выражениях; ошибка появилась в 0.7.42.
Изменения в nginx 0.7.44 23.03.2009
*) Добавление: предварительная поддержка кэширования в модуле
ngx_http_proxy_module.
*) Добавление: параметр --with-pcre в configure.
*) Добавление: теперь директива try_files может быть использована на
уровне server.
*) Исправление: директива try_files неправильно обрабатывала строку
запроса в последнем параметре.
*) Исправление: директива try_files могла неверно тестировать каталоги.
*) Исправление: если для пары адрес:порт описан только один сервер, то
выделения в регулярных выражениях в директиве server_name не
работали.
Изменения в nginx 0.7.43 18.03.2009
*) Исправление: запрос обрабатывался неверно, если директива root
использовала переменные; ошибка появилась в 0.7.42.
*) Исправление: если сервер слушал на адресах типа "*", то значение
переменной $server_addr было "0.0.0.0"; ошибка появилась в 0.7.36.
Изменения в nginx 0.7.42 16.03.2009
*) Изменение: ошибка "Invalid argument", возвращаемая
setsockopt(TCP_NODELAY) на Solaris, теперь игнорируется.
*) Изменение: при отсутствии файла, указанного в директиве
auth_basic_user_file, теперь возвращается ошибка 403 вместо 500.
*) Добавление: директива auth_basic_user_file поддерживает переменные.
Спасибо Кириллу Коринскому.
*) Добавление: директива listen поддерживает параметр ipv6only.
Спасибо Zhang Hua.
*) Исправление: в директиве alias со ссылками на выделения в регулярных
выражениях; ошибка появилась в 0.7.40.
*) Исправление: совместимость с Tru64 UNIX.
Спасибо Dustin Marquess.
*) Исправление: nginx не собирался без библиотеки PCRE; ошибка
появилась в 0.7.41.
Изменения в nginx 0.7.41 11.03.2009
*) Исправление: в рабочем процессе мог произойти segmentation fault,
если в server_name или location были выделения в регулярных
выражениях; ошибка появилась в 0.7.40.
Спасибо Владимиру Сопоту.
Изменения в nginx 0.7.40 09.03.2009
*) Добавление: директива location поддерживает выделения в регулярных
выражениях.
*) Добавление: директиву alias с ссылками на выделения в регулярных
выражениях можно использовать внутри location'а, заданного
регулярным выражением с выделениями.
*) Добавление: директива server_name поддерживает выделения в
регулярных выражениях.
*) Изменение: модуль ngx_http_autoindex_module не показывал последний
слэш для каталогов на файловой системе XFS; ошибка появилась в
0.7.15.
Спасибо Дмитрию Кузьменко.
Изменения в nginx 0.7.39 02.03.2009
*) Исправление: при включённом сжатии большие ответы с использованием
SSI могли зависать; ошибка появилась в 0.7.28.
Спасибо Артёму Бохану.
*) Исправление: при использовании коротких статических вариантов в
директиве try_files в рабочем процессе мог произойти segmentation
fault.
Изменения в nginx 0.7.38 23.02.2009
*) Добавление: логгирование ошибок аутентификации.
*) Исправление: имя/пароль, заданные в auth_basic_user_file,
игнорировались после нечётного числа пустых строк.
Спасибо Александру Загребину.
*) Исправление: при использовании длинного пути в unix domain сокете в
главном процессе происходил segmentation fault; ошибка появилась в
0.7.36.
Изменения в nginx 0.7.37 21.02.2009
*) Исправление: директивы, использующие upstream'ы, не работали; ошибка
появилась в 0.7.36.
Изменения в nginx 0.7.36 21.02.2009
*) Добавление: предварительная поддержка IPv6; директива listen модуля
HTTP поддерживает IPv6.
*) Исправление: переменная $ancient_browser не работала для браузеров,
заданных директивами modern_browser.
Изменения в nginx 0.7.35 16.02.2009
*) Исправление: директива ssl_engine не использовала SSL-акселератор
для асимметричных шифров.
Спасибо Marcin Gozdalik.
*) Исправление: директива try_files выставляла MIME-type, исходя из
расширения первоначального запроса.
*) Исправление: в директивах server_name, valid_referers и map
неправильно обрабатывались имена вида "*domain.tld", если
использовались маски вида ".domain.tld" и ".subdomain.domain.tld";
ошибка появилась в 0.7.9.
Изменения в nginx 0.7.34 10.02.2009
*) Добавление: параметр off в директиве if_modified_since.
*) Добавление: теперь после команды XCLIENT nginx посылает команду
HELO/EHLO.
Спасибо Максиму Дунину.
*) Добавление: поддержка Microsoft-специфичного режима
"AUTH LOGIN with User Name" в почтовом прокси-сервере.
Спасибо Максиму Дунину.
*) Исправление: в директиве rewrite, возвращающей редирект, старые
аргументы присоединялись к новым через символ "?" вместо "&";
ошибка появилась в 0.1.18.
Спасибо Максиму Дунину.
*) Исправление: nginx не собирался на AIX.
Изменения в nginx 0.7.33 02.02.2009
*) Исправление: если на запрос с телом возвращался редирект, то ответ
мог быть двойным при использовании методов epoll или rtsig.
Спасибо Eden Li.
*) Исправление: для некоторых типов редиректов в переменной
$sent_http_location было пустое значение.
*) Исправление: при использовании директивы resolver в SMTP
прокси-сервере в рабочем процессе мог произойти segmentation fault.
Изменения в nginx 0.7.32 26.01.2009
*) Добавление: теперь в директиве try_files можно явно указать проверку
каталога.
*) Исправление: fastcgi_store не всегда сохранял файлы.
*) Исправление: в гео-диапазонах.
*) Исправление: ошибки выделения больших блоков в разделяемой памяти,
если nginx был собран без отладки.
Спасибо Андрею Квасову.
Изменения в nginx 0.7.31 19.01.2009
*) Изменение: теперь директива try_files проверяет только файлы,
игнорируя каталоги.
*) Добавление: директива fastcgi_split_path_info.
*) Исправления в поддержке строки "Expect" в заголовке запроса.
*) Исправления в гео-диапазонах.
*) Исправление: при отсутствии ответа ngx_http_memcached_module
возвращал в теле ответа строку "END" вместо 404-ой страницы по
умолчанию; ошибка появилась в 0.7.18.
Спасибо Максиму Дунину.
*) Исправление: при проксировании SMPT nginx выдавал сообщение
"250 2.0.0 OK" вместо "235 2.0.0 OK"; ошибка появилась в 0.7.22.
Спасибо Максиму Дунину.
Изменения в nginx 0.7.30 24.12.2008
*) Исправление: в рабочем процессе происходил segmentation fault, если
в директивах fastcgi_pass или proxy_pass использовались переменные и
имя хоста должно было резолвиться; ошибка появилась в 0.7.29.
Изменения в nginx 0.7.29 24.12.2008
*) Исправление: директивы fastcgi_pass и proxy_pass не поддерживали
переменные при использовании unix domain сокетов.
*) Исправления в обработке подзапросов; ошибки появились в 0.7.25.
*) Исправление: ответ "100 Continue" выдавался для запросов версии
HTTP/1.0;
Спасибо Максиму Дунину.
*) Исправление: в выделении памяти в модуле ngx_http_gzip_filter_module
под Cygwin.
Изменения в nginx 0.7.28 22.12.2008
*) Изменение: в выделении памяти в модуле ngx_http_gzip_filter_module.
*) Изменение: значения по умолчанию для директивы gzip_buffers изменены
с 4 4k/8k на 32 4k или 16 8k.
Изменения в nginx 0.7.27 15.12.2008
*) Добавление: директива try_files.
*) Добавление: директива fastcgi_pass поддерживает переменные.
*) Добавление: теперь директива geo может брать адрес из переменной.
Спасибо Андрею Нигматулину.
*) Добавление: теперь модификатор location'а можно указывать без
пробела перед названием.
*) Добавление: переменная $upstream_response_length.
*) Исправление: теперь директива add_header не добавляет пустое
значение.
*) Исправление: при запросе файла нулевой длины nginx закрывал
соединение, ничего не передав; ошибка появилась в 0.7.25.
*) Исправление: метод MOVE не мог перемещать файл в несуществующий
каталог.
*) Исправление: если в сервере не был описан ни один именованный
location, но такой location использовался в директиве error_page, то
в рабочем процессе происходил segmentation fault.
Спасибо Сергею Боченкову.
Изменения в nginx 0.7.26 08.12.2008
*) Исправление: в обработке подзапросов; ошибка появилась в 0.7.25.
Изменения в nginx 0.7.25 08.12.2008
*) Изменение: в обработке подзапросов.
*) Изменение: теперь разрешаются POST'ы без строки "Content-Length" в
заголовке запроса.
*) Исправление: теперь директивы limit_req и limit_conn указывают
причину запрета запроса.
*) Исправление: в параметре delete директивы geo.
Изменения в nginx 0.7.24 01.12.2008
*) Добавление: директива if_modified_since.
*) Исправление: nginx не обрабатывал ответ FastCGI-сервера, если перед
ответом сервер передавал много сообщений в stderr.
*) Исправление: переменные "$cookie_..." не работали в SSI and в
перловом модуле.
Изменения в nginx 0.7.23 27.11.2008
*) Добавление: параметры delete и ranges в директиве geo.
*) Добавление: ускорение загрузки geo-базы с большим числом значений.
*) Добавление: уменьшение памяти, необходимой для загрузки geo-базы.
Изменения в nginx 0.7.22 20.11.2008
*) Добавление: параметр none в директиве smtp_auth.
Спасибо Максиму Дунину.
*) Добавление: переменные "$cookie_...".
*) Исправление: директива directio не работала с файловой системой XFS.
*) Исправление: resolver не понимал большие DNS-ответы.
Спасибо Zyb.
Изменения в nginx 0.7.21 11.11.2008
*) Изменения в модуле ngx_http_limit_req_module.
*) Добавление: поддержка EXSLT в модуле ngx_http_xslt_module.
Спасибо Денису Латыпову.
*) Изменение: совместимость с glibc 2.3.
Спасибо Eric Benson и Максиму Дунину.
*) Исправление: nginx не запускался на MacOSX 10.4 и более ранних;
ошибка появилась в 0.7.6.
Изменения в nginx 0.7.20 10.11.2008
*) Изменения в модуле ngx_http_gzip_filter_module.
*) Добавление: модуль ngx_http_limit_req_module.
*) Исправление: на платформах sparc и ppc рабочие процессы могли
выходить по сигналу SIGBUS; ошибка появилась в 0.7.3.
Спасибо Максиму Дунину.
*) Исправление: директивы вида "proxy_pass http://host/some:uri" не
работали; ошибка появилась в 0.7.12.
*) Исправление: при использовании HTTPS запросы могли завершаться с
ошибкой "bad write retry".
*) Исправление: модуль ngx_http_secure_link_module не работал внутри
location'ов с именами меньше 3 символов.
*) Исправление: переменная $server_addr могла не иметь значения.
Изменения в nginx 0.7.19 13.10.2008
*) Исправление: обновление номера версии.
Изменения в nginx 0.7.18 13.10.2008
*) Изменение: директива underscores_in_headers; теперь nginx по
умолчанию не разрешает подчёркивания в именах строк в заголовке
запроса клиента.
*) Добавление: модуль ngx_http_secure_link_module.
*) Добавление: директива real_ip_header поддерживает любой заголовок.
*) Добавление: директива log_subrequest.
*) Добавление: переменная $realpath_root.
*) Добавление: параметры http_502 и http_504 в директиве
proxy_next_upstream.
*) Исправление: параметр http_503 в директивах proxy_next_upstream или
fastcgi_next_upstream не работал.
*) Исправление: nginx мог выдавать строку "Transfer-Encoding: chunked"
для запросов HEAD.
*) Исправление: теперь accept-лимит зависит от числа worker_connections.
Изменения в nginx 0.7.17 15.09.2008
*) Добавление: директива directio теперь работает на Linux.
*) Добавление: переменная $pid.
*) Исправление: оптимизация directio, появившаяся в 0.7.15, не работала
при использовании open_file_cache.
*) Исправление: access_log с переменными не работал на Linux; ошибка
появилась в 0.7.7.
*) Исправление: модуль ngx_http_charset_module не понимал название
кодировки в кавычках, полученное от бэкенда.
Изменения в nginx 0.7.16 08.09.2008
*) Исправление: nginx не собирался на 64-битных платформах; ошибка
появилась в 0.7.15.
Изменения в nginx 0.7.15 08.09.2008
*) Добавление: модуль ngx_http_random_index_module.
*) Добавление: директива directio оптимизирована для запросов файлов,
начинающихся с произвольной позиции.
*) Добавление: директива directio при необходимости запрещает
использование sendfile.
*) Добавление: теперь nginx разрешает подчёркивания в именах строк в
заголовке запроса клиента.
Изменения в nginx 0.7.14 01.09.2008
*) Изменение: теперь директивы ssl_certificate и ssl_certificate_key не
имеют значений по умолчанию.
*) Добавление: директива listen поддерживает параметр ssl.
*) Добавление: теперь при переконфигурации nginx учитывает изменение
временной зоны на FreeBSD и Linux.
*) Исправление: параметры директивы listen, такие как backlog, rcvbuf и
прочие, не устанавливались, если сервером по умолчанию был не первый
сервер.
*) Исправление: при использовании в качестве аргументов части URI,
выделенного с помощью директивы rewrite, эти аргументы не
экранировались.
*) Исправление: улучшения тестирования правильности конфигурационного
файла.
Изменения в nginx 0.7.13 26.08.2008
*) Исправление: nginx не собирался на Linux и Solaris; ошибка появилась
в 0.7.12.
Изменения в nginx 0.7.12 26.08.2008
*) Добавление: директива server_name поддерживает пустое имя "".
*) Добавление: директива gzip_disable поддерживает специальную маску
msie6.
*) Исправление: при использовании параметра max_fails=0 в upstream'е с
несколькими серверами рабочий процесс выходил по сигналу SIGFPE.
Спасибо Максиму Дунину.
*) Исправление: при перенаправлении запроса с помощью директивы
error_page терялось тело запроса.
*) Исправление: при перенаправлении запроса с методом HEAD с помощью
директивы error_page возвращался полный ответ.
*) Исправление: метод $r->header_in() не возвращал значения строк
"Host", "User-Agent", и "Connection" из заголовка запроса; ошибка
появилась в 0.7.0.
Изменения в nginx 0.7.11 18.08.2008
*) Изменение: теперь ngx_http_charset_module по умолчанию не работает
MIME-типом text/css.
*) Добавление: теперь nginx возвращает код 405 для метода POST при
запросе статического файла, только если файл существует.
*) Добавление: директива proxy_ssl_session_reuse.
*) Исправление: после перенаправления запроса с помощью
"X-Accel-Redirect" директива proxy_pass без URI могла использовать
оригинальный запрос.
*) Исправление: если у каталога были права доступа только на поиск
файлов и первый индексный файл отсутствовал, то nginx возвращал
ошибку 500.
*) Исправление: ошибок во вложенных location'ах; ошибки появились в
0.7.1.
Изменения в nginx 0.7.10 13.08.2008
*) Исправление: ошибок в директивах addition_types, charset_types,
gzip_types, ssi_types, sub_filter_types и xslt_types; ошибки
появились в 0.7.9.
*) Исправление: рекурсивной error_page для 500 ошибки.
*) Исправление: теперь модуль ngx_http_realip_module устанавливает
адрес не для всего keepalive соединения, а для каждого запроса по
этому соединению.
Изменения в nginx 0.7.9 12.08.2008
*) Изменение: теперь ngx_http_charset_module по умолчанию работает со
следующими MIME-типами: text/html, text/css, text/xml, text/plain,
text/vnd.wap.wml, application/x-javascript и application/rss+xml.
*) Добавление: директивы charset_types и addition_types.
*) Добавление: теперь директивы gzip_types, ssi_types и
sub_filter_types используют хэш.
*) Добавление: модуль ngx_cpp_test_module.
*) Добавление: директива expires поддерживает суточное время.
*) Добавление: улучшения и исправления в модуле
ngx_http_xslt_module.
Спасибо Денису Латыпову и Максиму Дунину.
*) Исправление: директива log_not_found не работала при поиске
индексных файлов.
*) Исправление: HTTPS-соединения могли зависнуть, если использовались
методы kqueue, epoll, rtsig или eventport; ошибка появилась в 0.7.7.
*) Исправление: если в директивах server_name, valid_referers и map
использовалась маска вида "*.domain.tld" и при этом полное имя вида
"domain.tld" не было описано, то это имя попадало под маску; ошибка
появилась в 0.3.18.
Изменения в nginx 0.7.8 04.08.2008
*) Добавление: модуль ngx_http_xslt_module.
*) Добавление: переменные "$arg_...".
*) Добавление: поддержка directio в Solaris.
Спасибо Ivan Debnar.
*) Исправление: теперь, если FastCGI-сервер присылает строку "Location"
в заголовке ответа без строки статуса, то nginx использует код
статуса 302.
Спасибо Максиму Дунину.
Изменения в nginx 0.7.7 30.07.2008
*) Изменение: теперь ошибка EAGAIN при вызове connect() не считается
временной.
*) Изменение: значением переменной $ssl_client_cert теперь является
сертификат, перед каждой строкой которого, кроме первой, вставляется
символ табуляции; неизменённый сертификат доступен через переменную
$ssl_client_raw_cert.
*) Добавление: параметр ask директивы ssl_verify_client.
*) Добавление: улучшения в обработке byte-range.
Спасибо Максиму Дунину.
*) Добавление: директива directio.
Спасибо Jiang Hong.
*) Добавление: поддержка sendfile() в MacOSX 10.5.
*) Исправление: в MacOSX и Cygwin при проверке location'ов теперь
делается сравнение без учёта регистра символов; однако, сравнение
ограничено только однобайтными locale'ями.
*) Исправление: соединения почтового прокси-сервера зависали в режиме
SSL, если использовались методы select, poll или /dev/poll.
*) Исправление: ошибки при использовании кодировки UTF-8 в
ngx_http_autoindex_module.
Изменения в nginx 0.7.6 07.07.2008
*) Исправление: теперь при использовании переменных в директиве
access_log всегда проверяется существовании root'а для запроса.
*) Исправление: модуль ngx_http_flv_module не поддерживал несколько
значений в аргументах запроса.
Изменения в nginx 0.7.5 01.07.2008
*) Исправления в поддержке переменных в директиве access_log; ошибки
появились в 0.7.4.
*) Исправление: nginx не собирался с параметром
--without-http_gzip_module; ошибка появилась в 0.7.3.
Спасибо Кириллу Коринскому.
*) Исправление: при совместном использовании sub_filter и SSI ответы
могли передаваться неверно.
Изменения в nginx 0.7.4 30.06.2008
*) Добавление: директива access_log поддерживает переменные.
*) Добавление: директива open_log_file_cache.
*) Добавление: ключ -g.
*) Добавление: поддержка строки "Expect" в заголовке запроса.
*) Исправление: большие включения в SSI могли передавались не полностью.
Изменения в nginx 0.7.3 23.06.2008
*) Изменение: MIME-тип для расширения rss изменён на
"application/rss+xml".
*) Изменение: теперь директива "gzip_vary on" выдаёт строку
"Vary: Accept-Encoding" в заголовке ответа и для несжатых ответов.
*) Добавление: теперь при использовании протокола "https://" в
директиве rewrite автоматически делается редирект.
*) Исправление: директива proxy_pass не работала с протоколом HTTPS;
ошибка появилась в 0.6.9.
Изменения в nginx 0.7.2 16.06.2008
*) Добавление: теперь nginx поддерживает шифры с обменом EDH-ключами.
*) Добавление: директива ssl_dhparam.
*) Добавление: переменная $ssl_client_cert.
Спасибо Manlio Perillo.
*) Исправление: после изменения URI с помощью директивы rewrite nginx
не искал новый location; ошибка появилась в 0.7.1.
Спасибо Максиму Дунину.
*) Исправление: nginx не собирался без библиотеки PCRE; ошибка
появилась в 0.7.1.
*) Исправление: при редиректе запроса к каталогу с добавлением слэша
nginx не добавлял аргументы из оригинального запроса.
Изменения в nginx 0.7.1 26.05.2008
*) Изменение: теперь поиск location'а делается с помощью дерева.
*) Изменение: директива optimize_server_names упразднена в связи с
появлением директивы server_name_in_redirect.
*) Изменение: некоторые давно устаревшие директивы больше не
поддерживаются.
*) Изменение: параметр "none" в директиве ssl_session_cache; теперь
этот параметр используется по умолчанию.
Спасибо Rob Mueller.
*) Исправление: рабочие процессы могли не реагировать на сигналы
переконфигурации и ротации логов.
*) Исправление: nginx не собирался на последних Fedora 9 Linux.
Спасибо Roxis.
Изменения в nginx 0.7.0 19.05.2008
*) Изменение: теперь символы 0x00-0x1F, '"' и '\' в access_log
записываются в виде \xXX.
Спасибо Максиму Дунину.
*) Изменение: теперь nginx разрешает несколько строк "Host" в заголовке
запроса.
*) Добавление: директива expires поддерживает флаг modified.
*) Добавление: переменные $uid_got и $uid_set можно использовать на
любой стадии обработки запроса.
*) Добавление: переменная $hostname.
Спасибо Андрею Нигматулину.
*) Добавление: поддержка DESTDIR.
Спасибо Todd A. Fisher и Andras Voroskoi.
*) Исправление: при использовании keepalive на Linux в рабочем процессе
мог произойти segmentation fault.
Изменения в nginx 0.6.31 12.05.2008
*) Исправление: nginx не обрабатывал ответ FastCGI-сервера, если строка
заголовка ответ была в конце записи FastCGI; ошибка появилась в
0.6.2.
Спасибо Сергею Серову.
*) Исправление: при удалении файла и использовании директивы
open_file_cache_errors off в рабочем процессе мог произойти
segmentation fault.
Изменения в nginx 0.6.30 29.04.2008
*) Изменение: теперь, если маске, заданной в директиве include, не
соответствует ни один файл, то nginx не выдаёт ошибку.
*) Добавление: теперь время в директивах можно задавать без пробела,
например, "1h50m".
*) Исправление: утечек памяти, если директива ssl_verify_client имела
значение on.
Спасибо Chavelle Vincent.
*) Исправление: директива sub_filter могла вставлять заменяемый текст в
вывод.
*) Исправление: директива error_page не воспринимала параметры в
перенаправляемом URI.
*) Исправление: теперь при сборке с Cygwin nginx всегда открывает файлы
в бинарном режиме.
*) Исправление: nginx не собирался под OpenBSD; ошибка появилась в
0.6.15.
Изменения в nginx 0.6.29 18.03.2008
*) Добавление: модуль ngx_google_perftools_module.
*) Исправление: модуль ngx_http_perl_module не собирался на 64-битных
платформах; ошибка появилась в 0.6.27.
Изменения в nginx 0.6.28 13.03.2008
*) Исправление: метод rtsig не собирался; ошибка появилась в 0.6.27.
Изменения в nginx 0.6.27 12.03.2008
*) Изменение: теперь на Linux 2.6.18+ по умолчанию не собирается метод
rtsig.
*) Изменение: теперь при перенаправлении запроса в именованный location
с помощью директивы error_page метод запроса не изменяется.
*) Добавление: директивы resolver и resolver_timeout в SMTP
прокси-сервере.
*) Добавление: директива post_action поддерживает именованные
location'ы.
*) Исправление: при перенаправлении запроса из location'а c
обработчиком proxy, FastCGI или memcached в именованный location со
статическим обработчиком в рабочем процессе происходил segmentation
fault.
*) Исправление: браузеры не повторяли SSL handshake, если при первом
handshake не оказалось правильного клиентского сертификата.
Спасибо Александру Инюхину.
*) Исправление: при перенаправлении ошибок 495-497 с помощью директивы
error_page без изменения кода ошибки nginx пытался выделить очень
много памяти.
*) Исправление: утечки памяти в долгоживущих небуфферизированных
соединениях.
*) Исправление: утечки памяти в resolver'е.
*) Исправление: при перенаправлении запроса из location'а c
обработчиком proxy в другой location с обработчиком proxy в рабочем
процессе происходил segmentation fault.
*) Исправление: ошибки в кэшировании переменных $proxy_host и
$proxy_port.
Спасибо Сергею Боченкову.
*) Исправление: директива proxy_pass с переменными использовала порт,
описанной в другой директиве proxy_pass без переменных, но с таким
же именем хоста.
Спасибо Сергею Боченкову.
*) Исправление: во время переконфигурации на некоторых 64-битном
платформах в лог записывался alert "sendmsg() failed (9: Bad file
descriptor)".
*) Исправление: при повторном использовании в SSI пустого block'а в
качестве заглушки в рабочем процессе происходил segmentation fault.
*) Исправление: ошибки при копировании части URI, содержащего
экранированные символы, в аргументы.
Изменения в nginx 0.6.26 11.02.2008
*) Исправление: директивы proxy_store и fastcgi_store не проверяли
длину ответа.
*) Исправление: при использовании большого значения в директиве expires
в рабочем процессе происходил segmentation fault.
Спасибо Joaquin Cuenca Abela.
*) Исправление: nginx неверно определял длину строки кэша на
Pentium 4.
Спасибо Геннадию Махомеду.
*) Исправление: в проксированных подзапросах и подзапросах к
FastCGI-серверу вместо метода GET использовался оригинальный метод
клиента.
*) Исправление: утечки сокетов в режиме HTTPS при использовании
отложенного accept'а.
Спасибо Ben Maurer.
*) Исправление: nginx выдавал ошибочное сообщение "SSL_shutdown()
failed (SSL: )"; ошибка появилась в 0.6.23.
*) Исправление: при использовании HTTPS запросы могли завершаться с
ошибкой "bad write retry"; ошибка появилась в 0.6.23.
Изменения в nginx 0.6.25 08.01.2008
*) Изменение: вместо специального параметра "*" в директиве server_name
теперь используется директива server_name_in_redirect.
*) Изменение: в качестве основного имени в директиве server_name теперь
можно использовать имена с масками и регулярными выражениями.
*) Изменение: директива satisfy_any заменена директивой satisfy.
*) Изменение: после переконфигурации старые рабочие процесс могли
сильно нагружать процессор при запуске под Linux OpenVZ.
*) Добавление: директива min_delete_depth.
*) Исправление: методы COPY и MOVE не работали с одиночными файлами.
*) Исправление: модуль ngx_http_gzip_static_module не позволял работать
модулю ngx_http_dav_module; ошибка появилась в 0.6.23.
*) Исправление: утечки сокетов в режиме HTTPS при использовании
отложенного accept'а.
Спасибо Ben Maurer.
*) Исправление: nginx не собирался без библиотеки PCRE; ошибка
появилась в 0.6.23.
Изменения в nginx 0.6.24 27.12.2007
*) Исправление: при использовании HTTPS в рабочем процессе мог
произойти segmentation fault; ошибка появилась в 0.6.23.
Изменения в nginx 0.6.23 27.12.2007
*) Изменение: параметр "off" в директиве ssl_session_cache; теперь этот
параметр используется по умолчанию.
*) Изменение: директива open_file_cache_retest переименована в
open_file_cache_valid.
*) Добавление: директива open_file_cache_min_uses.
*) Добавление: модуль ngx_http_gzip_static_module.
*) Добавление: директива gzip_disable.
*) Добавление: директиву memcached_pass можно использовать внутри блока
if.
*) Исправление: если внутри одного location'а использовались директивы
"memcached_pass" и "if", то в рабочем процессе происходил
segmentation fault.
*) Исправление: если при использовании директивы satisfy_any on" были
заданы директивы не всех модулей доступа, то заданные директивы не
проверялись.
*) Исправление: параметры, заданные регулярным выражением в директиве
valid_referers, не наследовалась с предыдущего уровня.
*) Исправление: директива post_action не работала, если запрос
завершался с кодом 499.
*) Исправление: оптимизация использования 16K буфера для
SSL-соединения.
Спасибо Ben Maurer.
*) Исправление: STARTTLS в режиме SMTP не работал.
Спасибо Олегу Мотиенко.
*) Исправление: при использовании HTTPS запросы могли завершаться с
ошибкой "bad write retry"; ошибка появилась в 0.5.13.
Изменения в nginx 0.6.22 19.12.2007
*) Изменение: теперь все методы модуля ngx_http_perl_module возвращают
значения, скопированные в память, выделенную perl'ом.
*) Исправление: если nginx был собран с модулем ngx_http_perl_module,
использовался perl до версии 5.8.6 и perl поддерживал потоки, то во
время переконфигурации основной процесс аварийно выходил; ошибка
появилась в 0.5.9.
Спасибо Борису Жмурову.
*) Исправление: в методы модуля ngx_http_perl_module могли передаваться
неверные результаты выделения в регулярных выражениях.
*) Исправление: если метод $r->has_request_body() вызывался для
запроса, у которого небольшое тело запроса было уже полностью
получено, то в рабочем процессе происходил segmentation fault.
*) Исправление: large_client_header_buffers не освобождались перед
переходом в состояние keep-alive.
Спасибо Олександру Штепе.
*) Исправление: в переменной $upstream_addr не записывался последний
адрес; ошибка появилась в 0.6.18.
*) Исправление: директива fastcgi_catch_stderr не возвращала ошибку;
теперь она возвращает ошибку 502, которую можно направить на
следующий сервер с помощью "fastcgi_next_upstream invalid_header".
*) Исправление: при использовании директивы fastcgi_catch_stderr в
основном процессе происходил segmentation fault; ошибка появилась в
0.6.10.
Спасибо Manlio Perillo.
Изменения в nginx 0.6.21 03.12.2007
*) Изменение: если в значениях переменных директивы proxy_pass
используются только IP-адреса, то указывать resolver не нужно.
*) Исправление: при использовании директивы proxy_pass c URI-частью в
рабочем процессе мог произойти segmentation fault; ошибка появилась
в 0.6.19.
*) Исправление: если resolver использовался на платформах, не
поддерживающих метод kqueue, то nginx выдавал alert "name is out of
response".
Спасибо Андрею Нигматулину.
*) Исправление: При использовании переменной $server_protocol в
FastCGI-параметрах и запросе, длина которого была близка к значению
директивы client_header_buffer_size, nginx выдавал alert "fastcgi:
the request record is too big".
*) Исправление: при обычном запросе версии HTTP/0.9 к HTTPS серверу
nginx возвращал обычный ответ.
Изменения в nginx 0.6.20 28.11.2007
*) Исправление: при использовании директивы proxy_pass c URI-частью в
рабочем процессе мог произойти segmentation fault; ошибка появилась
в 0.6.19.
Изменения в nginx 0.6.19 27.11.2007
*) Исправление: версия 0.6.18 не собиралась.
Изменения в nginx 0.6.18 27.11.2007
*) Изменение: теперь модуль ngx_http_userid_module в поле куки с
номером процесса добавляет микросекунды на время старта.
*) Изменение: в error_log теперь записывается полная строка запроса
вместо только URI.
*) Добавление: директива proxy_pass поддерживает переменные.
*) Добавление: директивы resolver и resolver_timeout.
*) Добавление: теперь директива "add_header last-modified ''" удаляет в
заголовке ответа строку "Last-Modified".
*) Исправление: директива limit_rate не позволяла передавать на полной
скорости, даже если был указан очень большой лимит.
Изменения в nginx 0.6.17 15.11.2007
*) Добавление: поддержка строки "If-Range" в заголовке запроса.
Спасибо Александру Инюхину.
*) Исправление: при использовании директивы msie_refresh повторно
экранировались уже экранированные символы; ошибка появилась в 0.6.4.
*) Исправление: директива autoindex не работала при использовании
"alias /".
*) Исправление: при использовании подзапросов в рабочем процессе мог
произойти segmentation fault.
*) Исправление: при использовании SSL и gzip большие ответы могли
передаваться не полностью.
*) Исправление: если ответ проксированного сервера был версии HTTP/0.9,
то переменная $status была равна 0.
Изменения в nginx 0.6.16 29.10.2007
*) Изменение: теперь на Linux используется uname(2) вместо procfs.
Спасибо Илье Новикову.
*) Исправление: если в директиве error_page использовался символ "?",
то он экранировался при проксировании запроса; ошибка появилась в
0.6.11.
*) Исправление: совместимость с mget.
Изменения в nginx 0.6.15 22.10.2007
*) Добавление: совместимость с Cygwin.
Спасибо Владимиру Кутакову.
*) Добавление: директива merge_slashes.
*) Добавление: директива gzip_vary.
*) Добавление: директива server_tokens.
*) Исправление: nginx не раскодировал URI в команде SSI include.
*) Исправление: при использовании переменной в директивах charset или
source_charset на старте или во время переконфигурации происходил
segmentation fault,
*) Исправление: nginx возвращал ошибку 400 на запросы вида
"GET http://www.domain.com HTTP/1.0".
Спасибо James Oakley.
*) Исправление: после перенаправления запроса с телом запроса с помощью
директивы error_page nginx пытался снова прочитать тело запроса;
ошибка появилась в 0.6.7.
*) Исправление: в рабочем процессе происходил segmentation fault, если
у сервера, обрабатывающему запрос, не был явно определён
server_name; ошибка появилась в 0.6.7.
Изменения в nginx 0.6.14 15.10.2007
*) Изменение: теперь по умолчанию команда SSI echo использует
кодирование entity.
*) Добавление: параметр encoding в команде SSI echo.
*) Добавление: директиву access_log можно использовать внутри блока
limit_except.
*) Исправление: если все сервера апстрима оказывались недоступными, то
до восстановления работоспособности у всех серверов вес становился
равным одному; ошибка появилась в 0.6.6.
*) Исправление: при использовании переменных $date_local и $date_gmt
вне модуля ngx_http_ssi_filter_module в рабочем процессе происходил
segmentation fault.
*) Исправление: при использовании включённом отладочном логе в рабочем
процессе мог произойти segmentation fault.
Спасибо Андрею Нигматулину.
*) Исправление: ngx_http_memcached_module не устанавливал
$upstream_response_time.
Спасибо Максиму Дунину.
*) Исправление: рабочий процесс мог зациклиться при использовании
memcached.
*) Исправление: nginx распознавал параметры "close" и "keep-alive" в
строке "Connection" в заголовке запроса только, если они были в
нижнем регистре; ошибка появилась в 0.6.11.
*) Исправление: sub_filter не работал с пустой строкой замены.
*) Исправление: в парсинге sub_filter.
Изменения в nginx 0.6.13 24.09.2007
*) Исправление: nginx не закрывал файл каталога для запроса HEAD, если
использовался autoindex
Спасибо Arkadiusz Patyk.
Изменения в nginx 0.6.12 21.09.2007
*) Изменение: почтовый прокси-сервер разделён на три модуля: pop3, imap
и smtp.
*) Добавление: параметры конфигурации --without-mail_pop3_module,
--without-mail_imap_module и --without-mail_smtp_module.
*) Добавление: директивы smtp_greeting_delay и smtp_client_buffer
модуля ngx_mail_smtp_module.
*) Исправление: wildcard в конце имени сервера не работали; ошибка
появилась в 0.6.9.
*) Исправление: при использовании разделяемой библиотеки PCRE,
расположенной в нестандартном месте, nginx не запускался на Solaris.
*) Исправление: директивы proxy_hide_header и fastcgi_hide_header не
скрывали строки заголовка ответа с именем больше 32 символов.
Спасибо Manlio Perillo.
Изменения в nginx 0.6.11 11.09.2007
*) Исправление: счётчик активных соединений всегда рос при
использовании почтового прокси-сервера.
*) Исправление: если бэкенд возвращал только заголовок ответа при
небуферизированном проксировании, то nginx закрывал соединение с
бэкендом по таймауту.
*) Исправление: nginx не поддерживал несколько строк "Connection" в
заголовке запроса.
*) Исправление: если в сервере апстрима был задан max_fails, то после
первой же неудачной попытки вес сервера навсегда становился равным
одному; ошибка появилась в 0.6.6.
Изменения в nginx 0.6.10 03.09.2007
*) Добавление: директивы open_file_cache, open_file_cache_retest и
open_file_cache_errors.
*) Исправление: утечки сокетов; ошибка появилась в 0.6.7.
*) Исправление: В строку заголовка ответа "Content-Type", указанную в
методе $r->send_http_header(), не добавлялась кодировка, указанная в
директиве charset.
*) Исправление: при использовании метода /dev/poll в рабочем процессе
мог произойти segmentation fault.
Изменения в nginx 0.6.9 28.08.2007
*) Исправление: рабочий процесс мог зациклиться при использовании
протокола HTTPS; ошибка появилась в 0.6.7.
*) Исправление: если сервер слушал на двух адресах или портах, то nginx
не запускался при использовании wildcard в конце имени сервера.
*) Исправление: директива ip_hash могла неверно помечать сервера как
нерабочие.
*) Исправление: nginx не собирался на amd64; ошибка появилась в 0.6.8.
Изменения в nginx 0.6.8 20.08.2007
*) Изменение: теперь nginx пытается установить директивы
worker_priority, worker_rlimit_nofile, worker_rlimit_core,
worker_rlimit_sigpending без привилегий root'а.
*) Изменение: теперь nginx экранирует символы пробела и "%" при
передаче запроса серверу аутентификации почтового прокси-сервера.
*) Изменение: теперь nginx экранирует символ "%" в переменной
$memcached_key.
*) Исправление: при указании относительного пути к конфигурационному
файлу в качестве параметра ключа -c nginx определял путь
относительно конфигурационного префикса; ошибка появилась в 0.6.6.
*) Исправление: nginx не работал на FreeBSD/sparc64.
Изменения в nginx 0.6.7 15.08.2007
*) Изменение: теперь пути, указанные в директивах include,
auth_basic_user_file, perl_modules, ssl_certificate,
ssl_certificate_key и ssl_client_certificate, определяются
относительно каталога конфигурационного файла nginx.conf, а не
относительно префикса.
*) Изменение: параметр --sysconfdir=PATH в configure упразднён.
*) Изменение: для обновления на лету версий 0.1.x создан специальный
сценарий make upgrade1.
*) Добавление: директивы server_name и valid_referers поддерживают
регулярные выражения.
*) Добавление: директива server в блоке upstream поддерживает параметр
backup.
*) Добавление: модуль ngx_http_perl_module поддерживает метод
$r->discard_request_body.
*) Добавление: директива "add_header Last-Modified ..." меняет строку
"Last-Modified" в заголовке ответа.
*) Исправление: если на запрос с телом возвращался ответ с кодом HTTP
отличным от 200, и после этого запроса соединение переходило в
состояние keep-alive, то на следующий запрос nginx возвращал 400.
*) Исправление: если в директиве auth_http был задан неправильный
адрес, то в рабочем процессе происходил segmentation fault.
*) Исправление: теперь по умолчанию nginx использует значение 511 для
listen backlog на всех платформах, кроме FreeBSD.
Спасибо Jiang Hong.
*) Исправление: рабочий процесс мог зациклиться, если server в блоке
upstream был помечен как down; ошибка появилась в 0.6.6.
*) Исправление: sendfilev() в Solaris теперь не используется при
передаче тела запроса FastCGI-серверу через unix domain сокет.
Изменения в nginx 0.6.6 30.07.2007
*) Добавление: параметр --sysconfdir=PATH в configure.
*) Добавление: именованные location'ы.
*) Добавление: переменную $args можно устанавливать с помощью set.
*) Добавление: переменная $is_args.
*) Исправление: равномерное распределение запросов к апстримам с
большими весами.
*) Исправление: если клиент в почтовом прокси-сервере закрывал
соединение, то nginx мог не закрывать соединение с бэкендом.
*) Исправление: при использовании одного хоста в качестве бэкендов для
протоколов HTTP и HTTPS без явного указания портов, nginx
использовал только один порт - 80 или 443.
*) Исправление: nginx не собирался на Solaris/amd64 Sun Studio 11 и
более ранними версиями; ошибка появилась в 0.6.4.
Изменения в nginx 0.6.5 23.07.2007
*) Добавление: переменная $nginx_version.
Спасибо Николаю Гречуху.
*) Добавление: почтовый прокси-сервер поддерживает AUTHENTICATE в
режиме IMAP.
Спасибо Максиму Дунину.
*) Добавление: почтовый прокси-сервер поддерживает STARTTLS в режиме
SMTP.
Спасибо Максиму Дунину.
*) Исправление: теперь nginx экранирует пробел в переменной
$memcached_key.
*) Исправление: nginx неправильно собирался Sun Studio на
Solaris/amd64.
Спасибо Jiang Hong.
*) Исправление: незначительных потенциальных ошибок.
Спасибо Coverity's Scan.
Изменения в nginx 0.6.4 17.07.2007
*) Безопасность: при использовании директивы msie_refresh был возможен
XSS.
Спасибо Максиму Богуку.
*) Изменение: директивы proxy_store и fastcgi_store изменены.
*) Добавление: директивы proxy_store_access и fastcgi_store_access.
*) Исправление: nginx не работал на Solaris/sparc64, если был собран
Sun Studio.
Спасибо Андрею Нигматулину.
*) Изменение: обход ошибки в Sun Studio 12.
Спасибо Jiang Hong.
Изменения в nginx 0.6.3 12.07.2007
*) Добавление: директивы proxy_store и fastcgi_store.
*) Исправление: при использовании директивы auth_http_header в рабочем
процессе мог произойти segmentation fault.
Спасибо Максиму Дунину.
*) Исправление: если использовался метод аутентификации CRAM-MD5, но он
не был разрешён, то в рабочем процессе происходил segmentation fault.
*) Исправление: при использовании протокола HTTPS в директиве
proxy_pass в рабочем процессе мог произойти segmentation fault.
*) Исправление: в рабочем процессе мог произойти segmentation fault,
если использовался метод eventport.
*) Исправление: директивы proxy_ignore_client_abort и
fastcgi_ignore_client_abort не работали; ошибка появилась в 0.5.13.
Изменения в nginx 0.6.2 09.07.2007
*) Исправление: если заголовок ответа был разделён в FastCGI-записях,
то nginx передавал клиенту мусор в таких заголовках.
Изменения в nginx 0.6.1 17.06.2007
*) Исправление: в парсинге SSI.
*) Исправление: при использовании удалённого подзапроса в SSI
последующий подзапрос локального файла мог отдаваться клиенту в
неверном порядке.
*) Исправление: большие включения в SSI, сохранённые во временные
файлы, передавались не полностью.
*) Исправление: значение perl'овой переменной $$ модуля
ngx_http_perl_module было равно номеру главного процесса.
Изменения в nginx 0.6.0 14.06.2007
*) Добавление: директивы "server_name", "map", and "valid_referers"
поддерживают маски вида "www.example.*".
Изменения в nginx 0.5.25 11.06.2007
*) Исправление: nginx не собирался с параметром
--without-http_rewrite_module; ошибка появилась в 0.5.24.
Изменения в nginx 0.5.24 06.06.2007
*) Безопасность: директива ssl_verify_client не работала, если запрос
выполнялся по протоколу HTTP/0.9.
*) Исправление: при использовании сжатия часть ответа могла
передаваться несжатой; ошибка появилась в 0.5.23.
Изменения в nginx 0.5.23 04.06.2007
*) Добавление: модуль ngx_http_ssl_module поддерживает расширение TLS
Server Name Indication.
*) Добавление: директива fastcgi_catch_stderr.
Спасибо Николаю Гречуху, проект OWOX.
*) Исправление: на Линуксе в основном процессе происходил segmentation
fault, если два виртуальных сервера должны bind()ится к
пересекающимся портам.
*) Исправление: если nginx был собран с модулем ngx_http_perl_module и
perl поддерживал потоки, то во время второй переконфигурации
выдавались ошибки "panic: MUTEX_LOCK" и "perl_parse() failed".
*) Исправление: в использовании протокола HTTPS в директиве proxy_pass.
Изменения в nginx 0.5.22 29.05.2007
*) Исправление: большое тело запроса могло не передаваться бэкенду;
ошибка появилась в 0.5.21.
Изменения в nginx 0.5.21 28.05.2007
*) Исправление: если внутри сервера описано больше примерно десяти
location'ов, то location'ы, заданные с помощью регулярного
выражения, могли выполняться не в том, порядке, в каком они описаны.
*) Исправление: на 64-битной платформе рабочий процесс мог зациклиться,
если 33-тий по счёту или последующий бэкенд упал.
Спасибо Антону Поварову.
*) Исправление: при использовании библиотеки PCRE на Solaris/sparc64
мог произойти bus error.
Спасибо Андрею Нигматулину.
*) Исправление: в использовании протокола HTTPS в директиве proxy_pass.
Изменения в nginx 0.5.20 07.05.2007
*) Добавление: директива sendfile_max_chunk.
*) Добавление: переменные "$http_...", "$sent_http_..." и
"$upstream_http_..." можно менять директивой set.
*) Исправление: при использовании SSI-команды 'if expr="$var = /"' в
рабочем процессе мог произойти segmentation fault.
*) Исправление: завершающая строка multipart range ответа передавалась
неверно.
Спасибо Evan Miller.
*) Исправление: nginx не работал на Solaris/sparc64, если был собран
Sun Studio.
Спасибо Андрею Нигматулину.
*) Исправление: модуль ngx_http_perl_module не собирался make в
Solaris.
Спасибо Андрею Нигматулину.
Изменения в nginx 0.5.19 24.04.2007
*) Изменение: значение переменной $request_time теперь записывается с
точностью до миллисекунд.
*) Изменение: метод $r->rflush в модуле ngx_http_perl_module
переименован в $r->flush.
*) Добавление: переменная $upstream_addr.
*) Добавление: директивы proxy_headers_hash_max_size и
proxy_headers_hash_bucket_size.
Спасибо Володымыру Костырко.
*) Исправление: при использовании sendfile и limit_rate на 64-битных
платформах нельзя было передавать файлы больше 2G.
*) Исправление: при использовании sendfile на 64-битном Linux нельзя
было передавать файлы больше 2G.
Изменения в nginx 0.5.18 19.04.2007
*) Добавление: модуль ngx_http_sub_filter_module.
*) Добавление: переменные "$upstream_http_...".
*) Добавление: теперь переменные $upstream_status и
$upstream_response_time содержат данные о всех обращениях к
апстримам, сделанным до X-Accel-Redirect.
*) Исправление: если nginx был собран с модулем ngx_http_perl_module и
perl не поддерживал multiplicity, то после первой переконфигурации и
после получения любого сигнала в основном процессе происходил
segmentation fault; ошибка появилась в 0.5.9.
*) Исправление: если perl не поддерживал multiplicity, то после
переконфигурации перловый код не работал; ошибка появилась в 0.3.38.
Изменения в nginx 0.5.17 02.04.2007
*) Изменение: теперь nginx для метода TRACE всегда возвращает код 405.
*) Добавление: теперь nginx поддерживает директиву include внутри блока
types.
*) Исправление: использование переменной $document_root в директиве
root и alias запрещено: оно вызывало рекурсивное переполнение стека.
*) Исправление: в использовании протокола HTTPS в директиве proxy_pass.
*) Исправление: в некоторых случаях некэшируемые переменные (такие, как
$uri) возвращали старое закэшированное значение.
Изменения в nginx 0.5.16 26.03.2007
*) Исправление: в качестве ключа для хэша в директиве ip_hash не
использовалась сеть класса С.
Спасибо Павлу Ярковому.
*) Исправление: если в строке "Content-Type" в заголовке ответа бэкенда
был указан charset и строка завершалась символом ";", то в рабочем
процессе мог произойти segmentation fault; ошибка появилась в 0.3.50.
*) Исправление: ошибки "[alert] zero size buf" при работе с
FastCGI-сервером, если тело запроса, записанное во временный файл,
было кратно 32K.
*) Исправление: nginx не собирался на Solaris без параметра
--with-debug; ошибка появилась в 0.5.15.
Изменения в nginx 0.5.15 19.03.2007
*) Добавление: почтовый прокси-сервер поддерживает аутентифицированное
SMTP-проксирование и директивы smtp_auth, smtp_capablities и
xclient.
Спасибо Антону Южанинову и Максиму Дунину.
*) Добавление: теперь keep-alive соединения закрываются сразу же по
получении сигнала переконфигурации.
*) Изменение: директивы imap и auth переименованы соответственно в mail
и pop3_auth.
*) Исправление: если использовался метод аутентификации CRAM-MD5 и не
был разрешён метод APOP, то в рабочем процессе происходил
segmentation fault.
*) Исправление: при использовании директивы starttls only в протоколе
POP3 nginx разрешал аутентификацию без перехода в режим SSL.
*) Исправление: рабочие процессы не выходили после переконфигурации и
не переоткрывали логи, если использовался метод eventport.
*) Исправление: при использовании директивы ip_hash рабочий процесс мог
зациклиться.
*) Исправление: теперь nginx не пишет в лог некоторые alert'ы, если
используются методы eventport или /dev/poll.
Изменения в nginx 0.5.14 23.02.2007
*) Исправление: nginx игнорировал лишние закрывающие скобки "}" в конце
конфигурационного файла.
Изменения в nginx 0.5.13 19.02.2007
*) Добавление: методы COPY и MOVE.
*) Исправление: модуль ngx_http_realip_module устанавливал мусор для
запросов, переданных по keep-alive соединению.
*) Исправление: nginx не работал на 64-битном big-endian Linux.
Спасибо Андрею Нигматулину.
*) Исправление: при получении слишком длинной команды IMAP/POP3-прокси
теперь сразу закрывает соединение, а не по таймауту.
*) Исправление: если при использовании метода epoll клиент закрывал
преждевременно соединение со своей стороны, то nginx закрывал это
соединение только по истечении таймаута на передачу.
*) Исправление: nginx не собирался на платформах, отличных от i386,
amd64, sparc и ppc; ошибка появилась в 0.5.8.
Изменения в nginx 0.5.12 12.02.2007
*) Исправление: nginx не собирался на платформах, отличных от i386,
amd64, sparc и ppc; ошибка появилась в 0.5.8.
*) Исправление: при использовании временных файлов в время работы с
FastCGI-сервером в рабочем процессе мог произойти segmentation
fault; ошибка появилась в 0.5.8.
*) Исправление: если переменная $fastcgi_script_name записывалась в
лог, то в рабочем процессе мог произойти segmentation fault.
*) Исправление: ngx_http_perl_module не собирался на Solaris.
Изменения в nginx 0.5.11 05.02.2007
*) Добавление: теперь configure определяет библиотеку PCRE в
MacPorts.
Спасибо Chris McGrath.
*) Исправление: ответ был неверным, если запрашивалось несколько
диапазонов; ошибка появилась в 0.5.6.
*) Исправление: директива create_full_put_path не могла создавать
промежуточные каталоги, если не была установлена директива
dav_access.
Спасибо Evan Miller.
*) Исправление: вместо кодов ошибок "400" и "408" в access_log мог
записываться код "0".
*) Исправление: при сборке с оптимизацией -O2 в рабочем процессе мог
произойти segmentation fault.
Изменения в nginx 0.5.10 26.01.2007
*) Исправление: во время обновления исполняемого файла новый процесс не
наследовал слушающие сокеты; ошибка появилась в 0.5.9.
*) Исправление: при сборке с оптимизацией -O2 в рабочем процессе мог
произойти segmentation fault; ошибка появилась в 0.5.1.
Изменения в nginx 0.5.9 25.01.2007
*) Изменение: модуль ngx_http_memcached_module теперь в качестве ключа
использует значение переменной $memcached_key.
*) Добавление: переменная $memcached_key.
*) Добавление: параметр clean в директиве client_body_in_file_only.
*) Добавление: директива env.
*) Добавление: директива sendfile работает внутри блока if.
*) Добавление: теперь при ошибке записи в access_log nginx записывает
сообщение в error_log, но не чаще одного раза в минуту.
*) Исправление: директива "access_log off" не всегда запрещала запись в
лог.
Изменения в nginx 0.5.8 19.01.2007
*) Исправление: если использовалась директива
"client_body_in_file_only on" и тело запроса было небольшое, то мог
произойти segmentation fault.
*) Исправление: происходил segmentation fault, если использовались
директивы "client_body_in_file_only on" и
"proxy_pass_request_body off" или "fastcgi_pass_request_body off", и
делался переход к следующему бэкенду.
*) Исправление: если при использовании директивы "proxy_buffering off"
соединение с клиентом было неактивно, то оно закрывалось по
таймауту, заданному директивой send_timeout; ошибка появилась в
0.4.7.
*) Исправление: если при использовании метода epoll клиент закрывал
преждевременно соединение со своей стороны, то nginx закрывал это
соединение только по истечении таймаута на передачу.
*) Исправление: ошибки "[alert] zero size buf" при работе с
FastCGI-сервером.
*) Исправление ошибок в директиве limit_zone.
Изменения в nginx 0.5.7 15.01.2007
*) Добавление: оптимизация использования памяти в ssl_session_cache.
*) Исправление ошибок в директивах ssl_session_cache и limit_zone.
*) Исправление: на старте или во время переконфигурации происходил
segmentation fault, если директивы ssl_session_cache или limit_zone
использовались на 64-битных платформах.
*) Исправление: при использовании директив add_before_body или
add_after_body происходил segmentation fault, если в заголовке
ответа нет строки "Content-Type".
*) Исправление: библиотека OpenSSL всегда собиралась с поддержкой
потоков.
Спасибо Дену Иванову.
*) Исправление: совместимость библиотеки PCRE-6.5+ и компилятора icc.
Изменения в nginx 0.5.6 09.01.2007
*) Изменение: теперь модуль ngx_http_index_module игнорирует все
методы, кроме GET, HEAD и POST.
*) Добавление: модуль ngx_http_limit_zone_module.
*) Добавление: переменная $binary_remote_addr.
*) Добавление: директивы ssl_session_cache модулей ngx_http_ssl_module
и ngx_imap_ssl_module.
*) Добавление: метод DELETE поддерживает рекурсивное удаление.
*) Исправление: при использовании $r->sendfile() byte-ranges
передавались неверно.
Изменения в nginx 0.5.5 24.12.2006
*) Изменение: ключ -v больше не выводит информацию о компиляторе.
*) Добавление: ключ -V.
*) Добавление: директива worker_rlimit_core поддерживает указание
размера в K, M и G.
*) Исправление: модуль nginx.pm теперь может устанавливаться
непривилегированным пользователем.
*) Исправление: при использовании методов $r->request_body или
$r->request_body_file мог произойти segmentation fault.
*) Исправление: ошибок, специфичных для платформы ppc.
Изменения в nginx 0.5.4 15.12.2006
*) Добавление: директиву perl можно использовать внутри блока
limit_except.
*) Исправление: модуль ngx_http_dav_module требовал строку "Date" в
заголовке запроса для метода DELETE.
*) Исправление: при использовании одного параметра в директиве
dav_access nginx мог сообщить об ошибке в конфигурации.
*) Исправление: при использовании переменной $host мог произойти
segmentation fault; ошибка появилась в 0.4.14.
Изменения в nginx 0.5.3 13.12.2006
*) Добавление: модуль ngx_http_perl_module поддерживает методы
$r->status, $r->log_error и $r->sleep.
*) Добавление: метод $r->variable поддерживает переменные, неописанные
в конфигурации nginx'а.
*) Исправление: метод $r->has_request_body не работал.
Изменения в nginx 0.5.2 11.12.2006
*) Исправление: если в директивах proxy_pass использовалось имя,
указанное в upstream, то nginx пытался найти IP-адрес этого имени;
ошибка появилась в 0.5.1.
Изменения в nginx 0.5.1 11.12.2006
*) Исправление: директива post_action могла не работать после
неудачного завершения запроса.
*) Изменение: обход ошибки в Eudora для Mac; ошибка появилась в
0.4.11.
Спасибо Bron Gondwana.
*) Исправление: при указании в директиве fastcgi_pass имени описанного
upstream'а выдавалось сообщение "no port in upstream"; ошибка
появилась в 0.5.0.
*) Исправление: если в директивах proxy_pass и fastcgi_pass
использовались одинаковых имена серверов, но с разными портами, то
эти директивы использовали первый описанный порт; ошибка появилась в
0.5.0.
*) Исправление: если в директивах proxy_pass и fastcgi_pass
использовались unix domain сокеты, то эти директивы использовали
первый описанный сокет; ошибка появилась в 0.5.0.
*) Исправление: ngx_http_auth_basic_module игнорировал пользователя,
если он был указан в последней строке файла паролей и после пароля
не было перевода строки, возврата каретки или символа ":".
*) Исправление: переменная $upstream_response_time могла быть равна
"0.000", хотя время обработки было больше 1 миллисекунды.
Изменения в nginx 0.5.0 04.12.2006
*) Изменение: параметры в виде "%name" в директиве log_format больше не
поддерживаются.
*) Изменение: директивы proxy_upstream_max_fails,
proxy_upstream_fail_timeout, fastcgi_upstream_max_fails, и
fastcgi_upstream_fail_timeout, memcached_upstream_max_fails и
memcached_upstream_fail_timeout больше не поддерживаются.
*) Добавление: директива server в блоке upstream поддерживает параметры
max_fails, fail_timeout и down.
*) Добавление: директива ip_hash в блоке upstream.
*) Добавление: статус WAIT в строке "Auth-Status" в заголовка ответа
сервера аутентификации IMAP/POP3 прокси.
*) Исправление: nginx не собирался на 64-битных платформах; ошибка
появилась в 0.4.14.
Изменения в nginx 0.4.14 27.11.2006
*) Добавление: директива proxy_pass_error_message в IMAP/POP3 прокси.
*) Добавление: теперь configure определяет библиотеку PCRE на FreeBSD,
Linux и NetBSD.
*) Исправление: ngx_http_perl_module не работал с перлом, собранным с
поддержкой потоков; ошибка появилась в 0.3.38.
*) Исправление: ngx_http_perl_module не работал корректно, если перл
вызывался рекурсивно.
*) Исправление: nginx игнорировал имя сервера в строке запроса.
*) Исправление: если FastCGI сервер передавал много в stderr, то
рабочий процесс мог зациклиться.
*) Исправление: при изменении системного времени переменная
$upstream_response_time могла быть отрицательной.
*) Исправление: при использовании POP3 серверу аутентификации IMAP/POP3
прокси не передавался параметр Auth-Login-Attempt.
*) Исправление: при ошибке соединения с сервером аутентификации
IMAP/POP3 прокси мог произойти segmentation fault.
Изменения в nginx 0.4.13 15.11.2006
*) Добавление: директиву proxy_pass можно использовать внутри блока
limit_except.
*) Добавление: директива limit_except поддерживает все WebDAV методы.
*) Исправление: при использовании директивы add_before_body без
директивы add_after_body ответ передавался не полностью.
*) Исправление: большое тело запроса не принималось, если
использовались метод epoll и deferred accept().
*) Исправление: для ответов модуля ngx_http_autoindex_module не
выставлялась кодировка; ошибка появилась в 0.3.50.
*) Исправление: ошибки "[alert] zero size buf" при работе с
FastCGI-сервером;
*) Исправление: параметр конфигурации --group= игнорировался.
Спасибо Thomas Moschny.
*) Исправление: 50-й подзапрос в SSI ответе не работал; ошибка
появилась в 0.3.50.
Изменения в nginx 0.4.12 31.10.2006
*) Добавление: модуль ngx_http_perl_module поддерживает метод
$r->variable.
*) Исправление: при включении в ответ большого статического файла с
помощью SSI ответ мог передаваться не полностью.
*) Исправление: nginx не убирал "#fragment" в URI.
Изменения в nginx 0.4.11 25.10.2006
*) Добавление: POP3 прокси поддерживает AUTH LOIGN PLAIN и CRAM-MD5.
*) Добавление: модуль ngx_http_perl_module поддерживает метод
$r->allow_ranges.
*) Исправление: при включённой поддержке команды APOP в POP3 прокси
могли не работать команды USER/PASS; ошибка появилась в 0.4.10.
Изменения в nginx 0.4.10 23.10.2006
*) Добавление: POP3 прокси поддерживает APOP.
*) Исправление: при использовании методов select, poll и /dev/poll во
время ожидания ответа от сервера аутентификации IMAP/POP3 прокси
нагружал процессор.
*) Исправление: при использовании переменной $server_addr в директиве
map мог произойти segmentation fault.
*) Исправление: модуль ngx_http_flv_module не поддерживал byte ranges
для полных ответов; ошибка появилась в 0.4.7.
*) Исправление: nginx не собирался на Debian amd64; ошибка появилась в
0.4.9.
Изменения в nginx 0.4.9 13.10.2006
*) Добавление: параметр set в команде SSI include.
*) Добавление: модуль ngx_http_perl_module теперь проверяет версию
модуля nginx.pm.
Изменения в nginx 0.4.8 11.10.2006
*) Исправление: если до команды SSI include с параметром wait
выполнялась ещё одна команда SSI include, то параметр wait мог не
работать.
*) Исправление: модуль ngx_http_flv_module добавлял FLV-заголовок для
полных ответов.
Спасибо Алексею Ковырину.
Изменения в nginx 0.4.7 10.10.2006
*) Добавление: модуль ngx_http_flv_module.
*) Добавление: переменная $request_body_file.
*) Добавление: директивы charset и source_charset поддерживают
переменные.
*) Исправление: если до команды SSI include с параметром wait
выполнялась ещё одна команда SSI include, то параметр wait мог не
работать.
*) Исправление: при использовании директивы "proxy_buffering off" или
при работе с memcached соединения могли не закрываться по таймауту.
*) Исправление: nginx не запускался на 64-битных платформах, отличных
от amd64, sparc64 и ppc64.
Изменения в nginx 0.4.6 06.10.2006
*) Исправление: nginx не запускался на 64-битных платформах, отличных
от amd64, sparc64 и ppc64.
*) Исправление: при запросе версии HTTP/1.1 nginx передавал ответ
chunk'ами, если длина ответа в методе
$r->headers_out("Content-Length", ...) была задана текстовой строкой.
*) Исправление: после перенаправления ошибки с помощью директивы
error_page любая директива модуля ngx_http_rewrite_module возвращала
эту ошибку; ошибка появилась в 0.4.4.
Изменения в nginx 0.4.5 02.10.2006
*) Исправление: nginx не собирался на Linux и Solaris; ошибка появилась
в 0.4.4.
Изменения в nginx 0.4.4 02.10.2006
*) Добавление: переменная $scheme.
*) Добавление: директива expires поддерживает параметр max.
*) Добавление: директива include поддерживает маску "*".
Спасибо Jonathan Dance.
*) Исправление: директива return всегда изменяла код ответа,
перенаправленного директивой error_page.
*) Исправление: происходил segmentation fault, если в методе PUT
передавалось тело нулевой длины.
*) Исправление: при использовании переменных в директиве proxy_redirect
редирект изменялся неверно.
Изменения в nginx 0.4.3 26.09.2006
*) Изменение: ошибку 499 теперь нельзя перенаправить с помощью
директивы error_page.
*) Добавление: поддержка Solaris 10 event ports.
*) Добавление: модуль ngx_http_browser_module.
*) Исправление: при перенаправлении ошибки 400 проксированному серверу
помощью директивы error_page мог произойти segmentation fault.
*) Исправление: происходил segmentation fault, если в директиве
proxy_pass использовался unix domain сокет; ошибка появилась в
0.3.47.
*) Исправление: SSI не работал с ответами memcached и
небуферизированными проксированными ответами.
*) Изменение: обход ошибки PAUSE hardware capability в Sun Studio.
Изменения в nginx 0.4.2 14.09.2006
*) Исправление: убрана поддержка флага O_NOATIME на Linux; ошибка
появилась в 0.4.1.
Изменения в nginx 0.4.1 14.09.2006
*) Исправление: совместимость с DragonFlyBSD.
Спасибо Павлу Назарову.
*) Изменение: обход ошибки в sendfile() в 64-битном Linux при передаче
файлов больше 2G.
*) Добавление: теперь на Linux nginx для статических запросов
использует флаг O_NOATIME.
Спасибо Yusuf Goolamabbas.
Изменения в nginx 0.4.0 30.08.2006
*) Изменение во внутреннем API: инициализация модулей HTTP перенесена
из фазы init module в фазу HTTP postconfiguration.
*) Изменение: теперь тело запроса в модуле ngx_http_perl_module не
считывается заранее: нужно явно инициировать чтение с помощью метода
$r->has_request_body.
*) Добавление: модуль ngx_http_perl_module поддерживает код возврата
DECLINED.
*) Добавление: модуль ngx_http_dav_module поддерживает входящую строку
заголовка "Date" для метода PUT.
*) Добавление: директива ssi работает внутри блока if.
*) Исправление: происходил segmentation fault, если в директиве index
использовалась переменные и при этом первое имя индексного файла
было без переменных; ошибка появилась в 0.1.29.
Изменения в nginx 0.3.61 28.08.2006
*) Изменение: директива tcp_nodelay теперь по умолчанию включена.
*) Добавление: директива msie_refresh.
*) Добавление: директива recursive_error_pages.
*) Исправление: директива rewrite возвращала неправильный редирект,
если редирект включал в себя выделенные закодированные символы из
оригинального URI.
Изменения в nginx 0.3.60 18.08.2006
*) Исправление: во время перенаправления ошибки рабочий процесс мог
зациклиться; ошибка появилась в 0.3.59.
Изменения в nginx 0.3.59 16.08.2006
*) Добавление: теперь можно делать несколько перенаправлений через
директиву error_page.
*) Исправление: директива dav_access не поддерживала три параметра.
*) Исправление: директива error_page не изменяла строку "Content-Type"
после перенаправления с помощью "X-Accel-Redirect"; ошибка появилась
в 0.3.58.
Изменения в nginx 0.3.58 14.08.2006
*) Добавление: директива error_page поддерживает переменные.
*) Изменение: теперь на Linux используется интерфейс procfs вместо
sysctl.
*) Изменение: теперь при использовании "X-Accel-Redirect" строка
"Content-Type" наследуется из первоначального ответа.
*) Исправление: директива error_page не перенаправляла ошибку 413.
*) Исправление: завершающий "?" не удалял старые аргументы, если в
переписанном URI не было новых аргументов.
*) Исправление: nginx не запускался на 64-битной FreeBSD 7.0-CURRENT.
Изменения в nginx 0.3.57 09.08.2006
*) Добавление: переменная $ssl_client_serial.
*) Исправление: в операторе "!-e" в директиве if.
Спасибо Андриану Буданцову.
*) Исправление: при проверке клиентского сертификата nginx не передавал
клиенту информацию о требуемых сертификатах.
*) Исправление: переменная $document_root не поддерживала переменные в
директиве root.
Изменения в nginx 0.3.56 04.08.2006
*) Добавление: директива dav_access.
*) Добавление: директива if поддерживает операторы "-d", "!-d", "-e",
"!-e", "-x" и "!-x".
*) Исправление: при записи в access_log некоторых передаваемых клиенту
строк заголовков происходил segmentation fault, если запрос
возвращал редирект.
Изменения в nginx 0.3.55 28.07.2006
*) Добавление: параметр stub в команде SSI include.
*) Добавление: команда SSI block.
*) Добавление: скрипт unicode2nginx добавлен в contrib.
*) Исправление: если root был задан только переменной, то корень
задавался относительно префикса сервера.
*) Исправление: если в запросе был "//" или "/.", и после этого
закодированные символы в виде "%XX", то проксируемый запрос
передавался незакодированным.
*) Исправление: метод $r->header_in("Cookie") модуля
ngx_http_perl_module теперь возвращает все строки "Cookie" в
заголовке запроса.
*) Исправление: происходил segmentation fault, если использовался
"client_body_in_file_only on" и делался переход к следующему бэкенду.
*) Исправление: при некоторых условиях во время переконфигурации коды
символов внутри директивы charset_map могли считаться неверными;
ошибка появилась в 0.3.50.
Изменения в nginx 0.3.54 11.07.2006
*) Добавление: nginx теперь записывает в лог информацию о подзапросах.
*) Добавление: директивы proxy_next_upstream, fastcgi_next_upstream и
memcached_next_upstream поддерживают параметр off.
*) Добавление: директива debug_connection поддерживает запись адресов в
формате CIDR.
*) Исправление: при перекодировании ответа проксированного сервера или
сервера FastCGI в UTF-8 или наоборот ответ мог передаваться не
полностью.
*) Исправление: переменная $upstream_response_time содержала время
только первого обращения к бэкенду.
*) Исправление: nginx не собирался на платформе amd64; ошибка появилась
в 0.3.53.
Изменения в nginx 0.3.53 07.07.2006
*) Изменение: директива add_header добавляет строки в ответы с кодом
204, 301 и 302.
*) Добавление: директива server в блоке upstream поддерживает параметр
weight.
*) Добавление: директива server_name поддерживает маску "*".
*) Добавление: nginx поддерживает тело запроса больше 2G.
*) Исправление: если при использовании "satisfy_any on" клиент успешно
проходил аутентификацию, в лог всё равно записалоcь сообщение
"access forbidden by rule".
*) Исправление: метод PUT мог ошибочно не создать файл и вернуть код
409.
*) Исправление: если во время аутентификации IMAP/POP3 бэкенд возвращал
ошибку, nginx продолжал проксирование.
Изменения в nginx 0.3.52 03.07.2006
*) Изменение: восстановлено поведение модуля ngx_http_index_module для
запросов "POST /": как в версии до 0.3.40, модуль теперь не выдаёт
ошибку 405.
*) Исправление: при использовании ограничения скорости рабочий процесс
мог зациклиться; ошибка появилась в 0.3.37.
*) Исправление: модуль ngx_http_charset_module записывал в лог ошибку
"unknown charset", даже если перекодировка не требовалась; ошибка
появилась в 0.3.50.
*) Исправление: если в результате запроса PUT возвращался код 409, то
временный файл не удалялся.
Изменения в nginx 0.3.51 30.06.2006
*) Исправление: при некоторых условиях в SSI мог пропадать символы "<";
ошибка появилась в 0.3.50.
Изменения в nginx 0.3.50 28.06.2006
*) Изменение: директивы proxy_redirect_errors и fastcgi_redirect_errors
переименованы соответственно в proxy_intercept_errors и
fastcgi_intercept_errors.
*) Добавление: модуль ngx_http_charset_module поддерживает
перекодирование из однобайтных кодировок в UTF-8 и обратно.
*) Добавление: в режиме прокси и FastCGI поддерживается строка
заголовка "X-Accel-Charset" в ответе бэкенда.
*) Исправление: символ "\" в парах "\"" и "\'" в SSI командах убирался,
только если также использовался символ "$".
*) Исправление: при некоторых условиях в SSI после вставки могла быть
добавлена строка "" CRLF
"" CRLF
"" CRLF
"" CRLF
"" CRLF
"" CRLF
;
static u_char ngx_http_msie_refresh_head[] =
"
" CRLF;
static char ngx_http_error_301_page[] =
"" CRLF
"301 Moved Permanently" CRLF
"" CRLF
"301 Moved Permanently
" CRLF
;
static char ngx_http_error_302_page[] =
"" CRLF
"302 Found" CRLF
"" CRLF
"302 Found
" CRLF
;
static char ngx_http_error_400_page[] =
"" CRLF
"400 Bad Request" CRLF
"" CRLF
"400 Bad Request
" CRLF
;
static char ngx_http_error_401_page[] =
"" CRLF
"401 Authorization Required" CRLF
"" CRLF
"401 Authorization Required
" CRLF
;
static char ngx_http_error_402_page[] =
"" CRLF
"402 Payment Required" CRLF
"" CRLF
"402 Payment Required
" CRLF
;
static char ngx_http_error_403_page[] =
"" CRLF
"403 Forbidden" CRLF
"" CRLF
"403 Forbidden
" CRLF
;
static char ngx_http_error_404_page[] =
"" CRLF
"404 Not Found" CRLF
"" CRLF
"404 Not Found
" CRLF
;
static char ngx_http_error_405_page[] =
"" CRLF
"405 Not Allowed" CRLF
"" CRLF
"405 Not Allowed
" CRLF
;
static char ngx_http_error_406_page[] =
"" CRLF
"406 Not Acceptable" CRLF
"" CRLF
"406 Not Acceptable
" CRLF
;
static char ngx_http_error_408_page[] =
"" CRLF
"408 Request Time-out" CRLF
"" CRLF
"408 Request Time-out
" CRLF
;
static char ngx_http_error_409_page[] =
"" CRLF
"409 Conflict" CRLF
"" CRLF
"409 Conflict
" CRLF
;
static char ngx_http_error_410_page[] =
"" CRLF
"410 Gone" CRLF
"" CRLF
"410 Gone
" CRLF
;
static char ngx_http_error_411_page[] =
"" CRLF
"411 Length Required" CRLF
"" CRLF
"411 Length Required
" CRLF
;
static char ngx_http_error_412_page[] =
"" CRLF
"412 Precondition Failed" CRLF
"" CRLF
"412 Precondition Failed
" CRLF
;
static char ngx_http_error_413_page[] =
"" CRLF
"413 Request Entity Too Large" CRLF
"" CRLF
"413 Request Entity Too Large
" CRLF
;
static char ngx_http_error_414_page[] =
"" CRLF
"414 Request-URI Too Large" CRLF
"" CRLF
"414 Request-URI Too Large
" CRLF
;
static char ngx_http_error_415_page[] =
"" CRLF
"415 Unsupported Media Type" CRLF
"" CRLF
"415 Unsupported Media Type
" CRLF
;
static char ngx_http_error_416_page[] =
"" CRLF
"416 Requested Range Not Satisfiable" CRLF
"" CRLF
"416 Requested Range Not Satisfiable
" CRLF
;
static char ngx_http_error_495_page[] =
"" CRLF
"400 The SSL certificate error"
CRLF
"" CRLF
"400 Bad Request
" CRLF
"The SSL certificate error" CRLF
;
static char ngx_http_error_496_page[] =
"" CRLF
"400 No required SSL certificate was sent"
CRLF
"" CRLF
"400 Bad Request
" CRLF
"No required SSL certificate was sent" CRLF
;
static char ngx_http_error_497_page[] =
"" CRLF
"400 The plain HTTP request was sent to HTTPS port"
CRLF
"" CRLF
"400 Bad Request
" CRLF
"The plain HTTP request was sent to HTTPS port" CRLF
;
static char ngx_http_error_500_page[] =
"" CRLF
"500 Internal Server Error" CRLF
"" CRLF
"500 Internal Server Error
" CRLF
;
static char ngx_http_error_501_page[] =
"" CRLF
"501 Method Not Implemented" CRLF
"" CRLF
"501 Method Not Implemented
" CRLF
;
static char ngx_http_error_502_page[] =
"" CRLF
"502 Bad Gateway" CRLF
"" CRLF
"502 Bad Gateway
" CRLF
;
static char ngx_http_error_503_page[] =
"" CRLF
"503 Service Temporarily Unavailable" CRLF
"" CRLF
"503 Service Temporarily Unavailable
" CRLF
;
static char ngx_http_error_504_page[] =
"" CRLF
"504 Gateway Time-out" CRLF
"" CRLF
"504 Gateway Time-out
" CRLF
;
static char ngx_http_error_507_page[] =
"" CRLF
"507 Insufficient Storage" CRLF
"" CRLF
"507 Insufficient Storage
" CRLF
;
static ngx_str_t ngx_http_error_pages[] = {
ngx_null_string, /* 201, 204 */
#define NGX_HTTP_LAST_LEVEL_200 202
#define NGX_HTTP_LEVEL_200 (NGX_HTTP_LAST_LEVEL_200 - 201)
/* ngx_null_string, */ /* 300 */
ngx_string(ngx_http_error_301_page),
ngx_string(ngx_http_error_302_page),
ngx_null_string, /* 303 */
#define NGX_HTTP_LAST_LEVEL_300 304
#define NGX_HTTP_LEVEL_300 (NGX_HTTP_LAST_LEVEL_300 - 301)
ngx_string(ngx_http_error_400_page),
ngx_string(ngx_http_error_401_page),
ngx_string(ngx_http_error_402_page),
ngx_string(ngx_http_error_403_page),
ngx_string(ngx_http_error_404_page),
ngx_string(ngx_http_error_405_page),
ngx_string(ngx_http_error_406_page),
ngx_null_string, /* 407 */
ngx_string(ngx_http_error_408_page),
ngx_string(ngx_http_error_409_page),
ngx_string(ngx_http_error_410_page),
ngx_string(ngx_http_error_411_page),
ngx_string(ngx_http_error_412_page),
ngx_string(ngx_http_error_413_page),
ngx_string(ngx_http_error_414_page),
ngx_string(ngx_http_error_415_page),
ngx_string(ngx_http_error_416_page),
#define NGX_HTTP_LAST_LEVEL_400 417
#define NGX_HTTP_LEVEL_400 (NGX_HTTP_LAST_LEVEL_400 - 400)
ngx_string(ngx_http_error_495_page), /* 495, https certificate error */
ngx_string(ngx_http_error_496_page), /* 496, https no certificate */
ngx_string(ngx_http_error_497_page), /* 497, http to https */
ngx_string(ngx_http_error_404_page), /* 498, canceled */
ngx_null_string, /* 499, client has closed connection */
ngx_string(ngx_http_error_500_page),
ngx_string(ngx_http_error_501_page),
ngx_string(ngx_http_error_502_page),
ngx_string(ngx_http_error_503_page),
ngx_string(ngx_http_error_504_page),
ngx_null_string, /* 505 */
ngx_null_string, /* 506 */
ngx_string(ngx_http_error_507_page)
#define NGX_HTTP_LAST_LEVEL_500 508
};
static ngx_str_t ngx_http_get_name = { 3, (u_char *) "GET " };
ngx_int_t
ngx_http_special_response_handler(ngx_http_request_t *r, ngx_int_t error)
{
ngx_uint_t i, err;
ngx_http_err_page_t *err_page;
ngx_http_core_loc_conf_t *clcf;
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http special response: %d, \"%V?%V\"",
error, &r->uri, &r->args);
r->err_status = error;
if (r->keepalive) {
switch (error) {
case NGX_HTTP_BAD_REQUEST:
case NGX_HTTP_REQUEST_ENTITY_TOO_LARGE:
case NGX_HTTP_REQUEST_URI_TOO_LARGE:
case NGX_HTTP_TO_HTTPS:
case NGX_HTTPS_CERT_ERROR:
case NGX_HTTPS_NO_CERT:
case NGX_HTTP_INTERNAL_SERVER_ERROR:
r->keepalive = 0;
}
}
if (r->lingering_close == 1) {
switch (error) {
case NGX_HTTP_BAD_REQUEST:
case NGX_HTTP_TO_HTTPS:
case NGX_HTTPS_CERT_ERROR:
case NGX_HTTPS_NO_CERT:
r->lingering_close = 0;
}
}
r->headers_out.content_type.len = 0;
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (!r->error_page && clcf->error_pages && r->uri_changes != 0) {
if (clcf->recursive_error_pages == 0) {
r->error_page = 1;
}
err_page = clcf->error_pages->elts;
for (i = 0; i < clcf->error_pages->nelts; i++) {
if (err_page[i].status == error) {
return ngx_http_send_error_page(r, &err_page[i]);
}
}
}
r->expect_tested = 1;
if (ngx_http_discard_request_body(r) != NGX_OK) {
error = NGX_HTTP_INTERNAL_SERVER_ERROR;
}
if (clcf->msie_refresh
&& r->headers_in.msie
&& (error == NGX_HTTP_MOVED_PERMANENTLY
|| error == NGX_HTTP_MOVED_TEMPORARILY))
{
return ngx_http_send_refresh(r);
}
if (error == NGX_HTTP_CREATED) {
/* 201 */
err = 0;
r->header_only = 1;
} else if (error == NGX_HTTP_NO_CONTENT) {
/* 204 */
err = 0;
} else if (error >= NGX_HTTP_MOVED_PERMANENTLY
&& error < NGX_HTTP_LAST_LEVEL_300)
{
/* 3XX */
err = error - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_LEVEL_200;
} else if (error >= NGX_HTTP_BAD_REQUEST
&& error < NGX_HTTP_LAST_LEVEL_400)
{
/* 4XX */
err = error - NGX_HTTP_BAD_REQUEST + NGX_HTTP_LEVEL_200
+ NGX_HTTP_LEVEL_300;
} else if (error >= NGX_HTTP_OWN_CODES
&& error < NGX_HTTP_LAST_LEVEL_500)
{
/* 49X, 5XX */
err = error - NGX_HTTP_OWN_CODES + NGX_HTTP_LEVEL_200
+ NGX_HTTP_LEVEL_300
+ NGX_HTTP_LEVEL_400;
switch (error) {
case NGX_HTTP_TO_HTTPS:
case NGX_HTTPS_CERT_ERROR:
case NGX_HTTPS_NO_CERT:
r->err_status = NGX_HTTP_BAD_REQUEST;
break;
}
} else {
/* unknown code, zero body */
err = 0;
}
return ngx_http_send_special_response(r, clcf, err);
}
ngx_int_t
ngx_http_filter_finalize_request(ngx_http_request_t *r, ngx_module_t *m,
ngx_int_t error)
{
void *ctx;
ngx_int_t rc;
ngx_http_clean_header(r);
ctx = NULL;
if (m) {
ctx = r->ctx[m->ctx_index];
}
/* clear the modules contexts */
ngx_memzero(r->ctx, sizeof(void *) * ngx_http_max_module);
if (m) {
r->ctx[m->ctx_index] = ctx;
}
r->filter_finalize = 1;
rc = ngx_http_special_response_handler(r, error);
/* NGX_ERROR resets any pending data */
switch (rc) {
case NGX_OK:
case NGX_DONE:
return NGX_ERROR;
default:
return rc;
}
}
void
ngx_http_clean_header(ngx_http_request_t *r)
{
ngx_memzero(&r->headers_out.status,
sizeof(ngx_http_headers_out_t)
- offsetof(ngx_http_headers_out_t, status));
r->headers_out.headers.part.nelts = 0;
r->headers_out.headers.part.next = NULL;
r->headers_out.headers.last = &r->headers_out.headers.part;
r->headers_out.content_length_n = -1;
r->headers_out.last_modified_time = -1;
}
static ngx_int_t
ngx_http_send_error_page(ngx_http_request_t *r, ngx_http_err_page_t *err_page)
{
ngx_int_t overwrite;
ngx_str_t uri, args;
ngx_table_elt_t *location;
ngx_http_core_loc_conf_t *clcf;
overwrite = err_page->overwrite;
if (overwrite && overwrite != NGX_HTTP_OK) {
r->expect_tested = 1;
}
r->err_status = overwrite;
if (ngx_http_complex_value(r, &err_page->value, &uri) != NGX_OK) {
return NGX_ERROR;
}
if (uri.data[0] == '/') {
if (err_page->value.lengths) {
ngx_http_split_args(r, &uri, &args);
} else {
args = err_page->args;
}
if (r->method != NGX_HTTP_HEAD) {
r->method = NGX_HTTP_GET;
r->method_name = ngx_http_get_name;
}
return ngx_http_internal_redirect(r, &uri, &args);
}
if (uri.data[0] == '@') {
return ngx_http_named_location(r, &uri);
}
location = ngx_list_push(&r->headers_out.headers);
if (location == NULL) {
return NGX_ERROR;
}
r->err_status = NGX_HTTP_MOVED_TEMPORARILY;
location->hash = 1;
location->key.len = sizeof("Location") - 1;
location->key.data = (u_char *) "Location";
location->value = uri;
r->headers_out.location = location;
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (clcf->msie_refresh && r->headers_in.msie) {
return ngx_http_send_refresh(r);
}
return ngx_http_send_special_response(r, clcf, NGX_HTTP_MOVED_TEMPORARILY
- NGX_HTTP_MOVED_PERMANENTLY
+ NGX_HTTP_LEVEL_200);
}
static ngx_int_t
ngx_http_send_special_response(ngx_http_request_t *r,
ngx_http_core_loc_conf_t *clcf, ngx_uint_t err)
{
u_char *tail;
size_t len;
ngx_int_t rc;
ngx_buf_t *b;
ngx_uint_t msie_padding;
ngx_chain_t out[3];
if (clcf->server_tokens) {
len = sizeof(ngx_http_error_full_tail) - 1;
tail = ngx_http_error_full_tail;
} else {
len = sizeof(ngx_http_error_tail) - 1;
tail = ngx_http_error_tail;
}
msie_padding = 0;
if (!r->zero_body) {
if (ngx_http_error_pages[err].len) {
r->headers_out.content_length_n = ngx_http_error_pages[err].len
+ len;
if (clcf->msie_padding
&& (r->headers_in.msie || r->headers_in.chrome)
&& r->http_version >= NGX_HTTP_VERSION_10
&& err >= NGX_HTTP_LEVEL_300)
{
r->headers_out.content_length_n +=
sizeof(ngx_http_msie_padding) - 1;
msie_padding = 1;
}
r->headers_out.content_type_len = sizeof("text/html") - 1;
r->headers_out.content_type.len = sizeof("text/html") - 1;
r->headers_out.content_type.data = (u_char *) "text/html";
r->headers_out.content_type_lowcase = NULL;
} else {
r->headers_out.content_length_n = -1;
}
} else {
r->headers_out.content_length_n = 0;
err = 0;
}
if (r->headers_out.content_length) {
r->headers_out.content_length->hash = 0;
r->headers_out.content_length = NULL;
}
ngx_http_clear_accept_ranges(r);
ngx_http_clear_last_modified(r);
rc = ngx_http_send_header(r);
if (rc == NGX_ERROR || r->header_only) {
return rc;
}
if (ngx_http_error_pages[err].len == 0) {
return NGX_OK;
}
b = ngx_calloc_buf(r->pool);
if (b == NULL) {
return NGX_ERROR;
}
b->memory = 1;
b->pos = ngx_http_error_pages[err].data;
b->last = ngx_http_error_pages[err].data + ngx_http_error_pages[err].len;
out[0].buf = b;
out[0].next = &out[1];
b = ngx_calloc_buf(r->pool);
if (b == NULL) {
return NGX_ERROR;
}
b->memory = 1;
b->pos = tail;
b->last = tail + len;
out[1].buf = b;
out[1].next = NULL;
if (msie_padding) {
b = ngx_calloc_buf(r->pool);
if (b == NULL) {
return NGX_ERROR;
}
b->memory = 1;
b->pos = ngx_http_msie_padding;
b->last = ngx_http_msie_padding + sizeof(ngx_http_msie_padding) - 1;
out[1].next = &out[2];
out[2].buf = b;
out[2].next = NULL;
}
if (r == r->main) {
b->last_buf = 1;
}
b->last_in_chain = 1;
return ngx_http_output_filter(r, &out[0]);
}
static ngx_int_t
ngx_http_send_refresh(ngx_http_request_t *r)
{
u_char *p, *location;
size_t len, size;
uintptr_t escape;
ngx_int_t rc;
ngx_buf_t *b;
ngx_chain_t out;
len = r->headers_out.location->value.len;
location = r->headers_out.location->value.data;
escape = 2 * ngx_escape_uri(NULL, location, len, NGX_ESCAPE_REFRESH);
size = sizeof(ngx_http_msie_refresh_head) - 1
+ escape + len
+ sizeof(ngx_http_msie_refresh_tail) - 1;
r->err_status = NGX_HTTP_OK;
r->headers_out.content_type_len = sizeof("text/html") - 1;
r->headers_out.content_type.len = sizeof("text/html") - 1;
r->headers_out.content_type.data = (u_char *) "text/html";
r->headers_out.content_type_lowcase = NULL;
r->headers_out.location->hash = 0;
r->headers_out.location = NULL;
r->headers_out.content_length_n = size;
if (r->headers_out.content_length) {
r->headers_out.content_length->hash = 0;
r->headers_out.content_length = NULL;
}
ngx_http_clear_accept_ranges(r);
ngx_http_clear_last_modified(r);
rc = ngx_http_send_header(r);
if (rc == NGX_ERROR || r->header_only) {
return rc;
}
b = ngx_create_temp_buf(r->pool, size);
if (b == NULL) {
return NGX_ERROR;
}
p = ngx_cpymem(b->pos, ngx_http_msie_refresh_head,
sizeof(ngx_http_msie_refresh_head) - 1);
if (escape == 0) {
p = ngx_cpymem(p, location, len);
} else {
p = (u_char *) ngx_escape_uri(p, location, len, NGX_ESCAPE_REFRESH);
}
b->last = ngx_cpymem(p, ngx_http_msie_refresh_tail,
sizeof(ngx_http_msie_refresh_tail) - 1);
b->last_buf = 1;
b->last_in_chain = 1;
out.buf = b;
out.next = NULL;
return ngx_http_output_filter(r, &out);
}
nginx-0.7.68/src/http/ngx_http_busy_lock.c 000644 001750 001750 00000014677 10704463117 017670 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#include
#include
#include
static int ngx_http_busy_lock_look_cacheable(ngx_http_busy_lock_t *bl,
ngx_http_busy_lock_ctx_t *bc,
int lock);
int ngx_http_busy_lock(ngx_http_busy_lock_t *bl, ngx_http_busy_lock_ctx_t *bc)
{
if (bl->busy < bl->max_busy) {
bl->busy++;
if (bc->time) {
bc->time = 0;
bl->waiting--;
}
return NGX_OK;
}
if (bc->time) {
if (bc->time < bl->timeout) {
ngx_add_timer(bc->event, 1000);
return NGX_AGAIN;
}
bl->waiting--;
return NGX_DONE;
}
if (bl->timeout == 0) {
return NGX_DONE;
}
if (bl->waiting < bl->max_waiting) {
bl->waiting++;
#if 0
ngx_add_timer(bc->event, 1000);
bc->event->event_handler = bc->event_handler;
#endif
/* TODO: ngx_handle_level_read_event() */
return NGX_AGAIN;
}
return NGX_ERROR;
}
int ngx_http_busy_lock_cacheable(ngx_http_busy_lock_t *bl,
ngx_http_busy_lock_ctx_t *bc, int lock)
{
int rc;
rc = ngx_http_busy_lock_look_cacheable(bl, bc, lock);
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, bc->event->log, 0,
"http busylock: %d w:%d mw::%d",
rc, bl->waiting, bl->max_waiting);
if (rc == NGX_OK) { /* no the same request, there's free slot */
return NGX_OK;
}
if (rc == NGX_ERROR && !lock) { /* no the same request, no free slot */
return NGX_OK;
}
/* rc == NGX_AGAIN: the same request */
if (bc->time) {
if (bc->time < bl->timeout) {
ngx_add_timer(bc->event, 1000);
return NGX_AGAIN;
}
bl->waiting--;
return NGX_DONE;
}
if (bl->timeout == 0) {
return NGX_DONE;
}
if (bl->waiting < bl->max_waiting) {
#if 0
bl->waiting++;
ngx_add_timer(bc->event, 1000);
bc->event->event_handler = bc->event_handler;
#endif
/* TODO: ngx_handle_level_read_event() */
return NGX_AGAIN;
}
return NGX_ERROR;
}
void ngx_http_busy_unlock(ngx_http_busy_lock_t *bl,
ngx_http_busy_lock_ctx_t *bc)
{
if (bl == NULL) {
return;
}
if (bl->md5) {
bl->md5_mask[bc->slot / 8] &= ~(1 << (bc->slot & 7));
bl->cacheable--;
}
bl->busy--;
}
static int ngx_http_busy_lock_look_cacheable(ngx_http_busy_lock_t *bl,
ngx_http_busy_lock_ctx_t *bc,
int lock)
{
int i, b, cacheable, free;
u_int mask;
b = 0;
cacheable = 0;
free = -1;
#if (NGX_SUPPRESS_WARN)
mask = 0;
#endif
for (i = 0; i < bl->max_busy; i++) {
if ((b & 7) == 0) {
mask = bl->md5_mask[i / 8];
}
if (mask & 1) {
if (ngx_memcmp(&bl->md5[i * 16], bc->md5, 16) == 0) {
return NGX_AGAIN;
}
cacheable++;
} else if (free == -1) {
free = i;
}
#if 1
if (cacheable == bl->cacheable) {
if (free == -1 && cacheable < bl->max_busy) {
free = i + 1;
}
break;
}
#endif
mask >>= 1;
b++;
}
if (free == -1) {
return NGX_ERROR;
}
if (lock) {
if (bl->busy == bl->max_busy) {
return NGX_ERROR;
}
ngx_memcpy(&bl->md5[free * 16], bc->md5, 16);
bl->md5_mask[free / 8] |= 1 << (free & 7);
bc->slot = free;
bl->cacheable++;
bl->busy++;
}
return NGX_OK;
}
char *ngx_http_set_busy_lock_slot(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf)
{
char *p = conf;
ngx_uint_t i, dup, invalid;
ngx_str_t *value, line;
ngx_http_busy_lock_t *bl, **blp;
blp = (ngx_http_busy_lock_t **) (p + cmd->offset);
if (*blp) {
return "is duplicate";
}
/* ngx_calloc_shared() */
bl = ngx_pcalloc(cf->pool, sizeof(ngx_http_busy_lock_t));
if (bl == NULL) {
return NGX_CONF_ERROR;
}
*blp = bl;
/* ngx_calloc_shared() */
bl->mutex = ngx_pcalloc(cf->pool, sizeof(ngx_event_mutex_t));
if (bl->mutex == NULL) {
return NGX_CONF_ERROR;
}
dup = 0;
invalid = 0;
value = cf->args->elts;
for (i = 1; i < cf->args->nelts; i++) {
if (value[i].data[1] != '=') {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid value \"%s\"", value[i].data);
return NGX_CONF_ERROR;
}
switch (value[i].data[0]) {
case 'b':
if (bl->max_busy) {
dup = 1;
break;
}
bl->max_busy = ngx_atoi(value[i].data + 2, value[i].len - 2);
if (bl->max_busy == NGX_ERROR) {
invalid = 1;
break;
}
continue;
case 'w':
if (bl->max_waiting) {
dup = 1;
break;
}
bl->max_waiting = ngx_atoi(value[i].data + 2, value[i].len - 2);
if (bl->max_waiting == NGX_ERROR) {
invalid = 1;
break;
}
continue;
case 't':
if (bl->timeout) {
dup = 1;
break;
}
line.len = value[i].len - 2;
line.data = value[i].data + 2;
bl->timeout = ngx_parse_time(&line, 1);
if (bl->timeout == NGX_ERROR) {
invalid = 1;
break;
}
continue;
default:
invalid = 1;
}
if (dup) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"duplicate value \"%s\"", value[i].data);
return NGX_CONF_ERROR;
}
if (invalid) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid value \"%s\"", value[i].data);
return NGX_CONF_ERROR;
}
}
if (bl->timeout == 0 && bl->max_waiting) {
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
"busy lock waiting is useless with zero timeout, ignoring");
}
return NGX_CONF_OK;
}
nginx-0.7.68/src/http/ngx_http_core_module.c 000644 001750 001750 00000353125 11501741074 020162 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#include
#include
#include
typedef struct {
u_char *name;
uint32_t method;
} ngx_http_method_name_t;
#define NGX_HTTP_REQUEST_BODY_FILE_OFF 0
#define NGX_HTTP_REQUEST_BODY_FILE_ON 1
#define NGX_HTTP_REQUEST_BODY_FILE_CLEAN 2
static ngx_int_t ngx_http_core_find_location(ngx_http_request_t *r);
static ngx_int_t ngx_http_core_find_static_location(ngx_http_request_t *r,
ngx_http_location_tree_node_t *node);
static ngx_int_t ngx_http_core_preconfiguration(ngx_conf_t *cf);
static void *ngx_http_core_create_main_conf(ngx_conf_t *cf);
static char *ngx_http_core_init_main_conf(ngx_conf_t *cf, void *conf);
static void *ngx_http_core_create_srv_conf(ngx_conf_t *cf);
static char *ngx_http_core_merge_srv_conf(ngx_conf_t *cf,
void *parent, void *child);
static void *ngx_http_core_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_core_merge_loc_conf(ngx_conf_t *cf,
void *parent, void *child);
static char *ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd,
void *dummy);
static char *ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd,
void *dummy);
static ngx_int_t ngx_http_core_regex_location(ngx_conf_t *cf,
ngx_http_core_loc_conf_t *clcf, ngx_str_t *regex, ngx_uint_t caseless);
static char *ngx_http_core_types(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_core_type(ngx_conf_t *cf, ngx_command_t *dummy,
void *conf);
static char *ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_core_server_name(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_core_root(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static char *ngx_http_core_limit_except(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_core_directio(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_core_try_files(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_core_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_core_keepalive(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_core_internal(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
#if (NGX_HTTP_GZIP)
static char *ngx_http_gzip_disable(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
#endif
static char *ngx_http_core_lowat_check(ngx_conf_t *cf, void *post, void *data);
static char *ngx_http_core_pool_size(ngx_conf_t *cf, void *post, void *data);
static ngx_conf_post_t ngx_http_core_lowat_post =
{ ngx_http_core_lowat_check };
static ngx_conf_post_handler_pt ngx_http_core_pool_size_p =
ngx_http_core_pool_size;
static ngx_conf_deprecated_t ngx_conf_deprecated_optimize_server_names = {
ngx_conf_deprecated, "optimize_server_names", "server_name_in_redirect"
};
static ngx_conf_deprecated_t ngx_conf_deprecated_open_file_cache_retest = {
ngx_conf_deprecated, "open_file_cache_retest", "open_file_cache_valid"
};
static ngx_conf_deprecated_t ngx_conf_deprecated_satisfy_any = {
ngx_conf_deprecated, "satisfy_any", "satisfy"
};
static ngx_conf_enum_t ngx_http_core_request_body_in_file[] = {
{ ngx_string("off"), NGX_HTTP_REQUEST_BODY_FILE_OFF },
{ ngx_string("on"), NGX_HTTP_REQUEST_BODY_FILE_ON },
{ ngx_string("clean"), NGX_HTTP_REQUEST_BODY_FILE_CLEAN },
{ ngx_null_string, 0 }
};
static ngx_conf_enum_t ngx_http_core_satisfy[] = {
{ ngx_string("all"), NGX_HTTP_SATISFY_ALL },
{ ngx_string("any"), NGX_HTTP_SATISFY_ANY },
{ ngx_null_string, 0 }
};
static ngx_conf_enum_t ngx_http_core_if_modified_since[] = {
{ ngx_string("off"), NGX_HTTP_IMS_OFF },
{ ngx_string("exact"), NGX_HTTP_IMS_EXACT },
{ ngx_string("before"), NGX_HTTP_IMS_BEFORE },
{ ngx_null_string, 0 }
};
static ngx_path_init_t ngx_http_client_temp_path = {
ngx_string(NGX_HTTP_CLIENT_TEMP_PATH), { 0, 0, 0 }
};
#if (NGX_HTTP_GZIP)
static ngx_conf_enum_t ngx_http_gzip_http_version[] = {
{ ngx_string("1.0"), NGX_HTTP_VERSION_10 },
{ ngx_string("1.1"), NGX_HTTP_VERSION_11 },
{ ngx_null_string, 0 }
};
static ngx_conf_bitmask_t ngx_http_gzip_proxied_mask[] = {
{ ngx_string("off"), NGX_HTTP_GZIP_PROXIED_OFF },
{ ngx_string("expired"), NGX_HTTP_GZIP_PROXIED_EXPIRED },
{ ngx_string("no-cache"), NGX_HTTP_GZIP_PROXIED_NO_CACHE },
{ ngx_string("no-store"), NGX_HTTP_GZIP_PROXIED_NO_STORE },
{ ngx_string("private"), NGX_HTTP_GZIP_PROXIED_PRIVATE },
{ ngx_string("no_last_modified"), NGX_HTTP_GZIP_PROXIED_NO_LM },
{ ngx_string("no_etag"), NGX_HTTP_GZIP_PROXIED_NO_ETAG },
{ ngx_string("auth"), NGX_HTTP_GZIP_PROXIED_AUTH },
{ ngx_string("any"), NGX_HTTP_GZIP_PROXIED_ANY },
{ ngx_null_string, 0 }
};
static ngx_str_t ngx_http_gzip_no_cache = ngx_string("no-cache");
static ngx_str_t ngx_http_gzip_no_store = ngx_string("no-store");
static ngx_str_t ngx_http_gzip_private = ngx_string("private");
#endif
static ngx_command_t ngx_http_core_commands[] = {
{ ngx_string("variables_hash_max_size"),
NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_HTTP_MAIN_CONF_OFFSET,
offsetof(ngx_http_core_main_conf_t, variables_hash_max_size),
NULL },
{ ngx_string("variables_hash_bucket_size"),
NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_HTTP_MAIN_CONF_OFFSET,
offsetof(ngx_http_core_main_conf_t, variables_hash_bucket_size),
NULL },
{ ngx_string("server_names_hash_max_size"),
NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_HTTP_MAIN_CONF_OFFSET,
offsetof(ngx_http_core_main_conf_t, server_names_hash_max_size),
NULL },
{ ngx_string("server_names_hash_bucket_size"),
NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_HTTP_MAIN_CONF_OFFSET,
offsetof(ngx_http_core_main_conf_t, server_names_hash_bucket_size),
NULL },
{ ngx_string("server"),
NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_MULTI|NGX_CONF_NOARGS,
ngx_http_core_server,
0,
0,
NULL },
{ ngx_string("connection_pool_size"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_core_srv_conf_t, connection_pool_size),
&ngx_http_core_pool_size_p },
{ ngx_string("request_pool_size"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_core_srv_conf_t, request_pool_size),
&ngx_http_core_pool_size_p },
{ ngx_string("client_header_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_msec_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_core_srv_conf_t, client_header_timeout),
NULL },
{ ngx_string("client_header_buffer_size"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_core_srv_conf_t, client_header_buffer_size),
NULL },
{ ngx_string("large_client_header_buffers"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE2,
ngx_conf_set_bufs_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_core_srv_conf_t, large_client_header_buffers),
NULL },
{ ngx_string("optimize_server_names"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, server_name_in_redirect),
&ngx_conf_deprecated_optimize_server_names },
{ ngx_string("ignore_invalid_headers"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_core_srv_conf_t, ignore_invalid_headers),
NULL },
{ ngx_string("merge_slashes"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_core_srv_conf_t, merge_slashes),
NULL },
{ ngx_string("underscores_in_headers"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_core_srv_conf_t, underscores_in_headers),
NULL },
{ ngx_string("location"),
NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE12,
ngx_http_core_location,
NGX_HTTP_SRV_CONF_OFFSET,
0,
NULL },
{ ngx_string("listen"),
NGX_HTTP_SRV_CONF|NGX_CONF_1MORE,
ngx_http_core_listen,
NGX_HTTP_SRV_CONF_OFFSET,
0,
NULL },
{ ngx_string("server_name"),
NGX_HTTP_SRV_CONF|NGX_CONF_1MORE,
ngx_http_core_server_name,
NGX_HTTP_SRV_CONF_OFFSET,
0,
NULL },
{ ngx_string("types_hash_max_size"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, types_hash_max_size),
NULL },
{ ngx_string("types_hash_bucket_size"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, types_hash_bucket_size),
NULL },
{ ngx_string("types"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF
|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
ngx_http_core_types,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("default_type"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, default_type),
NULL },
{ ngx_string("root"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|NGX_CONF_TAKE1,
ngx_http_core_root,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("alias"),
NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_http_core_root,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("limit_except"),
NGX_HTTP_LOC_CONF|NGX_CONF_BLOCK|NGX_CONF_1MORE,
ngx_http_core_limit_except,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("client_max_body_size"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_off_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, client_max_body_size),
NULL },
{ ngx_string("client_body_buffer_size"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, client_body_buffer_size),
NULL },
{ ngx_string("client_body_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_msec_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, client_body_timeout),
NULL },
{ ngx_string("client_body_temp_path"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
ngx_conf_set_path_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, client_body_temp_path),
NULL },
{ ngx_string("client_body_in_file_only"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_enum_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, client_body_in_file_only),
&ngx_http_core_request_body_in_file },
{ ngx_string("client_body_in_single_buffer"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, client_body_in_single_buffer),
NULL },
{ ngx_string("sendfile"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|NGX_CONF_TAKE1,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, sendfile),
NULL },
{ ngx_string("sendfile_max_chunk"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, sendfile_max_chunk),
NULL },
{ ngx_string("directio"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_http_core_directio,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("tcp_nopush"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, tcp_nopush),
NULL },
{ ngx_string("tcp_nodelay"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, tcp_nodelay),
NULL },
{ ngx_string("send_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_msec_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, send_timeout),
NULL },
{ ngx_string("send_lowat"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, send_lowat),
&ngx_http_core_lowat_post },
{ ngx_string("postpone_output"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, postpone_output),
NULL },
{ ngx_string("limit_rate"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, limit_rate),
NULL },
{ ngx_string("limit_rate_after"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, limit_rate_after),
NULL },
{ ngx_string("keepalive_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
ngx_http_core_keepalive,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("keepalive_requests"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, keepalive_requests),
NULL },
{ ngx_string("satisfy"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_enum_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, satisfy),
&ngx_http_core_satisfy },
{ ngx_string("satisfy_any"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, satisfy),
&ngx_conf_deprecated_satisfy_any },
{ ngx_string("internal"),
NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
ngx_http_core_internal,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("lingering_time"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_msec_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, lingering_time),
NULL },
{ ngx_string("lingering_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_msec_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, lingering_timeout),
NULL },
{ ngx_string("reset_timedout_connection"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, reset_timedout_connection),
NULL },
{ ngx_string("server_name_in_redirect"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, server_name_in_redirect),
NULL },
{ ngx_string("port_in_redirect"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, port_in_redirect),
NULL },
{ ngx_string("msie_padding"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, msie_padding),
NULL },
{ ngx_string("msie_refresh"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, msie_refresh),
NULL },
{ ngx_string("log_not_found"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, log_not_found),
NULL },
{ ngx_string("log_subrequest"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, log_subrequest),
NULL },
{ ngx_string("recursive_error_pages"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, recursive_error_pages),
NULL },
{ ngx_string("server_tokens"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, server_tokens),
NULL },
{ ngx_string("if_modified_since"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_enum_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, if_modified_since),
&ngx_http_core_if_modified_since },
{ ngx_string("chunked_transfer_encoding"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, chunked_transfer_encoding),
NULL },
{ ngx_string("error_page"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|NGX_CONF_2MORE,
ngx_http_core_error_page,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("try_files"),
NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE,
ngx_http_core_try_files,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("post_action"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, post_action),
NULL },
{ ngx_string("error_log"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
ngx_http_core_error_log,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("open_file_cache"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
ngx_http_core_open_file_cache,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, open_file_cache),
NULL },
{ ngx_string("open_file_cache_valid"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_sec_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, open_file_cache_valid),
NULL },
{ ngx_string("open_file_cache_retest"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_sec_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, open_file_cache_valid),
&ngx_conf_deprecated_open_file_cache_retest },
{ ngx_string("open_file_cache_min_uses"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, open_file_cache_min_uses),
NULL },
{ ngx_string("open_file_cache_errors"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, open_file_cache_errors),
NULL },
{ ngx_string("open_file_cache_events"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, open_file_cache_events),
NULL },
{ ngx_string("resolver"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_http_core_resolver,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("resolver_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_msec_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, resolver_timeout),
NULL },
#if (NGX_HTTP_GZIP)
{ ngx_string("gzip_vary"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, gzip_vary),
NULL },
{ ngx_string("gzip_http_version"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_enum_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, gzip_http_version),
&ngx_http_gzip_http_version },
{ ngx_string("gzip_proxied"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
ngx_conf_set_bitmask_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, gzip_proxied),
&ngx_http_gzip_proxied_mask },
{ ngx_string("gzip_disable"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
ngx_http_gzip_disable,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
#endif
ngx_null_command
};
static ngx_http_module_t ngx_http_core_module_ctx = {
ngx_http_core_preconfiguration, /* preconfiguration */
NULL, /* postconfiguration */
ngx_http_core_create_main_conf, /* create main configuration */
ngx_http_core_init_main_conf, /* init main configuration */
ngx_http_core_create_srv_conf, /* create server configuration */
ngx_http_core_merge_srv_conf, /* merge server configuration */
ngx_http_core_create_loc_conf, /* create location configuration */
ngx_http_core_merge_loc_conf /* merge location configuration */
};
ngx_module_t ngx_http_core_module = {
NGX_MODULE_V1,
&ngx_http_core_module_ctx, /* module context */
ngx_http_core_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
ngx_str_t ngx_http_core_get_method = { 3, (u_char *) "GET " };
void
ngx_http_handler(ngx_http_request_t *r)
{
ngx_http_core_main_conf_t *cmcf;
r->connection->log->action = NULL;
r->connection->unexpected_eof = 0;
if (!r->internal) {
switch (r->headers_in.connection_type) {
case 0:
if (r->http_version > NGX_HTTP_VERSION_10) {
r->keepalive = 1;
} else {
r->keepalive = 0;
}
break;
case NGX_HTTP_CONNECTION_CLOSE:
r->keepalive = 0;
break;
case NGX_HTTP_CONNECTION_KEEP_ALIVE:
r->keepalive = 1;
break;
}
if (r->keepalive) {
if (r->headers_in.msie6) {
if (r->method == NGX_HTTP_POST) {
/*
* MSIE may wait for some time if an response for
* a POST request was sent over a keepalive connection
*/
r->keepalive = 0;
}
} else if (r->headers_in.safari) {
/*
* Safari may send a POST request to a closed keepalive
* connection and stalls for some time
*/
r->keepalive = 0;
}
}
if (r->headers_in.content_length_n > 0) {
r->lingering_close = 1;
} else {
r->lingering_close = 0;
}
r->phase_handler = 0;
} else {
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
r->phase_handler = cmcf->phase_engine.server_rewrite_index;
}
r->valid_location = 1;
#if (NGX_HTTP_GZIP)
r->gzip_tested = 0;
r->gzip_ok = 0;
r->gzip_vary = 0;
#endif
r->write_event_handler = ngx_http_core_run_phases;
ngx_http_core_run_phases(r);
}
void
ngx_http_core_run_phases(ngx_http_request_t *r)
{
ngx_int_t rc;
ngx_http_phase_handler_t *ph;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
ph = cmcf->phase_engine.handlers;
while (ph[r->phase_handler].checker) {
rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]);
if (rc == NGX_OK) {
return;
}
}
}
ngx_int_t
ngx_http_core_generic_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph)
{
ngx_int_t rc;
/*
* generic phase checker,
* used by the post read, server rewrite, rewrite, and pre-access phases
*/
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"generic phase: %ui", r->phase_handler);
rc = ph->handler(r);
if (rc == NGX_OK) {
r->phase_handler = ph->next;
return NGX_AGAIN;
}
if (rc == NGX_DECLINED) {
r->phase_handler++;
return NGX_AGAIN;
}
if (rc == NGX_AGAIN || rc == NGX_DONE) {
return NGX_OK;
}
/* rc == NGX_ERROR || rc == NGX_HTTP_... */
ngx_http_finalize_request(r, rc);
return NGX_OK;
}
ngx_int_t
ngx_http_core_find_config_phase(ngx_http_request_t *r,
ngx_http_phase_handler_t *ph)
{
u_char *p;
size_t len;
ngx_int_t rc;
ngx_http_core_loc_conf_t *clcf;
r->content_handler = NULL;
r->uri_changed = 0;
rc = ngx_http_core_find_location(r);
if (rc == NGX_ERROR) {
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return NGX_OK;
}
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (!r->internal && clcf->internal) {
ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND);
return NGX_OK;
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"using configuration \"%s%V\"",
(clcf->noname ? "*" : (clcf->exact_match ? "=" : "")),
&clcf->name);
ngx_http_update_location_config(r);
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http cl:%O max:%O",
r->headers_in.content_length_n, clcf->client_max_body_size);
if (r->headers_in.content_length_n != -1
&& !r->discard_body
&& clcf->client_max_body_size
&& clcf->client_max_body_size < r->headers_in.content_length_n)
{
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"client intended to send too large body: %O bytes",
r->headers_in.content_length_n);
(void) ngx_http_discard_request_body(r);
ngx_http_finalize_request(r, NGX_HTTP_REQUEST_ENTITY_TOO_LARGE);
return NGX_OK;
}
if (rc == NGX_DONE) {
r->headers_out.location = ngx_list_push(&r->headers_out.headers);
if (r->headers_out.location == NULL) {
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return NGX_OK;
}
/*
* we do not need to set the r->headers_out.location->hash and
* r->headers_out.location->key fields
*/
if (r->args.len == 0) {
r->headers_out.location->value = clcf->name;
} else {
len = clcf->name.len + 1 + r->args.len;
p = ngx_pnalloc(r->pool, len);
if (p == NULL) {
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return NGX_OK;
}
r->headers_out.location->value.len = len;
r->headers_out.location->value.data = p;
p = ngx_cpymem(p, clcf->name.data, clcf->name.len);
*p++ = '?';
ngx_memcpy(p, r->args.data, r->args.len);
}
ngx_http_finalize_request(r, NGX_HTTP_MOVED_PERMANENTLY);
return NGX_OK;
}
r->phase_handler++;
return NGX_AGAIN;
}
ngx_int_t
ngx_http_core_post_rewrite_phase(ngx_http_request_t *r,
ngx_http_phase_handler_t *ph)
{
ngx_http_core_srv_conf_t *cscf;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"post rewrite phase: %ui", r->phase_handler);
if (!r->uri_changed) {
r->phase_handler++;
return NGX_AGAIN;
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"uri changes: %d", r->uri_changes);
/*
* gcc before 3.3 compiles the broken code for
* if (r->uri_changes-- == 0)
* if the r->uri_changes is defined as
* unsigned uri_changes:4
*/
r->uri_changes--;
if (r->uri_changes == 0) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"rewrite or internal redirection cycle "
"while processing \"%V\"", &r->uri);
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return NGX_OK;
}
r->phase_handler = ph->next;
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
r->loc_conf = cscf->ctx->loc_conf;
return NGX_AGAIN;
}
ngx_int_t
ngx_http_core_access_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph)
{
ngx_int_t rc;
ngx_http_core_loc_conf_t *clcf;
if (r != r->main) {
r->phase_handler = ph->next;
return NGX_AGAIN;
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"access phase: %ui", r->phase_handler);
rc = ph->handler(r);
if (rc == NGX_DECLINED) {
r->phase_handler++;
return NGX_AGAIN;
}
if (rc == NGX_AGAIN || rc == NGX_DONE) {
return NGX_OK;
}
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (clcf->satisfy == NGX_HTTP_SATISFY_ALL) {
if (rc == NGX_OK) {
r->phase_handler++;
return NGX_AGAIN;
}
} else {
if (rc == NGX_OK) {
r->access_code = 0;
if (r->headers_out.www_authenticate) {
r->headers_out.www_authenticate->hash = 0;
}
r->phase_handler = ph->next;
return NGX_AGAIN;
}
if (rc == NGX_HTTP_FORBIDDEN || rc == NGX_HTTP_UNAUTHORIZED) {
r->access_code = rc;
r->phase_handler++;
return NGX_AGAIN;
}
}
/* rc == NGX_ERROR || rc == NGX_HTTP_... */
ngx_http_finalize_request(r, rc);
return NGX_OK;
}
ngx_int_t
ngx_http_core_post_access_phase(ngx_http_request_t *r,
ngx_http_phase_handler_t *ph)
{
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"post access phase: %ui", r->phase_handler);
if (r->access_code) {
if (r->access_code == NGX_HTTP_FORBIDDEN) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"access forbidden by rule");
}
ngx_http_finalize_request(r, r->access_code);
return NGX_OK;
}
r->phase_handler++;
return NGX_AGAIN;
}
ngx_int_t
ngx_http_core_try_files_phase(ngx_http_request_t *r,
ngx_http_phase_handler_t *ph)
{
size_t len, root, alias, reserve, allocated;
u_char *p, *name;
ngx_str_t path, args;
ngx_uint_t test_dir;
ngx_http_try_file_t *tf;
ngx_open_file_info_t of;
ngx_http_script_code_pt code;
ngx_http_script_engine_t e;
ngx_http_core_loc_conf_t *clcf;
ngx_http_script_len_code_pt lcode;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"try files phase: %ui", r->phase_handler);
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (clcf->try_files == NULL) {
r->phase_handler++;
return NGX_AGAIN;
}
allocated = 0;
root = 0;
name = NULL;
/* suppress MSVC warning */
path.data = NULL;
tf = clcf->try_files;
alias = clcf->alias ? clcf->name.len : 0;
for ( ;; ) {
if (tf->lengths) {
ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
e.ip = tf->lengths->elts;
e.request = r;
/* 1 is for terminating '\0' as in static names */
len = 1;
while (*(uintptr_t *) e.ip) {
lcode = *(ngx_http_script_len_code_pt *) e.ip;
len += lcode(&e);
}
} else {
len = tf->name.len;
}
/* 16 bytes are preallocation */
reserve = ngx_abs((ssize_t) (len - r->uri.len)) + alias + 16;
if (reserve > allocated) {
/* we just need to allocate path and to copy a root */
if (ngx_http_map_uri_to_path(r, &path, &root, reserve) == NULL) {
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return NGX_OK;
}
name = path.data + root;
allocated = path.len - root - (r->uri.len - alias);
}
if (tf->values == NULL) {
/* tf->name.len includes the terminating '\0' */
ngx_memcpy(name, tf->name.data, tf->name.len);
path.len = (name + tf->name.len - 1) - path.data;
} else {
e.ip = tf->values->elts;
e.pos = name;
e.flushed = 1;
while (*(uintptr_t *) e.ip) {
code = *(ngx_http_script_code_pt *) e.ip;
code((ngx_http_script_engine_t *) &e);
}
path.len = e.pos - path.data;
*e.pos = '\0';
if (alias && ngx_strncmp(name, clcf->name.data, alias) == 0) {
ngx_memcpy(name, name + alias, len - alias);
path.len -= alias;
}
}
test_dir = tf->test_dir;
tf++;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"try to use file: \"%s\" \"%s\"", name, path.data);
if (tf->lengths == NULL && tf->name.len == 0) {
if (tf->code) {
ngx_http_finalize_request(r, tf->code);
return NGX_OK;
}
path.len -= root;
path.data += root;
if (path.data[0] == '@') {
(void) ngx_http_named_location(r, &path);
} else {
ngx_http_split_args(r, &path, &args);
(void) ngx_http_internal_redirect(r, &path, &args);
}
return NGX_OK;
}
ngx_memzero(&of, sizeof(ngx_open_file_info_t));
of.directio = clcf->directio;
of.valid = clcf->open_file_cache_valid;
of.min_uses = clcf->open_file_cache_min_uses;
of.test_only = 1;
of.errors = clcf->open_file_cache_errors;
of.events = clcf->open_file_cache_events;
if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
!= NGX_OK)
{
if (of.err != NGX_ENOENT
&& of.err != NGX_ENOTDIR
&& of.err != NGX_ENAMETOOLONG)
{
ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err,
"%s \"%s\" failed", of.failed, path.data);
}
continue;
}
if (of.is_dir && !test_dir) {
continue;
}
path.len -= root;
path.data += root;
if (!alias) {
r->uri = path;
} else {
r->uri.len = alias + path.len;
r->uri.data = ngx_pnalloc(r->pool, r->uri.len);
if (r->uri.data == NULL) {
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return NGX_OK;
}
p = ngx_copy(r->uri.data, clcf->name.data, alias);
ngx_memcpy(p, name, path.len);
}
ngx_http_set_exten(r);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"try file uri: \"%V\"", &r->uri);
r->phase_handler++;
return NGX_AGAIN;
}
/* not reached */
}
ngx_int_t
ngx_http_core_content_phase(ngx_http_request_t *r,
ngx_http_phase_handler_t *ph)
{
size_t root;
ngx_int_t rc;
ngx_str_t path;
if (r->content_handler) {
r->write_event_handler = ngx_http_request_empty_handler;
ngx_http_finalize_request(r, r->content_handler(r));
return NGX_OK;
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"content phase: %ui", r->phase_handler);
rc = ph->handler(r);
if (rc == NGX_DONE) {
return NGX_OK;
}
if (rc != NGX_DECLINED) {
ngx_http_finalize_request(r, rc);
return NGX_OK;
}
/* rc == NGX_DECLINED */
ph++;
if (ph->checker) {
r->phase_handler++;
return NGX_AGAIN;
}
/* no content handler was found */
if (r->uri.data[r->uri.len - 1] == '/') {
if (ngx_http_map_uri_to_path(r, &path, &root, 0) != NULL) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"directory index of \"%s\" is forbidden", path.data);
}
ngx_http_finalize_request(r, NGX_HTTP_FORBIDDEN);
return NGX_OK;
}
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no handler found");
ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND);
return NGX_OK;
}
void
ngx_http_update_location_config(ngx_http_request_t *r)
{
ngx_http_core_loc_conf_t *clcf;
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (r->method & clcf->limit_except) {
r->loc_conf = clcf->limit_except_loc_conf;
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
}
if (r == r->main) {
r->connection->log->file = clcf->error_log->file;
if (!(r->connection->log->log_level & NGX_LOG_DEBUG_CONNECTION)) {
r->connection->log->log_level = clcf->error_log->log_level;
}
}
if ((ngx_io.flags & NGX_IO_SENDFILE) && clcf->sendfile) {
r->connection->sendfile = 1;
} else {
r->connection->sendfile = 0;
}
if (clcf->client_body_in_file_only) {
r->request_body_in_file_only = 1;
r->request_body_in_persistent_file = 1;
r->request_body_in_clean_file =
clcf->client_body_in_file_only == NGX_HTTP_REQUEST_BODY_FILE_CLEAN;
r->request_body_file_log_level = NGX_LOG_NOTICE;
} else {
r->request_body_file_log_level = NGX_LOG_WARN;
}
r->request_body_in_single_buf = clcf->client_body_in_single_buffer;
if (r->keepalive) {
if (clcf->keepalive_timeout == 0) {
r->keepalive = 0;
} else if (r->connection->requests >= clcf->keepalive_requests) {
r->keepalive = 0;
}
}
if (!clcf->tcp_nopush) {
/* disable TCP_NOPUSH/TCP_CORK use */
r->connection->tcp_nopush = NGX_TCP_NOPUSH_DISABLED;
}
if (r->limit_rate == 0) {
r->limit_rate = clcf->limit_rate;
}
if (clcf->handler) {
r->content_handler = clcf->handler;
}
}
/*
* NGX_OK - exact or regex match
* NGX_DONE - auto redirect
* NGX_AGAIN - inclusive match
* NGX_ERROR - regex error
* NGX_DECLINED - no match
*/
static ngx_int_t
ngx_http_core_find_location(ngx_http_request_t *r)
{
ngx_int_t rc;
ngx_http_core_loc_conf_t *pclcf;
#if (NGX_PCRE)
ngx_int_t n, len;
ngx_uint_t noregex;
ngx_http_core_loc_conf_t *clcf, **clcfp;
noregex = 0;
#endif
pclcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
rc = ngx_http_core_find_static_location(r, pclcf->static_locations);
if (rc == NGX_AGAIN) {
#if (NGX_PCRE)
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
noregex = clcf->noregex;
#endif
/* look up nested locations */
rc = ngx_http_core_find_location(r);
}
if (rc == NGX_OK || rc == NGX_DONE) {
return rc;
}
/* rc == NGX_DECLINED or rc == NGX_AGAIN in nested location */
#if (NGX_PCRE)
if (noregex == 0 && pclcf->regex_locations) {
len = 0;
for (clcfp = pclcf->regex_locations; *clcfp; clcfp++) {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"test location: ~ \"%V\"", &(*clcfp)->name);
if ((*clcfp)->captures) {
len = (NGX_HTTP_MAX_CAPTURES + 1) * 3;
if (r->captures == NULL) {
r->captures = ngx_palloc(r->pool, len * sizeof(int));
if (r->captures == NULL) {
return NGX_ERROR;
}
}
}
n = ngx_regex_exec((*clcfp)->regex, &r->uri, r->captures, len);
if (n == NGX_REGEX_NO_MATCHED) {
continue;
}
if (n < 0) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
ngx_regex_exec_n
" failed: %d on \"%V\" using \"%V\"",
n, &r->uri, &(*clcfp)->name);
return NGX_ERROR;
}
/* match */
r->loc_conf = (*clcfp)->loc_conf;
r->ncaptures = len;
r->captures_data = r->uri.data;
/* look up nested locations */
rc = ngx_http_core_find_location(r);
return (rc == NGX_ERROR) ? rc : NGX_OK;
}
}
#endif
return rc;
}
/*
* NGX_OK - exact match
* NGX_DONE - auto redirect
* NGX_AGAIN - inclusive match
* NGX_DECLINED - no match
*/
static ngx_int_t
ngx_http_core_find_static_location(ngx_http_request_t *r,
ngx_http_location_tree_node_t *node)
{
u_char *uri;
size_t len, n;
ngx_int_t rc, rv;
len = r->uri.len;
uri = r->uri.data;
rv = NGX_DECLINED;
for ( ;; ) {
if (node == NULL) {
return rv;
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"test location: \"%*s\"", node->len, node->name);
n = (len <= (size_t) node->len) ? len : node->len;
rc = ngx_filename_cmp(uri, node->name, n);
if (rc != 0) {
node = (rc < 0) ? node->left : node->right;
continue;
}
if (len > (size_t) node->len) {
if (node->inclusive) {
r->loc_conf = node->inclusive->loc_conf;
rv = NGX_AGAIN;
node = node->tree;
uri += n;
len -= n;
continue;
}
/* exact only */
node = node->right;
continue;
}
if (len == (size_t) node->len) {
r->loc_conf = (node->exact) ? node->exact->loc_conf:
node->inclusive->loc_conf;
return NGX_OK;
}
/* len < node->len */
if (len + 1 == (size_t) node->len && node->auto_redirect) {
r->loc_conf = (node->exact) ? node->exact->loc_conf:
node->inclusive->loc_conf;
rv = NGX_DONE;
}
node = node->left;
}
}
void *
ngx_http_test_content_type(ngx_http_request_t *r, ngx_hash_t *types_hash)
{
u_char c, *lowcase;
size_t len;
ngx_uint_t i, hash;
if (r->headers_out.content_type.len == 0) {
return NULL;
}
len = r->headers_out.content_type_len;
if (r->headers_out.content_type_lowcase == NULL) {
lowcase = ngx_pnalloc(r->pool, len);
if (lowcase == NULL) {
return NULL;
}
r->headers_out.content_type_lowcase = lowcase;
hash = 0;
for (i = 0; i < len; i++) {
c = ngx_tolower(r->headers_out.content_type.data[i]);
hash = ngx_hash(hash, c);
lowcase[i] = c;
}
r->headers_out.content_type_hash = hash;
}
return ngx_hash_find(types_hash, r->headers_out.content_type_hash,
r->headers_out.content_type_lowcase, len);
}
ngx_int_t
ngx_http_set_content_type(ngx_http_request_t *r)
{
u_char c, *exten;
ngx_str_t *type;
ngx_uint_t i, hash;
ngx_http_core_loc_conf_t *clcf;
if (r->headers_out.content_type.len) {
return NGX_OK;
}
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (r->exten.len) {
hash = 0;
for (i = 0; i < r->exten.len; i++) {
c = r->exten.data[i];
if (c >= 'A' && c <= 'Z') {
exten = ngx_pnalloc(r->pool, r->exten.len);
if (exten == NULL) {
return NGX_ERROR;
}
hash = ngx_hash_strlow(exten, r->exten.data, r->exten.len);
r->exten.data = exten;
break;
}
hash = ngx_hash(hash, c);
}
type = ngx_hash_find(&clcf->types_hash, hash,
r->exten.data, r->exten.len);
if (type) {
r->headers_out.content_type_len = type->len;
r->headers_out.content_type = *type;
return NGX_OK;
}
}
r->headers_out.content_type_len = clcf->default_type.len;
r->headers_out.content_type = clcf->default_type;
return NGX_OK;
}
void
ngx_http_set_exten(ngx_http_request_t *r)
{
ngx_int_t i;
r->exten.len = 0;
r->exten.data = NULL;
for (i = r->uri.len - 1; i > 1; i--) {
if (r->uri.data[i] == '.' && r->uri.data[i - 1] != '/') {
r->exten.len = r->uri.len - i - 1;
r->exten.data = &r->uri.data[i + 1];
return;
} else if (r->uri.data[i] == '/') {
return;
}
}
return;
}
ngx_int_t
ngx_http_send_header(ngx_http_request_t *r)
{
if (r->err_status) {
r->headers_out.status = r->err_status;
r->headers_out.status_line.len = 0;
}
return ngx_http_top_header_filter(r);
}
ngx_int_t
ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
ngx_int_t rc;
ngx_connection_t *c;
c = r->connection;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http output filter \"%V?%V\"", &r->uri, &r->args);
rc = ngx_http_top_body_filter(r, in);
if (rc == NGX_ERROR) {
if (c->destroyed) {
return NGX_DONE;
}
/* NGX_ERROR may be returned by any filter */
c->error = 1;
}
return rc;
}
u_char *
ngx_http_map_uri_to_path(ngx_http_request_t *r, ngx_str_t *path,
size_t *root_length, size_t reserved)
{
u_char *last;
size_t alias;
ngx_http_core_loc_conf_t *clcf;
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
alias = clcf->alias ? clcf->name.len : 0;
if (alias && !r->valid_location) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
"\"alias\" could not be used in location \"%V\" "
"where URI was rewritten", &clcf->name);
return NULL;
}
if (clcf->root_lengths == NULL) {
*root_length = clcf->root.len;
path->len = clcf->root.len + reserved + r->uri.len - alias + 1;
path->data = ngx_pnalloc(r->pool, path->len);
if (path->data == NULL) {
return NULL;
}
last = ngx_copy(path->data, clcf->root.data, clcf->root.len);
} else {
#if (NGX_PCRE)
ngx_uint_t captures;
captures = alias && clcf->captures;
reserved += captures ? 1 : r->uri.len - alias + 1;
#else
reserved += r->uri.len - alias + 1;
#endif
if (ngx_http_script_run(r, path, clcf->root_lengths->elts, reserved,
clcf->root_values->elts)
== NULL)
{
return NULL;
}
if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, path, 0) != NGX_OK) {
return NULL;
}
*root_length = path->len - reserved;
last = path->data + *root_length;
#if (NGX_PCRE)
if (captures) {
*last = '\0';
return last;
}
#endif
}
last = ngx_cpystrn(last, r->uri.data + alias, r->uri.len - alias + 1);
return last;
}
ngx_int_t
ngx_http_auth_basic_user(ngx_http_request_t *r)
{
ngx_str_t auth, encoded;
ngx_uint_t len;
if (r->headers_in.user.len == 0 && r->headers_in.user.data != NULL) {
return NGX_DECLINED;
}
if (r->headers_in.authorization == NULL) {
r->headers_in.user.data = (u_char *) "";
return NGX_DECLINED;
}
encoded = r->headers_in.authorization->value;
if (encoded.len < sizeof("Basic ") - 1
|| ngx_strncasecmp(encoded.data, (u_char *) "Basic ",
sizeof("Basic ") - 1)
!= 0)
{
r->headers_in.user.data = (u_char *) "";
return NGX_DECLINED;
}
encoded.len -= sizeof("Basic ") - 1;
encoded.data += sizeof("Basic ") - 1;
while (encoded.len && encoded.data[0] == ' ') {
encoded.len--;
encoded.data++;
}
if (encoded.len == 0) {
r->headers_in.user.data = (u_char *) "";
return NGX_DECLINED;
}
auth.len = ngx_base64_decoded_length(encoded.len);
auth.data = ngx_pnalloc(r->pool, auth.len + 1);
if (auth.data == NULL) {
return NGX_ERROR;
}
if (ngx_decode_base64(&auth, &encoded) != NGX_OK) {
r->headers_in.user.data = (u_char *) "";
return NGX_DECLINED;
}
auth.data[auth.len] = '\0';
for (len = 0; len < auth.len; len++) {
if (auth.data[len] == ':') {
break;
}
}
if (len == 0 || len == auth.len) {
r->headers_in.user.data = (u_char *) "";
return NGX_DECLINED;
}
r->headers_in.user.len = len;
r->headers_in.user.data = auth.data;
r->headers_in.passwd.len = auth.len - len - 1;
r->headers_in.passwd.data = &auth.data[len + 1];
return NGX_OK;
}
#if (NGX_HTTP_GZIP)
ngx_int_t
ngx_http_gzip_ok(ngx_http_request_t *r)
{
time_t date, expires;
ngx_uint_t p;
ngx_array_t *cc;
ngx_table_elt_t *e, *d;
ngx_http_core_loc_conf_t *clcf;
r->gzip_tested = 1;
if (r != r->main
|| r->headers_in.accept_encoding == NULL
|| ngx_strcasestrn(r->headers_in.accept_encoding->value.data,
"gzip", 4 - 1)
== NULL
/*
* if the URL (without the "http://" prefix) is longer than 253 bytes,
* then MSIE 4.x can not handle the compressed stream - it waits
* too long, hangs up or crashes
*/
|| (r->headers_in.msie4 && r->unparsed_uri.len > 200))
{
return NGX_DECLINED;
}
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (r->headers_in.msie6 && clcf->gzip_disable_msie6) {
return NGX_DECLINED;
}
if (r->http_version < clcf->gzip_http_version) {
return NGX_DECLINED;
}
if (r->headers_in.via == NULL) {
goto ok;
}
p = clcf->gzip_proxied;
if (p & NGX_HTTP_GZIP_PROXIED_OFF) {
return NGX_DECLINED;
}
if (p & NGX_HTTP_GZIP_PROXIED_ANY) {
goto ok;
}
if (r->headers_in.authorization && (p & NGX_HTTP_GZIP_PROXIED_AUTH)) {
goto ok;
}
e = r->headers_out.expires;
if (e) {
if (!(p & NGX_HTTP_GZIP_PROXIED_EXPIRED)) {
return NGX_DECLINED;
}
expires = ngx_http_parse_time(e->value.data, e->value.len);
if (expires == NGX_ERROR) {
return NGX_DECLINED;
}
d = r->headers_out.date;
if (d) {
date = ngx_http_parse_time(d->value.data, d->value.len);
if (date == NGX_ERROR) {
return NGX_DECLINED;
}
} else {
date = ngx_time();
}
if (expires < date) {
goto ok;
}
return NGX_DECLINED;
}
cc = &r->headers_out.cache_control;
if (cc->elts) {
if ((p & NGX_HTTP_GZIP_PROXIED_NO_CACHE)
&& ngx_http_parse_multi_header_lines(cc, &ngx_http_gzip_no_cache,
NULL)
>= 0)
{
goto ok;
}
if ((p & NGX_HTTP_GZIP_PROXIED_NO_STORE)
&& ngx_http_parse_multi_header_lines(cc, &ngx_http_gzip_no_store,
NULL)
>= 0)
{
goto ok;
}
if ((p & NGX_HTTP_GZIP_PROXIED_PRIVATE)
&& ngx_http_parse_multi_header_lines(cc, &ngx_http_gzip_private,
NULL)
>= 0)
{
goto ok;
}
return NGX_DECLINED;
}
if ((p & NGX_HTTP_GZIP_PROXIED_NO_LM) && r->headers_out.last_modified) {
return NGX_DECLINED;
}
if ((p & NGX_HTTP_GZIP_PROXIED_NO_ETAG) && r->headers_out.etag) {
return NGX_DECLINED;
}
ok:
#if (NGX_PCRE)
if (clcf->gzip_disable && r->headers_in.user_agent) {
if (ngx_regex_exec_array(clcf->gzip_disable,
&r->headers_in.user_agent->value,
r->connection->log)
!= NGX_DECLINED)
{
return NGX_DECLINED;
}
}
#endif
r->gzip_ok = 1;
return NGX_OK;
}
#endif
ngx_int_t
ngx_http_subrequest(ngx_http_request_t *r,
ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **psr,
ngx_http_post_subrequest_t *ps, ngx_uint_t flags)
{
ngx_connection_t *c;
ngx_http_request_t *sr;
ngx_http_core_srv_conf_t *cscf;
ngx_http_postponed_request_t *pr, *p;
r->main->subrequests--;
if (r->main->subrequests == 0) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"subrequests cycle while processing \"%V\"", uri);
r->main->subrequests = 1;
return NGX_ERROR;
}
sr = ngx_pcalloc(r->pool, sizeof(ngx_http_request_t));
if (sr == NULL) {
return NGX_ERROR;
}
sr->signature = NGX_HTTP_MODULE;
c = r->connection;
sr->connection = c;
sr->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module);
if (sr->ctx == NULL) {
return NGX_ERROR;
}
if (ngx_list_init(&sr->headers_out.headers, r->pool, 20,
sizeof(ngx_table_elt_t))
!= NGX_OK)
{
return NGX_ERROR;
}
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
sr->main_conf = cscf->ctx->main_conf;
sr->srv_conf = cscf->ctx->srv_conf;
sr->loc_conf = cscf->ctx->loc_conf;
sr->pool = r->pool;
sr->headers_in = r->headers_in;
ngx_http_clear_content_length(sr);
ngx_http_clear_accept_ranges(sr);
ngx_http_clear_last_modified(sr);
sr->request_body = r->request_body;
sr->method = NGX_HTTP_GET;
sr->http_version = r->http_version;
sr->request_line = r->request_line;
sr->uri = *uri;
if (args) {
sr->args = *args;
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http subrequest \"%V?%V\"", uri, &sr->args);
sr->subrequest_in_memory = (flags & NGX_HTTP_SUBREQUEST_IN_MEMORY) != 0;
sr->waited = (flags & NGX_HTTP_SUBREQUEST_WAITED) != 0;
sr->unparsed_uri = r->unparsed_uri;
sr->method_name = ngx_http_core_get_method;
sr->http_protocol = r->http_protocol;
ngx_http_set_exten(sr);
sr->main = r->main;
sr->parent = r;
sr->post_subrequest = ps;
sr->read_event_handler = ngx_http_request_empty_handler;
sr->write_event_handler = ngx_http_handler;
if (c->data == r && r->postponed == NULL) {
c->data = sr;
}
sr->variables = r->variables;
sr->log_handler = r->log_handler;
pr = ngx_palloc(r->pool, sizeof(ngx_http_postponed_request_t));
if (pr == NULL) {
return NGX_ERROR;
}
pr->request = sr;
pr->out = NULL;
pr->next = NULL;
if (r->postponed) {
for (p = r->postponed; p->next; p = p->next) { /* void */ }
p->next = pr;
} else {
r->postponed = pr;
}
sr->internal = 1;
sr->discard_body = r->discard_body;
sr->expect_tested = 1;
sr->main_filter_need_in_memory = r->main_filter_need_in_memory;
sr->uri_changes = NGX_HTTP_MAX_URI_CHANGES + 1;
r->main->subrequests++;
*psr = sr;
return ngx_http_post_request(sr);
}
ngx_int_t
ngx_http_internal_redirect(ngx_http_request_t *r,
ngx_str_t *uri, ngx_str_t *args)
{
ngx_http_core_srv_conf_t *cscf;
r->uri_changes--;
if (r->uri_changes == 0) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"rewrite or internal redirection cycle "
"while internal redirect to \"%V\"", uri);
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return NGX_DONE;
}
r->uri = *uri;
if (args) {
r->args = *args;
} else {
r->args.len = 0;
r->args.data = NULL;
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"internal redirect: \"%V?%V\"", uri, &r->args);
ngx_http_set_exten(r);
/* clear the modules contexts */
ngx_memzero(r->ctx, sizeof(void *) * ngx_http_max_module);
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
r->loc_conf = cscf->ctx->loc_conf;
ngx_http_update_location_config(r);
#if (NGX_HTTP_CACHE)
r->cache = NULL;
#endif
r->internal = 1;
ngx_http_handler(r);
return NGX_DONE;
}
ngx_int_t
ngx_http_named_location(ngx_http_request_t *r, ngx_str_t *name)
{
ngx_http_core_srv_conf_t *cscf;
ngx_http_core_loc_conf_t **clcfp;
ngx_http_core_main_conf_t *cmcf;
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
if (cscf->named_locations) {
for (clcfp = cscf->named_locations; *clcfp; clcfp++) {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"test location: \"%V\"", &(*clcfp)->name);
if (name->len != (*clcfp)->name.len
|| ngx_strncmp(name->data, (*clcfp)->name.data, name->len) != 0)
{
continue;
}
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"using location: %V \"%V?%V\"",
name, &r->uri, &r->args);
r->internal = 1;
r->content_handler = NULL;
r->loc_conf = (*clcfp)->loc_conf;
ngx_http_update_location_config(r);
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
r->phase_handler = cmcf->phase_engine.location_rewrite_index;
ngx_http_core_run_phases(r);
return NGX_DONE;
}
}
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"could not find named location \"%V\"", name);
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return NGX_DONE;
}
ngx_http_cleanup_t *
ngx_http_cleanup_add(ngx_http_request_t *r, size_t size)
{
ngx_http_cleanup_t *cln;
r = r->main;
cln = ngx_palloc(r->pool, sizeof(ngx_http_cleanup_t));
if (cln == NULL) {
return NULL;
}
if (size) {
cln->data = ngx_palloc(r->pool, size);
if (cln->data == NULL) {
return NULL;
}
} else {
cln->data = NULL;
}
cln->handler = NULL;
cln->next = r->cleanup;
r->cleanup = cln;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http cleanup add: %p", cln);
return cln;
}
static char *
ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
{
char *rv;
void *mconf;
ngx_uint_t i;
ngx_conf_t pcf;
ngx_http_module_t *module;
ngx_http_conf_ctx_t *ctx, *http_ctx;
ngx_http_core_srv_conf_t *cscf, **cscfp;
ngx_http_core_main_conf_t *cmcf;
ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
if (ctx == NULL) {
return NGX_CONF_ERROR;
}
http_ctx = cf->ctx;
ctx->main_conf = http_ctx->main_conf;
/* the server{}'s srv_conf */
ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
if (ctx->srv_conf == NULL) {
return NGX_CONF_ERROR;
}
/* the server{}'s loc_conf */
ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
if (ctx->loc_conf == NULL) {
return NGX_CONF_ERROR;
}
for (i = 0; ngx_modules[i]; i++) {
if (ngx_modules[i]->type != NGX_HTTP_MODULE) {
continue;
}
module = ngx_modules[i]->ctx;
if (module->create_srv_conf) {
mconf = module->create_srv_conf(cf);
if (mconf == NULL) {
return NGX_CONF_ERROR;
}
ctx->srv_conf[ngx_modules[i]->ctx_index] = mconf;
}
if (module->create_loc_conf) {
mconf = module->create_loc_conf(cf);
if (mconf == NULL) {
return NGX_CONF_ERROR;
}
ctx->loc_conf[ngx_modules[i]->ctx_index] = mconf;
}
}
/* the server configuration context */
cscf = ctx->srv_conf[ngx_http_core_module.ctx_index];
cscf->ctx = ctx;
cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
cscfp = ngx_array_push(&cmcf->servers);
if (cscfp == NULL) {
return NGX_CONF_ERROR;
}
*cscfp = cscf;
/* parse inside server{} */
pcf = *cf;
cf->ctx = ctx;
cf->cmd_type = NGX_HTTP_SRV_CONF;
rv = ngx_conf_parse(cf, NULL);
*cf = pcf;
return rv;
}
static char *
ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
{
char *rv;
u_char *mod;
size_t len;
ngx_str_t *value, *name;
ngx_uint_t i;
ngx_conf_t save;
ngx_http_module_t *module;
ngx_http_conf_ctx_t *ctx, *pctx;
ngx_http_core_loc_conf_t *clcf, *pclcf;
ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
if (ctx == NULL) {
return NGX_CONF_ERROR;
}
pctx = cf->ctx;
ctx->main_conf = pctx->main_conf;
ctx->srv_conf = pctx->srv_conf;
ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
if (ctx->loc_conf == NULL) {
return NGX_CONF_ERROR;
}
for (i = 0; ngx_modules[i]; i++) {
if (ngx_modules[i]->type != NGX_HTTP_MODULE) {
continue;
}
module = ngx_modules[i]->ctx;
if (module->create_loc_conf) {
ctx->loc_conf[ngx_modules[i]->ctx_index] =
module->create_loc_conf(cf);
if (ctx->loc_conf[ngx_modules[i]->ctx_index] == NULL) {
return NGX_CONF_ERROR;
}
}
}
clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
clcf->loc_conf = ctx->loc_conf;
value = cf->args->elts;
if (cf->args->nelts == 3) {
len = value[1].len;
mod = value[1].data;
name = &value[2];
if (len == 1 && mod[0] == '=') {
clcf->name = *name;
clcf->exact_match = 1;
} else if (len == 2 && mod[0] == '^' && mod[1] == '~') {
clcf->name = *name;
clcf->noregex = 1;
} else if (len == 1 && mod[0] == '~') {
if (ngx_http_core_regex_location(cf, clcf, name, 0) != NGX_OK) {
return NGX_CONF_ERROR;
}
} else if (len == 2 && mod[0] == '~' && mod[1] == '*') {
if (ngx_http_core_regex_location(cf, clcf, name, 1) != NGX_OK) {
return NGX_CONF_ERROR;
}
} else {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid location modifier \"%V\"", &value[1]);
return NGX_CONF_ERROR;
}
} else {
name = &value[1];
if (name->data[0] == '=') {
clcf->name.len = name->len - 1;
clcf->name.data = name->data + 1;
clcf->exact_match = 1;
} else if (name->data[0] == '^' && name->data[1] == '~') {
clcf->name.len = name->len - 2;
clcf->name.data = name->data + 2;
clcf->noregex = 1;
} else if (name->data[0] == '~') {
name->len--;
name->data++;
if (name->data[0] == '*') {
name->len--;
name->data++;
if (ngx_http_core_regex_location(cf, clcf, name, 1) != NGX_OK) {
return NGX_CONF_ERROR;
}
} else {
if (ngx_http_core_regex_location(cf, clcf, name, 0) != NGX_OK) {
return NGX_CONF_ERROR;
}
}
} else {
clcf->name = *name;
if (name->data[0] == '@') {
clcf->named = 1;
}
}
}
pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index];
if (pclcf->name.len) {
/* nested location */
#if 0
clcf->prev_location = pclcf;
#endif
if (pclcf->exact_match) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"location \"%V\" could not be inside "
"the exact location \"%V\"",
&clcf->name, &pclcf->name);
return NGX_CONF_ERROR;
}
if (pclcf->named) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"location \"%V\" could not be inside "
"the named location \"%V\"",
&clcf->name, &pclcf->name);
return NGX_CONF_ERROR;
}
if (clcf->named) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"named location \"%V\" must be "
"on server level only",
&clcf->name);
return NGX_CONF_ERROR;
}
len = pclcf->name.len;
#if (NGX_PCRE)
if (clcf->regex == NULL
&& ngx_strncmp(clcf->name.data, pclcf->name.data, len) != 0)
#else
if (ngx_strncmp(clcf->name.data, pclcf->name.data, len) != 0)
#endif
{
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"location \"%V\" is outside location \"%V\"",
&clcf->name, &pclcf->name);
return NGX_CONF_ERROR;
}
}
if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) {
return NGX_CONF_ERROR;
}
save = *cf;
cf->ctx = ctx;
cf->cmd_type = NGX_HTTP_LOC_CONF;
rv = ngx_conf_parse(cf, NULL);
*cf = save;
return rv;
}
static ngx_int_t
ngx_http_core_regex_location(ngx_conf_t *cf, ngx_http_core_loc_conf_t *clcf,
ngx_str_t *regex, ngx_uint_t caseless)
{
#if (NGX_PCRE)
ngx_str_t err;
u_char errstr[NGX_MAX_CONF_ERRSTR];
err.len = NGX_MAX_CONF_ERRSTR;
err.data = errstr;
#if (NGX_HAVE_CASELESS_FILESYSTEM)
caseless = 1;
#endif
clcf->regex = ngx_regex_compile(regex, caseless ? NGX_REGEX_CASELESS: 0,
cf->pool, &err);
if (clcf->regex == NULL) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data);
return NGX_ERROR;
}
clcf->name = *regex;
clcf->captures = (ngx_regex_capture_count(clcf->regex) > 0);
return NGX_OK;
#else
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the using of the regex \"%V\" requires PCRE library",
regex);
return NGX_ERROR;
#endif
}
static char *
ngx_http_core_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_loc_conf_t *lcf = conf;
char *rv;
ngx_conf_t save;
if (lcf->types == NULL) {
lcf->types = ngx_array_create(cf->pool, 64, sizeof(ngx_hash_key_t));
if (lcf->types == NULL) {
return NGX_CONF_ERROR;
}
}
save = *cf;
cf->handler = ngx_http_core_type;
cf->handler_conf = conf;
rv = ngx_conf_parse(cf, NULL);
*cf = save;
return rv;
}
static char *
ngx_http_core_type(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
{
ngx_http_core_loc_conf_t *lcf = conf;
ngx_str_t *value, *content_type, *old, file;
ngx_uint_t i, n, hash;
ngx_hash_key_t *type;
value = cf->args->elts;
if (ngx_strcmp(value[0].data, "include") == 0) {
file = value[1];
if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK) {
return NGX_CONF_ERROR;
}
ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data);
return ngx_conf_parse(cf, &file);
}
content_type = ngx_palloc(cf->pool, sizeof(ngx_str_t));
if (content_type == NULL) {
return NGX_CONF_ERROR;
}
*content_type = value[0];
for (i = 1; i < cf->args->nelts; i++) {
hash = ngx_hash_strlow(value[i].data, value[i].data, value[i].len);
type = lcf->types->elts;
for (n = 0; n < lcf->types->nelts; n++) {
if (ngx_strcmp(value[i].data, type[n].key.data) == 0) {
old = type[n].value;
type[n].value = content_type;
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
"duplicate extention \"%V\", "
"content type: \"%V\", "
"old content type: \"%V\"",
&value[i], content_type, old);
continue;
}
}
type = ngx_array_push(lcf->types);
if (type == NULL) {
return NGX_CONF_ERROR;
}
type->key = value[i];
type->key_hash = hash;
type->value = content_type;
}
return NGX_CONF_OK;
}
static ngx_int_t
ngx_http_core_preconfiguration(ngx_conf_t *cf)
{
return ngx_http_variables_add_core_vars(cf);
}
static void *
ngx_http_core_create_main_conf(ngx_conf_t *cf)
{
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_main_conf_t));
if (cmcf == NULL) {
return NULL;
}
if (ngx_array_init(&cmcf->servers, cf->pool, 4,
sizeof(ngx_http_core_srv_conf_t *))
!= NGX_OK)
{
return NULL;
}
cmcf->server_names_hash_max_size = NGX_CONF_UNSET_UINT;
cmcf->server_names_hash_bucket_size = NGX_CONF_UNSET_UINT;
cmcf->variables_hash_max_size = NGX_CONF_UNSET_UINT;
cmcf->variables_hash_bucket_size = NGX_CONF_UNSET_UINT;
return cmcf;
}
static char *
ngx_http_core_init_main_conf(ngx_conf_t *cf, void *conf)
{
ngx_http_core_main_conf_t *cmcf = conf;
if (cmcf->server_names_hash_max_size == NGX_CONF_UNSET_UINT) {
cmcf->server_names_hash_max_size = 512;
}
if (cmcf->server_names_hash_bucket_size == NGX_CONF_UNSET_UINT) {
cmcf->server_names_hash_bucket_size = ngx_cacheline_size;
}
cmcf->server_names_hash_bucket_size =
ngx_align(cmcf->server_names_hash_bucket_size, ngx_cacheline_size);
if (cmcf->variables_hash_max_size == NGX_CONF_UNSET_UINT) {
cmcf->variables_hash_max_size = 512;
}
if (cmcf->variables_hash_bucket_size == NGX_CONF_UNSET_UINT) {
cmcf->variables_hash_bucket_size = 64;
}
cmcf->variables_hash_bucket_size =
ngx_align(cmcf->variables_hash_bucket_size, ngx_cacheline_size);
return NGX_CONF_OK;
}
static void *
ngx_http_core_create_srv_conf(ngx_conf_t *cf)
{
ngx_http_core_srv_conf_t *cscf;
cscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_srv_conf_t));
if (cscf == NULL) {
return NULL;
}
/*
* set by ngx_pcalloc():
*
* conf->client_large_buffers.num = 0;
*/
if (ngx_array_init(&cscf->listen, cf->temp_pool, 4,
sizeof(ngx_http_listen_t))
!= NGX_OK)
{
return NULL;
}
if (ngx_array_init(&cscf->server_names, cf->temp_pool, 4,
sizeof(ngx_http_server_name_t))
!= NGX_OK)
{
return NULL;
}
cscf->connection_pool_size = NGX_CONF_UNSET_SIZE;
cscf->request_pool_size = NGX_CONF_UNSET_SIZE;
cscf->client_header_timeout = NGX_CONF_UNSET_MSEC;
cscf->client_header_buffer_size = NGX_CONF_UNSET_SIZE;
cscf->ignore_invalid_headers = NGX_CONF_UNSET;
cscf->merge_slashes = NGX_CONF_UNSET;
cscf->underscores_in_headers = NGX_CONF_UNSET;
return cscf;
}
static char *
ngx_http_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_core_srv_conf_t *prev = parent;
ngx_http_core_srv_conf_t *conf = child;
ngx_http_listen_t *ls;
struct sockaddr_in *sin;
ngx_http_server_name_t *sn;
/* TODO: it does not merge, it inits only */
if (conf->listen.nelts == 0) {
ls = ngx_array_push(&conf->listen);
if (ls == NULL) {
return NGX_CONF_ERROR;
}
ngx_memzero(ls, sizeof(ngx_http_listen_t));
sin = (struct sockaddr_in *) &ls->sockaddr;
sin->sin_family = AF_INET;
#if (NGX_WIN32)
sin->sin_port = htons(80);
#else
sin->sin_port = htons((getuid() == 0) ? 80 : 8000);
#endif
sin->sin_addr.s_addr = INADDR_ANY;
ls->socklen = sizeof(struct sockaddr_in);
ls->conf.backlog = NGX_LISTEN_BACKLOG;
ls->conf.rcvbuf = -1;
ls->conf.sndbuf = -1;
ls->conf.wildcard = 1;
(void) ngx_sock_ntop((struct sockaddr *) &ls->sockaddr, ls->conf.addr,
NGX_SOCKADDR_STRLEN, 1);
}
if (conf->server_name.data == NULL) {
conf->server_name = cf->cycle->hostname;
sn = ngx_array_push(&conf->server_names);
if (sn == NULL) {
return NGX_CONF_ERROR;
}
#if (NGX_PCRE)
sn->regex = NULL;
sn->captures = 0;
#endif
sn->core_srv_conf = conf;
sn->name.len = conf->server_name.len;
sn->name.data = conf->server_name.data;
}
ngx_conf_merge_size_value(conf->connection_pool_size,
prev->connection_pool_size, 256);
ngx_conf_merge_size_value(conf->request_pool_size,
prev->request_pool_size, 4096);
ngx_conf_merge_msec_value(conf->client_header_timeout,
prev->client_header_timeout, 60000);
ngx_conf_merge_size_value(conf->client_header_buffer_size,
prev->client_header_buffer_size, 1024);
ngx_conf_merge_bufs_value(conf->large_client_header_buffers,
prev->large_client_header_buffers,
4, 8192);
if (conf->large_client_header_buffers.size < conf->connection_pool_size) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the \"large_client_header_buffers\" size must be "
"equal to or bigger than \"connection_pool_size\"");
return NGX_CONF_ERROR;
}
ngx_conf_merge_value(conf->ignore_invalid_headers,
prev->ignore_invalid_headers, 1);
ngx_conf_merge_value(conf->merge_slashes, prev->merge_slashes, 1);
ngx_conf_merge_value(conf->underscores_in_headers,
prev->underscores_in_headers, 0);
return NGX_CONF_OK;
}
static void *
ngx_http_core_create_loc_conf(ngx_conf_t *cf)
{
ngx_http_core_loc_conf_t *lcf;
lcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_loc_conf_t));
if (lcf == NULL) {
return NULL;
}
/*
* set by ngx_pcalloc():
*
* lcf->root = { 0, NULL };
* lcf->limit_except = 0;
* lcf->post_action = { 0, NULL };
* lcf->types = NULL;
* lcf->default_type = { 0, NULL };
* lcf->error_log = NULL;
* lcf->error_pages = NULL;
* lcf->try_files = NULL;
* lcf->client_body_path = NULL;
* lcf->regex = NULL;
* lcf->exact_match = 0;
* lcf->auto_redirect = 0;
* lcf->alias = 0;
* lcf->gzip_proxied = 0;
*/
lcf->client_max_body_size = NGX_CONF_UNSET;
lcf->client_body_buffer_size = NGX_CONF_UNSET_SIZE;
lcf->client_body_timeout = NGX_CONF_UNSET_MSEC;
lcf->satisfy = NGX_CONF_UNSET_UINT;
lcf->if_modified_since = NGX_CONF_UNSET_UINT;
lcf->client_body_in_file_only = NGX_CONF_UNSET_UINT;
lcf->client_body_in_single_buffer = NGX_CONF_UNSET;
lcf->internal = NGX_CONF_UNSET;
lcf->sendfile = NGX_CONF_UNSET;
lcf->sendfile_max_chunk = NGX_CONF_UNSET_SIZE;
lcf->directio = NGX_CONF_UNSET;
lcf->tcp_nopush = NGX_CONF_UNSET;
lcf->tcp_nodelay = NGX_CONF_UNSET;
lcf->send_timeout = NGX_CONF_UNSET_MSEC;
lcf->send_lowat = NGX_CONF_UNSET_SIZE;
lcf->postpone_output = NGX_CONF_UNSET_SIZE;
lcf->limit_rate = NGX_CONF_UNSET_SIZE;
lcf->limit_rate_after = NGX_CONF_UNSET_SIZE;
lcf->keepalive_timeout = NGX_CONF_UNSET_MSEC;
lcf->keepalive_header = NGX_CONF_UNSET;
lcf->keepalive_requests = NGX_CONF_UNSET_UINT;
lcf->lingering_time = NGX_CONF_UNSET_MSEC;
lcf->lingering_timeout = NGX_CONF_UNSET_MSEC;
lcf->resolver_timeout = NGX_CONF_UNSET_MSEC;
lcf->reset_timedout_connection = NGX_CONF_UNSET;
lcf->server_name_in_redirect = NGX_CONF_UNSET;
lcf->port_in_redirect = NGX_CONF_UNSET;
lcf->msie_padding = NGX_CONF_UNSET;
lcf->msie_refresh = NGX_CONF_UNSET;
lcf->log_not_found = NGX_CONF_UNSET;
lcf->log_subrequest = NGX_CONF_UNSET;
lcf->recursive_error_pages = NGX_CONF_UNSET;
lcf->server_tokens = NGX_CONF_UNSET;
lcf->chunked_transfer_encoding = NGX_CONF_UNSET;
lcf->types_hash_max_size = NGX_CONF_UNSET_UINT;
lcf->types_hash_bucket_size = NGX_CONF_UNSET_UINT;
lcf->open_file_cache = NGX_CONF_UNSET_PTR;
lcf->open_file_cache_valid = NGX_CONF_UNSET;
lcf->open_file_cache_min_uses = NGX_CONF_UNSET_UINT;
lcf->open_file_cache_errors = NGX_CONF_UNSET;
lcf->open_file_cache_events = NGX_CONF_UNSET;
#if (NGX_HTTP_GZIP)
lcf->gzip_vary = NGX_CONF_UNSET;
lcf->gzip_http_version = NGX_CONF_UNSET_UINT;
#if (NGX_PCRE)
lcf->gzip_disable = NGX_CONF_UNSET_PTR;
lcf->gzip_disable_msie6 = 3;
#endif
#endif
return lcf;
}
static ngx_str_t ngx_http_core_text_html_type = ngx_string("text/html");
static ngx_str_t ngx_http_core_image_gif_type = ngx_string("image/gif");
static ngx_str_t ngx_http_core_image_jpeg_type = ngx_string("image/jpeg");
static ngx_hash_key_t ngx_http_core_default_types[] = {
{ ngx_string("html"), 0, &ngx_http_core_text_html_type },
{ ngx_string("gif"), 0, &ngx_http_core_image_gif_type },
{ ngx_string("jpg"), 0, &ngx_http_core_image_jpeg_type },
{ ngx_null_string, 0, NULL }
};
static char *
ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_core_loc_conf_t *prev = parent;
ngx_http_core_loc_conf_t *conf = child;
ngx_uint_t i;
ngx_hash_key_t *type;
ngx_hash_init_t types_hash;
if (conf->root.data == NULL) {
conf->alias = prev->alias;
conf->root = prev->root;
conf->root_lengths = prev->root_lengths;
conf->root_values = prev->root_values;
if (prev->root.data == NULL) {
conf->root.len = sizeof("html") - 1;
conf->root.data = (u_char *) "html";
if (ngx_conf_full_name(cf->cycle, &conf->root, 0) != NGX_OK) {
return NGX_CONF_ERROR;
}
}
}
if (conf->post_action.data == NULL) {
conf->post_action = prev->post_action;
}
ngx_conf_merge_uint_value(conf->types_hash_max_size,
prev->types_hash_max_size, 1024);
ngx_conf_merge_uint_value(conf->types_hash_bucket_size,
prev->types_hash_bucket_size,
ngx_cacheline_size);
conf->types_hash_bucket_size = ngx_align(conf->types_hash_bucket_size,
ngx_cacheline_size);
/*
* the special handling the "types" directive in the "http" section
* to inherit the http's conf->types_hash to all servers
*/
if (prev->types && prev->types_hash.buckets == NULL) {
types_hash.hash = &prev->types_hash;
types_hash.key = ngx_hash_key_lc;
types_hash.max_size = conf->types_hash_max_size;
types_hash.bucket_size = conf->types_hash_bucket_size;
types_hash.name = "types_hash";
types_hash.pool = cf->pool;
types_hash.temp_pool = NULL;
if (ngx_hash_init(&types_hash, prev->types->elts, prev->types->nelts)
!= NGX_OK)
{
return NGX_CONF_ERROR;
}
}
if (conf->types == NULL) {
conf->types = prev->types;
conf->types_hash = prev->types_hash;
}
if (conf->types == NULL) {
conf->types = ngx_array_create(cf->pool, 4, sizeof(ngx_hash_key_t));
if (conf->types == NULL) {
return NGX_CONF_ERROR;
}
for (i = 0; ngx_http_core_default_types[i].key.len; i++) {
type = ngx_array_push(conf->types);
if (type == NULL) {
return NGX_CONF_ERROR;
}
type->key = ngx_http_core_default_types[i].key;
type->key_hash =
ngx_hash_key_lc(ngx_http_core_default_types[i].key.data,
ngx_http_core_default_types[i].key.len);
type->value = ngx_http_core_default_types[i].value;
}
}
if (conf->types_hash.buckets == NULL) {
types_hash.hash = &conf->types_hash;
types_hash.key = ngx_hash_key_lc;
types_hash.max_size = conf->types_hash_max_size;
types_hash.bucket_size = conf->types_hash_bucket_size;
types_hash.name = "mime_types_hash";
types_hash.pool = cf->pool;
types_hash.temp_pool = NULL;
if (ngx_hash_init(&types_hash, conf->types->elts, conf->types->nelts)
!= NGX_OK)
{
return NGX_CONF_ERROR;
}
}
if (conf->error_log == NULL) {
if (prev->error_log) {
conf->error_log = prev->error_log;
} else {
conf->error_log = &cf->cycle->new_log;
}
}
if (conf->error_pages == NULL && prev->error_pages) {
conf->error_pages = prev->error_pages;
}
ngx_conf_merge_str_value(conf->default_type,
prev->default_type, "text/plain");
ngx_conf_merge_off_value(conf->client_max_body_size,
prev->client_max_body_size, 1 * 1024 * 1024);
ngx_conf_merge_size_value(conf->client_body_buffer_size,
prev->client_body_buffer_size,
(size_t) 2 * ngx_pagesize);
ngx_conf_merge_msec_value(conf->client_body_timeout,
prev->client_body_timeout, 60000);
ngx_conf_merge_uint_value(conf->satisfy, prev->satisfy,
NGX_HTTP_SATISFY_ALL);
ngx_conf_merge_uint_value(conf->if_modified_since, prev->if_modified_since,
NGX_HTTP_IMS_EXACT);
ngx_conf_merge_uint_value(conf->client_body_in_file_only,
prev->client_body_in_file_only, 0);
ngx_conf_merge_value(conf->client_body_in_single_buffer,
prev->client_body_in_single_buffer, 0);
ngx_conf_merge_value(conf->internal, prev->internal, 0);
ngx_conf_merge_value(conf->sendfile, prev->sendfile, 0);
ngx_conf_merge_size_value(conf->sendfile_max_chunk,
prev->sendfile_max_chunk, 0);
ngx_conf_merge_off_value(conf->directio, prev->directio,
NGX_MAX_OFF_T_VALUE);
ngx_conf_merge_value(conf->tcp_nopush, prev->tcp_nopush, 0);
ngx_conf_merge_value(conf->tcp_nodelay, prev->tcp_nodelay, 1);
ngx_conf_merge_msec_value(conf->send_timeout, prev->send_timeout, 60000);
ngx_conf_merge_size_value(conf->send_lowat, prev->send_lowat, 0);
ngx_conf_merge_size_value(conf->postpone_output, prev->postpone_output,
1460);
ngx_conf_merge_size_value(conf->limit_rate, prev->limit_rate, 0);
ngx_conf_merge_size_value(conf->limit_rate_after, prev->limit_rate_after,
0);
ngx_conf_merge_msec_value(conf->keepalive_timeout,
prev->keepalive_timeout, 75000);
ngx_conf_merge_sec_value(conf->keepalive_header,
prev->keepalive_header, 0);
ngx_conf_merge_uint_value(conf->keepalive_requests,
prev->keepalive_requests, 100);
ngx_conf_merge_msec_value(conf->lingering_time,
prev->lingering_time, 30000);
ngx_conf_merge_msec_value(conf->lingering_timeout,
prev->lingering_timeout, 5000);
ngx_conf_merge_msec_value(conf->resolver_timeout,
prev->resolver_timeout, 30000);
if (conf->resolver == NULL) {
if (prev->resolver == NULL) {
/*
* create dummy resolver in http {} context
* to inherit it in all servers
*/
prev->resolver = ngx_resolver_create(cf, NULL);
if (prev->resolver == NULL) {
return NGX_CONF_ERROR;
}
}
conf->resolver = prev->resolver;
}
if (ngx_conf_merge_path_value(cf, &conf->client_body_temp_path,
prev->client_body_temp_path,
&ngx_http_client_temp_path)
!= NGX_OK)
{
return NGX_CONF_ERROR;
}
ngx_conf_merge_value(conf->reset_timedout_connection,
prev->reset_timedout_connection, 0);
ngx_conf_merge_value(conf->server_name_in_redirect,
prev->server_name_in_redirect, 1);
ngx_conf_merge_value(conf->port_in_redirect, prev->port_in_redirect, 1);
ngx_conf_merge_value(conf->msie_padding, prev->msie_padding, 1);
ngx_conf_merge_value(conf->msie_refresh, prev->msie_refresh, 0);
ngx_conf_merge_value(conf->log_not_found, prev->log_not_found, 1);
ngx_conf_merge_value(conf->log_subrequest, prev->log_subrequest, 0);
ngx_conf_merge_value(conf->recursive_error_pages,
prev->recursive_error_pages, 0);
ngx_conf_merge_value(conf->server_tokens, prev->server_tokens, 1);
ngx_conf_merge_value(conf->chunked_transfer_encoding,
prev->chunked_transfer_encoding, 1);
ngx_conf_merge_ptr_value(conf->open_file_cache,
prev->open_file_cache, NULL);
ngx_conf_merge_sec_value(conf->open_file_cache_valid,
prev->open_file_cache_valid, 60);
ngx_conf_merge_uint_value(conf->open_file_cache_min_uses,
prev->open_file_cache_min_uses, 1);
ngx_conf_merge_sec_value(conf->open_file_cache_errors,
prev->open_file_cache_errors, 0);
ngx_conf_merge_sec_value(conf->open_file_cache_events,
prev->open_file_cache_events, 0);
#if (NGX_HTTP_GZIP)
ngx_conf_merge_value(conf->gzip_vary, prev->gzip_vary, 0);
ngx_conf_merge_uint_value(conf->gzip_http_version, prev->gzip_http_version,
NGX_HTTP_VERSION_11);
ngx_conf_merge_bitmask_value(conf->gzip_proxied, prev->gzip_proxied,
(NGX_CONF_BITMASK_SET|NGX_HTTP_GZIP_PROXIED_OFF));
#if (NGX_PCRE)
ngx_conf_merge_ptr_value(conf->gzip_disable, prev->gzip_disable, NULL);
#endif
if (conf->gzip_disable_msie6 == 3) {
conf->gzip_disable_msie6 =
(prev->gzip_disable_msie6 == 3) ? 0 : prev->gzip_disable_msie6;
}
#endif
return NGX_CONF_OK;
}
static char *
ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_srv_conf_t *scf = conf;
ngx_str_t *value, size;
ngx_url_t u;
ngx_uint_t n;
ngx_http_listen_t *ls;
/*
* TODO: check duplicate 'listen' directives,
* add resolved name to server names ???
*/
value = cf->args->elts;
ngx_memzero(&u, sizeof(ngx_url_t));
u.url = value[1];
u.listen = 1;
u.default_port = 80;
if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
if (u.err) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"%s in \"%V\" of the \"listen\" directive",
u.err, &u.url);
}
return NGX_CONF_ERROR;
}
ls = ngx_array_push(&scf->listen);
if (ls == NULL) {
return NGX_CONF_ERROR;
}
ngx_memzero(ls, sizeof(ngx_http_listen_t));
ngx_memcpy(ls->sockaddr, u.sockaddr, u.socklen);
ls->socklen = u.socklen;
ls->file_name = cf->conf_file->file.name.data;
ls->line = cf->conf_file->line;
ls->conf.backlog = NGX_LISTEN_BACKLOG;
ls->conf.rcvbuf = -1;
ls->conf.sndbuf = -1;
ls->conf.wildcard = u.wildcard;
(void) ngx_sock_ntop((struct sockaddr *) &ls->sockaddr, ls->conf.addr,
NGX_SOCKADDR_STRLEN, 1);
if (cf->args->nelts == 2) {
return NGX_CONF_OK;
}
if (ngx_strcmp(value[2].data, "default") == 0) {
ls->conf.default_server = 1;
n = 3;
} else {
n = 2;
}
for ( /* void */ ; n < cf->args->nelts; n++) {
if (ls->conf.default_server == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"%V\" parameter can be specified for "
"the default \"listen\" directive only",
&value[n]);
return NGX_CONF_ERROR;
}
if (ngx_strcmp(value[n].data, "bind") == 0) {
ls->conf.bind = 1;
continue;
}
if (ngx_strncmp(value[n].data, "backlog=", 8) == 0) {
ls->conf.backlog = ngx_atoi(value[n].data + 8, value[n].len - 8);
ls->conf.bind = 1;
if (ls->conf.backlog == NGX_ERROR || ls->conf.backlog == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid backlog \"%V\"", &value[n]);
return NGX_CONF_ERROR;
}
continue;
}
if (ngx_strncmp(value[n].data, "rcvbuf=", 7) == 0) {
size.len = value[n].len - 7;
size.data = value[n].data + 7;
ls->conf.rcvbuf = ngx_parse_size(&size);
ls->conf.bind = 1;
if (ls->conf.rcvbuf == NGX_ERROR) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid rcvbuf \"%V\"", &value[n]);
return NGX_CONF_ERROR;
}
continue;
}
if (ngx_strncmp(value[n].data, "sndbuf=", 7) == 0) {
size.len = value[n].len - 7;
size.data = value[n].data + 7;
ls->conf.sndbuf = ngx_parse_size(&size);
ls->conf.bind = 1;
if (ls->conf.sndbuf == NGX_ERROR) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid sndbuf \"%V\"", &value[n]);
return NGX_CONF_ERROR;
}
continue;
}
if (ngx_strncmp(value[n].data, "accept_filter=", 14) == 0) {
#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
ls->conf.accept_filter = (char *) &value[n].data[14];
ls->conf.bind = 1;
#else
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"accept filters \"%V\" are not supported "
"on this platform, ignored",
&value[n]);
#endif
continue;
}
if (ngx_strcmp(value[n].data, "deferred") == 0) {
#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
ls->conf.deferred_accept = 1;
ls->conf.bind = 1;
#else
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the deferred accept is not supported "
"on this platform, ignored");
#endif
continue;
}
if (ngx_strncmp(value[n].data, "ipv6only=o", 10) == 0) {
#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
struct sockaddr *sa;
sa = (struct sockaddr *) ls->sockaddr;
if (sa->sa_family == AF_INET6) {
if (ngx_strcmp(&value[n].data[10], "n") == 0) {
ls->conf.ipv6only = 1;
} else if (ngx_strcmp(&value[n].data[10], "ff") == 0) {
ls->conf.ipv6only = 2;
} else {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid ipv6only flags \"%s\"",
&value[n].data[9]);
return NGX_CONF_ERROR;
}
ls->conf.bind = 1;
} else {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"ipv6only is not supported "
"on addr \"%s\", ignored",
ls->conf.addr);
}
continue;
#else
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"bind ipv6only is not supported "
"on this platform");
return NGX_CONF_ERROR;
#endif
}
if (ngx_strcmp(value[n].data, "ssl") == 0) {
#if (NGX_HTTP_SSL)
ls->conf.ssl = 1;
continue;
#else
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the \"ssl\" parameter requires "
"ngx_http_ssl_module");
return NGX_CONF_ERROR;
#endif
}
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the invalid \"%V\" parameter", &value[n]);
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
static char *
ngx_http_core_server_name(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_srv_conf_t *cscf = conf;
u_char ch;
ngx_str_t *value, name;
ngx_uint_t i;
ngx_http_server_name_t *sn;
value = cf->args->elts;
ch = value[1].data[0];
if (cscf->server_name.data == NULL) {
if (value[1].len) {
name = value[1];
if (ch == '.') {
name.len--;
name.data++;
}
cscf->server_name.len = name.len;
cscf->server_name.data = ngx_pstrdup(cf->pool, &name);
if (cscf->server_name.data == NULL) {
return NGX_CONF_ERROR;
}
} else {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the first server name must not be empty");
return NGX_CONF_ERROR;
}
}
for (i = 1; i < cf->args->nelts; i++) {
ch = value[i].data[0];
if ((ch == '*' && (value[i].len < 3 || value[i].data[1] != '.'))
|| (ch == '.' && value[i].len < 2))
{
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"server name \"%V\" is invalid", &value[i]);
return NGX_CONF_ERROR;
}
if (ngx_strchr(value[i].data, '/')) {
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
"server name \"%V\" has strange symbols",
&value[i]);
}
if (value[i].len == 1 && ch == '*') {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"server_name *\" is unsupported, use "
"\"server_name_in_redirect off\" instead");
return NGX_CONF_ERROR;
}
sn = ngx_array_push(&cscf->server_names);
if (sn == NULL) {
return NGX_CONF_ERROR;
}
#if (NGX_PCRE)
sn->regex = NULL;
sn->captures = 0;
#endif
sn->core_srv_conf = cscf;
sn->name = value[i];
if (value[i].data[0] != '~') {
continue;
}
#if (NGX_PCRE)
{
ngx_str_t err;
u_char errstr[NGX_MAX_CONF_ERRSTR];
if (value[i].len == 1) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"empty regex in server name \"%V\"", &value[i]);
return NGX_CONF_ERROR;
}
err.len = NGX_MAX_CONF_ERRSTR;
err.data = errstr;
value[i].len--;
value[i].data++;
sn->regex = ngx_regex_compile(&value[i], 0, cf->pool, &err);
if (sn->regex == NULL) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data);
return NGX_CONF_ERROR;
}
sn->captures = (ngx_regex_capture_count(sn->regex) > 0);
sn->name = value[i];
}
#else
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the using of the regex \"%V\" "
"requires PCRE library", &value[i]);
return NGX_CONF_ERROR;
#endif
}
return NGX_CONF_OK;
}
static char *
ngx_http_core_root(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_loc_conf_t *lcf = conf;
ngx_str_t *value;
ngx_uint_t alias, n;
ngx_http_script_compile_t sc;
alias = (cmd->name.len == sizeof("alias") - 1) ? 1 : 0;
if (lcf->root.data) {
/* the (ngx_uint_t) cast is required by gcc 2.7.2.3 */
if ((ngx_uint_t) lcf->alias == alias) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"%V\" directive is duplicate",
&cmd->name);
} else {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"%V\" directive is duplicate, "
"\"%s\" directive is specified before",
&cmd->name, lcf->alias ? "alias" : "root");
}
return NGX_CONF_ERROR;
}
if (lcf->named && alias) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the \"alias\" directive may not be used "
"inside named location");
return NGX_CONF_ERROR;
}
value = cf->args->elts;
if (ngx_strstr(value[1].data, "$document_root")
|| ngx_strstr(value[1].data, "${document_root}"))
{
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the $document_root variable may not be used "
"in the \"%V\" directive",
&cmd->name);
return NGX_CONF_ERROR;
}
if (ngx_strstr(value[1].data, "$realpath_root")
|| ngx_strstr(value[1].data, "${realpath_root}"))
{
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the $realpath_root variable may not be used "
"in the \"%V\" directive",
&cmd->name);
return NGX_CONF_ERROR;
}
lcf->alias = alias;
lcf->root = value[1];
if (!alias && lcf->root.data[lcf->root.len - 1] == '/') {
lcf->root.len--;
}
if (lcf->root.data[0] != '$') {
if (ngx_conf_full_name(cf->cycle, &lcf->root, 0) != NGX_OK) {
return NGX_CONF_ERROR;
}
}
n = ngx_http_script_variables_count(&lcf->root);
ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
if (n) {
sc.cf = cf;
sc.source = &lcf->root;
sc.lengths = &lcf->root_lengths;
sc.values = &lcf->root_values;
sc.variables = n;
sc.complete_lengths = 1;
sc.complete_values = 1;
if (ngx_http_script_compile(&sc) != NGX_OK) {
return NGX_CONF_ERROR;
}
}
#if (NGX_PCRE)
if (alias && lcf->regex
&& (ngx_regex_capture_count(lcf->regex) <= 0 || sc.ncaptures == 0))
{
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the \"alias\" directive must use captures "
"inside location given by regular expression");
return NGX_CONF_ERROR;
}
#endif
return NGX_CONF_OK;
}
static ngx_http_method_name_t ngx_methods_names[] = {
{ (u_char *) "GET", (uint32_t) ~NGX_HTTP_GET },
{ (u_char *) "HEAD", (uint32_t) ~NGX_HTTP_HEAD },
{ (u_char *) "POST", (uint32_t) ~NGX_HTTP_POST },
{ (u_char *) "PUT", (uint32_t) ~NGX_HTTP_PUT },
{ (u_char *) "DELETE", (uint32_t) ~NGX_HTTP_DELETE },
{ (u_char *) "MKCOL", (uint32_t) ~NGX_HTTP_MKCOL },
{ (u_char *) "COPY", (uint32_t) ~NGX_HTTP_COPY },
{ (u_char *) "MOVE", (uint32_t) ~NGX_HTTP_MOVE },
{ (u_char *) "OPTIONS", (uint32_t) ~NGX_HTTP_OPTIONS },
{ (u_char *) "PROPFIND" , (uint32_t) ~NGX_HTTP_PROPFIND },
{ (u_char *) "PROPPATCH", (uint32_t) ~NGX_HTTP_PROPPATCH },
{ (u_char *) "LOCK", (uint32_t) ~NGX_HTTP_LOCK },
{ (u_char *) "UNLOCK", (uint32_t) ~NGX_HTTP_UNLOCK },
{ NULL, 0 }
};
static char *
ngx_http_core_limit_except(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_loc_conf_t *pclcf = conf;
char *rv;
void *mconf;
ngx_str_t *value;
ngx_uint_t i;
ngx_conf_t save;
ngx_http_module_t *module;
ngx_http_conf_ctx_t *ctx, *pctx;
ngx_http_method_name_t *name;
ngx_http_core_loc_conf_t *clcf;
if (pclcf->limit_except) {
return "duplicate";
}
pclcf->limit_except = 0xffffffff;
value = cf->args->elts;
for (i = 1; i < cf->args->nelts; i++) {
for (name = ngx_methods_names; name->name; name++) {
if (ngx_strcasecmp(value[i].data, name->name) == 0) {
pclcf->limit_except &= name->method;
goto next;
}
}
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid method \"%V\"", &value[i]);
return NGX_CONF_ERROR;
next:
continue;
}
if (!(pclcf->limit_except & NGX_HTTP_GET)) {
pclcf->limit_except &= (uint32_t) ~NGX_HTTP_HEAD;
}
ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
if (ctx == NULL) {
return NGX_CONF_ERROR;
}
pctx = cf->ctx;
ctx->main_conf = pctx->main_conf;
ctx->srv_conf = pctx->srv_conf;
ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
if (ctx->loc_conf == NULL) {
return NGX_CONF_ERROR;
}
for (i = 0; ngx_modules[i]; i++) {
if (ngx_modules[i]->type != NGX_HTTP_MODULE) {
continue;
}
module = ngx_modules[i]->ctx;
if (module->create_loc_conf) {
mconf = module->create_loc_conf(cf);
if (mconf == NULL) {
return NGX_CONF_ERROR;
}
ctx->loc_conf[ngx_modules[i]->ctx_index] = mconf;
}
}
clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
pclcf->limit_except_loc_conf = ctx->loc_conf;
clcf->loc_conf = ctx->loc_conf;
clcf->name = pclcf->name;
clcf->noname = 1;
if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) {
return NGX_CONF_ERROR;
}
save = *cf;
cf->ctx = ctx;
cf->cmd_type = NGX_HTTP_LMT_CONF;
rv = ngx_conf_parse(cf, NULL);
*cf = save;
return rv;
}
static char *
ngx_http_core_directio(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_loc_conf_t *clcf = conf;
ngx_str_t *value;
if (clcf->directio != NGX_CONF_UNSET) {
return "is duplicate";
}
value = cf->args->elts;
if (ngx_strcmp(value[1].data, "off") == 0) {
clcf->directio = NGX_OPEN_FILE_DIRECTIO_OFF;
return NGX_CONF_OK;
}
clcf->directio = ngx_parse_offset(&value[1]);
if (clcf->directio == (off_t) NGX_ERROR) {
return "invalid value";
}
return NGX_CONF_OK;
}
static char *
ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_loc_conf_t *lcf = conf;
u_char *p;
ngx_int_t overwrite;
ngx_str_t *value, uri, args;
ngx_uint_t i, n;
ngx_http_err_page_t *err;
ngx_http_complex_value_t cv;
ngx_http_compile_complex_value_t ccv;
if (lcf->error_pages == NULL) {
lcf->error_pages = ngx_array_create(cf->pool, 4,
sizeof(ngx_http_err_page_t));
if (lcf->error_pages == NULL) {
return NGX_CONF_ERROR;
}
}
value = cf->args->elts;
i = cf->args->nelts - 2;
if (value[i].data[0] == '=') {
if (i == 1) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid value \"%V\"", &value[i]);
return NGX_CONF_ERROR;
}
if (value[i].len > 1) {
overwrite = ngx_atoi(&value[i].data[1], value[i].len - 1);
if (overwrite == NGX_ERROR) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid value \"%V\"", &value[i]);
return NGX_CONF_ERROR;
}
} else {
overwrite = 0;
}
n = 2;
} else {
overwrite = -1;
n = 1;
}
uri = value[cf->args->nelts - 1];
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
ccv.cf = cf;
ccv.value = &uri;
ccv.complex_value = &cv;
if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
return NGX_CONF_ERROR;
}
args.len = 0;
args.data = NULL;
if (cv.lengths == NULL && uri.data[0] == '/') {
p = (u_char *) ngx_strchr(uri.data, '?');
if (p) {
cv.value.len = p - uri.data;
cv.value.data = uri.data;
p++;
args.len = (uri.data + uri.len) - p;
args.data = p;
}
}
for (i = 1; i < cf->args->nelts - n; i++) {
err = ngx_array_push(lcf->error_pages);
if (err == NULL) {
return NGX_CONF_ERROR;
}
err->status = ngx_atoi(value[i].data, value[i].len);
if (err->status == NGX_ERROR || err->status == 499) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid value \"%V\"", &value[i]);
return NGX_CONF_ERROR;
}
if (err->status < 400 || err->status > 599) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"value \"%V\" must be between 400 and 599",
&value[i]);
return NGX_CONF_ERROR;
}
if (overwrite >= 0) {
err->overwrite = overwrite;
} else {
switch (err->status) {
case NGX_HTTP_TO_HTTPS:
case NGX_HTTPS_CERT_ERROR:
case NGX_HTTPS_NO_CERT:
err->overwrite = NGX_HTTP_BAD_REQUEST;
break;
default:
err->overwrite = err->status;
break;
}
}
err->value = cv;
err->args = args;
}
return NGX_CONF_OK;
}
static char *
ngx_http_core_try_files(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_loc_conf_t *clcf = conf;
ngx_str_t *value;
ngx_int_t code;
ngx_uint_t i, n;
ngx_http_try_file_t *tf;
ngx_http_script_compile_t sc;
ngx_http_core_main_conf_t *cmcf;
if (clcf->try_files) {
return "is duplicate";
}
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
cmcf->try_files = 1;
tf = ngx_pcalloc(cf->pool, cf->args->nelts * sizeof(ngx_http_try_file_t));
if (tf == NULL) {
return NGX_CONF_ERROR;
}
clcf->try_files = tf;
value = cf->args->elts;
for (i = 0; i < cf->args->nelts - 1; i++) {
tf[i].name = value[i + 1];
if (tf[i].name.data[tf[i].name.len - 1] == '/') {
tf[i].test_dir = 1;
tf[i].name.len--;
tf[i].name.data[tf[i].name.len] = '\0';
}
n = ngx_http_script_variables_count(&tf[i].name);
if (n) {
ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
sc.cf = cf;
sc.source = &tf[i].name;
sc.lengths = &tf[i].lengths;
sc.values = &tf[i].values;
sc.variables = n;
sc.complete_lengths = 1;
sc.complete_values = 1;
if (ngx_http_script_compile(&sc) != NGX_OK) {
return NGX_CONF_ERROR;
}
} else {
/* add trailing '\0' to length */
tf[i].name.len++;
}
}
if (tf[i - 1].name.data[0] == '=') {
code = ngx_atoi(tf[i - 1].name.data + 1, tf[i - 1].name.len - 2);
if (code == NGX_ERROR) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid code \"%*s\"",
tf[i - 1].name.len - 1, tf[i - 1].name.data);
return NGX_CONF_ERROR;
}
tf[i].code = code;
}
return NGX_CONF_OK;
}
static char *
ngx_http_core_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_loc_conf_t *lcf = conf;
time_t inactive;
ngx_str_t *value, s;
ngx_int_t max;
ngx_uint_t i;
if (lcf->open_file_cache != NGX_CONF_UNSET_PTR) {
return "is duplicate";
}
value = cf->args->elts;
max = 0;
inactive = 60;
for (i = 1; i < cf->args->nelts; i++) {
if (ngx_strncmp(value[i].data, "max=", 4) == 0) {
max = ngx_atoi(value[i].data + 4, value[i].len - 4);
if (max == NGX_ERROR) {
goto failed;
}
continue;
}
if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {
s.len = value[i].len - 9;
s.data = value[i].data + 9;
inactive = ngx_parse_time(&s, 1);
if (inactive < 0) {
goto failed;
}
continue;
}
if (ngx_strcmp(value[i].data, "off") == 0) {
lcf->open_file_cache = NULL;
continue;
}
failed:
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid \"open_file_cache\" parameter \"%V\"",
&value[i]);
return NGX_CONF_ERROR;
}
if (lcf->open_file_cache == NULL) {
return NGX_CONF_OK;
}
if (max == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"open_file_cache\" must have \"max\" parameter");
return NGX_CONF_ERROR;
}
lcf->open_file_cache = ngx_open_file_cache_init(cf->pool, max, inactive);
if (lcf->open_file_cache) {
return NGX_CONF_OK;
}
return NGX_CONF_ERROR;
}
static char *
ngx_http_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_loc_conf_t *lcf = conf;
ngx_str_t *value;
if (lcf->error_log) {
return "is duplicate";
}
value = cf->args->elts;
lcf->error_log = ngx_log_create(cf->cycle, &value[1]);
if (lcf->error_log == NULL) {
return NGX_CONF_ERROR;
}
if (cf->args->nelts == 2) {
lcf->error_log->log_level = NGX_LOG_ERR;
return NGX_CONF_OK;
}
return ngx_log_set_levels(cf, lcf->error_log);
}
static char *
ngx_http_core_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_loc_conf_t *lcf = conf;
ngx_str_t *value;
if (lcf->keepalive_timeout != NGX_CONF_UNSET_MSEC) {
return "is duplicate";
}
value = cf->args->elts;
lcf->keepalive_timeout = ngx_parse_time(&value[1], 0);
if (lcf->keepalive_timeout == (ngx_msec_t) NGX_ERROR) {
return "invalid value";
}
if (lcf->keepalive_timeout == (ngx_msec_t) NGX_PARSE_LARGE_TIME) {
return "value must be less than 597 hours";
}
if (cf->args->nelts == 2) {
return NGX_CONF_OK;
}
lcf->keepalive_header = ngx_parse_time(&value[2], 1);
if (lcf->keepalive_header == NGX_ERROR) {
return "invalid value";
}
if (lcf->keepalive_header == NGX_PARSE_LARGE_TIME) {
return "value must be less than 68 years";
}
return NGX_CONF_OK;
}
static char *
ngx_http_core_internal(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_loc_conf_t *lcf = conf;
if (lcf->internal != NGX_CONF_UNSET) {
return "is duplicate";
}
lcf->internal = 1;
return NGX_CONF_OK;
}
static char *
ngx_http_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_loc_conf_t *clcf = conf;
ngx_url_t u;
ngx_str_t *value;
if (clcf->resolver) {
return "is duplicate";
}
value = cf->args->elts;
ngx_memzero(&u, sizeof(ngx_url_t));
u.host = value[1];
u.port = 53;
if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V: %s", &u.host, u.err);
return NGX_CONF_ERROR;
}
clcf->resolver = ngx_resolver_create(cf, &u.addrs[0]);
if (clcf->resolver == NULL) {
return NGX_OK;
}
return NGX_CONF_OK;
}
#if (NGX_HTTP_GZIP)
static char *
ngx_http_gzip_disable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_loc_conf_t *clcf = conf;
#if (NGX_PCRE)
ngx_str_t err, *value;
ngx_uint_t i;
ngx_regex_elt_t *re;
u_char errstr[NGX_MAX_CONF_ERRSTR];
if (clcf->gzip_disable == NGX_CONF_UNSET_PTR) {
clcf->gzip_disable = ngx_array_create(cf->pool, 2,
sizeof(ngx_regex_elt_t));
if (clcf->gzip_disable == NULL) {
return NGX_CONF_ERROR;
}
}
value = cf->args->elts;
err.len = NGX_MAX_CONF_ERRSTR;
err.data = errstr;
for (i = 1; i < cf->args->nelts; i++) {
if (ngx_strcmp(value[1].data, "msie6") == 0) {
clcf->gzip_disable_msie6 = 1;
continue;
}
re = ngx_array_push(clcf->gzip_disable);
if (re == NULL) {
return NGX_CONF_ERROR;
}
re->regex = ngx_regex_compile(&value[i], NGX_REGEX_CASELESS, cf->pool,
&err);
if (re->regex == NULL) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data);
return NGX_CONF_ERROR;
}
re->name = value[i].data;
}
return NGX_CONF_OK;
#else
ngx_str_t *value;
value = cf->args->elts;
if (cf->args->nelts == 2 && ngx_strcmp(value[1].data, "msie6") == 0) {
clcf->gzip_disable_msie6 = 1;
return NGX_CONF_OK;
}
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"without PCRE library \"gzip_disable\" supports "
"builtin \"msie6\" mask only");
return NGX_CONF_ERROR;
#endif
}
#endif
static char *
ngx_http_core_lowat_check(ngx_conf_t *cf, void *post, void *data)
{
#if (NGX_FREEBSD)
ssize_t *np = data;
if ((u_long) *np >= ngx_freebsd_net_inet_tcp_sendspace) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"send_lowat\" must be less than %d "
"(sysctl net.inet.tcp.sendspace)",
ngx_freebsd_net_inet_tcp_sendspace);
return NGX_CONF_ERROR;
}
#elif !(NGX_HAVE_SO_SNDLOWAT)
ssize_t *np = data;
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
"\"send_lowat\" is not supported, ignored");
*np = 0;
#endif
return NGX_CONF_OK;
}
static char *
ngx_http_core_pool_size(ngx_conf_t *cf, void *post, void *data)
{
size_t *sp = data;
if (*sp < NGX_MIN_POOL_SIZE) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"pool must be no less than %uz", NGX_MIN_POOL_SIZE);
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
nginx-0.7.68/src/http/ngx_http_request.h 000644 001750 001750 00000043410 11403162632 017351 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#ifndef _NGX_HTTP_REQUEST_H_INCLUDED_
#define _NGX_HTTP_REQUEST_H_INCLUDED_
#define NGX_HTTP_MAX_URI_CHANGES 10
#define NGX_HTTP_MAX_SUBREQUESTS 50
#define NGX_HTTP_MAX_CAPTURES 9
/* must be 2^n */
#define NGX_HTTP_LC_HEADER_LEN 32
#define NGX_HTTP_DISCARD_BUFFER_SIZE 4096
#define NGX_HTTP_LINGERING_BUFFER_SIZE 4096
#define NGX_HTTP_VERSION_9 9
#define NGX_HTTP_VERSION_10 1000
#define NGX_HTTP_VERSION_11 1001
#define NGX_HTTP_UNKNOWN 0x0001
#define NGX_HTTP_GET 0x0002
#define NGX_HTTP_HEAD 0x0004
#define NGX_HTTP_POST 0x0008
#define NGX_HTTP_PUT 0x0010
#define NGX_HTTP_DELETE 0x0020
#define NGX_HTTP_MKCOL 0x0040
#define NGX_HTTP_COPY 0x0080
#define NGX_HTTP_MOVE 0x0100
#define NGX_HTTP_OPTIONS 0x0200
#define NGX_HTTP_PROPFIND 0x0400
#define NGX_HTTP_PROPPATCH 0x0800
#define NGX_HTTP_LOCK 0x1000
#define NGX_HTTP_UNLOCK 0x2000
#define NGX_HTTP_TRACE 0x4000
#define NGX_HTTP_CONNECTION_CLOSE 1
#define NGX_HTTP_CONNECTION_KEEP_ALIVE 2
#define NGX_NONE 1
#define NGX_HTTP_PARSE_HEADER_DONE 1
#define NGX_HTTP_CLIENT_ERROR 10
#define NGX_HTTP_PARSE_INVALID_METHOD 10
#define NGX_HTTP_PARSE_INVALID_REQUEST 11
#define NGX_HTTP_PARSE_INVALID_09_METHOD 12
#define NGX_HTTP_PARSE_INVALID_HEADER 13
/* unused 1 */
#define NGX_HTTP_SUBREQUEST_IN_MEMORY 2
#define NGX_HTTP_SUBREQUEST_WAITED 4
#define NGX_HTTP_LOG_UNSAFE 8
#define NGX_HTTP_OK 200
#define NGX_HTTP_CREATED 201
#define NGX_HTTP_NO_CONTENT 204
#define NGX_HTTP_PARTIAL_CONTENT 206
#define NGX_HTTP_SPECIAL_RESPONSE 300
#define NGX_HTTP_MOVED_PERMANENTLY 301
#define NGX_HTTP_MOVED_TEMPORARILY 302
#define NGX_HTTP_NOT_MODIFIED 304
#define NGX_HTTP_BAD_REQUEST 400
#define NGX_HTTP_UNAUTHORIZED 401
#define NGX_HTTP_FORBIDDEN 403
#define NGX_HTTP_NOT_FOUND 404
#define NGX_HTTP_NOT_ALLOWED 405
#define NGX_HTTP_REQUEST_TIME_OUT 408
#define NGX_HTTP_CONFLICT 409
#define NGX_HTTP_LENGTH_REQUIRED 411
#define NGX_HTTP_PRECONDITION_FAILED 412
#define NGX_HTTP_REQUEST_ENTITY_TOO_LARGE 413
#define NGX_HTTP_REQUEST_URI_TOO_LARGE 414
#define NGX_HTTP_UNSUPPORTED_MEDIA_TYPE 415
#define NGX_HTTP_RANGE_NOT_SATISFIABLE 416
/* Our own HTTP codes */
/* The special code to close connection without any response */
#define NGX_HTTP_CLOSE 444
#define NGX_HTTP_OWN_CODES 495
#define NGX_HTTPS_CERT_ERROR 495
#define NGX_HTTPS_NO_CERT 496
/*
* We use the special code for the plain HTTP requests that are sent to
* HTTPS port to distinguish it from 4XX in an error page redirection
*/
#define NGX_HTTP_TO_HTTPS 497
/* 498 is the canceled code for the requests with invalid host name */
/*
* HTTP does not define the code for the case when a client closed
* the connection while we are processing its request so we introduce
* own code to log such situation when a client has closed the connection
* before we even try to send the HTTP header to it
*/
#define NGX_HTTP_CLIENT_CLOSED_REQUEST 499
#define NGX_HTTP_INTERNAL_SERVER_ERROR 500
#define NGX_HTTP_NOT_IMPLEMENTED 501
#define NGX_HTTP_BAD_GATEWAY 502
#define NGX_HTTP_SERVICE_UNAVAILABLE 503
#define NGX_HTTP_GATEWAY_TIME_OUT 504
#define NGX_HTTP_INSUFFICIENT_STORAGE 507
#define NGX_HTTP_LOWLEVEL_BUFFERED 0xf0
#define NGX_HTTP_WRITE_BUFFERED 0x10
#define NGX_HTTP_GZIP_BUFFERED 0x20
#define NGX_HTTP_SSI_BUFFERED 0x01
#define NGX_HTTP_SUB_BUFFERED 0x02
#define NGX_HTTP_COPY_BUFFERED 0x04
typedef enum {
NGX_HTTP_INITING_REQUEST_STATE = 0,
NGX_HTTP_READING_REQUEST_STATE,
NGX_HTTP_PROCESS_REQUEST_STATE,
NGX_HTTP_CONNECT_UPSTREAM_STATE,
NGX_HTTP_WRITING_UPSTREAM_STATE,
NGX_HTTP_READING_UPSTREAM_STATE,
NGX_HTTP_WRITING_REQUEST_STATE,
NGX_HTTP_LINGERING_CLOSE_STATE,
NGX_HTTP_KEEPALIVE_STATE
} ngx_http_state_e;
typedef struct {
ngx_str_t name;
ngx_uint_t offset;
ngx_http_header_handler_pt handler;
} ngx_http_header_t;
typedef struct {
ngx_str_t name;
ngx_uint_t offset;
} ngx_http_header_out_t;
typedef struct {
ngx_list_t headers;
ngx_table_elt_t *host;
ngx_table_elt_t *connection;
ngx_table_elt_t *if_modified_since;
ngx_table_elt_t *user_agent;
ngx_table_elt_t *referer;
ngx_table_elt_t *content_length;
ngx_table_elt_t *content_type;
ngx_table_elt_t *range;
ngx_table_elt_t *if_range;
ngx_table_elt_t *transfer_encoding;
ngx_table_elt_t *expect;
#if (NGX_HTTP_GZIP)
ngx_table_elt_t *accept_encoding;
ngx_table_elt_t *via;
#endif
ngx_table_elt_t *authorization;
ngx_table_elt_t *keep_alive;
#if (NGX_HTTP_PROXY || NGX_HTTP_REALIP || NGX_HTTP_GEO)
ngx_table_elt_t *x_forwarded_for;
#endif
#if (NGX_HTTP_REALIP)
ngx_table_elt_t *x_real_ip;
#endif
#if (NGX_HTTP_HEADERS)
ngx_table_elt_t *accept;
ngx_table_elt_t *accept_language;
#endif
#if (NGX_HTTP_DAV)
ngx_table_elt_t *depth;
ngx_table_elt_t *destination;
ngx_table_elt_t *overwrite;
ngx_table_elt_t *date;
#endif
ngx_str_t user;
ngx_str_t passwd;
ngx_array_t cookies;
ngx_str_t server;
off_t content_length_n;
time_t keep_alive_n;
unsigned connection_type:2;
unsigned msie:1;
unsigned msie4:1;
unsigned msie6:1;
unsigned opera:1;
unsigned gecko:1;
unsigned chrome:1;
unsigned safari:1;
unsigned konqueror:1;
} ngx_http_headers_in_t;
typedef struct {
ngx_list_t headers;
ngx_uint_t status;
ngx_str_t status_line;
ngx_table_elt_t *server;
ngx_table_elt_t *date;
ngx_table_elt_t *content_length;
ngx_table_elt_t *content_encoding;
ngx_table_elt_t *location;
ngx_table_elt_t *refresh;
ngx_table_elt_t *last_modified;
ngx_table_elt_t *content_range;
ngx_table_elt_t *accept_ranges;
ngx_table_elt_t *www_authenticate;
ngx_table_elt_t *expires;
ngx_table_elt_t *etag;
ngx_str_t *override_charset;
size_t content_type_len;
ngx_str_t content_type;
ngx_str_t charset;
u_char *content_type_lowcase;
ngx_uint_t content_type_hash;
ngx_array_t cache_control;
off_t content_length_n;
time_t date_time;
time_t last_modified_time;
} ngx_http_headers_out_t;
typedef void (*ngx_http_client_body_handler_pt)(ngx_http_request_t *r);
typedef struct {
ngx_temp_file_t *temp_file;
ngx_chain_t *bufs;
ngx_buf_t *buf;
off_t rest;
ngx_chain_t *to_write;
ngx_http_client_body_handler_pt post_handler;
} ngx_http_request_body_t;
typedef struct {
ngx_http_request_t *request;
ngx_buf_t **busy;
ngx_int_t nbusy;
ngx_buf_t **free;
ngx_int_t nfree;
ngx_uint_t pipeline; /* unsigned pipeline:1; */
} ngx_http_connection_t;
typedef struct ngx_http_server_name_s ngx_http_server_name_t;
typedef struct {
ngx_hash_combined_t names;
ngx_uint_t nregex;
ngx_http_server_name_t *regex;
} ngx_http_virtual_names_t;
typedef void (*ngx_http_cleanup_pt)(void *data);
typedef struct ngx_http_cleanup_s ngx_http_cleanup_t;
struct ngx_http_cleanup_s {
ngx_http_cleanup_pt handler;
void *data;
ngx_http_cleanup_t *next;
};
typedef ngx_int_t (*ngx_http_post_subrequest_pt)(ngx_http_request_t *r,
void *data, ngx_int_t rc);
typedef struct {
ngx_http_post_subrequest_pt handler;
void *data;
} ngx_http_post_subrequest_t;
typedef struct ngx_http_postponed_request_s ngx_http_postponed_request_t;
struct ngx_http_postponed_request_s {
ngx_http_request_t *request;
ngx_chain_t *out;
ngx_http_postponed_request_t *next;
};
typedef struct ngx_http_posted_request_s ngx_http_posted_request_t;
struct ngx_http_posted_request_s {
ngx_http_request_t *request;
ngx_http_posted_request_t *next;
};
typedef ngx_int_t (*ngx_http_handler_pt)(ngx_http_request_t *r);
typedef void (*ngx_http_event_handler_pt)(ngx_http_request_t *r);
struct ngx_http_request_s {
uint32_t signature; /* "HTTP" */
ngx_connection_t *connection;
void **ctx;
void **main_conf;
void **srv_conf;
void **loc_conf;
ngx_http_event_handler_pt read_event_handler;
ngx_http_event_handler_pt write_event_handler;
#if (NGX_HTTP_CACHE)
ngx_http_cache_t *cache;
#endif
ngx_http_upstream_t *upstream;
ngx_array_t *upstream_states;
/* of ngx_http_upstream_state_t */
ngx_pool_t *pool;
ngx_buf_t *header_in;
ngx_http_headers_in_t headers_in;
ngx_http_headers_out_t headers_out;
ngx_http_request_body_t *request_body;
time_t lingering_time;
time_t start_sec;
ngx_msec_t start_msec;
ngx_uint_t method;
ngx_uint_t http_version;
ngx_str_t request_line;
ngx_str_t uri;
ngx_str_t args;
ngx_str_t exten;
ngx_str_t unparsed_uri;
ngx_str_t method_name;
ngx_str_t http_protocol;
ngx_chain_t *out;
ngx_http_request_t *main;
ngx_http_request_t *parent;
ngx_http_postponed_request_t *postponed;
ngx_http_post_subrequest_t *post_subrequest;
ngx_http_posted_request_t *posted_requests;
ngx_http_virtual_names_t *virtual_names;
ngx_int_t phase_handler;
ngx_http_handler_pt content_handler;
ngx_uint_t access_code;
ngx_http_variable_value_t *variables;
#if (NGX_PCRE)
ngx_uint_t ncaptures;
int *captures;
u_char *captures_data;
#endif
size_t limit_rate;
/* used to learn the Apache compatible response length without a header */
size_t header_size;
off_t request_length;
ngx_uint_t err_status;
ngx_http_connection_t *http_connection;
ngx_http_log_handler_pt log_handler;
ngx_http_cleanup_t *cleanup;
unsigned http_state:4;
/* URI with "/." and on Win32 with "//" */
unsigned complex_uri:1;
/* URI with "%" */
unsigned quoted_uri:1;
/* URI with "+" */
unsigned plus_in_uri:1;
unsigned invalid_header:1;
unsigned valid_location:1;
unsigned valid_unparsed_uri:1;
unsigned uri_changed:1;
unsigned uri_changes:4;
unsigned request_body_in_single_buf:1;
unsigned request_body_in_file_only:1;
unsigned request_body_in_persistent_file:1;
unsigned request_body_in_clean_file:1;
unsigned request_body_file_group_access:1;
unsigned request_body_file_log_level:3;
unsigned subrequest_in_memory:1;
unsigned waited:1;
#if (NGX_HTTP_CACHE)
unsigned cached:1;
#endif
#if (NGX_HTTP_GZIP)
unsigned gzip_tested:1;
unsigned gzip_ok:1;
unsigned gzip_vary:1;
#endif
unsigned proxy:1;
unsigned bypass_cache:1;
unsigned no_cache:1;
/*
* instead of using the request context data in
* ngx_http_limit_zone_module and ngx_http_limit_req_module
* we use the single bits in the request structure
*/
unsigned limit_zone_set:1;
unsigned limit_req_set:1;
#if 0
unsigned cacheable:1;
#endif
unsigned pipeline:1;
unsigned plain_http:1;
unsigned chunked:1;
unsigned header_only:1;
unsigned zero_body:1;
unsigned keepalive:1;
unsigned lingering_close:1;
unsigned discard_body:1;
unsigned internal:1;
unsigned error_page:1;
unsigned ignore_content_encoding:1;
unsigned filter_finalize:1;
unsigned post_action:1;
unsigned request_complete:1;
unsigned request_output:1;
unsigned header_sent:1;
unsigned expect_tested:1;
unsigned root_tested:1;
unsigned done:1;
unsigned logged:1;
unsigned buffered:4;
unsigned main_filter_need_in_memory:1;
unsigned filter_need_in_memory:1;
unsigned filter_need_temporary:1;
unsigned allow_ranges:1;
#if (NGX_STAT_STUB)
unsigned stat_reading:1;
unsigned stat_writing:1;
#endif
unsigned subrequests:8;
/* used to parse HTTP headers */
ngx_uint_t state;
u_char *uri_start;
u_char *uri_end;
u_char *uri_ext;
u_char *args_start;
u_char *request_start;
u_char *request_end;
u_char *method_end;
u_char *schema_start;
u_char *schema_end;
u_char *host_start;
u_char *host_end;
u_char *port_start;
u_char *port_end;
u_char *header_name_start;
u_char *header_name_end;
u_char *header_start;
u_char *header_end;
unsigned http_minor:16;
unsigned http_major:16;
ngx_uint_t header_hash;
ngx_uint_t lowcase_index;
u_char lowcase_header[NGX_HTTP_LC_HEADER_LEN];
};
extern ngx_http_header_t ngx_http_headers_in[];
extern ngx_http_header_out_t ngx_http_headers_out[];
#endif /* _NGX_HTTP_REQUEST_H_INCLUDED_ */
nginx-0.7.68/src/http/ngx_http_header_filter_module.c 000644 001750 001750 00000045560 11403136641 022027 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#include
#include
#include
#include
static ngx_int_t ngx_http_header_filter_init(ngx_conf_t *cf);
static ngx_int_t ngx_http_header_filter(ngx_http_request_t *r);
static ngx_http_module_t ngx_http_header_filter_module_ctx = {
NULL, /* preconfiguration */
ngx_http_header_filter_init, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
NULL, /* create location configuration */
NULL, /* merge location configuration */
};
ngx_module_t ngx_http_header_filter_module = {
NGX_MODULE_V1,
&ngx_http_header_filter_module_ctx, /* module context */
NULL, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static char ngx_http_server_string[] = "Server: nginx" CRLF;
static char ngx_http_server_full_string[] = "Server: " NGINX_VER CRLF;
static ngx_str_t ngx_http_status_lines[] = {
ngx_string("200 OK"),
ngx_string("201 Created"),
ngx_null_string, /* "202 Accepted" */
ngx_null_string, /* "203 Non-Authoritative Information" */
ngx_string("204 No Content"),
ngx_null_string, /* "205 Reset Content" */
ngx_string("206 Partial Content"),
/* ngx_null_string, */ /* "207 Multi-Status" */
#define NGX_HTTP_LAST_LEVEL_200 207
#define NGX_HTTP_LEVEL_200 (NGX_HTTP_LAST_LEVEL_200 - 200)
/* ngx_null_string, */ /* "300 Multiple Choices" */
ngx_string("301 Moved Permanently"),
ngx_string("302 Moved Temporarily"),
ngx_null_string, /* "303 See Other" */
ngx_string("304 Not Modified"),
/* ngx_null_string, */ /* "305 Use Proxy" */
/* ngx_null_string, */ /* "306 unused" */
/* ngx_null_string, */ /* "307 Temporary Redirect" */
#define NGX_HTTP_LAST_LEVEL_300 305
#define NGX_HTTP_LEVEL_300 (NGX_HTTP_LAST_LEVEL_300 - 301)
ngx_string("400 Bad Request"),
ngx_string("401 Unauthorized"),
ngx_string("402 Payment Required"),
ngx_string("403 Forbidden"),
ngx_string("404 Not Found"),
ngx_string("405 Not Allowed"),
ngx_string("406 Not Acceptable"),
ngx_null_string, /* "407 Proxy Authentication Required" */
ngx_string("408 Request Time-out"),
ngx_string("409 Conflict"),
ngx_string("410 Gone"),
ngx_string("411 Length Required"),
ngx_string("412 Precondition Failed"),
ngx_string("413 Request Entity Too Large"),
ngx_null_string, /* "414 Request-URI Too Large", but we never send it
* because we treat such requests as the HTTP/0.9
* requests and send only a body without a header
*/
ngx_string("415 Unsupported Media Type"),
ngx_string("416 Requested Range Not Satisfiable"),
/* ngx_null_string, */ /* "417 Expectation Failed" */
/* ngx_null_string, */ /* "418 unused" */
/* ngx_null_string, */ /* "419 unused" */
/* ngx_null_string, */ /* "420 unused" */
/* ngx_null_string, */ /* "421 unused" */
/* ngx_null_string, */ /* "422 Unprocessable Entity" */
/* ngx_null_string, */ /* "423 Locked" */
/* ngx_null_string, */ /* "424 Failed Dependency" */
#define NGX_HTTP_LAST_LEVEL_400 417
#define NGX_HTTP_LEVEL_400 (NGX_HTTP_LAST_LEVEL_400 - 400)
ngx_string("500 Internal Server Error"),
ngx_string("501 Method Not Implemented"),
ngx_string("502 Bad Gateway"),
ngx_string("503 Service Temporarily Unavailable"),
ngx_string("504 Gateway Time-out"),
ngx_null_string, /* "505 HTTP Version Not Supported" */
ngx_null_string, /* "506 Variant Also Negotiates" */
ngx_string("507 Insufficient Storage"),
/* ngx_null_string, */ /* "508 unused" */
/* ngx_null_string, */ /* "509 unused" */
/* ngx_null_string, */ /* "510 Not Extended" */
#define NGX_HTTP_LAST_LEVEL_500 508
};
ngx_http_header_out_t ngx_http_headers_out[] = {
{ ngx_string("Server"), offsetof(ngx_http_headers_out_t, server) },
{ ngx_string("Date"), offsetof(ngx_http_headers_out_t, date) },
#if 0
{ ngx_string("Content-Type"),
offsetof(ngx_http_headers_out_t, content_type) },
#endif
{ ngx_string("Content-Length"),
offsetof(ngx_http_headers_out_t, content_length) },
{ ngx_string("Content-Encoding"),
offsetof(ngx_http_headers_out_t, content_encoding) },
{ ngx_string("Location"), offsetof(ngx_http_headers_out_t, location) },
{ ngx_string("Last-Modified"),
offsetof(ngx_http_headers_out_t, last_modified) },
{ ngx_string("Accept-Ranges"),
offsetof(ngx_http_headers_out_t, accept_ranges) },
{ ngx_string("Expires"), offsetof(ngx_http_headers_out_t, expires) },
{ ngx_string("Cache-Control"),
offsetof(ngx_http_headers_out_t, cache_control) },
{ ngx_string("ETag"), offsetof(ngx_http_headers_out_t, etag) },
{ ngx_null_string, 0 }
};
static ngx_int_t
ngx_http_header_filter(ngx_http_request_t *r)
{
u_char *p;
size_t len;
ngx_str_t host, *status_line;
ngx_buf_t *b;
ngx_uint_t status, i, port;
ngx_chain_t out;
ngx_list_part_t *part;
ngx_table_elt_t *header;
ngx_connection_t *c;
ngx_http_core_loc_conf_t *clcf;
ngx_http_core_srv_conf_t *cscf;
struct sockaddr_in *sin;
#if (NGX_HAVE_INET6)
struct sockaddr_in6 *sin6;
#endif
u_char addr[NGX_SOCKADDR_STRLEN];
r->header_sent = 1;
if (r != r->main) {
return NGX_OK;
}
if (r->http_version < NGX_HTTP_VERSION_10) {
return NGX_OK;
}
if (r->method == NGX_HTTP_HEAD) {
r->header_only = 1;
}
if (r->headers_out.last_modified_time != -1) {
if (r->headers_out.status != NGX_HTTP_OK
&& r->headers_out.status != NGX_HTTP_PARTIAL_CONTENT
&& r->headers_out.status != NGX_HTTP_NOT_MODIFIED)
{
r->headers_out.last_modified_time = -1;
r->headers_out.last_modified = NULL;
}
}
len = sizeof("HTTP/1.x ") - 1 + sizeof(CRLF) - 1
/* the end of the header */
+ sizeof(CRLF) - 1;
/* status line */
if (r->headers_out.status_line.len) {
len += r->headers_out.status_line.len;
status_line = &r->headers_out.status_line;
#if (NGX_SUPPRESS_WARN)
status = 0;
#endif
} else {
status = r->headers_out.status;
if (status >= NGX_HTTP_OK
&& status < NGX_HTTP_LAST_LEVEL_200)
{
/* 2XX */
if (status == NGX_HTTP_NO_CONTENT) {
r->header_only = 1;
r->headers_out.content_type.len = 0;
r->headers_out.content_type.data = NULL;
r->headers_out.last_modified_time = -1;
r->headers_out.last_modified = NULL;
r->headers_out.content_length = NULL;
r->headers_out.content_length_n = -1;
}
status -= NGX_HTTP_OK;
status_line = &ngx_http_status_lines[status];
len += ngx_http_status_lines[status].len;
} else if (status >= NGX_HTTP_MOVED_PERMANENTLY
&& status < NGX_HTTP_LAST_LEVEL_300)
{
/* 3XX */
if (status == NGX_HTTP_NOT_MODIFIED) {
r->header_only = 1;
}
status = status - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_LEVEL_200;
status_line = &ngx_http_status_lines[status];
len += ngx_http_status_lines[status].len;
} else if (status >= NGX_HTTP_BAD_REQUEST
&& status < NGX_HTTP_LAST_LEVEL_400)
{
/* 4XX */
status = status - NGX_HTTP_BAD_REQUEST
+ NGX_HTTP_LEVEL_200
+ NGX_HTTP_LEVEL_300;
status_line = &ngx_http_status_lines[status];
len += ngx_http_status_lines[status].len;
} else if (status >= NGX_HTTP_INTERNAL_SERVER_ERROR
&& status < NGX_HTTP_LAST_LEVEL_500)
{
/* 5XX */
status = status - NGX_HTTP_INTERNAL_SERVER_ERROR
+ NGX_HTTP_LEVEL_200
+ NGX_HTTP_LEVEL_300
+ NGX_HTTP_LEVEL_400;
status_line = &ngx_http_status_lines[status];
len += ngx_http_status_lines[status].len;
} else {
len += NGX_INT_T_LEN;
status_line = NULL;
}
}
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (r->headers_out.server == NULL) {
len += clcf->server_tokens ? sizeof(ngx_http_server_full_string) - 1:
sizeof(ngx_http_server_string) - 1;
}
if (r->headers_out.date == NULL) {
len += sizeof("Date: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1;
}
if (r->headers_out.content_type.len) {
len += sizeof("Content-Type: ") - 1
+ r->headers_out.content_type.len + 2;
if (r->headers_out.content_type_len == r->headers_out.content_type.len
&& r->headers_out.charset.len)
{
len += sizeof("; charset=") - 1 + r->headers_out.charset.len;
}
}
if (r->headers_out.content_length == NULL
&& r->headers_out.content_length_n >= 0)
{
len += sizeof("Content-Length: ") - 1 + NGX_OFF_T_LEN + 2;
}
if (r->headers_out.last_modified == NULL
&& r->headers_out.last_modified_time != -1)
{
len += sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1;
}
c = r->connection;
if (r->headers_out.location
&& r->headers_out.location->value.len
&& r->headers_out.location->value.data[0] == '/')
{
r->headers_out.location->hash = 0;
if (clcf->server_name_in_redirect) {
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
host = cscf->server_name;
} else if (r->headers_in.server.len) {
host = r->headers_in.server;
} else {
host.len = NGX_SOCKADDR_STRLEN;
host.data = addr;
if (ngx_connection_local_sockaddr(c, &host, 0) != NGX_OK) {
return NGX_ERROR;
}
}
switch (c->local_sockaddr->sa_family) {
#if (NGX_HAVE_INET6)
case AF_INET6:
sin6 = (struct sockaddr_in6 *) c->local_sockaddr;
port = ntohs(sin6->sin6_port);
break;
#endif
default: /* AF_INET */
sin = (struct sockaddr_in *) c->local_sockaddr;
port = ntohs(sin->sin_port);
break;
}
len += sizeof("Location: https://") - 1
+ host.len
+ r->headers_out.location->value.len + 2;
if (clcf->port_in_redirect) {
#if (NGX_HTTP_SSL)
if (c->ssl)
port = (port == 443) ? 0 : port;
else
#endif
port = (port == 80) ? 0 : port;
} else {
port = 0;
}
if (port) {
len += sizeof(":65535") - 1;
}
} else {
host.len = 0;
host.data = NULL;
port = 0;
}
if (r->chunked) {
len += sizeof("Transfer-Encoding: chunked" CRLF) - 1;
}
if (r->keepalive) {
len += sizeof("Connection: keep-alive" CRLF) - 1;
/*
* MSIE and Opera ignore the "Keep-Alive: timeout=" header.
* MSIE keeps the connection alive for about 60-65 seconds.
* Opera keeps the connection alive very long.
* Mozilla keeps the connection alive for N plus about 1-10 seconds.
* Konqueror keeps the connection alive for about N seconds.
*/
if (clcf->keepalive_header) {
len += sizeof("Keep-Alive: timeout=") - 1 + NGX_TIME_T_LEN + 2;
}
} else {
len += sizeof("Connection: closed" CRLF) - 1;
}
#if (NGX_HTTP_GZIP)
if (r->gzip_vary) {
if (clcf->gzip_vary) {
len += sizeof("Vary: Accept-Encoding" CRLF) - 1;
} else {
r->gzip_vary = 0;
}
}
#endif
part = &r->headers_out.headers.part;
header = part->elts;
for (i = 0; /* void */; i++) {
if (i >= part->nelts) {
if (part->next == NULL) {
break;
}
part = part->next;
header = part->elts;
i = 0;
}
if (header[i].hash == 0) {
continue;
}
len += header[i].key.len + sizeof(": ") - 1 + header[i].value.len
+ sizeof(CRLF) - 1;
}
b = ngx_create_temp_buf(r->pool, len);
if (b == NULL) {
return NGX_ERROR;
}
/* "HTTP/1.x " */
b->last = ngx_cpymem(b->last, "HTTP/1.1 ", sizeof("HTTP/1.x ") - 1);
/* status line */
if (status_line) {
b->last = ngx_copy(b->last, status_line->data, status_line->len);
} else {
b->last = ngx_sprintf(b->last, "%ui", status);
}
*b->last++ = CR; *b->last++ = LF;
if (r->headers_out.server == NULL) {
if (clcf->server_tokens) {
p = (u_char *) ngx_http_server_full_string;
len = sizeof(ngx_http_server_full_string) - 1;
} else {
p = (u_char *) ngx_http_server_string;
len = sizeof(ngx_http_server_string) - 1;
}
b->last = ngx_cpymem(b->last, p, len);
}
if (r->headers_out.date == NULL) {
b->last = ngx_cpymem(b->last, "Date: ", sizeof("Date: ") - 1);
b->last = ngx_cpymem(b->last, ngx_cached_http_time.data,
ngx_cached_http_time.len);
*b->last++ = CR; *b->last++ = LF;
}
if (r->headers_out.content_type.len) {
b->last = ngx_cpymem(b->last, "Content-Type: ",
sizeof("Content-Type: ") - 1);
p = b->last;
b->last = ngx_copy(b->last, r->headers_out.content_type.data,
r->headers_out.content_type.len);
if (r->headers_out.content_type_len == r->headers_out.content_type.len
&& r->headers_out.charset.len)
{
b->last = ngx_cpymem(b->last, "; charset=",
sizeof("; charset=") - 1);
b->last = ngx_copy(b->last, r->headers_out.charset.data,
r->headers_out.charset.len);
/* update r->headers_out.content_type for possible logging */
r->headers_out.content_type.len = b->last - p;
r->headers_out.content_type.data = p;
}
*b->last++ = CR; *b->last++ = LF;
}
if (r->headers_out.content_length == NULL
&& r->headers_out.content_length_n >= 0)
{
b->last = ngx_sprintf(b->last, "Content-Length: %O" CRLF,
r->headers_out.content_length_n);
}
if (r->headers_out.last_modified == NULL
&& r->headers_out.last_modified_time != -1)
{
b->last = ngx_cpymem(b->last, "Last-Modified: ",
sizeof("Last-Modified: ") - 1);
b->last = ngx_http_time(b->last, r->headers_out.last_modified_time);
*b->last++ = CR; *b->last++ = LF;
}
if (host.data) {
p = b->last + sizeof("Location: ") - 1;
b->last = ngx_cpymem(b->last, "Location: http",
sizeof("Location: http") - 1);
#if (NGX_HTTP_SSL)
if (c->ssl) {
*b->last++ ='s';
}
#endif
*b->last++ = ':'; *b->last++ = '/'; *b->last++ = '/';
b->last = ngx_copy(b->last, host.data, host.len);
if (port) {
b->last = ngx_sprintf(b->last, ":%ui", port);
}
b->last = ngx_copy(b->last, r->headers_out.location->value.data,
r->headers_out.location->value.len);
/* update r->headers_out.location->value for possible logging */
r->headers_out.location->value.len = b->last - p;
r->headers_out.location->value.data = p;
r->headers_out.location->key.len = sizeof("Location") - 1;
r->headers_out.location->key.data = (u_char *) "Location";
*b->last++ = CR; *b->last++ = LF;
}
if (r->chunked) {
b->last = ngx_cpymem(b->last, "Transfer-Encoding: chunked" CRLF,
sizeof("Transfer-Encoding: chunked" CRLF) - 1);
}
if (r->keepalive) {
b->last = ngx_cpymem(b->last, "Connection: keep-alive" CRLF,
sizeof("Connection: keep-alive" CRLF) - 1);
if (clcf->keepalive_header) {
b->last = ngx_sprintf(b->last, "Keep-Alive: timeout=%T" CRLF,
clcf->keepalive_header);
}
} else {
b->last = ngx_cpymem(b->last, "Connection: close" CRLF,
sizeof("Connection: close" CRLF) - 1);
}
#if (NGX_HTTP_GZIP)
if (r->gzip_vary) {
b->last = ngx_cpymem(b->last, "Vary: Accept-Encoding" CRLF,
sizeof("Vary: Accept-Encoding" CRLF) - 1);
}
#endif
part = &r->headers_out.headers.part;
header = part->elts;
for (i = 0; /* void */; i++) {
if (i >= part->nelts) {
if (part->next == NULL) {
break;
}
part = part->next;
header = part->elts;
i = 0;
}
if (header[i].hash == 0) {
continue;
}
b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len);
*b->last++ = ':'; *b->last++ = ' ';
b->last = ngx_copy(b->last, header[i].value.data, header[i].value.len);
*b->last++ = CR; *b->last++ = LF;
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
"%*s", (size_t) (b->last - b->pos), b->pos);
/* the end of HTTP header */
*b->last++ = CR; *b->last++ = LF;
r->header_size = b->last - b->pos;
if (r->header_only) {
b->last_buf = 1;
}
out.buf = b;
out.next = NULL;
return ngx_http_write_filter(r, &out);
}
static ngx_int_t
ngx_http_header_filter_init(ngx_conf_t *cf)
{
ngx_http_top_header_filter = ngx_http_header_filter;
return NGX_OK;
}
nginx-0.7.68/src/http/ngx_http_busy_lock.h 000644 001750 001750 00000002333 10704463117 017657 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#ifndef _NGX_HTTP_BUSY_LOCK_H_INCLUDED_
#define _NGX_HTTP_BUSY_LOCK_H_INCLUDED_
#include
#include
#include
#include
typedef struct {
u_char *md5_mask;
char *md5;
int cacheable;
int busy;
int max_busy;
int waiting;
int max_waiting;
time_t timeout;
ngx_event_mutex_t *mutex;
} ngx_http_busy_lock_t;
typedef struct {
time_t time;
ngx_event_t *event;
void (*event_handler)(ngx_event_t *ev);
u_char *md5;
int slot;
} ngx_http_busy_lock_ctx_t;
int ngx_http_busy_lock(ngx_http_busy_lock_t *bl, ngx_http_busy_lock_ctx_t *bc);
int ngx_http_busy_lock_cacheable(ngx_http_busy_lock_t *bl,
ngx_http_busy_lock_ctx_t *bc, int lock);
void ngx_http_busy_unlock(ngx_http_busy_lock_t *bl,
ngx_http_busy_lock_ctx_t *bc);
char *ngx_http_set_busy_lock_slot(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
#endif /* _NGX_HTTP_BUSY_LOCK_H_INCLUDED_ */
nginx-0.7.68/src/http/ngx_http_upstream.c 000644 001750 001750 00000330142 11403162632 017515 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#include
#include
#include
#if (NGX_HTTP_CACHE)
static ngx_int_t ngx_http_upstream_cache(ngx_http_request_t *r,
ngx_http_upstream_t *u);
static ngx_int_t ngx_http_upstream_cache_send(ngx_http_request_t *r,
ngx_http_upstream_t *u);
static ngx_int_t ngx_http_upstream_cache_status(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
#endif
static void ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx);
static void ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r);
static void ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r);
static void ngx_http_upstream_check_broken_connection(ngx_http_request_t *r,
ngx_event_t *ev);
static void ngx_http_upstream_connect(ngx_http_request_t *r,
ngx_http_upstream_t *u);
static ngx_int_t ngx_http_upstream_reinit(ngx_http_request_t *r,
ngx_http_upstream_t *u);
static void ngx_http_upstream_send_request(ngx_http_request_t *r,
ngx_http_upstream_t *u);
static void ngx_http_upstream_send_request_handler(ngx_http_request_t *r,
ngx_http_upstream_t *u);
static void ngx_http_upstream_process_header(ngx_http_request_t *r,
ngx_http_upstream_t *u);
static ngx_int_t ngx_http_upstream_test_next(ngx_http_request_t *r,
ngx_http_upstream_t *u);
static ngx_int_t ngx_http_upstream_intercept_errors(ngx_http_request_t *r,
ngx_http_upstream_t *u);
static ngx_int_t ngx_http_upstream_test_connect(ngx_connection_t *c);
static ngx_int_t ngx_http_upstream_process_headers(ngx_http_request_t *r,
ngx_http_upstream_t *u);
static void ngx_http_upstream_process_body_in_memory(ngx_http_request_t *r,
ngx_http_upstream_t *u);
static void ngx_http_upstream_send_response(ngx_http_request_t *r,
ngx_http_upstream_t *u);
static void
ngx_http_upstream_process_non_buffered_downstream(ngx_http_request_t *r);
static void
ngx_http_upstream_process_non_buffered_upstream(ngx_http_request_t *r,
ngx_http_upstream_t *u);
static void
ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r,
ngx_uint_t do_write);
static ngx_int_t ngx_http_upstream_non_buffered_filter_init(void *data);
static ngx_int_t ngx_http_upstream_non_buffered_filter(void *data,
ssize_t bytes);
static void ngx_http_upstream_process_downstream(ngx_http_request_t *r);
static void ngx_http_upstream_process_upstream(ngx_http_request_t *r,
ngx_http_upstream_t *u);
static void ngx_http_upstream_process_request(ngx_http_request_t *r);
static void ngx_http_upstream_store(ngx_http_request_t *r,
ngx_http_upstream_t *u);
static void ngx_http_upstream_dummy_handler(ngx_http_request_t *r,
ngx_http_upstream_t *u);
static void ngx_http_upstream_next(ngx_http_request_t *r,
ngx_http_upstream_t *u, ngx_uint_t ft_type);
static void ngx_http_upstream_cleanup(void *data);
static void ngx_http_upstream_finalize_request(ngx_http_request_t *r,
ngx_http_upstream_t *u, ngx_int_t rc);
static ngx_int_t ngx_http_upstream_process_header_line(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t
ngx_http_upstream_process_cache_control(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_upstream_ignore_header_line(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_upstream_process_expires(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_upstream_process_accel_expires(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_upstream_process_limit_rate(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_upstream_process_buffering(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_upstream_process_charset(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_upstream_copy_header_line(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t
ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_upstream_copy_content_type(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_upstream_copy_content_length(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_upstream_copy_last_modified(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_upstream_rewrite_location(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_upstream_rewrite_refresh(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
#if (NGX_HTTP_GZIP)
static ngx_int_t ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
#endif
static ngx_int_t ngx_http_upstream_add_variables(ngx_conf_t *cf);
static ngx_int_t ngx_http_upstream_addr_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_upstream_status_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_upstream_response_time_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_upstream_response_length_variable(
ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data);
static char *ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy);
static char *ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static void *ngx_http_upstream_create_main_conf(ngx_conf_t *cf);
static char *ngx_http_upstream_init_main_conf(ngx_conf_t *cf, void *conf);
#if (NGX_HTTP_SSL)
static void ngx_http_upstream_ssl_init_connection(ngx_http_request_t *,
ngx_http_upstream_t *u, ngx_connection_t *c);
static void ngx_http_upstream_ssl_handshake(ngx_connection_t *c);
#endif
ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = {
{ ngx_string("Status"),
ngx_http_upstream_process_header_line,
offsetof(ngx_http_upstream_headers_in_t, status),
ngx_http_upstream_copy_header_line, 0, 0 },
{ ngx_string("Content-Type"),
ngx_http_upstream_process_header_line,
offsetof(ngx_http_upstream_headers_in_t, content_type),
ngx_http_upstream_copy_content_type, 0, 1 },
{ ngx_string("Content-Length"),
ngx_http_upstream_process_header_line,
offsetof(ngx_http_upstream_headers_in_t, content_length),
ngx_http_upstream_copy_content_length, 0, 0 },
{ ngx_string("Date"),
ngx_http_upstream_process_header_line,
offsetof(ngx_http_upstream_headers_in_t, date),
ngx_http_upstream_copy_header_line,
offsetof(ngx_http_headers_out_t, date), 0 },
{ ngx_string("Last-Modified"),
ngx_http_upstream_process_header_line,
offsetof(ngx_http_upstream_headers_in_t, last_modified),
ngx_http_upstream_copy_last_modified, 0, 0 },
{ ngx_string("ETag"),
ngx_http_upstream_process_header_line,
offsetof(ngx_http_upstream_headers_in_t, etag),
ngx_http_upstream_copy_header_line,
offsetof(ngx_http_headers_out_t, etag), 0 },
{ ngx_string("Server"),
ngx_http_upstream_process_header_line,
offsetof(ngx_http_upstream_headers_in_t, server),
ngx_http_upstream_copy_header_line,
offsetof(ngx_http_headers_out_t, server), 0 },
{ ngx_string("WWW-Authenticate"),
ngx_http_upstream_process_header_line,
offsetof(ngx_http_upstream_headers_in_t, www_authenticate),
ngx_http_upstream_copy_header_line, 0, 0 },
{ ngx_string("Location"),
ngx_http_upstream_process_header_line,
offsetof(ngx_http_upstream_headers_in_t, location),
ngx_http_upstream_rewrite_location, 0, 0 },
{ ngx_string("Refresh"),
ngx_http_upstream_ignore_header_line, 0,
ngx_http_upstream_rewrite_refresh, 0, 0 },
{ ngx_string("Set-Cookie"),
ngx_http_upstream_ignore_header_line, 0,
ngx_http_upstream_copy_header_line, 0, 1 },
{ ngx_string("Content-Disposition"),
ngx_http_upstream_ignore_header_line, 0,
ngx_http_upstream_copy_header_line, 0, 1 },
{ ngx_string("Cache-Control"),
ngx_http_upstream_process_cache_control, 0,
ngx_http_upstream_copy_multi_header_lines,
offsetof(ngx_http_headers_out_t, cache_control), 1 },
{ ngx_string("Expires"),
ngx_http_upstream_process_expires, 0,
ngx_http_upstream_copy_header_line,
offsetof(ngx_http_headers_out_t, expires), 1 },
{ ngx_string("Accept-Ranges"),
ngx_http_upstream_process_header_line,
offsetof(ngx_http_upstream_headers_in_t, accept_ranges),
ngx_http_upstream_copy_allow_ranges,
offsetof(ngx_http_headers_out_t, accept_ranges), 1 },
{ ngx_string("Connection"),
ngx_http_upstream_ignore_header_line, 0,
ngx_http_upstream_ignore_header_line, 0, 0 },
{ ngx_string("Keep-Alive"),
ngx_http_upstream_ignore_header_line, 0,
ngx_http_upstream_ignore_header_line, 0, 0 },
{ ngx_string("X-Powered-By"),
ngx_http_upstream_ignore_header_line, 0,
ngx_http_upstream_copy_header_line, 0, 0 },
{ ngx_string("X-Accel-Expires"),
ngx_http_upstream_process_accel_expires, 0,
ngx_http_upstream_copy_header_line, 0, 0 },
{ ngx_string("X-Accel-Redirect"),
ngx_http_upstream_process_header_line,
offsetof(ngx_http_upstream_headers_in_t, x_accel_redirect),
ngx_http_upstream_copy_header_line, 0, 0 },
{ ngx_string("X-Accel-Limit-Rate"),
ngx_http_upstream_process_limit_rate, 0,
ngx_http_upstream_copy_header_line, 0, 0 },
{ ngx_string("X-Accel-Buffering"),
ngx_http_upstream_process_buffering, 0,
ngx_http_upstream_copy_header_line, 0, 0 },
{ ngx_string("X-Accel-Charset"),
ngx_http_upstream_process_charset, 0,
ngx_http_upstream_copy_header_line, 0, 0 },
#if (NGX_HTTP_GZIP)
{ ngx_string("Content-Encoding"),
ngx_http_upstream_process_header_line,
offsetof(ngx_http_upstream_headers_in_t, content_encoding),
ngx_http_upstream_copy_content_encoding, 0, 0 },
#endif
{ ngx_null_string, NULL, 0, NULL, 0, 0 }
};
static ngx_command_t ngx_http_upstream_commands[] = {
{ ngx_string("upstream"),
NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE1,
ngx_http_upstream,
0,
0,
NULL },
{ ngx_string("server"),
NGX_HTTP_UPS_CONF|NGX_CONF_1MORE,
ngx_http_upstream_server,
NGX_HTTP_SRV_CONF_OFFSET,
0,
NULL },
ngx_null_command
};
static ngx_http_module_t ngx_http_upstream_module_ctx = {
ngx_http_upstream_add_variables, /* preconfiguration */
NULL, /* postconfiguration */
ngx_http_upstream_create_main_conf, /* create main configuration */
ngx_http_upstream_init_main_conf, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
NULL, /* create location configuration */
NULL /* merge location configuration */
};
ngx_module_t ngx_http_upstream_module = {
NGX_MODULE_V1,
&ngx_http_upstream_module_ctx, /* module context */
ngx_http_upstream_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_http_variable_t ngx_http_upstream_vars[] = {
{ ngx_string("upstream_addr"), NULL,
ngx_http_upstream_addr_variable, 0,
NGX_HTTP_VAR_NOHASH|NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("upstream_status"), NULL,
ngx_http_upstream_status_variable, 0,
NGX_HTTP_VAR_NOHASH|NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("upstream_response_time"), NULL,
ngx_http_upstream_response_time_variable, 0,
NGX_HTTP_VAR_NOHASH|NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("upstream_response_length"), NULL,
ngx_http_upstream_response_length_variable, 0,
NGX_HTTP_VAR_NOHASH|NGX_HTTP_VAR_NOCACHEABLE, 0 },
#if (NGX_HTTP_CACHE)
{ ngx_string("upstream_cache_status"), NULL,
ngx_http_upstream_cache_status, 0,
NGX_HTTP_VAR_NOHASH|NGX_HTTP_VAR_NOCACHEABLE, 0 },
#endif
{ ngx_null_string, NULL, NULL, 0, 0, 0 }
};
static ngx_http_upstream_next_t ngx_http_upstream_next_errors[] = {
{ 500, NGX_HTTP_UPSTREAM_FT_HTTP_500 },
{ 502, NGX_HTTP_UPSTREAM_FT_HTTP_502 },
{ 503, NGX_HTTP_UPSTREAM_FT_HTTP_503 },
{ 504, NGX_HTTP_UPSTREAM_FT_HTTP_504 },
{ 404, NGX_HTTP_UPSTREAM_FT_HTTP_404 },
{ 0, 0 }
};
ngx_conf_bitmask_t ngx_http_upstream_cache_method_mask[] = {
{ ngx_string("GET"), NGX_HTTP_GET},
{ ngx_string("HEAD"), NGX_HTTP_HEAD },
{ ngx_string("POST"), NGX_HTTP_POST },
{ ngx_null_string, 0 }
};
ngx_int_t
ngx_http_upstream_create(ngx_http_request_t *r)
{
ngx_http_upstream_t *u;
u = r->upstream;
if (u && u->cleanup) {
ngx_http_upstream_cleanup(r);
}
u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t));
if (u == NULL) {
return NGX_ERROR;
}
r->upstream = u;
u->peer.log = r->connection->log;
u->peer.log_error = NGX_ERROR_ERR;
#if (NGX_THREADS)
u->peer.lock = &r->connection->lock;
#endif
return NGX_OK;
}
void
ngx_http_upstream_init(ngx_http_request_t *r)
{
ngx_str_t *host;
ngx_uint_t i;
ngx_connection_t *c;
ngx_resolver_ctx_t *ctx, temp;
ngx_http_cleanup_t *cln;
ngx_http_upstream_t *u;
ngx_http_core_loc_conf_t *clcf;
ngx_http_upstream_srv_conf_t *uscf, **uscfp;
ngx_http_upstream_main_conf_t *umcf;
c = r->connection;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http init upstream, client timer: %d", c->read->timer_set);
if (c->read->timer_set) {
ngx_del_timer(c->read);
}
u = r->upstream;
u->store = (u->conf->store || u->conf->store_lengths);
if (!u->store && !r->post_action && !u->conf->ignore_client_abort) {
r->read_event_handler = ngx_http_upstream_rd_check_broken_connection;
r->write_event_handler = ngx_http_upstream_wr_check_broken_connection;
}
if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
if (!c->write->active) {
if (ngx_add_event(c->write, NGX_WRITE_EVENT, NGX_CLEAR_EVENT)
== NGX_ERROR)
{
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
}
}
if (r->request_body) {
u->request_bufs = r->request_body->bufs;
}
#if (NGX_HTTP_CACHE)
if (u->conf->cache) {
ngx_int_t rc;
rc = ngx_http_upstream_cache(r, u);
if (rc == NGX_DONE) {
return;
}
if (rc != NGX_DECLINED) {
ngx_http_finalize_request(r, rc);
return;
}
}
#endif
if (u->create_request(r) != NGX_OK) {
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
u->output.pool = r->pool;
u->output.bufs.num = 1;
u->output.bufs.size = clcf->client_body_buffer_size;
u->output.output_filter = ngx_chain_writer;
u->output.filter_ctx = &u->writer;
u->writer.pool = r->pool;
if (r->upstream_states == NULL) {
r->upstream_states = ngx_array_create(r->pool, 1,
sizeof(ngx_http_upstream_state_t));
if (r->upstream_states == NULL) {
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
} else {
u->state = ngx_array_push(r->upstream_states);
if (u->state == NULL) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t));
}
cln = ngx_http_cleanup_add(r, 0);
if (cln == NULL) {
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
cln->handler = ngx_http_upstream_cleanup;
cln->data = r;
u->cleanup = &cln->handler;
if (u->resolved == NULL) {
uscf = u->conf->upstream;
} else {
if (u->resolved->sockaddr) {
if (ngx_http_upstream_create_round_robin_peer(r, u->resolved)
!= NGX_OK)
{
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
ngx_http_upstream_connect(r, u);
return;
}
host = &u->resolved->host;
umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
uscfp = umcf->upstreams.elts;
for (i = 0; i < umcf->upstreams.nelts; i++) {
uscf = uscfp[i];
if (uscf->host.len == host->len
&& ((uscf->port == 0 && u->resolved->no_port)
|| uscf->port == u->resolved->port)
&& ngx_memcmp(uscf->host.data, host->data, host->len) == 0)
{
goto found;
}
}
temp.name = *host;
ctx = ngx_resolve_start(clcf->resolver, &temp);
if (ctx == NULL) {
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
if (ctx == NGX_NO_RESOLVER) {
ngx_log_error(NGX_LOG_ERR, c->log, 0,
"no resolver defined to resolve %V", host);
ngx_http_finalize_request(r, NGX_HTTP_BAD_GATEWAY);
return;
}
ctx->name = *host;
ctx->type = NGX_RESOLVE_A;
ctx->handler = ngx_http_upstream_resolve_handler;
ctx->data = r;
ctx->timeout = clcf->resolver_timeout;
u->resolved->ctx = ctx;
if (ngx_resolve_name(ctx) != NGX_OK) {
u->resolved->ctx = NULL;
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
return;
}
found:
if (uscf->peer.init(r, uscf) != NGX_OK) {
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
ngx_http_upstream_connect(r, u);
}
#if (NGX_HTTP_CACHE)
static ngx_int_t
ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u)
{
ngx_int_t rc;
ngx_http_cache_t *c;
if (u->conf->no_cache) {
rc = ngx_http_cache(r, u->conf->no_cache);
if (rc != NGX_OK) {
return rc;
}
}
if (!(r->method & u->conf->cache_methods)) {
return NGX_DECLINED;
}
if (r->method & NGX_HTTP_HEAD) {
u->method = ngx_http_core_get_method;
}
c = ngx_pcalloc(r->pool, sizeof(ngx_http_cache_t));
if (c == NULL) {
return NGX_ERROR;
}
if (ngx_array_init(&c->keys, r->pool, 4, sizeof(ngx_str_t)) != NGX_OK) {
return NGX_ERROR;
}
r->cache = c;
c->file.log = r->connection->log;
if (u->create_key(r) != NGX_OK) {
return NGX_ERROR;
}
/* TODO: add keys */
ngx_http_file_cache_create_key(r);
u->cacheable = 1;
c->min_uses = u->conf->cache_min_uses;
c->body_start = u->conf->buffer_size;
c->file_cache = u->conf->cache->data;
u->cache_status = NGX_HTTP_CACHE_MISS;
rc = ngx_http_file_cache_open(r);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http upstream cache: %i", rc);
switch (rc) {
case NGX_HTTP_CACHE_UPDATING:
if (u->conf->cache_use_stale & NGX_HTTP_UPSTREAM_FT_UPDATING) {
u->cache_status = rc;
rc = NGX_OK;
} else {
rc = NGX_HTTP_CACHE_STALE;
}
break;
case NGX_OK:
u->cache_status = NGX_HTTP_CACHE_HIT;
}
switch (rc) {
case NGX_OK:
rc = ngx_http_upstream_cache_send(r, u);
if (rc != NGX_HTTP_UPSTREAM_INVALID_HEADER) {
return rc;
}
break;
case NGX_ERROR:
return NGX_ERROR;
case NGX_HTTP_CACHE_STALE:
c->valid_sec = 0;
u->buffer.start = NULL;
u->cache_status = NGX_HTTP_CACHE_EXPIRED;
break;
case NGX_DECLINED:
if ((size_t) (u->buffer.end - u->buffer.start) < u->conf->buffer_size) {
u->buffer.start = NULL;
} else {
u->buffer.pos = u->buffer.start + c->header_start;
u->buffer.last = u->buffer.pos;
}
break;
case NGX_AGAIN:
u->cacheable = 0;
break;
default:
/* cached NGX_HTTP_BAD_GATEWAY, NGX_HTTP_GATEWAY_TIME_OUT, etc. */
u->cache_status = NGX_HTTP_CACHE_HIT;
return rc;
}
r->cached = 0;
return NGX_DECLINED;
}
static ngx_int_t
ngx_http_upstream_cache_send(ngx_http_request_t *r, ngx_http_upstream_t *u)
{
ngx_int_t rc;
ngx_http_cache_t *c;
r->cached = 1;
c = r->cache;
if (c->header_start == c->body_start) {
r->http_version = NGX_HTTP_VERSION_9;
return ngx_http_cache_send(r);
}
/* TODO: cache stack */
u->buffer = *c->buf;
u->buffer.pos += c->header_start;
ngx_memzero(&u->headers_in, sizeof(ngx_http_upstream_headers_in_t));
if (ngx_list_init(&u->headers_in.headers, r->pool, 8,
sizeof(ngx_table_elt_t))
!= NGX_OK)
{
return NGX_ERROR;
}
rc = u->process_header(r);
if (rc == NGX_OK) {
if (ngx_http_upstream_process_headers(r, u) != NGX_OK) {
return NGX_DONE;
}
return ngx_http_cache_send(r);
}
if (rc == NGX_ERROR) {
return NGX_ERROR;
}
/* rc == NGX_HTTP_UPSTREAM_INVALID_HEADER */
/* TODO: delete file */
return rc;
}
#endif
static void
ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx)
{
ngx_http_request_t *r;
ngx_http_upstream_resolved_t *ur;
r = ctx->data;
r->upstream->resolved->ctx = NULL;
if (ctx->state) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"%V could not be resolved (%i: %s)",
&ctx->name, ctx->state,
ngx_resolver_strerror(ctx->state));
ngx_resolve_name_done(ctx);
ngx_http_finalize_request(r, NGX_HTTP_BAD_GATEWAY);
return;
}
ur = r->upstream->resolved;
ur->naddrs = ctx->naddrs;
ur->addrs = ctx->addrs;
#if (NGX_DEBUG)
{
in_addr_t addr;
ngx_uint_t i;
for (i = 0; i < ctx->naddrs; i++) {
addr = ntohl(ur->addrs[i]);
ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"name was resolved to %ud.%ud.%ud.%ud",
(addr >> 24) & 0xff, (addr >> 16) & 0xff,
(addr >> 8) & 0xff, addr & 0xff);
}
}
#endif
if (ngx_http_upstream_create_round_robin_peer(r, ur) != NGX_OK) {
ngx_resolve_name_done(ctx);
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
ngx_resolve_name_done(ctx);
ngx_http_upstream_connect(r, r->upstream);
}
static void
ngx_http_upstream_handler(ngx_event_t *ev)
{
ngx_connection_t *c;
ngx_http_request_t *r;
ngx_http_log_ctx_t *ctx;
ngx_http_upstream_t *u;
c = ev->data;
r = c->data;
u = r->upstream;
c = r->connection;
ctx = c->log->data;
ctx->current_request = r;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http upstream request: \"%V?%V\"", &r->uri, &r->args);
if (ev->write) {
u->write_event_handler(r, u);
} else {
u->read_event_handler(r, u);
}
ngx_http_run_posted_requests(c);
}
static void
ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r)
{
ngx_http_upstream_check_broken_connection(r, r->connection->read);
}
static void
ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r)
{
ngx_http_upstream_check_broken_connection(r, r->connection->write);
}
static void
ngx_http_upstream_check_broken_connection(ngx_http_request_t *r,
ngx_event_t *ev)
{
int n;
char buf[1];
ngx_err_t err;
ngx_int_t event;
ngx_connection_t *c;
ngx_http_upstream_t *u;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ev->log, 0,
"http upstream check client, write event:%d, \"%V\"",
ev->write, &r->uri);
c = r->connection;
u = r->upstream;
if (c->error) {
if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) {
event = ev->write ? NGX_WRITE_EVENT : NGX_READ_EVENT;
if (ngx_del_event(ev, event, 0) != NGX_OK) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
}
if (!u->cacheable) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_CLIENT_CLOSED_REQUEST);
}
return;
}
if (u->peer.connection == NULL) {
return;
}
#if (NGX_HAVE_KQUEUE)
if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
if (!ev->pending_eof) {
return;
}
ev->eof = 1;
c->error = 1;
if (ev->kq_errno) {
ev->error = 1;
}
if (!u->cacheable && u->peer.connection) {
ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno,
"kevent() reported that client closed prematurely "
"connection, so upstream connection is closed too");
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_CLIENT_CLOSED_REQUEST);
return;
}
ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno,
"kevent() reported that client closed "
"prematurely connection");
if (u->peer.connection == NULL) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_CLIENT_CLOSED_REQUEST);
return;
}
return;
}
#endif
n = recv(c->fd, buf, 1, MSG_PEEK);
err = ngx_socket_errno;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, err,
"http upstream recv(): %d", n);
if (ev->write && (n >= 0 || err == NGX_EAGAIN)) {
return;
}
if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) {
event = ev->write ? NGX_WRITE_EVENT : NGX_READ_EVENT;
if (ngx_del_event(ev, event, 0) != NGX_OK) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
}
if (n > 0) {
return;
}
if (n == -1) {
if (err == NGX_EAGAIN) {
return;
}
ev->error = 1;
} else { /* n == 0 */
err = 0;
}
ev->eof = 1;
c->error = 1;
if (!u->cacheable && u->peer.connection) {
ngx_log_error(NGX_LOG_INFO, ev->log, err,
"client closed prematurely connection, "
"so upstream connection is closed too");
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_CLIENT_CLOSED_REQUEST);
return;
}
ngx_log_error(NGX_LOG_INFO, ev->log, err,
"client closed prematurely connection");
if (u->peer.connection == NULL) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_CLIENT_CLOSED_REQUEST);
return;
}
}
static void
ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u)
{
ngx_int_t rc;
ngx_time_t *tp;
ngx_connection_t *c;
r->connection->log->action = "connecting to upstream";
r->connection->single_connection = 0;
if (u->state && u->state->response_sec) {
tp = ngx_timeofday();
u->state->response_sec = tp->sec - u->state->response_sec;
u->state->response_msec = tp->msec - u->state->response_msec;
}
u->state = ngx_array_push(r->upstream_states);
if (u->state == NULL) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t));
tp = ngx_timeofday();
u->state->response_sec = tp->sec;
u->state->response_msec = tp->msec;
rc = ngx_event_connect_peer(&u->peer);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http upstream connect: %i", rc);
if (rc == NGX_ERROR) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
u->state->peer = u->peer.name;
if (rc == NGX_BUSY) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no live upstreams");
ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_NOLIVE);
return;
}
if (rc == NGX_DECLINED) {
ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
return;
}
/* rc == NGX_OK || rc == NGX_AGAIN */
c = u->peer.connection;
c->data = r;
c->write->handler = ngx_http_upstream_handler;
c->read->handler = ngx_http_upstream_handler;
u->write_event_handler = ngx_http_upstream_send_request_handler;
u->read_event_handler = ngx_http_upstream_process_header;
c->sendfile &= r->connection->sendfile;
u->output.sendfile = c->sendfile;
c->pool = r->pool;
c->log = r->connection->log;
c->read->log = c->log;
c->write->log = c->log;
/* init or reinit the ngx_output_chain() and ngx_chain_writer() contexts */
u->writer.out = NULL;
u->writer.last = &u->writer.out;
u->writer.connection = c;
u->writer.limit = 0;
if (u->request_sent) {
if (ngx_http_upstream_reinit(r, u) != NGX_OK) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
}
if (r->request_body
&& r->request_body->buf
&& r->request_body->temp_file
&& r == r->main)
{
/*
* the r->request_body->buf can be reused for one request only,
* the subrequests should allocate their own temporay bufs
*/
u->output.free = ngx_alloc_chain_link(r->pool);
if (u->output.free == NULL) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
u->output.free->buf = r->request_body->buf;
u->output.free->next = NULL;
u->output.allocated = 1;
r->request_body->buf->pos = r->request_body->buf->start;
r->request_body->buf->last = r->request_body->buf->start;
r->request_body->buf->tag = u->output.tag;
}
u->request_sent = 0;
if (rc == NGX_AGAIN) {
ngx_add_timer(c->write, u->conf->connect_timeout);
return;
}
#if (NGX_HTTP_SSL)
if (u->ssl && c->ssl == NULL) {
ngx_http_upstream_ssl_init_connection(r, u, c);
return;
}
#endif
ngx_http_upstream_send_request(r, u);
}
#if (NGX_HTTP_SSL)
static void
ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r,
ngx_http_upstream_t *u, ngx_connection_t *c)
{
ngx_int_t rc;
if (ngx_ssl_create_connection(u->conf->ssl, c,
NGX_SSL_BUFFER|NGX_SSL_CLIENT)
!= NGX_OK)
{
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
c->sendfile = 0;
u->output.sendfile = 0;
if (u->conf->ssl_session_reuse) {
if (u->peer.set_session(&u->peer, u->peer.data) != NGX_OK) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
}
r->connection->log->action = "SSL handshaking to upstream";
rc = ngx_ssl_handshake(c);
if (rc == NGX_AGAIN) {
c->ssl->handler = ngx_http_upstream_ssl_handshake;
return;
}
ngx_http_upstream_ssl_handshake(c);
}
static void
ngx_http_upstream_ssl_handshake(ngx_connection_t *c)
{
ngx_http_request_t *r;
ngx_http_upstream_t *u;
r = c->data;
u = r->upstream;
if (c->ssl->handshaked) {
if (u->conf->ssl_session_reuse) {
u->peer.save_session(&u->peer, u->peer.data);
}
c->write->handler = ngx_http_upstream_handler;
c->read->handler = ngx_http_upstream_handler;
ngx_http_upstream_send_request(r, u);
return;
}
ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
}
#endif
static ngx_int_t
ngx_http_upstream_reinit(ngx_http_request_t *r, ngx_http_upstream_t *u)
{
ngx_chain_t *cl;
if (u->reinit_request(r) != NGX_OK) {
return NGX_ERROR;
}
ngx_memzero(&u->headers_in, sizeof(ngx_http_upstream_headers_in_t));
if (ngx_list_init(&u->headers_in.headers, r->pool, 8,
sizeof(ngx_table_elt_t))
!= NGX_OK)
{
return NGX_ERROR;
}
/* reinit the request chain */
for (cl = u->request_bufs; cl; cl = cl->next) {
cl->buf->pos = cl->buf->start;
cl->buf->file_pos = 0;
}
/* reinit the subrequest's ngx_output_chain() context */
if (r->request_body && r->request_body->temp_file
&& r != r->main && u->output.buf)
{
u->output.free = ngx_alloc_chain_link(r->pool);
if (u->output.free == NULL) {
return NGX_ERROR;
}
u->output.free->buf = u->output.buf;
u->output.free->next = NULL;
u->output.buf->pos = u->output.buf->start;
u->output.buf->last = u->output.buf->start;
}
u->output.buf = NULL;
u->output.in = NULL;
u->output.busy = NULL;
/* reinit u->buffer */
u->buffer.pos = u->buffer.start;
#if (NGX_HTTP_CACHE)
if (r->cache) {
u->buffer.pos += r->cache->header_start;
}
#endif
u->buffer.last = u->buffer.pos;
return NGX_OK;
}
static void
ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u)
{
ngx_int_t rc;
ngx_connection_t *c;
c = u->peer.connection;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http upstream send request");
if (!u->request_sent && ngx_http_upstream_test_connect(c) != NGX_OK) {
ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
return;
}
c->log->action = "sending request to upstream";
rc = ngx_output_chain(&u->output, u->request_sent ? NULL : u->request_bufs);
u->request_sent = 1;
if (rc == NGX_ERROR) {
ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
return;
}
if (c->write->timer_set) {
ngx_del_timer(c->write);
}
if (rc == NGX_AGAIN) {
ngx_add_timer(c->write, u->conf->send_timeout);
if (ngx_handle_write_event(c->write, u->conf->send_lowat) != NGX_OK) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
return;
}
/* rc == NGX_OK */
if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) {
if (ngx_tcp_push(c->fd) == NGX_ERROR) {
ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno,
ngx_tcp_push_n " failed");
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
c->tcp_nopush = NGX_TCP_NOPUSH_UNSET;
}
ngx_add_timer(c->read, u->conf->read_timeout);
#if 1
if (c->read->ready) {
/* post aio operation */
/*
* TODO comment
* although we can post aio operation just in the end
* of ngx_http_upstream_connect() CHECK IT !!!
* it's better to do here because we postpone header buffer allocation
*/
ngx_http_upstream_process_header(r, u);
return;
}
#endif
u->write_event_handler = ngx_http_upstream_dummy_handler;
if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
}
static void
ngx_http_upstream_send_request_handler(ngx_http_request_t *r,
ngx_http_upstream_t *u)
{
ngx_connection_t *c;
c = u->peer.connection;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http upstream send request handler");
if (c->write->timedout) {
ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_TIMEOUT);
return;
}
#if (NGX_HTTP_SSL)
if (u->ssl && c->ssl == NULL) {
ngx_http_upstream_ssl_init_connection(r, u, c);
return;
}
#endif
if (u->header_sent) {
u->write_event_handler = ngx_http_upstream_dummy_handler;
(void) ngx_handle_write_event(c->write, 0);
return;
}
ngx_http_upstream_send_request(r, u);
}
static void
ngx_http_upstream_process_header(ngx_http_request_t *r, ngx_http_upstream_t *u)
{
ssize_t n;
ngx_int_t rc;
ngx_connection_t *c;
c = u->peer.connection;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http upstream process header");
c->log->action = "reading response header from upstream";
if (c->read->timedout) {
ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_TIMEOUT);
return;
}
if (!u->request_sent && ngx_http_upstream_test_connect(c) != NGX_OK) {
ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
return;
}
if (u->buffer.start == NULL) {
u->buffer.start = ngx_palloc(r->pool, u->conf->buffer_size);
if (u->buffer.start == NULL) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
u->buffer.pos = u->buffer.start;
u->buffer.last = u->buffer.start;
u->buffer.end = u->buffer.start + u->conf->buffer_size;
u->buffer.temporary = 1;
u->buffer.tag = u->output.tag;
if (ngx_list_init(&u->headers_in.headers, r->pool, 8,
sizeof(ngx_table_elt_t))
!= NGX_OK)
{
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
#if (NGX_HTTP_CACHE)
if (r->cache) {
u->buffer.pos += r->cache->header_start;
u->buffer.last = u->buffer.pos;
}
#endif
}
for ( ;; ) {
n = c->recv(c, u->buffer.last, u->buffer.end - u->buffer.last);
if (n == NGX_AGAIN) {
#if 0
ngx_add_timer(rev, u->read_timeout);
#endif
if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
return;
}
if (n == 0) {
ngx_log_error(NGX_LOG_ERR, c->log, 0,
"upstream prematurely closed connection");
}
if (n == NGX_ERROR || n == 0) {
ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
return;
}
u->buffer.last += n;
#if 0
u->valid_header_in = 0;
u->peer.cached = 0;
#endif
rc = u->process_header(r);
if (rc == NGX_AGAIN) {
if (u->buffer.pos == u->buffer.end) {
ngx_log_error(NGX_LOG_ERR, c->log, 0,
"upstream sent too big header");
ngx_http_upstream_next(r, u,
NGX_HTTP_UPSTREAM_FT_INVALID_HEADER);
return;
}
continue;
}
break;
}
if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) {
ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_INVALID_HEADER);
return;
}
if (rc == NGX_ERROR) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
/* rc == NGX_OK */
if (u->headers_in.status_n >= NGX_HTTP_BAD_REQUEST) {
if (r->subrequest_in_memory) {
u->buffer.last = u->buffer.pos;
}
if (ngx_http_upstream_test_next(r, u) == NGX_OK) {
return;
}
if (ngx_http_upstream_intercept_errors(r, u) == NGX_OK) {
return;
}
}
if (ngx_http_upstream_process_headers(r, u) != NGX_OK) {
return;
}
if (!r->subrequest_in_memory) {
ngx_http_upstream_send_response(r, u);
return;
}
/* subrequest content in memory */
if (u->input_filter == NULL) {
u->input_filter_init = ngx_http_upstream_non_buffered_filter_init;
u->input_filter = ngx_http_upstream_non_buffered_filter;
u->input_filter_ctx = r;
}
if (u->input_filter_init(u->input_filter_ctx) == NGX_ERROR) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
n = u->buffer.last - u->buffer.pos;
if (n) {
u->buffer.last -= n;
u->state->response_length += n;
if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) {
ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
if (u->length == 0) {
ngx_http_upstream_finalize_request(r, u, 0);
return;
}
}
u->read_event_handler = ngx_http_upstream_process_body_in_memory;
ngx_http_upstream_process_body_in_memory(r, u);
}
static ngx_int_t
ngx_http_upstream_test_next(ngx_http_request_t *r, ngx_http_upstream_t *u)
{
ngx_uint_t status;
ngx_http_upstream_next_t *un;
status = u->headers_in.status_n;
for (un = ngx_http_upstream_next_errors; un->status; un++) {
if (status != un->status) {
continue;
}
if (u->peer.tries > 1 && (u->conf->next_upstream & un->mask)) {
ngx_http_upstream_next(r, u, un->mask);
return NGX_OK;
}
#if (NGX_HTTP_CACHE)
if (u->cache_status == NGX_HTTP_CACHE_EXPIRED
&& (u->conf->cache_use_stale & un->mask))
{
ngx_int_t rc;
rc = u->reinit_request(r);
if (rc == NGX_OK) {
u->cache_status = NGX_HTTP_CACHE_STALE;
rc = ngx_http_upstream_cache_send(r, u);
}
ngx_http_upstream_finalize_request(r, u, rc);
return NGX_OK;
}
#endif
}
return NGX_DECLINED;
}
static ngx_int_t
ngx_http_upstream_intercept_errors(ngx_http_request_t *r,
ngx_http_upstream_t *u)
{
ngx_int_t status;
ngx_uint_t i;
ngx_table_elt_t *h;
ngx_http_err_page_t *err_page;
ngx_http_core_loc_conf_t *clcf;
status = u->headers_in.status_n;
if (status == NGX_HTTP_NOT_FOUND && u->conf->intercept_404) {
ngx_http_upstream_finalize_request(r, u, NGX_HTTP_NOT_FOUND);
return NGX_OK;
}
if (!u->conf->intercept_errors) {
return NGX_DECLINED;
}
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (clcf->error_pages == NULL) {
return NGX_DECLINED;
}
err_page = clcf->error_pages->elts;
for (i = 0; i < clcf->error_pages->nelts; i++) {
if (err_page[i].status == status) {
if (status == NGX_HTTP_UNAUTHORIZED
&& u->headers_in.www_authenticate)
{
h = ngx_list_push(&r->headers_out.headers);
if (h == NULL) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
return NGX_OK;
}
*h = *u->headers_in.www_authenticate;
r->headers_out.www_authenticate = h;
}
ngx_http_upstream_finalize_request(r, u, status);
return NGX_OK;
}
}
return NGX_DECLINED;
}
static ngx_int_t
ngx_http_upstream_test_connect(ngx_connection_t *c)
{
int err;
socklen_t len;
#if (NGX_HAVE_KQUEUE)
if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
if (c->write->pending_eof) {
c->log->action = "connecting to upstream";
(void) ngx_connection_error(c, c->write->kq_errno,
"kevent() reported that connect() failed");
return NGX_ERROR;
}
} else
#endif
{
err = 0;
len = sizeof(int);
/*
* BSDs and Linux return 0 and set a pending error in err
* Solaris returns -1 and sets errno
*/
if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len)
== -1)
{
err = ngx_errno;
}
if (err) {
c->log->action = "connecting to upstream";
(void) ngx_connection_error(c, err, "connect() failed");
return NGX_ERROR;
}
}
return NGX_OK;
}
static ngx_int_t
ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u)
{
ngx_str_t *uri, args;
ngx_uint_t i, flags;
ngx_list_part_t *part;
ngx_table_elt_t *h;
ngx_http_upstream_header_t *hh;
ngx_http_upstream_main_conf_t *umcf;
umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
if (u->headers_in.x_accel_redirect
&& !(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT))
{
ngx_http_upstream_finalize_request(r, u, NGX_DECLINED);
part = &u->headers_in.headers.part;
h = part->elts;
for (i = 0; /* void */; i++) {
if (i >= part->nelts) {
if (part->next == NULL) {
break;
}
part = part->next;
h = part->elts;
i = 0;
}
hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash,
h[i].lowcase_key, h[i].key.len);
if (hh && hh->redirect) {
if (hh->copy_handler(r, &h[i], hh->conf) != NGX_OK) {
ngx_http_finalize_request(r,
NGX_HTTP_INTERNAL_SERVER_ERROR);
return NGX_DONE;
}
}
}
uri = &u->headers_in.x_accel_redirect->value;
args.len = 0;
args.data = NULL;
flags = NGX_HTTP_LOG_UNSAFE;
if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) {
ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND);
return NGX_DONE;
}
if (r->method != NGX_HTTP_HEAD) {
r->method = NGX_HTTP_GET;
}
r->valid_unparsed_uri = 0;
ngx_http_internal_redirect(r, uri, &args);
return NGX_DONE;
}
part = &u->headers_in.headers.part;
h = part->elts;
for (i = 0; /* void */; i++) {
if (i >= part->nelts) {
if (part->next == NULL) {
break;
}
part = part->next;
h = part->elts;
i = 0;
}
if (ngx_hash_find(&u->conf->hide_headers_hash, h[i].hash,
h[i].lowcase_key, h[i].key.len))
{
continue;
}
hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash,
h[i].lowcase_key, h[i].key.len);
if (hh) {
if (hh->copy_handler(r, &h[i], hh->conf) != NGX_OK) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
return NGX_DONE;
}
continue;
}
if (ngx_http_upstream_copy_header_line(r, &h[i], 0) != NGX_OK) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
return NGX_DONE;
}
}
if (r->headers_out.server && r->headers_out.server->value.data == NULL) {
r->headers_out.server->hash = 0;
}
if (r->headers_out.date && r->headers_out.date->value.data == NULL) {
r->headers_out.date->hash = 0;
}
r->headers_out.status = u->headers_in.status_n;
r->headers_out.status_line = u->headers_in.status_line;
u->headers_in.content_length_n = r->headers_out.content_length_n;
if (r->headers_out.content_length_n != -1) {
u->length = (size_t) r->headers_out.content_length_n;
} else {
u->length = NGX_MAX_SIZE_T_VALUE;
}
return NGX_OK;
}
static void
ngx_http_upstream_process_body_in_memory(ngx_http_request_t *r,
ngx_http_upstream_t *u)
{
size_t size;
ssize_t n;
ngx_buf_t *b;
ngx_event_t *rev;
ngx_connection_t *c;
c = u->peer.connection;
rev = c->read;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http upstream process body on memory");
if (rev->timedout) {
ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
ngx_http_upstream_finalize_request(r, u, NGX_ETIMEDOUT);
return;
}
b = &u->buffer;
for ( ;; ) {
size = b->end - b->last;
if (size == 0) {
ngx_log_error(NGX_LOG_ALERT, c->log, 0,
"upstream buffer is too small to read repsonse");
ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
n = c->recv(c, b->last, size);
if (n == NGX_AGAIN) {
break;
}
if (n == 0 || n == NGX_ERROR) {
ngx_http_upstream_finalize_request(r, u, n);
return;
}
u->state->response_length += n;
if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) {
ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
if (!rev->ready) {
break;
}
}
if (ngx_handle_read_event(rev, 0) != NGX_OK) {
ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
if (rev->active) {
ngx_add_timer(rev, u->conf->read_timeout);
} else if (rev->timer_set) {
ngx_del_timer(rev);
}
}
static void
ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
{
int tcp_nodelay;
ssize_t n;
ngx_int_t rc;
ngx_event_pipe_t *p;
ngx_connection_t *c;
ngx_http_core_loc_conf_t *clcf;
rc = ngx_http_send_header(r);
if (rc == NGX_ERROR || rc > NGX_OK || r->post_action) {
ngx_http_upstream_finalize_request(r, u, rc);
return;
}
c = r->connection;
if (r->header_only) {
if (u->cacheable || u->store) {
if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) {
ngx_connection_error(c, ngx_socket_errno,
ngx_shutdown_socket_n " failed");
}
r->read_event_handler = ngx_http_request_empty_handler;
r->write_event_handler = ngx_http_request_empty_handler;
c->error = 1;
} else {
ngx_http_upstream_finalize_request(r, u, rc);
return;
}
}
u->header_sent = 1;
if (r->request_body && r->request_body->temp_file) {
ngx_pool_run_cleanup_file(r->pool, r->request_body->temp_file->file.fd);
r->request_body->temp_file->file.fd = NGX_INVALID_FILE;
}
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (!u->buffering) {
if (u->input_filter == NULL) {
u->input_filter_init = ngx_http_upstream_non_buffered_filter_init;
u->input_filter = ngx_http_upstream_non_buffered_filter;
u->input_filter_ctx = r;
}
u->read_event_handler = ngx_http_upstream_process_non_buffered_upstream;
r->write_event_handler =
ngx_http_upstream_process_non_buffered_downstream;
r->limit_rate = 0;
if (u->input_filter_init(u->input_filter_ctx) == NGX_ERROR) {
ngx_http_upstream_finalize_request(r, u, 0);
return;
}
if (clcf->tcp_nodelay && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay");
tcp_nodelay = 1;
if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
(const void *) &tcp_nodelay, sizeof(int)) == -1)
{
ngx_connection_error(c, ngx_socket_errno,
"setsockopt(TCP_NODELAY) failed");
ngx_http_upstream_finalize_request(r, u, 0);
return;
}
c->tcp_nodelay = NGX_TCP_NODELAY_SET;
}
n = u->buffer.last - u->buffer.pos;
if (n) {
u->buffer.last = u->buffer.pos;
u->state->response_length += n;
if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) {
ngx_http_upstream_finalize_request(r, u, 0);
return;
}
ngx_http_upstream_process_non_buffered_downstream(r);
} else {
u->buffer.pos = u->buffer.start;
u->buffer.last = u->buffer.start;
if (ngx_http_send_special(r, NGX_HTTP_FLUSH) == NGX_ERROR) {
ngx_http_upstream_finalize_request(r, u, 0);
return;
}
if (u->peer.connection->read->ready) {
ngx_http_upstream_process_non_buffered_upstream(r, u);
}
}
return;
}
/* TODO: preallocate event_pipe bufs, look "Content-Length" */
#if (NGX_HTTP_CACHE)
if (r->cache && r->cache->file.fd != NGX_INVALID_FILE) {
ngx_pool_run_cleanup_file(r->pool, r->cache->file.fd);
r->cache->file.fd = NGX_INVALID_FILE;
}
if (u->cacheable) {
time_t now, valid;
now = ngx_time();
valid = r->cache->valid_sec;
if (valid == 0) {
valid = ngx_http_file_cache_valid(u->conf->cache_valid,
u->headers_in.status_n);
if (valid) {
r->cache->valid_sec = now + valid;
}
}
if (valid) {
r->cache->last_modified = r->headers_out.last_modified_time;
r->cache->date = now;
r->cache->body_start = (u_short) (u->buffer.pos - u->buffer.start);
ngx_http_file_cache_set_header(r, u->buffer.start);
} else {
u->cacheable = 0;
r->headers_out.last_modified_time = -1;
}
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http cacheable: %d", u->cacheable);
if (u->cacheable == 0 && r->cache) {
ngx_http_file_cache_free(r, u->pipe->temp_file);
}
#endif
p = u->pipe;
p->output_filter = (ngx_event_pipe_output_filter_pt) ngx_http_output_filter;
p->output_ctx = r;
p->tag = u->output.tag;
p->bufs = u->conf->bufs;
p->busy_size = u->conf->busy_buffers_size;
p->upstream = u->peer.connection;
p->downstream = c;
p->pool = r->pool;
p->log = c->log;
p->cacheable = u->cacheable || u->store;
p->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
if (p->temp_file == NULL) {
ngx_http_upstream_finalize_request(r, u, 0);
return;
}
p->temp_file->file.fd = NGX_INVALID_FILE;
p->temp_file->file.log = c->log;
p->temp_file->path = u->conf->temp_path;
p->temp_file->pool = r->pool;
if (p->cacheable) {
p->temp_file->persistent = 1;
} else {
p->temp_file->log_level = NGX_LOG_WARN;
p->temp_file->warn = "an upstream response is buffered "
"to a temporary file";
}
p->max_temp_file_size = u->conf->max_temp_file_size;
p->temp_file_write_size = u->conf->temp_file_write_size;
p->preread_bufs = ngx_alloc_chain_link(r->pool);
if (p->preread_bufs == NULL) {
ngx_http_upstream_finalize_request(r, u, 0);
return;
}
p->preread_bufs->buf = &u->buffer;
p->preread_bufs->next = NULL;
u->buffer.recycled = 1;
p->preread_size = u->buffer.last - u->buffer.pos;
if (u->cacheable) {
p->buf_to_file = ngx_calloc_buf(r->pool);
if (p->buf_to_file == NULL) {
ngx_http_upstream_finalize_request(r, u, 0);
return;
}
p->buf_to_file->pos = u->buffer.start;
p->buf_to_file->last = u->buffer.pos;
p->buf_to_file->temporary = 1;
}
if (ngx_event_flags & NGX_USE_AIO_EVENT) {
/* the posted aio operation may currupt a shadow buffer */
p->single_buf = 1;
}
/* TODO: p->free_bufs = 0 if use ngx_create_chain_of_bufs() */
p->free_bufs = 1;
/*
* event_pipe would do u->buffer.last += p->preread_size
* as though these bytes were read
*/
u->buffer.last = u->buffer.pos;
if (u->conf->cyclic_temp_file) {
/*
* we need to disable the use of sendfile() if we use cyclic temp file
* because the writing a new data may interfere with sendfile()
* that uses the same kernel file pages (at least on FreeBSD)
*/
p->cyclic_temp_file = 1;
c->sendfile = 0;
} else {
p->cyclic_temp_file = 0;
}
p->read_timeout = u->conf->read_timeout;
p->send_timeout = clcf->send_timeout;
p->send_lowat = clcf->send_lowat;
u->read_event_handler = ngx_http_upstream_process_upstream;
r->write_event_handler = ngx_http_upstream_process_downstream;
ngx_http_upstream_process_upstream(r, u);
}
static void
ngx_http_upstream_process_non_buffered_downstream(ngx_http_request_t *r)
{
ngx_event_t *wev;
ngx_connection_t *c;
ngx_http_upstream_t *u;
c = r->connection;
u = r->upstream;
wev = c->write;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http upstream process non buffered downstream");
c->log->action = "sending to client";
if (wev->timedout) {
c->timedout = 1;
ngx_connection_error(c, NGX_ETIMEDOUT, "client timed out");
ngx_http_upstream_finalize_request(r, u, 0);
return;
}
ngx_http_upstream_process_non_buffered_request(r, 1);
}
static void
ngx_http_upstream_process_non_buffered_upstream(ngx_http_request_t *r,
ngx_http_upstream_t *u)
{
ngx_connection_t *c;
c = u->peer.connection;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http upstream process non buffered upstream");
c->log->action = "reading upstream";
if (c->read->timedout) {
ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
ngx_http_upstream_finalize_request(r, u, 0);
return;
}
ngx_http_upstream_process_non_buffered_request(r, 0);
}
static void
ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r,
ngx_uint_t do_write)
{
size_t size;
ssize_t n;
ngx_buf_t *b;
ngx_int_t rc;
ngx_connection_t *downstream, *upstream;
ngx_http_upstream_t *u;
ngx_http_core_loc_conf_t *clcf;
u = r->upstream;
downstream = r->connection;
upstream = u->peer.connection;
b = &u->buffer;
do_write = do_write || u->length == 0;
for ( ;; ) {
if (do_write) {
if (u->out_bufs || u->busy_bufs) {
rc = ngx_http_output_filter(r, u->out_bufs);
if (downstream->destroyed) {
return;
}
if (rc == NGX_ERROR) {
ngx_http_upstream_finalize_request(r, u, 0);
return;
}
ngx_chain_update_chains(&u->free_bufs, &u->busy_bufs,
&u->out_bufs, u->output.tag);
}
if (u->busy_bufs == NULL) {
if (u->length == 0
|| upstream->read->eof
|| upstream->read->error)
{
ngx_http_upstream_finalize_request(r, u, 0);
return;
}
b->pos = b->start;
b->last = b->start;
}
}
size = b->end - b->last;
if (size > u->length) {
size = u->length;
}
if (size && upstream->read->ready) {
n = upstream->recv(upstream, b->last, size);
if (n == NGX_AGAIN) {
break;
}
if (n > 0) {
u->state->response_length += n;
if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) {
ngx_http_upstream_finalize_request(r, u, 0);
return;
}
}
do_write = 1;
continue;
}
break;
}
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (downstream->data == r) {
if (ngx_handle_write_event(downstream->write, clcf->send_lowat)
!= NGX_OK)
{
ngx_http_upstream_finalize_request(r, u, 0);
return;
}
}
if (downstream->write->active && !downstream->write->ready) {
ngx_add_timer(downstream->write, clcf->send_timeout);
} else if (downstream->write->timer_set) {
ngx_del_timer(downstream->write);
}
if (ngx_handle_read_event(upstream->read, 0) != NGX_OK) {
ngx_http_upstream_finalize_request(r, u, 0);
return;
}
if (upstream->read->active && !upstream->read->ready) {
ngx_add_timer(upstream->read, u->conf->read_timeout);
} else if (upstream->read->timer_set) {
ngx_del_timer(upstream->read);
}
}
static ngx_int_t
ngx_http_upstream_non_buffered_filter_init(void *data)
{
return NGX_OK;
}
static ngx_int_t
ngx_http_upstream_non_buffered_filter(void *data, ssize_t bytes)
{
ngx_http_request_t *r = data;
ngx_buf_t *b;
ngx_chain_t *cl, **ll;
ngx_http_upstream_t *u;
u = r->upstream;
for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
ll = &cl->next;
}
cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
if (cl == NULL) {
return NGX_ERROR;
}
*ll = cl;
cl->buf->flush = 1;
cl->buf->memory = 1;
b = &u->buffer;
cl->buf->pos = b->last;
b->last += bytes;
cl->buf->last = b->last;
cl->buf->tag = u->output.tag;
if (u->length == NGX_MAX_SIZE_T_VALUE) {
return NGX_OK;
}
u->length -= bytes;
return NGX_OK;
}
static void
ngx_http_upstream_process_downstream(ngx_http_request_t *r)
{
ngx_event_t *wev;
ngx_connection_t *c;
ngx_event_pipe_t *p;
ngx_http_upstream_t *u;
c = r->connection;
u = r->upstream;
p = u->pipe;
wev = c->write;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http upstream process downstream");
c->log->action = "sending to client";
if (wev->timedout) {
if (wev->delayed) {
wev->timedout = 0;
wev->delayed = 0;
if (!wev->ready) {
ngx_add_timer(wev, p->send_timeout);
if (ngx_handle_write_event(wev, p->send_lowat) != NGX_OK) {
ngx_http_upstream_finalize_request(r, u, 0);
}
return;
}
if (ngx_event_pipe(p, wev->write) == NGX_ABORT) {
if (c->destroyed) {
return;
}
ngx_http_upstream_finalize_request(r, u, 0);
return;
}
} else {
p->downstream_error = 1;
c->timedout = 1;
ngx_connection_error(c, NGX_ETIMEDOUT, "client timed out");
}
} else {
if (wev->delayed) {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http downstream delayed");
if (ngx_handle_write_event(wev, p->send_lowat) != NGX_OK) {
ngx_http_upstream_finalize_request(r, u, 0);
}
return;
}
if (ngx_event_pipe(p, 1) == NGX_ABORT) {
if (c->destroyed) {
return;
}
ngx_http_upstream_finalize_request(r, u, 0);
return;
}
}
ngx_http_upstream_process_request(r);
}
static void
ngx_http_upstream_process_upstream(ngx_http_request_t *r,
ngx_http_upstream_t *u)
{
ngx_connection_t *c;
c = u->peer.connection;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http upstream process upstream");
c->log->action = "reading upstream";
if (c->read->timedout) {
u->pipe->upstream_error = 1;
ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
} else {
c = r->connection;
if (ngx_event_pipe(u->pipe, 0) == NGX_ABORT) {
if (c->destroyed) {
return;
}
ngx_http_upstream_finalize_request(r, u, 0);
return;
}
}
ngx_http_upstream_process_request(r);
}
static void
ngx_http_upstream_process_request(ngx_http_request_t *r)
{
ngx_uint_t del;
ngx_temp_file_t *tf;
ngx_event_pipe_t *p;
ngx_http_upstream_t *u;
u = r->upstream;
p = u->pipe;
if (u->peer.connection) {
if (u->store) {
del = p->upstream_error;
tf = u->pipe->temp_file;
if (p->upstream_eof || p->upstream_done) {
if (u->headers_in.status_n == NGX_HTTP_OK
&& (u->headers_in.content_length_n == -1
|| (u->headers_in.content_length_n == tf->offset)))
{
ngx_http_upstream_store(r, u);
} else {
del = 1;
}
}
if (del && tf->file.fd != NGX_INVALID_FILE) {
if (ngx_delete_file(tf->file.name.data) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
ngx_delete_file_n " \"%s\" failed",
u->pipe->temp_file->file.name.data);
}
}
}
#if (NGX_HTTP_CACHE)
if (u->cacheable) {
if (p->upstream_done) {
ngx_http_file_cache_update(r, u->pipe->temp_file);
} else if (p->upstream_eof) {
/* TODO: check length & update cache */
ngx_http_file_cache_update(r, u->pipe->temp_file);
} else if (p->upstream_error) {
ngx_http_file_cache_free(r, u->pipe->temp_file);
}
}
#endif
if (p->upstream_done || p->upstream_eof || p->upstream_error) {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http upstream exit: %p", p->out);
#if 0
ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock);
#endif
ngx_http_upstream_finalize_request(r, u, 0);
return;
}
}
if (p->downstream_error) {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http upstream downstream error");
if (!u->cacheable && !u->store && u->peer.connection) {
ngx_http_upstream_finalize_request(r, u, 0);
}
}
}
static void
ngx_http_upstream_store(ngx_http_request_t *r, ngx_http_upstream_t *u)
{
size_t root;
time_t lm;
ngx_str_t path;
ngx_temp_file_t *tf;
ngx_ext_rename_file_t ext;
tf = u->pipe->temp_file;
if (tf->file.fd == NGX_INVALID_FILE) {
/* create file for empty 200 response */
tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
if (tf == NULL) {
return;
}
tf->file.fd = NGX_INVALID_FILE;
tf->file.log = r->connection->log;
tf->path = u->conf->temp_path;
tf->pool = r->pool;
tf->persistent = 1;
if (ngx_create_temp_file(&tf->file, tf->path, tf->pool,
tf->persistent, tf->clean, tf->access)
!= NGX_OK)
{
return;
}
u->pipe->temp_file = tf;
}
ext.access = u->conf->store_access;
ext.path_access = u->conf->store_access;
ext.time = -1;
ext.create_path = 1;
ext.delete_file = 1;
ext.log = r->connection->log;
if (u->headers_in.last_modified) {
lm = ngx_http_parse_time(u->headers_in.last_modified->value.data,
u->headers_in.last_modified->value.len);
if (lm != NGX_ERROR) {
ext.time = lm;
ext.fd = tf->file.fd;
}
}
if (u->conf->store_lengths == NULL) {
ngx_http_map_uri_to_path(r, &path, &root, 0);
} else {
if (ngx_http_script_run(r, &path, u->conf->store_lengths->elts, 0,
u->conf->store_values->elts)
== NULL)
{
return;
}
}
path.len--;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"upstream stores \"%s\" to \"%s\"",
tf->file.name.data, path.data);
(void) ngx_ext_rename_file(&tf->file.name, &path, &ext);
}
static void
ngx_http_upstream_dummy_handler(ngx_http_request_t *r, ngx_http_upstream_t *u)
{
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http upstream dummy handler");
}
static void
ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u,
ngx_uint_t ft_type)
{
ngx_uint_t status, state;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http next upstream, %xi", ft_type);
#if 0
ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock);
#endif
if (ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_404) {
state = NGX_PEER_NEXT;
} else {
state = NGX_PEER_FAILED;
}
if (ft_type != NGX_HTTP_UPSTREAM_FT_NOLIVE) {
u->peer.free(&u->peer, u->peer.data, state);
}
if (ft_type == NGX_HTTP_UPSTREAM_FT_TIMEOUT) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ETIMEDOUT,
"upstream timed out");
}
if (u->peer.cached && ft_type == NGX_HTTP_UPSTREAM_FT_ERROR) {
status = 0;
} else {
switch(ft_type) {
case NGX_HTTP_UPSTREAM_FT_TIMEOUT:
status = NGX_HTTP_GATEWAY_TIME_OUT;
break;
case NGX_HTTP_UPSTREAM_FT_HTTP_500:
status = NGX_HTTP_INTERNAL_SERVER_ERROR;
break;
case NGX_HTTP_UPSTREAM_FT_HTTP_404:
status = NGX_HTTP_NOT_FOUND;
break;
/*
* NGX_HTTP_UPSTREAM_FT_BUSY_LOCK and NGX_HTTP_UPSTREAM_FT_MAX_WAITING
* never reach here
*/
default:
status = NGX_HTTP_BAD_GATEWAY;
}
}
if (r->connection->error) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_CLIENT_CLOSED_REQUEST);
return;
}
if (status) {
u->state->status = status;
if (u->peer.tries == 0 || !(u->conf->next_upstream & ft_type)) {
#if (NGX_HTTP_CACHE)
if (u->cache_status == NGX_HTTP_CACHE_EXPIRED
&& (u->conf->cache_use_stale & ft_type))
{
ngx_int_t rc;
rc = u->reinit_request(r);
if (rc == NGX_OK) {
u->cache_status = NGX_HTTP_CACHE_STALE;
rc = ngx_http_upstream_cache_send(r, u);
}
ngx_http_upstream_finalize_request(r, u, rc);
return;
}
#endif
ngx_http_upstream_finalize_request(r, u, status);
return;
}
}
if (u->peer.connection) {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"close http upstream connection: %d",
u->peer.connection->fd);
#if (NGX_HTTP_SSL)
if (u->peer.connection->ssl) {
u->peer.connection->ssl->no_wait_shutdown = 1;
u->peer.connection->ssl->no_send_shutdown = 1;
(void) ngx_ssl_shutdown(u->peer.connection);
}
#endif
ngx_close_connection(u->peer.connection);
}
#if 0
if (u->conf->busy_lock && !u->busy_locked) {
ngx_http_upstream_busy_lock(p);
return;
}
#endif
ngx_http_upstream_connect(r, u);
}
static void
ngx_http_upstream_cleanup(void *data)
{
ngx_http_request_t *r = data;
ngx_http_upstream_t *u;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"cleanup http upstream request: \"%V\"", &r->uri);
u = r->upstream;
if (u->resolved && u->resolved->ctx) {
ngx_resolve_name_done(u->resolved->ctx);
}
ngx_http_upstream_finalize_request(r, u, NGX_DONE);
}
static void
ngx_http_upstream_finalize_request(ngx_http_request_t *r,
ngx_http_upstream_t *u, ngx_int_t rc)
{
ngx_time_t *tp;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"finalize http upstream request: %i", rc);
if (u->cleanup) {
*u->cleanup = NULL;
u->cleanup = NULL;
}
if (u->state && u->state->response_sec) {
tp = ngx_timeofday();
u->state->response_sec = tp->sec - u->state->response_sec;
u->state->response_msec = tp->msec - u->state->response_msec;
if (u->pipe) {
u->state->response_length = u->pipe->read_length;
}
}
u->finalize_request(r, rc);
if (u->peer.free) {
u->peer.free(&u->peer, u->peer.data, 0);
}
if (u->peer.connection) {
#if (NGX_HTTP_SSL)
/* TODO: do not shutdown persistent connection */
if (u->peer.connection->ssl) {
/*
* We send the "close notify" shutdown alert to the upstream only
* and do not wait its "close notify" shutdown alert.
* It is acceptable according to the TLS standard.
*/
u->peer.connection->ssl->no_wait_shutdown = 1;
(void) ngx_ssl_shutdown(u->peer.connection);
}
#endif
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"close http upstream connection: %d",
u->peer.connection->fd);
ngx_close_connection(u->peer.connection);
}
u->peer.connection = NULL;
if (u->pipe && u->pipe->temp_file) {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http upstream temp fd: %d",
u->pipe->temp_file->file.fd);
}
#if (NGX_HTTP_CACHE)
if (u->cacheable && r->cache) {
time_t valid;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http upstream cache fd: %d",
r->cache->file.fd);
if (rc == NGX_HTTP_BAD_GATEWAY || rc == NGX_HTTP_GATEWAY_TIME_OUT) {
valid = ngx_http_file_cache_valid(u->conf->cache_valid, rc);
if (valid) {
r->cache->valid_sec = ngx_time() + valid;
r->cache->error = rc;
}
}
ngx_http_file_cache_free(r, u->pipe->temp_file);
}
#endif
if (u->header_sent
&& (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE))
{
rc = 0;
}
if (rc == NGX_DECLINED) {
return;
}
r->connection->log->action = "sending to client";
if (rc == 0) {
rc = ngx_http_send_special(r, NGX_HTTP_LAST);
}
ngx_http_finalize_request(r, rc);
}
static ngx_int_t
ngx_http_upstream_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset)
{
ngx_table_elt_t **ph;
ph = (ngx_table_elt_t **) ((char *) &r->upstream->headers_in + offset);
if (*ph == NULL) {
*ph = h;
}
return NGX_OK;
}
static ngx_int_t
ngx_http_upstream_ignore_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset)
{
return NGX_OK;
}
static ngx_int_t
ngx_http_upstream_process_cache_control(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset)
{
ngx_array_t *pa;
ngx_table_elt_t **ph;
ngx_http_upstream_t *u;
u = r->upstream;
pa = &u->headers_in.cache_control;
if (pa->elts == NULL) {
if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK)
{
return NGX_ERROR;
}
}
ph = ngx_array_push(pa);
if (ph == NULL) {
return NGX_ERROR;
}
*ph = h;
#if (NGX_HTTP_CACHE)
{
u_char *p, *last;
ngx_int_t n;
if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_CACHE_CONTROL) {
return NGX_OK;
}
if (r->cache == NULL) {
return NGX_OK;
}
if (r->cache->valid_sec != 0) {
return NGX_OK;
}
p = h->value.data;
last = p + h->value.len;
if (ngx_strlcasestrn(p, last, (u_char *) "no-cache", 8 - 1) != NULL
|| ngx_strlcasestrn(p, last, (u_char *) "no-store", 8 - 1) != NULL
|| ngx_strlcasestrn(p, last, (u_char *) "private", 7 - 1) != NULL)
{
u->cacheable = 0;
return NGX_OK;
}
p = ngx_strlcasestrn(p, last, (u_char *) "max-age=", 8 - 1);
if (p == NULL) {
return NGX_OK;
}
n = 0;
for (p += 8; p < last; p++) {
if (*p == ',' || *p == ';' || *p == ' ') {
break;
}
if (*p >= '0' && *p <= '9') {
n = n * 10 + *p - '0';
continue;
}
u->cacheable = 0;
return NGX_OK;
}
if (n == 0) {
u->cacheable = 0;
return NGX_OK;
}
r->cache->valid_sec = ngx_time() + n;
}
#endif
return NGX_OK;
}
static ngx_int_t
ngx_http_upstream_process_expires(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset)
{
ngx_http_upstream_t *u;
u = r->upstream;
u->headers_in.expires = h;
#if (NGX_HTTP_CACHE)
{
time_t expires;
if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_EXPIRES) {
return NGX_OK;
}
if (r->cache == NULL) {
return NGX_OK;
}
if (r->cache->valid_sec != 0) {
return NGX_OK;
}
expires = ngx_http_parse_time(h->value.data, h->value.len);
if (expires == NGX_ERROR || expires < ngx_time()) {
u->cacheable = 0;
return NGX_OK;
}
r->cache->valid_sec = expires;
}
#endif
return NGX_OK;
}
static ngx_int_t
ngx_http_upstream_process_accel_expires(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset)
{
ngx_http_upstream_t *u;
u = r->upstream;
u->headers_in.x_accel_expires = h;
#if (NGX_HTTP_CACHE)
{
u_char *p;
size_t len;
ngx_int_t n;
if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_EXPIRES) {
return NGX_OK;
}
if (r->cache == NULL) {
return NGX_OK;
}
len = h->value.len;
p = h->value.data;
if (p[0] != '@') {
n = ngx_atoi(p, len);
switch (n) {
case 0:
u->cacheable = 0;
case NGX_ERROR:
return NGX_OK;
default:
r->cache->valid_sec = ngx_time() + n;
return NGX_OK;
}
}
p++;
len--;
n = ngx_atoi(p, len);
if (n != NGX_ERROR) {
r->cache->valid_sec = n;
}
}
#endif
return NGX_OK;
}
static ngx_int_t
ngx_http_upstream_process_limit_rate(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset)
{
ngx_int_t n;
r->upstream->headers_in.x_accel_limit_rate = h;
n = ngx_atoi(h->value.data, h->value.len);
if (n != NGX_ERROR) {
r->limit_rate = (size_t) n;
}
return NGX_OK;
}
static ngx_int_t
ngx_http_upstream_process_buffering(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset)
{
u_char c0, c1, c2;
if (r->upstream->conf->change_buffering) {
if (h->value.len == 2) {
c0 = ngx_tolower(h->value.data[0]);
c1 = ngx_tolower(h->value.data[1]);
if (c0 == 'n' && c1 == 'o') {
r->upstream->buffering = 0;
}
} else if (h->value.len == 3) {
c0 = ngx_tolower(h->value.data[0]);
c1 = ngx_tolower(h->value.data[1]);
c2 = ngx_tolower(h->value.data[2]);
if (c0 == 'y' && c1 == 'e' && c2 == 's') {
r->upstream->buffering = 1;
}
}
}
return NGX_OK;
}
static ngx_int_t
ngx_http_upstream_process_charset(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset)
{
r->headers_out.override_charset = &h->value;
return NGX_OK;
}
static ngx_int_t
ngx_http_upstream_copy_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset)
{
ngx_table_elt_t *ho, **ph;
ho = ngx_list_push(&r->headers_out.headers);
if (ho == NULL) {
return NGX_ERROR;
}
*ho = *h;
if (offset) {
ph = (ngx_table_elt_t **) ((char *) &r->headers_out + offset);
*ph = ho;
}
return NGX_OK;
}
static ngx_int_t
ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset)
{
ngx_array_t *pa;
ngx_table_elt_t *ho, **ph;
pa = (ngx_array_t *) ((char *) &r->headers_out + offset);
if (pa->elts == NULL) {
if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK)
{
return NGX_ERROR;
}
}
ph = ngx_array_push(pa);
if (ph == NULL) {
return NGX_ERROR;
}
ho = ngx_list_push(&r->headers_out.headers);
if (ho == NULL) {
return NGX_ERROR;
}
*ho = *h;
*ph = ho;
return NGX_OK;
}
static ngx_int_t
ngx_http_upstream_copy_content_type(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset)
{
u_char *p, *last;
r->headers_out.content_type_len = h->value.len;
r->headers_out.content_type = h->value;
r->headers_out.content_type_lowcase = NULL;
for (p = h->value.data; *p; p++) {
if (*p != ';') {
continue;
}
last = p;
while (*++p == ' ') { /* void */ }
if (*p == '\0') {
return NGX_OK;
}
if (ngx_strncasecmp(p, (u_char *) "charset=", 8) != 0) {
continue;
}
p += 8;
r->headers_out.content_type_len = last - h->value.data;
if (*p == '"') {
p++;
}
last = h->value.data + h->value.len;
if (*(last - 1) == '"') {
last--;
}
r->headers_out.charset.len = last - p;
r->headers_out.charset.data = p;
return NGX_OK;
}
return NGX_OK;
}
static ngx_int_t
ngx_http_upstream_copy_content_length(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset)
{
ngx_table_elt_t *ho;
ho = ngx_list_push(&r->headers_out.headers);
if (ho == NULL) {
return NGX_ERROR;
}
*ho = *h;
r->headers_out.content_length = ho;
r->headers_out.content_length_n = ngx_atoof(h->value.data, h->value.len);
return NGX_OK;
}
static ngx_int_t
ngx_http_upstream_copy_last_modified(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset)
{
ngx_table_elt_t *ho;
ho = ngx_list_push(&r->headers_out.headers);
if (ho == NULL) {
return NGX_ERROR;
}
*ho = *h;
r->headers_out.last_modified = ho;
#if (NGX_HTTP_CACHE)
if (r->upstream->cacheable) {
r->headers_out.last_modified_time = ngx_http_parse_time(h->value.data,
h->value.len);
}
#endif
return NGX_OK;
}
static ngx_int_t
ngx_http_upstream_rewrite_location(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset)
{
ngx_int_t rc;
ngx_table_elt_t *ho;
ho = ngx_list_push(&r->headers_out.headers);
if (ho == NULL) {
return NGX_ERROR;
}
*ho = *h;
if (r->upstream->rewrite_redirect) {
rc = r->upstream->rewrite_redirect(r, ho, 0);
if (rc == NGX_DECLINED) {
return NGX_OK;
}
if (rc == NGX_OK) {
r->headers_out.location = ho;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"rewritten location: \"%V\"", &ho->value);
}
return rc;
}
if (ho->value.data[0] != '/') {
r->headers_out.location = ho;
}
/*
* we do not set r->headers_out.location here to avoid the handling
* the local redirects without a host name by ngx_http_header_filter()
*/
return NGX_OK;
}
static ngx_int_t
ngx_http_upstream_rewrite_refresh(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset)
{
u_char *p;
ngx_int_t rc;
ngx_table_elt_t *ho;
ho = ngx_list_push(&r->headers_out.headers);
if (ho == NULL) {
return NGX_ERROR;
}
*ho = *h;
if (r->upstream->rewrite_redirect) {
p = ngx_strcasestrn(ho->value.data, "url=", 4 - 1);
if (p) {
rc = r->upstream->rewrite_redirect(r, ho, p + 4 - ho->value.data);
} else {
return NGX_OK;
}
if (rc == NGX_DECLINED) {
return NGX_OK;
}
if (rc == NGX_OK) {
r->headers_out.refresh = ho;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"rewritten refresh: \"%V\"", &ho->value);
}
return rc;
}
r->headers_out.refresh = ho;
return NGX_OK;
}
static ngx_int_t
ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset)
{
ngx_table_elt_t *ho;
#if (NGX_HTTP_CACHE)
if (r->cached) {
r->allow_ranges = 1;
return NGX_OK;
}
#endif
ho = ngx_list_push(&r->headers_out.headers);
if (ho == NULL) {
return NGX_ERROR;
}
*ho = *h;
r->headers_out.accept_ranges = ho;
return NGX_OK;
}
#if (NGX_HTTP_GZIP)
static ngx_int_t
ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset)
{
ngx_table_elt_t *ho;
ho = ngx_list_push(&r->headers_out.headers);
if (ho == NULL) {
return NGX_ERROR;
}
*ho = *h;
r->headers_out.content_encoding = ho;
return NGX_OK;
}
#endif
static ngx_int_t
ngx_http_upstream_add_variables(ngx_conf_t *cf)
{
ngx_http_variable_t *var, *v;
for (v = ngx_http_upstream_vars; v->name.len; v++) {
var = ngx_http_add_variable(cf, &v->name, v->flags);
if (var == NULL) {
return NGX_ERROR;
}
var->get_handler = v->get_handler;
var->data = v->data;
}
return NGX_OK;
}
static ngx_int_t
ngx_http_upstream_addr_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
u_char *p;
size_t len;
ngx_uint_t i;
ngx_http_upstream_state_t *state;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
if (r->upstream_states == NULL || r->upstream_states->nelts == 0) {
v->not_found = 1;
return NGX_OK;
}
len = 0;
state = r->upstream_states->elts;
for (i = 0; i < r->upstream_states->nelts; i++) {
if (state[i].peer) {
len += state[i].peer->len + 2;
} else {
len += 3;
}
}
p = ngx_pnalloc(r->pool, len);
if (p == NULL) {
return NGX_ERROR;
}
v->data = p;
i = 0;
for ( ;; ) {
if (state[i].peer) {
p = ngx_cpymem(p, state[i].peer->data, state[i].peer->len);
}
if (++i == r->upstream_states->nelts) {
break;
}
if (state[i].peer) {
*p++ = ',';
*p++ = ' ';
} else {
*p++ = ' ';
*p++ = ':';
*p++ = ' ';
if (++i == r->upstream_states->nelts) {
break;
}
continue;
}
}
v->len = p - v->data;
return NGX_OK;
}
static ngx_int_t
ngx_http_upstream_status_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
u_char *p;
size_t len;
ngx_uint_t i;
ngx_http_upstream_state_t *state;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
if (r->upstream_states == NULL || r->upstream_states->nelts == 0) {
v->not_found = 1;
return NGX_OK;
}
len = r->upstream_states->nelts * (3 + 2);
p = ngx_pnalloc(r->pool, len);
if (p == NULL) {
return NGX_ERROR;
}
v->data = p;
i = 0;
state = r->upstream_states->elts;
for ( ;; ) {
if (state[i].status) {
p = ngx_sprintf(p, "%ui", state[i].status);
} else {
*p++ = '-';
}
if (++i == r->upstream_states->nelts) {
break;
}
if (state[i].peer) {
*p++ = ',';
*p++ = ' ';
} else {
*p++ = ' ';
*p++ = ':';
*p++ = ' ';
if (++i == r->upstream_states->nelts) {
break;
}
continue;
}
}
v->len = p - v->data;
return NGX_OK;
}
static ngx_int_t
ngx_http_upstream_response_time_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
u_char *p;
size_t len;
ngx_uint_t i;
ngx_msec_int_t ms;
ngx_http_upstream_state_t *state;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
if (r->upstream_states == NULL || r->upstream_states->nelts == 0) {
v->not_found = 1;
return NGX_OK;
}
len = r->upstream_states->nelts * (NGX_TIME_T_LEN + 4 + 2);
p = ngx_pnalloc(r->pool, len);
if (p == NULL) {
return NGX_ERROR;
}
v->data = p;
i = 0;
state = r->upstream_states->elts;
for ( ;; ) {
if (state[i].status) {
ms = (ngx_msec_int_t)
(state[i].response_sec * 1000 + state[i].response_msec);
ms = (ms >= 0) ? ms : 0;
p = ngx_sprintf(p, "%d.%03d", ms / 1000, ms % 1000);
} else {
*p++ = '-';
}
if (++i == r->upstream_states->nelts) {
break;
}
if (state[i].peer) {
*p++ = ',';
*p++ = ' ';
} else {
*p++ = ' ';
*p++ = ':';
*p++ = ' ';
if (++i == r->upstream_states->nelts) {
break;
}
continue;
}
}
v->len = p - v->data;
return NGX_OK;
}
static ngx_int_t
ngx_http_upstream_response_length_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
u_char *p;
size_t len;
ngx_uint_t i;
ngx_http_upstream_state_t *state;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
if (r->upstream_states == NULL || r->upstream_states->nelts == 0) {
v->not_found = 1;
return NGX_OK;
}
len = r->upstream_states->nelts * (NGX_OFF_T_LEN + 2);
p = ngx_pnalloc(r->pool, len);
if (p == NULL) {
return NGX_ERROR;
}
v->data = p;
i = 0;
state = r->upstream_states->elts;
for ( ;; ) {
p = ngx_sprintf(p, "%O", state[i].response_length);
if (++i == r->upstream_states->nelts) {
break;
}
if (state[i].peer) {
*p++ = ',';
*p++ = ' ';
} else {
*p++ = ' ';
*p++ = ':';
*p++ = ' ';
if (++i == r->upstream_states->nelts) {
break;
}
continue;
}
}
v->len = p - v->data;
return NGX_OK;
}
ngx_int_t
ngx_http_upstream_header_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
if (r->upstream == NULL) {
v->not_found = 1;
return NGX_OK;
}
return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
&r->upstream->headers_in.headers.part,
sizeof("upstream_http_") - 1);
}
#if (NGX_HTTP_CACHE)
ngx_int_t
ngx_http_upstream_cache_status(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
ngx_uint_t n;
if (r->upstream == NULL || r->upstream->cache_status == 0) {
v->not_found = 1;
return NGX_OK;
}
n = r->upstream->cache_status - 1;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->len = ngx_http_cache_status[n].len;
v->data = ngx_http_cache_status[n].data;
return NGX_OK;
}
#endif
static char *
ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
{
char *rv;
void *mconf;
ngx_str_t *value;
ngx_url_t u;
ngx_uint_t m;
ngx_conf_t pcf;
ngx_http_module_t *module;
ngx_http_conf_ctx_t *ctx, *http_ctx;
ngx_http_upstream_srv_conf_t *uscf;
ngx_memzero(&u, sizeof(ngx_url_t));
value = cf->args->elts;
u.host = value[1];
u.no_resolve = 1;
uscf = ngx_http_upstream_add(cf, &u, NGX_HTTP_UPSTREAM_CREATE
|NGX_HTTP_UPSTREAM_WEIGHT
|NGX_HTTP_UPSTREAM_MAX_FAILS
|NGX_HTTP_UPSTREAM_FAIL_TIMEOUT
|NGX_HTTP_UPSTREAM_DOWN
|NGX_HTTP_UPSTREAM_BACKUP);
if (uscf == NULL) {
return NGX_CONF_ERROR;
}
ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
if (ctx == NULL) {
return NGX_CONF_ERROR;
}
http_ctx = cf->ctx;
ctx->main_conf = http_ctx->main_conf;
/* the upstream{}'s srv_conf */
ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
if (ctx->srv_conf == NULL) {
return NGX_CONF_ERROR;
}
ctx->srv_conf[ngx_http_upstream_module.ctx_index] = uscf;
uscf->srv_conf = ctx->srv_conf;
/* the upstream{}'s loc_conf */
ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
if (ctx->loc_conf == NULL) {
return NGX_CONF_ERROR;
}
for (m = 0; ngx_modules[m]; m++) {
if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
continue;
}
module = ngx_modules[m]->ctx;
if (module->create_srv_conf) {
mconf = module->create_srv_conf(cf);
if (mconf == NULL) {
return NGX_CONF_ERROR;
}
ctx->srv_conf[ngx_modules[m]->ctx_index] = mconf;
}
if (module->create_loc_conf) {
mconf = module->create_loc_conf(cf);
if (mconf == NULL) {
return NGX_CONF_ERROR;
}
ctx->loc_conf[ngx_modules[m]->ctx_index] = mconf;
}
}
/* parse inside upstream{} */
pcf = *cf;
cf->ctx = ctx;
cf->cmd_type = NGX_HTTP_UPS_CONF;
rv = ngx_conf_parse(cf, NULL);
*cf = pcf;
if (rv != NGX_CONF_OK) {
return rv;
}
if (uscf->servers == NULL) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"no servers are inside upstream");
return NGX_CONF_ERROR;
}
return rv;
}
static char *
ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_upstream_srv_conf_t *uscf = conf;
time_t fail_timeout;
ngx_str_t *value, s;
ngx_url_t u;
ngx_int_t weight, max_fails;
ngx_uint_t i;
ngx_http_upstream_server_t *us;
if (uscf->servers == NULL) {
uscf->servers = ngx_array_create(cf->pool, 4,
sizeof(ngx_http_upstream_server_t));
if (uscf->servers == NULL) {
return NGX_CONF_ERROR;
}
}
us = ngx_array_push(uscf->servers);
if (us == NULL) {
return NGX_CONF_ERROR;
}
ngx_memzero(us, sizeof(ngx_http_upstream_server_t));
value = cf->args->elts;
ngx_memzero(&u, sizeof(ngx_url_t));
u.url = value[1];
u.default_port = 80;
if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
if (u.err) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"%s in upstream \"%V\"", u.err, &u.url);
}
return NGX_CONF_ERROR;
}
weight = 1;
max_fails = 1;
fail_timeout = 10;
for (i = 2; i < cf->args->nelts; i++) {
if (ngx_strncmp(value[i].data, "weight=", 7) == 0) {
if (!(uscf->flags & NGX_HTTP_UPSTREAM_WEIGHT)) {
goto invalid;
}
weight = ngx_atoi(&value[i].data[7], value[i].len - 7);
if (weight == NGX_ERROR || weight == 0) {
goto invalid;
}
continue;
}
if (ngx_strncmp(value[i].data, "max_fails=", 10) == 0) {
if (!(uscf->flags & NGX_HTTP_UPSTREAM_MAX_FAILS)) {
goto invalid;
}
max_fails = ngx_atoi(&value[i].data[10], value[i].len - 10);
if (max_fails == NGX_ERROR) {
goto invalid;
}
continue;
}
if (ngx_strncmp(value[i].data, "fail_timeout=", 13) == 0) {
if (!(uscf->flags & NGX_HTTP_UPSTREAM_FAIL_TIMEOUT)) {
goto invalid;
}
s.len = value[i].len - 13;
s.data = &value[i].data[13];
fail_timeout = ngx_parse_time(&s, 1);
if (fail_timeout == NGX_ERROR) {
goto invalid;
}
continue;
}
if (ngx_strncmp(value[i].data, "backup", 6) == 0) {
if (!(uscf->flags & NGX_HTTP_UPSTREAM_BACKUP)) {
goto invalid;
}
us->backup = 1;
continue;
}
if (ngx_strncmp(value[i].data, "down", 4) == 0) {
if (!(uscf->flags & NGX_HTTP_UPSTREAM_DOWN)) {
goto invalid;
}
us->down = 1;
continue;
}
goto invalid;
}
us->addrs = u.addrs;
us->naddrs = u.naddrs;
us->weight = weight;
us->max_fails = max_fails;
us->fail_timeout = fail_timeout;
return NGX_CONF_OK;
invalid:
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid parameter \"%V\"", &value[i]);
return NGX_CONF_ERROR;
}
ngx_http_upstream_srv_conf_t *
ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags)
{
ngx_uint_t i;
ngx_http_upstream_server_t *us;
ngx_http_upstream_srv_conf_t *uscf, **uscfp;
ngx_http_upstream_main_conf_t *umcf;
if (!(flags & NGX_HTTP_UPSTREAM_CREATE)) {
if (ngx_parse_url(cf->pool, u) != NGX_OK) {
if (u->err) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"%s in upstream \"%V\"", u->err, &u->url);
}
return NULL;
}
}
umcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_upstream_module);
uscfp = umcf->upstreams.elts;
for (i = 0; i < umcf->upstreams.nelts; i++) {
if (uscfp[i]->host.len != u->host.len
|| ngx_strncasecmp(uscfp[i]->host.data, u->host.data, u->host.len)
!= 0)
{
continue;
}
if ((flags & NGX_HTTP_UPSTREAM_CREATE)
&& (uscfp[i]->flags & NGX_HTTP_UPSTREAM_CREATE))
{
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"duplicate upstream \"%V\"", &u->host);
return NULL;
}
if ((uscfp[i]->flags & NGX_HTTP_UPSTREAM_CREATE) && u->port) {
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
"upstream \"%V\" may not have port %d",
&u->host, u->port);
return NULL;
}
if ((flags & NGX_HTTP_UPSTREAM_CREATE) && uscfp[i]->port) {
ngx_log_error(NGX_LOG_WARN, cf->log, 0,
"upstream \"%V\" may not have port %d in %s:%ui",
&u->host, uscfp[i]->port,
uscfp[i]->file_name, uscfp[i]->line);
return NULL;
}
if (uscfp[i]->port != u->port) {
continue;
}
if (uscfp[i]->default_port && u->default_port
&& uscfp[i]->default_port != u->default_port)
{
continue;
}
return uscfp[i];
}
uscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_srv_conf_t));
if (uscf == NULL) {
return NULL;
}
uscf->flags = flags;
uscf->host = u->host;
uscf->file_name = cf->conf_file->file.name.data;
uscf->line = cf->conf_file->line;
uscf->port = u->port;
uscf->default_port = u->default_port;
if (u->naddrs == 1) {
uscf->servers = ngx_array_create(cf->pool, 1,
sizeof(ngx_http_upstream_server_t));
if (uscf->servers == NULL) {
return NGX_CONF_ERROR;
}
us = ngx_array_push(uscf->servers);
if (us == NULL) {
return NGX_CONF_ERROR;
}
ngx_memzero(us, sizeof(ngx_http_upstream_server_t));
us->addrs = u->addrs;
us->naddrs = u->naddrs;
}
uscfp = ngx_array_push(&umcf->upstreams);
if (uscfp == NULL) {
return NULL;
}
*uscfp = uscf;
return uscf;
}
ngx_int_t
ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf,
ngx_http_upstream_conf_t *conf, ngx_http_upstream_conf_t *prev,
ngx_str_t *default_hide_headers, ngx_hash_init_t *hash)
{
ngx_str_t *h;
ngx_uint_t i, j;
ngx_array_t hide_headers;
ngx_hash_key_t *hk;
if (conf->hide_headers == NGX_CONF_UNSET_PTR
&& conf->pass_headers == NGX_CONF_UNSET_PTR)
{
conf->hide_headers_hash = prev->hide_headers_hash;
if (conf->hide_headers_hash.buckets
#if (NGX_HTTP_CACHE)
&& ((conf->cache == NULL) == (prev->cache == NULL))
#endif
)
{
return NGX_OK;
}
conf->hide_headers = prev->hide_headers;
conf->pass_headers = prev->pass_headers;
} else {
if (conf->hide_headers == NGX_CONF_UNSET_PTR) {
conf->hide_headers = prev->hide_headers;
}
if (conf->pass_headers == NGX_CONF_UNSET_PTR) {
conf->pass_headers = prev->pass_headers;
}
}
if (ngx_array_init(&hide_headers, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
!= NGX_OK)
{
return NGX_ERROR;
}
for (h = default_hide_headers; h->len; h++) {
hk = ngx_array_push(&hide_headers);
if (hk == NULL) {
return NGX_ERROR;
}
hk->key = *h;
hk->key_hash = ngx_hash_key_lc(h->data, h->len);
hk->value = (void *) 1;
}
if (conf->hide_headers != NGX_CONF_UNSET_PTR) {
h = conf->hide_headers->elts;
for (i = 0; i < conf->hide_headers->nelts; i++) {
hk = hide_headers.elts;
for (j = 0; j < hide_headers.nelts; j++) {
if (ngx_strcasecmp(h[i].data, hk[j].key.data) == 0) {
goto exist;
}
}
hk = ngx_array_push(&hide_headers);
if (hk == NULL) {
return NGX_ERROR;
}
hk->key = h[i];
hk->key_hash = ngx_hash_key_lc(h[i].data, h[i].len);
hk->value = (void *) 1;
exist:
continue;
}
}
if (conf->pass_headers != NGX_CONF_UNSET_PTR) {
h = conf->pass_headers->elts;
hk = hide_headers.elts;
for (i = 0; i < conf->pass_headers->nelts; i++) {
for (j = 0; j < hide_headers.nelts; j++) {
if (hk[j].key.data == NULL) {
continue;
}
if (ngx_strcasecmp(h[i].data, hk[j].key.data) == 0) {
hk[j].key.data = NULL;
break;
}
}
}
}
hash->hash = &conf->hide_headers_hash;
hash->key = ngx_hash_key_lc;
hash->pool = cf->pool;
hash->temp_pool = NULL;
return ngx_hash_init(hash, hide_headers.elts, hide_headers.nelts);
}
static void *
ngx_http_upstream_create_main_conf(ngx_conf_t *cf)
{
ngx_http_upstream_main_conf_t *umcf;
umcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_main_conf_t));
if (umcf == NULL) {
return NULL;
}
if (ngx_array_init(&umcf->upstreams, cf->pool, 4,
sizeof(ngx_http_upstream_srv_conf_t *))
!= NGX_OK)
{
return NULL;
}
return umcf;
}
static char *
ngx_http_upstream_init_main_conf(ngx_conf_t *cf, void *conf)
{
ngx_http_upstream_main_conf_t *umcf = conf;
ngx_uint_t i;
ngx_array_t headers_in;
ngx_hash_key_t *hk;
ngx_hash_init_t hash;
ngx_http_upstream_init_pt init;
ngx_http_upstream_header_t *header;
ngx_http_upstream_srv_conf_t **uscfp;
uscfp = umcf->upstreams.elts;
for (i = 0; i < umcf->upstreams.nelts; i++) {
init = uscfp[i]->peer.init_upstream ? uscfp[i]->peer.init_upstream:
ngx_http_upstream_init_round_robin;
if (init(cf, uscfp[i]) != NGX_OK) {
return NGX_CONF_ERROR;
}
}
/* upstream_headers_in_hash */
if (ngx_array_init(&headers_in, cf->temp_pool, 32, sizeof(ngx_hash_key_t))
!= NGX_OK)
{
return NGX_CONF_ERROR;
}
for (header = ngx_http_upstream_headers_in; header->name.len; header++) {
hk = ngx_array_push(&headers_in);
if (hk == NULL) {
return NGX_CONF_ERROR;
}
hk->key = header->name;
hk->key_hash = ngx_hash_key_lc(header->name.data, header->name.len);
hk->value = header;
}
hash.hash = &umcf->headers_in_hash;
hash.key = ngx_hash_key_lc;
hash.max_size = 512;
hash.bucket_size = ngx_align(64, ngx_cacheline_size);
hash.name = "upstream_headers_in_hash";
hash.pool = cf->pool;
hash.temp_pool = NULL;
if (ngx_hash_init(&hash, headers_in.elts, headers_in.nelts) != NGX_OK) {
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
nginx-0.7.68/src/http/modules/ 000755 001750 001750 00000000000 11501744766 015260 5 ustar 00is is 000000 000000 nginx-0.7.68/src/http/ngx_http.c 000644 001750 001750 00000142040 11501741453 015576 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#include
#include
#include
static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static ngx_int_t ngx_http_init_phases(ngx_conf_t *cf,
ngx_http_core_main_conf_t *cmcf);
static ngx_int_t ngx_http_init_headers_in_hash(ngx_conf_t *cf,
ngx_http_core_main_conf_t *cmcf);
static ngx_int_t ngx_http_init_phase_handlers(ngx_conf_t *cf,
ngx_http_core_main_conf_t *cmcf);
static ngx_int_t ngx_http_init_server_lists(ngx_conf_t *cf,
ngx_array_t *servers, ngx_array_t *ports);
static ngx_int_t ngx_http_add_ports(ngx_conf_t *cf,
ngx_http_core_srv_conf_t *cscf, ngx_array_t *ports,
ngx_http_listen_t *listen);
static ngx_int_t ngx_http_add_addresses(ngx_conf_t *cf,
ngx_http_core_srv_conf_t *cscf, ngx_http_conf_port_t *port,
ngx_http_listen_t *listen);
static ngx_int_t ngx_http_add_address(ngx_conf_t *cf,
ngx_http_core_srv_conf_t *cscf, ngx_http_conf_port_t *port,
ngx_http_listen_t *listen);
static ngx_int_t ngx_http_add_names(ngx_conf_t *cf,
ngx_http_core_srv_conf_t *cscf, ngx_http_conf_addr_t *addr);
static char *ngx_http_merge_locations(ngx_conf_t *cf,
ngx_queue_t *locations, void **loc_conf, ngx_http_module_t *module,
ngx_uint_t ctx_index);
static ngx_int_t ngx_http_init_locations(ngx_conf_t *cf,
ngx_http_core_srv_conf_t *cscf, ngx_http_core_loc_conf_t *pclcf);
static ngx_int_t ngx_http_init_static_location_trees(ngx_conf_t *cf,
ngx_http_core_loc_conf_t *pclcf);
static ngx_int_t ngx_http_cmp_locations(const ngx_queue_t *one,
const ngx_queue_t *two);
static ngx_int_t ngx_http_join_exact_locations(ngx_conf_t *cf,
ngx_queue_t *locations);
static void ngx_http_create_locations_list(ngx_queue_t *locations,
ngx_queue_t *q);
static ngx_http_location_tree_node_t *
ngx_http_create_locations_tree(ngx_conf_t *cf, ngx_queue_t *locations,
size_t prefix);
static ngx_int_t ngx_http_optimize_servers(ngx_conf_t *cf,
ngx_http_core_main_conf_t *cmcf, ngx_array_t *ports);
static ngx_int_t ngx_http_server_names(ngx_conf_t *cf,
ngx_http_core_main_conf_t *cmcf, ngx_http_conf_addr_t *addr);
static ngx_int_t ngx_http_cmp_conf_addrs(const void *one, const void *two);
static int ngx_libc_cdecl ngx_http_cmp_dns_wildcards(const void *one,
const void *two);
static ngx_int_t ngx_http_init_listening(ngx_conf_t *cf,
ngx_http_conf_port_t *port);
static ngx_listening_t *ngx_http_add_listening(ngx_conf_t *cf,
ngx_http_conf_addr_t *addr);
static ngx_int_t ngx_http_add_addrs(ngx_conf_t *cf, ngx_http_port_t *hport,
ngx_http_conf_addr_t *addr);
#if (NGX_HAVE_INET6)
static ngx_int_t ngx_http_add_addrs6(ngx_conf_t *cf, ngx_http_port_t *hport,
ngx_http_conf_addr_t *addr);
#endif
ngx_uint_t ngx_http_max_module;
ngx_int_t (*ngx_http_top_header_filter) (ngx_http_request_t *r);
ngx_int_t (*ngx_http_top_body_filter) (ngx_http_request_t *r, ngx_chain_t *ch);
ngx_str_t ngx_http_html_default_types[] = {
ngx_string("text/html"),
ngx_null_string
};
static ngx_command_t ngx_http_commands[] = {
{ ngx_string("http"),
NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
ngx_http_block,
0,
0,
NULL },
ngx_null_command
};
static ngx_core_module_t ngx_http_module_ctx = {
ngx_string("http"),
NULL,
NULL
};
ngx_module_t ngx_http_module = {
NGX_MODULE_V1,
&ngx_http_module_ctx, /* module context */
ngx_http_commands, /* module directives */
NGX_CORE_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static char *
ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
char *rv;
ngx_uint_t mi, m, s;
ngx_conf_t pcf;
ngx_array_t ports;
ngx_http_module_t *module;
ngx_http_conf_ctx_t *ctx;
ngx_http_core_loc_conf_t *clcf;
ngx_http_core_srv_conf_t **cscfp;
ngx_http_core_main_conf_t *cmcf;
/* the main http context */
ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
if (ctx == NULL) {
return NGX_CONF_ERROR;
}
*(ngx_http_conf_ctx_t **) conf = ctx;
/* count the number of the http modules and set up their indices */
ngx_http_max_module = 0;
for (m = 0; ngx_modules[m]; m++) {
if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
continue;
}
ngx_modules[m]->ctx_index = ngx_http_max_module++;
}
/* the http main_conf context, it is the same in the all http contexts */
ctx->main_conf = ngx_pcalloc(cf->pool,
sizeof(void *) * ngx_http_max_module);
if (ctx->main_conf == NULL) {
return NGX_CONF_ERROR;
}
/*
* the http null srv_conf context, it is used to merge
* the server{}s' srv_conf's
*/
ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
if (ctx->srv_conf == NULL) {
return NGX_CONF_ERROR;
}
/*
* the http null loc_conf context, it is used to merge
* the server{}s' loc_conf's
*/
ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
if (ctx->loc_conf == NULL) {
return NGX_CONF_ERROR;
}
/*
* create the main_conf's, the null srv_conf's, and the null loc_conf's
* of the all http modules
*/
for (m = 0; ngx_modules[m]; m++) {
if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
continue;
}
module = ngx_modules[m]->ctx;
mi = ngx_modules[m]->ctx_index;
if (module->create_main_conf) {
ctx->main_conf[mi] = module->create_main_conf(cf);
if (ctx->main_conf[mi] == NULL) {
return NGX_CONF_ERROR;
}
}
if (module->create_srv_conf) {
ctx->srv_conf[mi] = module->create_srv_conf(cf);
if (ctx->srv_conf[mi] == NULL) {
return NGX_CONF_ERROR;
}
}
if (module->create_loc_conf) {
ctx->loc_conf[mi] = module->create_loc_conf(cf);
if (ctx->loc_conf[mi] == NULL) {
return NGX_CONF_ERROR;
}
}
}
pcf = *cf;
cf->ctx = ctx;
for (m = 0; ngx_modules[m]; m++) {
if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
continue;
}
module = ngx_modules[m]->ctx;
if (module->preconfiguration) {
if (module->preconfiguration(cf) != NGX_OK) {
return NGX_CONF_ERROR;
}
}
}
/* parse inside the http{} block */
cf->module_type = NGX_HTTP_MODULE;
cf->cmd_type = NGX_HTTP_MAIN_CONF;
rv = ngx_conf_parse(cf, NULL);
if (rv != NGX_CONF_OK) {
goto failed;
}
/*
* init http{} main_conf's, merge the server{}s' srv_conf's
* and its location{}s' loc_conf's
*/
cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
cscfp = cmcf->servers.elts;
for (m = 0; ngx_modules[m]; m++) {
if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
continue;
}
module = ngx_modules[m]->ctx;
mi = ngx_modules[m]->ctx_index;
/* init http{} main_conf's */
if (module->init_main_conf) {
rv = module->init_main_conf(cf, ctx->main_conf[mi]);
if (rv != NGX_CONF_OK) {
goto failed;
}
}
for (s = 0; s < cmcf->servers.nelts; s++) {
/* merge the server{}s' srv_conf's */
if (module->merge_srv_conf) {
rv = module->merge_srv_conf(cf, ctx->srv_conf[mi],
cscfp[s]->ctx->srv_conf[mi]);
if (rv != NGX_CONF_OK) {
goto failed;
}
}
if (module->merge_loc_conf) {
/* merge the server{}'s loc_conf */
rv = module->merge_loc_conf(cf, ctx->loc_conf[mi],
cscfp[s]->ctx->loc_conf[mi]);
if (rv != NGX_CONF_OK) {
goto failed;
}
/* merge the locations{}' loc_conf's */
clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
rv = ngx_http_merge_locations(cf, clcf->locations,
cscfp[s]->ctx->loc_conf,
module, mi);
if (rv != NGX_CONF_OK) {
goto failed;
}
}
}
}
/* create location trees */
for (s = 0; s < cmcf->servers.nelts; s++) {
clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
if (ngx_http_init_locations(cf, cscfp[s], clcf) != NGX_OK) {
return NGX_CONF_ERROR;
}
if (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) {
return NGX_CONF_ERROR;
}
}
if (ngx_http_init_phases(cf, cmcf) != NGX_OK) {
return NGX_CONF_ERROR;
}
if (ngx_http_init_headers_in_hash(cf, cmcf) != NGX_OK) {
return NGX_CONF_ERROR;
}
for (m = 0; ngx_modules[m]; m++) {
if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
continue;
}
module = ngx_modules[m]->ctx;
if (module->postconfiguration) {
if (module->postconfiguration(cf) != NGX_OK) {
return NGX_CONF_ERROR;
}
}
}
if (ngx_http_variables_init_vars(cf) != NGX_OK) {
return NGX_CONF_ERROR;
}
/*
* http{}'s cf->ctx was needed while the configuration merging
* and in postconfiguration process
*/
*cf = pcf;
if (ngx_http_init_phase_handlers(cf, cmcf) != NGX_OK) {
return NGX_CONF_ERROR;
}
/*
* create the lists of ports, addresses and server names
* to find quickly the server core module configuration at run-time
*/
if (ngx_http_init_server_lists(cf, &cmcf->servers, &ports) != NGX_OK) {
return NGX_CONF_ERROR;
}
/* optimize the lists of ports, addresses and server names */
if (ngx_http_optimize_servers(cf, cmcf, &ports) != NGX_OK) {
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
failed:
*cf = pcf;
return rv;
}
static ngx_int_t
ngx_http_init_phases(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf)
{
if (ngx_array_init(&cmcf->phases[NGX_HTTP_POST_READ_PHASE].handlers,
cf->pool, 1, sizeof(ngx_http_handler_pt))
!= NGX_OK)
{
return NGX_ERROR;
}
if (ngx_array_init(&cmcf->phases[NGX_HTTP_SERVER_REWRITE_PHASE].handlers,
cf->pool, 1, sizeof(ngx_http_handler_pt))
!= NGX_OK)
{
return NGX_ERROR;
}
if (ngx_array_init(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers,
cf->pool, 1, sizeof(ngx_http_handler_pt))
!= NGX_OK)
{
return NGX_ERROR;
}
if (ngx_array_init(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers,
cf->pool, 1, sizeof(ngx_http_handler_pt))
!= NGX_OK)
{
return NGX_ERROR;
}
if (ngx_array_init(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers,
cf->pool, 2, sizeof(ngx_http_handler_pt))
!= NGX_OK)
{
return NGX_ERROR;
}
if (ngx_array_init(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers,
cf->pool, 4, sizeof(ngx_http_handler_pt))
!= NGX_OK)
{
return NGX_ERROR;
}
if (ngx_array_init(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers,
cf->pool, 1, sizeof(ngx_http_handler_pt))
!= NGX_OK)
{
return NGX_ERROR;
}
return NGX_OK;
}
static ngx_int_t
ngx_http_init_headers_in_hash(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf)
{
ngx_array_t headers_in;
ngx_hash_key_t *hk;
ngx_hash_init_t hash;
ngx_http_header_t *header;
if (ngx_array_init(&headers_in, cf->temp_pool, 32, sizeof(ngx_hash_key_t))
!= NGX_OK)
{
return NGX_ERROR;
}
for (header = ngx_http_headers_in; header->name.len; header++) {
hk = ngx_array_push(&headers_in);
if (hk == NULL) {
return NGX_ERROR;
}
hk->key = header->name;
hk->key_hash = ngx_hash_key_lc(header->name.data, header->name.len);
hk->value = header;
}
hash.hash = &cmcf->headers_in_hash;
hash.key = ngx_hash_key_lc;
hash.max_size = 512;
hash.bucket_size = ngx_align(64, ngx_cacheline_size);
hash.name = "headers_in_hash";
hash.pool = cf->pool;
hash.temp_pool = NULL;
if (ngx_hash_init(&hash, headers_in.elts, headers_in.nelts) != NGX_OK) {
return NGX_ERROR;
}
return NGX_OK;
}
static ngx_int_t
ngx_http_init_phase_handlers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf)
{
ngx_int_t j;
ngx_uint_t i, n;
ngx_uint_t find_config_index, use_rewrite, use_access;
ngx_http_handler_pt *h;
ngx_http_phase_handler_t *ph;
ngx_http_phase_handler_pt checker;
cmcf->phase_engine.server_rewrite_index = (ngx_uint_t) -1;
cmcf->phase_engine.location_rewrite_index = (ngx_uint_t) -1;
find_config_index = 0;
use_rewrite = cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers.nelts ? 1 : 0;
use_access = cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers.nelts ? 1 : 0;
n = use_rewrite + use_access + cmcf->try_files + 1 /* find config phase */;
for (i = 0; i < NGX_HTTP_LOG_PHASE; i++) {
n += cmcf->phases[i].handlers.nelts;
}
ph = ngx_pcalloc(cf->pool,
n * sizeof(ngx_http_phase_handler_t) + sizeof(void *));
if (ph == NULL) {
return NGX_ERROR;
}
cmcf->phase_engine.handlers = ph;
n = 0;
for (i = 0; i < NGX_HTTP_LOG_PHASE; i++) {
h = cmcf->phases[i].handlers.elts;
switch (i) {
case NGX_HTTP_SERVER_REWRITE_PHASE:
if (cmcf->phase_engine.server_rewrite_index == (ngx_uint_t) -1) {
cmcf->phase_engine.server_rewrite_index = n;
}
checker = ngx_http_core_generic_phase;
break;
case NGX_HTTP_FIND_CONFIG_PHASE:
find_config_index = n;
ph->checker = ngx_http_core_find_config_phase;
n++;
ph++;
continue;
case NGX_HTTP_REWRITE_PHASE:
if (cmcf->phase_engine.location_rewrite_index == (ngx_uint_t) -1) {
cmcf->phase_engine.location_rewrite_index = n;
}
checker = ngx_http_core_generic_phase;
break;
case NGX_HTTP_POST_REWRITE_PHASE:
if (use_rewrite) {
ph->checker = ngx_http_core_post_rewrite_phase;
ph->next = find_config_index;
n++;
ph++;
}
continue;
case NGX_HTTP_ACCESS_PHASE:
checker = ngx_http_core_access_phase;
n++;
break;
case NGX_HTTP_POST_ACCESS_PHASE:
if (use_access) {
ph->checker = ngx_http_core_post_access_phase;
ph->next = n;
ph++;
}
continue;
case NGX_HTTP_TRY_FILES_PHASE:
if (cmcf->try_files) {
ph->checker = ngx_http_core_try_files_phase;
n++;
ph++;
}
continue;
case NGX_HTTP_CONTENT_PHASE:
checker = ngx_http_core_content_phase;
break;
default:
checker = ngx_http_core_generic_phase;
}
n += cmcf->phases[i].handlers.nelts;
for (j = cmcf->phases[i].handlers.nelts - 1; j >=0; j--) {
ph->checker = checker;
ph->handler = h[j];
ph->next = n;
ph++;
}
}
return NGX_OK;
}
static char *
ngx_http_merge_locations(ngx_conf_t *cf, ngx_queue_t *locations,
void **loc_conf, ngx_http_module_t *module, ngx_uint_t ctx_index)
{
char *rv;
ngx_queue_t *q;
ngx_http_core_loc_conf_t *clcf;
ngx_http_location_queue_t *lq;
if (locations == NULL) {
return NGX_CONF_OK;
}
for (q = ngx_queue_head(locations);
q != ngx_queue_sentinel(locations);
q = ngx_queue_next(q))
{
lq = (ngx_http_location_queue_t *) q;
clcf = lq->exact ? lq->exact : lq->inclusive;
rv = module->merge_loc_conf(cf, loc_conf[ctx_index],
clcf->loc_conf[ctx_index]);
if (rv != NGX_CONF_OK) {
return rv;
}
rv = ngx_http_merge_locations(cf, clcf->locations, clcf->loc_conf,
module, ctx_index);
if (rv != NGX_CONF_OK) {
return rv;
}
}
return NGX_CONF_OK;
}
static ngx_int_t
ngx_http_init_locations(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
ngx_http_core_loc_conf_t *pclcf)
{
ngx_uint_t n;
ngx_queue_t *q, *locations, *named, tail;
ngx_http_core_loc_conf_t *clcf;
ngx_http_location_queue_t *lq;
ngx_http_core_loc_conf_t **clcfp;
#if (NGX_PCRE)
ngx_uint_t r;
ngx_queue_t *regex;
#endif
locations = pclcf->locations;
if (locations == NULL) {
return NGX_OK;
}
ngx_queue_sort(locations, ngx_http_cmp_locations);
named = NULL;
n = 0;
#if (NGX_PCRE)
regex = NULL;
r = 0;
#endif
for (q = ngx_queue_head(locations);
q != ngx_queue_sentinel(locations);
q = ngx_queue_next(q))
{
lq = (ngx_http_location_queue_t *) q;
clcf = lq->exact ? lq->exact : lq->inclusive;
if (ngx_http_init_locations(cf, NULL, clcf) != NGX_OK) {
return NGX_ERROR;
}
#if (NGX_PCRE)
if (clcf->regex) {
r++;
if (regex == NULL) {
regex = q;
}
continue;
}
#endif
if (clcf->named) {
n++;
if (named == NULL) {
named = q;
}
continue;
}
if (clcf->noname) {
break;
}
}
if (q != ngx_queue_sentinel(locations)) {
ngx_queue_split(locations, q, &tail);
}
if (named) {
clcfp = ngx_palloc(cf->pool,
(n + 1) * sizeof(ngx_http_core_loc_conf_t **));
if (clcfp == NULL) {
return NGX_ERROR;
}
cscf->named_locations = clcfp;
for (q = named;
q != ngx_queue_sentinel(locations);
q = ngx_queue_next(q))
{
lq = (ngx_http_location_queue_t *) q;
*(clcfp++) = lq->exact;
}
*clcfp = NULL;
ngx_queue_split(locations, named, &tail);
}
#if (NGX_PCRE)
if (regex) {
clcfp = ngx_palloc(cf->pool,
(r + 1) * sizeof(ngx_http_core_loc_conf_t **));
if (clcfp == NULL) {
return NGX_ERROR;
}
pclcf->regex_locations = clcfp;
for (q = regex;
q != ngx_queue_sentinel(locations);
q = ngx_queue_next(q))
{
lq = (ngx_http_location_queue_t *) q;
*(clcfp++) = lq->exact;
}
*clcfp = NULL;
ngx_queue_split(locations, regex, &tail);
}
#endif
return NGX_OK;
}
static ngx_int_t
ngx_http_init_static_location_trees(ngx_conf_t *cf,
ngx_http_core_loc_conf_t *pclcf)
{
ngx_queue_t *q, *locations;
ngx_http_core_loc_conf_t *clcf;
ngx_http_location_queue_t *lq;
locations = pclcf->locations;
if (locations == NULL) {
return NGX_OK;
}
if (ngx_queue_empty(locations)) {
return NGX_OK;
}
for (q = ngx_queue_head(locations);
q != ngx_queue_sentinel(locations);
q = ngx_queue_next(q))
{
lq = (ngx_http_location_queue_t *) q;
clcf = lq->exact ? lq->exact : lq->inclusive;
if (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) {
return NGX_ERROR;
}
}
if (ngx_http_join_exact_locations(cf, locations) != NGX_OK) {
return NGX_ERROR;
}
ngx_http_create_locations_list(locations, ngx_queue_head(locations));
pclcf->static_locations = ngx_http_create_locations_tree(cf, locations, 0);
if (pclcf->static_locations == NULL) {
return NGX_ERROR;
}
return NGX_OK;
}
ngx_int_t
ngx_http_add_location(ngx_conf_t *cf, ngx_queue_t **locations,
ngx_http_core_loc_conf_t *clcf)
{
ngx_http_location_queue_t *lq;
if (*locations == NULL) {
*locations = ngx_palloc(cf->temp_pool,
sizeof(ngx_http_location_queue_t));
if (*locations == NULL) {
return NGX_ERROR;
}
ngx_queue_init(*locations);
}
lq = ngx_palloc(cf->temp_pool, sizeof(ngx_http_location_queue_t));
if (lq == NULL) {
return NGX_ERROR;
}
if (clcf->exact_match
#if (NGX_PCRE)
|| clcf->regex
#endif
|| clcf->named || clcf->noname)
{
lq->exact = clcf;
lq->inclusive = NULL;
} else {
lq->exact = NULL;
lq->inclusive = clcf;
}
lq->name = &clcf->name;
lq->file_name = cf->conf_file->file.name.data;
lq->line = cf->conf_file->line;
ngx_queue_init(&lq->list);
ngx_queue_insert_tail(*locations, &lq->queue);
return NGX_OK;
}
static ngx_int_t
ngx_http_cmp_locations(const ngx_queue_t *one, const ngx_queue_t *two)
{
ngx_int_t rc;
ngx_http_core_loc_conf_t *first, *second;
ngx_http_location_queue_t *lq1, *lq2;
lq1 = (ngx_http_location_queue_t *) one;
lq2 = (ngx_http_location_queue_t *) two;
first = lq1->exact ? lq1->exact : lq1->inclusive;
second = lq2->exact ? lq2->exact : lq2->inclusive;
if (first->noname && !second->noname) {
/* shift no named locations to the end */
return 1;
}
if (!first->noname && second->noname) {
/* shift no named locations to the end */
return -1;
}
if (first->noname || second->noname) {
/* do not sort no named locations */
return 0;
}
if (first->named && !second->named) {
/* shift named locations to the end */
return 1;
}
if (!first->named && second->named) {
/* shift named locations to the end */
return -1;
}
if (first->named && second->named) {
return ngx_strcmp(first->name.data, second->name.data);
}
#if (NGX_PCRE)
if (first->regex && !second->regex) {
/* shift the regex matches to the end */
return 1;
}
if (!first->regex && second->regex) {
/* shift the regex matches to the end */
return -1;
}
if (first->regex || second->regex) {
/* do not sort the regex matches */
return 0;
}
#endif
rc = ngx_strcmp(first->name.data, second->name.data);
if (rc == 0 && !first->exact_match && second->exact_match) {
/* an exact match must be before the same inclusive one */
return 1;
}
return rc;
}
static ngx_int_t
ngx_http_join_exact_locations(ngx_conf_t *cf, ngx_queue_t *locations)
{
ngx_queue_t *q, *x;
ngx_http_location_queue_t *lq, *lx;
q = ngx_queue_head(locations);
while (q != ngx_queue_last(locations)) {
x = ngx_queue_next(q);
lq = (ngx_http_location_queue_t *) q;
lx = (ngx_http_location_queue_t *) x;
if (ngx_strcmp(lq->name->data, lx->name->data) == 0) {
if ((lq->exact && lx->exact) || (lq->inclusive && lx->inclusive)) {
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"duplicate location \"%V\" in %s:%ui",
lx->name, lx->file_name, lx->line);
return NGX_ERROR;
}
lq->inclusive = lx->inclusive;
ngx_queue_remove(x);
continue;
}
q = ngx_queue_next(q);
}
return NGX_OK;
}
static void
ngx_http_create_locations_list(ngx_queue_t *locations, ngx_queue_t *q)
{
u_char *name;
size_t len;
ngx_queue_t *x, tail;
ngx_http_location_queue_t *lq, *lx;
if (q == ngx_queue_last(locations)) {
return;
}
lq = (ngx_http_location_queue_t *) q;
if (lq->inclusive == NULL) {
ngx_http_create_locations_list(locations, ngx_queue_next(q));
return;
}
len = lq->name->len;
name = lq->name->data;
for (x = ngx_queue_next(q);
x != ngx_queue_sentinel(locations);
x = ngx_queue_next(x))
{
lx = (ngx_http_location_queue_t *) x;
if (len > lx->name->len
|| (ngx_strncmp(name, lx->name->data, len) != 0))
{
break;
}
}
q = ngx_queue_next(q);
if (q == x) {
ngx_http_create_locations_list(locations, x);
return;
}
ngx_queue_split(locations, q, &tail);
ngx_queue_add(&lq->list, &tail);
if (x == ngx_queue_sentinel(locations)) {
ngx_http_create_locations_list(&lq->list, ngx_queue_head(&lq->list));
return;
}
ngx_queue_split(&lq->list, x, &tail);
ngx_queue_add(locations, &tail);
ngx_http_create_locations_list(&lq->list, ngx_queue_head(&lq->list));
ngx_http_create_locations_list(locations, x);
}
/*
* to keep cache locality for left leaf nodes, allocate nodes in following
* order: node, left subtree, right subtree, inclusive subtree
*/
static ngx_http_location_tree_node_t *
ngx_http_create_locations_tree(ngx_conf_t *cf, ngx_queue_t *locations,
size_t prefix)
{
size_t len;
ngx_queue_t *q, tail;
ngx_http_location_queue_t *lq;
ngx_http_location_tree_node_t *node;
q = ngx_queue_middle(locations);
lq = (ngx_http_location_queue_t *) q;
len = lq->name->len - prefix;
node = ngx_palloc(cf->pool,
offsetof(ngx_http_location_tree_node_t, name) + len);
if (node == NULL) {
return NULL;
}
node->left = NULL;
node->right = NULL;
node->tree = NULL;
node->exact = lq->exact;
node->inclusive = lq->inclusive;
node->auto_redirect = (u_char) ((lq->exact && lq->exact->auto_redirect)
|| (lq->inclusive && lq->inclusive->auto_redirect));
node->len = (u_char) len;
ngx_memcpy(node->name, &lq->name->data[prefix], len);
ngx_queue_split(locations, q, &tail);
if (ngx_queue_empty(locations)) {
/*
* ngx_queue_split() insures that if left part is empty,
* then right one is empty too
*/
goto inclusive;
}
node->left = ngx_http_create_locations_tree(cf, locations, prefix);
if (node->left == NULL) {
return NULL;
}
ngx_queue_remove(q);
if (ngx_queue_empty(&tail)) {
goto inclusive;
}
node->right = ngx_http_create_locations_tree(cf, &tail, prefix);
if (node->right == NULL) {
return NULL;
}
inclusive:
if (ngx_queue_empty(&lq->list)) {
return node;
}
node->tree = ngx_http_create_locations_tree(cf, &lq->list, prefix + len);
if (node->tree == NULL) {
return NULL;
}
return node;
}
static ngx_int_t
ngx_http_init_server_lists(ngx_conf_t *cf, ngx_array_t *servers,
ngx_array_t *ports)
{
ngx_uint_t s, i;
ngx_http_listen_t *listen;
ngx_http_core_srv_conf_t **cscfp;
if (ngx_array_init(ports, cf->temp_pool, 2, sizeof(ngx_http_conf_port_t))
!= NGX_OK)
{
return NGX_ERROR;
}
/* "server" directives */
cscfp = servers->elts;
for (s = 0; s < servers->nelts; s++) {
/* "listen" directives */
listen = cscfp[s]->listen.elts;
for (i = 0; i < cscfp[s]->listen.nelts; i++) {
if (ngx_http_add_ports(cf, cscfp[s], ports, &listen[i]) != NGX_OK) {
return NGX_ERROR;
}
}
}
return NGX_OK;
}
static ngx_int_t
ngx_http_add_ports(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
ngx_array_t *ports, ngx_http_listen_t *listen)
{
in_port_t p;
ngx_uint_t i;
struct sockaddr *sa;
struct sockaddr_in *sin;
ngx_http_conf_port_t *port;
#if (NGX_HAVE_INET6)
struct sockaddr_in6 *sin6;
#endif
sa = (struct sockaddr *) &listen->sockaddr;
switch (sa->sa_family) {
#if (NGX_HAVE_INET6)
case AF_INET6:
sin6 = (struct sockaddr_in6 *) sa;
p = sin6->sin6_port;
break;
#endif
default: /* AF_INET */
sin = (struct sockaddr_in *) sa;
p = sin->sin_port;
break;
}
port = ports->elts;
for (i = 0; i < ports->nelts; i++) {
if (p != port[i].port || sa->sa_family != port[i].family) {
continue;
}
/* a port is already in the port list */
return ngx_http_add_addresses(cf, cscf, &port[i], listen);
}
/* add a port to the port list */
port = ngx_array_push(ports);
if (port == NULL) {
return NGX_ERROR;
}
port->family = sa->sa_family;
port->port = p;
port->addrs.elts = NULL;
return ngx_http_add_address(cf, cscf, port, listen);
}
static ngx_int_t
ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
ngx_http_conf_port_t *port, ngx_http_listen_t *listen)
{
u_char *p;
size_t len, off;
ngx_uint_t i;
struct sockaddr *sa;
ngx_http_conf_addr_t *addr;
/*
* we can not compare whole sockaddr struct's as kernel
* may fill some fields in inherited sockaddr struct's
*/
sa = (struct sockaddr *) &listen->sockaddr;
switch (sa->sa_family) {
#if (NGX_HAVE_INET6)
case AF_INET6:
off = offsetof(struct sockaddr_in6, sin6_addr);
len = 16;
break;
#endif
default: /* AF_INET */
off = offsetof(struct sockaddr_in, sin_addr);
len = 4;
break;
}
p = listen->sockaddr + off;
addr = port->addrs.elts;
for (i = 0; i < port->addrs.nelts; i++) {
if (ngx_memcmp(p, (u_char *) addr[i].sockaddr + off, len) != 0) {
continue;
}
/* the address is already in the address list */
if (ngx_http_add_names(cf, cscf, &addr[i]) != NGX_OK) {
return NGX_ERROR;
}
/* check the duplicate "default" server for this address:port */
if (listen->conf.default_server) {
if (addr[i].default_server) {
ngx_log_error(NGX_LOG_ERR, cf->log, 0,
"the duplicate default server in %s:%ui",
listen->file_name, listen->line);
return NGX_ERROR;
}
addr[i].core_srv_conf = cscf;
addr[i].default_server = 1;
#if (NGX_HTTP_SSL)
addr[i].ssl = listen->conf.ssl;
#endif
addr[i].listen_conf = &listen->conf;
}
return NGX_OK;
}
/* add the address to the addresses list that bound to this port */
return ngx_http_add_address(cf, cscf, port, listen);
}
/*
* add the server address, the server names and the server core module
* configurations to the port list
*/
static ngx_int_t
ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
ngx_http_conf_port_t *port, ngx_http_listen_t *listen)
{
ngx_http_conf_addr_t *addr;
if (port->addrs.elts == NULL) {
if (ngx_array_init(&port->addrs, cf->temp_pool, 4,
sizeof(ngx_http_conf_addr_t))
!= NGX_OK)
{
return NGX_ERROR;
}
}
addr = ngx_array_push(&port->addrs);
if (addr == NULL) {
return NGX_ERROR;
}
addr->sockaddr = (struct sockaddr *) &listen->sockaddr;
addr->socklen = listen->socklen;
addr->hash.buckets = NULL;
addr->hash.size = 0;
addr->wc_head = NULL;
addr->wc_tail = NULL;
addr->names.elts = NULL;
#if (NGX_PCRE)
addr->nregex = 0;
addr->regex = NULL;
#endif
addr->core_srv_conf = cscf;
addr->default_server = listen->conf.default_server;
addr->bind = listen->conf.bind;
addr->wildcard = listen->conf.wildcard;
#if (NGX_HTTP_SSL)
addr->ssl = listen->conf.ssl;
#endif
addr->listen_conf = &listen->conf;
return ngx_http_add_names(cf, cscf, addr);
}
/*
* add the server names and the server core module
* configurations to the address:port
*/
static ngx_int_t
ngx_http_add_names(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
ngx_http_conf_addr_t *addr)
{
ngx_uint_t i;
ngx_http_server_name_t *server_names, *name;
if (addr->names.elts == NULL) {
if (ngx_array_init(&addr->names, cf->temp_pool, 4,
sizeof(ngx_http_server_name_t))
!= NGX_OK)
{
return NGX_ERROR;
}
}
server_names = cscf->server_names.elts;
for (i = 0; i < cscf->server_names.nelts; i++) {
ngx_strlow(server_names[i].name.data, server_names[i].name.data,
server_names[i].name.len);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0,
"name: %V", &server_names[i].name);
name = ngx_array_push(&addr->names);
if (name == NULL) {
return NGX_ERROR;
}
*name = server_names[i];
}
return NGX_OK;
}
static ngx_int_t
ngx_http_optimize_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,
ngx_array_t *ports)
{
ngx_uint_t s, p, a;
ngx_http_conf_port_t *port;
ngx_http_conf_addr_t *addr;
ngx_http_server_name_t *name;
port = ports->elts;
for (p = 0; p < ports->nelts; p++) {
ngx_sort(port[p].addrs.elts, (size_t) port[p].addrs.nelts,
sizeof(ngx_http_conf_addr_t), ngx_http_cmp_conf_addrs);
/*
* check whether all name-based servers have the same
* configuraiton as a default server for given address:port
*/
addr = port[p].addrs.elts;
for (a = 0; a < port[p].addrs.nelts; a++) {
name = addr[a].names.elts;
for (s = 0; s < addr[a].names.nelts; s++) {
if (addr[a].core_srv_conf == name[s].core_srv_conf
#if (NGX_PCRE)
&& name[s].captures == 0
#endif
)
{
continue;
}
if (ngx_http_server_names(cf, cmcf, &addr[a]) != NGX_OK) {
return NGX_ERROR;
}
break;
}
}
if (ngx_http_init_listening(cf, &port[p]) != NGX_OK) {
return NGX_ERROR;
}
}
return NGX_OK;
}
static ngx_int_t
ngx_http_server_names(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,
ngx_http_conf_addr_t *addr)
{
ngx_int_t rc;
ngx_uint_t s;
ngx_hash_init_t hash;
ngx_hash_keys_arrays_t ha;
ngx_http_server_name_t *name;
#if (NGX_PCRE)
ngx_uint_t regex, i;
regex = 0;
#endif
ngx_memzero(&ha, sizeof(ngx_hash_keys_arrays_t));
ha.temp_pool = ngx_create_pool(16384, cf->log);
if (ha.temp_pool == NULL) {
return NGX_ERROR;
}
ha.pool = cf->pool;
if (ngx_hash_keys_array_init(&ha, NGX_HASH_LARGE) != NGX_OK) {
goto failed;
}
name = addr->names.elts;
for (s = 0; s < addr->names.nelts; s++) {
#if (NGX_PCRE)
if (name[s].regex) {
regex++;
continue;
}
#endif
rc = ngx_hash_add_key(&ha, &name[s].name, name[s].core_srv_conf,
NGX_HASH_WILDCARD_KEY);
if (rc == NGX_ERROR) {
return NGX_ERROR;
}
if (rc == NGX_DECLINED) {
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"invalid server name or wildcard \"%V\" on %s",
&name[s].name, addr->listen_conf->addr);
return NGX_ERROR;
}
if (rc == NGX_BUSY) {
ngx_log_error(NGX_LOG_WARN, cf->log, 0,
"conflicting server name \"%V\" on %s, ignored",
&name[s].name, addr->listen_conf->addr);
}
}
hash.key = ngx_hash_key_lc;
hash.max_size = cmcf->server_names_hash_max_size;
hash.bucket_size = cmcf->server_names_hash_bucket_size;
hash.name = "server_names_hash";
hash.pool = cf->pool;
if (ha.keys.nelts) {
hash.hash = &addr->hash;
hash.temp_pool = NULL;
if (ngx_hash_init(&hash, ha.keys.elts, ha.keys.nelts) != NGX_OK) {
goto failed;
}
}
if (ha.dns_wc_head.nelts) {
ngx_qsort(ha.dns_wc_head.elts, (size_t) ha.dns_wc_head.nelts,
sizeof(ngx_hash_key_t), ngx_http_cmp_dns_wildcards);
hash.hash = NULL;
hash.temp_pool = ha.temp_pool;
if (ngx_hash_wildcard_init(&hash, ha.dns_wc_head.elts,
ha.dns_wc_head.nelts)
!= NGX_OK)
{
goto failed;
}
addr->wc_head = (ngx_hash_wildcard_t *) hash.hash;
}
if (ha.dns_wc_tail.nelts) {
ngx_qsort(ha.dns_wc_tail.elts, (size_t) ha.dns_wc_tail.nelts,
sizeof(ngx_hash_key_t), ngx_http_cmp_dns_wildcards);
hash.hash = NULL;
hash.temp_pool = ha.temp_pool;
if (ngx_hash_wildcard_init(&hash, ha.dns_wc_tail.elts,
ha.dns_wc_tail.nelts)
!= NGX_OK)
{
goto failed;
}
addr->wc_tail = (ngx_hash_wildcard_t *) hash.hash;
}
ngx_destroy_pool(ha.temp_pool);
#if (NGX_PCRE)
if (regex == 0) {
return NGX_OK;
}
addr->nregex = regex;
addr->regex = ngx_palloc(cf->pool, regex * sizeof(ngx_http_server_name_t));
if (addr->regex == NULL) {
return NGX_ERROR;
}
for (i = 0, s = 0; s < addr->names.nelts; s++) {
if (name[s].regex) {
addr->regex[i++] = name[s];
}
}
#endif
return NGX_OK;
failed:
ngx_destroy_pool(ha.temp_pool);
return NGX_ERROR;
}
static ngx_int_t
ngx_http_cmp_conf_addrs(const void *one, const void *two)
{
ngx_http_conf_addr_t *first, *second;
first = (ngx_http_conf_addr_t *) one;
second = (ngx_http_conf_addr_t *) two;
if (first->wildcard) {
/* a wildcard address must be the last resort, shift it to the end */
return 1;
}
if (first->bind && !second->bind) {
/* shift explicit bind()ed addresses to the start */
return -1;
}
if (!first->bind && second->bind) {
/* shift explicit bind()ed addresses to the start */
return 1;
}
/* do not sort by default */
return 0;
}
static int ngx_libc_cdecl
ngx_http_cmp_dns_wildcards(const void *one, const void *two)
{
ngx_hash_key_t *first, *second;
first = (ngx_hash_key_t *) one;
second = (ngx_hash_key_t *) two;
return ngx_dns_strcmp(first->key.data, second->key.data);
}
static ngx_int_t
ngx_http_init_listening(ngx_conf_t *cf, ngx_http_conf_port_t *port)
{
ngx_uint_t i, last, bind_wildcard;
ngx_listening_t *ls;
ngx_http_port_t *hport;
ngx_http_conf_addr_t *addr;
addr = port->addrs.elts;
last = port->addrs.nelts;
/*
* If there is a binding to an "*:port" then we need to bind() to
* the "*:port" only and ignore other implicit bindings. The bindings
* have been already sorted: explicit bindings are on the start, then
* implicit bindings go, and wildcard binding is in the end.
*/
if (addr[last - 1].wildcard) {
addr[last - 1].bind = 1;
bind_wildcard = 1;
} else {
bind_wildcard = 0;
}
i = 0;
while (i < last) {
if (bind_wildcard && !addr[i].bind) {
i++;
continue;
}
ls = ngx_http_add_listening(cf, &addr[i]);
if (ls == NULL) {
return NGX_ERROR;
}
hport = ngx_pcalloc(cf->pool, sizeof(ngx_http_port_t));
if (hport == NULL) {
return NGX_ERROR;
}
ls->servers = hport;
if (i == last - 1) {
hport->naddrs = last;
} else {
hport->naddrs = 1;
i = 0;
}
switch (ls->sockaddr->sa_family) {
#if (NGX_HAVE_INET6)
case AF_INET6:
if (ngx_http_add_addrs6(cf, hport, addr) != NGX_OK) {
return NGX_ERROR;
}
break;
#endif
default: /* AF_INET */
if (ngx_http_add_addrs(cf, hport, addr) != NGX_OK) {
return NGX_ERROR;
}
break;
}
addr++;
last--;
}
return NGX_OK;
}
static ngx_listening_t *
ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr)
{
ngx_listening_t *ls;
ngx_http_core_loc_conf_t *clcf;
ngx_http_core_srv_conf_t *cscf;
ls = ngx_create_listening(cf, addr->sockaddr, addr->socklen);
if (ls == NULL) {
return NULL;
}
ls->addr_ntop = 1;
ls->handler = ngx_http_init_connection;
cscf = addr->core_srv_conf;
ls->pool_size = cscf->connection_pool_size;
ls->post_accept_timeout = cscf->client_header_timeout;
clcf = cscf->ctx->loc_conf[ngx_http_core_module.ctx_index];
ls->logp = clcf->error_log;
ls->log.data = &ls->addr_text;
ls->log.handler = ngx_accept_log_error;
#if (NGX_WIN32)
{
ngx_iocp_conf_t *iocpcf;
iocpcf = ngx_event_get_conf(cf->cycle->conf_ctx, ngx_iocp_module);
if (iocpcf->acceptex_read) {
ls->post_accept_buffer_size = cscf->client_header_buffer_size;
}
}
#endif
ls->backlog = addr->listen_conf->backlog;
ls->rcvbuf = addr->listen_conf->rcvbuf;
ls->sndbuf = addr->listen_conf->sndbuf;
#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
ls->accept_filter = addr->listen_conf->accept_filter;
#endif
#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
ls->deferred_accept = addr->listen_conf->deferred_accept;
#endif
#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
ls->ipv6only = addr->listen_conf->ipv6only;
#endif
return ls;
}
static ngx_int_t
ngx_http_add_addrs(ngx_conf_t *cf, ngx_http_port_t *hport,
ngx_http_conf_addr_t *addr)
{
ngx_uint_t i;
ngx_http_in_addr_t *addrs;
struct sockaddr_in *sin;
ngx_http_virtual_names_t *vn;
hport->addrs = ngx_pcalloc(cf->pool,
hport->naddrs * sizeof(ngx_http_in_addr_t));
if (hport->addrs == NULL) {
return NGX_ERROR;
}
addrs = hport->addrs;
for (i = 0; i < hport->naddrs; i++) {
sin = (struct sockaddr_in *) addr[i].sockaddr;
addrs[i].addr = sin->sin_addr.s_addr;
addrs[i].conf.core_srv_conf = addr[i].core_srv_conf;
#if (NGX_HTTP_SSL)
addrs[i].conf.ssl = addr[i].ssl;
#endif
if (addr[i].hash.buckets == NULL
&& (addr[i].wc_head == NULL
|| addr[i].wc_head->hash.buckets == NULL)
&& (addr[i].wc_tail == NULL
|| addr[i].wc_tail->hash.buckets == NULL)
#if (NGX_PCRE)
&& addr[i].nregex == 0
#endif
)
{
continue;
}
vn = ngx_palloc(cf->pool, sizeof(ngx_http_virtual_names_t));
if (vn == NULL) {
return NGX_ERROR;
}
addrs[i].conf.virtual_names = vn;
vn->names.hash = addr[i].hash;
vn->names.wc_head = addr[i].wc_head;
vn->names.wc_tail = addr[i].wc_tail;
#if (NGX_PCRE)
vn->nregex = addr[i].nregex;
vn->regex = addr[i].regex;
#endif
}
return NGX_OK;
}
#if (NGX_HAVE_INET6)
static ngx_int_t
ngx_http_add_addrs6(ngx_conf_t *cf, ngx_http_port_t *hport,
ngx_http_conf_addr_t *addr)
{
ngx_uint_t i;
ngx_http_in6_addr_t *addrs6;
struct sockaddr_in6 *sin6;
ngx_http_virtual_names_t *vn;
hport->addrs = ngx_pcalloc(cf->pool,
hport->naddrs * sizeof(ngx_http_in6_addr_t));
if (hport->addrs == NULL) {
return NGX_ERROR;
}
addrs6 = hport->addrs;
for (i = 0; i < hport->naddrs; i++) {
sin6 = (struct sockaddr_in6 *) addr[i].sockaddr;
addrs6[i].addr6 = sin6->sin6_addr;
addrs6[i].conf.core_srv_conf = addr[i].core_srv_conf;
#if (NGX_HTTP_SSL)
addrs6[i].conf.ssl = addr[i].ssl;
#endif
if (addr[i].hash.buckets == NULL
&& (addr[i].wc_head == NULL
|| addr[i].wc_head->hash.buckets == NULL)
&& (addr[i].wc_tail == NULL
|| addr[i].wc_tail->hash.buckets == NULL)
#if (NGX_PCRE)
&& addr[i].nregex == 0
#endif
)
{
continue;
}
vn = ngx_palloc(cf->pool, sizeof(ngx_http_virtual_names_t));
if (vn == NULL) {
return NGX_ERROR;
}
addrs6[i].conf.virtual_names = vn;
vn->names.hash = addr[i].hash;
vn->names.wc_head = addr[i].wc_head;
vn->names.wc_tail = addr[i].wc_tail;
#if (NGX_PCRE)
vn->nregex = addr[i].nregex;
vn->regex = addr[i].regex;
#endif
}
return NGX_OK;
}
#endif
char *
ngx_http_types_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
char *p = conf;
ngx_array_t **types;
ngx_str_t *value, *default_type;
ngx_uint_t i, n, hash;
ngx_hash_key_t *type;
types = (ngx_array_t **) (p + cmd->offset);
default_type = cmd->post;
if (*types == NULL) {
*types = ngx_array_create(cf->temp_pool, 1, sizeof(ngx_hash_key_t));
if (*types == NULL) {
return NGX_CONF_ERROR;
}
if (default_type) {
type = ngx_array_push(*types);
if (type == NULL) {
return NGX_CONF_ERROR;
}
type->key = *default_type;
type->key_hash = ngx_hash_key(default_type->data,
default_type->len);
type->value = (void *) 4;
}
}
value = cf->args->elts;
for (i = 1; i < cf->args->nelts; i++) {
hash = ngx_hash_strlow(value[i].data, value[i].data, value[i].len);
value[i].data[value[i].len] = '\0';
type = (*types)->elts;
for (n = 0; n < (*types)->nelts; n++) {
if (ngx_strcmp(value[i].data, type[n].key.data) == 0) {
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
"duplicate MIME type \"%V\"", &value[i]);
continue;
}
}
type = ngx_array_push(*types);
if (type == NULL) {
return NGX_CONF_ERROR;
}
type->key = value[i];
type->key_hash = hash;
type->value = (void *) 4;
}
return NGX_CONF_OK;
}
char *
ngx_http_merge_types(ngx_conf_t *cf, ngx_array_t *keys, ngx_hash_t *types_hash,
ngx_array_t *prev_keys, ngx_hash_t *prev_types_hash,
ngx_str_t *default_types)
{
ngx_hash_init_t hash;
if (keys) {
hash.hash = types_hash;
hash.key = NULL;
hash.max_size = 2048;
hash.bucket_size = 64;
hash.name = "test_types_hash";
hash.pool = cf->pool;
hash.temp_pool = NULL;
if (ngx_hash_init(&hash, keys->elts, keys->nelts) != NGX_OK) {
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
if (prev_types_hash->buckets == NULL) {
if (prev_keys == NULL) {
if (ngx_http_set_default_types(cf, &prev_keys, default_types)
!= NGX_OK)
{
return NGX_CONF_ERROR;
}
}
hash.hash = prev_types_hash;
hash.key = NULL;
hash.max_size = 2048;
hash.bucket_size = 64;
hash.name = "test_types_hash";
hash.pool = cf->pool;
hash.temp_pool = NULL;
if (ngx_hash_init(&hash, prev_keys->elts, prev_keys->nelts) != NGX_OK) {
return NGX_CONF_ERROR;
}
}
*types_hash = *prev_types_hash;
return NGX_CONF_OK;
}
ngx_int_t
ngx_http_set_default_types(ngx_conf_t *cf, ngx_array_t **types,
ngx_str_t *default_type)
{
ngx_hash_key_t *type;
*types = ngx_array_create(cf->temp_pool, 1, sizeof(ngx_hash_key_t));
if (*types == NULL) {
return NGX_ERROR;
}
while (default_type->len) {
type = ngx_array_push(*types);
if (type == NULL) {
return NGX_ERROR;
}
type->key = *default_type;
type->key_hash = ngx_hash_key(default_type->data,
default_type->len);
type->value = (void *) 4;
default_type++;
}
return NGX_OK;
}
nginx-0.7.68/src/http/ngx_http_upstream_round_robin.c 000644 001750 001750 00000047130 11124236560 022121 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#include
#include
#include
static ngx_int_t ngx_http_upstream_cmp_servers(const void *one,
const void *two);
static ngx_uint_t
ngx_http_upstream_get_peer(ngx_http_upstream_rr_peers_t *peers);
ngx_int_t
ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
ngx_http_upstream_srv_conf_t *us)
{
ngx_url_t u;
ngx_uint_t i, j, n;
ngx_http_upstream_server_t *server;
ngx_http_upstream_rr_peers_t *peers, *backup;
us->peer.init = ngx_http_upstream_init_round_robin_peer;
if (us->servers) {
server = us->servers->elts;
n = 0;
for (i = 0; i < us->servers->nelts; i++) {
if (server[i].backup) {
continue;
}
n += server[i].naddrs;
}
peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t)
+ sizeof(ngx_http_upstream_rr_peer_t) * (n - 1));
if (peers == NULL) {
return NGX_ERROR;
}
peers->single = (n == 1);
peers->number = n;
peers->name = &us->host;
n = 0;
for (i = 0; i < us->servers->nelts; i++) {
for (j = 0; j < server[i].naddrs; j++) {
if (server[i].backup) {
continue;
}
peers->peer[n].sockaddr = server[i].addrs[j].sockaddr;
peers->peer[n].socklen = server[i].addrs[j].socklen;
peers->peer[n].name = server[i].addrs[j].name;
peers->peer[n].max_fails = server[i].max_fails;
peers->peer[n].fail_timeout = server[i].fail_timeout;
peers->peer[n].down = server[i].down;
peers->peer[n].weight = server[i].down ? 0 : server[i].weight;
peers->peer[n].current_weight = peers->peer[n].weight;
n++;
}
}
us->peer.data = peers;
ngx_sort(&peers->peer[0], (size_t) n,
sizeof(ngx_http_upstream_rr_peer_t),
ngx_http_upstream_cmp_servers);
/* backup servers */
n = 0;
for (i = 0; i < us->servers->nelts; i++) {
if (!server[i].backup) {
continue;
}
n += server[i].naddrs;
}
if (n == 0) {
return NGX_OK;
}
backup = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t)
+ sizeof(ngx_http_upstream_rr_peer_t) * (n - 1));
if (backup == NULL) {
return NGX_ERROR;
}
peers->single = 0;
backup->single = 0;
backup->number = n;
backup->name = &us->host;
n = 0;
for (i = 0; i < us->servers->nelts; i++) {
for (j = 0; j < server[i].naddrs; j++) {
if (!server[i].backup) {
continue;
}
backup->peer[n].sockaddr = server[i].addrs[j].sockaddr;
backup->peer[n].socklen = server[i].addrs[j].socklen;
backup->peer[n].name = server[i].addrs[j].name;
backup->peer[n].weight = server[i].weight;
backup->peer[n].current_weight = server[i].weight;
backup->peer[n].max_fails = server[i].max_fails;
backup->peer[n].fail_timeout = server[i].fail_timeout;
backup->peer[n].down = server[i].down;
n++;
}
}
peers->next = backup;
ngx_sort(&backup->peer[0], (size_t) n,
sizeof(ngx_http_upstream_rr_peer_t),
ngx_http_upstream_cmp_servers);
return NGX_OK;
}
/* an upstream implicitly defined by proxy_pass, etc. */
if (us->port == 0 && us->default_port == 0) {
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"no port in upstream \"%V\" in %s:%ui",
&us->host, us->file_name, us->line);
return NGX_ERROR;
}
ngx_memzero(&u, sizeof(ngx_url_t));
u.host = us->host;
u.port = (in_port_t) (us->port ? us->port : us->default_port);
if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) {
if (u.err) {
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"%s in upstream \"%V\" in %s:%ui",
u.err, &us->host, us->file_name, us->line);
}
return NGX_ERROR;
}
n = u.naddrs;
peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t)
+ sizeof(ngx_http_upstream_rr_peer_t) * (n - 1));
if (peers == NULL) {
return NGX_ERROR;
}
peers->single = (n == 1);
peers->number = n;
peers->name = &us->host;
for (i = 0; i < u.naddrs; i++) {
peers->peer[i].sockaddr = u.addrs[i].sockaddr;
peers->peer[i].socklen = u.addrs[i].socklen;
peers->peer[i].name = u.addrs[i].name;
peers->peer[i].weight = 1;
peers->peer[i].current_weight = 1;
peers->peer[i].max_fails = 1;
peers->peer[i].fail_timeout = 10;
}
us->peer.data = peers;
/* implicitly defined upstream has no backup servers */
return NGX_OK;
}
static ngx_int_t
ngx_http_upstream_cmp_servers(const void *one, const void *two)
{
ngx_http_upstream_rr_peer_t *first, *second;
first = (ngx_http_upstream_rr_peer_t *) one;
second = (ngx_http_upstream_rr_peer_t *) two;
return (first->weight < second->weight);
}
ngx_int_t
ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r,
ngx_http_upstream_srv_conf_t *us)
{
ngx_uint_t n;
ngx_http_upstream_rr_peer_data_t *rrp;
rrp = r->upstream->peer.data;
if (rrp == NULL) {
rrp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_rr_peer_data_t));
if (rrp == NULL) {
return NGX_ERROR;
}
r->upstream->peer.data = rrp;
}
rrp->peers = us->peer.data;
rrp->current = 0;
if (rrp->peers->number <= 8 * sizeof(uintptr_t)) {
rrp->tried = &rrp->data;
rrp->data = 0;
} else {
n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
/ (8 * sizeof(uintptr_t));
rrp->tried = ngx_pcalloc(r->pool, n * sizeof(uintptr_t));
if (rrp->tried == NULL) {
return NGX_ERROR;
}
}
r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer;
r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer;
r->upstream->peer.tries = rrp->peers->number;
#if (NGX_HTTP_SSL)
r->upstream->peer.set_session =
ngx_http_upstream_set_round_robin_peer_session;
r->upstream->peer.save_session =
ngx_http_upstream_save_round_robin_peer_session;
#endif
return NGX_OK;
}
ngx_int_t
ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
ngx_http_upstream_resolved_t *ur)
{
u_char *p;
size_t len;
ngx_uint_t i, n;
struct sockaddr_in *sin;
ngx_http_upstream_rr_peers_t *peers;
ngx_http_upstream_rr_peer_data_t *rrp;
rrp = r->upstream->peer.data;
if (rrp == NULL) {
rrp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_rr_peer_data_t));
if (rrp == NULL) {
return NGX_ERROR;
}
r->upstream->peer.data = rrp;
}
peers = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_rr_peers_t)
+ sizeof(ngx_http_upstream_rr_peer_t) * (ur->naddrs - 1));
if (peers == NULL) {
return NGX_ERROR;
}
peers->single = (ur->naddrs == 1);
peers->number = ur->naddrs;
peers->name = &ur->host;
if (ur->sockaddr) {
peers->peer[0].sockaddr = ur->sockaddr;
peers->peer[0].socklen = ur->socklen;
peers->peer[0].name = ur->host;
peers->peer[0].weight = 1;
peers->peer[0].current_weight = 1;
peers->peer[0].max_fails = 1;
peers->peer[0].fail_timeout = 10;
} else {
for (i = 0; i < ur->naddrs; i++) {
len = NGX_INET_ADDRSTRLEN + sizeof(":65536") - 1;
p = ngx_pnalloc(r->pool, len);
if (p == NULL) {
return NGX_ERROR;
}
len = ngx_inet_ntop(AF_INET, &ur->addrs[i], p, NGX_INET_ADDRSTRLEN);
len = ngx_sprintf(&p[len], ":%d", ur->port) - p;
sin = ngx_pcalloc(r->pool, sizeof(struct sockaddr_in));
if (sin == NULL) {
return NGX_ERROR;
}
sin->sin_family = AF_INET;
sin->sin_port = htons(ur->port);
sin->sin_addr.s_addr = ur->addrs[i];
peers->peer[i].sockaddr = (struct sockaddr *) sin;
peers->peer[i].socklen = sizeof(struct sockaddr_in);
peers->peer[i].name.len = len;
peers->peer[i].name.data = p;
peers->peer[i].weight = 1;
peers->peer[i].current_weight = 1;
peers->peer[i].max_fails = 1;
peers->peer[i].fail_timeout = 10;
}
}
rrp->peers = peers;
rrp->current = 0;
if (rrp->peers->number <= 8 * sizeof(uintptr_t)) {
rrp->tried = &rrp->data;
rrp->data = 0;
} else {
n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
/ (8 * sizeof(uintptr_t));
rrp->tried = ngx_pcalloc(r->pool, n * sizeof(uintptr_t));
if (rrp->tried == NULL) {
return NGX_ERROR;
}
}
r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer;
r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer;
r->upstream->peer.tries = rrp->peers->number;
#if (NGX_HTTP_SSL)
r->upstream->peer.set_session =
ngx_http_upstream_set_round_robin_peer_session;
r->upstream->peer.save_session =
ngx_http_upstream_save_round_robin_peer_session;
#endif
return NGX_OK;
}
ngx_int_t
ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
{
ngx_http_upstream_rr_peer_data_t *rrp = data;
time_t now;
uintptr_t m;
ngx_int_t rc;
ngx_uint_t i, n;
ngx_connection_t *c;
ngx_http_upstream_rr_peer_t *peer;
ngx_http_upstream_rr_peers_t *peers;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
"get rr peer, try: %ui", pc->tries);
now = ngx_time();
/* ngx_lock_mutex(rrp->peers->mutex); */
if (rrp->peers->last_cached) {
/* cached connection */
c = rrp->peers->cached[rrp->peers->last_cached];
rrp->peers->last_cached--;
/* ngx_unlock_mutex(ppr->peers->mutex); */
#if (NGX_THREADS)
c->read->lock = c->read->own_lock;
c->write->lock = c->write->own_lock;
#endif
pc->connection = c;
pc->cached = 1;
return NGX_OK;
}
pc->cached = 0;
pc->connection = NULL;
if (rrp->peers->single) {
peer = &rrp->peers->peer[0];
} else {
/* there are several peers */
if (pc->tries == rrp->peers->number) {
/* it's a first try - get a current peer */
i = pc->tries;
for ( ;; ) {
rrp->current = ngx_http_upstream_get_peer(rrp->peers);
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
"get rr peer, current: %ui %i",
rrp->current,
rrp->peers->peer[rrp->current].current_weight);
n = rrp->current / (8 * sizeof(uintptr_t));
m = (uintptr_t) 1 << rrp->current % (8 * sizeof(uintptr_t));
if (!(rrp->tried[n] & m)) {
peer = &rrp->peers->peer[rrp->current];
if (!peer->down) {
if (peer->max_fails == 0
|| peer->fails < peer->max_fails)
{
break;
}
if (now - peer->accessed > peer->fail_timeout) {
peer->fails = 0;
break;
}
peer->current_weight = 0;
} else {
rrp->tried[n] |= m;
}
pc->tries--;
}
if (pc->tries == 0) {
goto failed;
}
if (--i == 0) {
ngx_log_error(NGX_LOG_ALERT, pc->log, 0,
"round robin upstream stuck on %ui tries",
pc->tries);
goto failed;
}
}
peer->current_weight--;
} else {
i = pc->tries;
for ( ;; ) {
n = rrp->current / (8 * sizeof(uintptr_t));
m = (uintptr_t) 1 << rrp->current % (8 * sizeof(uintptr_t));
if (!(rrp->tried[n] & m)) {
peer = &rrp->peers->peer[rrp->current];
if (!peer->down) {
if (peer->max_fails == 0
|| peer->fails < peer->max_fails)
{
break;
}
if (now - peer->accessed > peer->fail_timeout) {
peer->fails = 0;
break;
}
peer->current_weight = 0;
} else {
rrp->tried[n] |= m;
}
pc->tries--;
}
rrp->current++;
if (rrp->current >= rrp->peers->number) {
rrp->current = 0;
}
if (pc->tries == 0) {
goto failed;
}
if (--i == 0) {
ngx_log_error(NGX_LOG_ALERT, pc->log, 0,
"round robin upstream stuck on %ui tries",
pc->tries);
goto failed;
}
}
peer->current_weight--;
}
rrp->tried[n] |= m;
}
pc->sockaddr = peer->sockaddr;
pc->socklen = peer->socklen;
pc->name = &peer->name;
/* ngx_unlock_mutex(rrp->peers->mutex); */
if (pc->tries == 1 && rrp->peers->next) {
pc->tries += rrp->peers->next->number;
n = rrp->peers->next->number / (8 * sizeof(uintptr_t)) + 1;
for (i = 0; i < n; i++) {
rrp->tried[i] = 0;
}
}
return NGX_OK;
failed:
peers = rrp->peers;
if (peers->next) {
/* ngx_unlock_mutex(peers->mutex); */
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "backup servers");
rrp->peers = peers->next;
pc->tries = rrp->peers->number;
n = rrp->peers->number / (8 * sizeof(uintptr_t)) + 1;
for (i = 0; i < n; i++) {
rrp->tried[i] = 0;
}
rc = ngx_http_upstream_get_round_robin_peer(pc, rrp);
if (rc != NGX_BUSY) {
return rc;
}
/* ngx_lock_mutex(peers->mutex); */
}
/* all peers failed, mark them as live for quick recovery */
for (i = 0; i < peers->number; i++) {
peers->peer[i].fails = 0;
}
/* ngx_unlock_mutex(peers->mutex); */
pc->name = peers->name;
return NGX_BUSY;
}
static ngx_uint_t
ngx_http_upstream_get_peer(ngx_http_upstream_rr_peers_t *peers)
{
ngx_uint_t i, n;
ngx_http_upstream_rr_peer_t *peer;
peer = &peers->peer[0];
for ( ;; ) {
for (i = 0; i < peers->number; i++) {
if (peer[i].current_weight <= 0) {
continue;
}
n = i;
while (i < peers->number - 1) {
i++;
if (peer[i].current_weight <= 0) {
continue;
}
if (peer[n].current_weight * 1000 / peer[i].current_weight
> peer[n].weight * 1000 / peer[i].weight)
{
return n;
}
n = i;
}
if (peer[i].current_weight > 0) {
n = i;
}
return n;
}
for (i = 0; i < peers->number; i++) {
peer[i].current_weight = peer[i].weight;
}
}
}
void
ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, void *data,
ngx_uint_t state)
{
ngx_http_upstream_rr_peer_data_t *rrp = data;
time_t now;
ngx_http_upstream_rr_peer_t *peer;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
"free rr peer %ui %ui", pc->tries, state);
if (state == 0 && pc->tries == 0) {
return;
}
/* TODO: NGX_PEER_KEEPALIVE */
if (rrp->peers->single) {
pc->tries = 0;
return;
}
if (state & NGX_PEER_FAILED) {
now = ngx_time();
peer = &rrp->peers->peer[rrp->current];
/* ngx_lock_mutex(rrp->peers->mutex); */
peer->fails++;
peer->accessed = now;
if (peer->max_fails) {
peer->current_weight -= peer->weight / peer->max_fails;
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
"free rr peer failed: %ui %i",
rrp->current, peer->current_weight);
if (peer->current_weight < 0) {
peer->current_weight = 0;
}
/* ngx_unlock_mutex(rrp->peers->mutex); */
}
rrp->current++;
if (rrp->current >= rrp->peers->number) {
rrp->current = 0;
}
if (pc->tries) {
pc->tries--;
}
/* ngx_unlock_mutex(rrp->peers->mutex); */
}
#if (NGX_HTTP_SSL)
ngx_int_t
ngx_http_upstream_set_round_robin_peer_session(ngx_peer_connection_t *pc,
void *data)
{
ngx_http_upstream_rr_peer_data_t *rrp = data;
ngx_int_t rc;
ngx_ssl_session_t *ssl_session;
ngx_http_upstream_rr_peer_t *peer;
peer = &rrp->peers->peer[rrp->current];
/* TODO: threads only mutex */
/* ngx_lock_mutex(rrp->peers->mutex); */
ssl_session = peer->ssl_session;
rc = ngx_ssl_set_session(pc->connection, ssl_session);
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
"set session: %p:%d",
ssl_session, ssl_session ? ssl_session->references : 0);
/* ngx_unlock_mutex(rrp->peers->mutex); */
return rc;
}
void
ngx_http_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc,
void *data)
{
ngx_http_upstream_rr_peer_data_t *rrp = data;
ngx_ssl_session_t *old_ssl_session, *ssl_session;
ngx_http_upstream_rr_peer_t *peer;
ssl_session = ngx_ssl_get_session(pc->connection);
if (ssl_session == NULL) {
return;
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
"save session: %p:%d", ssl_session, ssl_session->references);
peer = &rrp->peers->peer[rrp->current];
/* TODO: threads only mutex */
/* ngx_lock_mutex(rrp->peers->mutex); */
old_ssl_session = peer->ssl_session;
peer->ssl_session = ssl_session;
/* ngx_unlock_mutex(rrp->peers->mutex); */
if (old_ssl_session) {
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
"old session: %p:%d",
old_ssl_session, old_ssl_session->references);
/* TODO: may block */
ngx_ssl_free_session(old_ssl_session);
}
}
#endif
nginx-0.7.68/src/http/ngx_http_file_cache.c 000644 001750 001750 00000121051 11403162273 017715 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#include
#include
#include
#include
static ngx_int_t ngx_http_file_cache_exists(ngx_http_file_cache_t *cache,
ngx_http_cache_t *c);
static ngx_http_file_cache_node_t *
ngx_http_file_cache_lookup(ngx_http_file_cache_t *cache, u_char *key);
static void ngx_http_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp,
ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
static void ngx_http_file_cache_cleanup(void *data);
static time_t ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache);
static time_t ngx_http_file_cache_expire(ngx_http_file_cache_t *cache);
static void ngx_http_file_cache_delete(ngx_http_file_cache_t *cache,
ngx_queue_t *q, u_char *name);
static ngx_int_t
ngx_http_file_cache_manager_sleep(ngx_http_file_cache_t *cache);
static ngx_int_t ngx_http_file_cache_noop(ngx_tree_ctx_t *ctx,
ngx_str_t *path);
static ngx_int_t ngx_http_file_cache_manage_file(ngx_tree_ctx_t *ctx,
ngx_str_t *path);
static ngx_int_t ngx_http_file_cache_add_file(ngx_tree_ctx_t *ctx,
ngx_str_t *path);
static ngx_int_t ngx_http_file_cache_add(ngx_http_file_cache_t *cache,
ngx_http_cache_t *c);
static ngx_int_t ngx_http_file_cache_delete_file(ngx_tree_ctx_t *ctx,
ngx_str_t *path);
ngx_str_t ngx_http_cache_status[] = {
ngx_string("MISS"),
ngx_string("EXPIRED"),
ngx_string("STALE"),
ngx_string("UPDATING"),
ngx_string("HIT")
};
static u_char ngx_http_file_cache_key[] = { LF, 'K', 'E', 'Y', ':', ' ' };
static ngx_int_t
ngx_http_file_cache_init(ngx_shm_zone_t *shm_zone, void *data)
{
ngx_http_file_cache_t *ocache = data;
size_t len;
ngx_uint_t n;
ngx_http_file_cache_t *cache;
cache = shm_zone->data;
if (ocache) {
if (ngx_strcmp(cache->path->name.data, ocache->path->name.data) != 0) {
ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
"cache \"%V\" uses the \"%V\" cache path "
"while previously it used the \"%V\" cache path",
&shm_zone->shm.name, &cache->path->name,
&ocache->path->name);
return NGX_ERROR;
}
for (n = 0; n < 3; n++) {
if (cache->path->level[n] != ocache->path->level[n]) {
ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
"cache \"%V\" had previously different levels",
&shm_zone->shm.name);
return NGX_ERROR;
}
}
cache->sh = ocache->sh;
cache->shpool = ocache->shpool;
cache->bsize = ocache->bsize;
cache->max_size /= cache->bsize;
if (!cache->sh->cold || cache->sh->loading) {
cache->path->loader = NULL;
}
return NGX_OK;
}
cache->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
if (shm_zone->shm.exists) {
cache->sh = cache->shpool->data;
cache->bsize = ngx_fs_bsize(cache->path->name.data);
return NGX_OK;
}
cache->sh = ngx_slab_alloc(cache->shpool, sizeof(ngx_http_file_cache_sh_t));
if (cache->sh == NULL) {
return NGX_ERROR;
}
cache->shpool->data = cache->sh;
ngx_rbtree_init(&cache->sh->rbtree, &cache->sh->sentinel,
ngx_http_file_cache_rbtree_insert_value);
ngx_queue_init(&cache->sh->queue);
cache->sh->cold = 1;
cache->sh->loading = 0;
cache->sh->size = 0;
cache->bsize = ngx_fs_bsize(cache->path->name.data);
cache->max_size /= cache->bsize;
len = sizeof(" in cache keys zone \"\"") + shm_zone->shm.name.len;
cache->shpool->log_ctx = ngx_slab_alloc(cache->shpool, len);
if (cache->shpool->log_ctx == NULL) {
return NGX_ERROR;
}
ngx_sprintf(cache->shpool->log_ctx, " in cache keys zone \"%V\"%Z",
&shm_zone->shm.name);
return NGX_OK;
}
void
ngx_http_file_cache_create_key(ngx_http_request_t *r)
{
size_t len;
ngx_str_t *key;
ngx_uint_t i;
ngx_md5_t md5;
ngx_http_cache_t *c;
c = r->cache;
len = 0;
ngx_crc32_init(c->crc32);
ngx_md5_init(&md5);
key = c->keys.elts;
for (i = 0; i < c->keys.nelts; i++) {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http cache key: \"%V\"", &key[i]);
len += key[i].len;
ngx_crc32_update(&c->crc32, key[i].data, key[i].len);
ngx_md5_update(&md5, key[i].data, key[i].len);
}
c->header_start = sizeof(ngx_http_file_cache_header_t)
+ sizeof(ngx_http_file_cache_key) + len + 1;
ngx_crc32_final(c->crc32);
ngx_md5_final(c->key, &md5);
}
ngx_int_t
ngx_http_file_cache_open(ngx_http_request_t *r)
{
u_char *p;
time_t now;
ssize_t n;
ngx_int_t rc, rv;
ngx_uint_t cold, test;
ngx_path_t *path;
ngx_http_cache_t *c;
ngx_pool_cleanup_t *cln;
ngx_open_file_info_t of;
ngx_http_file_cache_t *cache;
ngx_http_core_loc_conf_t *clcf;
ngx_http_file_cache_header_t *h;
c = r->cache;
cache = c->file_cache;
cln = ngx_pool_cleanup_add(r->pool, 0);
if (cln == NULL) {
return NGX_ERROR;
}
rc = ngx_http_file_cache_exists(cache, c);
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http file cache exists: %i e:%d", rc, c->exists);
if (rc == NGX_ERROR) {
return rc;
}
cln->handler = ngx_http_file_cache_cleanup;
cln->data = c;
if (rc == NGX_AGAIN) {
return rc;
}
cold = cache->sh->cold;
if (rc == NGX_OK) {
if (c->error) {
return c->error;
}
c->temp_file = 1;
test = c->exists ? 1 : 0;
rv = NGX_DECLINED;
} else { /* rc == NGX_DECLINED */
if (c->min_uses > 1) {
if (!cold) {
return NGX_AGAIN;
}
test = 1;
rv = NGX_AGAIN;
} else {
c->temp_file = 1;
test = cold ? 1 : 0;
rv = NGX_DECLINED;
}
}
path = cache->path;
c->file.name.len = path->name.len + 1 + path->len
+ 2 * NGX_HTTP_CACHE_KEY_LEN;
c->file.name.data = ngx_pnalloc(r->pool, c->file.name.len + 1);
if (c->file.name.data == NULL) {
return NGX_ERROR;
}
ngx_memcpy(c->file.name.data, path->name.data, path->name.len);
p = c->file.name.data + path->name.len + 1 + path->len;
p = ngx_hex_dump(p, c->key, NGX_HTTP_CACHE_KEY_LEN);
*p = '\0';
ngx_create_hashed_filename(path, c->file.name.data, c->file.name.len);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
"cache file: \"%s\"", c->file.name.data);
if (!test) {
return NGX_DECLINED;
}
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
ngx_memzero(&of, sizeof(ngx_open_file_info_t));
of.uniq = c->uniq;
of.valid = clcf->open_file_cache_valid;
of.min_uses = clcf->open_file_cache_min_uses;
of.events = clcf->open_file_cache_events;
of.directio = NGX_OPEN_FILE_DIRECTIO_OFF;
if (ngx_open_cached_file(clcf->open_file_cache, &c->file.name, &of, r->pool)
!= NGX_OK)
{
switch (of.err) {
case 0:
return NGX_ERROR;
case NGX_ENOENT:
case NGX_ENOTDIR:
return rv;
default:
ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err,
ngx_open_file_n " \"%s\" failed", c->file.name.data);
return NGX_ERROR;
}
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http file cache fd: %d", of.fd);
c->file.fd = of.fd;
c->file.log = r->connection->log;
c->buf = ngx_create_temp_buf(r->pool, c->body_start);
if (c->buf == NULL) {
return NGX_ERROR;
}
n = ngx_read_file(&c->file, c->buf->pos, c->body_start, 0);
if (n == NGX_ERROR) {
return n;
}
if ((size_t) n < c->header_start) {
ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
"cache file \"%s\" is too small", c->file.name.data);
return NGX_ERROR;
}
h = (ngx_http_file_cache_header_t *) c->buf->pos;
if (h->crc32 != c->crc32 || (size_t) h->header_start != c->header_start) {
ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
"cache file \"%s\" has md5 collision", c->file.name.data);
return NGX_DECLINED;
}
c->buf->last += n;
c->valid_sec = h->valid_sec;
c->last_modified = h->last_modified;
c->date = h->date;
c->valid_msec = h->valid_msec;
c->length = of.size;
c->body_start = h->body_start;
r->cached = 1;
if (cold) {
ngx_shmtx_lock(&cache->shpool->mutex);
if (!c->node->exists) {
c->node->uses = 1;
c->node->body_start = c->body_start;
c->node->exists = 1;
c->node->uniq = of.uniq;
cache->sh->size += (c->length + cache->bsize - 1) / cache->bsize;
}
ngx_shmtx_unlock(&cache->shpool->mutex);
}
now = ngx_time();
if (c->valid_sec < now) {
ngx_shmtx_lock(&cache->shpool->mutex);
if (c->node->updating) {
rc = NGX_HTTP_CACHE_UPDATING;
} else {
c->node->updating = 1;
rc = NGX_HTTP_CACHE_STALE;
}
ngx_shmtx_unlock(&cache->shpool->mutex);
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http file cache expired: %i %T %T",
rc, c->valid_sec, now);
return rc;
}
return NGX_OK;
}
static ngx_int_t
ngx_http_file_cache_exists(ngx_http_file_cache_t *cache, ngx_http_cache_t *c)
{
ngx_int_t rc;
ngx_http_file_cache_node_t *fcn;
ngx_shmtx_lock(&cache->shpool->mutex);
fcn = ngx_http_file_cache_lookup(cache, c->key);
if (fcn) {
ngx_queue_remove(&fcn->queue);
if (fcn->error) {
if (fcn->valid_sec < ngx_time()) {
goto renew;
}
rc = NGX_OK;
goto done;
}
fcn->uses++;
fcn->count++;
if (fcn->exists) {
c->exists = fcn->exists;
c->body_start = fcn->body_start;
rc = NGX_OK;
goto done;
}
if (fcn->uses >= c->min_uses) {
c->exists = fcn->exists;
c->body_start = fcn->body_start;
rc = NGX_OK;
} else {
rc = NGX_AGAIN;
}
goto done;
}
fcn = ngx_slab_alloc_locked(cache->shpool,
sizeof(ngx_http_file_cache_node_t));
if (fcn == NULL) {
ngx_shmtx_unlock(&cache->shpool->mutex);
(void) ngx_http_file_cache_forced_expire(cache);
ngx_shmtx_lock(&cache->shpool->mutex);
fcn = ngx_slab_alloc_locked(cache->shpool,
sizeof(ngx_http_file_cache_node_t));
if (fcn == NULL) {
rc = NGX_ERROR;
goto failed;
}
}
ngx_memcpy((u_char *) &fcn->node.key, c->key, sizeof(ngx_rbtree_key_t));
ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)],
NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t));
ngx_rbtree_insert(&cache->sh->rbtree, &fcn->node);
renew:
rc = NGX_DECLINED;
fcn->uses = 1;
fcn->count = 1;
fcn->valid_msec = 0;
fcn->error = 0;
fcn->exists = 0;
fcn->valid_sec = 0;
fcn->uniq = 0;
fcn->body_start = 0;
fcn->length = 0;
done:
fcn->expire = ngx_time() + cache->inactive;
ngx_queue_insert_head(&cache->sh->queue, &fcn->queue);
c->uniq = fcn->uniq;
c->error = fcn->error;
c->node = fcn;
failed:
ngx_shmtx_unlock(&cache->shpool->mutex);
return rc;
}
static ngx_http_file_cache_node_t *
ngx_http_file_cache_lookup(ngx_http_file_cache_t *cache, u_char *key)
{
ngx_int_t rc;
ngx_rbtree_key_t node_key;
ngx_rbtree_node_t *node, *sentinel;
ngx_http_file_cache_node_t *fcn;
ngx_memcpy((u_char *) &node_key, key, sizeof(ngx_rbtree_key_t));
node = cache->sh->rbtree.root;
sentinel = cache->sh->rbtree.sentinel;
while (node != sentinel) {
if (node_key < node->key) {
node = node->left;
continue;
}
if (node_key > node->key) {
node = node->right;
continue;
}
/* node_key == node->key */
do {
fcn = (ngx_http_file_cache_node_t *) node;
rc = ngx_memcmp(&key[sizeof(ngx_rbtree_key_t)], fcn->key,
NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t));
if (rc == 0) {
return fcn;
}
node = (rc < 0) ? node->left : node->right;
} while (node != sentinel && node_key == node->key);
break;
}
/* not found */
return NULL;
}
static void
ngx_http_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp,
ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
{
ngx_rbtree_node_t **p;
ngx_http_file_cache_node_t *cn, *cnt;
for ( ;; ) {
if (node->key < temp->key) {
p = &temp->left;
} else if (node->key > temp->key) {
p = &temp->right;
} else { /* node->key == temp->key */
cn = (ngx_http_file_cache_node_t *) node;
cnt = (ngx_http_file_cache_node_t *) temp;
p = (ngx_memcmp(cn->key, cnt->key,
NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t))
< 0)
? &temp->left : &temp->right;
}
if (*p == sentinel) {
break;
}
temp = *p;
}
*p = node;
node->parent = temp;
node->left = sentinel;
node->right = sentinel;
ngx_rbt_red(node);
}
void
ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf)
{
ngx_http_file_cache_header_t *h = (ngx_http_file_cache_header_t *) buf;
u_char *p;
ngx_str_t *key;
ngx_uint_t i;
ngx_http_cache_t *c;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http file cache set header");
c = r->cache;
h->valid_sec = c->valid_sec;
h->last_modified = c->last_modified;
h->date = c->date;
h->crc32 = c->crc32;
h->valid_msec = (u_short) c->valid_msec;
h->header_start = (u_short) c->header_start;
h->body_start = (u_short) c->body_start;
p = buf + sizeof(ngx_http_file_cache_header_t);
p = ngx_cpymem(p, ngx_http_file_cache_key, sizeof(ngx_http_file_cache_key));
key = c->keys.elts;
for (i = 0; i < c->keys.nelts; i++) {
p = ngx_copy(p, key[i].data, key[i].len);
}
*p = LF;
}
void
ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf)
{
off_t size, length;
ngx_int_t rc;
ngx_file_uniq_t uniq;
ngx_file_info_t fi;
ngx_http_cache_t *c;
ngx_ext_rename_file_t ext;
ngx_http_file_cache_t *cache;
c = r->cache;
if (c->updated) {
return;
}
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http file cache update");
c->updated = 1;
cache = c->file_cache;
uniq = 0;
length = 0;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http file cache rename: \"%s\" to \"%s\"",
tf->file.name.data, c->file.name.data);
ext.access = NGX_FILE_OWNER_ACCESS;
ext.path_access = NGX_FILE_OWNER_ACCESS;
ext.time = -1;
ext.create_path = 1;
ext.delete_file = 1;
ext.log = r->connection->log;
rc = ngx_ext_rename_file(&tf->file.name, &c->file.name, &ext);
if (rc == NGX_OK) {
if (ngx_fd_info(tf->file.fd, &fi) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
ngx_fd_info_n " \"%s\" failed", tf->file.name.data);
rc = NGX_ERROR;
} else {
uniq = ngx_file_uniq(&fi);
length = ngx_file_size(&fi);
}
}
size = (length + cache->bsize - 1) / cache->bsize;
ngx_shmtx_lock(&cache->shpool->mutex);
c->node->count--;
c->node->uniq = uniq;
c->node->body_start = c->body_start;
size = size - (c->node->length + cache->bsize - 1) / cache->bsize;
c->node->length = length;
cache->sh->size += size;
if (rc == NGX_OK) {
c->node->exists = 1;
}
c->node->updating = 0;
ngx_shmtx_unlock(&cache->shpool->mutex);
}
ngx_int_t
ngx_http_cache_send(ngx_http_request_t *r)
{
ngx_int_t rc;
ngx_buf_t *b;
ngx_chain_t out;
ngx_http_cache_t *c;
c = r->cache;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http file cache send: %s", c->file.name.data);
/* we need to allocate all before the header would be sent */
b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
if (b == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
if (b->file == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
r->header_only = (c->length - c->body_start) == 0;
rc = ngx_http_send_header(r);
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
return rc;
}
b->file_pos = c->body_start;
b->file_last = c->length;
b->in_file = 1;
b->last_buf = (r == r->main) ? 1: 0;
b->last_in_chain = 1;
b->file->fd = c->file.fd;
b->file->name = c->file.name;
b->file->log = r->connection->log;
out.buf = b;
out.next = NULL;
return ngx_http_output_filter(r, &out);
}
void
ngx_http_file_cache_free(ngx_http_request_t *r, ngx_temp_file_t *tf)
{
ngx_http_cache_t *c;
ngx_http_file_cache_t *cache;
c = r->cache;
if (c->updated) {
return;
}
c->updated = 1;
cache = c->file_cache;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http file cache free");
ngx_shmtx_lock(&cache->shpool->mutex);
c->node->count--;
if (c->error) {
c->node->valid_sec = c->valid_sec;
c->node->valid_msec = c->valid_msec;
c->node->error = c->error;
}
c->node->updating = 0;
ngx_shmtx_unlock(&cache->shpool->mutex);
if (c->temp_file) {
if (tf && tf->file.fd != NGX_INVALID_FILE) {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http file cache incomplete: \"%s\"",
tf->file.name.data);
if (ngx_delete_file(tf->file.name.data) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
ngx_delete_file_n " \"%s\" failed",
tf->file.name.data);
}
}
}
}
static void
ngx_http_file_cache_cleanup(void *data)
{
ngx_http_cache_t *c = data;
ngx_http_file_cache_t *cache;
if (c->updated) {
return;
}
c->updated = 1;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->file.log, 0,
"http file cache cleanup");
if (c->error) {
return;
}
cache = c->file_cache;
ngx_shmtx_lock(&cache->shpool->mutex);
c->node->count--;
ngx_shmtx_unlock(&cache->shpool->mutex);
}
static time_t
ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache)
{
u_char *name;
size_t len;
time_t wait;
ngx_uint_t tries;
ngx_path_t *path;
ngx_queue_t *q;
ngx_http_file_cache_node_t *fcn;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
"http file cache forced expire");
path = cache->path;
len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN;
name = ngx_alloc(len + 1, ngx_cycle->log);
if (name == NULL) {
return 10;
}
ngx_memcpy(name, path->name.data, path->name.len);
wait = 10;
tries = 0;
ngx_shmtx_lock(&cache->shpool->mutex);
for (q = ngx_queue_last(&cache->sh->queue);
q != ngx_queue_sentinel(&cache->sh->queue);
q = ngx_queue_prev(q))
{
fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue);
ngx_log_debug6(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
"http file cache forced expire: #%d %d %02xd%02xd%02xd%02xd",
fcn->count, fcn->exists,
fcn->key[0], fcn->key[1], fcn->key[2], fcn->key[3]);
if (fcn->count) {
if (tries++ < 20) {
continue;
}
wait = 1;
break;
}
if (!fcn->exists) {
ngx_queue_remove(q);
ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
ngx_slab_free_locked(cache->shpool, fcn);
break;
}
ngx_http_file_cache_delete(cache, q, name);
break;
}
ngx_shmtx_unlock(&cache->shpool->mutex);
ngx_free(name);
return wait;
}
static time_t
ngx_http_file_cache_expire(ngx_http_file_cache_t *cache)
{
u_char *name, *p;
size_t len;
time_t now, wait;
ngx_path_t *path;
ngx_queue_t *q;
ngx_http_file_cache_node_t *fcn;
u_char key[2 * NGX_HTTP_CACHE_KEY_LEN];
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
"http file cache expire");
path = cache->path;
len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN;
name = ngx_alloc(len + 1, ngx_cycle->log);
if (name == NULL) {
return 10;
}
ngx_memcpy(name, path->name.data, path->name.len);
now = ngx_time();
ngx_shmtx_lock(&cache->shpool->mutex);
for ( ;; ) {
if (ngx_queue_empty(&cache->sh->queue)) {
wait = 10;
break;
}
q = ngx_queue_last(&cache->sh->queue);
fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue);
wait = fcn->expire - now;
if (wait > 0) {
wait = wait > 10 ? 10 : wait;
break;
}
ngx_log_debug6(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
"http file cache expire: #%d %d %02xd%02xd%02xd%02xd",
fcn->count, fcn->exists,
fcn->key[0], fcn->key[1], fcn->key[2], fcn->key[3]);
if (fcn->count) {
p = ngx_hex_dump(key, (u_char *) &fcn->node.key,
sizeof(ngx_rbtree_key_t));
len = NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t);
(void) ngx_hex_dump(p, fcn->key, len);
/*
* abnormally exited workers may leave locked cache entries,
* and although it may be safe to remove them completely,
* we prefer to remove them from inactive queue and rbtree
* only, and to allow other leaks
*/
ngx_queue_remove(q);
ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
"ignore long locked inactive cache entry %*s, count:%d",
2 * NGX_HTTP_CACHE_KEY_LEN, key, fcn->count);
continue;
}
if (!fcn->exists) {
ngx_queue_remove(q);
ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
ngx_slab_free_locked(cache->shpool, fcn);
continue;
}
ngx_http_file_cache_delete(cache, q, name);
}
ngx_shmtx_unlock(&cache->shpool->mutex);
ngx_free(name);
return wait;
}
static void
ngx_http_file_cache_delete(ngx_http_file_cache_t *cache, ngx_queue_t *q,
u_char *name)
{
u_char *p;
size_t len;
ngx_path_t *path;
ngx_http_file_cache_node_t *fcn;
fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue);
cache->sh->size -= (fcn->length + cache->bsize - 1) / cache->bsize;
path = cache->path;
p = name + path->name.len + 1 + path->len;
p = ngx_hex_dump(p, (u_char *) &fcn->node.key, sizeof(ngx_rbtree_key_t));
len = NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t);
p = ngx_hex_dump(p, fcn->key, len);
*p = '\0';
ngx_queue_remove(q);
ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
ngx_slab_free_locked(cache->shpool, fcn);
ngx_shmtx_unlock(&cache->shpool->mutex);
len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN;
ngx_create_hashed_filename(path, name, len);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
"http file cache expire: \"%s\"", name);
if (ngx_delete_file(name) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, ngx_errno,
ngx_delete_file_n " \"%s\" failed", name);
}
ngx_shmtx_lock(&cache->shpool->mutex);
}
static time_t
ngx_http_file_cache_manager(void *data)
{
ngx_http_file_cache_t *cache = data;
off_t size;
time_t next;
next = ngx_http_file_cache_expire(cache);
cache->last = ngx_current_msec;
cache->files = 0;
for ( ;; ) {
ngx_shmtx_lock(&cache->shpool->mutex);
size = cache->sh->size;
ngx_shmtx_unlock(&cache->shpool->mutex);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
"http file cache size: %O", size);
if (size < cache->max_size) {
return next;
}
next = ngx_http_file_cache_forced_expire(cache);
if (ngx_http_file_cache_manager_sleep(cache) != NGX_OK) {
return next;
}
}
}
static void
ngx_http_file_cache_loader(void *data)
{
ngx_http_file_cache_t *cache = data;
ngx_tree_ctx_t tree;
if (!cache->sh->cold || cache->sh->loading) {
return;
}
if (!ngx_atomic_cmp_set(&cache->sh->loading, 0, ngx_pid)) {
return;
}
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
"http file cache loader");
tree.init_handler = NULL;
tree.file_handler = ngx_http_file_cache_manage_file;
tree.pre_tree_handler = ngx_http_file_cache_noop;
tree.post_tree_handler = ngx_http_file_cache_noop;
tree.spec_handler = ngx_http_file_cache_delete_file;
tree.data = cache;
tree.alloc = 0;
tree.log = ngx_cycle->log;
cache->last = ngx_current_msec;
cache->files = 0;
if (ngx_walk_tree(&tree, &cache->path->name) == NGX_ABORT) {
cache->sh->loading = 0;
return;
}
cache->sh->cold = 0;
cache->sh->loading = 0;
ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
"http file cache: %V %.3fM, bsize: %uz",
&cache->path->name,
((double) cache->sh->size * cache->bsize) / (1024 * 1024),
cache->bsize);
}
static ngx_int_t
ngx_http_file_cache_manager_sleep(ngx_http_file_cache_t *cache)
{
ngx_msec_t elapsed;
if (cache->files++ > 100) {
ngx_time_update();
elapsed = ngx_abs((ngx_msec_int_t) (ngx_current_msec - cache->last));
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
"http file cache manager time: %M", elapsed);
if (elapsed > 200) {
/*
* if processing 100 files takes more than 200ms,
* it seems that many operations require disk i/o,
* therefore sleep 200ms
*/
ngx_msleep(200);
ngx_time_update();
}
cache->last = ngx_current_msec;
cache->files = 0;
}
return (ngx_quit || ngx_terminate) ? NGX_ABORT : NGX_OK;
}
static ngx_int_t
ngx_http_file_cache_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path)
{
return NGX_OK;
}
static ngx_int_t
ngx_http_file_cache_manage_file(ngx_tree_ctx_t *ctx, ngx_str_t *path)
{
ngx_http_file_cache_t *cache;
cache = ctx->data;
if (ngx_http_file_cache_add_file(ctx, path) != NGX_OK) {
(void) ngx_http_file_cache_delete_file(ctx, path);
}
return ngx_http_file_cache_manager_sleep(cache);
}
static ngx_int_t
ngx_http_file_cache_add_file(ngx_tree_ctx_t *ctx, ngx_str_t *name)
{
u_char *p;
ngx_fd_t fd;
ngx_int_t n;
ngx_uint_t i;
ngx_file_info_t fi;
ngx_http_cache_t c;
ngx_http_file_cache_t *cache;
ngx_http_file_cache_header_t h;
if (name->len < 2 * NGX_HTTP_CACHE_KEY_LEN) {
return NGX_ERROR;
}
ngx_memzero(&c, sizeof(ngx_http_cache_t));
fd = ngx_open_file(name->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
if (fd == NGX_INVALID_FILE) {
ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
ngx_open_file_n " \"%s\" failed", name->data);
return NGX_ERROR;
}
c.file.fd = fd;
c.file.name = *name;
c.file.log = ctx->log;
n = ngx_read_file(&c.file, (u_char *) &h,
sizeof(ngx_http_file_cache_header_t), 0);
if (n == NGX_ERROR) {
return NGX_ERROR;
}
if ((size_t) n < sizeof(ngx_http_file_cache_header_t)) {
ngx_log_error(NGX_LOG_CRIT, ctx->log, 0,
"cache file \"%s\" is too small", name->data);
return NGX_ERROR;
}
if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
ngx_fd_info_n " \"%s\" failed", name->data);
} else {
c.uniq = ngx_file_uniq(&fi);
c.valid_sec = h.valid_sec;
c.valid_msec = h.valid_msec;
c.body_start = h.body_start;
c.length = ngx_file_size(&fi);
}
if (ngx_close_file(fd) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
ngx_close_file_n " \"%s\" failed", name->data);
}
if (c.body_start == 0) {
return NGX_ERROR;
}
p = &name->data[name->len - 2 * NGX_HTTP_CACHE_KEY_LEN];
for (i = 0; i < NGX_HTTP_CACHE_KEY_LEN; i++) {
n = ngx_hextoi(p, 2);
if (n == NGX_ERROR) {
return NGX_ERROR;
}
p += 2;
c.key[i] = (u_char) n;
}
cache = ctx->data;
return ngx_http_file_cache_add(cache, &c);
}
static ngx_int_t
ngx_http_file_cache_add(ngx_http_file_cache_t *cache, ngx_http_cache_t *c)
{
ngx_http_file_cache_node_t *fcn;
ngx_shmtx_lock(&cache->shpool->mutex);
fcn = ngx_http_file_cache_lookup(cache, c->key);
if (fcn == NULL) {
fcn = ngx_slab_alloc_locked(cache->shpool,
sizeof(ngx_http_file_cache_node_t));
if (fcn == NULL) {
ngx_shmtx_unlock(&cache->shpool->mutex);
return NGX_ERROR;
}
ngx_memcpy((u_char *) &fcn->node.key, c->key, sizeof(ngx_rbtree_key_t));
ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)],
NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t));
ngx_rbtree_insert(&cache->sh->rbtree, &fcn->node);
fcn->uses = 1;
fcn->count = 0;
fcn->valid_msec = c->valid_msec;
fcn->error = 0;
fcn->exists = 1;
fcn->uniq = c->uniq;
fcn->valid_sec = c->valid_sec;
fcn->body_start = c->body_start;
fcn->length = c->length;
cache->sh->size += (c->length + cache->bsize - 1) / cache->bsize;
} else {
ngx_queue_remove(&fcn->queue);
}
fcn->expire = ngx_time() + cache->inactive;
ngx_queue_insert_head(&cache->sh->queue, &fcn->queue);
ngx_shmtx_unlock(&cache->shpool->mutex);
return NGX_OK;
}
static ngx_int_t
ngx_http_file_cache_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path)
{
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
"http file cache delete: \"%s\"", path->data);
if (ngx_delete_file(path->data) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
ngx_delete_file_n " \"%s\" failed", path->data);
}
return NGX_OK;
}
time_t
ngx_http_file_cache_valid(ngx_array_t *cache_valid, ngx_uint_t status)
{
ngx_uint_t i;
ngx_http_cache_valid_t *valid;
if (cache_valid == NULL) {
return 0;
}
valid = cache_valid->elts;
for (i = 0; i < cache_valid->nelts; i++) {
if (valid[i].status == 0) {
return valid[i].valid;
}
if (valid[i].status == status) {
return valid[i].valid;
}
}
return 0;
}
char *
ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
off_t max_size;
u_char *last, *p;
time_t inactive;
ssize_t size;
ngx_str_t s, name, *value;
ngx_uint_t i, n;
ngx_http_file_cache_t *cache;
cache = ngx_pcalloc(cf->pool, sizeof(ngx_http_file_cache_t));
if (cache == NULL) {
return NGX_CONF_ERROR;
}
cache->path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t));
if (cache->path == NULL) {
return NGX_CONF_ERROR;
}
inactive = 600;
name.len = 0;
size = 0;
max_size = NGX_MAX_OFF_T_VALUE;
value = cf->args->elts;
cache->path->name = value[1];
if (cache->path->name.data[cache->path->name.len - 1] == '/') {
cache->path->name.len--;
}
if (ngx_conf_full_name(cf->cycle, &cache->path->name, 0) != NGX_OK) {
return NGX_CONF_ERROR;
}
for (i = 2; i < cf->args->nelts; i++) {
if (ngx_strncmp(value[i].data, "levels=", 7) == 0) {
p = value[i].data + 7;
last = value[i].data + value[i].len;
for (n = 0; n < 3 && p < last; n++) {
if (*p > '0' && *p < '3') {
cache->path->level[n] = *p++ - '0';
cache->path->len += cache->path->level[n] + 1;
if (p == last) {
break;
}
if (*p++ == ':' && n < 2 && p != last) {
continue;
}
goto invalid_levels;
}
goto invalid_levels;
}
if (cache->path->len < 10 + 3) {
continue;
}
invalid_levels:
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid \"levels\" \"%V\"", &value[i]);
return NGX_CONF_ERROR;
}
if (ngx_strncmp(value[i].data, "keys_zone=", 10) == 0) {
name.data = value[i].data + 10;
p = (u_char *) ngx_strchr(name.data, ':');
if (p) {
*p = '\0';
name.len = p - name.data;
p++;
s.len = value[i].data + value[i].len - p;
s.data = p;
size = ngx_parse_size(&s);
if (size > 8191) {
continue;
}
}
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid keys zone size \"%V\"", &value[i]);
return NGX_CONF_ERROR;
}
if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {
s.len = value[i].len - 9;
s.data = value[i].data + 9;
inactive = ngx_parse_time(&s, 1);
if (inactive < 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid inactive value \"%V\"", &value[i]);
return NGX_CONF_ERROR;
}
continue;
}
if (ngx_strncmp(value[i].data, "max_size=", 9) == 0) {
s.len = value[i].len - 9;
s.data = value[i].data + 9;
max_size = ngx_parse_offset(&s);
if (max_size < 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid max_size value \"%V\"", &value[i]);
return NGX_CONF_ERROR;
}
continue;
}
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid parameter \"%V\"", &value[i]);
return NGX_CONF_ERROR;
}
if (name.len == 0 || size == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"%V\" must have \"keys_zone\" parameter",
&cmd->name);
return NGX_CONF_ERROR;
}
cache->path->manager = ngx_http_file_cache_manager;
cache->path->loader = ngx_http_file_cache_loader;
cache->path->data = cache;
if (ngx_add_path(cf, &cache->path) != NGX_OK) {
return NGX_CONF_ERROR;
}
cache->shm_zone = ngx_shared_memory_add(cf, &name, size, cmd->post);
if (cache->shm_zone == NULL) {
return NGX_CONF_ERROR;
}
if (cache->shm_zone->data) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"duplicate zone \"%V\"", &name);
return NGX_CONF_ERROR;
}
cache->shm_zone->init = ngx_http_file_cache_init;
cache->shm_zone->data = cache;
cache->inactive = inactive;
cache->max_size = max_size;
return NGX_CONF_OK;
}
char *
ngx_http_file_cache_valid_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf)
{
char *p = conf;
time_t valid;
ngx_str_t *value;
ngx_uint_t i, n, status;
ngx_array_t **a;
ngx_http_cache_valid_t *v;
static ngx_uint_t statuses[] = { 200, 301, 302 };
a = (ngx_array_t **) (p + cmd->offset);
if (*a == NGX_CONF_UNSET_PTR) {
*a = ngx_array_create(cf->pool, 1, sizeof(ngx_http_cache_valid_t));
if (*a == NULL) {
return NGX_CONF_ERROR;
}
}
value = cf->args->elts;
n = cf->args->nelts - 1;
valid = ngx_parse_time(&value[n], 1);
if (valid < 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid time value \"%V\"", &value[n]);
return NGX_CONF_ERROR;
}
if (n == 1) {
for (i = 0; i < 3; i++) {
v = ngx_array_push(*a);
if (v == NULL) {
return NGX_CONF_ERROR;
}
v->status = statuses[i];
v->valid = valid;
}
return NGX_CONF_OK;
}
for (i = 1; i < n; i++) {
if (ngx_strcmp(value[i].data, "any") == 0) {
status = 0;
} else {
status = ngx_atoi(value[i].data, value[i].len);
if (status < 100) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid status \"%V\"", &value[i]);
return NGX_CONF_ERROR;
}
}
v = ngx_array_push(*a);
if (v == NULL) {
return NGX_CONF_ERROR;
}
v->status = status;
v->valid = valid;
}
return NGX_CONF_OK;
}
ngx_int_t
ngx_http_cache(ngx_http_request_t *r, ngx_array_t *no_cache)
{
ngx_str_t val;
ngx_uint_t i;
ngx_http_complex_value_t *cv;
cv = no_cache->elts;
for (i = 0; i < no_cache->nelts; i++) {
if (ngx_http_complex_value(r, &cv[i], &val) != NGX_OK) {
return NGX_ERROR;
}
if (val.len && val.data[0] != '0') {
return NGX_DECLINED;
}
}
return NGX_OK;
}
char *
ngx_http_no_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
char *p = conf;
ngx_str_t *value;
ngx_uint_t i;
ngx_array_t **a;
ngx_http_complex_value_t *cv;
ngx_http_compile_complex_value_t ccv;
a = (ngx_array_t **) (p + cmd->offset);
if (*a == NGX_CONF_UNSET_PTR) {
*a = ngx_array_create(cf->pool, 1, sizeof(ngx_http_complex_value_t));
if (*a == NULL) {
return NGX_CONF_ERROR;
}
}
value = cf->args->elts;
for (i = 1; i < cf->args->nelts; i++) {
cv = ngx_array_push(*a);
if (cv == NULL) {
return NGX_CONF_ERROR;
}
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
ccv.cf = cf;
ccv.value = &value[i];
ccv.complex_value = cv;
if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
return NGX_CONF_ERROR;
}
}
return NGX_CONF_OK;
}
nginx-0.7.68/src/http/ngx_http_core_module.h 000644 001750 001750 00000036640 11403134616 020166 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#ifndef _NGX_HTTP_CORE_H_INCLUDED_
#define _NGX_HTTP_CORE_H_INCLUDED_
#include
#include
#include
#define NGX_HTTP_GZIP_PROXIED_OFF 0x0002
#define NGX_HTTP_GZIP_PROXIED_EXPIRED 0x0004
#define NGX_HTTP_GZIP_PROXIED_NO_CACHE 0x0008
#define NGX_HTTP_GZIP_PROXIED_NO_STORE 0x0010
#define NGX_HTTP_GZIP_PROXIED_PRIVATE 0x0020
#define NGX_HTTP_GZIP_PROXIED_NO_LM 0x0040
#define NGX_HTTP_GZIP_PROXIED_NO_ETAG 0x0080
#define NGX_HTTP_GZIP_PROXIED_AUTH 0x0100
#define NGX_HTTP_GZIP_PROXIED_ANY 0x0200
#define NGX_HTTP_SATISFY_ALL 0
#define NGX_HTTP_SATISFY_ANY 1
#define NGX_HTTP_IMS_OFF 0
#define NGX_HTTP_IMS_EXACT 1
#define NGX_HTTP_IMS_BEFORE 2
typedef struct ngx_http_location_tree_node_s ngx_http_location_tree_node_t;
typedef struct ngx_http_core_loc_conf_s ngx_http_core_loc_conf_t;
typedef struct {
unsigned default_server:1;
unsigned bind:1;
unsigned wildcard:1;
#if (NGX_HTTP_SSL)
unsigned ssl:1;
#endif
#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
unsigned ipv6only:2;
#endif
int backlog;
int rcvbuf;
int sndbuf;
#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
char *accept_filter;
#endif
#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
ngx_uint_t deferred_accept;
#endif
u_char addr[NGX_SOCKADDR_STRLEN + 1];
} ngx_http_listen_conf_t;
typedef struct {
u_char sockaddr[NGX_SOCKADDRLEN];
socklen_t socklen;
u_char *file_name;
ngx_uint_t line;
ngx_http_listen_conf_t conf;
} ngx_http_listen_t;
typedef enum {
NGX_HTTP_POST_READ_PHASE = 0,
NGX_HTTP_SERVER_REWRITE_PHASE,
NGX_HTTP_FIND_CONFIG_PHASE,
NGX_HTTP_REWRITE_PHASE,
NGX_HTTP_POST_REWRITE_PHASE,
NGX_HTTP_PREACCESS_PHASE,
NGX_HTTP_ACCESS_PHASE,
NGX_HTTP_POST_ACCESS_PHASE,
NGX_HTTP_TRY_FILES_PHASE,
NGX_HTTP_CONTENT_PHASE,
NGX_HTTP_LOG_PHASE
} ngx_http_phases;
typedef struct ngx_http_phase_handler_s ngx_http_phase_handler_t;
typedef ngx_int_t (*ngx_http_phase_handler_pt)(ngx_http_request_t *r,
ngx_http_phase_handler_t *ph);
struct ngx_http_phase_handler_s {
ngx_http_phase_handler_pt checker;
ngx_http_handler_pt handler;
ngx_uint_t next;
};
typedef struct {
ngx_http_phase_handler_t *handlers;
ngx_uint_t server_rewrite_index;
ngx_uint_t location_rewrite_index;
} ngx_http_phase_engine_t;
typedef struct {
ngx_array_t handlers;
} ngx_http_phase_t;
typedef struct {
ngx_array_t servers; /* ngx_http_core_srv_conf_t */
ngx_http_phase_engine_t phase_engine;
ngx_hash_t headers_in_hash;
ngx_hash_t variables_hash;
ngx_array_t variables; /* ngx_http_variable_t */
ngx_uint_t server_names_hash_max_size;
ngx_uint_t server_names_hash_bucket_size;
ngx_uint_t variables_hash_max_size;
ngx_uint_t variables_hash_bucket_size;
ngx_hash_keys_arrays_t *variables_keys;
ngx_uint_t try_files; /* unsigned try_files:1 */
ngx_http_phase_t phases[NGX_HTTP_LOG_PHASE + 1];
} ngx_http_core_main_conf_t;
typedef struct {
/* array of the ngx_http_listen_t, "listen" directive */
ngx_array_t listen;
/* array of the ngx_http_server_name_t, "server_name" directive */
ngx_array_t server_names;
/* server ctx */
ngx_http_conf_ctx_t *ctx;
ngx_str_t server_name;
size_t connection_pool_size;
size_t request_pool_size;
size_t client_header_buffer_size;
ngx_bufs_t large_client_header_buffers;
ngx_msec_t client_header_timeout;
ngx_flag_t ignore_invalid_headers;
ngx_flag_t merge_slashes;
ngx_flag_t underscores_in_headers;
ngx_http_core_loc_conf_t **named_locations;
} ngx_http_core_srv_conf_t;
/* list of structures to find core_srv_conf quickly at run time */
typedef struct {
/* the default server configuration for this address:port */
ngx_http_core_srv_conf_t *core_srv_conf;
ngx_http_virtual_names_t *virtual_names;
#if (NGX_HTTP_SSL)
ngx_uint_t ssl; /* unsigned ssl:1; */
#endif
} ngx_http_addr_conf_t;
typedef struct {
in_addr_t addr;
ngx_http_addr_conf_t conf;
} ngx_http_in_addr_t;
#if (NGX_HAVE_INET6)
typedef struct {
struct in6_addr addr6;
ngx_http_addr_conf_t conf;
} ngx_http_in6_addr_t;
#endif
typedef struct {
/* ngx_http_in_addr_t or ngx_http_in6_addr_t */
void *addrs;
ngx_uint_t naddrs;
} ngx_http_port_t;
typedef struct {
ngx_int_t family;
in_port_t port;
ngx_array_t addrs; /* array of ngx_http_conf_addr_t */
} ngx_http_conf_port_t;
typedef struct {
struct sockaddr *sockaddr;
socklen_t socklen;
ngx_hash_t hash;
ngx_hash_wildcard_t *wc_head;
ngx_hash_wildcard_t *wc_tail;
ngx_array_t names; /* array of ngx_http_server_name_t */
#if (NGX_PCRE)
ngx_uint_t nregex;
ngx_http_server_name_t *regex;
#endif
/* the default server configuration for this address:port */
ngx_http_core_srv_conf_t *core_srv_conf;
unsigned default_server:1;
unsigned bind:1;
unsigned wildcard:1;
#if (NGX_HTTP_SSL)
unsigned ssl:1;
#endif
ngx_http_listen_conf_t *listen_conf;
} ngx_http_conf_addr_t;
struct ngx_http_server_name_s {
#if (NGX_PCRE)
ngx_regex_t *regex;
ngx_uint_t captures; /* unsigned captures:1; */
#endif
ngx_http_core_srv_conf_t *core_srv_conf; /* virtual name server conf */
ngx_str_t name;
};
typedef struct {
ngx_int_t status;
ngx_int_t overwrite;
ngx_http_complex_value_t value;
ngx_str_t args;
} ngx_http_err_page_t;
typedef struct {
ngx_array_t *lengths;
ngx_array_t *values;
ngx_str_t name;
unsigned code:10;
unsigned test_dir:1;
} ngx_http_try_file_t;
struct ngx_http_core_loc_conf_s {
ngx_str_t name; /* location name */
#if (NGX_PCRE)
ngx_regex_t *regex;
unsigned captures:1;
#endif
unsigned noname:1; /* "if () {}" block or limit_except */
unsigned named:1;
unsigned exact_match:1;
unsigned noregex:1;
unsigned auto_redirect:1;
unsigned alias:1;
#if (NGX_HTTP_GZIP)
unsigned gzip_disable_msie6:2;
#endif
ngx_http_location_tree_node_t *static_locations;
#if (NGX_PCRE)
ngx_http_core_loc_conf_t **regex_locations;
#endif
/* pointer to the modules' loc_conf */
void **loc_conf;
uint32_t limit_except;
void **limit_except_loc_conf;
ngx_http_handler_pt handler;
ngx_str_t root; /* root, alias */
ngx_str_t post_action;
ngx_array_t *root_lengths;
ngx_array_t *root_values;
ngx_array_t *types;
ngx_hash_t types_hash;
ngx_str_t default_type;
off_t client_max_body_size; /* client_max_body_size */
off_t directio; /* directio */
size_t client_body_buffer_size; /* client_body_buffer_size */
size_t send_lowat; /* send_lowat */
size_t postpone_output; /* postpone_output */
size_t limit_rate; /* limit_rate */
size_t limit_rate_after; /* limit_rate_after */
size_t sendfile_max_chunk; /* sendfile_max_chunk */
ngx_msec_t client_body_timeout; /* client_body_timeout */
ngx_msec_t send_timeout; /* send_timeout */
ngx_msec_t keepalive_timeout; /* keepalive_timeout */
ngx_msec_t lingering_time; /* lingering_time */
ngx_msec_t lingering_timeout; /* lingering_timeout */
ngx_msec_t resolver_timeout; /* resolver_timeout */
ngx_resolver_t *resolver; /* resolver */
time_t keepalive_header; /* keepalive_timeout */
ngx_uint_t keepalive_requests; /* keepalive_requests */
ngx_uint_t satisfy; /* satisfy */
ngx_uint_t if_modified_since; /* if_modified_since */
ngx_uint_t client_body_in_file_only; /* client_body_in_file_only */
ngx_flag_t client_body_in_single_buffer;
/* client_body_in_singe_buffer */
ngx_flag_t internal; /* internal */
ngx_flag_t sendfile; /* sendfile */
ngx_flag_t tcp_nopush; /* tcp_nopush */
ngx_flag_t tcp_nodelay; /* tcp_nodelay */
ngx_flag_t reset_timedout_connection; /* reset_timedout_connection */
ngx_flag_t server_name_in_redirect; /* server_name_in_redirect */
ngx_flag_t port_in_redirect; /* port_in_redirect */
ngx_flag_t msie_padding; /* msie_padding */
ngx_flag_t msie_refresh; /* msie_refresh */
ngx_flag_t log_not_found; /* log_not_found */
ngx_flag_t log_subrequest; /* log_subrequest */
ngx_flag_t recursive_error_pages; /* recursive_error_pages */
ngx_flag_t server_tokens; /* server_tokens */
ngx_flag_t chunked_transfer_encoding; /* chunked_transfer_encoding */
#if (NGX_HTTP_GZIP)
ngx_flag_t gzip_vary; /* gzip_vary */
ngx_uint_t gzip_http_version; /* gzip_http_version */
ngx_uint_t gzip_proxied; /* gzip_proxied */
#if (NGX_PCRE)
ngx_array_t *gzip_disable; /* gzip_disable */
#endif
#endif
ngx_array_t *error_pages; /* error_page */
ngx_http_try_file_t *try_files; /* try_files */
ngx_path_t *client_body_temp_path; /* client_body_temp_path */
ngx_open_file_cache_t *open_file_cache;
time_t open_file_cache_valid;
ngx_uint_t open_file_cache_min_uses;
ngx_flag_t open_file_cache_errors;
ngx_flag_t open_file_cache_events;
ngx_log_t *error_log;
ngx_uint_t types_hash_max_size;
ngx_uint_t types_hash_bucket_size;
ngx_queue_t *locations;
#if 0
ngx_http_core_loc_conf_t *prev_location;
#endif
};
typedef struct {
ngx_queue_t queue;
ngx_http_core_loc_conf_t *exact;
ngx_http_core_loc_conf_t *inclusive;
ngx_str_t *name;
u_char *file_name;
ngx_uint_t line;
ngx_queue_t list;
} ngx_http_location_queue_t;
struct ngx_http_location_tree_node_s {
ngx_http_location_tree_node_t *left;
ngx_http_location_tree_node_t *right;
ngx_http_location_tree_node_t *tree;
ngx_http_core_loc_conf_t *exact;
ngx_http_core_loc_conf_t *inclusive;
u_char auto_redirect;
u_char len;
u_char name[1];
};
void ngx_http_core_run_phases(ngx_http_request_t *r);
ngx_int_t ngx_http_core_generic_phase(ngx_http_request_t *r,
ngx_http_phase_handler_t *ph);
ngx_int_t ngx_http_core_find_config_phase(ngx_http_request_t *r,
ngx_http_phase_handler_t *ph);
ngx_int_t ngx_http_core_post_rewrite_phase(ngx_http_request_t *r,
ngx_http_phase_handler_t *ph);
ngx_int_t ngx_http_core_access_phase(ngx_http_request_t *r,
ngx_http_phase_handler_t *ph);
ngx_int_t ngx_http_core_post_access_phase(ngx_http_request_t *r,
ngx_http_phase_handler_t *ph);
ngx_int_t ngx_http_core_try_files_phase(ngx_http_request_t *r,
ngx_http_phase_handler_t *ph);
ngx_int_t ngx_http_core_content_phase(ngx_http_request_t *r,
ngx_http_phase_handler_t *ph);
void *ngx_http_test_content_type(ngx_http_request_t *r, ngx_hash_t *types_hash);
ngx_int_t ngx_http_set_content_type(ngx_http_request_t *r);
void ngx_http_set_exten(ngx_http_request_t *r);
u_char *ngx_http_map_uri_to_path(ngx_http_request_t *r, ngx_str_t *name,
size_t *root_length, size_t reserved);
ngx_int_t ngx_http_auth_basic_user(ngx_http_request_t *r);
#if (NGX_HTTP_GZIP)
ngx_int_t ngx_http_gzip_ok(ngx_http_request_t *r);
#endif
ngx_int_t ngx_http_subrequest(ngx_http_request_t *r,
ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **sr,
ngx_http_post_subrequest_t *psr, ngx_uint_t flags);
ngx_int_t ngx_http_internal_redirect(ngx_http_request_t *r,
ngx_str_t *uri, ngx_str_t *args);
ngx_int_t ngx_http_named_location(ngx_http_request_t *r, ngx_str_t *name);
ngx_http_cleanup_t *ngx_http_cleanup_add(ngx_http_request_t *r, size_t size);
typedef ngx_int_t (*ngx_http_output_header_filter_pt)(ngx_http_request_t *r);
typedef ngx_int_t (*ngx_http_output_body_filter_pt)
(ngx_http_request_t *r, ngx_chain_t *chain);
ngx_int_t ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *chain);
ngx_int_t ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *chain);
extern ngx_module_t ngx_http_core_module;
extern ngx_uint_t ngx_http_max_module;
extern ngx_str_t ngx_http_core_get_method;
#define ngx_http_clear_content_length(r) \
\
r->headers_out.content_length_n = -1; \
if (r->headers_out.content_length) { \
r->headers_out.content_length->hash = 0; \
r->headers_out.content_length = NULL; \
}
\
#define ngx_http_clear_accept_ranges(r) \
\
r->allow_ranges = 0; \
if (r->headers_out.accept_ranges) { \
r->headers_out.accept_ranges->hash = 0; \
r->headers_out.accept_ranges = NULL; \
}
#define ngx_http_clear_last_modified(r) \
\
r->headers_out.last_modified_time = -1; \
if (r->headers_out.last_modified) { \
r->headers_out.last_modified->hash = 0; \
r->headers_out.last_modified = NULL; \
}
#endif /* _NGX_HTTP_CORE_H_INCLUDED_ */
nginx-0.7.68/src/http/ngx_http_script.c 000644 001750 001750 00000116473 11331562676 017206 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#include
#include
#include
static ngx_int_t ngx_http_script_init_arrays(ngx_http_script_compile_t *sc);
static ngx_int_t ngx_http_script_done(ngx_http_script_compile_t *sc);
static ngx_int_t ngx_http_script_add_copy_code(ngx_http_script_compile_t *sc,
ngx_str_t *value, ngx_uint_t last);
static ngx_int_t ngx_http_script_add_var_code(ngx_http_script_compile_t *sc,
ngx_str_t *name);
static ngx_int_t ngx_http_script_add_args_code(ngx_http_script_compile_t *sc);
#if (NGX_PCRE)
static ngx_int_t ngx_http_script_add_capture_code(ngx_http_script_compile_t *sc,
ngx_uint_t n);
#endif
static ngx_int_t
ngx_http_script_add_full_name_code(ngx_http_script_compile_t *sc);
static size_t ngx_http_script_full_name_len_code(ngx_http_script_engine_t *e);
static void ngx_http_script_full_name_code(ngx_http_script_engine_t *e);
#define ngx_http_script_exit (u_char *) &ngx_http_script_exit_code
static uintptr_t ngx_http_script_exit_code = (uintptr_t) NULL;
void
ngx_http_script_flush_complex_value(ngx_http_request_t *r,
ngx_http_complex_value_t *val)
{
ngx_uint_t *index;
index = val->flushes;
if (index) {
while (*index != (ngx_uint_t) -1) {
if (r->variables[*index].no_cacheable) {
r->variables[*index].valid = 0;
r->variables[*index].not_found = 0;
}
index++;
}
}
}
ngx_int_t
ngx_http_complex_value(ngx_http_request_t *r, ngx_http_complex_value_t *val,
ngx_str_t *value)
{
size_t len;
ngx_http_script_code_pt code;
ngx_http_script_len_code_pt lcode;
ngx_http_script_engine_t e;
if (val->lengths == NULL) {
*value = val->value;
return NGX_OK;
}
ngx_http_script_flush_complex_value(r, val);
ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
e.ip = val->lengths;
e.request = r;
e.flushed = 1;
len = 0;
while (*(uintptr_t *) e.ip) {
lcode = *(ngx_http_script_len_code_pt *) e.ip;
len += lcode(&e);
}
value->len = len;
value->data = ngx_pnalloc(r->pool, len);
if (value->data == NULL) {
return NGX_ERROR;
}
e.ip = val->values;
e.pos = value->data;
e.buf = *value;
while (*(uintptr_t *) e.ip) {
code = *(ngx_http_script_code_pt *) e.ip;
code((ngx_http_script_engine_t *) &e);
}
*value = e.buf;
return NGX_OK;
}
ngx_int_t
ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv)
{
ngx_str_t *v;
ngx_uint_t i, n, nv, nc;
ngx_array_t flushes, lengths, values, *pf, *pl, *pv;
ngx_http_script_compile_t sc;
v = ccv->value;
if (v->len == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, ccv->cf, 0, "empty parameter");
return NGX_ERROR;
}
nv = 0;
nc = 0;
for (i = 0; i < v->len; i++) {
if (v->data[i] == '$') {
if (v->data[i + 1] >= '1' && v->data[i + 1] <= '9') {
nc++;
} else {
nv++;
}
}
}
if (v->data[0] != '$' && (ccv->conf_prefix || ccv->root_prefix)) {
if (ngx_conf_full_name(ccv->cf->cycle, v, ccv->conf_prefix) != NGX_OK) {
return NGX_ERROR;
}
ccv->conf_prefix = 0;
ccv->root_prefix = 0;
}
ccv->complex_value->value = *v;
ccv->complex_value->flushes = NULL;
ccv->complex_value->lengths = NULL;
ccv->complex_value->values = NULL;
if (nv == 0 && nc == 0) {
return NGX_OK;
}
n = nv + 1;
if (ngx_array_init(&flushes, ccv->cf->pool, n, sizeof(ngx_uint_t))
!= NGX_OK)
{
return NGX_ERROR;
}
n = nv * (2 * sizeof(ngx_http_script_copy_code_t)
+ sizeof(ngx_http_script_var_code_t))
+ sizeof(uintptr_t);
if (ngx_array_init(&lengths, ccv->cf->pool, n, 1) != NGX_OK) {
return NGX_ERROR;
}
n = (nv * (2 * sizeof(ngx_http_script_copy_code_t)
+ sizeof(ngx_http_script_var_code_t))
+ sizeof(uintptr_t)
+ v->len
+ sizeof(uintptr_t) - 1)
& ~(sizeof(uintptr_t) - 1);
if (ngx_array_init(&values, ccv->cf->pool, n, 1) != NGX_OK) {
return NGX_ERROR;
}
pf = &flushes;
pl = &lengths;
pv = &values;
ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
sc.cf = ccv->cf;
sc.source = v;
sc.flushes = &pf;
sc.lengths = &pl;
sc.values = &pv;
sc.complete_lengths = 1;
sc.complete_values = 1;
sc.zero = ccv->zero;
sc.conf_prefix = ccv->conf_prefix;
sc.root_prefix = ccv->root_prefix;
if (ngx_http_script_compile(&sc) != NGX_OK) {
return NGX_ERROR;
}
if (flushes.nelts) {
ccv->complex_value->flushes = flushes.elts;
ccv->complex_value->flushes[flushes.nelts] = (ngx_uint_t) -1;
}
ccv->complex_value->lengths = lengths.elts;
ccv->complex_value->values = values.elts;
return NGX_OK;
}
ngx_uint_t
ngx_http_script_variables_count(ngx_str_t *value)
{
ngx_uint_t i, n;
for (n = 0, i = 0; i < value->len; i++) {
if (value->data[i] == '$') {
n++;
}
}
return n;
}
ngx_int_t
ngx_http_script_compile(ngx_http_script_compile_t *sc)
{
u_char ch;
ngx_str_t name;
ngx_uint_t i, bracket;
if (ngx_http_script_init_arrays(sc) != NGX_OK) {
return NGX_ERROR;
}
for (i = 0; i < sc->source->len; /* void */ ) {
name.len = 0;
if (sc->source->data[i] == '$') {
if (++i == sc->source->len) {
goto invalid_variable;
}
#if (NGX_PCRE)
{
ngx_uint_t n;
/* NGX_HTTP_MAX_CAPTURES is 9 */
if (sc->source->data[i] >= '1' && sc->source->data[i] <= '9') {
n = sc->source->data[i] - '0';
if (sc->captures_mask & (1 << n)) {
sc->dup_capture = 1;
}
sc->captures_mask |= 1 << n;
if (ngx_http_script_add_capture_code(sc, n) != NGX_OK) {
return NGX_ERROR;
}
i++;
continue;
}
}
#endif
if (sc->source->data[i] == '{') {
bracket = 1;
if (++i == sc->source->len) {
goto invalid_variable;
}
name.data = &sc->source->data[i];
} else {
bracket = 0;
name.data = &sc->source->data[i];
}
for ( /* void */ ; i < sc->source->len; i++, name.len++) {
ch = sc->source->data[i];
if (ch == '}' && bracket) {
i++;
bracket = 0;
break;
}
if ((ch >= 'A' && ch <= 'Z')
|| (ch >= 'a' && ch <= 'z')
|| (ch >= '0' && ch <= '9')
|| ch == '_')
{
continue;
}
break;
}
if (bracket) {
ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0,
"the closing bracket in \"%V\" "
"variable is missing", &name);
return NGX_ERROR;
}
if (name.len == 0) {
goto invalid_variable;
}
sc->variables++;
if (ngx_http_script_add_var_code(sc, &name) != NGX_OK) {
return NGX_ERROR;
}
continue;
}
if (sc->source->data[i] == '?' && sc->compile_args) {
sc->args = 1;
sc->compile_args = 0;
if (ngx_http_script_add_args_code(sc) != NGX_OK) {
return NGX_ERROR;
}
i++;
continue;
}
name.data = &sc->source->data[i];
while (i < sc->source->len) {
if (sc->source->data[i] == '$') {
break;
}
if (sc->source->data[i] == '?') {
sc->args = 1;
if (sc->compile_args) {
break;
}
}
i++;
name.len++;
}
sc->size += name.len;
if (ngx_http_script_add_copy_code(sc, &name, (i == sc->source->len))
!= NGX_OK)
{
return NGX_ERROR;
}
}
return ngx_http_script_done(sc);
invalid_variable:
ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0, "invalid variable name");
return NGX_ERROR;
}
u_char *
ngx_http_script_run(ngx_http_request_t *r, ngx_str_t *value,
void *code_lengths, size_t len, void *code_values)
{
ngx_uint_t i;
ngx_http_script_code_pt code;
ngx_http_script_len_code_pt lcode;
ngx_http_script_engine_t e;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
for (i = 0; i < cmcf->variables.nelts; i++) {
if (r->variables[i].no_cacheable) {
r->variables[i].valid = 0;
r->variables[i].not_found = 0;
}
}
ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
e.ip = code_lengths;
e.request = r;
e.flushed = 1;
while (*(uintptr_t *) e.ip) {
lcode = *(ngx_http_script_len_code_pt *) e.ip;
len += lcode(&e);
}
value->len = len;
value->data = ngx_pnalloc(r->pool, len);
if (value->data == NULL) {
return NULL;
}
e.ip = code_values;
e.pos = value->data;
while (*(uintptr_t *) e.ip) {
code = *(ngx_http_script_code_pt *) e.ip;
code((ngx_http_script_engine_t *) &e);
}
return e.pos;
}
void
ngx_http_script_flush_no_cacheable_variables(ngx_http_request_t *r,
ngx_array_t *indices)
{
ngx_uint_t n, *index;
if (indices) {
index = indices->elts;
for (n = 0; n < indices->nelts; n++) {
if (r->variables[index[n]].no_cacheable) {
r->variables[index[n]].valid = 0;
r->variables[index[n]].not_found = 0;
}
}
}
}
static ngx_int_t
ngx_http_script_init_arrays(ngx_http_script_compile_t *sc)
{
ngx_uint_t n;
if (sc->flushes && *sc->flushes == NULL) {
n = sc->variables ? sc->variables : 1;
*sc->flushes = ngx_array_create(sc->cf->pool, n, sizeof(ngx_uint_t));
if (*sc->flushes == NULL) {
return NGX_ERROR;
}
}
if (*sc->lengths == NULL) {
n = sc->variables * (2 * sizeof(ngx_http_script_copy_code_t)
+ sizeof(ngx_http_script_var_code_t))
+ sizeof(uintptr_t);
*sc->lengths = ngx_array_create(sc->cf->pool, n, 1);
if (*sc->lengths == NULL) {
return NGX_ERROR;
}
}
if (*sc->values == NULL) {
n = (sc->variables * (2 * sizeof(ngx_http_script_copy_code_t)
+ sizeof(ngx_http_script_var_code_t))
+ sizeof(uintptr_t)
+ sc->source->len
+ sizeof(uintptr_t) - 1)
& ~(sizeof(uintptr_t) - 1);
*sc->values = ngx_array_create(sc->cf->pool, n, 1);
if (*sc->values == NULL) {
return NGX_ERROR;
}
}
sc->variables = 0;
return NGX_OK;
}
static ngx_int_t
ngx_http_script_done(ngx_http_script_compile_t *sc)
{
ngx_str_t zero;
uintptr_t *code;
if (sc->zero) {
zero.len = 1;
zero.data = (u_char *) "\0";
if (ngx_http_script_add_copy_code(sc, &zero, 0) != NGX_OK) {
return NGX_ERROR;
}
}
if (sc->conf_prefix || sc->root_prefix) {
if (ngx_http_script_add_full_name_code(sc) != NGX_OK) {
return NGX_ERROR;
}
}
if (sc->complete_lengths) {
code = ngx_http_script_add_code(*sc->lengths, sizeof(uintptr_t), NULL);
if (code == NULL) {
return NGX_ERROR;
}
*code = (uintptr_t) NULL;
}
if (sc->complete_values) {
code = ngx_http_script_add_code(*sc->values, sizeof(uintptr_t),
&sc->main);
if (code == NULL) {
return NGX_ERROR;
}
*code = (uintptr_t) NULL;
}
return NGX_OK;
}
void *
ngx_http_script_start_code(ngx_pool_t *pool, ngx_array_t **codes, size_t size)
{
if (*codes == NULL) {
*codes = ngx_array_create(pool, 256, 1);
if (*codes == NULL) {
return NULL;
}
}
return ngx_array_push_n(*codes, size);
}
void *
ngx_http_script_add_code(ngx_array_t *codes, size_t size, void *code)
{
u_char *elts, **p;
void *new;
elts = codes->elts;
new = ngx_array_push_n(codes, size);
if (new == NULL) {
return NULL;
}
if (code) {
if (elts != codes->elts) {
p = code;
*p += (u_char *) codes->elts - elts;
}
}
return new;
}
static ngx_int_t
ngx_http_script_add_copy_code(ngx_http_script_compile_t *sc, ngx_str_t *value,
ngx_uint_t last)
{
u_char *p;
size_t size, len, zero;
ngx_http_script_copy_code_t *code;
zero = (sc->zero && last);
len = value->len + zero;
code = ngx_http_script_add_code(*sc->lengths,
sizeof(ngx_http_script_copy_code_t), NULL);
if (code == NULL) {
return NGX_ERROR;
}
code->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
code->len = len;
size = (sizeof(ngx_http_script_copy_code_t) + len + sizeof(uintptr_t) - 1)
& ~(sizeof(uintptr_t) - 1);
code = ngx_http_script_add_code(*sc->values, size, &sc->main);
if (code == NULL) {
return NGX_ERROR;
}
code->code = ngx_http_script_copy_code;
code->len = len;
p = ngx_cpymem((u_char *) code + sizeof(ngx_http_script_copy_code_t),
value->data, value->len);
if (zero) {
*p = '\0';
sc->zero = 0;
}
return NGX_OK;
}
size_t
ngx_http_script_copy_len_code(ngx_http_script_engine_t *e)
{
ngx_http_script_copy_code_t *code;
code = (ngx_http_script_copy_code_t *) e->ip;
e->ip += sizeof(ngx_http_script_copy_code_t);
return code->len;
}
void
ngx_http_script_copy_code(ngx_http_script_engine_t *e)
{
u_char *p;
ngx_http_script_copy_code_t *code;
code = (ngx_http_script_copy_code_t *) e->ip;
p = e->pos;
if (!e->skip) {
e->pos = ngx_copy(p, e->ip + sizeof(ngx_http_script_copy_code_t),
code->len);
}
e->ip += sizeof(ngx_http_script_copy_code_t)
+ ((code->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1));
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
"http script copy: \"%*s\"", e->pos - p, p);
}
static ngx_int_t
ngx_http_script_add_var_code(ngx_http_script_compile_t *sc, ngx_str_t *name)
{
ngx_int_t index, *p;
ngx_http_script_var_code_t *code;
index = ngx_http_get_variable_index(sc->cf, name);
if (index == NGX_ERROR) {
return NGX_ERROR;
}
if (sc->flushes) {
p = ngx_array_push(*sc->flushes);
if (p == NULL) {
return NGX_ERROR;
}
*p = index;
}
code = ngx_http_script_add_code(*sc->lengths,
sizeof(ngx_http_script_var_code_t), NULL);
if (code == NULL) {
return NGX_ERROR;
}
code->code = (ngx_http_script_code_pt) ngx_http_script_copy_var_len_code;
code->index = (uintptr_t) index;
code = ngx_http_script_add_code(*sc->values,
sizeof(ngx_http_script_var_code_t),
&sc->main);
if (code == NULL) {
return NGX_ERROR;
}
code->code = ngx_http_script_copy_var_code;
code->index = (uintptr_t) index;
return NGX_OK;
}
size_t
ngx_http_script_copy_var_len_code(ngx_http_script_engine_t *e)
{
ngx_http_variable_value_t *value;
ngx_http_script_var_code_t *code;
code = (ngx_http_script_var_code_t *) e->ip;
e->ip += sizeof(ngx_http_script_var_code_t);
if (e->flushed) {
value = ngx_http_get_indexed_variable(e->request, code->index);
} else {
value = ngx_http_get_flushed_variable(e->request, code->index);
}
if (value && !value->not_found) {
return value->len;
}
return 0;
}
void
ngx_http_script_copy_var_code(ngx_http_script_engine_t *e)
{
u_char *p;
ngx_http_variable_value_t *value;
ngx_http_script_var_code_t *code;
code = (ngx_http_script_var_code_t *) e->ip;
e->ip += sizeof(ngx_http_script_var_code_t);
if (!e->skip) {
if (e->flushed) {
value = ngx_http_get_indexed_variable(e->request, code->index);
} else {
value = ngx_http_get_flushed_variable(e->request, code->index);
}
if (value && !value->not_found) {
p = e->pos;
e->pos = ngx_copy(p, value->data, value->len);
ngx_log_debug2(NGX_LOG_DEBUG_HTTP,
e->request->connection->log, 0,
"http script var: \"%*s\"", e->pos - p, p);
}
}
}
static ngx_int_t
ngx_http_script_add_args_code(ngx_http_script_compile_t *sc)
{
uintptr_t *code;
code = ngx_http_script_add_code(*sc->lengths, sizeof(uintptr_t), NULL);
if (code == NULL) {
return NGX_ERROR;
}
*code = (uintptr_t) ngx_http_script_mark_args_code;
code = ngx_http_script_add_code(*sc->values, sizeof(uintptr_t), &sc->main);
if (code == NULL) {
return NGX_ERROR;
}
*code = (uintptr_t) ngx_http_script_start_args_code;
return NGX_OK;
}
size_t
ngx_http_script_mark_args_code(ngx_http_script_engine_t *e)
{
e->is_args = 1;
e->ip += sizeof(uintptr_t);
return 1;
}
void
ngx_http_script_start_args_code(ngx_http_script_engine_t *e)
{
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
"http script args");
e->is_args = 1;
e->args = e->pos;
e->ip += sizeof(uintptr_t);
}
#if (NGX_PCRE)
void
ngx_http_script_regex_start_code(ngx_http_script_engine_t *e)
{
size_t len;
ngx_int_t rc;
ngx_uint_t n;
ngx_http_request_t *r;
ngx_http_script_engine_t le;
ngx_http_script_len_code_pt lcode;
ngx_http_script_regex_code_t *code;
code = (ngx_http_script_regex_code_t *) e->ip;
r = e->request;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http script regex: \"%V\"", &code->name);
if (code->uri) {
e->line = r->uri;
} else {
e->sp--;
e->line.len = e->sp->len;
e->line.data = e->sp->data;
}
if (code->ncaptures && r->captures == NULL) {
r->captures = ngx_palloc(r->pool,
(NGX_HTTP_MAX_CAPTURES + 1) * 3 * sizeof(int));
if (r->captures == NULL) {
e->ip = ngx_http_script_exit;
e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
return;
}
}
rc = ngx_regex_exec(code->regex, &e->line, r->captures, code->ncaptures);
if (rc == NGX_REGEX_NO_MATCHED) {
if (e->log || (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP)) {
ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
"\"%V\" does not match \"%V\"",
&code->name, &e->line);
}
r->ncaptures = 0;
if (code->test) {
if (code->negative_test) {
e->sp->len = 1;
e->sp->data = (u_char *) "1";
} else {
e->sp->len = 0;
e->sp->data = (u_char *) "";
}
e->sp++;
e->ip += sizeof(ngx_http_script_regex_code_t);
return;
}
e->ip += code->next;
return;
}
if (rc < 0) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
ngx_regex_exec_n " failed: %d on \"%V\" using \"%V\"",
rc, &e->line, &code->name);
e->ip = ngx_http_script_exit;
e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
return;
}
if (e->log || (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP)) {
ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
"\"%V\" matches \"%V\"", &code->name, &e->line);
}
r->ncaptures = code->ncaptures;
r->captures_data = e->line.data;
if (code->test) {
if (code->negative_test) {
e->sp->len = 0;
e->sp->data = (u_char *) "";
} else {
e->sp->len = 1;
e->sp->data = (u_char *) "1";
}
e->sp++;
e->ip += sizeof(ngx_http_script_regex_code_t);
return;
}
if (code->status) {
e->status = code->status;
if (!code->redirect) {
e->ip = ngx_http_script_exit;
return;
}
}
if (code->uri) {
r->internal = 1;
r->valid_unparsed_uri = 0;
if (code->break_cycle) {
r->valid_location = 0;
r->uri_changed = 0;
} else {
r->uri_changed = 1;
}
}
if (code->lengths == NULL) {
e->buf.len = code->size;
if (code->uri) {
if (rc && (r->quoted_uri || r->plus_in_uri)) {
e->buf.len += 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len,
NGX_ESCAPE_ARGS);
}
}
for (n = 1; n < (ngx_uint_t) rc; n++) {
e->buf.len += r->captures[2 * n + 1] - r->captures[2 * n];
}
} else {
ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
le.ip = code->lengths->elts;
le.line = e->line;
le.request = r;
le.quote = code->redirect;
len = 0;
while (*(uintptr_t *) le.ip) {
lcode = *(ngx_http_script_len_code_pt *) le.ip;
len += lcode(&le);
}
e->buf.len = len;
e->is_args = le.is_args;
}
if (code->add_args && r->args.len) {
e->buf.len += r->args.len + 1;
}
e->buf.data = ngx_pnalloc(r->pool, e->buf.len);
if (e->buf.data == NULL) {
e->ip = ngx_http_script_exit;
e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
return;
}
e->quote = code->redirect;
e->pos = e->buf.data;
e->ip += sizeof(ngx_http_script_regex_code_t);
}
void
ngx_http_script_regex_end_code(ngx_http_script_engine_t *e)
{
u_char *dst, *src;
ngx_http_request_t *r;
ngx_http_script_regex_end_code_t *code;
code = (ngx_http_script_regex_end_code_t *) e->ip;
r = e->request;
e->quote = 0;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http script regex end");
if (code->redirect) {
dst = e->buf.data;
src = e->buf.data;
ngx_unescape_uri(&dst, &src, e->pos - e->buf.data,
NGX_UNESCAPE_REDIRECT);
if (src < e->pos) {
dst = ngx_copy(dst, src, e->pos - src);
}
e->pos = dst;
if (code->add_args && r->args.len) {
*e->pos++ = (u_char) (code->args ? '&' : '?');
e->pos = ngx_copy(e->pos, r->args.data, r->args.len);
}
e->buf.len = e->pos - e->buf.data;
if (e->log || (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP)) {
ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
"rewritten redirect: \"%V\"", &e->buf);
}
r->headers_out.location = ngx_list_push(&r->headers_out.headers);
if (r->headers_out.location == NULL) {
e->ip = ngx_http_script_exit;
e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
return;
}
r->headers_out.location->hash = 1;
r->headers_out.location->key.len = sizeof("Location") - 1;
r->headers_out.location->key.data = (u_char *) "Location";
r->headers_out.location->value = e->buf;
e->ip += sizeof(ngx_http_script_regex_end_code_t);
return;
}
if (e->args) {
e->buf.len = e->args - e->buf.data;
if (code->add_args && r->args.len) {
*e->pos++ = '&';
e->pos = ngx_copy(e->pos, r->args.data, r->args.len);
}
r->args.len = e->pos - e->args;
r->args.data = e->args;
e->args = NULL;
} else {
e->buf.len = e->pos - e->buf.data;
if (!code->add_args) {
r->args.len = 0;
}
}
if (e->log || (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP)) {
ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
"rewritten data: \"%V\", args: \"%V\"",
&e->buf, &r->args);
}
if (code->uri) {
r->uri = e->buf;
if (r->uri.len == 0) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"the rewritten URI has a zero length");
e->ip = ngx_http_script_exit;
e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
return;
}
ngx_http_set_exten(r);
}
e->ip += sizeof(ngx_http_script_regex_end_code_t);
}
static ngx_int_t
ngx_http_script_add_capture_code(ngx_http_script_compile_t *sc, ngx_uint_t n)
{
ngx_http_script_copy_capture_code_t *code;
code = ngx_http_script_add_code(*sc->lengths,
sizeof(ngx_http_script_copy_capture_code_t),
NULL);
if (code == NULL) {
return NGX_ERROR;
}
code->code = (ngx_http_script_code_pt)
ngx_http_script_copy_capture_len_code;
code->n = 2 * n;
code = ngx_http_script_add_code(*sc->values,
sizeof(ngx_http_script_copy_capture_code_t),
&sc->main);
if (code == NULL) {
return NGX_ERROR;
}
code->code = ngx_http_script_copy_capture_code;
code->n = 2 * n;
if (sc->ncaptures < n) {
sc->ncaptures = n;
}
return NGX_OK;
}
size_t
ngx_http_script_copy_capture_len_code(ngx_http_script_engine_t *e)
{
int *cap;
u_char *p;
ngx_uint_t n;
ngx_http_request_t *r;
ngx_http_script_copy_capture_code_t *code;
r = e->request;
code = (ngx_http_script_copy_capture_code_t *) e->ip;
e->ip += sizeof(ngx_http_script_copy_capture_code_t);
n = code->n;
if (n < r->ncaptures) {
cap = r->captures;
if ((e->is_args || e->quote)
&& (e->request->quoted_uri || e->request->plus_in_uri))
{
p = r->captures_data;
return cap[n + 1] - cap[n]
+ 2 * ngx_escape_uri(NULL, &p[cap[n]], cap[n + 1] - cap[n],
NGX_ESCAPE_ARGS);
} else {
return cap[n + 1] - cap[n];
}
}
return 0;
}
void
ngx_http_script_copy_capture_code(ngx_http_script_engine_t *e)
{
int *cap;
u_char *p, *pos;
ngx_uint_t n;
ngx_http_request_t *r;
ngx_http_script_copy_capture_code_t *code;
r = e->request;
code = (ngx_http_script_copy_capture_code_t *) e->ip;
e->ip += sizeof(ngx_http_script_copy_capture_code_t);
n = code->n;
pos = e->pos;
if (n < r->ncaptures) {
cap = r->captures;
p = r->captures_data;
if ((e->is_args || e->quote)
&& (e->request->quoted_uri || e->request->plus_in_uri))
{
e->pos = (u_char *) ngx_escape_uri(pos, &p[cap[n]],
cap[n + 1] - cap[n],
NGX_ESCAPE_ARGS);
} else {
e->pos = ngx_copy(pos, &p[cap[n]], cap[n + 1] - cap[n]);
}
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
"http script capture: \"%*s\"", e->pos - pos, pos);
}
#endif
static ngx_int_t
ngx_http_script_add_full_name_code(ngx_http_script_compile_t *sc)
{
ngx_http_script_full_name_code_t *code;
code = ngx_http_script_add_code(*sc->lengths,
sizeof(ngx_http_script_full_name_code_t),
NULL);
if (code == NULL) {
return NGX_ERROR;
}
code->code = (ngx_http_script_code_pt) ngx_http_script_full_name_len_code;
code->conf_prefix = sc->conf_prefix;
code = ngx_http_script_add_code(*sc->values,
sizeof(ngx_http_script_full_name_code_t),
&sc->main);
if (code == NULL) {
return NGX_ERROR;
}
code->code = ngx_http_script_full_name_code;
code->conf_prefix = sc->conf_prefix;
return NGX_OK;
}
static size_t
ngx_http_script_full_name_len_code(ngx_http_script_engine_t *e)
{
ngx_http_script_full_name_code_t *code;
code = (ngx_http_script_full_name_code_t *) e->ip;
e->ip += sizeof(ngx_http_script_full_name_code_t);
return code->conf_prefix ? ngx_cycle->conf_prefix.len:
ngx_cycle->prefix.len;
}
static void
ngx_http_script_full_name_code(ngx_http_script_engine_t *e)
{
ngx_http_script_full_name_code_t *code;
ngx_str_t value;
code = (ngx_http_script_full_name_code_t *) e->ip;
value.data = e->buf.data;
value.len = e->pos - e->buf.data;
if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &value, code->conf_prefix)
!= NGX_OK)
{
e->ip = ngx_http_script_exit;
e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
return;
}
e->buf = value;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
"http script fullname: \"%V\"", &value);
e->ip += sizeof(ngx_http_script_full_name_code_t);
}
void
ngx_http_script_return_code(ngx_http_script_engine_t *e)
{
ngx_http_script_return_code_t *code;
code = (ngx_http_script_return_code_t *) e->ip;
e->status = code->status;
if (code->status == NGX_HTTP_NO_CONTENT) {
e->request->header_only = 1;
e->request->zero_body = 1;
}
e->ip += sizeof(ngx_http_script_return_code_t) - sizeof(uintptr_t);
}
void
ngx_http_script_break_code(ngx_http_script_engine_t *e)
{
e->request->uri_changed = 0;
e->ip = ngx_http_script_exit;
}
void
ngx_http_script_if_code(ngx_http_script_engine_t *e)
{
ngx_http_script_if_code_t *code;
code = (ngx_http_script_if_code_t *) e->ip;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
"http script if");
e->sp--;
if (e->sp->len && e->sp->data[0] != '0') {
if (code->loc_conf) {
e->request->loc_conf = code->loc_conf;
ngx_http_update_location_config(e->request);
}
e->ip += sizeof(ngx_http_script_if_code_t);
return;
}
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
"http script if: false");
e->ip += code->next;
}
void
ngx_http_script_equal_code(ngx_http_script_engine_t *e)
{
ngx_http_variable_value_t *val, *res;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
"http script equal");
e->sp--;
val = e->sp;
res = e->sp - 1;
e->ip += sizeof(uintptr_t);
if (val->len == res->len
&& ngx_strncmp(val->data, res->data, res->len) == 0)
{
*res = ngx_http_variable_true_value;
return;
}
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
"http script equal: no");
*res = ngx_http_variable_null_value;
}
void
ngx_http_script_not_equal_code(ngx_http_script_engine_t *e)
{
ngx_http_variable_value_t *val, *res;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
"http script not equal");
e->sp--;
val = e->sp;
res = e->sp - 1;
e->ip += sizeof(uintptr_t);
if (val->len == res->len
&& ngx_strncmp(val->data, res->data, res->len) == 0)
{
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
"http script not equal: no");
*res = ngx_http_variable_null_value;
return;
}
*res = ngx_http_variable_true_value;
}
void
ngx_http_script_file_code(ngx_http_script_engine_t *e)
{
ngx_str_t path;
ngx_http_request_t *r;
ngx_open_file_info_t of;
ngx_http_core_loc_conf_t *clcf;
ngx_http_variable_value_t *value;
ngx_http_script_file_code_t *code;
value = e->sp - 1;
code = (ngx_http_script_file_code_t *) e->ip;
e->ip += sizeof(ngx_http_script_file_code_t);
path.len = value->len - 1;
path.data = value->data;
r = e->request;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http script file op %p \"%V\"", code->op, &path);
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
ngx_memzero(&of, sizeof(ngx_open_file_info_t));
of.directio = clcf->directio;
of.valid = clcf->open_file_cache_valid;
of.min_uses = clcf->open_file_cache_min_uses;
of.test_only = 1;
of.errors = clcf->open_file_cache_errors;
of.events = clcf->open_file_cache_events;
if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
!= NGX_OK)
{
if (of.err != NGX_ENOENT
&& of.err != NGX_ENOTDIR
&& of.err != NGX_ENAMETOOLONG)
{
ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err,
"%s \"%s\" failed", of.failed, value->data);
}
switch (code->op) {
case ngx_http_script_file_plain:
case ngx_http_script_file_dir:
case ngx_http_script_file_exists:
case ngx_http_script_file_exec:
goto false_value;
case ngx_http_script_file_not_plain:
case ngx_http_script_file_not_dir:
case ngx_http_script_file_not_exists:
case ngx_http_script_file_not_exec:
goto true_value;
}
goto false_value;
}
switch (code->op) {
case ngx_http_script_file_plain:
if (of.is_file) {
goto true_value;
}
goto false_value;
case ngx_http_script_file_not_plain:
if (of.is_file) {
goto false_value;
}
goto true_value;
case ngx_http_script_file_dir:
if (of.is_dir) {
goto true_value;
}
goto false_value;
case ngx_http_script_file_not_dir:
if (of.is_dir) {
goto false_value;
}
goto true_value;
case ngx_http_script_file_exists:
if (of.is_file || of.is_dir || of.is_link) {
goto true_value;
}
goto false_value;
case ngx_http_script_file_not_exists:
if (of.is_file || of.is_dir || of.is_link) {
goto false_value;
}
goto true_value;
case ngx_http_script_file_exec:
if (of.is_exec) {
goto true_value;
}
goto false_value;
case ngx_http_script_file_not_exec:
if (of.is_exec) {
goto false_value;
}
goto true_value;
}
false_value:
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http script file op false");
*value = ngx_http_variable_null_value;
return;
true_value:
*value = ngx_http_variable_true_value;
return;
}
void
ngx_http_script_complex_value_code(ngx_http_script_engine_t *e)
{
size_t len;
ngx_http_script_engine_t le;
ngx_http_script_len_code_pt lcode;
ngx_http_script_complex_value_code_t *code;
code = (ngx_http_script_complex_value_code_t *) e->ip;
e->ip += sizeof(ngx_http_script_complex_value_code_t);
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
"http script complex value");
ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
le.ip = code->lengths->elts;
le.line = e->line;
le.request = e->request;
le.quote = e->quote;
for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) {
lcode = *(ngx_http_script_len_code_pt *) le.ip;
}
e->buf.len = len;
e->buf.data = ngx_pnalloc(e->request->pool, len);
if (e->buf.data == NULL) {
e->ip = ngx_http_script_exit;
e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
return;
}
e->pos = e->buf.data;
e->sp->len = e->buf.len;
e->sp->data = e->buf.data;
e->sp++;
}
void
ngx_http_script_value_code(ngx_http_script_engine_t *e)
{
ngx_http_script_value_code_t *code;
code = (ngx_http_script_value_code_t *) e->ip;
e->ip += sizeof(ngx_http_script_value_code_t);
e->sp->len = code->text_len;
e->sp->data = (u_char *) code->text_data;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
"http script value: \"%v\"", e->sp);
e->sp++;
}
void
ngx_http_script_set_var_code(ngx_http_script_engine_t *e)
{
ngx_http_request_t *r;
ngx_http_script_var_code_t *code;
code = (ngx_http_script_var_code_t *) e->ip;
e->ip += sizeof(ngx_http_script_var_code_t);
r = e->request;
e->sp--;
r->variables[code->index].len = e->sp->len;
r->variables[code->index].valid = 1;
r->variables[code->index].no_cacheable = 0;
r->variables[code->index].not_found = 0;
r->variables[code->index].data = e->sp->data;
#if (NGX_DEBUG)
{
ngx_http_variable_t *v;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
v = cmcf->variables.elts;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
"http script set $%V", &v[code->index].name);
}
#endif
}
void
ngx_http_script_var_set_handler_code(ngx_http_script_engine_t *e)
{
ngx_http_script_var_handler_code_t *code;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
"http script set var handler");
code = (ngx_http_script_var_handler_code_t *) e->ip;
e->ip += sizeof(ngx_http_script_var_handler_code_t);
e->sp--;
code->handler(e->request, e->sp, code->data);
}
void
ngx_http_script_var_code(ngx_http_script_engine_t *e)
{
ngx_http_variable_value_t *value;
ngx_http_script_var_code_t *code;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
"http script var");
code = (ngx_http_script_var_code_t *) e->ip;
e->ip += sizeof(ngx_http_script_var_code_t);
value = ngx_http_get_flushed_variable(e->request, code->index);
if (value && !value->not_found) {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
"http script var: \"%v\"", value);
*e->sp = *value;
e->sp++;
return;
}
*e->sp = ngx_http_variable_null_value;
e->sp++;
}
void
ngx_http_script_nop_code(ngx_http_script_engine_t *e)
{
e->ip += sizeof(uintptr_t);
}
nginx-0.7.68/src/http/ngx_http_request_body.c 000644 001750 001750 00000036730 11331564136 020375 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#include
#include
#include
static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r);
static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r);
static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r,
ngx_chain_t *body);
static void ngx_http_read_discarded_request_body_handler(ngx_http_request_t *r);
static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r);
static ngx_int_t ngx_http_test_expect(ngx_http_request_t *r);
/*
* on completion ngx_http_read_client_request_body() adds to
* r->request_body->bufs one or two bufs:
* *) one memory buf that was preread in r->header_in;
* *) one memory or file buf that contains the rest of the body
*/
ngx_int_t
ngx_http_read_client_request_body(ngx_http_request_t *r,
ngx_http_client_body_handler_pt post_handler)
{
size_t preread;
ssize_t size;
ngx_buf_t *b;
ngx_chain_t *cl, **next;
ngx_temp_file_t *tf;
ngx_http_request_body_t *rb;
ngx_http_core_loc_conf_t *clcf;
if (r->request_body || r->discard_body) {
post_handler(r);
return NGX_OK;
}
if (ngx_http_test_expect(r) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
if (rb == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
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) {
if (r->request_body_in_file_only) {
tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
if (tf == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
tf->file.fd = NGX_INVALID_FILE;
tf->file.log = r->connection->log;
tf->path = clcf->client_body_temp_path;
tf->pool = r->pool;
tf->warn = "a client request body is buffered to a temporary file";
tf->log_level = r->request_body_file_log_level;
tf->persistent = r->request_body_in_persistent_file;
tf->clean = r->request_body_in_clean_file;
if (r->request_body_file_group_access) {
tf->access = 0660;
}
rb->temp_file = tf;
if (ngx_create_temp_file(&tf->file, tf->path, tf->pool,
tf->persistent, tf->clean, tf->access)
!= NGX_OK)
{
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
}
post_handler(r);
return NGX_OK;
}
rb->post_handler = post_handler;
/*
* set by ngx_pcalloc():
*
* rb->bufs = NULL;
* rb->buf = NULL;
* rb->rest = 0;
*/
preread = r->header_in->last - r->header_in->pos;
if (preread) {
/* there is the pre-read part of the request body */
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http client request body preread %uz", preread);
b = ngx_calloc_buf(r->pool);
if (b == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
b->temporary = 1;
b->start = r->header_in->pos;
b->pos = r->header_in->pos;
b->last = r->header_in->last;
b->end = r->header_in->end;
rb->bufs = ngx_alloc_chain_link(r->pool);
if (rb->bufs == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
rb->bufs->buf = b;
rb->bufs->next = NULL;
rb->buf = b;
if ((off_t) preread >= r->headers_in.content_length_n) {
/* the whole request body was pre-read */
r->header_in->pos += (size_t) r->headers_in.content_length_n;
r->request_length += r->headers_in.content_length_n;
if (r->request_body_in_file_only) {
if (ngx_http_write_request_body(r, rb->bufs) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
}
post_handler(r);
return NGX_OK;
}
/*
* to not consider the body as pipelined request in
* ngx_http_set_keepalive()
*/
r->header_in->pos = r->header_in->last;
r->request_length += preread;
rb->rest = r->headers_in.content_length_n - preread;
if (rb->rest <= (off_t) (b->end - b->last)) {
/* the whole request body may be placed in r->header_in */
rb->to_write = rb->bufs;
r->read_event_handler = ngx_http_read_client_request_body_handler;
return ngx_http_do_read_client_request_body(r);
}
next = &rb->bufs->next;
} else {
b = NULL;
rb->rest = r->headers_in.content_length_n;
next = &rb->bufs;
}
size = clcf->client_body_buffer_size;
size += size >> 2;
if (rb->rest < size) {
size = (ssize_t) rb->rest;
if (r->request_body_in_single_buf) {
size += preread;
}
} else {
size = clcf->client_body_buffer_size;
/* disable copying buffer for r->request_body_in_single_buf */
b = NULL;
}
rb->buf = ngx_create_temp_buf(r->pool, size);
if (rb->buf == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
cl = ngx_alloc_chain_link(r->pool);
if (cl == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
cl->buf = rb->buf;
cl->next = NULL;
if (b && r->request_body_in_single_buf) {
size = b->last - b->pos;
ngx_memcpy(rb->buf->pos, b->pos, size);
rb->buf->last += size;
next = &rb->bufs;
}
*next = cl;
if (r->request_body_in_file_only || r->request_body_in_single_buf) {
rb->to_write = rb->bufs;
} else {
rb->to_write = rb->bufs->next ? rb->bufs->next : rb->bufs;
}
r->read_event_handler = ngx_http_read_client_request_body_handler;
return ngx_http_do_read_client_request_body(r);
}
static void
ngx_http_read_client_request_body_handler(ngx_http_request_t *r)
{
ngx_int_t rc;
if (r->connection->read->timedout) {
r->connection->timedout = 1;
ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT);
return;
}
rc = ngx_http_do_read_client_request_body(r);
if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
ngx_http_finalize_request(r, rc);
}
}
static ngx_int_t
ngx_http_do_read_client_request_body(ngx_http_request_t *r)
{
size_t size;
ssize_t n;
ngx_buf_t *b;
ngx_connection_t *c;
ngx_http_request_body_t *rb;
ngx_http_core_loc_conf_t *clcf;
c = r->connection;
rb = r->request_body;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http read client request body");
for ( ;; ) {
for ( ;; ) {
if (rb->buf->last == rb->buf->end) {
if (ngx_http_write_request_body(r, rb->to_write) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
rb->to_write = rb->bufs->next ? rb->bufs->next : rb->bufs;
rb->buf->last = rb->buf->start;
}
size = rb->buf->end - rb->buf->last;
if ((off_t) size > rb->rest) {
size = (size_t) rb->rest;
}
n = c->recv(c, rb->buf->last, size);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http client request body recv %z", n);
if (n == NGX_AGAIN) {
break;
}
if (n == 0) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"client closed prematurely connection");
}
if (n == 0 || n == NGX_ERROR) {
c->error = 1;
return NGX_HTTP_BAD_REQUEST;
}
rb->buf->last += n;
rb->rest -= n;
r->request_length += n;
if (rb->rest == 0) {
break;
}
if (rb->buf->last < rb->buf->end) {
break;
}
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http client request body rest %O", rb->rest);
if (rb->rest == 0) {
break;
}
if (!c->read->ready) {
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
ngx_add_timer(c->read, clcf->client_body_timeout);
if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
return NGX_AGAIN;
}
}
if (c->read->timer_set) {
ngx_del_timer(c->read);
}
if (rb->temp_file || r->request_body_in_file_only) {
/* save the last part */
if (ngx_http_write_request_body(r, rb->to_write) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
b = ngx_calloc_buf(r->pool);
if (b == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
b->in_file = 1;
b->file_pos = 0;
b->file_last = rb->temp_file->file.offset;
b->file = &rb->temp_file->file;
if (rb->bufs->next) {
rb->bufs->next->buf = b;
} else {
rb->bufs->buf = b;
}
}
if (r->request_body_in_file_only && rb->bufs->next) {
rb->bufs = rb->bufs->next;
}
rb->post_handler(r);
return NGX_OK;
}
static ngx_int_t
ngx_http_write_request_body(ngx_http_request_t *r, ngx_chain_t *body)
{
ssize_t n;
ngx_temp_file_t *tf;
ngx_http_request_body_t *rb;
ngx_http_core_loc_conf_t *clcf;
rb = r->request_body;
if (rb->temp_file == NULL) {
tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
if (tf == NULL) {
return NGX_ERROR;
}
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
tf->file.fd = NGX_INVALID_FILE;
tf->file.log = r->connection->log;
tf->path = clcf->client_body_temp_path;
tf->pool = r->pool;
tf->warn = "a client request body is buffered to a temporary file";
tf->log_level = r->request_body_file_log_level;
tf->persistent = r->request_body_in_persistent_file;
tf->clean = r->request_body_in_clean_file;
if (r->request_body_file_group_access) {
tf->access = 0660;
}
rb->temp_file = tf;
}
n = ngx_write_chain_to_temp_file(rb->temp_file, body);
/* TODO: n == 0 or not complete and level event */
if (n == NGX_ERROR) {
return NGX_ERROR;
}
rb->temp_file->offset += n;
return NGX_OK;
}
ngx_int_t
ngx_http_discard_request_body(ngx_http_request_t *r)
{
ssize_t size;
ngx_event_t *rev;
if (r != r->main || r->discard_body) {
return NGX_OK;
}
if (ngx_http_test_expect(r) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
rev = r->connection->read;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http set discard body");
if (rev->timer_set) {
ngx_del_timer(rev);
}
if (r->headers_in.content_length_n <= 0 || r->request_body) {
return NGX_OK;
}
size = r->header_in->last - r->header_in->pos;
if (size) {
if (r->headers_in.content_length_n > size) {
r->header_in->pos += size;
r->headers_in.content_length_n -= size;
} else {
r->header_in->pos += (size_t) r->headers_in.content_length_n;
r->headers_in.content_length_n = 0;
return NGX_OK;
}
}
r->discard_body = 1;
r->read_event_handler = ngx_http_read_discarded_request_body_handler;
if (ngx_handle_read_event(rev, 0) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
(void) ngx_http_read_discarded_request_body(r);
return NGX_OK;
}
static void
ngx_http_read_discarded_request_body_handler(ngx_http_request_t *r)
{
ngx_int_t rc;
ngx_msec_t timer;
ngx_event_t *rev;
ngx_connection_t *c;
ngx_http_core_loc_conf_t *clcf;
c = r->connection;
rev = c->read;
if (rev->timedout) {
c->timedout = 1;
c->error = 1;
ngx_http_finalize_request(r, 0);
return;
}
if (r->lingering_time) {
timer = (ngx_msec_t) (r->lingering_time - ngx_time());
if (timer <= 0) {
r->discard_body = 0;
ngx_http_finalize_request(r, 0);
return;
}
} else {
timer = 0;
}
rc = ngx_http_read_discarded_request_body(r);
if (rc == NGX_OK) {
r->discard_body = 0;
if (r->done) {
ngx_http_finalize_request(r, 0);
}
return;
}
/* rc == NGX_AGAIN */
if (ngx_handle_read_event(rev, 0) != NGX_OK) {
c->error = 1;
ngx_http_finalize_request(r, rc);
return;
}
if (timer) {
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
timer *= 1000;
if (timer > clcf->lingering_timeout) {
timer = clcf->lingering_timeout;
}
ngx_add_timer(rev, timer);
}
}
static ngx_int_t
ngx_http_read_discarded_request_body(ngx_http_request_t *r)
{
size_t size;
ssize_t n;
u_char buffer[NGX_HTTP_DISCARD_BUFFER_SIZE];
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http read discarded body");
for ( ;; ) {
if (r->headers_in.content_length_n == 0) {
r->read_event_handler = ngx_http_block_reading;
return NGX_OK;
}
if (!r->connection->read->ready) {
return NGX_AGAIN;
}
size = (r->headers_in.content_length_n > NGX_HTTP_DISCARD_BUFFER_SIZE) ?
NGX_HTTP_DISCARD_BUFFER_SIZE:
(size_t) r->headers_in.content_length_n;
n = r->connection->recv(r->connection, buffer, size);
if (n == NGX_ERROR) {
r->connection->error = 1;
return NGX_OK;
}
if (n == NGX_AGAIN) {
return NGX_AGAIN;
}
if (n == 0) {
return NGX_OK;
}
r->headers_in.content_length_n -= n;
}
}
static ngx_int_t
ngx_http_test_expect(ngx_http_request_t *r)
{
ngx_int_t n;
ngx_str_t *expect;
if (r->expect_tested
|| r->headers_in.expect == NULL
|| r->http_version < NGX_HTTP_VERSION_11)
{
return NGX_OK;
}
r->expect_tested = 1;
expect = &r->headers_in.expect->value;
if (expect->len != sizeof("100-continue") - 1
|| ngx_strncasecmp(expect->data, (u_char *) "100-continue",
sizeof("100-continue") - 1)
!= 0)
{
return NGX_OK;
}
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"send 100 Continue");
n = r->connection->send(r->connection,
(u_char *) "HTTP/1.1 100 Continue" CRLF CRLF,
sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1);
if (n == sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1) {
return NGX_OK;
}
/* we assume that such small packet should be send successfully */
return NGX_ERROR;
}
nginx-0.7.68/src/http/ngx_http_write_filter_module.c 000644 001750 001750 00000020644 11271342163 021726 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#include
#include
#include
static ngx_int_t ngx_http_write_filter_init(ngx_conf_t *cf);
static ngx_http_module_t ngx_http_write_filter_module_ctx = {
NULL, /* preconfiguration */
ngx_http_write_filter_init, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
NULL, /* create location configuration */
NULL, /* merge location configuration */
};
ngx_module_t ngx_http_write_filter_module = {
NGX_MODULE_V1,
&ngx_http_write_filter_module_ctx, /* module context */
NULL, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
ngx_int_t
ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
off_t size, sent, nsent, limit;
ngx_uint_t last, flush;
ngx_msec_t delay;
ngx_chain_t *cl, *ln, **ll, *chain;
ngx_connection_t *c;
ngx_http_core_loc_conf_t *clcf;
c = r->connection;
if (c->error) {
return NGX_ERROR;
}
size = 0;
flush = 0;
last = 0;
ll = &r->out;
/* find the size, the flush point and the last link of the saved chain */
for (cl = r->out; cl; cl = cl->next) {
ll = &cl->next;
ngx_log_debug7(NGX_LOG_DEBUG_EVENT, c->log, 0,
"write old buf t:%d f:%d %p, pos %p, size: %z "
"file: %O, size: %z",
cl->buf->temporary, cl->buf->in_file,
cl->buf->start, cl->buf->pos,
cl->buf->last - cl->buf->pos,
cl->buf->file_pos,
cl->buf->file_last - cl->buf->file_pos);
#if 1
if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) {
ngx_log_error(NGX_LOG_ALERT, c->log, 0,
"zero size buf in writer "
"t:%d r:%d f:%d %p %p-%p %p %O-%O",
cl->buf->temporary,
cl->buf->recycled,
cl->buf->in_file,
cl->buf->start,
cl->buf->pos,
cl->buf->last,
cl->buf->file,
cl->buf->file_pos,
cl->buf->file_last);
ngx_debug_point();
return NGX_ERROR;
}
#endif
size += ngx_buf_size(cl->buf);
if (cl->buf->flush || cl->buf->recycled) {
flush = 1;
}
if (cl->buf->last_buf) {
last = 1;
}
}
/* add the new chain to the existent one */
for (ln = in; ln; ln = ln->next) {
cl = ngx_alloc_chain_link(r->pool);
if (cl == NULL) {
return NGX_ERROR;
}
cl->buf = ln->buf;
*ll = cl;
ll = &cl->next;
ngx_log_debug7(NGX_LOG_DEBUG_EVENT, c->log, 0,
"write new buf t:%d f:%d %p, pos %p, size: %z "
"file: %O, size: %z",
cl->buf->temporary, cl->buf->in_file,
cl->buf->start, cl->buf->pos,
cl->buf->last - cl->buf->pos,
cl->buf->file_pos,
cl->buf->file_last - cl->buf->file_pos);
#if 1
if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) {
ngx_log_error(NGX_LOG_ALERT, c->log, 0,
"zero size buf in writer "
"t:%d r:%d f:%d %p %p-%p %p %O-%O",
cl->buf->temporary,
cl->buf->recycled,
cl->buf->in_file,
cl->buf->start,
cl->buf->pos,
cl->buf->last,
cl->buf->file,
cl->buf->file_pos,
cl->buf->file_last);
ngx_debug_point();
return NGX_ERROR;
}
#endif
size += ngx_buf_size(cl->buf);
if (cl->buf->flush || cl->buf->recycled) {
flush = 1;
}
if (cl->buf->last_buf) {
last = 1;
}
}
*ll = NULL;
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http write filter: l:%d f:%d s:%O", last, flush, size);
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
/*
* avoid the output if there are no last buf, no flush point,
* there are the incoming bufs and the size of all bufs
* is smaller than "postpone_output" directive
*/
if (!last && !flush && in && size < (off_t) clcf->postpone_output) {
return NGX_OK;
}
if (c->write->delayed) {
c->buffered |= NGX_HTTP_WRITE_BUFFERED;
return NGX_AGAIN;
}
if (size == 0 && !(c->buffered & NGX_LOWLEVEL_BUFFERED)) {
if (last) {
r->out = NULL;
c->buffered &= ~NGX_HTTP_WRITE_BUFFERED;
return NGX_OK;
}
if (flush) {
do {
r->out = r->out->next;
} while (r->out);
c->buffered &= ~NGX_HTTP_WRITE_BUFFERED;
return NGX_OK;
}
ngx_log_error(NGX_LOG_ALERT, c->log, 0,
"the http output chain is empty");
ngx_debug_point();
return NGX_ERROR;
}
if (r->limit_rate) {
limit = r->limit_rate * (ngx_time() - r->start_sec + 1)
- (c->sent - clcf->limit_rate_after);
if (limit <= 0) {
c->write->delayed = 1;
ngx_add_timer(c->write,
(ngx_msec_t) (- limit * 1000 / r->limit_rate + 1));
c->buffered |= NGX_HTTP_WRITE_BUFFERED;
return NGX_AGAIN;
}
} else if (clcf->sendfile_max_chunk) {
limit = clcf->sendfile_max_chunk;
} else {
limit = 0;
}
sent = c->sent;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http write filter limit %O", limit);
chain = c->send_chain(c, r->out, limit);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http write filter %p", chain);
if (chain == NGX_CHAIN_ERROR) {
c->error = 1;
return NGX_ERROR;
}
if (r->limit_rate) {
nsent = c->sent;
if (clcf->limit_rate_after) {
sent -= clcf->limit_rate_after;
if (sent < 0) {
sent = 0;
}
nsent -= clcf->limit_rate_after;
if (nsent < 0) {
nsent = 0;
}
}
delay = (ngx_msec_t) ((nsent - sent) * 1000 / r->limit_rate + 1);
if (delay > 0) {
c->write->delayed = 1;
ngx_add_timer(c->write, delay);
}
} else if (c->write->ready
&& clcf->sendfile_max_chunk
&& (size_t) (c->sent - sent)
>= clcf->sendfile_max_chunk - 2 * ngx_pagesize)
{
c->write->delayed = 1;
ngx_add_timer(c->write, 1);
}
for (cl = r->out; cl && cl != chain; /* void */) {
ln = cl;
cl = cl->next;
ngx_free_chain(r->pool, ln);
}
r->out = chain;
if (chain) {
c->buffered |= NGX_HTTP_WRITE_BUFFERED;
return NGX_AGAIN;
}
c->buffered &= ~NGX_HTTP_WRITE_BUFFERED;
if ((c->buffered & NGX_LOWLEVEL_BUFFERED) && r->postponed == NULL) {
return NGX_AGAIN;
}
return NGX_OK;
}
static ngx_int_t
ngx_http_write_filter_init(ngx_conf_t *cf)
{
ngx_http_top_body_filter = ngx_http_write_filter;
return NGX_OK;
}
nginx-0.7.68/src/http/ngx_http_upstream.h 000644 001750 001750 00000026346 11403162273 017533 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#ifndef _NGX_HTTP_UPSTREAM_H_INCLUDED_
#define _NGX_HTTP_UPSTREAM_H_INCLUDED_
#include
#include
#include
#include
#include
#include
#define NGX_HTTP_UPSTREAM_FT_ERROR 0x00000002
#define NGX_HTTP_UPSTREAM_FT_TIMEOUT 0x00000004
#define NGX_HTTP_UPSTREAM_FT_INVALID_HEADER 0x00000008
#define NGX_HTTP_UPSTREAM_FT_HTTP_500 0x00000010
#define NGX_HTTP_UPSTREAM_FT_HTTP_502 0x00000020
#define NGX_HTTP_UPSTREAM_FT_HTTP_503 0x00000040
#define NGX_HTTP_UPSTREAM_FT_HTTP_504 0x00000080
#define NGX_HTTP_UPSTREAM_FT_HTTP_404 0x00000100
#define NGX_HTTP_UPSTREAM_FT_UPDATING 0x00000200
#define NGX_HTTP_UPSTREAM_FT_BUSY_LOCK 0x00000400
#define NGX_HTTP_UPSTREAM_FT_MAX_WAITING 0x00000800
#define NGX_HTTP_UPSTREAM_FT_NOLIVE 0x40000000
#define NGX_HTTP_UPSTREAM_FT_OFF 0x80000000
#define NGX_HTTP_UPSTREAM_FT_STATUS (NGX_HTTP_UPSTREAM_FT_HTTP_500 \
|NGX_HTTP_UPSTREAM_FT_HTTP_502 \
|NGX_HTTP_UPSTREAM_FT_HTTP_503 \
|NGX_HTTP_UPSTREAM_FT_HTTP_504 \
|NGX_HTTP_UPSTREAM_FT_HTTP_404)
#define NGX_HTTP_UPSTREAM_INVALID_HEADER 40
#define NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT 0x00000002
#define NGX_HTTP_UPSTREAM_IGN_XA_EXPIRES 0x00000004
#define NGX_HTTP_UPSTREAM_IGN_EXPIRES 0x00000008
#define NGX_HTTP_UPSTREAM_IGN_CACHE_CONTROL 0x00000010
typedef struct {
ngx_msec_t bl_time;
ngx_uint_t bl_state;
ngx_uint_t status;
time_t response_sec;
ngx_uint_t response_msec;
off_t response_length;
ngx_str_t *peer;
} ngx_http_upstream_state_t;
typedef struct {
ngx_hash_t headers_in_hash;
ngx_array_t upstreams;
/* ngx_http_upstream_srv_conf_t */
} ngx_http_upstream_main_conf_t;
typedef struct ngx_http_upstream_srv_conf_s ngx_http_upstream_srv_conf_t;
typedef ngx_int_t (*ngx_http_upstream_init_pt)(ngx_conf_t *cf,
ngx_http_upstream_srv_conf_t *us);
typedef ngx_int_t (*ngx_http_upstream_init_peer_pt)(ngx_http_request_t *r,
ngx_http_upstream_srv_conf_t *us);
typedef struct {
ngx_http_upstream_init_pt init_upstream;
ngx_http_upstream_init_peer_pt init;
void *data;
} ngx_http_upstream_peer_t;
typedef struct {
ngx_peer_addr_t *addrs;
ngx_uint_t naddrs;
ngx_uint_t weight;
ngx_uint_t max_fails;
time_t fail_timeout;
unsigned down:1;
unsigned backup:1;
} ngx_http_upstream_server_t;
#define NGX_HTTP_UPSTREAM_CREATE 0x0001
#define NGX_HTTP_UPSTREAM_WEIGHT 0x0002
#define NGX_HTTP_UPSTREAM_MAX_FAILS 0x0004
#define NGX_HTTP_UPSTREAM_FAIL_TIMEOUT 0x0008
#define NGX_HTTP_UPSTREAM_DOWN 0x0010
#define NGX_HTTP_UPSTREAM_BACKUP 0x0020
struct ngx_http_upstream_srv_conf_s {
ngx_http_upstream_peer_t peer;
void **srv_conf;
ngx_array_t *servers; /* ngx_http_upstream_server_t */
ngx_uint_t flags;
ngx_str_t host;
u_char *file_name;
ngx_uint_t line;
in_port_t port;
in_port_t default_port;
};
typedef struct {
ngx_http_upstream_srv_conf_t *upstream;
ngx_msec_t connect_timeout;
ngx_msec_t send_timeout;
ngx_msec_t read_timeout;
ngx_msec_t timeout;
size_t send_lowat;
size_t buffer_size;
size_t busy_buffers_size;
size_t max_temp_file_size;
size_t temp_file_write_size;
size_t busy_buffers_size_conf;
size_t max_temp_file_size_conf;
size_t temp_file_write_size_conf;
ngx_bufs_t bufs;
ngx_uint_t ignore_headers;
ngx_uint_t next_upstream;
ngx_uint_t store_access;
ngx_flag_t buffering;
ngx_flag_t pass_request_headers;
ngx_flag_t pass_request_body;
ngx_flag_t ignore_client_abort;
ngx_flag_t intercept_errors;
ngx_flag_t cyclic_temp_file;
ngx_path_t *temp_path;
ngx_hash_t hide_headers_hash;
ngx_array_t *hide_headers;
ngx_array_t *pass_headers;
#if (NGX_HTTP_CACHE)
ngx_shm_zone_t *cache;
ngx_uint_t cache_min_uses;
ngx_uint_t cache_use_stale;
ngx_uint_t cache_methods;
ngx_array_t *cache_valid;
ngx_array_t *no_cache; /* ngx_http_complex_value_t */
#endif
ngx_array_t *store_lengths;
ngx_array_t *store_values;
signed store:2;
unsigned intercept_404:1;
unsigned change_buffering:1;
#if (NGX_HTTP_SSL)
ngx_ssl_t *ssl;
ngx_flag_t ssl_session_reuse;
#endif
} ngx_http_upstream_conf_t;
typedef struct {
ngx_str_t name;
ngx_http_header_handler_pt handler;
ngx_uint_t offset;
ngx_http_header_handler_pt copy_handler;
ngx_uint_t conf;
ngx_uint_t redirect; /* unsigned redirect:1; */
} ngx_http_upstream_header_t;
typedef struct {
ngx_list_t headers;
ngx_uint_t status_n;
ngx_str_t status_line;
ngx_table_elt_t *status;
ngx_table_elt_t *date;
ngx_table_elt_t *server;
ngx_table_elt_t *connection;
ngx_table_elt_t *expires;
ngx_table_elt_t *etag;
ngx_table_elt_t *x_accel_expires;
ngx_table_elt_t *x_accel_redirect;
ngx_table_elt_t *x_accel_limit_rate;
ngx_table_elt_t *content_type;
ngx_table_elt_t *content_length;
ngx_table_elt_t *last_modified;
ngx_table_elt_t *location;
ngx_table_elt_t *accept_ranges;
ngx_table_elt_t *www_authenticate;
#if (NGX_HTTP_GZIP)
ngx_table_elt_t *content_encoding;
#endif
off_t content_length_n;
ngx_array_t cache_control;
} ngx_http_upstream_headers_in_t;
typedef struct {
ngx_str_t host;
in_port_t port;
ngx_uint_t no_port; /* unsigned no_port:1 */
ngx_uint_t naddrs;
in_addr_t *addrs;
struct sockaddr *sockaddr;
socklen_t socklen;
ngx_resolver_ctx_t *ctx;
} ngx_http_upstream_resolved_t;
typedef void (*ngx_http_upstream_handler_pt)(ngx_http_request_t *r,
ngx_http_upstream_t *u);
struct ngx_http_upstream_s {
ngx_http_upstream_handler_pt read_event_handler;
ngx_http_upstream_handler_pt write_event_handler;
ngx_peer_connection_t peer;
ngx_event_pipe_t *pipe;
ngx_chain_t *request_bufs;
ngx_output_chain_ctx_t output;
ngx_chain_writer_ctx_t writer;
ngx_http_upstream_conf_t *conf;
ngx_http_upstream_headers_in_t headers_in;
ngx_http_upstream_resolved_t *resolved;
ngx_buf_t buffer;
size_t length;
ngx_chain_t *out_bufs;
ngx_chain_t *busy_bufs;
ngx_chain_t *free_bufs;
ngx_int_t (*input_filter_init)(void *data);
ngx_int_t (*input_filter)(void *data, ssize_t bytes);
void *input_filter_ctx;
#if (NGX_HTTP_CACHE)
ngx_int_t (*create_key)(ngx_http_request_t *r);
#endif
ngx_int_t (*create_request)(ngx_http_request_t *r);
ngx_int_t (*reinit_request)(ngx_http_request_t *r);
ngx_int_t (*process_header)(ngx_http_request_t *r);
void (*abort_request)(ngx_http_request_t *r);
void (*finalize_request)(ngx_http_request_t *r,
ngx_int_t rc);
ngx_int_t (*rewrite_redirect)(ngx_http_request_t *r,
ngx_table_elt_t *h, size_t prefix);
ngx_msec_t timeout;
ngx_http_upstream_state_t *state;
ngx_str_t method;
ngx_str_t schema;
ngx_str_t uri;
ngx_http_cleanup_pt *cleanup;
unsigned store:1;
unsigned cacheable:1;
unsigned accel:1;
unsigned ssl:1;
#if (NGX_HTTP_CACHE)
unsigned cache_status:3;
#endif
unsigned buffering:1;
unsigned request_sent:1;
unsigned header_sent:1;
};
typedef struct {
ngx_uint_t status;
ngx_uint_t mask;
} ngx_http_upstream_next_t;
ngx_int_t ngx_http_upstream_header_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
ngx_int_t ngx_http_upstream_create(ngx_http_request_t *r);
void ngx_http_upstream_init(ngx_http_request_t *r);
ngx_http_upstream_srv_conf_t *ngx_http_upstream_add(ngx_conf_t *cf,
ngx_url_t *u, ngx_uint_t flags);
ngx_int_t ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf,
ngx_http_upstream_conf_t *conf, ngx_http_upstream_conf_t *prev,
ngx_str_t *default_hide_headers, ngx_hash_init_t *hash);
#define ngx_http_conf_upstream_srv_conf(uscf, module) \
uscf->srv_conf[module.ctx_index]
extern ngx_module_t ngx_http_upstream_module;
extern ngx_conf_bitmask_t ngx_http_upstream_cache_method_mask[];
#endif /* _NGX_HTTP_UPSTREAM_H_INCLUDED_ */
nginx-0.7.68/src/http/ngx_http_cache.h 000644 001750 001750 00000010525 11403162273 016726 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#ifndef _NGX_HTTP_CACHE_H_INCLUDED_
#define _NGX_HTTP_CACHE_H_INCLUDED_
#include
#include
#include
#define NGX_HTTP_CACHE_MISS 1
#define NGX_HTTP_CACHE_EXPIRED 2
#define NGX_HTTP_CACHE_STALE 3
#define NGX_HTTP_CACHE_UPDATING 4
#define NGX_HTTP_CACHE_HIT 5
#define NGX_HTTP_CACHE_KEY_LEN 16
typedef struct {
ngx_uint_t status;
time_t valid;
} ngx_http_cache_valid_t;
typedef struct {
ngx_rbtree_node_t node;
ngx_queue_t queue;
u_char key[NGX_HTTP_CACHE_KEY_LEN
- sizeof(ngx_rbtree_key_t)];
unsigned count:20;
unsigned uses:10;
unsigned valid_msec:10;
unsigned error:10;
unsigned exists:1;
unsigned updating:1;
/* 12 unused bits */
ngx_file_uniq_t uniq;
time_t expire;
time_t valid_sec;
size_t body_start;
off_t length;
} ngx_http_file_cache_node_t;
struct ngx_http_cache_s {
ngx_file_t file;
ngx_array_t keys;
uint32_t crc32;
u_char key[NGX_HTTP_CACHE_KEY_LEN];
ngx_file_uniq_t uniq;
time_t valid_sec;
time_t last_modified;
time_t date;
size_t header_start;
size_t body_start;
off_t length;
ngx_uint_t min_uses;
ngx_uint_t error;
ngx_uint_t valid_msec;
ngx_buf_t *buf;
ngx_http_file_cache_t *file_cache;
ngx_http_file_cache_node_t *node;
unsigned updated:1;
unsigned exists:1;
unsigned temp_file:1;
};
typedef struct {
time_t valid_sec;
time_t last_modified;
time_t date;
uint32_t crc32;
u_short valid_msec;
u_short header_start;
u_short body_start;
} ngx_http_file_cache_header_t;
typedef struct {
ngx_rbtree_t rbtree;
ngx_rbtree_node_t sentinel;
ngx_queue_t queue;
ngx_atomic_t cold;
ngx_atomic_t loading;
off_t size;
} ngx_http_file_cache_sh_t;
struct ngx_http_file_cache_s {
ngx_http_file_cache_sh_t *sh;
ngx_slab_pool_t *shpool;
ngx_path_t *path;
off_t max_size;
size_t bsize;
time_t inactive;
ngx_msec_t last;
ngx_uint_t files;
ngx_shm_zone_t *shm_zone;
};
void ngx_http_file_cache_create_key(ngx_http_request_t *r);
ngx_int_t ngx_http_file_cache_open(ngx_http_request_t *r);
void ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf);
void ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf);
ngx_int_t ngx_http_cache_send(ngx_http_request_t *);
void ngx_http_file_cache_free(ngx_http_request_t *r, ngx_temp_file_t *tf);
time_t ngx_http_file_cache_valid(ngx_array_t *cache_valid, ngx_uint_t status);
char *ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
char *ngx_http_file_cache_valid_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
ngx_int_t ngx_http_cache(ngx_http_request_t *r, ngx_array_t *no_cache);
char *ngx_http_no_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
extern ngx_str_t ngx_http_cache_status[];
#endif /* _NGX_HTTP_CACHE_H_INCLUDED_ */
nginx-0.7.68/src/http/ngx_http_upstream_round_robin.h 000644 001750 001750 00000004556 10723016325 022132 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#ifndef _NGX_HTTP_UPSTREAM_ROUND_ROBIN_H_INCLUDED_
#define _NGX_HTTP_UPSTREAM_ROUND_ROBIN_H_INCLUDED_
#include
#include
#include
typedef struct {
struct sockaddr *sockaddr;
socklen_t socklen;
ngx_str_t name;
ngx_int_t current_weight;
ngx_int_t weight;
ngx_uint_t fails;
time_t accessed;
ngx_uint_t max_fails;
time_t fail_timeout;
ngx_uint_t down; /* unsigned down:1; */
#if (NGX_HTTP_SSL)
ngx_ssl_session_t *ssl_session; /* local to a process */
#endif
} ngx_http_upstream_rr_peer_t;
typedef struct ngx_http_upstream_rr_peers_s ngx_http_upstream_rr_peers_t;
struct ngx_http_upstream_rr_peers_s {
ngx_uint_t single; /* unsigned single:1; */
ngx_uint_t number;
ngx_uint_t last_cached;
/* ngx_mutex_t *mutex; */
ngx_connection_t **cached;
ngx_str_t *name;
ngx_http_upstream_rr_peers_t *next;
ngx_http_upstream_rr_peer_t peer[1];
};
typedef struct {
ngx_http_upstream_rr_peers_t *peers;
ngx_uint_t current;
uintptr_t *tried;
uintptr_t data;
} ngx_http_upstream_rr_peer_data_t;
ngx_int_t ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
ngx_http_upstream_srv_conf_t *us);
ngx_int_t ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r,
ngx_http_upstream_srv_conf_t *us);
ngx_int_t ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
ngx_http_upstream_resolved_t *ur);
ngx_int_t ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc,
void *data);
void ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc,
void *data, ngx_uint_t state);
#if (NGX_HTTP_SSL)
ngx_int_t
ngx_http_upstream_set_round_robin_peer_session(ngx_peer_connection_t *pc,
void *data);
void ngx_http_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc,
void *data);
#endif
#endif /* _NGX_HTTP_UPSTREAM_ROUND_ROBIN_H_INCLUDED_ */
nginx-0.7.68/src/http/ngx_http_variables.c 000644 001750 001750 00000133460 11403144552 017632 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#include
#include
#include
#include
static ngx_int_t ngx_http_variable_request(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static void ngx_http_variable_request_set(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_request_get_size(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static void ngx_http_variable_request_set_size(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_header(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_headers(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_unknown_header_in(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_unknown_header_out(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_request_line(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_cookie(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_argument(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_host(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_binary_remote_addr(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_remote_addr(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_remote_port(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_server_addr(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_server_port(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_scheme(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_is_args(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_document_root(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_realpath_root(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_request_filename(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_server_name(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_request_method(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_remote_user(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_body_bytes_sent(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_request_completion(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_request_body(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_request_body_file(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_sent_content_type(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_sent_content_length(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_sent_location(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_sent_last_modified(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_sent_connection(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_sent_keep_alive(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_sent_transfer_encoding(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_nginx_version(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_hostname(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_pid(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
/*
* TODO:
* Apache CGI: AUTH_TYPE, PATH_INFO (null), PATH_TRANSLATED
* REMOTE_HOST (null), REMOTE_IDENT (null),
* SERVER_SOFTWARE
*
* Apache SSI: DOCUMENT_NAME, LAST_MODIFIED, USER_NAME (file owner)
*/
/*
* the $http_host, $http_user_agent, $http_referer, $http_via,
* and $http_x_forwarded_for variables may be handled by generic
* ngx_http_variable_unknown_header_in(), but for perfomance reasons
* they are handled using dedicated entries
*/
static ngx_http_variable_t ngx_http_core_variables[] = {
{ ngx_string("http_host"), NULL, ngx_http_variable_header,
offsetof(ngx_http_request_t, headers_in.host), 0, 0 },
{ ngx_string("http_user_agent"), NULL, ngx_http_variable_header,
offsetof(ngx_http_request_t, headers_in.user_agent), 0, 0 },
{ ngx_string("http_referer"), NULL, ngx_http_variable_header,
offsetof(ngx_http_request_t, headers_in.referer), 0, 0 },
#if (NGX_HTTP_GZIP)
{ ngx_string("http_via"), NULL, ngx_http_variable_header,
offsetof(ngx_http_request_t, headers_in.via), 0, 0 },
#endif
#if (NGX_HTTP_PROXY || NGX_HTTP_REALIP)
{ ngx_string("http_x_forwarded_for"), NULL, ngx_http_variable_header,
offsetof(ngx_http_request_t, headers_in.x_forwarded_for), 0, 0 },
#endif
{ ngx_string("http_cookie"), NULL, ngx_http_variable_headers,
offsetof(ngx_http_request_t, headers_in.cookies), 0, 0 },
{ ngx_string("content_length"), NULL, ngx_http_variable_header,
offsetof(ngx_http_request_t, headers_in.content_length), 0, 0 },
{ ngx_string("content_type"), NULL, ngx_http_variable_header,
offsetof(ngx_http_request_t, headers_in.content_type), 0, 0 },
{ ngx_string("host"), NULL, ngx_http_variable_host, 0, 0, 0 },
{ ngx_string("binary_remote_addr"), NULL,
ngx_http_variable_binary_remote_addr, 0, 0, 0 },
{ ngx_string("remote_addr"), NULL, ngx_http_variable_remote_addr, 0, 0, 0 },
{ ngx_string("remote_port"), NULL, ngx_http_variable_remote_port, 0, 0, 0 },
{ ngx_string("server_addr"), NULL, ngx_http_variable_server_addr, 0, 0, 0 },
{ ngx_string("server_port"), NULL, ngx_http_variable_server_port, 0, 0, 0 },
{ ngx_string("server_protocol"), NULL, ngx_http_variable_request,
offsetof(ngx_http_request_t, http_protocol), 0, 0 },
{ ngx_string("scheme"), NULL, ngx_http_variable_scheme, 0, 0, 0 },
{ ngx_string("request_uri"), NULL, ngx_http_variable_request,
offsetof(ngx_http_request_t, unparsed_uri), 0, 0 },
{ ngx_string("uri"), NULL, ngx_http_variable_request,
offsetof(ngx_http_request_t, uri),
NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("document_uri"), NULL, ngx_http_variable_request,
offsetof(ngx_http_request_t, uri),
NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("request"), NULL, ngx_http_variable_request_line, 0, 0, 0 },
{ ngx_string("document_root"), NULL,
ngx_http_variable_document_root, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("realpath_root"), NULL,
ngx_http_variable_realpath_root, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("query_string"), NULL, ngx_http_variable_request,
offsetof(ngx_http_request_t, args),
NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("args"),
ngx_http_variable_request_set,
ngx_http_variable_request,
offsetof(ngx_http_request_t, args),
NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("is_args"), NULL, ngx_http_variable_is_args,
0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("request_filename"), NULL,
ngx_http_variable_request_filename, 0,
NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("server_name"), NULL, ngx_http_variable_server_name, 0, 0, 0 },
{ ngx_string("request_method"), NULL,
ngx_http_variable_request_method, 0,
NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("remote_user"), NULL, ngx_http_variable_remote_user, 0, 0, 0 },
{ ngx_string("body_bytes_sent"), NULL, ngx_http_variable_body_bytes_sent,
0, 0, 0 },
{ ngx_string("request_completion"), NULL,
ngx_http_variable_request_completion,
0, 0, 0 },
{ ngx_string("request_body"), NULL,
ngx_http_variable_request_body,
0, 0, 0 },
{ ngx_string("request_body_file"), NULL,
ngx_http_variable_request_body_file,
0, 0, 0 },
{ ngx_string("sent_http_content_type"), NULL,
ngx_http_variable_sent_content_type, 0, 0, 0 },
{ ngx_string("sent_http_content_length"), NULL,
ngx_http_variable_sent_content_length, 0, 0, 0 },
{ ngx_string("sent_http_location"), NULL,
ngx_http_variable_sent_location, 0, 0, 0 },
{ ngx_string("sent_http_last_modified"), NULL,
ngx_http_variable_sent_last_modified, 0, 0, 0 },
{ ngx_string("sent_http_connection"), NULL,
ngx_http_variable_sent_connection, 0, 0, 0 },
{ ngx_string("sent_http_keep_alive"), NULL,
ngx_http_variable_sent_keep_alive, 0, 0, 0 },
{ ngx_string("sent_http_transfer_encoding"), NULL,
ngx_http_variable_sent_transfer_encoding, 0, 0, 0 },
{ ngx_string("sent_http_cache_control"), NULL, ngx_http_variable_headers,
offsetof(ngx_http_request_t, headers_out.cache_control), 0, 0 },
{ ngx_string("limit_rate"), ngx_http_variable_request_set_size,
ngx_http_variable_request_get_size,
offsetof(ngx_http_request_t, limit_rate),
NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("nginx_version"), NULL, ngx_http_variable_nginx_version,
0, 0, 0 },
{ ngx_string("hostname"), NULL, ngx_http_variable_hostname,
0, 0, 0 },
{ ngx_string("pid"), NULL, ngx_http_variable_pid,
0, 0, 0 },
{ ngx_null_string, NULL, NULL, 0, 0, 0 }
};
ngx_http_variable_value_t ngx_http_variable_null_value =
ngx_http_variable("");
ngx_http_variable_value_t ngx_http_variable_true_value =
ngx_http_variable("1");
ngx_http_variable_t *
ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags)
{
ngx_int_t rc;
ngx_uint_t i;
ngx_hash_key_t *key;
ngx_http_variable_t *v;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
key = cmcf->variables_keys->keys.elts;
for (i = 0; i < cmcf->variables_keys->keys.nelts; i++) {
if (name->len != key[i].key.len
|| ngx_strncasecmp(name->data, key[i].key.data, name->len) != 0)
{
continue;
}
v = key[i].value;
if (!(v->flags & NGX_HTTP_VAR_CHANGEABLE)) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the duplicate \"%V\" variable", name);
return NULL;
}
return v;
}
v = ngx_palloc(cf->pool, sizeof(ngx_http_variable_t));
if (v == NULL) {
return NULL;
}
v->name.len = name->len;
v->name.data = ngx_pnalloc(cf->pool, name->len);
if (v->name.data == NULL) {
return NULL;
}
ngx_strlow(v->name.data, name->data, name->len);
v->set_handler = NULL;
v->get_handler = NULL;
v->data = 0;
v->flags = flags;
v->index = 0;
rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v, 0);
if (rc == NGX_ERROR) {
return NULL;
}
if (rc == NGX_BUSY) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"conflicting variable name \"%V\"", name);
return NULL;
}
return v;
}
ngx_int_t
ngx_http_get_variable_index(ngx_conf_t *cf, ngx_str_t *name)
{
ngx_uint_t i;
ngx_http_variable_t *v;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
v = cmcf->variables.elts;
if (v == NULL) {
if (ngx_array_init(&cmcf->variables, cf->pool, 4,
sizeof(ngx_http_variable_t))
!= NGX_OK)
{
return NGX_ERROR;
}
} else {
for (i = 0; i < cmcf->variables.nelts; i++) {
if (name->len != v[i].name.len
|| ngx_strncasecmp(name->data, v[i].name.data, name->len) != 0)
{
continue;
}
return i;
}
}
v = ngx_array_push(&cmcf->variables);
if (v == NULL) {
return NGX_ERROR;
}
v->name.len = name->len;
v->name.data = ngx_pnalloc(cf->pool, name->len);
if (v->name.data == NULL) {
return NGX_ERROR;
}
ngx_strlow(v->name.data, name->data, name->len);
v->set_handler = NULL;
v->get_handler = NULL;
v->data = 0;
v->flags = 0;
v->index = cmcf->variables.nelts - 1;
return cmcf->variables.nelts - 1;
}
ngx_http_variable_value_t *
ngx_http_get_indexed_variable(ngx_http_request_t *r, ngx_uint_t index)
{
ngx_http_variable_t *v;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
if (cmcf->variables.nelts <= index) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
"unknown variable index: %d", index);
return NULL;
}
if (r->variables[index].not_found || r->variables[index].valid) {
return &r->variables[index];
}
v = cmcf->variables.elts;
if (v[index].get_handler(r, &r->variables[index], v[index].data)
== NGX_OK)
{
if (v[index].flags & NGX_HTTP_VAR_NOCACHEABLE) {
r->variables[index].no_cacheable = 1;
}
return &r->variables[index];
}
r->variables[index].valid = 0;
r->variables[index].not_found = 1;
return NULL;
}
ngx_http_variable_value_t *
ngx_http_get_flushed_variable(ngx_http_request_t *r, ngx_uint_t index)
{
ngx_http_variable_value_t *v;
v = &r->variables[index];
if (v->valid) {
if (!v->no_cacheable) {
return v;
}
v->valid = 0;
v->not_found = 0;
}
return ngx_http_get_indexed_variable(r, index);
}
ngx_http_variable_value_t *
ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key)
{
ngx_http_variable_t *v;
ngx_http_variable_value_t *vv;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
v = ngx_hash_find(&cmcf->variables_hash, key, name->data, name->len);
if (v) {
if (v->flags & NGX_HTTP_VAR_INDEXED) {
return ngx_http_get_flushed_variable(r, v->index);
} else {
vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
if (vv && v->get_handler(r, vv, v->data) == NGX_OK) {
return vv;
}
return NULL;
}
}
vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
if (vv == NULL) {
return NULL;
}
if (ngx_strncmp(name->data, "http_", 5) == 0) {
if (ngx_http_variable_unknown_header_in(r, vv, (uintptr_t) name)
== NGX_OK)
{
return vv;
}
return NULL;
}
if (ngx_strncmp(name->data, "sent_http_", 10) == 0) {
if (ngx_http_variable_unknown_header_out(r, vv, (uintptr_t) name)
== NGX_OK)
{
return vv;
}
return NULL;
}
if (ngx_strncmp(name->data, "upstream_http_", 14) == 0) {
if (ngx_http_upstream_header_variable(r, vv, (uintptr_t) name)
== NGX_OK)
{
return vv;
}
return NULL;
}
if (ngx_strncmp(name->data, "cookie_", 7) == 0) {
if (ngx_http_variable_cookie(r, vv, (uintptr_t) name) == NGX_OK) {
return vv;
}
return NULL;
}
if (ngx_strncmp(name->data, "arg_", 4) == 0) {
if (ngx_http_variable_argument(r, vv, (uintptr_t) name) == NGX_OK) {
return vv;
}
return NULL;
}
vv->not_found = 1;
return vv;
}
static ngx_int_t
ngx_http_variable_request(ngx_http_request_t *r, ngx_http_variable_value_t *v,
uintptr_t data)
{
ngx_str_t *s;
s = (ngx_str_t *) ((char *) r + data);
if (s->data) {
v->len = s->len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = s->data;
} else {
v->not_found = 1;
}
return NGX_OK;
}
static void
ngx_http_variable_request_set(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
ngx_str_t *s;
s = (ngx_str_t *) ((char *) r + data);
s->len = v->len;
s->data = v->data;
}
static ngx_int_t
ngx_http_variable_request_get_size(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
size_t *sp;
sp = (size_t *) ((char *) r + data);
v->data = ngx_pnalloc(r->pool, NGX_SIZE_T_LEN);
if (v->data == NULL) {
return NGX_ERROR;
}
v->len = ngx_sprintf(v->data, "%uz", *sp) - v->data;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
return NGX_OK;
}
static void
ngx_http_variable_request_set_size(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
ssize_t s, *sp;
ngx_str_t val;
val.len = v->len;
val.data = v->data;
s = ngx_parse_size(&val);
if (s == NGX_ERROR) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"invalid size \"%V\"", &val);
return;
}
sp = (ssize_t *) ((char *) r + data);
*sp = s;
return;
}
static ngx_int_t
ngx_http_variable_header(ngx_http_request_t *r, ngx_http_variable_value_t *v,
uintptr_t data)
{
ngx_table_elt_t *h;
h = *(ngx_table_elt_t **) ((char *) r + data);
if (h) {
v->len = h->value.len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = h->value.data;
} else {
v->not_found = 1;
}
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_headers(ngx_http_request_t *r, ngx_http_variable_value_t *v,
uintptr_t data)
{
ssize_t len;
u_char *p;
ngx_uint_t i, n;
ngx_array_t *a;
ngx_table_elt_t **h;
a = (ngx_array_t *) ((char *) r + data);
n = a->nelts;
if (n == 0) {
v->not_found = 1;
return NGX_OK;
}
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
h = a->elts;
if (n == 1) {
v->len = (*h)->value.len;
v->data = (*h)->value.data;
return NGX_OK;
}
len = - (ssize_t) (sizeof("; ") - 1);
for (i = 0; i < n; i++) {
len += h[i]->value.len + sizeof("; ") - 1;
}
p = ngx_pnalloc(r->pool, len);
if (p == NULL) {
return NGX_ERROR;
}
v->len = len;
v->data = p;
for (i = 0; /* void */ ; i++) {
p = ngx_copy(p, h[i]->value.data, h[i]->value.len);
if (i == n - 1) {
break;
}
*p++ = ';'; *p++ = ' ';
}
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_unknown_header_in(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
&r->headers_in.headers.part,
sizeof("http_") - 1);
}
static ngx_int_t
ngx_http_variable_unknown_header_out(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
&r->headers_out.headers.part,
sizeof("sent_http_") - 1);
}
ngx_int_t
ngx_http_variable_unknown_header(ngx_http_variable_value_t *v, ngx_str_t *var,
ngx_list_part_t *part, size_t prefix)
{
u_char ch;
ngx_uint_t i, n;
ngx_table_elt_t *header;
header = part->elts;
for (i = 0; /* void */ ; i++) {
if (i >= part->nelts) {
if (part->next == NULL) {
break;
}
part = part->next;
header = part->elts;
i = 0;
}
for (n = 0; n + prefix < var->len && n < header[i].key.len; n++) {
ch = header[i].key.data[n];
if (ch >= 'A' && ch <= 'Z') {
ch |= 0x20;
} else if (ch == '-') {
ch = '_';
}
if (var->data[n + prefix] != ch) {
break;
}
}
if (n + prefix == var->len && n == header[i].key.len) {
v->len = header[i].value.len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = header[i].value.data;
return NGX_OK;
}
}
v->not_found = 1;
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_request_line(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
u_char *p, *s;
s = r->request_line.data;
if (s == NULL) {
s = r->request_start;
if (s == NULL) {
v->not_found = 1;
return NGX_OK;
}
for (p = s; p < r->header_in->last; p++) {
if (*p == CR || *p == LF) {
break;
}
}
r->request_line.len = p - s;
r->request_line.data = s;
}
v->len = r->request_line.len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = s;
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_cookie(ngx_http_request_t *r, ngx_http_variable_value_t *v,
uintptr_t data)
{
ngx_str_t *name = (ngx_str_t *) data;
ngx_str_t cookie, s;
s.len = name->len - (sizeof("cookie_") - 1);
s.data = name->data + sizeof("cookie_") - 1;
if (ngx_http_parse_multi_header_lines(&r->headers_in.cookies, &s, &cookie)
== NGX_DECLINED)
{
v->not_found = 1;
return NGX_OK;
}
v->len = cookie.len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = cookie.data;
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_argument(ngx_http_request_t *r, ngx_http_variable_value_t *v,
uintptr_t data)
{
ngx_str_t *name = (ngx_str_t *) data;
u_char *arg;
size_t len;
ngx_str_t value;
len = name->len - (sizeof("arg_") - 1);
arg = name->data + sizeof("arg_") - 1;
if (ngx_http_arg(r, arg, len, &value) != NGX_OK) {
v->not_found = 1;
return NGX_OK;
}
v->data = value.data;
v->len = value.len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_host(ngx_http_request_t *r, ngx_http_variable_value_t *v,
uintptr_t data)
{
ngx_http_core_srv_conf_t *cscf;
if (r->headers_in.server.len) {
v->len = r->headers_in.server.len;
v->data = r->headers_in.server.data;
} else {
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
v->len = cscf->server_name.len;
v->data = cscf->server_name.data;
}
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_binary_remote_addr(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
struct sockaddr_in *sin;
#if (NGX_HAVE_INET6)
struct sockaddr_in6 *sin6;
#endif
switch (r->connection->sockaddr->sa_family) {
#if (NGX_HAVE_INET6)
case AF_INET6:
sin6 = (struct sockaddr_in6 *) r->connection->sockaddr;
v->len = sizeof(struct in6_addr);
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = (u_char *) &sin6->sin6_addr;
break;
#endif
default: /* AF_INET */
sin = (struct sockaddr_in *) r->connection->sockaddr;
v->len = sizeof(in_addr_t);
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = (u_char *) &sin->sin_addr;
break;
}
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_remote_addr(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
v->len = r->connection->addr_text.len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = r->connection->addr_text.data;
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_remote_port(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
ngx_uint_t port;
struct sockaddr_in *sin;
#if (NGX_HAVE_INET6)
struct sockaddr_in6 *sin6;
#endif
v->len = 0;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = ngx_pnalloc(r->pool, sizeof("65535") - 1);
if (v->data == NULL) {
return NGX_ERROR;
}
switch (r->connection->sockaddr->sa_family) {
#if (NGX_HAVE_INET6)
case AF_INET6:
sin6 = (struct sockaddr_in6 *) r->connection->sockaddr;
port = ntohs(sin6->sin6_port);
break;
#endif
default: /* AF_INET */
sin = (struct sockaddr_in *) r->connection->sockaddr;
port = ntohs(sin->sin_port);
break;
}
if (port > 0 && port < 65536) {
v->len = ngx_sprintf(v->data, "%ui", port) - v->data;
}
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_server_addr(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
ngx_str_t s;
u_char addr[NGX_SOCKADDR_STRLEN];
s.len = NGX_SOCKADDR_STRLEN;
s.data = addr;
if (ngx_connection_local_sockaddr(r->connection, &s, 0) != NGX_OK) {
return NGX_ERROR;
}
s.data = ngx_pnalloc(r->pool, s.len);
if (s.data == NULL) {
return NGX_ERROR;
}
ngx_memcpy(s.data, addr, s.len);
v->len = s.len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = s.data;
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_server_port(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
ngx_uint_t port;
struct sockaddr_in *sin;
#if (NGX_HAVE_INET6)
struct sockaddr_in6 *sin6;
#endif
v->len = 0;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
if (ngx_connection_local_sockaddr(r->connection, NULL, 0) != NGX_OK) {
return NGX_ERROR;
}
v->data = ngx_pnalloc(r->pool, sizeof("65535") - 1);
if (v->data == NULL) {
return NGX_ERROR;
}
switch (r->connection->local_sockaddr->sa_family) {
#if (NGX_HAVE_INET6)
case AF_INET6:
sin6 = (struct sockaddr_in6 *) r->connection->local_sockaddr;
port = ntohs(sin6->sin6_port);
break;
#endif
default: /* AF_INET */
sin = (struct sockaddr_in *) r->connection->local_sockaddr;
port = ntohs(sin->sin_port);
break;
}
if (port > 0 && port < 65536) {
v->len = ngx_sprintf(v->data, "%ui", port) - v->data;
}
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_scheme(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
#if (NGX_HTTP_SSL)
if (r->connection->ssl) {
v->len = sizeof("https") - 1;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = (u_char *) "https";
return NGX_OK;
}
#endif
v->len = sizeof("http") - 1;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = (u_char *) "http";
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_is_args(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
if (r->args.len == 0) {
v->len = 0;
v->data = NULL;
return NGX_OK;
}
v->len = 1;
v->data = (u_char *) "?";
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_document_root(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
ngx_str_t path;
ngx_http_core_loc_conf_t *clcf;
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (clcf->root_lengths == NULL) {
v->len = clcf->root.len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = clcf->root.data;
} else {
if (ngx_http_script_run(r, &path, clcf->root_lengths->elts, 0,
clcf->root_values->elts)
== NULL)
{
return NGX_ERROR;
}
if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &path, 0) != NGX_OK) {
return NGX_ERROR;
}
v->len = path.len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = path.data;
}
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_realpath_root(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
size_t len;
ngx_str_t path;
ngx_http_core_loc_conf_t *clcf;
u_char real[NGX_MAX_PATH];
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (clcf->root_lengths == NULL) {
path = clcf->root;
} else {
if (ngx_http_script_run(r, &path, clcf->root_lengths->elts, 1,
clcf->root_values->elts)
== NULL)
{
return NGX_ERROR;
}
path.data[path.len - 1] = '\0';
if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &path, 0) != NGX_OK) {
return NGX_ERROR;
}
}
if (ngx_realpath(path.data, real) == NULL) {
ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
ngx_realpath_n " \"%s\" failed", path.data);
return NGX_ERROR;
}
len = ngx_strlen(real);
v->data = ngx_pnalloc(r->pool, len);
if (v->data == NULL) {
return NGX_ERROR;
}
v->len = len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
ngx_memcpy(v->data, real, len);
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_request_filename(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
size_t root;
ngx_str_t path;
if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) {
return NGX_ERROR;
}
/* ngx_http_map_uri_to_path() allocates memory for terminating '\0' */
v->len = path.len - 1;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = path.data;
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_server_name(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
ngx_http_core_srv_conf_t *cscf;
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
v->len = cscf->server_name.len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = cscf->server_name.data;
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_request_method(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
if (r->main->method_name.data) {
v->len = r->main->method_name.len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = r->main->method_name.data;
} else {
v->not_found = 1;
}
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_remote_user(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
ngx_int_t rc;
rc = ngx_http_auth_basic_user(r);
if (rc == NGX_DECLINED) {
v->not_found = 1;
return NGX_OK;
}
if (rc == NGX_ERROR) {
return NGX_ERROR;
}
v->len = r->headers_in.user.len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = r->headers_in.user.data;
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_body_bytes_sent(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
off_t sent;
u_char *p;
sent = r->connection->sent - r->header_size;
if (sent < 0) {
sent = 0;
}
p = ngx_pnalloc(r->pool, NGX_OFF_T_LEN);
if (p == NULL) {
return NGX_ERROR;
}
v->len = ngx_sprintf(p, "%O", sent) - p;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = p;
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_sent_content_type(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
if (r->headers_out.content_type.len) {
v->len = r->headers_out.content_type.len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = r->headers_out.content_type.data;
} else {
v->not_found = 1;
}
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_sent_content_length(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
u_char *p;
if (r->headers_out.content_length) {
v->len = r->headers_out.content_length->value.len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = r->headers_out.content_length->value.data;
return NGX_OK;
}
if (r->headers_out.content_length_n >= 0) {
p = ngx_pnalloc(r->pool, NGX_OFF_T_LEN);
if (p == NULL) {
return NGX_ERROR;
}
v->len = ngx_sprintf(p, "%O", r->headers_out.content_length_n) - p;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = p;
return NGX_OK;
}
v->not_found = 1;
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_sent_location(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
ngx_str_t name;
if (r->headers_out.location) {
v->len = r->headers_out.location->value.len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = r->headers_out.location->value.data;
return NGX_OK;
}
name.len = sizeof("sent_http_location") - 1;
name.data = (u_char *) "sent_http_location";
return ngx_http_variable_unknown_header(v, &name,
&r->headers_out.headers.part,
sizeof("sent_http_") - 1);
}
static ngx_int_t
ngx_http_variable_sent_last_modified(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
u_char *p;
if (r->headers_out.last_modified) {
v->len = r->headers_out.last_modified->value.len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = r->headers_out.last_modified->value.data;
return NGX_OK;
}
if (r->headers_out.last_modified_time >= 0) {
p = ngx_pnalloc(r->pool,
sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT") - 1);
if (p == NULL) {
return NGX_ERROR;
}
v->len = ngx_http_time(p, r->headers_out.last_modified_time) - p;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = p;
return NGX_OK;
}
v->not_found = 1;
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_sent_connection(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
size_t len;
char *p;
if (r->keepalive) {
len = sizeof("keep-alive") - 1;
p = "keep-alive";
} else {
len = sizeof("close") - 1;
p = "close";
}
v->len = len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = (u_char *) p;
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_sent_keep_alive(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
u_char *p;
ngx_http_core_loc_conf_t *clcf;
if (r->keepalive) {
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (clcf->keepalive_header) {
p = ngx_pnalloc(r->pool, sizeof("timeout=") - 1 + NGX_TIME_T_LEN);
if (p == NULL) {
return NGX_ERROR;
}
v->len = ngx_sprintf(p, "timeout=%T", clcf->keepalive_header) - p;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = p;
return NGX_OK;
}
}
v->not_found = 1;
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_sent_transfer_encoding(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
if (r->chunked) {
v->len = sizeof("chunked") - 1;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = (u_char *) "chunked";
} else {
v->not_found = 1;
}
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_request_completion(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
if (r->request_complete) {
v->len = 2;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = (u_char *) "OK";
return NGX_OK;
}
v->len = 0;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = (u_char *) "";
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_request_body(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
u_char *p;
size_t len;
ngx_buf_t *buf, *next;
ngx_chain_t *cl;
if (r->request_body == NULL
|| r->request_body->bufs == NULL
|| r->request_body->temp_file)
{
v->not_found = 1;
return NGX_OK;
}
cl = r->request_body->bufs;
buf = cl->buf;
if (cl->next == NULL) {
v->len = buf->last - buf->pos;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = buf->pos;
return NGX_OK;
}
next = cl->next->buf;
len = (buf->last - buf->pos) + (next->last - next->pos);
p = ngx_pnalloc(r->pool, len);
if (p == NULL) {
return NGX_ERROR;
}
v->data = p;
p = ngx_cpymem(p, buf->pos, buf->last - buf->pos);
ngx_memcpy(p, next->pos, next->last - next->pos);
v->len = len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_request_body_file(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
if (r->request_body == NULL || r->request_body->temp_file == NULL) {
v->not_found = 1;
return NGX_OK;
}
v->len = r->request_body->temp_file->file.name.len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = r->request_body->temp_file->file.name.data;
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_nginx_version(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
v->len = sizeof(NGINX_VERSION) - 1;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = (u_char *) NGINX_VERSION;
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_hostname(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
v->len = ngx_cycle->hostname.len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = ngx_cycle->hostname.data;
return NGX_OK;
}
static ngx_int_t
ngx_http_variable_pid(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
u_char *p;
p = ngx_pnalloc(r->pool, NGX_INT64_LEN);
if (p == NULL) {
return NGX_ERROR;
}
v->len = ngx_sprintf(p, "%P", ngx_pid) - p;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = p;
return NGX_OK;
}
ngx_int_t
ngx_http_variables_add_core_vars(ngx_conf_t *cf)
{
ngx_int_t rc;
ngx_http_variable_t *v;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
cmcf->variables_keys = ngx_pcalloc(cf->temp_pool,
sizeof(ngx_hash_keys_arrays_t));
if (cmcf->variables_keys == NULL) {
return NGX_ERROR;
}
cmcf->variables_keys->pool = cf->pool;
cmcf->variables_keys->temp_pool = cf->pool;
if (ngx_hash_keys_array_init(cmcf->variables_keys, NGX_HASH_SMALL)
!= NGX_OK)
{
return NGX_ERROR;
}
for (v = ngx_http_core_variables; v->name.len; v++) {
rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v,
NGX_HASH_READONLY_KEY);
if (rc == NGX_OK) {
continue;
}
if (rc == NGX_BUSY) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"conflicting variable name \"%V\"", &v->name);
}
return NGX_ERROR;
}
return NGX_OK;
}
ngx_int_t
ngx_http_variables_init_vars(ngx_conf_t *cf)
{
ngx_uint_t i, n;
ngx_hash_key_t *key;
ngx_hash_init_t hash;
ngx_http_variable_t *v, *av;
ngx_http_core_main_conf_t *cmcf;
/* set the handlers for the indexed http variables */
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
v = cmcf->variables.elts;
key = cmcf->variables_keys->keys.elts;
for (i = 0; i < cmcf->variables.nelts; i++) {
for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {
av = key[n].value;
if (av->get_handler
&& v[i].name.len == key[n].key.len
&& ngx_strncmp(v[i].name.data, key[n].key.data, v[i].name.len)
== 0)
{
v[i].get_handler = av->get_handler;
v[i].data = av->data;
av->flags |= NGX_HTTP_VAR_INDEXED;
v[i].flags = av->flags;
av->index = i;
goto next;
}
}
if (ngx_strncmp(v[i].name.data, "http_", 5) == 0) {
v[i].get_handler = ngx_http_variable_unknown_header_in;
v[i].data = (uintptr_t) &v[i].name;
continue;
}
if (ngx_strncmp(v[i].name.data, "sent_http_", 10) == 0) {
v[i].get_handler = ngx_http_variable_unknown_header_out;
v[i].data = (uintptr_t) &v[i].name;
continue;
}
if (ngx_strncmp(v[i].name.data, "upstream_http_", 14) == 0) {
v[i].get_handler = ngx_http_upstream_header_variable;
v[i].data = (uintptr_t) &v[i].name;
v[i].flags = NGX_HTTP_VAR_NOCACHEABLE;
continue;
}
if (ngx_strncmp(v[i].name.data, "cookie_", 7) == 0) {
v[i].get_handler = ngx_http_variable_cookie;
v[i].data = (uintptr_t) &v[i].name;
continue;
}
if (ngx_strncmp(v[i].name.data, "arg_", 4) == 0) {
v[i].get_handler = ngx_http_variable_argument;
v[i].data = (uintptr_t) &v[i].name;
v[i].flags = NGX_HTTP_VAR_NOCACHEABLE;
continue;
}
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"unknown \"%V\" variable", &v[i].name);
return NGX_ERROR;
next:
continue;
}
for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {
av = key[n].value;
if (av->flags & NGX_HTTP_VAR_NOHASH) {
key[n].key.data = NULL;
}
}
hash.hash = &cmcf->variables_hash;
hash.key = ngx_hash_key;
hash.max_size = cmcf->variables_hash_max_size;
hash.bucket_size = cmcf->variables_hash_bucket_size;
hash.name = "variables_hash";
hash.pool = cf->pool;
hash.temp_pool = NULL;
if (ngx_hash_init(&hash, cmcf->variables_keys->keys.elts,
cmcf->variables_keys->keys.nelts)
!= NGX_OK)
{
return NGX_ERROR;
}
cmcf->variables_keys = NULL;
return NGX_OK;
}
void
ngx_http_variable_value_rbtree_insert(ngx_rbtree_node_t *temp,
ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
{
ngx_rbtree_node_t **p;
ngx_http_variable_value_node_t *vvn, *vvt;
for ( ;; ) {
vvn = (ngx_http_variable_value_node_t *) node;
vvt = (ngx_http_variable_value_node_t *) temp;
if (node->key != temp->key) {
p = (node->key < temp->key) ? &temp->left : &temp->right;
} else if (vvn->len != vvt->len) {
p = (vvn->len < vvt->len) ? &temp->left : &temp->right;
} else {
p = (ngx_memcmp(vvn->value->data, vvt->value->data, vvn->len) < 0)
? &temp->left : &temp->right;
}
if (*p == sentinel) {
break;
}
temp = *p;
}
*p = node;
node->parent = temp;
node->left = sentinel;
node->right = sentinel;
ngx_rbt_red(node);
}
ngx_http_variable_value_t *
ngx_http_variable_value_lookup(ngx_rbtree_t *rbtree, ngx_str_t *val,
uint32_t hash)
{
ngx_int_t rc;
ngx_rbtree_node_t *node, *sentinel;
ngx_http_variable_value_node_t *vvn;
node = rbtree->root;
sentinel = rbtree->sentinel;
while (node != sentinel) {
vvn = (ngx_http_variable_value_node_t *) node;
if (hash != node->key) {
node = (hash < node->key) ? node->left : node->right;
continue;
}
if (val->len != vvn->len) {
node = (val->len < vvn->len) ? node->left : node->right;
continue;
}
rc = ngx_memcmp(val->data, vvn->value->data, val->len);
if (rc < 0) {
node = node->left;
continue;
}
if (rc > 0) {
node = node->right;
continue;
}
return vvn->value;
}
return NULL;
}
nginx-0.7.68/src/http/ngx_http_script.h 000644 001750 001750 00000016503 11175313721 017173 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#ifndef _NGX_HTTP_SCRIPT_H_INCLUDED_
#define _NGX_HTTP_SCRIPT_H_INCLUDED_
#include
#include
#include
typedef struct {
u_char *ip;
u_char *pos;
ngx_http_variable_value_t *sp;
ngx_str_t buf;
ngx_str_t line;
/* the start of the rewritten arguments */
u_char *args;
unsigned flushed:1;
unsigned skip:1;
unsigned quote:1;
unsigned is_args:1;
unsigned log:1;
ngx_int_t status;
ngx_http_request_t *request;
} ngx_http_script_engine_t;
typedef struct {
ngx_conf_t *cf;
ngx_str_t *source;
ngx_array_t **flushes;
ngx_array_t **lengths;
ngx_array_t **values;
ngx_uint_t variables;
ngx_uint_t ncaptures;
ngx_uint_t captures_mask;
ngx_uint_t size;
void *main;
unsigned compile_args:1;
unsigned complete_lengths:1;
unsigned complete_values:1;
unsigned zero:1;
unsigned conf_prefix:1;
unsigned root_prefix:1;
unsigned dup_capture:1;
unsigned args:1;
} ngx_http_script_compile_t;
typedef struct {
ngx_str_t value;
ngx_uint_t *flushes;
void *lengths;
void *values;
} ngx_http_complex_value_t;
typedef struct {
ngx_conf_t *cf;
ngx_str_t *value;
ngx_http_complex_value_t *complex_value;
unsigned zero:1;
unsigned conf_prefix:1;
unsigned root_prefix:1;
} ngx_http_compile_complex_value_t;
typedef void (*ngx_http_script_code_pt) (ngx_http_script_engine_t *e);
typedef size_t (*ngx_http_script_len_code_pt) (ngx_http_script_engine_t *e);
typedef struct {
ngx_http_script_code_pt code;
uintptr_t len;
} ngx_http_script_copy_code_t;
typedef struct {
ngx_http_script_code_pt code;
uintptr_t index;
} ngx_http_script_var_code_t;
typedef struct {
ngx_http_script_code_pt code;
ngx_http_set_variable_pt handler;
uintptr_t data;
} ngx_http_script_var_handler_code_t;
typedef struct {
ngx_http_script_code_pt code;
uintptr_t n;
} ngx_http_script_copy_capture_code_t;
#if (NGX_PCRE)
typedef struct {
ngx_http_script_code_pt code;
ngx_regex_t *regex;
ngx_array_t *lengths;
uintptr_t size;
uintptr_t ncaptures;
uintptr_t status;
uintptr_t next;
uintptr_t test:1;
uintptr_t negative_test:1;
uintptr_t uri:1;
uintptr_t args:1;
/* add the r->args to the new arguments */
uintptr_t add_args:1;
uintptr_t redirect:1;
uintptr_t break_cycle:1;
ngx_str_t name;
} ngx_http_script_regex_code_t;
typedef struct {
ngx_http_script_code_pt code;
uintptr_t uri:1;
uintptr_t args:1;
/* add the r->args to the new arguments */
uintptr_t add_args:1;
uintptr_t redirect:1;
} ngx_http_script_regex_end_code_t;
#endif
typedef struct {
ngx_http_script_code_pt code;
uintptr_t conf_prefix;
} ngx_http_script_full_name_code_t;
typedef struct {
ngx_http_script_code_pt code;
uintptr_t status;
uintptr_t null;
} ngx_http_script_return_code_t;
typedef enum {
ngx_http_script_file_plain = 0,
ngx_http_script_file_not_plain,
ngx_http_script_file_dir,
ngx_http_script_file_not_dir,
ngx_http_script_file_exists,
ngx_http_script_file_not_exists,
ngx_http_script_file_exec,
ngx_http_script_file_not_exec
} ngx_http_script_file_op_e;
typedef struct {
ngx_http_script_code_pt code;
uintptr_t op;
} ngx_http_script_file_code_t;
typedef struct {
ngx_http_script_code_pt code;
uintptr_t next;
void **loc_conf;
} ngx_http_script_if_code_t;
typedef struct {
ngx_http_script_code_pt code;
ngx_array_t *lengths;
} ngx_http_script_complex_value_code_t;
typedef struct {
ngx_http_script_code_pt code;
uintptr_t value;
uintptr_t text_len;
uintptr_t text_data;
} ngx_http_script_value_code_t;
void ngx_http_script_flush_complex_value(ngx_http_request_t *r,
ngx_http_complex_value_t *val);
ngx_int_t ngx_http_complex_value(ngx_http_request_t *r,
ngx_http_complex_value_t *val, ngx_str_t *value);
ngx_int_t ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv);
ngx_uint_t ngx_http_script_variables_count(ngx_str_t *value);
ngx_int_t ngx_http_script_compile(ngx_http_script_compile_t *sc);
u_char *ngx_http_script_run(ngx_http_request_t *r, ngx_str_t *value,
void *code_lengths, size_t reserved, void *code_values);
void ngx_http_script_flush_no_cacheable_variables(ngx_http_request_t *r,
ngx_array_t *indices);
void *ngx_http_script_start_code(ngx_pool_t *pool, ngx_array_t **codes,
size_t size);
void *ngx_http_script_add_code(ngx_array_t *codes, size_t size, void *code);
size_t ngx_http_script_copy_len_code(ngx_http_script_engine_t *e);
void ngx_http_script_copy_code(ngx_http_script_engine_t *e);
size_t ngx_http_script_copy_var_len_code(ngx_http_script_engine_t *e);
void ngx_http_script_copy_var_code(ngx_http_script_engine_t *e);
size_t ngx_http_script_copy_capture_len_code(ngx_http_script_engine_t *e);
void ngx_http_script_copy_capture_code(ngx_http_script_engine_t *e);
size_t ngx_http_script_mark_args_code(ngx_http_script_engine_t *e);
void ngx_http_script_start_args_code(ngx_http_script_engine_t *e);
#if (NGX_PCRE)
void ngx_http_script_regex_start_code(ngx_http_script_engine_t *e);
void ngx_http_script_regex_end_code(ngx_http_script_engine_t *e);
#endif
void ngx_http_script_return_code(ngx_http_script_engine_t *e);
void ngx_http_script_break_code(ngx_http_script_engine_t *e);
void ngx_http_script_if_code(ngx_http_script_engine_t *e);
void ngx_http_script_equal_code(ngx_http_script_engine_t *e);
void ngx_http_script_not_equal_code(ngx_http_script_engine_t *e);
void ngx_http_script_file_code(ngx_http_script_engine_t *e);
void ngx_http_script_complex_value_code(ngx_http_script_engine_t *e);
void ngx_http_script_value_code(ngx_http_script_engine_t *e);
void ngx_http_script_set_var_code(ngx_http_script_engine_t *e);
void ngx_http_script_var_set_handler_code(ngx_http_script_engine_t *e);
void ngx_http_script_var_code(ngx_http_script_engine_t *e);
void ngx_http_script_nop_code(ngx_http_script_engine_t *e);
#endif /* _NGX_HTTP_SCRIPT_H_INCLUDED_ */
nginx-0.7.68/src/http/ngx_http_parse.c 000644 001750 001750 00000111115 11403162632 016764 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#include
#include
#include
static uint32_t usual[] = {
0xffffdbfe, /* 1111 1111 1111 1111 1101 1011 1111 1110 */
/* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
0x7fff37d6, /* 0111 1111 1111 1111 0011 0111 1101 0110 */
/* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
#if (NGX_WIN32)
0xefffffff, /* 1110 1111 1111 1111 1111 1111 1111 1111 */
#else
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
#endif
/* ~}| {zyx wvut srqp onml kjih gfed cba` */
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
};
#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)
#define ngx_str3_cmp(m, c0, c1, c2, c3) \
*(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)
#define ngx_str3Ocmp(m, c0, c1, c2, c3) \
*(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)
#define ngx_str4cmp(m, c0, c1, c2, c3) \
*(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)
#define ngx_str5cmp(m, c0, c1, c2, c3, c4) \
*(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
&& m[4] == c4
#define ngx_str6cmp(m, c0, c1, c2, c3, c4, c5) \
*(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
&& (((uint32_t *) m)[1] & 0xffff) == ((c5 << 8) | c4)
#define ngx_str7_cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
*(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
&& ((uint32_t *) m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4)
#define ngx_str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
*(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
&& ((uint32_t *) m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4)
#define ngx_str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) \
*(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
&& ((uint32_t *) m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4) \
&& m[8] == c8
#else /* !(NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED) */
#define ngx_str3_cmp(m, c0, c1, c2, c3) \
m[0] == c0 && m[1] == c1 && m[2] == c2
#define ngx_str3Ocmp(m, c0, c1, c2, c3) \
m[0] == c0 && m[2] == c2 && m[3] == c3
#define ngx_str4cmp(m, c0, c1, c2, c3) \
m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3
#define ngx_str5cmp(m, c0, c1, c2, c3, c4) \
m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 && m[4] == c4
#define ngx_str6cmp(m, c0, c1, c2, c3, c4, c5) \
m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \
&& m[4] == c4 && m[5] == c5
#define ngx_str7_cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \
&& m[4] == c4 && m[5] == c5 && m[6] == c6
#define ngx_str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \
&& m[4] == c4 && m[5] == c5 && m[6] == c6 && m[7] == c7
#define ngx_str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) \
m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \
&& m[4] == c4 && m[5] == c5 && m[6] == c6 && m[7] == c7 && m[8] == c8
#endif
/* gcc, icc, msvc and others compile these switches as an jump table */
ngx_int_t
ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
{
u_char c, ch, *p, *m;
enum {
sw_start = 0,
sw_method,
sw_spaces_before_uri,
sw_schema,
sw_schema_slash,
sw_schema_slash_slash,
sw_host,
sw_port,
sw_after_slash_in_uri,
sw_check_uri,
sw_uri,
sw_http_09,
sw_http_H,
sw_http_HT,
sw_http_HTT,
sw_http_HTTP,
sw_first_major_digit,
sw_major_digit,
sw_first_minor_digit,
sw_minor_digit,
sw_spaces_after_digit,
sw_almost_done
} state;
state = r->state;
for (p = b->pos; p < b->last; p++) {
ch = *p;
switch (state) {
/* HTTP methods: GET, HEAD, POST */
case sw_start:
r->request_start = p;
if (ch == CR || ch == LF) {
break;
}
if ((ch < 'A' || ch > 'Z') && ch != '_') {
return NGX_HTTP_PARSE_INVALID_METHOD;
}
state = sw_method;
break;
case sw_method:
if (ch == ' ') {
r->method_end = p - 1;
m = r->request_start;
switch (p - m) {
case 3:
if (ngx_str3_cmp(m, 'G', 'E', 'T', ' ')) {
r->method = NGX_HTTP_GET;
break;
}
if (ngx_str3_cmp(m, 'P', 'U', 'T', ' ')) {
r->method = NGX_HTTP_PUT;
break;
}
break;
case 4:
if (m[1] == 'O') {
if (ngx_str3Ocmp(m, 'P', 'O', 'S', 'T')) {
r->method = NGX_HTTP_POST;
break;
}
if (ngx_str3Ocmp(m, 'C', 'O', 'P', 'Y')) {
r->method = NGX_HTTP_COPY;
break;
}
if (ngx_str3Ocmp(m, 'M', 'O', 'V', 'E')) {
r->method = NGX_HTTP_MOVE;
break;
}
if (ngx_str3Ocmp(m, 'L', 'O', 'C', 'K')) {
r->method = NGX_HTTP_LOCK;
break;
}
} else {
if (ngx_str4cmp(m, 'H', 'E', 'A', 'D')) {
r->method = NGX_HTTP_HEAD;
break;
}
}
break;
case 5:
if (ngx_str5cmp(m, 'M', 'K', 'C', 'O', 'L')) {
r->method = NGX_HTTP_MKCOL;
}
if (ngx_str5cmp(m, 'T', 'R', 'A', 'C', 'E')) {
r->method = NGX_HTTP_TRACE;
}
break;
case 6:
if (ngx_str6cmp(m, 'D', 'E', 'L', 'E', 'T', 'E')) {
r->method = NGX_HTTP_DELETE;
break;
}
if (ngx_str6cmp(m, 'U', 'N', 'L', 'O', 'C', 'K')) {
r->method = NGX_HTTP_UNLOCK;
break;
}
break;
case 7:
if (ngx_str7_cmp(m, 'O', 'P', 'T', 'I', 'O', 'N', 'S', ' '))
{
r->method = NGX_HTTP_OPTIONS;
}
break;
case 8:
if (ngx_str8cmp(m, 'P', 'R', 'O', 'P', 'F', 'I', 'N', 'D'))
{
r->method = NGX_HTTP_PROPFIND;
}
break;
case 9:
if (ngx_str9cmp(m,
'P', 'R', 'O', 'P', 'P', 'A', 'T', 'C', 'H'))
{
r->method = NGX_HTTP_PROPPATCH;
}
break;
}
state = sw_spaces_before_uri;
break;
}
if ((ch < 'A' || ch > 'Z') && ch != '_') {
return NGX_HTTP_PARSE_INVALID_METHOD;
}
break;
/* space* before URI */
case sw_spaces_before_uri:
if (ch == '/' ){
r->uri_start = p;
state = sw_after_slash_in_uri;
break;
}
c = (u_char) (ch | 0x20);
if (c >= 'a' && c <= 'z') {
r->schema_start = p;
state = sw_schema;
break;
}
switch (ch) {
case ' ':
break;
default:
return NGX_HTTP_PARSE_INVALID_REQUEST;
}
break;
case sw_schema:
c = (u_char) (ch | 0x20);
if (c >= 'a' && c <= 'z') {
break;
}
switch (ch) {
case ':':
r->schema_end = p;
state = sw_schema_slash;
break;
default:
return NGX_HTTP_PARSE_INVALID_REQUEST;
}
break;
case sw_schema_slash:
switch (ch) {
case '/':
state = sw_schema_slash_slash;
break;
default:
return NGX_HTTP_PARSE_INVALID_REQUEST;
}
break;
case sw_schema_slash_slash:
switch (ch) {
case '/':
r->host_start = p + 1;
state = sw_host;
break;
default:
return NGX_HTTP_PARSE_INVALID_REQUEST;
}
break;
case sw_host:
c = (u_char) (ch | 0x20);
if (c >= 'a' && c <= 'z') {
break;
}
if ((ch >= '0' && ch <= '9') || ch == '.' || ch == '-') {
break;
}
r->host_end = p;
switch (ch) {
case ':':
state = sw_port;
break;
case '/':
r->uri_start = p;
state = sw_after_slash_in_uri;
break;
case ' ':
/*
* use single "/" from request line to preserve pointers,
* if request line will be copied to large client buffer
*/
r->uri_start = r->schema_end + 1;
r->uri_end = r->schema_end + 2;
state = sw_http_09;
break;
default:
return NGX_HTTP_PARSE_INVALID_REQUEST;
}
break;
case sw_port:
if (ch >= '0' && ch <= '9') {
break;
}
switch (ch) {
case '/':
r->port_end = p;
r->uri_start = p;
state = sw_after_slash_in_uri;
break;
case ' ':
r->port_end = p;
/*
* use single "/" from request line to preserve pointers,
* if request line will be copied to large client buffer
*/
r->uri_start = r->schema_end + 1;
r->uri_end = r->schema_end + 2;
state = sw_http_09;
break;
default:
return NGX_HTTP_PARSE_INVALID_REQUEST;
}
break;
/* check "/.", "//", "%", and "\" (Win32) in URI */
case sw_after_slash_in_uri:
if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
state = sw_check_uri;
break;
}
switch (ch) {
case ' ':
r->uri_end = p;
state = sw_http_09;
break;
case CR:
r->uri_end = p;
r->http_minor = 9;
state = sw_almost_done;
break;
case LF:
r->uri_end = p;
r->http_minor = 9;
goto done;
case '.':
r->complex_uri = 1;
state = sw_uri;
break;
case '%':
r->quoted_uri = 1;
state = sw_uri;
break;
case '/':
r->complex_uri = 1;
state = sw_uri;
break;
#if (NGX_WIN32)
case '\\':
r->complex_uri = 1;
state = sw_uri;
break;
#endif
case '?':
r->args_start = p + 1;
state = sw_uri;
break;
case '#':
r->complex_uri = 1;
state = sw_uri;
break;
case '+':
r->plus_in_uri = 1;
break;
case '\0':
return NGX_HTTP_PARSE_INVALID_REQUEST;
default:
state = sw_check_uri;
break;
}
break;
/* check "/", "%" and "\" (Win32) in URI */
case sw_check_uri:
if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
break;
}
switch (ch) {
case '/':
r->uri_ext = NULL;
state = sw_after_slash_in_uri;
break;
case '.':
r->uri_ext = p + 1;
break;
case ' ':
r->uri_end = p;
state = sw_http_09;
break;
case CR:
r->uri_end = p;
r->http_minor = 9;
state = sw_almost_done;
break;
case LF:
r->uri_end = p;
r->http_minor = 9;
goto done;
#if (NGX_WIN32)
case '\\':
r->complex_uri = 1;
state = sw_after_slash_in_uri;
break;
#endif
case '%':
r->quoted_uri = 1;
state = sw_uri;
break;
case '?':
r->args_start = p + 1;
state = sw_uri;
break;
case '#':
r->complex_uri = 1;
state = sw_uri;
break;
case '+':
r->plus_in_uri = 1;
break;
case '\0':
return NGX_HTTP_PARSE_INVALID_REQUEST;
}
break;
/* URI */
case sw_uri:
if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
break;
}
switch (ch) {
case ' ':
r->uri_end = p;
state = sw_http_09;
break;
case CR:
r->uri_end = p;
r->http_minor = 9;
state = sw_almost_done;
break;
case LF:
r->uri_end = p;
r->http_minor = 9;
goto done;
case '#':
r->complex_uri = 1;
break;
case '\0':
return NGX_HTTP_PARSE_INVALID_REQUEST;
}
break;
/* space+ after URI */
case sw_http_09:
switch (ch) {
case ' ':
break;
case CR:
r->http_minor = 9;
state = sw_almost_done;
break;
case LF:
r->http_minor = 9;
goto done;
case 'H':
r->http_protocol.data = p;
state = sw_http_H;
break;
default:
return NGX_HTTP_PARSE_INVALID_REQUEST;
}
break;
case sw_http_H:
switch (ch) {
case 'T':
state = sw_http_HT;
break;
default:
return NGX_HTTP_PARSE_INVALID_REQUEST;
}
break;
case sw_http_HT:
switch (ch) {
case 'T':
state = sw_http_HTT;
break;
default:
return NGX_HTTP_PARSE_INVALID_REQUEST;
}
break;
case sw_http_HTT:
switch (ch) {
case 'P':
state = sw_http_HTTP;
break;
default:
return NGX_HTTP_PARSE_INVALID_REQUEST;
}
break;
case sw_http_HTTP:
switch (ch) {
case '/':
state = sw_first_major_digit;
break;
default:
return NGX_HTTP_PARSE_INVALID_REQUEST;
}
break;
/* first digit of major HTTP version */
case sw_first_major_digit:
if (ch < '1' || ch > '9') {
return NGX_HTTP_PARSE_INVALID_REQUEST;
}
r->http_major = ch - '0';
state = sw_major_digit;
break;
/* major HTTP version or dot */
case sw_major_digit:
if (ch == '.') {
state = sw_first_minor_digit;
break;
}
if (ch < '0' || ch > '9') {
return NGX_HTTP_PARSE_INVALID_REQUEST;
}
r->http_major = r->http_major * 10 + ch - '0';
break;
/* first digit of minor HTTP version */
case sw_first_minor_digit:
if (ch < '0' || ch > '9') {
return NGX_HTTP_PARSE_INVALID_REQUEST;
}
r->http_minor = ch - '0';
state = sw_minor_digit;
break;
/* minor HTTP version or end of request line */
case sw_minor_digit:
if (ch == CR) {
state = sw_almost_done;
break;
}
if (ch == LF) {
goto done;
}
if (ch == ' ') {
state = sw_spaces_after_digit;
break;
}
if (ch < '0' || ch > '9') {
return NGX_HTTP_PARSE_INVALID_REQUEST;
}
r->http_minor = r->http_minor * 10 + ch - '0';
break;
case sw_spaces_after_digit:
switch (ch) {
case ' ':
break;
case CR:
state = sw_almost_done;
break;
case LF:
goto done;
default:
return NGX_HTTP_PARSE_INVALID_REQUEST;
}
break;
/* end of request line */
case sw_almost_done:
r->request_end = p - 1;
switch (ch) {
case LF:
goto done;
default:
return NGX_HTTP_PARSE_INVALID_REQUEST;
}
}
}
b->pos = p;
r->state = state;
return NGX_AGAIN;
done:
b->pos = p + 1;
if (r->request_end == NULL) {
r->request_end = p;
}
r->http_version = r->http_major * 1000 + r->http_minor;
r->state = sw_start;
if (r->http_version == 9 && r->method != NGX_HTTP_GET) {
return NGX_HTTP_PARSE_INVALID_09_METHOD;
}
return NGX_OK;
}
ngx_int_t
ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b,
ngx_uint_t allow_underscores)
{
u_char c, ch, *p;
ngx_uint_t hash, i;
enum {
sw_start = 0,
sw_name,
sw_space_before_value,
sw_value,
sw_space_after_value,
sw_ignore_line,
sw_almost_done,
sw_header_almost_done
} state;
/* the last '\0' is not needed because string is zero terminated */
static u_char lowcase[] =
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0-\0\0" "0123456789\0\0\0\0\0\0"
"\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0"
"\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
state = r->state;
hash = r->header_hash;
i = r->lowcase_index;
for (p = b->pos; p < b->last; p++) {
ch = *p;
switch (state) {
/* first char */
case sw_start:
r->header_name_start = p;
r->invalid_header = 0;
switch (ch) {
case CR:
r->header_end = p;
state = sw_header_almost_done;
break;
case LF:
r->header_end = p;
goto header_done;
default:
state = sw_name;
c = lowcase[ch];
if (c) {
hash = ngx_hash(0, c);
r->lowcase_header[0] = c;
i = 1;
break;
}
r->invalid_header = 1;
break;
}
break;
/* header name */
case sw_name:
c = lowcase[ch];
if (c) {
hash = ngx_hash(hash, c);
r->lowcase_header[i++] = c;
i &= (NGX_HTTP_LC_HEADER_LEN - 1);
break;
}
if (ch == '_') {
if (allow_underscores) {
hash = ngx_hash(hash, ch);
r->lowcase_header[i++] = ch;
i &= (NGX_HTTP_LC_HEADER_LEN - 1);
} else {
r->invalid_header = 1;
}
break;
}
if (ch == ':') {
r->header_name_end = p;
state = sw_space_before_value;
break;
}
if (ch == CR) {
r->header_name_end = p;
r->header_start = p;
r->header_end = p;
state = sw_almost_done;
break;
}
if (ch == LF) {
r->header_name_end = p;
r->header_start = p;
r->header_end = p;
goto done;
}
/* IIS may send the duplicate "HTTP/1.1 ..." lines */
if (ch == '/'
&& r->upstream
&& p - r->header_name_start == 4
&& ngx_strncmp(r->header_name_start, "HTTP", 4) == 0)
{
state = sw_ignore_line;
break;
}
r->invalid_header = 1;
break;
/* space* before header value */
case sw_space_before_value:
switch (ch) {
case ' ':
break;
case CR:
r->header_start = p;
r->header_end = p;
state = sw_almost_done;
break;
case LF:
r->header_start = p;
r->header_end = p;
goto done;
default:
r->header_start = p;
state = sw_value;
break;
}
break;
/* header value */
case sw_value:
switch (ch) {
case ' ':
r->header_end = p;
state = sw_space_after_value;
break;
case CR:
r->header_end = p;
state = sw_almost_done;
break;
case LF:
r->header_end = p;
goto done;
}
break;
/* space* before end of header line */
case sw_space_after_value:
switch (ch) {
case ' ':
break;
case CR:
state = sw_almost_done;
break;
case LF:
goto done;
default:
state = sw_value;
break;
}
break;
/* ignore header line */
case sw_ignore_line:
switch (ch) {
case LF:
state = sw_start;
break;
default:
break;
}
break;
/* end of header line */
case sw_almost_done:
switch (ch) {
case LF:
goto done;
case CR:
break;
default:
return NGX_HTTP_PARSE_INVALID_HEADER;
}
break;
/* end of header */
case sw_header_almost_done:
switch (ch) {
case LF:
goto header_done;
default:
return NGX_HTTP_PARSE_INVALID_HEADER;
}
}
}
b->pos = p;
r->state = state;
r->header_hash = hash;
r->lowcase_index = i;
return NGX_AGAIN;
done:
b->pos = p + 1;
r->state = sw_start;
r->header_hash = hash;
r->lowcase_index = i;
return NGX_OK;
header_done:
b->pos = p + 1;
r->state = sw_start;
return NGX_HTTP_PARSE_HEADER_DONE;
}
ngx_int_t
ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes)
{
u_char c, ch, decoded, *p, *u;
enum {
sw_usual = 0,
sw_slash,
sw_dot,
sw_dot_dot,
sw_quoted,
sw_quoted_second
} state, quoted_state;
#if (NGX_SUPPRESS_WARN)
decoded = '\0';
quoted_state = sw_usual;
#endif
state = sw_usual;
p = r->uri_start;
u = r->uri.data;
r->uri_ext = NULL;
r->args_start = NULL;
ch = *p++;
while (p <= r->uri_end) {
/*
* we use "ch = *p++" inside the cycle, but this operation is safe,
* because after the URI there is always at least one charcter:
* the line feed
*/
ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"s:%d in:'%Xd:%c', out:'%c'", state, ch, ch, *u);
switch (state) {
case sw_usual:
if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
*u++ = ch;
ch = *p++;
break;
}
switch(ch) {
#if (NGX_WIN32)
case '\\':
r->uri_ext = NULL;
if (p == r->uri_start + r->uri.len) {
/*
* we omit the last "\" to cause redirect because
* the browsers do not treat "\" as "/" in relative URL path
*/
break;
}
state = sw_slash;
*u++ = '/';
break;
#endif
case '/':
r->uri_ext = NULL;
state = sw_slash;
*u++ = ch;
break;
case '%':
quoted_state = state;
state = sw_quoted;
break;
case '?':
r->args_start = p;
goto args;
case '#':
goto done;
case '.':
r->uri_ext = u + 1;
*u++ = ch;
break;
case '+':
r->plus_in_uri = 1;
default:
*u++ = ch;
break;
}
ch = *p++;
break;
case sw_slash:
if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
state = sw_usual;
*u++ = ch;
ch = *p++;
break;
}
switch(ch) {
#if (NGX_WIN32)
case '\\':
break;
#endif
case '/':
if (!merge_slashes) {
*u++ = ch;
}
break;
case '.':
state = sw_dot;
*u++ = ch;
break;
case '%':
quoted_state = state;
state = sw_quoted;
break;
case '?':
r->args_start = p;
goto args;
case '#':
goto done;
case '+':
r->plus_in_uri = 1;
default:
state = sw_usual;
*u++ = ch;
break;
}
ch = *p++;
break;
case sw_dot:
if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
state = sw_usual;
*u++ = ch;
ch = *p++;
break;
}
switch(ch) {
#if (NGX_WIN32)
case '\\':
#endif
case '/':
state = sw_slash;
u--;
break;
case '.':
state = sw_dot_dot;
*u++ = ch;
break;
case '%':
quoted_state = state;
state = sw_quoted;
break;
case '?':
r->args_start = p;
goto args;
case '#':
goto done;
case '+':
r->plus_in_uri = 1;
default:
state = sw_usual;
*u++ = ch;
break;
}
ch = *p++;
break;
case sw_dot_dot:
if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
state = sw_usual;
*u++ = ch;
ch = *p++;
break;
}
switch(ch) {
#if (NGX_WIN32)
case '\\':
#endif
case '/':
state = sw_slash;
u -= 5;
for ( ;; ) {
if (u < r->uri.data) {
return NGX_HTTP_PARSE_INVALID_REQUEST;
}
if (*u == '/') {
u++;
break;
}
u--;
}
break;
case '%':
quoted_state = state;
state = sw_quoted;
break;
case '?':
r->args_start = p;
goto args;
case '#':
goto done;
case '+':
r->plus_in_uri = 1;
default:
state = sw_usual;
*u++ = ch;
break;
}
ch = *p++;
break;
case sw_quoted:
r->quoted_uri = 1;
if (ch >= '0' && ch <= '9') {
decoded = (u_char) (ch - '0');
state = sw_quoted_second;
ch = *p++;
break;
}
c = (u_char) (ch | 0x20);
if (c >= 'a' && c <= 'f') {
decoded = (u_char) (c - 'a' + 10);
state = sw_quoted_second;
ch = *p++;
break;
}
return NGX_HTTP_PARSE_INVALID_REQUEST;
case sw_quoted_second:
if (ch >= '0' && ch <= '9') {
ch = (u_char) ((decoded << 4) + ch - '0');
if (ch == '%') {
state = sw_usual;
*u++ = ch;
ch = *p++;
break;
}
if (ch == '#') {
*u++ = ch;
ch = *p++;
} else if (ch == '\0') {
return NGX_HTTP_PARSE_INVALID_REQUEST;
}
state = quoted_state;
break;
}
c = (u_char) (ch | 0x20);
if (c >= 'a' && c <= 'f') {
ch = (u_char) ((decoded << 4) + c - 'a' + 10);
if (ch == '?') {
*u++ = ch;
ch = *p++;
} else if (ch == '+') {
r->plus_in_uri = 1;
}
state = quoted_state;
break;
}
return NGX_HTTP_PARSE_INVALID_REQUEST;
}
}
done:
r->uri.len = u - r->uri.data;
if (r->uri_ext) {
r->exten.len = u - r->uri_ext;
r->exten.data = r->uri_ext;
}
r->uri_ext = NULL;
return NGX_OK;
args:
while (p < r->uri_end) {
if (*p++ != '#') {
continue;
}
r->args.len = p - 1 - r->args_start;
r->args.data = r->args_start;
r->args_start = NULL;
break;
}
r->uri.len = u - r->uri.data;
if (r->uri_ext) {
r->exten.len = u - r->uri_ext;
r->exten.data = r->uri_ext;
}
r->uri_ext = NULL;
return NGX_OK;
}
ngx_int_t
ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri,
ngx_str_t *args, ngx_uint_t *flags)
{
u_char ch, *p;
size_t len;
len = uri->len;
p = uri->data;
if (len == 0 || p[0] == '?') {
goto unsafe;
}
if (p[0] == '.' && len == 3 && p[1] == '.' && (ngx_path_separator(p[2]))) {
goto unsafe;
}
for ( /* void */ ; len; len--) {
ch = *p++;
if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
continue;
}
if (ch == '?') {
args->len = len - 1;
args->data = p;
uri->len -= len;
return NGX_OK;
}
if (ch == '\0') {
goto unsafe;
}
if (ngx_path_separator(ch) && len > 2) {
/* detect "/../" */
if (p[0] == '.' && p[1] == '.' && ngx_path_separator(p[2])) {
goto unsafe;
}
}
}
return NGX_OK;
unsafe:
if (*flags & NGX_HTTP_LOG_UNSAFE) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"unsafe URI \"%V\" was detected", uri);
}
return NGX_ERROR;
}
ngx_int_t
ngx_http_parse_multi_header_lines(ngx_array_t *headers, ngx_str_t *name,
ngx_str_t *value)
{
ngx_uint_t i;
u_char *start, *last, *end, ch;
ngx_table_elt_t **h;
h = headers->elts;
for (i = 0; i < headers->nelts; i++) {
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, headers->pool->log, 0,
"parse header: \"%V: %V\"", &h[i]->key, &h[i]->value);
if (name->len > h[i]->value.len) {
continue;
}
start = h[i]->value.data;
end = h[i]->value.data + h[i]->value.len;
while (start < end) {
if (ngx_strncasecmp(start, name->data, name->len) != 0) {
goto skip;
}
for (start += name->len; start < end && *start == ' '; start++) {
/* void */
}
if (value == NULL) {
if (start == end || *start == ',') {
return i;
}
goto skip;
}
if (start == end || *start++ != '=') {
/* the invalid header value */
goto skip;
}
while (start < end && *start == ' ') { start++; }
for (last = start; last < end && *last != ';'; last++) {
/* void */
}
value->len = last - start;
value->data = start;
return i;
skip:
while (start < end) {
ch = *start++;
if (ch == ';' || ch == ',') {
break;
}
}
while (start < end && *start == ' ') { start++; }
}
}
return NGX_DECLINED;
}
ngx_int_t
ngx_http_arg(ngx_http_request_t *r, u_char *name, size_t len, ngx_str_t *value)
{
u_char *p, *last;
if (r->args.len == 0) {
return NGX_DECLINED;
}
p = r->args.data;
last = p + r->args.len;
for ( /* void */ ; p < last; p++) {
/* we need '=' after name, so drop one char from last */
p = ngx_strlcasestrn(p, last - 1, name, len - 1);
if (p == NULL) {
return NGX_DECLINED;
}
if ((p == r->args.data || *(p - 1) == '&') && *(p + len) == '=') {
value->data = p + len + 1;
p = ngx_strlchr(p, last, '&');
if (p == NULL) {
p = r->args.data + r->args.len;
}
value->len = p - value->data;
return NGX_OK;
}
}
return NGX_DECLINED;
}
void
ngx_http_split_args(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args)
{
u_char *p, *last;
last = uri->data + uri->len;
p = ngx_strlchr(uri->data, last, '?');
if (p) {
uri->len = p - uri->data;
p++;
args->len = last - p;
args->data = p;
} else {
args->len = 0;
}
}
nginx-0.7.68/src/http/ngx_http_config.h 000644 001750 001750 00000005214 11171441371 017130 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#ifndef _NGX_HTTP_CONFIG_H_INCLUDED_
#define _NGX_HTTP_CONFIG_H_INCLUDED_
#include
#include
#include
typedef struct {
void **main_conf;
void **srv_conf;
void **loc_conf;
} ngx_http_conf_ctx_t;
typedef struct {
ngx_int_t (*preconfiguration)(ngx_conf_t *cf);
ngx_int_t (*postconfiguration)(ngx_conf_t *cf);
void *(*create_main_conf)(ngx_conf_t *cf);
char *(*init_main_conf)(ngx_conf_t *cf, void *conf);
void *(*create_srv_conf)(ngx_conf_t *cf);
char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);
void *(*create_loc_conf)(ngx_conf_t *cf);
char *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);
} ngx_http_module_t;
#define NGX_HTTP_MODULE 0x50545448 /* "HTTP" */
#define NGX_HTTP_MAIN_CONF 0x02000000
#define NGX_HTTP_SRV_CONF 0x04000000
#define NGX_HTTP_LOC_CONF 0x08000000
#define NGX_HTTP_UPS_CONF 0x10000000
#define NGX_HTTP_SIF_CONF 0x20000000
#define NGX_HTTP_LIF_CONF 0x40000000
#define NGX_HTTP_LMT_CONF 0x80000000
#define NGX_HTTP_MAIN_CONF_OFFSET offsetof(ngx_http_conf_ctx_t, main_conf)
#define NGX_HTTP_SRV_CONF_OFFSET offsetof(ngx_http_conf_ctx_t, srv_conf)
#define NGX_HTTP_LOC_CONF_OFFSET offsetof(ngx_http_conf_ctx_t, loc_conf)
#define ngx_http_get_module_main_conf(r, module) \
(r)->main_conf[module.ctx_index]
#define ngx_http_get_module_srv_conf(r, module) (r)->srv_conf[module.ctx_index]
#define ngx_http_get_module_loc_conf(r, module) (r)->loc_conf[module.ctx_index]
/*
* ngx_http_conf_get_module_srv_conf() and ngx_http_conf_get_module_loc_conf()
* must not be used at the merge phase because cf->ctx points to http{}'s ctx
*/
#define ngx_http_conf_get_module_main_conf(cf, module) \
((ngx_http_conf_ctx_t *) cf->ctx)->main_conf[module.ctx_index]
#define ngx_http_conf_get_module_srv_conf(cf, module) \
((ngx_http_conf_ctx_t *) cf->ctx)->srv_conf[module.ctx_index]
#define ngx_http_conf_get_module_loc_conf(cf, module) \
((ngx_http_conf_ctx_t *) cf->ctx)->loc_conf[module.ctx_index]
#define ngx_http_cycle_get_module_main_conf(cycle, module) \
(cycle->conf_ctx[ngx_http_module.index] ? \
((ngx_http_conf_ctx_t *) cycle->conf_ctx[ngx_http_module.index]) \
->main_conf[module.ctx_index]: \
NULL)
#endif /* _NGX_HTTP_CONFIG_H_INCLUDED_ */
nginx-0.7.68/src/http/ngx_http_variables.h 000644 001750 001750 00000004726 11403144552 017641 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#ifndef _NGX_HTTP_VARIABLES_H_INCLUDED_
#define _NGX_HTTP_VARIABLES_H_INCLUDED_
#include
#include
#include
typedef ngx_variable_value_t ngx_http_variable_value_t;
#define ngx_http_variable(v) { sizeof(v) - 1, 1, 0, 0, 0, (u_char *) v }
typedef struct ngx_http_variable_s ngx_http_variable_t;
typedef void (*ngx_http_set_variable_pt) (ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
typedef ngx_int_t (*ngx_http_get_variable_pt) (ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
#define NGX_HTTP_VAR_CHANGEABLE 1
#define NGX_HTTP_VAR_NOCACHEABLE 2
#define NGX_HTTP_VAR_INDEXED 4
#define NGX_HTTP_VAR_NOHASH 8
struct ngx_http_variable_s {
ngx_str_t name; /* must be first to build the hash */
ngx_http_set_variable_pt set_handler;
ngx_http_get_variable_pt get_handler;
uintptr_t data;
ngx_uint_t flags;
ngx_uint_t index;
};
ngx_http_variable_t *ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name,
ngx_uint_t flags);
ngx_int_t ngx_http_get_variable_index(ngx_conf_t *cf, ngx_str_t *name);
ngx_http_variable_value_t *ngx_http_get_indexed_variable(ngx_http_request_t *r,
ngx_uint_t index);
ngx_http_variable_value_t *ngx_http_get_flushed_variable(ngx_http_request_t *r,
ngx_uint_t index);
ngx_http_variable_value_t *ngx_http_get_variable(ngx_http_request_t *r,
ngx_str_t *name, ngx_uint_t key);
ngx_int_t ngx_http_variable_unknown_header(ngx_http_variable_value_t *v,
ngx_str_t *var, ngx_list_part_t *part, size_t prefix);
#define ngx_http_clear_variable(r, index) r->variables0[index].text.data = NULL;
ngx_int_t ngx_http_variables_add_core_vars(ngx_conf_t *cf);
ngx_int_t ngx_http_variables_init_vars(ngx_conf_t *cf);
typedef struct {
ngx_rbtree_node_t node;
size_t len;
ngx_http_variable_value_t *value;
} ngx_http_variable_value_node_t;
void ngx_http_variable_value_rbtree_insert(ngx_rbtree_node_t *temp,
ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
ngx_http_variable_value_t *ngx_http_variable_value_lookup(ngx_rbtree_t *rbtree,
ngx_str_t *name, uint32_t hash);
extern ngx_http_variable_value_t ngx_http_variable_null_value;
extern ngx_http_variable_value_t ngx_http_variable_true_value;
#endif /* _NGX_HTTP_VARIABLES_H_INCLUDED_ */
nginx-0.7.68/src/http/ngx_http_postpone_filter_module.c 000644 001750 001750 00000010665 11117226730 022445 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#include
#include
#include
static ngx_int_t ngx_http_postpone_filter_add(ngx_http_request_t *r,
ngx_chain_t *in);
static ngx_int_t ngx_http_postpone_filter_init(ngx_conf_t *cf);
static ngx_http_module_t ngx_http_postpone_filter_module_ctx = {
NULL, /* preconfiguration */
ngx_http_postpone_filter_init, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
NULL, /* create location configuration */
NULL /* merge location configuration */
};
ngx_module_t ngx_http_postpone_filter_module = {
NGX_MODULE_V1,
&ngx_http_postpone_filter_module_ctx, /* module context */
NULL, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_http_output_body_filter_pt ngx_http_next_filter;
static ngx_int_t
ngx_http_postpone_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
ngx_connection_t *c;
ngx_http_postponed_request_t *pr;
c = r->connection;
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http postpone filter \"%V?%V\" %p", &r->uri, &r->args, in);
if (r != c->data) {
if (in) {
ngx_http_postpone_filter_add(r, in);
return NGX_OK;
}
#if 0
/* TODO: SSI may pass NULL */
ngx_log_error(NGX_LOG_ALERT, c->log, 0,
"http postpone filter NULL inactive request",
&r->uri, &r->args);
#endif
return NGX_OK;
}
if (r->postponed == NULL) {
if (in || c->buffered) {
return ngx_http_next_filter(r->main, in);
}
return NGX_OK;
}
if (in) {
ngx_http_postpone_filter_add(r, in);
}
do {
pr = r->postponed;
if (pr->request) {
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http postpone filter wake \"%V?%V\"",
&pr->request->uri, &pr->request->args);
r->postponed = pr->next;
c->data = pr->request;
return ngx_http_post_request(pr->request);
}
if (pr->out == NULL) {
ngx_log_error(NGX_LOG_ALERT, c->log, 0,
"http postpone filter NULL output",
&r->uri, &r->args);
} else {
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http postpone filter output \"%V?%V\"",
&r->uri, &r->args);
if (ngx_http_next_filter(r->main, pr->out) == NGX_ERROR) {
return NGX_ERROR;
}
}
r->postponed = pr->next;
} while (r->postponed);
return NGX_OK;
}
static ngx_int_t
ngx_http_postpone_filter_add(ngx_http_request_t *r, ngx_chain_t *in)
{
ngx_http_postponed_request_t *pr, **ppr;
if (r->postponed) {
for (pr = r->postponed; pr->next; pr = pr->next) { /* void */ }
if (pr->request == NULL) {
goto found;
}
ppr = &pr->next;
} else {
ppr = &r->postponed;
}
pr = ngx_palloc(r->pool, sizeof(ngx_http_postponed_request_t));
if (pr == NULL) {
return NGX_ERROR;
}
*ppr = pr;
pr->request = NULL;
pr->out = NULL;
pr->next = NULL;
found:
if (ngx_chain_add_copy(r->pool, &pr->out, in) == NGX_OK) {
return NGX_OK;
}
return NGX_ERROR;
}
static ngx_int_t
ngx_http_postpone_filter_init(ngx_conf_t *cf)
{
ngx_http_next_filter = ngx_http_top_body_filter;
ngx_http_top_body_filter = ngx_http_postpone_filter;
return NGX_OK;
}
nginx-0.7.68/src/http/modules/ngx_http_upstream_ip_hash_module.c 000644 001750 001750 00000014167 11147723352 024242 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#include
#include
#include
typedef struct {
/* the round robin data must be first */
ngx_http_upstream_rr_peer_data_t rrp;
ngx_uint_t hash;
u_char addr[3];
u_char tries;
ngx_event_get_peer_pt get_rr_peer;
} ngx_http_upstream_ip_hash_peer_data_t;
static ngx_int_t ngx_http_upstream_init_ip_hash_peer(ngx_http_request_t *r,
ngx_http_upstream_srv_conf_t *us);
static ngx_int_t ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc,
void *data);
static char *ngx_http_upstream_ip_hash(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static ngx_command_t ngx_http_upstream_ip_hash_commands[] = {
{ ngx_string("ip_hash"),
NGX_HTTP_UPS_CONF|NGX_CONF_NOARGS,
ngx_http_upstream_ip_hash,
0,
0,
NULL },
ngx_null_command
};
static ngx_http_module_t ngx_http_upstream_ip_hash_module_ctx = {
NULL, /* preconfiguration */
NULL, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
NULL, /* create location configuration */
NULL /* merge location configuration */
};
ngx_module_t ngx_http_upstream_ip_hash_module = {
NGX_MODULE_V1,
&ngx_http_upstream_ip_hash_module_ctx, /* module context */
ngx_http_upstream_ip_hash_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
ngx_int_t
ngx_http_upstream_init_ip_hash(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us)
{
if (ngx_http_upstream_init_round_robin(cf, us) != NGX_OK) {
return NGX_ERROR;
}
us->peer.init = ngx_http_upstream_init_ip_hash_peer;
return NGX_OK;
}
static ngx_int_t
ngx_http_upstream_init_ip_hash_peer(ngx_http_request_t *r,
ngx_http_upstream_srv_conf_t *us)
{
u_char *p;
struct sockaddr_in *sin;
ngx_http_upstream_ip_hash_peer_data_t *iphp;
iphp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_ip_hash_peer_data_t));
if (iphp == NULL) {
return NGX_ERROR;
}
r->upstream->peer.data = &iphp->rrp;
if (ngx_http_upstream_init_round_robin_peer(r, us) != NGX_OK) {
return NGX_ERROR;
}
r->upstream->peer.get = ngx_http_upstream_get_ip_hash_peer;
/* AF_INET only */
if (r->connection->sockaddr->sa_family == AF_INET) {
sin = (struct sockaddr_in *) r->connection->sockaddr;
p = (u_char *) &sin->sin_addr.s_addr;
iphp->addr[0] = p[0];
iphp->addr[1] = p[1];
iphp->addr[2] = p[2];
} else {
iphp->addr[0] = 0;
iphp->addr[1] = 0;
iphp->addr[2] = 0;
}
iphp->hash = 89;
iphp->tries = 0;
iphp->get_rr_peer = ngx_http_upstream_get_round_robin_peer;
return NGX_OK;
}
static ngx_int_t
ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data)
{
ngx_http_upstream_ip_hash_peer_data_t *iphp = data;
time_t now;
uintptr_t m;
ngx_uint_t i, n, p, hash;
ngx_http_upstream_rr_peer_t *peer;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
"get ip hash peer, try: %ui", pc->tries);
/* TODO: cached */
if (iphp->tries > 20 || iphp->rrp.peers->single) {
return iphp->get_rr_peer(pc, &iphp->rrp);
}
now = ngx_time();
pc->cached = 0;
pc->connection = NULL;
hash = iphp->hash;
for ( ;; ) {
for (i = 0; i < 3; i++) {
hash = (hash * 113 + iphp->addr[i]) % 6271;
}
p = hash % iphp->rrp.peers->number;
n = p / (8 * sizeof(uintptr_t));
m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t));
if (!(iphp->rrp.tried[n] & m)) {
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
"get ip hash peer, hash: %ui %04XA", p, m);
peer = &iphp->rrp.peers->peer[p];
/* ngx_lock_mutex(iphp->rrp.peers->mutex); */
if (!peer->down) {
if (peer->max_fails == 0 || peer->fails < peer->max_fails) {
break;
}
if (now - peer->accessed > peer->fail_timeout) {
peer->fails = 0;
break;
}
}
iphp->rrp.tried[n] |= m;
/* ngx_unlock_mutex(iphp->rrp.peers->mutex); */
pc->tries--;
}
if (++iphp->tries >= 20) {
return iphp->get_rr_peer(pc, &iphp->rrp);
}
}
iphp->rrp.current = p;
pc->sockaddr = peer->sockaddr;
pc->socklen = peer->socklen;
pc->name = &peer->name;
/* ngx_unlock_mutex(iphp->rrp.peers->mutex); */
iphp->rrp.tried[n] |= m;
iphp->hash = hash;
return NGX_OK;
}
static char *
ngx_http_upstream_ip_hash(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_upstream_srv_conf_t *uscf;
uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);
uscf->peer.init_upstream = ngx_http_upstream_init_ip_hash;
uscf->flags = NGX_HTTP_UPSTREAM_CREATE
|NGX_HTTP_UPSTREAM_MAX_FAILS
|NGX_HTTP_UPSTREAM_FAIL_TIMEOUT
|NGX_HTTP_UPSTREAM_DOWN;
return NGX_CONF_OK;
}
nginx-0.7.68/src/http/modules/ngx_http_gzip_filter_module.c 000644 001750 001750 00000073452 11331574432 023225 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#include
#include
#include
#include
typedef struct {
ngx_flag_t enable;
ngx_flag_t no_buffer;
ngx_hash_t types;
ngx_bufs_t bufs;
size_t postpone_gzipping;
ngx_int_t level;
size_t wbits;
size_t memlevel;
ssize_t min_length;
ngx_array_t *types_keys;
} ngx_http_gzip_conf_t;
typedef struct {
ngx_chain_t *in;
ngx_chain_t *free;
ngx_chain_t *busy;
ngx_chain_t *out;
ngx_chain_t **last_out;
ngx_chain_t *copied;
ngx_chain_t *copy_buf;
ngx_buf_t *in_buf;
ngx_buf_t *out_buf;
ngx_int_t bufs;
void *preallocated;
char *free_mem;
ngx_uint_t allocated;
int wbits;
int memlevel;
unsigned flush:4;
unsigned redo:1;
unsigned done:1;
unsigned nomem:1;
unsigned gzheader:1;
unsigned buffering:1;
size_t zin;
size_t zout;
uint32_t crc32;
z_stream zstream;
ngx_http_request_t *request;
} ngx_http_gzip_ctx_t;
#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)
struct gztrailer {
uint32_t crc32;
uint32_t zlen;
};
#else /* NGX_HAVE_BIG_ENDIAN || !NGX_HAVE_NONALIGNED */
struct gztrailer {
u_char crc32[4];
u_char zlen[4];
};
#endif
static void ngx_http_gzip_filter_memory(ngx_http_request_t *r,
ngx_http_gzip_ctx_t *ctx);
static ngx_int_t ngx_http_gzip_filter_buffer(ngx_http_gzip_ctx_t *ctx,
ngx_chain_t *in);
static ngx_int_t ngx_http_gzip_filter_deflate_start(ngx_http_request_t *r,
ngx_http_gzip_ctx_t *ctx);
static ngx_int_t ngx_http_gzip_filter_gzheader(ngx_http_request_t *r,
ngx_http_gzip_ctx_t *ctx);
static ngx_int_t ngx_http_gzip_filter_add_data(ngx_http_request_t *r,
ngx_http_gzip_ctx_t *ctx);
static ngx_int_t ngx_http_gzip_filter_get_buf(ngx_http_request_t *r,
ngx_http_gzip_ctx_t *ctx);
static ngx_int_t ngx_http_gzip_filter_deflate(ngx_http_request_t *r,
ngx_http_gzip_ctx_t *ctx);
static ngx_int_t ngx_http_gzip_filter_deflate_end(ngx_http_request_t *r,
ngx_http_gzip_ctx_t *ctx);
static void *ngx_http_gzip_filter_alloc(void *opaque, u_int items,
u_int size);
static void ngx_http_gzip_filter_free(void *opaque, void *address);
static void ngx_http_gzip_filter_free_copy_buf(ngx_http_request_t *r,
ngx_http_gzip_ctx_t *ctx);
static ngx_int_t ngx_http_gzip_add_variables(ngx_conf_t *cf);
static ngx_int_t ngx_http_gzip_ratio_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_gzip_filter_init(ngx_conf_t *cf);
static void *ngx_http_gzip_create_conf(ngx_conf_t *cf);
static char *ngx_http_gzip_merge_conf(ngx_conf_t *cf,
void *parent, void *child);
static char *ngx_http_gzip_window(ngx_conf_t *cf, void *post, void *data);
static char *ngx_http_gzip_hash(ngx_conf_t *cf, void *post, void *data);
static ngx_conf_num_bounds_t ngx_http_gzip_comp_level_bounds = {
ngx_conf_check_num_bounds, 1, 9
};
static ngx_conf_post_handler_pt ngx_http_gzip_window_p = ngx_http_gzip_window;
static ngx_conf_post_handler_pt ngx_http_gzip_hash_p = ngx_http_gzip_hash;
static ngx_command_t ngx_http_gzip_filter_commands[] = {
{ ngx_string("gzip"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_gzip_conf_t, enable),
NULL },
{ ngx_string("gzip_buffers"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
ngx_conf_set_bufs_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_gzip_conf_t, bufs),
NULL },
{ ngx_string("gzip_types"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
ngx_http_types_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_gzip_conf_t, types_keys),
&ngx_http_html_default_types[0] },
{ ngx_string("gzip_comp_level"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_gzip_conf_t, level),
&ngx_http_gzip_comp_level_bounds },
{ ngx_string("gzip_window"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_gzip_conf_t, wbits),
&ngx_http_gzip_window_p },
{ ngx_string("gzip_hash"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_gzip_conf_t, memlevel),
&ngx_http_gzip_hash_p },
{ ngx_string("postpone_gzipping"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_gzip_conf_t, postpone_gzipping),
NULL },
{ ngx_string("gzip_no_buffer"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_gzip_conf_t, no_buffer),
NULL },
{ ngx_string("gzip_min_length"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_gzip_conf_t, min_length),
NULL },
ngx_null_command
};
static ngx_http_module_t ngx_http_gzip_filter_module_ctx = {
ngx_http_gzip_add_variables, /* preconfiguration */
ngx_http_gzip_filter_init, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
ngx_http_gzip_create_conf, /* create location configuration */
ngx_http_gzip_merge_conf /* merge location configuration */
};
ngx_module_t ngx_http_gzip_filter_module = {
NGX_MODULE_V1,
&ngx_http_gzip_filter_module_ctx, /* module context */
ngx_http_gzip_filter_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_str_t ngx_http_gzip_ratio = ngx_string("gzip_ratio");
static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
static ngx_int_t
ngx_http_gzip_header_filter(ngx_http_request_t *r)
{
ngx_table_elt_t *h;
ngx_http_gzip_ctx_t *ctx;
ngx_http_gzip_conf_t *conf;
conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
if (!conf->enable
|| (r->headers_out.status != NGX_HTTP_OK
&& r->headers_out.status != NGX_HTTP_FORBIDDEN
&& r->headers_out.status != NGX_HTTP_NOT_FOUND)
|| (r->headers_out.content_encoding
&& r->headers_out.content_encoding->value.len)
|| (r->headers_out.content_length_n != -1
&& r->headers_out.content_length_n < conf->min_length)
|| ngx_http_test_content_type(r, &conf->types) == NULL
|| r->header_only)
{
return ngx_http_next_header_filter(r);
}
r->gzip_vary = 1;
if (!r->gzip_tested) {
if (ngx_http_gzip_ok(r) != NGX_OK) {
return ngx_http_next_header_filter(r);
}
} else if (!r->gzip_ok) {
return ngx_http_next_header_filter(r);
}
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_gzip_ctx_t));
if (ctx == NULL) {
return NGX_ERROR;
}
ngx_http_set_ctx(r, ctx, ngx_http_gzip_filter_module);
ctx->request = r;
ctx->buffering = (conf->postpone_gzipping != 0);
ngx_http_gzip_filter_memory(r, ctx);
h = ngx_list_push(&r->headers_out.headers);
if (h == NULL) {
return NGX_ERROR;
}
h->hash = 1;
h->key.len = sizeof("Content-Encoding") - 1;
h->key.data = (u_char *) "Content-Encoding";
h->value.len = sizeof("gzip") - 1;
h->value.data = (u_char *) "gzip";
r->headers_out.content_encoding = h;
r->main_filter_need_in_memory = 1;
ngx_http_clear_content_length(r);
ngx_http_clear_accept_ranges(r);
return ngx_http_next_header_filter(r);
}
static ngx_int_t
ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
int rc;
ngx_chain_t *cl;
ngx_http_gzip_ctx_t *ctx;
ctx = ngx_http_get_module_ctx(r, ngx_http_gzip_filter_module);
if (ctx == NULL || ctx->done) {
return ngx_http_next_body_filter(r, in);
}
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http gzip filter");
if (ctx->buffering) {
/*
* With default memory settings zlib starts to output gzipped data
* only after it has got about 90K, so it makes sense to allocate
* zlib memory (200-400K) only after we have enough data to compress.
* Although we copy buffers, nevertheless for not big responses
* this allows to allocate zlib memory, to compress and to output
* the response in one step using hot CPU cache.
*/
if (in) {
switch (ngx_http_gzip_filter_buffer(ctx, in)) {
case NGX_OK:
return NGX_OK;
case NGX_DONE:
in = NULL;
break;
default: /* NGX_ERROR */
goto failed;
}
} else {
ctx->buffering = 0;
}
}
if (ctx->preallocated == NULL) {
if (ngx_http_gzip_filter_deflate_start(r, ctx) != NGX_OK) {
goto failed;
}
}
if (in) {
if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) {
goto failed;
}
}
if (ctx->nomem) {
/* flush busy buffers */
if (ngx_http_next_body_filter(r, NULL) == NGX_ERROR) {
goto failed;
}
cl = NULL;
ngx_chain_update_chains(&ctx->free, &ctx->busy, &cl,
(ngx_buf_tag_t) &ngx_http_gzip_filter_module);
ctx->nomem = 0;
}
for ( ;; ) {
/* cycle while we can write to a client */
for ( ;; ) {
/* cycle while there is data to feed zlib and ... */
rc = ngx_http_gzip_filter_add_data(r, ctx);
if (rc == NGX_DECLINED) {
break;
}
if (rc == NGX_AGAIN) {
continue;
}
/* ... there are buffers to write zlib output */
rc = ngx_http_gzip_filter_get_buf(r, ctx);
if (rc == NGX_DECLINED) {
break;
}
if (rc == NGX_ERROR) {
goto failed;
}
rc = ngx_http_gzip_filter_deflate(r, ctx);
if (rc == NGX_OK) {
break;
}
if (rc == NGX_ERROR) {
goto failed;
}
/* rc == NGX_AGAIN */
}
if (ctx->out == NULL) {
ngx_http_gzip_filter_free_copy_buf(r, ctx);
return ctx->busy ? NGX_AGAIN : NGX_OK;
}
if (!ctx->gzheader) {
if (ngx_http_gzip_filter_gzheader(r, ctx) != NGX_OK) {
goto failed;
}
}
rc = ngx_http_next_body_filter(r, ctx->out);
if (rc == NGX_ERROR) {
goto failed;
}
ngx_http_gzip_filter_free_copy_buf(r, ctx);
ngx_chain_update_chains(&ctx->free, &ctx->busy, &ctx->out,
(ngx_buf_tag_t) &ngx_http_gzip_filter_module);
ctx->last_out = &ctx->out;
ctx->nomem = 0;
if (ctx->done) {
return rc;
}
}
/* unreachable */
failed:
ctx->done = 1;
if (ctx->preallocated) {
deflateEnd(&ctx->zstream);
ngx_pfree(r->pool, ctx->preallocated);
}
ngx_http_gzip_filter_free_copy_buf(r, ctx);
return NGX_ERROR;
}
static void
ngx_http_gzip_filter_memory(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
{
int wbits, memlevel;
ngx_http_gzip_conf_t *conf;
conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
wbits = conf->wbits;
memlevel = conf->memlevel;
if (r->headers_out.content_length_n > 0) {
/* the actual zlib window size is smaller by 262 bytes */
while (r->headers_out.content_length_n < ((1 << (wbits - 1)) - 262)) {
wbits--;
memlevel--;
}
}
ctx->wbits = wbits;
ctx->memlevel = memlevel;
/*
* We preallocate a memory for zlib in one buffer (200K-400K), this
* decreases a number of malloc() and free() calls and also probably
* decreases a number of syscalls (sbrk()/mmap() and so on).
* Besides we free the memory as soon as a gzipping will complete
* and do not wait while a whole response will be sent to a client.
*
* 8K is for zlib deflate_state, it takes
* *) 5816 bytes on i386 and sparc64 (32-bit mode)
* *) 5920 bytes on amd64 and sparc64
*/
ctx->allocated = 8192 + (1 << (wbits + 2)) + (1 << (memlevel + 9));
}
static ngx_int_t
ngx_http_gzip_filter_buffer(ngx_http_gzip_ctx_t *ctx, ngx_chain_t *in)
{
size_t size, buffered;
ngx_buf_t *b, *buf;
ngx_chain_t *cl, **ll;
ngx_http_request_t *r;
ngx_http_gzip_conf_t *conf;
r = ctx->request;
r->connection->buffered |= NGX_HTTP_GZIP_BUFFERED;
buffered = 0;
ll = &ctx->in;
for (cl = ctx->in; cl; cl = cl->next) {
buffered += cl->buf->last - cl->buf->pos;
ll = &cl->next;
}
conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
while (in) {
cl = ngx_alloc_chain_link(r->pool);
if (cl == NULL) {
return NGX_ERROR;
}
b = in->buf;
size = b->last - b->pos;
buffered += size;
if (b->flush || b->last_buf || buffered > conf->postpone_gzipping) {
ctx->buffering = 0;
}
if (ctx->buffering && size) {
buf = ngx_create_temp_buf(r->pool, size);
if (buf == NULL) {
return NGX_ERROR;
}
buf->last = ngx_cpymem(buf->pos, b->pos, size);
b->pos = b->last;
buf->last_buf = b->last_buf;
buf->tag = (ngx_buf_tag_t) &ngx_http_gzip_filter_module;
cl->buf = buf;
} else {
cl->buf = b;
}
*ll = cl;
ll = &cl->next;
in = in->next;
}
*ll = NULL;
return ctx->buffering ? NGX_OK : NGX_DONE;
}
static ngx_int_t
ngx_http_gzip_filter_deflate_start(ngx_http_request_t *r,
ngx_http_gzip_ctx_t *ctx)
{
int rc;
ngx_http_gzip_conf_t *conf;
conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
ctx->preallocated = ngx_palloc(r->pool, ctx->allocated);
if (ctx->preallocated == NULL) {
return NGX_ERROR;
}
ctx->free_mem = ctx->preallocated;
ctx->zstream.zalloc = ngx_http_gzip_filter_alloc;
ctx->zstream.zfree = ngx_http_gzip_filter_free;
ctx->zstream.opaque = ctx;
rc = deflateInit2(&ctx->zstream, (int) conf->level, Z_DEFLATED,
- ctx->wbits, ctx->memlevel, Z_DEFAULT_STRATEGY);
if (rc != Z_OK) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
"deflateInit2() failed: %d", rc);
return NGX_ERROR;
}
ctx->last_out = &ctx->out;
ctx->crc32 = crc32(0L, Z_NULL, 0);
ctx->flush = Z_NO_FLUSH;
return NGX_OK;
}
static ngx_int_t
ngx_http_gzip_filter_gzheader(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
{
ngx_buf_t *b;
ngx_chain_t *cl;
static u_char gzheader[10] =
{ 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 };
b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
if (b == NULL) {
return NGX_ERROR;
}
b->memory = 1;
b->pos = gzheader;
b->last = b->pos + 10;
cl = ngx_alloc_chain_link(r->pool);
if (cl == NULL) {
return NGX_ERROR;
}
cl->buf = b;
cl->next = ctx->out;
ctx->out = cl;
ctx->gzheader = 1;
return NGX_OK;
}
static ngx_int_t
ngx_http_gzip_filter_add_data(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
{
if (ctx->zstream.avail_in || ctx->flush != Z_NO_FLUSH || ctx->redo) {
return NGX_OK;
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"gzip in: %p", ctx->in);
if (ctx->in == NULL) {
return NGX_DECLINED;
}
if (ctx->copy_buf) {
/*
* to avoid CPU cache trashing we do not free() just quit buf,
* but postpone free()ing after zlib compressing and data output
*/
ctx->copy_buf->next = ctx->copied;
ctx->copied = ctx->copy_buf;
ctx->copy_buf = NULL;
}
ctx->in_buf = ctx->in->buf;
if (ctx->in_buf->tag == (ngx_buf_tag_t) &ngx_http_gzip_filter_module) {
ctx->copy_buf = ctx->in;
}
ctx->in = ctx->in->next;
ctx->zstream.next_in = ctx->in_buf->pos;
ctx->zstream.avail_in = ctx->in_buf->last - ctx->in_buf->pos;
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"gzip in_buf:%p ni:%p ai:%ud",
ctx->in_buf,
ctx->zstream.next_in, ctx->zstream.avail_in);
if (ctx->in_buf->last_buf) {
ctx->flush = Z_FINISH;
} else if (ctx->in_buf->flush) {
ctx->flush = Z_SYNC_FLUSH;
}
if (ctx->zstream.avail_in) {
ctx->crc32 = crc32(ctx->crc32, ctx->zstream.next_in,
ctx->zstream.avail_in);
} else if (ctx->flush == Z_NO_FLUSH) {
return NGX_AGAIN;
}
return NGX_OK;
}
static ngx_int_t
ngx_http_gzip_filter_get_buf(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
{
ngx_http_gzip_conf_t *conf;
if (ctx->zstream.avail_out) {
return NGX_OK;
}
conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
if (ctx->free) {
ctx->out_buf = ctx->free->buf;
ctx->free = ctx->free->next;
} else if (ctx->bufs < conf->bufs.num) {
ctx->out_buf = ngx_create_temp_buf(r->pool, conf->bufs.size);
if (ctx->out_buf == NULL) {
return NGX_ERROR;
}
ctx->out_buf->tag = (ngx_buf_tag_t) &ngx_http_gzip_filter_module;
ctx->out_buf->recycled = 1;
ctx->bufs++;
} else {
ctx->nomem = 1;
return NGX_DECLINED;
}
ctx->zstream.next_out = ctx->out_buf->pos;
ctx->zstream.avail_out = conf->bufs.size;
return NGX_OK;
}
static ngx_int_t
ngx_http_gzip_filter_deflate(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
{
int rc;
ngx_chain_t *cl;
ngx_http_gzip_conf_t *conf;
ngx_log_debug6(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"deflate in: ni:%p no:%p ai:%ud ao:%ud fl:%d redo:%d",
ctx->zstream.next_in, ctx->zstream.next_out,
ctx->zstream.avail_in, ctx->zstream.avail_out,
ctx->flush, ctx->redo);
rc = deflate(&ctx->zstream, ctx->flush);
if (rc != Z_OK && rc != Z_STREAM_END) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
"deflate() failed: %d, %d", ctx->flush, rc);
return NGX_ERROR;
}
ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"deflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d",
ctx->zstream.next_in, ctx->zstream.next_out,
ctx->zstream.avail_in, ctx->zstream.avail_out,
rc);
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"gzip in_buf:%p pos:%p",
ctx->in_buf, ctx->in_buf->pos);
if (ctx->zstream.next_in) {
ctx->in_buf->pos = ctx->zstream.next_in;
if (ctx->zstream.avail_in == 0) {
ctx->zstream.next_in = NULL;
}
}
ctx->out_buf->last = ctx->zstream.next_out;
if (ctx->zstream.avail_out == 0) {
/* zlib wants to output some more gzipped data */
cl = ngx_alloc_chain_link(r->pool);
if (cl == NULL) {
return NGX_ERROR;
}
cl->buf = ctx->out_buf;
cl->next = NULL;
*ctx->last_out = cl;
ctx->last_out = &cl->next;
ctx->redo = 1;
return NGX_AGAIN;
}
ctx->redo = 0;
if (ctx->flush == Z_SYNC_FLUSH) {
ctx->zstream.avail_out = 0;
ctx->out_buf->flush = 1;
ctx->flush = Z_NO_FLUSH;
cl = ngx_alloc_chain_link(r->pool);
if (cl == NULL) {
return NGX_ERROR;
}
cl->buf = ctx->out_buf;
cl->next = NULL;
*ctx->last_out = cl;
ctx->last_out = &cl->next;
return NGX_OK;
}
if (rc == Z_STREAM_END) {
if (ngx_http_gzip_filter_deflate_end(r, ctx) != NGX_OK) {
return NGX_ERROR;
}
return NGX_OK;
}
conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
if (conf->no_buffer && ctx->in == NULL) {
cl = ngx_alloc_chain_link(r->pool);
if (cl == NULL) {
return NGX_ERROR;
}
cl->buf = ctx->out_buf;
cl->next = NULL;
*ctx->last_out = cl;
ctx->last_out = &cl->next;
return NGX_OK;
}
return NGX_AGAIN;
}
static ngx_int_t
ngx_http_gzip_filter_deflate_end(ngx_http_request_t *r,
ngx_http_gzip_ctx_t *ctx)
{
int rc;
ngx_buf_t *b;
ngx_chain_t *cl;
struct gztrailer *trailer;
ctx->zin = ctx->zstream.total_in;
ctx->zout = 10 + ctx->zstream.total_out + 8;
rc = deflateEnd(&ctx->zstream);
if (rc != Z_OK) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
"deflateEnd() failed: %d", rc);
return NGX_ERROR;
}
ngx_pfree(r->pool, ctx->preallocated);
cl = ngx_alloc_chain_link(r->pool);
if (cl == NULL) {
return NGX_ERROR;
}
cl->buf = ctx->out_buf;
cl->next = NULL;
*ctx->last_out = cl;
ctx->last_out = &cl->next;
if (ctx->zstream.avail_out >= 8) {
trailer = (struct gztrailer *) ctx->out_buf->last;
ctx->out_buf->last += 8;
ctx->out_buf->last_buf = 1;
} else {
b = ngx_create_temp_buf(r->pool, 8);
if (b == NULL) {
return NGX_ERROR;
}
b->last_buf = 1;
cl = ngx_alloc_chain_link(r->pool);
if (cl == NULL) {
return NGX_ERROR;
}
cl->buf = b;
cl->next = NULL;
*ctx->last_out = cl;
ctx->last_out = &cl->next;
trailer = (struct gztrailer *) b->pos;
b->last += 8;
}
#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)
trailer->crc32 = ctx->crc32;
trailer->zlen = ctx->zin;
#else
trailer->crc32[0] = (u_char) (ctx->crc32 & 0xff);
trailer->crc32[1] = (u_char) ((ctx->crc32 >> 8) & 0xff);
trailer->crc32[2] = (u_char) ((ctx->crc32 >> 16) & 0xff);
trailer->crc32[3] = (u_char) ((ctx->crc32 >> 24) & 0xff);
trailer->zlen[0] = (u_char) (ctx->zin & 0xff);
trailer->zlen[1] = (u_char) ((ctx->zin >> 8) & 0xff);
trailer->zlen[2] = (u_char) ((ctx->zin >> 16) & 0xff);
trailer->zlen[3] = (u_char) ((ctx->zin >> 24) & 0xff);
#endif
ctx->zstream.avail_in = 0;
ctx->zstream.avail_out = 0;
ctx->done = 1;
r->connection->buffered &= ~NGX_HTTP_GZIP_BUFFERED;
return NGX_OK;
}
static void *
ngx_http_gzip_filter_alloc(void *opaque, u_int items, u_int size)
{
ngx_http_gzip_ctx_t *ctx = opaque;
void *p;
ngx_uint_t alloc;
alloc = items * size;
if (alloc % 512 != 0 && alloc < 8192) {
/*
* The zlib deflate_state allocation, it takes about 6K,
* we allocate 8K. Other allocations are divisible by 512.
*/
alloc = 8192;
}
if (alloc <= ctx->allocated) {
p = ctx->free_mem;
ctx->free_mem += alloc;
ctx->allocated -= alloc;
ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ctx->request->connection->log, 0,
"gzip alloc: n:%ud s:%ud a:%ud p:%p",
items, size, alloc, p);
return p;
}
ngx_log_error(NGX_LOG_ALERT, ctx->request->connection->log, 0,
"gzip filter failed to use preallocated memory: %ud of %ud",
items * size, ctx->allocated);
p = ngx_palloc(ctx->request->pool, items * size);
return p;
}
static void
ngx_http_gzip_filter_free(void *opaque, void *address)
{
#if 0
ngx_http_gzip_ctx_t *ctx = opaque;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->request->connection->log, 0,
"gzip free: %p", address);
#endif
}
static void
ngx_http_gzip_filter_free_copy_buf(ngx_http_request_t *r,
ngx_http_gzip_ctx_t *ctx)
{
ngx_chain_t *cl;
for (cl = ctx->copied; cl; cl = cl->next) {
ngx_pfree(r->pool, cl->buf->start);
}
ctx->copied = NULL;
}
static ngx_int_t
ngx_http_gzip_add_variables(ngx_conf_t *cf)
{
ngx_http_variable_t *var;
var = ngx_http_add_variable(cf, &ngx_http_gzip_ratio, NGX_HTTP_VAR_NOHASH);
if (var == NULL) {
return NGX_ERROR;
}
var->get_handler = ngx_http_gzip_ratio_variable;
return NGX_OK;
}
static ngx_int_t
ngx_http_gzip_ratio_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
ngx_uint_t zint, zfrac;
ngx_http_gzip_ctx_t *ctx;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
ctx = ngx_http_get_module_ctx(r, ngx_http_gzip_filter_module);
if (ctx == NULL || ctx->zout == 0) {
v->not_found = 1;
return NGX_OK;
}
v->data = ngx_pnalloc(r->pool, NGX_INT32_LEN + 3);
if (v->data == NULL) {
return NGX_ERROR;
}
zint = (ngx_uint_t) (ctx->zin / ctx->zout);
zfrac = (ngx_uint_t) ((ctx->zin * 100 / ctx->zout) % 100);
if ((ctx->zin * 1000 / ctx->zout) % 10 > 4) {
/* the rounding, e.g., 2.125 to 2.13 */
zfrac++;
if (zfrac > 99) {
zint++;
zfrac = 0;
}
}
v->len = ngx_sprintf(v->data, "%ui.%02ui", zint, zfrac) - v->data;
return NGX_OK;
}
static void *
ngx_http_gzip_create_conf(ngx_conf_t *cf)
{
ngx_http_gzip_conf_t *conf;
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_gzip_conf_t));
if (conf == NULL) {
return NULL;
}
/*
* set by ngx_pcalloc():
*
* conf->bufs.num = 0;
* conf->types = { NULL };
* conf->types_keys = NULL;
*/
conf->enable = NGX_CONF_UNSET;
conf->no_buffer = NGX_CONF_UNSET;
conf->postpone_gzipping = NGX_CONF_UNSET_SIZE;
conf->level = NGX_CONF_UNSET;
conf->wbits = NGX_CONF_UNSET_SIZE;
conf->memlevel = NGX_CONF_UNSET_SIZE;
conf->min_length = NGX_CONF_UNSET;
return conf;
}
static char *
ngx_http_gzip_merge_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_gzip_conf_t *prev = parent;
ngx_http_gzip_conf_t *conf = child;
ngx_conf_merge_value(conf->enable, prev->enable, 0);
ngx_conf_merge_value(conf->no_buffer, prev->no_buffer, 0);
ngx_conf_merge_bufs_value(conf->bufs, prev->bufs,
(128 * 1024) / ngx_pagesize, ngx_pagesize);
ngx_conf_merge_size_value(conf->postpone_gzipping, prev->postpone_gzipping,
0);
ngx_conf_merge_value(conf->level, prev->level, 1);
ngx_conf_merge_size_value(conf->wbits, prev->wbits, MAX_WBITS);
ngx_conf_merge_size_value(conf->memlevel, prev->memlevel,
MAX_MEM_LEVEL - 1);
ngx_conf_merge_value(conf->min_length, prev->min_length, 20);
if (ngx_http_merge_types(cf, conf->types_keys, &conf->types,
prev->types_keys, &prev->types,
ngx_http_html_default_types)
!= NGX_OK)
{
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
static ngx_int_t
ngx_http_gzip_filter_init(ngx_conf_t *cf)
{
ngx_http_next_header_filter = ngx_http_top_header_filter;
ngx_http_top_header_filter = ngx_http_gzip_header_filter;
ngx_http_next_body_filter = ngx_http_top_body_filter;
ngx_http_top_body_filter = ngx_http_gzip_body_filter;
return NGX_OK;
}
static char *
ngx_http_gzip_window(ngx_conf_t *cf, void *post, void *data)
{
size_t *np = data;
size_t wbits, wsize;
wbits = 15;
for (wsize = 32 * 1024; wsize > 256; wsize >>= 1) {
if (wsize == *np) {
*np = wbits;
return NGX_CONF_OK;
}
wbits--;
}
return "must be 512, 1k, 2k, 4k, 8k, 16k, or 32k";
}
static char *
ngx_http_gzip_hash(ngx_conf_t *cf, void *post, void *data)
{
size_t *np = data;
size_t memlevel, hsize;
memlevel = 9;
for (hsize = 128 * 1024; hsize > 256; hsize >>= 1) {
if (hsize == *np) {
*np = memlevel;
return NGX_CONF_OK;
}
memlevel--;
}
return "must be 512, 1k, 2k, 4k, 8k, 16k, 32k, 64k, or 128k";
}
nginx-0.7.68/src/http/modules/ngx_http_gzip_static_module.c 000644 001750 001750 00000016560 11403162632 023217 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#include
#include
#include
typedef struct {
ngx_flag_t enable;
} ngx_http_gzip_static_conf_t;
static ngx_int_t ngx_http_gzip_static_handler(ngx_http_request_t *r);
static void *ngx_http_gzip_static_create_conf(ngx_conf_t *cf);
static char *ngx_http_gzip_static_merge_conf(ngx_conf_t *cf, void *parent,
void *child);
static ngx_int_t ngx_http_gzip_static_init(ngx_conf_t *cf);
static ngx_command_t ngx_http_gzip_static_commands[] = {
{ ngx_string("gzip_static"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_gzip_static_conf_t, enable),
NULL },
ngx_null_command
};
ngx_http_module_t ngx_http_gzip_static_module_ctx = {
NULL, /* preconfiguration */
ngx_http_gzip_static_init, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
ngx_http_gzip_static_create_conf, /* create location configuration */
ngx_http_gzip_static_merge_conf /* merge location configuration */
};
ngx_module_t ngx_http_gzip_static_module = {
NGX_MODULE_V1,
&ngx_http_gzip_static_module_ctx, /* module context */
ngx_http_gzip_static_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_int_t
ngx_http_gzip_static_handler(ngx_http_request_t *r)
{
u_char *p;
size_t root;
ngx_str_t path;
ngx_int_t rc;
ngx_uint_t level;
ngx_log_t *log;
ngx_buf_t *b;
ngx_chain_t out;
ngx_table_elt_t *h;
ngx_open_file_info_t of;
ngx_http_core_loc_conf_t *clcf;
ngx_http_gzip_static_conf_t *gzcf;
if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
return NGX_DECLINED;
}
if (r->uri.data[r->uri.len - 1] == '/') {
return NGX_DECLINED;
}
gzcf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_static_module);
if (!gzcf->enable) {
return NGX_DECLINED;
}
rc = ngx_http_gzip_ok(r);
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (!clcf->gzip_vary && rc != NGX_OK) {
return NGX_DECLINED;
}
log = r->connection->log;
p = ngx_http_map_uri_to_path(r, &path, &root, sizeof(".gz") - 1);
if (p == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
*p++ = '.';
*p++ = 'g';
*p++ = 'z';
*p = '\0';
path.len = p - path.data;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
"http filename: \"%s\"", path.data);
ngx_memzero(&of, sizeof(ngx_open_file_info_t));
of.directio = clcf->directio;
of.valid = clcf->open_file_cache_valid;
of.min_uses = clcf->open_file_cache_min_uses;
of.errors = clcf->open_file_cache_errors;
of.events = clcf->open_file_cache_events;
if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
!= NGX_OK)
{
switch (of.err) {
case 0:
return NGX_HTTP_INTERNAL_SERVER_ERROR;
case NGX_ENOENT:
case NGX_ENOTDIR:
case NGX_ENAMETOOLONG:
return NGX_DECLINED;
case NGX_EACCES:
level = NGX_LOG_ERR;
break;
default:
level = NGX_LOG_CRIT;
break;
}
ngx_log_error(level, log, of.err,
"%s \"%s\" failed", of.failed, path.data);
return NGX_DECLINED;
}
r->gzip_vary = 1;
if (rc != NGX_OK) {
return NGX_DECLINED;
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", of.fd);
if (of.is_dir) {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir");
return NGX_DECLINED;
}
#if !(NGX_WIN32) /* the not regular files are probably Unix specific */
if (!of.is_file) {
ngx_log_error(NGX_LOG_CRIT, log, 0,
"\"%s\" is not a regular file", path.data);
return NGX_HTTP_NOT_FOUND;
}
#endif
r->root_tested = !r->error_page;
rc = ngx_http_discard_request_body(r);
if (rc != NGX_OK) {
return rc;
}
log->action = "sending response to client";
r->headers_out.status = NGX_HTTP_OK;
r->headers_out.content_length_n = of.size;
r->headers_out.last_modified_time = of.mtime;
if (ngx_http_set_content_type(r) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
h = ngx_list_push(&r->headers_out.headers);
if (h == NULL) {
return NGX_ERROR;
}
h->hash = 1;
h->key.len = sizeof("Content-Encoding") - 1;
h->key.data = (u_char *) "Content-Encoding";
h->value.len = sizeof("gzip") - 1;
h->value.data = (u_char *) "gzip";
r->headers_out.content_encoding = h;
r->ignore_content_encoding = 1;
/* we need to allocate all before the header would be sent */
b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
if (b == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
if (b->file == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
rc = ngx_http_send_header(r);
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
return rc;
}
b->file_pos = 0;
b->file_last = of.size;
b->in_file = b->file_last ? 1 : 0;
b->last_buf = 1;
b->last_in_chain = 1;
b->file->fd = of.fd;
b->file->name = path;
b->file->log = log;
b->file->directio = of.is_directio;
out.buf = b;
out.next = NULL;
return ngx_http_output_filter(r, &out);
}
static void *
ngx_http_gzip_static_create_conf(ngx_conf_t *cf)
{
ngx_http_gzip_static_conf_t *conf;
conf = ngx_palloc(cf->pool, sizeof(ngx_http_gzip_static_conf_t));
if (conf == NULL) {
return NULL;
}
conf->enable = NGX_CONF_UNSET;
return conf;
}
static char *
ngx_http_gzip_static_merge_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_gzip_static_conf_t *prev = parent;
ngx_http_gzip_static_conf_t *conf = child;
ngx_conf_merge_value(conf->enable, prev->enable, 0);
return NGX_CONF_OK;
}
static ngx_int_t
ngx_http_gzip_static_init(ngx_conf_t *cf)
{
ngx_http_handler_pt *h;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
if (h == NULL) {
return NGX_ERROR;
}
*h = ngx_http_gzip_static_handler;
return NGX_OK;
}
nginx-0.7.68/src/http/modules/ngx_http_rewrite_module.c 000644 001750 001750 00000066146 11403156511 022364 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#include
#include
#include
typedef struct {
ngx_array_t *codes; /* uintptr_t */
ngx_uint_t stack_size;
ngx_flag_t log;
ngx_flag_t uninitialized_variable_warn;
} ngx_http_rewrite_loc_conf_t;
static void *ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_rewrite_merge_loc_conf(ngx_conf_t *cf,
void *parent, void *child);
static ngx_int_t ngx_http_rewrite_init(ngx_conf_t *cf);
static char *ngx_http_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static char *ngx_http_rewrite_return(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_rewrite_break(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char * ngx_http_rewrite_if_condition(ngx_conf_t *cf,
ngx_http_rewrite_loc_conf_t *lcf);
static char *ngx_http_rewrite_variable(ngx_conf_t *cf,
ngx_http_rewrite_loc_conf_t *lcf, ngx_str_t *value);
static char *ngx_http_rewrite_set(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char * ngx_http_rewrite_value(ngx_conf_t *cf,
ngx_http_rewrite_loc_conf_t *lcf, ngx_str_t *value);
static ngx_command_t ngx_http_rewrite_commands[] = {
{ ngx_string("rewrite"),
NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|NGX_CONF_TAKE23,
ngx_http_rewrite,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("return"),
NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|NGX_CONF_TAKE1,
ngx_http_rewrite_return,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("break"),
NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|NGX_CONF_NOARGS,
ngx_http_rewrite_break,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("if"),
NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_BLOCK|NGX_CONF_1MORE,
ngx_http_rewrite_if,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("set"),
NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|NGX_CONF_TAKE2,
ngx_http_rewrite_set,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("rewrite_log"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF
|NGX_HTTP_LIF_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_rewrite_loc_conf_t, log),
NULL },
{ ngx_string("uninitialized_variable_warn"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF
|NGX_HTTP_LIF_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_rewrite_loc_conf_t, uninitialized_variable_warn),
NULL },
ngx_null_command
};
static ngx_http_module_t ngx_http_rewrite_module_ctx = {
NULL, /* preconfiguration */
ngx_http_rewrite_init, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
ngx_http_rewrite_create_loc_conf, /* create location configration */
ngx_http_rewrite_merge_loc_conf /* merge location configration */
};
ngx_module_t ngx_http_rewrite_module = {
NGX_MODULE_V1,
&ngx_http_rewrite_module_ctx, /* module context */
ngx_http_rewrite_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_int_t
ngx_http_rewrite_handler(ngx_http_request_t *r)
{
ngx_http_script_code_pt code;
ngx_http_script_engine_t *e;
ngx_http_rewrite_loc_conf_t *rlcf;
rlcf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module);
if (rlcf->codes == NULL) {
return NGX_DECLINED;
}
e = ngx_pcalloc(r->pool, sizeof(ngx_http_script_engine_t));
if (e == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
e->sp = ngx_pcalloc(r->pool,
rlcf->stack_size * sizeof(ngx_http_variable_value_t));
if (e->sp == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
e->ip = rlcf->codes->elts;
e->request = r;
e->quote = 1;
e->log = rlcf->log;
e->status = NGX_DECLINED;
while (*(uintptr_t *) e->ip) {
code = *(ngx_http_script_code_pt *) e->ip;
code(e);
}
if (e->status == NGX_DECLINED) {
return NGX_DECLINED;
}
if (r->err_status == 0) {
return e->status;
}
return r->err_status;
}
static ngx_int_t
ngx_http_rewrite_var(ngx_http_request_t *r, ngx_http_variable_value_t *v,
uintptr_t data)
{
ngx_http_variable_t *var;
ngx_http_core_main_conf_t *cmcf;
ngx_http_rewrite_loc_conf_t *rlcf;
rlcf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module);
if (rlcf->uninitialized_variable_warn == 0) {
*v = ngx_http_variable_null_value;
return NGX_OK;
}
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
var = cmcf->variables.elts;
/*
* the ngx_http_rewrite_module sets variables directly in r->variables,
* and they should be handled by ngx_http_get_indexed_variable(),
* so the handler is called only if the variable is not initialized
*/
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
"using uninitialized \"%V\" variable", &var[data].name);
*v = ngx_http_variable_null_value;
return NGX_OK;
}
static void *
ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf)
{
ngx_http_rewrite_loc_conf_t *conf;
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_rewrite_loc_conf_t));
if (conf == NULL) {
return NULL;
}
conf->stack_size = NGX_CONF_UNSET_UINT;
conf->log = NGX_CONF_UNSET;
conf->uninitialized_variable_warn = NGX_CONF_UNSET;
return conf;
}
static char *
ngx_http_rewrite_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_rewrite_loc_conf_t *prev = parent;
ngx_http_rewrite_loc_conf_t *conf = child;
uintptr_t *code;
ngx_conf_merge_value(conf->log, prev->log, 0);
ngx_conf_merge_value(conf->uninitialized_variable_warn,
prev->uninitialized_variable_warn, 1);
ngx_conf_merge_uint_value(conf->stack_size, prev->stack_size, 10);
if (conf->codes == NULL) {
return NGX_CONF_OK;
}
if (conf->codes == prev->codes) {
return NGX_CONF_OK;
}
code = ngx_array_push_n(conf->codes, sizeof(uintptr_t));
if (code == NULL) {
return NGX_CONF_ERROR;
}
*code = (uintptr_t) NULL;
return NGX_CONF_OK;
}
static ngx_int_t
ngx_http_rewrite_init(ngx_conf_t *cf)
{
ngx_http_handler_pt *h;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
h = ngx_array_push(&cmcf->phases[NGX_HTTP_SERVER_REWRITE_PHASE].handlers);
if (h == NULL) {
return NGX_ERROR;
}
*h = ngx_http_rewrite_handler;
h = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers);
if (h == NULL) {
return NGX_ERROR;
}
*h = ngx_http_rewrite_handler;
return NGX_OK;
}
static char *
ngx_http_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_rewrite_loc_conf_t *lcf = conf;
ngx_str_t *value, err;
ngx_int_t n;
ngx_uint_t last;
ngx_http_script_code_pt *code;
ngx_http_script_compile_t sc;
ngx_http_script_regex_code_t *regex;
ngx_http_script_regex_end_code_t *regex_end;
u_char errstr[NGX_MAX_CONF_ERRSTR];
regex = ngx_http_script_start_code(cf->pool, &lcf->codes,
sizeof(ngx_http_script_regex_code_t));
if (regex == NULL) {
return NGX_CONF_ERROR;
}
ngx_memzero(regex, sizeof(ngx_http_script_regex_code_t));
value = cf->args->elts;
err.len = NGX_MAX_CONF_ERRSTR;
err.data = errstr;
/* TODO: NGX_REGEX_CASELESS */
regex->regex = ngx_regex_compile(&value[1], 0, cf->pool, &err);
if (regex->regex == NULL) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data);
return NGX_CONF_ERROR;
}
regex->code = ngx_http_script_regex_start_code;
regex->uri = 1;
regex->name = value[1];
if (value[2].data[value[2].len - 1] == '?') {
/* the last "?" drops the original arguments */
value[2].len--;
} else {
regex->add_args = 1;
}
last = 0;
if (ngx_strncmp(value[2].data, "http://", sizeof("http://") - 1) == 0
|| ngx_strncmp(value[2].data, "https://", sizeof("https://") - 1) == 0
|| ngx_strncmp(value[2].data, "$scheme", sizeof("$scheme") - 1) == 0)
{
regex->status = NGX_HTTP_MOVED_TEMPORARILY;
regex->redirect = 1;
last = 1;
}
if (cf->args->nelts == 4) {
if (ngx_strcmp(value[3].data, "last") == 0) {
last = 1;
} else if (ngx_strcmp(value[3].data, "break") == 0) {
regex->break_cycle = 1;
last = 1;
} else if (ngx_strcmp(value[3].data, "redirect") == 0) {
regex->status = NGX_HTTP_MOVED_TEMPORARILY;
regex->redirect = 1;
last = 1;
} else if (ngx_strcmp(value[3].data, "permanent") == 0) {
regex->status = NGX_HTTP_MOVED_PERMANENTLY;
regex->redirect = 1;
last = 1;
} else {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid parameter \"%V\"", &value[3]);
return NGX_CONF_ERROR;
}
}
ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
sc.cf = cf;
sc.source = &value[2];
sc.lengths = ®ex->lengths;
sc.values = &lcf->codes;
sc.variables = ngx_http_script_variables_count(&value[2]);
sc.main = regex;
sc.complete_lengths = 1;
sc.compile_args = !regex->redirect;
if (ngx_http_script_compile(&sc) != NGX_OK) {
return NGX_CONF_ERROR;
}
regex = sc.main;
regex->ncaptures = sc.ncaptures;
regex->size = sc.size;
regex->args = sc.args;
if (sc.variables == 0 && !sc.dup_capture) {
regex->lengths = NULL;
}
n = ngx_regex_capture_count(regex->regex);
if (n < 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
ngx_regex_capture_count_n " failed for "
"pattern \"%V\"", &value[1]);
return NGX_CONF_ERROR;
}
if (regex->ncaptures > (ngx_uint_t) n) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"pattern \"%V\" has less captures "
"than referrenced in substitution \"%V\"",
&value[1], &value[2]);
return NGX_CONF_ERROR;
}
if (regex->ncaptures < (ngx_uint_t) n) {
regex->ncaptures = (ngx_uint_t) n;
}
if (regex->ncaptures) {
regex->ncaptures = (regex->ncaptures + 1) * 3;
}
regex_end = ngx_http_script_add_code(lcf->codes,
sizeof(ngx_http_script_regex_end_code_t),
®ex);
if (regex_end == NULL) {
return NGX_CONF_ERROR;
}
regex_end->code = ngx_http_script_regex_end_code;
regex_end->uri = regex->uri;
regex_end->args = regex->args;
regex_end->add_args = regex->add_args;
regex_end->redirect = regex->redirect;
if (last) {
code = ngx_http_script_add_code(lcf->codes, sizeof(uintptr_t), ®ex);
if (code == NULL) {
return NGX_CONF_ERROR;
}
*code = NULL;
}
regex->next = (u_char *) lcf->codes->elts + lcf->codes->nelts
- (u_char *) regex;
return NGX_CONF_OK;
}
static char *
ngx_http_rewrite_return(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_rewrite_loc_conf_t *lcf = conf;
ngx_str_t *value;
ngx_http_script_return_code_t *ret;
ret = ngx_http_script_start_code(cf->pool, &lcf->codes,
sizeof(ngx_http_script_return_code_t));
if (ret == NULL) {
return NGX_CONF_ERROR;
}
value = cf->args->elts;
ret->code = ngx_http_script_return_code;
ret->null = (uintptr_t) NULL;
ret->status = ngx_atoi(value[1].data, value[1].len);
if (ret->status == (uintptr_t) NGX_ERROR) {
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
static char *
ngx_http_rewrite_break(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_rewrite_loc_conf_t *lcf = conf;
ngx_http_script_code_pt *code;
code = ngx_http_script_start_code(cf->pool, &lcf->codes, sizeof(uintptr_t));
if (code == NULL) {
return NGX_CONF_ERROR;
}
*code = ngx_http_script_break_code;
return NGX_CONF_OK;
}
static char *
ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_rewrite_loc_conf_t *lcf = conf;
void *mconf;
char *rv;
u_char *elts;
ngx_uint_t i;
ngx_conf_t save;
ngx_http_module_t *module;
ngx_http_conf_ctx_t *ctx, *pctx;
ngx_http_core_loc_conf_t *clcf, *pclcf;
ngx_http_script_if_code_t *if_code;
ngx_http_rewrite_loc_conf_t *nlcf;
ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
if (ctx == NULL) {
return NGX_CONF_ERROR;
}
pctx = cf->ctx;
ctx->main_conf = pctx->main_conf;
ctx->srv_conf = pctx->srv_conf;
ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
if (ctx->loc_conf == NULL) {
return NGX_CONF_ERROR;
}
for (i = 0; ngx_modules[i]; i++) {
if (ngx_modules[i]->type != NGX_HTTP_MODULE) {
continue;
}
module = ngx_modules[i]->ctx;
if (module->create_loc_conf) {
mconf = module->create_loc_conf(cf);
if (mconf == NULL) {
return NGX_CONF_ERROR;
}
ctx->loc_conf[ngx_modules[i]->ctx_index] = mconf;
}
}
pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index];
clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
clcf->loc_conf = ctx->loc_conf;
clcf->name = pclcf->name;
clcf->noname = 1;
if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) {
return NGX_CONF_ERROR;
}
if (ngx_http_rewrite_if_condition(cf, lcf) != NGX_CONF_OK) {
return NGX_CONF_ERROR;
}
if_code = ngx_array_push_n(lcf->codes, sizeof(ngx_http_script_if_code_t));
if (if_code == NULL) {
return NGX_CONF_ERROR;
}
if_code->code = ngx_http_script_if_code;
elts = lcf->codes->elts;
/* the inner directives must be compiled to the same code array */
nlcf = ctx->loc_conf[ngx_http_rewrite_module.ctx_index];
nlcf->codes = lcf->codes;
save = *cf;
cf->ctx = ctx;
if (pclcf->name.len == 0) {
if_code->loc_conf = NULL;
cf->cmd_type = NGX_HTTP_SIF_CONF;
} else {
if_code->loc_conf = ctx->loc_conf;
cf->cmd_type = NGX_HTTP_LIF_CONF;
}
rv = ngx_conf_parse(cf, NULL);
*cf = save;
if (rv != NGX_CONF_OK) {
return rv;
}
if (elts != lcf->codes->elts) {
if_code = (ngx_http_script_if_code_t *)
((u_char *) if_code + ((u_char *) lcf->codes->elts - elts));
}
if_code->next = (u_char *) lcf->codes->elts + lcf->codes->nelts
- (u_char *) if_code;
/* the code array belong to parent block */
nlcf->codes = NULL;
return NGX_CONF_OK;
}
static char *
ngx_http_rewrite_if_condition(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf)
{
u_char *p;
size_t len;
ngx_str_t *value, err;
ngx_uint_t cur, last, n;
ngx_http_script_code_pt *code;
ngx_http_script_file_code_t *fop;
ngx_http_script_regex_code_t *regex;
u_char errstr[NGX_MAX_CONF_ERRSTR];
value = cf->args->elts;
last = cf->args->nelts - 1;
if (value[1].len < 1 || value[1].data[0] != '(') {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid condition \"%V\"", &value[1]);
return NGX_CONF_ERROR;
}
if (value[1].len == 1) {
cur = 2;
} else {
cur = 1;
value[1].len--;
value[1].data++;
}
if (value[last].len < 1 || value[last].data[value[last].len - 1] != ')') {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid condition \"%V\"", &value[last]);
return NGX_CONF_ERROR;
}
if (value[last].len == 1) {
last--;
} else {
value[last].len--;
value[last].data[value[last].len] = '\0';
}
len = value[cur].len;
p = value[cur].data;
if (len > 1 && p[0] == '$') {
if (cur != last && cur + 2 != last) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid condition \"%V\"", &value[cur]);
return NGX_CONF_ERROR;
}
if (ngx_http_rewrite_variable(cf, lcf, &value[cur]) != NGX_CONF_OK) {
return NGX_CONF_ERROR;
}
if (cur == last) {
return NGX_CONF_OK;
}
cur++;
len = value[cur].len;
p = value[cur].data;
if (len == 1 && p[0] == '=') {
if (ngx_http_rewrite_value(cf, lcf, &value[last]) != NGX_CONF_OK) {
return NGX_CONF_ERROR;
}
code = ngx_http_script_start_code(cf->pool, &lcf->codes,
sizeof(uintptr_t));
if (code == NULL) {
return NGX_CONF_ERROR;
}
*code = ngx_http_script_equal_code;
return NGX_CONF_OK;
}
if (len == 2 && p[0] == '!' && p[1] == '=') {
if (ngx_http_rewrite_value(cf, lcf, &value[last]) != NGX_CONF_OK) {
return NGX_CONF_ERROR;
}
code = ngx_http_script_start_code(cf->pool, &lcf->codes,
sizeof(uintptr_t));
if (code == NULL) {
return NGX_CONF_ERROR;
}
*code = ngx_http_script_not_equal_code;
return NGX_CONF_OK;
}
if ((len == 1 && p[0] == '~')
|| (len == 2 && p[0] == '~' && p[1] == '*')
|| (len == 2 && p[0] == '!' && p[1] == '~')
|| (len == 3 && p[0] == '!' && p[1] == '~' && p[2] == '*'))
{
regex = ngx_http_script_start_code(cf->pool, &lcf->codes,
sizeof(ngx_http_script_regex_code_t));
if (regex == NULL) {
return NGX_CONF_ERROR;
}
ngx_memzero(regex, sizeof(ngx_http_script_regex_code_t));
err.len = NGX_MAX_CONF_ERRSTR;
err.data = errstr;
regex->regex = ngx_regex_compile(&value[last],
(p[len - 1] == '*') ? NGX_REGEX_CASELESS : 0,
cf->pool, &err);
if (regex->regex == NULL) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data);
return NGX_CONF_ERROR;
}
regex->code = ngx_http_script_regex_start_code;
regex->next = sizeof(ngx_http_script_regex_code_t);
regex->test = 1;
if (p[0] == '!') {
regex->negative_test = 1;
}
regex->name = value[last];
n = ngx_regex_capture_count(regex->regex);
if (n) {
regex->ncaptures = (n + 1) * 3;
}
return NGX_CONF_OK;
}
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"unexpected \"%V\" in condition", &value[cur]);
return NGX_CONF_ERROR;
} else if ((len == 2 && p[0] == '-')
|| (len == 3 && p[0] == '!' && p[1] == '-'))
{
if (cur + 1 != last) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid condition \"%V\"", &value[cur]);
return NGX_CONF_ERROR;
}
value[last].data[value[last].len] = '\0';
value[last].len++;
if (ngx_http_rewrite_value(cf, lcf, &value[last]) != NGX_CONF_OK) {
return NGX_CONF_ERROR;
}
fop = ngx_http_script_start_code(cf->pool, &lcf->codes,
sizeof(ngx_http_script_file_code_t));
if (fop == NULL) {
return NGX_CONF_ERROR;
}
fop->code = ngx_http_script_file_code;
if (p[1] == 'f') {
fop->op = ngx_http_script_file_plain;
return NGX_CONF_OK;
}
if (p[1] == 'd') {
fop->op = ngx_http_script_file_dir;
return NGX_CONF_OK;
}
if (p[1] == 'e') {
fop->op = ngx_http_script_file_exists;
return NGX_CONF_OK;
}
if (p[1] == 'x') {
fop->op = ngx_http_script_file_exec;
return NGX_CONF_OK;
}
if (p[0] == '!') {
if (p[2] == 'f') {
fop->op = ngx_http_script_file_not_plain;
return NGX_CONF_OK;
}
if (p[2] == 'd') {
fop->op = ngx_http_script_file_not_dir;
return NGX_CONF_OK;
}
if (p[2] == 'e') {
fop->op = ngx_http_script_file_not_exists;
return NGX_CONF_OK;
}
if (p[2] == 'x') {
fop->op = ngx_http_script_file_not_exec;
return NGX_CONF_OK;
}
}
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid condition \"%V\"", &value[cur]);
return NGX_CONF_ERROR;
}
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid condition \"%V\"", &value[cur]);
return NGX_CONF_ERROR;
}
static char *
ngx_http_rewrite_variable(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf,
ngx_str_t *value)
{
ngx_int_t index;
ngx_http_script_var_code_t *var_code;
value->len--;
value->data++;
index = ngx_http_get_variable_index(cf, value);
if (index == NGX_ERROR) {
return NGX_CONF_ERROR;
}
var_code = ngx_http_script_start_code(cf->pool, &lcf->codes,
sizeof(ngx_http_script_var_code_t));
if (var_code == NULL) {
return NGX_CONF_ERROR;
}
var_code->code = ngx_http_script_var_code;
var_code->index = index;
return NGX_CONF_OK;
}
static char *
ngx_http_rewrite_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_rewrite_loc_conf_t *lcf = conf;
ngx_int_t index;
ngx_str_t *value;
ngx_http_variable_t *v;
ngx_http_script_var_code_t *vcode;
ngx_http_script_var_handler_code_t *vhcode;
value = cf->args->elts;
if (value[1].data[0] != '$') {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid variable name \"%V\"", &value[1]);
return NGX_CONF_ERROR;
}
value[1].len--;
value[1].data++;
v = ngx_http_add_variable(cf, &value[1], NGX_HTTP_VAR_CHANGEABLE);
if (v == NULL) {
return NGX_CONF_ERROR;
}
index = ngx_http_get_variable_index(cf, &value[1]);
if (index == NGX_ERROR) {
return NGX_CONF_ERROR;
}
if (v->get_handler == NULL
&& ngx_strncasecmp(value[1].data, (u_char *) "http_", 5) != 0
&& ngx_strncasecmp(value[1].data, (u_char *) "sent_http_", 10) != 0
&& ngx_strncasecmp(value[1].data, (u_char *) "upstream_http_", 14) != 0)
{
v->get_handler = ngx_http_rewrite_var;
v->data = index;
}
if (ngx_http_rewrite_value(cf, lcf, &value[2]) != NGX_CONF_OK) {
return NGX_CONF_ERROR;
}
if (v->set_handler) {
vhcode = ngx_http_script_start_code(cf->pool, &lcf->codes,
sizeof(ngx_http_script_var_handler_code_t));
if (vhcode == NULL) {
return NGX_CONF_ERROR;
}
vhcode->code = ngx_http_script_var_set_handler_code;
vhcode->handler = v->set_handler;
vhcode->data = v->data;
return NGX_CONF_OK;
}
vcode = ngx_http_script_start_code(cf->pool, &lcf->codes,
sizeof(ngx_http_script_var_code_t));
if (vcode == NULL) {
return NGX_CONF_ERROR;
}
vcode->code = ngx_http_script_set_var_code;
vcode->index = (uintptr_t) index;
return NGX_CONF_OK;
}
static char *
ngx_http_rewrite_value(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf,
ngx_str_t *value)
{
ngx_int_t n;
ngx_http_script_compile_t sc;
ngx_http_script_value_code_t *val;
ngx_http_script_complex_value_code_t *complex;
n = ngx_http_script_variables_count(value);
if (n == 0) {
val = ngx_http_script_start_code(cf->pool, &lcf->codes,
sizeof(ngx_http_script_value_code_t));
if (val == NULL) {
return NGX_CONF_ERROR;
}
n = ngx_atoi(value->data, value->len);
if (n == NGX_ERROR) {
n = 0;
}
val->code = ngx_http_script_value_code;
val->value = (uintptr_t) n;
val->text_len = (uintptr_t) value->len;
val->text_data = (uintptr_t) value->data;
return NGX_CONF_OK;
}
complex = ngx_http_script_start_code(cf->pool, &lcf->codes,
sizeof(ngx_http_script_complex_value_code_t));
if (complex == NULL) {
return NGX_CONF_ERROR;
}
complex->code = ngx_http_script_complex_value_code;
complex->lengths = NULL;
ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
sc.cf = cf;
sc.source = value;
sc.lengths = &complex->lengths;
sc.values = &lcf->codes;
sc.variables = n;
sc.complete_lengths = 1;
if (ngx_http_script_compile(&sc) != NGX_OK) {
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
nginx-0.7.68/src/http/modules/ngx_http_log_module.c 000644 001750 001750 00000105756 11331573506 021474 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#include
#include
#include
typedef struct ngx_http_log_op_s ngx_http_log_op_t;
typedef u_char *(*ngx_http_log_op_run_pt) (ngx_http_request_t *r, u_char *buf,
ngx_http_log_op_t *op);
typedef size_t (*ngx_http_log_op_getlen_pt) (ngx_http_request_t *r,
uintptr_t data);
struct ngx_http_log_op_s {
size_t len;
ngx_http_log_op_getlen_pt getlen;
ngx_http_log_op_run_pt run;
uintptr_t data;
};
typedef struct {
ngx_str_t name;
ngx_array_t *flushes;
ngx_array_t *ops; /* array of ngx_http_log_op_t */
} ngx_http_log_fmt_t;
typedef struct {
ngx_array_t formats; /* array of ngx_http_log_fmt_t */
ngx_uint_t combined_used; /* unsigned combined_used:1 */
} ngx_http_log_main_conf_t;
typedef struct {
ngx_array_t *lengths;
ngx_array_t *values;
} ngx_http_log_script_t;
typedef struct {
ngx_open_file_t *file;
ngx_http_log_script_t *script;
time_t disk_full_time;
time_t error_log_time;
ngx_http_log_fmt_t *format;
} ngx_http_log_t;
typedef struct {
ngx_array_t *logs; /* array of ngx_http_log_t */
ngx_open_file_cache_t *open_file_cache;
time_t open_file_cache_valid;
ngx_uint_t open_file_cache_min_uses;
ngx_uint_t off; /* unsigned off:1 */
} ngx_http_log_loc_conf_t;
typedef struct {
ngx_str_t name;
size_t len;
ngx_http_log_op_run_pt run;
} ngx_http_log_var_t;
static void ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log,
u_char *buf, size_t len);
static ssize_t ngx_http_log_script_write(ngx_http_request_t *r,
ngx_http_log_script_t *script, u_char **name, u_char *buf, size_t len);
static u_char *ngx_http_log_connection(ngx_http_request_t *r, u_char *buf,
ngx_http_log_op_t *op);
static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf,
ngx_http_log_op_t *op);
static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf,
ngx_http_log_op_t *op);
static u_char *ngx_http_log_msec(ngx_http_request_t *r, u_char *buf,
ngx_http_log_op_t *op);
static u_char *ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf,
ngx_http_log_op_t *op);
static u_char *ngx_http_log_status(ngx_http_request_t *r, u_char *buf,
ngx_http_log_op_t *op);
static u_char *ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf,
ngx_http_log_op_t *op);
static u_char *ngx_http_log_body_bytes_sent(ngx_http_request_t *r,
u_char *buf, ngx_http_log_op_t *op);
static u_char *ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
ngx_http_log_op_t *op);
static ngx_int_t ngx_http_log_variable_compile(ngx_conf_t *cf,
ngx_http_log_op_t *op, ngx_str_t *value);
static size_t ngx_http_log_variable_getlen(ngx_http_request_t *r,
uintptr_t data);
static u_char *ngx_http_log_variable(ngx_http_request_t *r, u_char *buf,
ngx_http_log_op_t *op);
static uintptr_t ngx_http_log_escape(u_char *dst, u_char *src, size_t size);
static void *ngx_http_log_create_main_conf(ngx_conf_t *cf);
static void *ngx_http_log_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent,
void *child);
static char *ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_log_compile_format(ngx_conf_t *cf,
ngx_array_t *flushes, ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s);
static char *ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static ngx_int_t ngx_http_log_init(ngx_conf_t *cf);
static ngx_command_t ngx_http_log_commands[] = {
{ ngx_string("log_format"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE,
ngx_http_log_set_format,
NGX_HTTP_MAIN_CONF_OFFSET,
0,
NULL },
{ ngx_string("access_log"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE123,
ngx_http_log_set_log,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("open_log_file_cache"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
ngx_http_log_open_file_cache,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
ngx_null_command
};
static ngx_http_module_t ngx_http_log_module_ctx = {
NULL, /* preconfiguration */
ngx_http_log_init, /* postconfiguration */
ngx_http_log_create_main_conf, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
ngx_http_log_create_loc_conf, /* create location configration */
ngx_http_log_merge_loc_conf /* merge location configration */
};
ngx_module_t ngx_http_log_module = {
NGX_MODULE_V1,
&ngx_http_log_module_ctx, /* module context */
ngx_http_log_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_str_t ngx_http_access_log = ngx_string(NGX_HTTP_LOG_PATH);
static ngx_str_t ngx_http_combined_fmt =
ngx_string("$remote_addr - $remote_user [$time_local] "
"\"$request\" $status $body_bytes_sent "
"\"$http_referer\" \"$http_user_agent\"");
static ngx_http_log_var_t ngx_http_log_vars[] = {
{ ngx_string("connection"), NGX_ATOMIC_T_LEN, ngx_http_log_connection },
{ ngx_string("pipe"), 1, ngx_http_log_pipe },
{ ngx_string("time_local"), sizeof("28/Sep/1970:12:00:00 +0600") - 1,
ngx_http_log_time },
{ ngx_string("msec"), NGX_TIME_T_LEN + 4, ngx_http_log_msec },
{ ngx_string("request_time"), NGX_TIME_T_LEN + 4,
ngx_http_log_request_time },
{ ngx_string("status"), 3, ngx_http_log_status },
{ ngx_string("bytes_sent"), NGX_OFF_T_LEN, ngx_http_log_bytes_sent },
{ ngx_string("body_bytes_sent"), NGX_OFF_T_LEN,
ngx_http_log_body_bytes_sent },
{ ngx_string("apache_bytes_sent"), NGX_OFF_T_LEN,
ngx_http_log_body_bytes_sent },
{ ngx_string("request_length"), NGX_SIZE_T_LEN,
ngx_http_log_request_length },
{ ngx_null_string, 0, NULL }
};
ngx_int_t
ngx_http_log_handler(ngx_http_request_t *r)
{
u_char *line, *p;
size_t len;
ngx_uint_t i, l;
ngx_http_log_t *log;
ngx_open_file_t *file;
ngx_http_log_op_t *op;
ngx_http_log_loc_conf_t *lcf;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http log handler");
lcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module);
if (lcf->off) {
return NGX_OK;
}
log = lcf->logs->elts;
for (l = 0; l < lcf->logs->nelts; l++) {
if (ngx_time() == log[l].disk_full_time) {
/*
* on FreeBSD writing to a full filesystem with enabled softupdates
* may block process for much longer time than writing to non-full
* filesystem, so we skip writing to a log for one second
*/
continue;
}
ngx_http_script_flush_no_cacheable_variables(r, log[l].format->flushes);
len = 0;
op = log[l].format->ops->elts;
for (i = 0; i < log[l].format->ops->nelts; i++) {
if (op[i].len == 0) {
len += op[i].getlen(r, op[i].data);
} else {
len += op[i].len;
}
}
len += NGX_LINEFEED_SIZE;
file = log[l].file;
if (file && file->buffer) {
if (len > (size_t) (file->last - file->pos)) {
ngx_http_log_write(r, &log[l], file->buffer,
file->pos - file->buffer);
file->pos = file->buffer;
}
if (len <= (size_t) (file->last - file->pos)) {
p = file->pos;
for (i = 0; i < log[l].format->ops->nelts; i++) {
p = op[i].run(r, p, &op[i]);
}
ngx_linefeed(p);
file->pos = p;
continue;
}
}
line = ngx_pnalloc(r->pool, len);
if (line == NULL) {
return NGX_ERROR;
}
p = line;
for (i = 0; i < log[l].format->ops->nelts; i++) {
p = op[i].run(r, p, &op[i]);
}
ngx_linefeed(p);
ngx_http_log_write(r, &log[l], line, p - line);
}
return NGX_OK;
}
static void
ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, u_char *buf,
size_t len)
{
u_char *name;
time_t now;
ssize_t n;
ngx_err_t err;
if (log->script == NULL) {
name = log->file->name.data;
n = ngx_write_fd(log->file->fd, buf, len);
} else {
name = NULL;
n = ngx_http_log_script_write(r, log->script, &name, buf, len);
}
if (n == (ssize_t) len) {
return;
}
now = ngx_time();
if (n == -1) {
err = ngx_errno;
if (err == NGX_ENOSPC) {
log->disk_full_time = now;
}
if (now - log->error_log_time > 59) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, err,
ngx_write_fd_n " to \"%s\" failed", name);
log->error_log_time = now;
}
return;
}
if (now - log->error_log_time > 59) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
name, n, len);
log->error_log_time = now;
}
}
static ssize_t
ngx_http_log_script_write(ngx_http_request_t *r, ngx_http_log_script_t *script,
u_char **name, u_char *buf, size_t len)
{
size_t root;
ssize_t n;
ngx_str_t log, path;
ngx_open_file_info_t of;
ngx_http_log_loc_conf_t *llcf;
ngx_http_core_loc_conf_t *clcf;
if (!r->root_tested) {
/* test root directory existance */
if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) {
/* simulate successfull logging */
return len;
}
path.data[root] = '\0';
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
ngx_memzero(&of, sizeof(ngx_open_file_info_t));
of.valid = clcf->open_file_cache_valid;
of.min_uses = clcf->open_file_cache_min_uses;
of.test_dir = 1;
of.test_only = 1;
of.errors = clcf->open_file_cache_errors;
of.events = clcf->open_file_cache_events;
if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
!= NGX_OK)
{
if (of.err == 0) {
/* simulate successfull logging */
return len;
}
ngx_log_error(NGX_LOG_ERR, r->connection->log, of.err,
"testing \"%s\" existence failed", path.data);
/* simulate successfull logging */
return len;
}
if (!of.is_dir) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ENOTDIR,
"testing \"%s\" existence failed", path.data);
/* simulate successfull logging */
return len;
}
}
if (ngx_http_script_run(r, &log, script->lengths->elts, 1,
script->values->elts)
== NULL)
{
/* simulate successfull logging */
return len;
}
log.data[log.len - 1] = '\0';
*name = log.data;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http log \"%s\"", log.data);
llcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module);
ngx_memzero(&of, sizeof(ngx_open_file_info_t));
of.log = 1;
of.valid = llcf->open_file_cache_valid;
of.min_uses = llcf->open_file_cache_min_uses;
of.directio = NGX_OPEN_FILE_DIRECTIO_OFF;
if (ngx_open_cached_file(llcf->open_file_cache, &log, &of, r->pool)
!= NGX_OK)
{
ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
"%s \"%s\" failed", of.failed, log.data);
/* simulate successfull logging */
return len;
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http log #%d", of.fd);
n = ngx_write_fd(of.fd, buf, len);
return n;
}
static u_char *
ngx_http_log_copy_short(ngx_http_request_t *r, u_char *buf,
ngx_http_log_op_t *op)
{
size_t len;
uintptr_t data;
len = op->len;
data = op->data;
while (len--) {
*buf++ = (u_char) (data & 0xff);
data >>= 8;
}
return buf;
}
static u_char *
ngx_http_log_copy_long(ngx_http_request_t *r, u_char *buf,
ngx_http_log_op_t *op)
{
return ngx_cpymem(buf, (u_char *) op->data, op->len);
}
static u_char *
ngx_http_log_connection(ngx_http_request_t *r, u_char *buf,
ngx_http_log_op_t *op)
{
return ngx_sprintf(buf, "%ui", r->connection->number);
}
static u_char *
ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
{
if (r->pipeline) {
*buf = 'p';
} else {
*buf = '.';
}
return buf + 1;
}
static u_char *
ngx_http_log_time(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
{
return ngx_cpymem(buf, ngx_cached_http_log_time.data,
ngx_cached_http_log_time.len);
}
static u_char *
ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
{
ngx_time_t *tp;
tp = ngx_timeofday();
return ngx_sprintf(buf, "%T.%03M", tp->sec, tp->msec);
}
static u_char *
ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf,
ngx_http_log_op_t *op)
{
ngx_time_t *tp;
ngx_msec_int_t ms;
tp = ngx_timeofday();
ms = (ngx_msec_int_t)
((tp->sec - r->start_sec) * 1000 + (tp->msec - r->start_msec));
ms = (ms >= 0) ? ms : 0;
return ngx_sprintf(buf, "%T.%03M", ms / 1000, ms % 1000);
}
static u_char *
ngx_http_log_status(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
{
ngx_uint_t status;
if (r->err_status) {
status = r->err_status;
} else if (r->headers_out.status) {
status = r->headers_out.status;
} else if (r->http_version == NGX_HTTP_VERSION_9) {
*buf++ = '0';
*buf++ = '0';
*buf++ = '9';
return buf;
} else {
status = 0;
}
return ngx_sprintf(buf, "%ui", status);
}
static u_char *
ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf,
ngx_http_log_op_t *op)
{
return ngx_sprintf(buf, "%O", r->connection->sent);
}
/*
* although there is a real $body_bytes_sent variable,
* this log operation code function is more optimized for logging
*/
static u_char *
ngx_http_log_body_bytes_sent(ngx_http_request_t *r, u_char *buf,
ngx_http_log_op_t *op)
{
off_t length;
length = r->connection->sent - r->header_size;
if (length > 0) {
return ngx_sprintf(buf, "%O", length);
}
*buf = '0';
return buf + 1;
}
static u_char *
ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
ngx_http_log_op_t *op)
{
return ngx_sprintf(buf, "%O", r->request_length);
}
static ngx_int_t
ngx_http_log_variable_compile(ngx_conf_t *cf, ngx_http_log_op_t *op,
ngx_str_t *value)
{
ngx_int_t index;
index = ngx_http_get_variable_index(cf, value);
if (index == NGX_ERROR) {
return NGX_ERROR;
}
op->len = 0;
op->getlen = ngx_http_log_variable_getlen;
op->run = ngx_http_log_variable;
op->data = index;
return NGX_OK;
}
static size_t
ngx_http_log_variable_getlen(ngx_http_request_t *r, uintptr_t data)
{
uintptr_t len;
ngx_http_variable_value_t *value;
value = ngx_http_get_indexed_variable(r, data);
if (value == NULL || value->not_found) {
return 1;
}
len = ngx_http_log_escape(NULL, value->data, value->len);
value->escape = len ? 1 : 0;
return value->len + len * 3;
}
static u_char *
ngx_http_log_variable(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
{
ngx_http_variable_value_t *value;
value = ngx_http_get_indexed_variable(r, op->data);
if (value == NULL || value->not_found) {
*buf = '-';
return buf + 1;
}
if (value->escape == 0) {
return ngx_cpymem(buf, value->data, value->len);
} else {
return (u_char *) ngx_http_log_escape(buf, value->data, value->len);
}
}
static uintptr_t
ngx_http_log_escape(u_char *dst, u_char *src, size_t size)
{
ngx_uint_t i, n;
static u_char hex[] = "0123456789ABCDEF";
static uint32_t escape[] = {
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
/* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
0x00000004, /* 0000 0000 0000 0000 0000 0000 0000 0100 */
/* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
0x10000000, /* 0001 0000 0000 0000 0000 0000 0000 0000 */
/* ~}| {zyx wvut srqp onml kjih gfed cba` */
0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
};
if (dst == NULL) {
/* find the number of the characters to be escaped */
n = 0;
for (i = 0; i < size; i++) {
if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
n++;
}
src++;
}
return (uintptr_t) n;
}
for (i = 0; i < size; i++) {
if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
*dst++ = '\\';
*dst++ = 'x';
*dst++ = hex[*src >> 4];
*dst++ = hex[*src & 0xf];
src++;
} else {
*dst++ = *src++;
}
}
return (uintptr_t) dst;
}
static void *
ngx_http_log_create_main_conf(ngx_conf_t *cf)
{
ngx_http_log_main_conf_t *conf;
ngx_http_log_fmt_t *fmt;
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_main_conf_t));
if (conf == NULL) {
return NULL;
}
if (ngx_array_init(&conf->formats, cf->pool, 4, sizeof(ngx_http_log_fmt_t))
!= NGX_OK)
{
return NULL;
}
fmt = ngx_array_push(&conf->formats);
if (fmt == NULL) {
return NULL;
}
fmt->name.len = sizeof("combined") - 1;
fmt->name.data = (u_char *) "combined";
fmt->flushes = NULL;
fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
if (fmt->ops == NULL) {
return NULL;
}
return conf;
}
static void *
ngx_http_log_create_loc_conf(ngx_conf_t *cf)
{
ngx_http_log_loc_conf_t *conf;
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_loc_conf_t));
if (conf == NULL) {
return NULL;
}
conf->open_file_cache = NGX_CONF_UNSET_PTR;
return conf;
}
static char *
ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_log_loc_conf_t *prev = parent;
ngx_http_log_loc_conf_t *conf = child;
ngx_http_log_t *log;
ngx_http_log_fmt_t *fmt;
ngx_http_log_main_conf_t *lmcf;
if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {
conf->open_file_cache = prev->open_file_cache;
conf->open_file_cache_valid = prev->open_file_cache_valid;
conf->open_file_cache_min_uses = prev->open_file_cache_min_uses;
if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {
conf->open_file_cache = NULL;
}
}
if (conf->logs || conf->off) {
return NGX_CONF_OK;
}
conf->logs = prev->logs;
conf->off = prev->off;
if (conf->logs || conf->off) {
return NGX_CONF_OK;
}
conf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t));
if (conf->logs == NULL) {
return NGX_CONF_ERROR;
}
log = ngx_array_push(conf->logs);
if (log == NULL) {
return NGX_CONF_ERROR;
}
log->file = ngx_conf_open_file(cf->cycle, &ngx_http_access_log);
if (log->file == NULL) {
return NGX_CONF_ERROR;
}
log->script = NULL;
log->disk_full_time = 0;
log->error_log_time = 0;
lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
fmt = lmcf->formats.elts;
/* the default "combined" format */
log->format = &fmt[0];
lmcf->combined_used = 1;
return NGX_CONF_OK;
}
static char *
ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_log_loc_conf_t *llcf = conf;
ssize_t buf;
ngx_uint_t i, n;
ngx_str_t *value, name;
ngx_http_log_t *log;
ngx_http_log_fmt_t *fmt;
ngx_http_log_main_conf_t *lmcf;
ngx_http_script_compile_t sc;
value = cf->args->elts;
if (ngx_strcmp(value[1].data, "off") == 0) {
llcf->off = 1;
if (cf->args->nelts == 2) {
return NGX_CONF_OK;
}
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid parameter \"%V\"", &value[2]);
return NGX_CONF_ERROR;
}
if (llcf->logs == NULL) {
llcf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t));
if (llcf->logs == NULL) {
return NGX_CONF_ERROR;
}
}
lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
log = ngx_array_push(llcf->logs);
if (log == NULL) {
return NGX_CONF_ERROR;
}
ngx_memzero(log, sizeof(ngx_http_log_t));
n = ngx_http_script_variables_count(&value[1]);
if (n == 0) {
log->file = ngx_conf_open_file(cf->cycle, &value[1]);
if (log->file == NULL) {
return NGX_CONF_ERROR;
}
} else {
if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) {
return NGX_CONF_ERROR;
}
log->script = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_script_t));
if (log->script == NULL) {
return NGX_CONF_ERROR;
}
ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
sc.cf = cf;
sc.source = &value[1];
sc.lengths = &log->script->lengths;
sc.values = &log->script->values;
sc.variables = n;
sc.complete_lengths = 1;
sc.complete_values = 1;
if (ngx_http_script_compile(&sc) != NGX_OK) {
return NGX_CONF_ERROR;
}
}
if (cf->args->nelts >= 3) {
name = value[2];
if (ngx_strcmp(name.data, "combined") == 0) {
lmcf->combined_used = 1;
}
} else {
name.len = sizeof("combined") - 1;
name.data = (u_char *) "combined";
lmcf->combined_used = 1;
}
fmt = lmcf->formats.elts;
for (i = 0; i < lmcf->formats.nelts; i++) {
if (fmt[i].name.len == name.len
&& ngx_strcasecmp(fmt[i].name.data, name.data) == 0)
{
log->format = &fmt[i];
goto buffer;
}
}
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"unknown log format \"%V\"", &name);
return NGX_CONF_ERROR;
buffer:
if (cf->args->nelts == 4) {
if (ngx_strncmp(value[3].data, "buffer=", 7) != 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid parameter \"%V\"", &value[3]);
return NGX_CONF_ERROR;
}
if (log->script) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"buffered logs can not have variables in name");
return NGX_CONF_ERROR;
}
name.len = value[3].len - 7;
name.data = value[3].data + 7;
buf = ngx_parse_size(&name);
if (buf == NGX_ERROR) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid parameter \"%V\"", &value[3]);
return NGX_CONF_ERROR;
}
if (log->file->buffer && log->file->last - log->file->pos != buf) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"access_log \"%V\" already defined "
"with different buffer size", &value[1]);
return NGX_CONF_ERROR;
}
log->file->buffer = ngx_palloc(cf->pool, buf);
if (log->file->buffer == NULL) {
return NGX_CONF_ERROR;
}
log->file->pos = log->file->buffer;
log->file->last = log->file->buffer + buf;
}
return NGX_CONF_OK;
}
static char *
ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_log_main_conf_t *lmcf = conf;
ngx_str_t *value;
ngx_uint_t i;
ngx_http_log_fmt_t *fmt;
value = cf->args->elts;
fmt = lmcf->formats.elts;
for (i = 0; i < lmcf->formats.nelts; i++) {
if (fmt[i].name.len == value[1].len
&& ngx_strcmp(fmt[i].name.data, value[1].data) == 0)
{
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"duplicate \"log_format\" name \"%V\"",
&value[1]);
return NGX_CONF_ERROR;
}
}
fmt = ngx_array_push(&lmcf->formats);
if (fmt == NULL) {
return NGX_CONF_ERROR;
}
fmt->name = value[1];
fmt->flushes = ngx_array_create(cf->pool, 4, sizeof(ngx_int_t));
if (fmt->flushes == NULL) {
return NGX_CONF_ERROR;
}
fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
if (fmt->ops == NULL) {
return NGX_CONF_ERROR;
}
return ngx_http_log_compile_format(cf, fmt->flushes, fmt->ops, cf->args, 2);
}
static char *
ngx_http_log_compile_format(ngx_conf_t *cf, ngx_array_t *flushes,
ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s)
{
u_char *data, *p, ch;
size_t i, len;
ngx_str_t *value, var;
ngx_int_t *flush;
ngx_uint_t bracket;
ngx_http_log_op_t *op;
ngx_http_log_var_t *v;
value = args->elts;
for ( /* void */ ; s < args->nelts; s++) {
for (i = 0; i < value[s].len; i++) {
if (value[s].data[i] != '%') {
continue;
}
ch = value[s].data[i + 1];
if ((ch >= 'A' && ch <= 'Z')
|| (ch >= 'a' && ch <= 'z')
|| ch == '{')
{
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the parameters in the \"%%name\" form are not supported, "
"use the \"$variable\" instead");
return NGX_CONF_ERROR;
}
}
i = 0;
while (i < value[s].len) {
op = ngx_array_push(ops);
if (op == NULL) {
return NGX_CONF_ERROR;
}
data = &value[s].data[i];
if (value[s].data[i] == '$') {
if (++i == value[s].len) {
goto invalid;
}
if (value[s].data[i] == '{') {
bracket = 1;
if (++i == value[s].len) {
goto invalid;
}
var.data = &value[s].data[i];
} else {
bracket = 0;
var.data = &value[s].data[i];
}
for (var.len = 0; i < value[s].len; i++, var.len++) {
ch = value[s].data[i];
if (ch == '}' && bracket) {
i++;
bracket = 0;
break;
}
if ((ch >= 'A' && ch <= 'Z')
|| (ch >= 'a' && ch <= 'z')
|| (ch >= '0' && ch <= '9')
|| ch == '_')
{
continue;
}
break;
}
if (bracket) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the closing bracket in \"%V\" "
"variable is missing", &var);
return NGX_CONF_ERROR;
}
if (var.len == 0) {
goto invalid;
}
if (ngx_strncmp(var.data, "apache_bytes_sent", 17) == 0) {
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
"use \"$body_bytes_sent\" instead of "
"\"$apache_bytes_sent\"");
}
for (v = ngx_http_log_vars; v->name.len; v++) {
if (v->name.len == var.len
&& ngx_strncmp(v->name.data, var.data, var.len) == 0)
{
op->len = v->len;
op->getlen = NULL;
op->run = v->run;
op->data = 0;
goto found;
}
}
if (ngx_http_log_variable_compile(cf, op, &var) != NGX_OK) {
return NGX_CONF_ERROR;
}
if (flushes) {
flush = ngx_array_push(flushes);
if (flush == NULL) {
return NGX_CONF_ERROR;
}
*flush = op->data; /* variable index */
}
found:
continue;
}
i++;
while (i < value[s].len && value[s].data[i] != '$') {
i++;
}
len = &value[s].data[i] - data;
if (len) {
op->len = len;
op->getlen = NULL;
if (len <= sizeof(uintptr_t)) {
op->run = ngx_http_log_copy_short;
op->data = 0;
while (len--) {
op->data <<= 8;
op->data |= data[len];
}
} else {
op->run = ngx_http_log_copy_long;
p = ngx_pnalloc(cf->pool, len);
if (p == NULL) {
return NGX_CONF_ERROR;
}
ngx_memcpy(p, data, len);
op->data = (uintptr_t) p;
}
}
}
}
return NGX_CONF_OK;
invalid:
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%s\"", data);
return NGX_CONF_ERROR;
}
static char *
ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_log_loc_conf_t *llcf = conf;
time_t inactive, valid;
ngx_str_t *value, s;
ngx_int_t max, min_uses;
ngx_uint_t i;
if (llcf->open_file_cache != NGX_CONF_UNSET_PTR) {
return "is duplicate";
}
value = cf->args->elts;
max = 0;
inactive = 10;
valid = 60;
min_uses = 1;
for (i = 1; i < cf->args->nelts; i++) {
if (ngx_strncmp(value[i].data, "max=", 4) == 0) {
max = ngx_atoi(value[i].data + 4, value[i].len - 4);
if (max == NGX_ERROR) {
goto failed;
}
continue;
}
if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {
s.len = value[i].len - 9;
s.data = value[i].data + 9;
inactive = ngx_parse_time(&s, 1);
if (inactive < 0) {
goto failed;
}
continue;
}
if (ngx_strncmp(value[i].data, "min_uses=", 9) == 0) {
min_uses = ngx_atoi(value[i].data + 9, value[i].len - 9);
if (min_uses == NGX_ERROR) {
goto failed;
}
continue;
}
if (ngx_strncmp(value[i].data, "valid=", 6) == 0) {
s.len = value[i].len - 6;
s.data = value[i].data + 6;
valid = ngx_parse_time(&s, 1);
if (valid < 0) {
goto failed;
}
continue;
}
if (ngx_strcmp(value[i].data, "off") == 0) {
llcf->open_file_cache = NULL;
continue;
}
failed:
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid \"open_log_file_cache\" parameter \"%V\"",
&value[i]);
return NGX_CONF_ERROR;
}
if (llcf->open_file_cache == NULL) {
return NGX_CONF_OK;
}
if (max == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"open_log_file_cache\" must have \"max\" parameter");
return NGX_CONF_ERROR;
}
llcf->open_file_cache = ngx_open_file_cache_init(cf->pool, max, inactive);
if (llcf->open_file_cache) {
llcf->open_file_cache_valid = valid;
llcf->open_file_cache_min_uses = min_uses;
return NGX_CONF_OK;
}
return NGX_CONF_ERROR;
}
static ngx_int_t
ngx_http_log_init(ngx_conf_t *cf)
{
ngx_str_t *value;
ngx_array_t a;
ngx_http_handler_pt *h;
ngx_http_log_fmt_t *fmt;
ngx_http_log_main_conf_t *lmcf;
ngx_http_core_main_conf_t *cmcf;
lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
if (lmcf->combined_used) {
if (ngx_array_init(&a, cf->pool, 1, sizeof(ngx_str_t)) != NGX_OK) {
return NGX_ERROR;
}
value = ngx_array_push(&a);
if (value == NULL) {
return NGX_ERROR;
}
*value = ngx_http_combined_fmt;
fmt = lmcf->formats.elts;
if (ngx_http_log_compile_format(cf, NULL, fmt->ops, &a, 0)
!= NGX_CONF_OK)
{
return NGX_ERROR;
}
}
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
h = ngx_array_push(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers);
if (h == NULL) {
return NGX_ERROR;
}
*h = ngx_http_log_handler;
return NGX_OK;
}
nginx-0.7.68/src/http/modules/ngx_http_empty_gif_module.c 000644 001750 001750 00000014316 11146473520 022664 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#include
#include
#include
static char *ngx_http_empty_gif(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static ngx_command_t ngx_http_empty_gif_commands[] = {
{ ngx_string("empty_gif"),
NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
ngx_http_empty_gif,
0,
0,
NULL },
ngx_null_command
};
/* the minimal single pixel transparent GIF, 43 bytes */
static u_char ngx_empty_gif[] = {
'G', 'I', 'F', '8', '9', 'a', /* header */
/* logical screen descriptor */
0x01, 0x00, /* logical screen width */
0x01, 0x00, /* logical screen height */
0x80, /* global 1-bit color table */
0x01, /* background color #1 */
0x00, /* no aspect ratio */
/* global color table */
0x00, 0x00, 0x00, /* #0: black */
0xff, 0xff, 0xff, /* #1: white */
/* graphic control extension */
0x21, /* extension introducer */
0xf9, /* graphic control label */
0x04, /* block size */
0x01, /* transparent color is given, */
/* no disposal specified, */
/* user input is not expected */
0x00, 0x00, /* delay time */
0x01, /* transparent color #1 */
0x00, /* block terminator */
/* image descriptor */
0x2c, /* image separator */
0x00, 0x00, /* image left position */
0x00, 0x00, /* image top position */
0x01, 0x00, /* image width */
0x01, 0x00, /* image height */
0x00, /* no local color table, no interlaced */
/* table based image data */
0x02, /* LZW minimum code size, */
/* must be at least 2-bit */
0x02, /* block size */
0x4c, 0x01, /* compressed bytes 01_001_100, 0000000_1 */
/* 100: clear code */
/* 001: 1 */
/* 101: end of information code */
0x00, /* block terminator */
0x3B /* trailer */
};
static ngx_http_module_t ngx_http_empty_gif_module_ctx = {
NULL, /* preconfiguration */
NULL, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
NULL, /* create location configuration */
NULL /* merge location configuration */
};
ngx_module_t ngx_http_empty_gif_module = {
NGX_MODULE_V1,
&ngx_http_empty_gif_module_ctx, /* module context */
ngx_http_empty_gif_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_int_t
ngx_http_empty_gif_handler(ngx_http_request_t *r)
{
ngx_int_t rc;
ngx_buf_t *b;
ngx_chain_t out;
if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
return NGX_HTTP_NOT_ALLOWED;
}
rc = ngx_http_discard_request_body(r);
if (rc != NGX_OK) {
return rc;
}
r->headers_out.content_type_len = sizeof("image/gif") - 1;
r->headers_out.content_type.len = sizeof("image/gif") - 1;
r->headers_out.content_type.data = (u_char *) "image/gif";
if (r->method == NGX_HTTP_HEAD) {
r->headers_out.status = NGX_HTTP_OK;
r->headers_out.content_length_n = sizeof(ngx_empty_gif);
r->headers_out.last_modified_time = 23349600;
return ngx_http_send_header(r);
}
b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
if (b == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
out.buf = b;
out.next = NULL;
b->pos = ngx_empty_gif;
b->last = ngx_empty_gif + sizeof(ngx_empty_gif);
b->memory = 1;
b->last_buf = 1;
r->headers_out.status = NGX_HTTP_OK;
r->headers_out.content_length_n = sizeof(ngx_empty_gif);
r->headers_out.last_modified_time = 23349600;
rc = ngx_http_send_header(r);
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
return rc;
}
return ngx_http_output_filter(r, &out);
}
static char *
ngx_http_empty_gif(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_loc_conf_t *clcf;
clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
clcf->handler = ngx_http_empty_gif_handler;
return NGX_CONF_OK;
}
nginx-0.7.68/src/http/modules/ngx_http_referer_module.c 000644 001750 001750 00000033611 11403143271 022323 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#include
#include
#include
#define NGX_HTTP_REFERER_NO_URI_PART ((void *) 4)
#if !(NGX_PCRE)
#define ngx_regex_t void
#endif
typedef struct {
ngx_hash_combined_t hash;
#if (NGX_PCRE)
ngx_array_t *regex;
#endif
ngx_flag_t no_referer;
ngx_flag_t blocked_referer;
ngx_hash_keys_arrays_t *keys;
} ngx_http_referer_conf_t;
static void * ngx_http_referer_create_conf(ngx_conf_t *cf);
static char * ngx_http_referer_merge_conf(ngx_conf_t *cf, void *parent,
void *child);
static char *ngx_http_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_add_referer(ngx_conf_t *cf, ngx_hash_keys_arrays_t *keys,
ngx_str_t *value, ngx_str_t *uri);
static char *ngx_http_add_regex_referer(ngx_conf_t *cf,
ngx_http_referer_conf_t *rlcf, ngx_str_t *name, ngx_regex_t *regex);
static int ngx_libc_cdecl ngx_http_cmp_referer_wildcards(const void *one,
const void *two);
static ngx_command_t ngx_http_referer_commands[] = {
{ ngx_string("valid_referers"),
NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
ngx_http_valid_referers,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
ngx_null_command
};
static ngx_http_module_t ngx_http_referer_module_ctx = {
NULL, /* preconfiguration */
NULL, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
ngx_http_referer_create_conf, /* create location configuration */
ngx_http_referer_merge_conf /* merge location configuration */
};
ngx_module_t ngx_http_referer_module = {
NGX_MODULE_V1,
&ngx_http_referer_module_ctx, /* module context */
ngx_http_referer_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_int_t
ngx_http_referer_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
uintptr_t data)
{
u_char *p, *ref, *last;
size_t len;
ngx_str_t *uri;
ngx_uint_t i, key;
ngx_http_referer_conf_t *rlcf;
u_char buf[256];
rlcf = ngx_http_get_module_loc_conf(r, ngx_http_referer_module);
if (rlcf->hash.hash.buckets == NULL
&& rlcf->hash.wc_head == NULL
&& rlcf->hash.wc_tail == NULL
#if (NGX_PCRE)
&& rlcf->regex == NULL
#endif
)
{
goto valid;
}
if (r->headers_in.referer == NULL) {
if (rlcf->no_referer) {
goto valid;
}
goto invalid;
}
len = r->headers_in.referer->value.len;
ref = r->headers_in.referer->value.data;
if (len >= sizeof("http://i.ru") - 1) {
last = ref + len;
if (ngx_strncasecmp(ref, (u_char *) "http://", 7) == 0) {
ref += 7;
goto valid_scheme;
} else if (ngx_strncasecmp(ref, (u_char *) "https://", 8) == 0) {
ref += 8;
goto valid_scheme;
}
}
if (rlcf->blocked_referer) {
goto valid;
}
goto invalid;
valid_scheme:
i = 0;
key = 0;
for (p = ref; p < last; p++) {
if (*p == '/' || *p == ':') {
break;
}
buf[i] = ngx_tolower(*p);
key = ngx_hash(key, buf[i++]);
if (i == 256) {
goto invalid;
}
}
uri = ngx_hash_find_combined(&rlcf->hash, key, buf, p - ref);
if (uri) {
goto uri;
}
#if (NGX_PCRE)
if (rlcf->regex) {
ngx_int_t rc;
ngx_str_t referer;
referer.len = len - 7;
referer.data = ref;
rc = ngx_regex_exec_array(rlcf->regex, &referer, r->connection->log);
if (rc == NGX_OK) {
goto valid;
}
if (rc == NGX_ERROR) {
return rc;
}
/* NGX_DECLINED */
}
#endif
invalid:
*v = ngx_http_variable_true_value;
return NGX_OK;
uri:
for ( /* void */ ; p < last; p++) {
if (*p == '/') {
break;
}
}
len = last - p;
if (uri == NGX_HTTP_REFERER_NO_URI_PART) {
goto valid;
}
if (len < uri->len || ngx_strncmp(uri->data, p, uri->len) != 0) {
goto invalid;
}
valid:
*v = ngx_http_variable_null_value;
return NGX_OK;
}
static void *
ngx_http_referer_create_conf(ngx_conf_t *cf)
{
ngx_http_referer_conf_t *conf;
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_referer_conf_t));
if (conf == NULL) {
return NULL;
}
#if (NGX_PCRE)
conf->regex = NGX_CONF_UNSET_PTR;
#endif
conf->no_referer = NGX_CONF_UNSET;
conf->blocked_referer = NGX_CONF_UNSET;
return conf;
}
static char *
ngx_http_referer_merge_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_referer_conf_t *prev = parent;
ngx_http_referer_conf_t *conf = child;
ngx_hash_init_t hash;
if (conf->keys == NULL) {
conf->hash = prev->hash;
#if (NGX_PCRE)
ngx_conf_merge_ptr_value(conf->regex, prev->regex, NULL);
#endif
ngx_conf_merge_value(conf->no_referer, prev->no_referer, 0);
ngx_conf_merge_value(conf->blocked_referer, prev->blocked_referer, 0);
return NGX_CONF_OK;
}
if ((conf->no_referer == 1 || conf->blocked_referer == 1)
&& conf->keys->keys.nelts == 0
&& conf->keys->dns_wc_head.nelts == 0
&& conf->keys->dns_wc_tail.nelts == 0)
{
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"the \"none\" or \"blocked\" referers are specified "
"in the \"valid_referers\" directive "
"without any valid referer");
return NGX_CONF_ERROR;
}
hash.key = ngx_hash_key_lc;
hash.max_size = 2048; /* TODO: referer_hash_max_size; */
hash.bucket_size = 64; /* TODO: referer_hash_bucket_size; */
hash.name = "referers_hash";
hash.pool = cf->pool;
if (conf->keys->keys.nelts) {
hash.hash = &conf->hash.hash;
hash.temp_pool = NULL;
if (ngx_hash_init(&hash, conf->keys->keys.elts, conf->keys->keys.nelts)
!= NGX_OK)
{
return NGX_CONF_ERROR;
}
}
if (conf->keys->dns_wc_head.nelts) {
ngx_qsort(conf->keys->dns_wc_head.elts,
(size_t) conf->keys->dns_wc_head.nelts,
sizeof(ngx_hash_key_t),
ngx_http_cmp_referer_wildcards);
hash.hash = NULL;
hash.temp_pool = cf->temp_pool;
if (ngx_hash_wildcard_init(&hash, conf->keys->dns_wc_head.elts,
conf->keys->dns_wc_head.nelts)
!= NGX_OK)
{
return NGX_CONF_ERROR;
}
conf->hash.wc_head = (ngx_hash_wildcard_t *) hash.hash;
}
if (conf->keys->dns_wc_tail.nelts) {
ngx_qsort(conf->keys->dns_wc_tail.elts,
(size_t) conf->keys->dns_wc_tail.nelts,
sizeof(ngx_hash_key_t),
ngx_http_cmp_referer_wildcards);
hash.hash = NULL;
hash.temp_pool = cf->temp_pool;
if (ngx_hash_wildcard_init(&hash, conf->keys->dns_wc_tail.elts,
conf->keys->dns_wc_tail.nelts)
!= NGX_OK)
{
return NGX_CONF_ERROR;
}
conf->hash.wc_tail = (ngx_hash_wildcard_t *) hash.hash;
}
#if (NGX_PCRE)
ngx_conf_merge_ptr_value(conf->regex, prev->regex, NULL);
#endif
if (conf->no_referer == NGX_CONF_UNSET) {
conf->no_referer = 0;
}
if (conf->blocked_referer == NGX_CONF_UNSET) {
conf->blocked_referer = 0;
}
conf->keys = NULL;
return NGX_CONF_OK;
}
static char *
ngx_http_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_referer_conf_t *rlcf = conf;
u_char *p;
ngx_str_t *value, uri, name;
ngx_uint_t i, n;
ngx_http_variable_t *var;
ngx_http_server_name_t *sn;
ngx_http_core_srv_conf_t *cscf;
name.len = sizeof("invalid_referer") - 1;
name.data = (u_char *) "invalid_referer";
var = ngx_http_add_variable(cf, &name,
NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOHASH);
if (var == NULL) {
return NGX_CONF_ERROR;
}
var->get_handler = ngx_http_referer_variable;
if (rlcf->keys == NULL) {
rlcf->keys = ngx_pcalloc(cf->temp_pool, sizeof(ngx_hash_keys_arrays_t));
if (rlcf->keys == NULL) {
return NGX_CONF_ERROR;
}
rlcf->keys->pool = cf->pool;
rlcf->keys->temp_pool = cf->pool;
if (ngx_hash_keys_array_init(rlcf->keys, NGX_HASH_SMALL) != NGX_OK) {
return NGX_CONF_ERROR;
}
}
value = cf->args->elts;
for (i = 1; i < cf->args->nelts; i++) {
if (value[i].len == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid referer \"%V\"", &value[i]);
return NGX_CONF_ERROR;
}
if (ngx_strcmp(value[i].data, "none") == 0) {
rlcf->no_referer = 1;
continue;
}
if (ngx_strcmp(value[i].data, "blocked") == 0) {
rlcf->blocked_referer = 1;
continue;
}
uri.len = 0;
uri.data = NULL;
if (ngx_strcmp(value[i].data, "server_names") == 0) {
cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module);
sn = cscf->server_names.elts;
for (n = 0; n < cscf->server_names.nelts; n++) {
#if (NGX_PCRE)
if (sn[n].regex) {
if (ngx_http_add_regex_referer(cf, rlcf, &sn[n].name,
sn[n].regex)
!= NGX_OK)
{
return NGX_CONF_ERROR;
}
continue;
}
#endif
if (ngx_http_add_referer(cf, rlcf->keys, &sn[n].name, &uri)
!= NGX_OK)
{
return NGX_CONF_ERROR;
}
}
continue;
}
if (value[i].data[0] == '~') {
if (ngx_http_add_regex_referer(cf, rlcf, &value[i], NULL) != NGX_OK)
{
return NGX_CONF_ERROR;
}
continue;
}
p = (u_char *) ngx_strchr(value[i].data, '/');
if (p) {
uri.len = (value[i].data + value[i].len) - p;
uri.data = p;
value[i].len = p - value[i].data;
}
if (ngx_http_add_referer(cf, rlcf->keys, &value[i], &uri) != NGX_OK) {
return NGX_CONF_ERROR;
}
}
return NGX_CONF_OK;
}
static char *
ngx_http_add_referer(ngx_conf_t *cf, ngx_hash_keys_arrays_t *keys,
ngx_str_t *value, ngx_str_t *uri)
{
ngx_int_t rc;
ngx_str_t *u;
if (uri->len == 0) {
u = NGX_HTTP_REFERER_NO_URI_PART;
} else {
u = ngx_palloc(cf->pool, sizeof(ngx_str_t));
if (u == NULL) {
return NGX_CONF_ERROR;
}
*u = *uri;
}
rc = ngx_hash_add_key(keys, value, u, NGX_HASH_WILDCARD_KEY);
if (rc == NGX_OK) {
return NGX_CONF_OK;
}
if (rc == NGX_DECLINED) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid hostname or wildcard \"%V\"", value);
}
if (rc == NGX_BUSY) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"conflicting parameter \"%V\"", value);
}
return NGX_CONF_ERROR;
}
static char *
ngx_http_add_regex_referer(ngx_conf_t *cf, ngx_http_referer_conf_t *rlcf,
ngx_str_t *name, ngx_regex_t *regex)
{
#if (NGX_PCRE)
ngx_str_t err;
ngx_regex_elt_t *re;
u_char errstr[NGX_MAX_CONF_ERRSTR];
if (name->len == 1) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "empty regex in \"%V\"", name);
return NGX_CONF_ERROR;
}
if (rlcf->regex == NGX_CONF_UNSET_PTR) {
rlcf->regex = ngx_array_create(cf->pool, 2, sizeof(ngx_regex_elt_t));
if (rlcf->regex == NULL) {
return NGX_CONF_ERROR;
}
}
re = ngx_array_push(rlcf->regex);
if (re == NULL) {
return NGX_CONF_ERROR;
}
if (regex) {
re->regex = regex;
re->name = name->data;
return NGX_CONF_OK;
}
err.len = NGX_MAX_CONF_ERRSTR;
err.data = errstr;
name->len--;
name->data++;
re->regex = ngx_regex_compile(name, NGX_REGEX_CASELESS, cf->pool, &err);
if (re->regex == NULL) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data);
return NGX_CONF_ERROR;
}
re->name = name->data;
return NGX_CONF_OK;
#else
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the using of the regex \"%V\" requires PCRE library",
name);
return NGX_CONF_ERROR;
#endif
}
static int ngx_libc_cdecl
ngx_http_cmp_referer_wildcards(const void *one, const void *two)
{
ngx_hash_key_t *first, *second;
first = (ngx_hash_key_t *) one;
second = (ngx_hash_key_t *) two;
return ngx_dns_strcmp(first->key.data, second->key.data);
}
nginx-0.7.68/src/http/modules/ngx_http_addition_filter_module.c 000644 001750 001750 00000015325 11331562024 024034 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#include
#include
#include
typedef struct {
ngx_str_t before_body;
ngx_str_t after_body;
ngx_hash_t types;
ngx_array_t *types_keys;
} ngx_http_addition_conf_t;
typedef struct {
ngx_uint_t before_body_sent;
} ngx_http_addition_ctx_t;
static void *ngx_http_addition_create_conf(ngx_conf_t *cf);
static char *ngx_http_addition_merge_conf(ngx_conf_t *cf, void *parent,
void *child);
static ngx_int_t ngx_http_addition_filter_init(ngx_conf_t *cf);
static ngx_command_t ngx_http_addition_commands[] = {
{ ngx_string("add_before_body"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_addition_conf_t, before_body),
NULL },
{ ngx_string("add_after_body"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_addition_conf_t, after_body),
NULL },
{ ngx_string("addition_types"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
ngx_http_types_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_addition_conf_t, types_keys),
&ngx_http_html_default_types[0] },
ngx_null_command
};
static ngx_http_module_t ngx_http_addition_filter_module_ctx = {
NULL, /* preconfiguration */
ngx_http_addition_filter_init, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
ngx_http_addition_create_conf, /* create location configuration */
ngx_http_addition_merge_conf /* merge location configuration */
};
ngx_module_t ngx_http_addition_filter_module = {
NGX_MODULE_V1,
&ngx_http_addition_filter_module_ctx, /* module context */
ngx_http_addition_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
static ngx_int_t
ngx_http_addition_header_filter(ngx_http_request_t *r)
{
ngx_http_addition_ctx_t *ctx;
ngx_http_addition_conf_t *conf;
if (r->headers_out.status != NGX_HTTP_OK || r != r->main) {
return ngx_http_next_header_filter(r);
}
conf = ngx_http_get_module_loc_conf(r, ngx_http_addition_filter_module);
if (conf->before_body.len == 0 && conf->after_body.len == 0) {
return ngx_http_next_header_filter(r);
}
if (ngx_http_test_content_type(r, &conf->types) == NULL) {
return ngx_http_next_header_filter(r);
}
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_addition_ctx_t));
if (ctx == NULL) {
return NGX_ERROR;
}
ngx_http_set_ctx(r, ctx, ngx_http_addition_filter_module);
ngx_http_clear_content_length(r);
ngx_http_clear_accept_ranges(r);
return ngx_http_next_header_filter(r);
}
static ngx_int_t
ngx_http_addition_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
ngx_int_t rc;
ngx_uint_t last;
ngx_chain_t *cl;
ngx_http_request_t *sr;
ngx_http_addition_ctx_t *ctx;
ngx_http_addition_conf_t *conf;
if (in == NULL || r->header_only) {
return ngx_http_next_body_filter(r, in);
}
ctx = ngx_http_get_module_ctx(r, ngx_http_addition_filter_module);
if (ctx == NULL) {
return ngx_http_next_body_filter(r, in);
}
conf = ngx_http_get_module_loc_conf(r, ngx_http_addition_filter_module);
if (!ctx->before_body_sent) {
ctx->before_body_sent = 1;
if (conf->before_body.len) {
if (ngx_http_subrequest(r, &conf->before_body, NULL, &sr, NULL, 0)
!= NGX_OK)
{
return NGX_ERROR;
}
}
}
if (conf->after_body.len == 0) {
ngx_http_set_ctx(r, NULL, ngx_http_addition_filter_module);
return ngx_http_next_body_filter(r, in);
}
last = 0;
for (cl = in; cl; cl = cl->next) {
if (cl->buf->last_buf) {
cl->buf->last_buf = 0;
cl->buf->sync = 1;
last = 1;
}
}
rc = ngx_http_next_body_filter(r, in);
if (rc == NGX_ERROR || !last || conf->after_body.len == 0) {
return rc;
}
if (ngx_http_subrequest(r, &conf->after_body, NULL, &sr, NULL, 0)
!= NGX_OK)
{
return NGX_ERROR;
}
ngx_http_set_ctx(r, NULL, ngx_http_addition_filter_module);
return ngx_http_send_special(r, NGX_HTTP_LAST);
}
static ngx_int_t
ngx_http_addition_filter_init(ngx_conf_t *cf)
{
ngx_http_next_header_filter = ngx_http_top_header_filter;
ngx_http_top_header_filter = ngx_http_addition_header_filter;
ngx_http_next_body_filter = ngx_http_top_body_filter;
ngx_http_top_body_filter = ngx_http_addition_body_filter;
return NGX_OK;
}
static void *
ngx_http_addition_create_conf(ngx_conf_t *cf)
{
ngx_http_addition_conf_t *conf;
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_addition_conf_t));
if (conf == NULL) {
return NULL;
}
/*
* set by ngx_pcalloc():
*
* conf->before_body = { 0, NULL };
* conf->after_body = { 0, NULL };
* conf->types = { NULL };
* conf->types_keys = NULL;
*/
return conf;
}
static char *
ngx_http_addition_merge_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_addition_conf_t *prev = parent;
ngx_http_addition_conf_t *conf = child;
ngx_conf_merge_str_value(conf->before_body, prev->before_body, "");
ngx_conf_merge_str_value(conf->after_body, prev->after_body, "");
if (ngx_http_merge_types(cf, conf->types_keys, &conf->types,
prev->types_keys, &prev->types,
ngx_http_html_default_types)
!= NGX_OK)
{
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
nginx-0.7.68/src/http/modules/ngx_http_sub_filter_module.c 000644 001750 001750 00000044000 11501743144 023025 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#include
#include
#include
typedef struct {
ngx_str_t match;
ngx_http_complex_value_t value;
ngx_hash_t types;
ngx_flag_t once;
ngx_array_t *types_keys;
} ngx_http_sub_loc_conf_t;
typedef enum {
sub_start_state = 0,
sub_match_state,
} ngx_http_sub_state_e;
typedef struct {
ngx_str_t match;
ngx_str_t saved;
ngx_str_t looked;
ngx_uint_t once; /* unsigned once:1 */
ngx_buf_t *buf;
u_char *pos;
u_char *copy_start;
u_char *copy_end;
ngx_chain_t *in;
ngx_chain_t *out;
ngx_chain_t **last_out;
ngx_chain_t *busy;
ngx_chain_t *free;
ngx_str_t sub;
ngx_uint_t state;
} ngx_http_sub_ctx_t;
static ngx_int_t ngx_http_sub_output(ngx_http_request_t *r,
ngx_http_sub_ctx_t *ctx);
static ngx_int_t ngx_http_sub_parse(ngx_http_request_t *r,
ngx_http_sub_ctx_t *ctx);
static char * ngx_http_sub_filter(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static void *ngx_http_sub_create_conf(ngx_conf_t *cf);
static char *ngx_http_sub_merge_conf(ngx_conf_t *cf,
void *parent, void *child);
static ngx_int_t ngx_http_sub_filter_init(ngx_conf_t *cf);
static ngx_command_t ngx_http_sub_filter_commands[] = {
{ ngx_string("sub_filter"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
ngx_http_sub_filter,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("sub_filter_types"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
ngx_http_types_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_sub_loc_conf_t, types_keys),
&ngx_http_html_default_types[0] },
{ ngx_string("sub_filter_once"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_sub_loc_conf_t, once),
NULL },
ngx_null_command
};
static ngx_http_module_t ngx_http_sub_filter_module_ctx = {
NULL, /* preconfiguration */
ngx_http_sub_filter_init, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
ngx_http_sub_create_conf, /* create location configuration */
ngx_http_sub_merge_conf /* merge location configuration */
};
ngx_module_t ngx_http_sub_filter_module = {
NGX_MODULE_V1,
&ngx_http_sub_filter_module_ctx, /* module context */
ngx_http_sub_filter_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
static ngx_int_t
ngx_http_sub_header_filter(ngx_http_request_t *r)
{
ngx_http_sub_ctx_t *ctx;
ngx_http_sub_loc_conf_t *slcf;
slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module);
if (slcf->match.len == 0
|| r->headers_out.content_length_n == 0
|| ngx_http_test_content_type(r, &slcf->types) == NULL)
{
return ngx_http_next_header_filter(r);
}
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_sub_ctx_t));
if (ctx == NULL) {
return NGX_ERROR;
}
ctx->saved.data = ngx_pnalloc(r->pool, slcf->match.len);
if (ctx->saved.data == NULL) {
return NGX_ERROR;
}
ctx->looked.data = ngx_pnalloc(r->pool, slcf->match.len);
if (ctx->looked.data == NULL) {
return NGX_ERROR;
}
ngx_http_set_ctx(r, ctx, ngx_http_sub_filter_module);
ctx->match = slcf->match;
ctx->last_out = &ctx->out;
r->filter_need_in_memory = 1;
if (r == r->main) {
ngx_http_clear_content_length(r);
ngx_http_clear_last_modified(r);
}
return ngx_http_next_header_filter(r);
}
static ngx_int_t
ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
ngx_int_t rc;
ngx_buf_t *b;
ngx_chain_t *cl;
ngx_http_sub_ctx_t *ctx;
ngx_http_sub_loc_conf_t *slcf;
ctx = ngx_http_get_module_ctx(r, ngx_http_sub_filter_module);
if (ctx == NULL) {
return ngx_http_next_body_filter(r, in);
}
if ((in == NULL
&& ctx->buf == NULL
&& ctx->in == NULL
&& ctx->busy == NULL))
{
return ngx_http_next_body_filter(r, in);
}
if (ctx->once && (ctx->buf == NULL || ctx->in == NULL)) {
if (ctx->busy) {
if (ngx_http_sub_output(r, ctx) == NGX_ERROR) {
return NGX_ERROR;
}
}
return ngx_http_next_body_filter(r, in);
}
/* add the incoming chain to the chain ctx->in */
if (in) {
if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) {
return NGX_ERROR;
}
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http sub filter \"%V\"", &r->uri);
while (ctx->in || ctx->buf) {
if (ctx->buf == NULL ){
ctx->buf = ctx->in->buf;
ctx->in = ctx->in->next;
ctx->pos = ctx->buf->pos;
}
if (ctx->state == sub_start_state) {
ctx->copy_start = ctx->pos;
ctx->copy_end = ctx->pos;
}
b = NULL;
while (ctx->pos < ctx->buf->last) {
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"saved: \"%V\" state: %d", &ctx->saved, ctx->state);
rc = ngx_http_sub_parse(r, ctx);
ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"parse: %d, looked: \"%V\" %p-%p",
rc, &ctx->looked, ctx->copy_start, ctx->copy_end);
if (rc == NGX_ERROR) {
return rc;
}
if (ctx->copy_start != ctx->copy_end) {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"saved: \"%V\"", &ctx->saved);
if (ctx->saved.len) {
if (ctx->free) {
cl = ctx->free;
ctx->free = ctx->free->next;
b = cl->buf;
ngx_memzero(b, sizeof(ngx_buf_t));
} else {
b = ngx_calloc_buf(r->pool);
if (b == NULL) {
return NGX_ERROR;
}
cl = ngx_alloc_chain_link(r->pool);
if (cl == NULL) {
return NGX_ERROR;
}
cl->buf = b;
}
b->pos = ngx_pnalloc(r->pool, ctx->saved.len);
if (b->pos == NULL) {
return NGX_ERROR;
}
ngx_memcpy(b->pos, ctx->saved.data, ctx->saved.len);
b->last = b->pos + ctx->saved.len;
b->memory = 1;
*ctx->last_out = cl;
ctx->last_out = &cl->next;
ctx->saved.len = 0;
}
if (ctx->free) {
cl = ctx->free;
ctx->free = ctx->free->next;
b = cl->buf;
} else {
b = ngx_alloc_buf(r->pool);
if (b == NULL) {
return NGX_ERROR;
}
cl = ngx_alloc_chain_link(r->pool);
if (cl == NULL) {
return NGX_ERROR;
}
cl->buf = b;
}
ngx_memcpy(b, ctx->buf, sizeof(ngx_buf_t));
b->pos = ctx->copy_start;
b->last = ctx->copy_end;
b->shadow = NULL;
b->last_buf = 0;
b->recycled = 0;
if (b->in_file) {
b->file_last = b->file_pos + (b->last - ctx->buf->pos);
b->file_pos += b->pos - ctx->buf->pos;
}
cl->next = NULL;
*ctx->last_out = cl;
ctx->last_out = &cl->next;
}
if (ctx->state == sub_start_state) {
ctx->copy_start = ctx->pos;
ctx->copy_end = ctx->pos;
} else {
ctx->copy_start = NULL;
ctx->copy_end = NULL;
}
if (rc == NGX_AGAIN) {
continue;
}
/* rc == NGX_OK */
b = ngx_calloc_buf(r->pool);
if (b == NULL) {
return NGX_ERROR;
}
cl = ngx_alloc_chain_link(r->pool);
if (cl == NULL) {
return NGX_ERROR;
}
slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module);
if (ctx->sub.data == NULL) {
if (ngx_http_complex_value(r, &slcf->value, &ctx->sub)
!= NGX_OK)
{
return NGX_ERROR;
}
}
if (ctx->sub.len) {
b->memory = 1;
b->pos = ctx->sub.data;
b->last = ctx->sub.data + ctx->sub.len;
} else {
b->sync = 1;
}
cl->buf = b;
cl->next = NULL;
*ctx->last_out = cl;
ctx->last_out = &cl->next;
ctx->once = slcf->once;
continue;
}
if (ctx->buf->last_buf || ngx_buf_in_memory(ctx->buf)) {
if (b == NULL) {
if (ctx->free) {
cl = ctx->free;
ctx->free = ctx->free->next;
b = cl->buf;
ngx_memzero(b, sizeof(ngx_buf_t));
} else {
b = ngx_calloc_buf(r->pool);
if (b == NULL) {
return NGX_ERROR;
}
cl = ngx_alloc_chain_link(r->pool);
if (cl == NULL) {
return NGX_ERROR;
}
cl->buf = b;
}
b->sync = 1;
cl->next = NULL;
*ctx->last_out = cl;
ctx->last_out = &cl->next;
}
b->last_buf = ctx->buf->last_buf;
b->shadow = ctx->buf;
b->recycled = ctx->buf->recycled;
}
ctx->buf = NULL;
ctx->saved.len = ctx->looked.len;
ngx_memcpy(ctx->saved.data, ctx->looked.data, ctx->looked.len);
}
if (ctx->out == NULL && ctx->busy == NULL) {
return NGX_OK;
}
return ngx_http_sub_output(r, ctx);
}
static ngx_int_t
ngx_http_sub_output(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx)
{
ngx_int_t rc;
ngx_buf_t *b;
ngx_chain_t *cl;
#if 1
b = NULL;
for (cl = ctx->out; cl; cl = cl->next) {
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"sub out: %p %p", cl->buf, cl->buf->pos);
if (cl->buf == b) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
"the same buf was used in sub");
ngx_debug_point();
return NGX_ERROR;
}
b = cl->buf;
}
#endif
rc = ngx_http_next_body_filter(r, ctx->out);
if (ctx->busy == NULL) {
ctx->busy = ctx->out;
} else {
for (cl = ctx->busy; cl->next; cl = cl->next) { /* void */ }
cl->next = ctx->out;
}
ctx->out = NULL;
ctx->last_out = &ctx->out;
while (ctx->busy) {
cl = ctx->busy;
b = cl->buf;
if (ngx_buf_size(b) != 0) {
break;
}
if (b->shadow) {
b->shadow->pos = b->shadow->last;
}
ctx->busy = cl->next;
if (ngx_buf_in_memory(b) || b->in_file) {
/* add data bufs only to the free buf chain */
cl->next = ctx->free;
ctx->free = cl;
}
}
if (ctx->in || ctx->buf) {
r->buffered |= NGX_HTTP_SUB_BUFFERED;
} else {
r->buffered &= ~NGX_HTTP_SUB_BUFFERED;
}
return rc;
}
static ngx_int_t
ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx)
{
u_char *p, *last, *copy_end, ch, match;
size_t looked;
ngx_http_sub_state_e state;
if (ctx->once) {
ctx->copy_start = ctx->pos;
ctx->copy_end = ctx->buf->last;
ctx->pos = ctx->buf->last;
ctx->looked.len = 0;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "once");
return NGX_AGAIN;
}
state = ctx->state;
looked = ctx->looked.len;
last = ctx->buf->last;
copy_end = ctx->copy_end;
for (p = ctx->pos; p < last; p++) {
ch = *p;
ch = ngx_tolower(ch);
if (state == sub_start_state) {
/* the tight loop */
match = ctx->match.data[0];
for ( ;; ) {
if (ch == match) {
copy_end = p;
ctx->looked.data[0] = *p;
looked = 1;
state = sub_match_state;
goto match_started;
}
if (++p == last) {
break;
}
ch = *p;
ch = ngx_tolower(ch);
}
ctx->state = state;
ctx->pos = p;
ctx->looked.len = looked;
ctx->copy_end = p;
if (ctx->copy_start == NULL) {
ctx->copy_start = ctx->buf->pos;
}
return NGX_AGAIN;
match_started:
continue;
}
/* state == sub_match_state */
if (ch == ctx->match.data[looked]) {
ctx->looked.data[looked] = *p;
looked++;
if (looked == ctx->match.len) {
if ((size_t) (p - ctx->pos) < looked) {
ctx->saved.len = 0;
}
ctx->state = sub_start_state;
ctx->pos = p + 1;
ctx->looked.len = 0;
ctx->copy_end = copy_end;
if (ctx->copy_start == NULL && copy_end) {
ctx->copy_start = ctx->buf->pos;
}
return NGX_OK;
}
} else if (ch == ctx->match.data[0]) {
copy_end = p;
ctx->looked.data[0] = *p;
looked = 1;
} else {
copy_end = p;
looked = 0;
state = sub_start_state;
}
}
ctx->state = state;
ctx->pos = p;
ctx->looked.len = looked;
ctx->copy_end = (state == sub_start_state) ? p : copy_end;
if (ctx->copy_start == NULL && ctx->copy_end) {
ctx->copy_start = ctx->buf->pos;
}
return NGX_AGAIN;
}
static char *
ngx_http_sub_filter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_sub_loc_conf_t *slcf = conf;
ngx_str_t *value;
ngx_http_compile_complex_value_t ccv;
if (slcf->match.len) {
return "is duplicate";
}
value = cf->args->elts;
ngx_strlow(value[1].data, value[1].data, value[1].len);
slcf->match = value[1];
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
ccv.cf = cf;
ccv.value = &value[2];
ccv.complex_value = &slcf->value;
if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
static void *
ngx_http_sub_create_conf(ngx_conf_t *cf)
{
ngx_http_sub_loc_conf_t *slcf;
slcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_sub_loc_conf_t));
if (slcf == NULL) {
return NULL;
}
/*
* set by ngx_pcalloc():
*
* conf->match = { 0, NULL };
* conf->sub = { 0, NULL };
* conf->sub_lengths = NULL;
* conf->sub_values = NULL;
* conf->types = { NULL };
* conf->types_keys = NULL;
*/
slcf->once = NGX_CONF_UNSET;
return slcf;
}
static char *
ngx_http_sub_merge_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_sub_loc_conf_t *prev = parent;
ngx_http_sub_loc_conf_t *conf = child;
ngx_conf_merge_value(conf->once, prev->once, 1);
ngx_conf_merge_str_value(conf->match, prev->match, "");
if (conf->value.value.len == 0) {
conf->value = prev->value;
}
if (ngx_http_merge_types(cf, conf->types_keys, &conf->types,
prev->types_keys, &prev->types,
ngx_http_html_default_types)
!= NGX_OK)
{
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
static ngx_int_t
ngx_http_sub_filter_init(ngx_conf_t *cf)
{
ngx_http_next_header_filter = ngx_http_top_header_filter;
ngx_http_top_header_filter = ngx_http_sub_header_filter;
ngx_http_next_body_filter = ngx_http_top_body_filter;
ngx_http_top_body_filter = ngx_http_sub_body_filter;
return NGX_OK;
}
nginx-0.7.68/src/http/modules/ngx_http_xslt_filter_module.c 000644 001750 001750 00000101271 11271344363 023236 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#if (NGX_HAVE_EXSLT)
#include
#endif
#ifndef NGX_HTTP_XSLT_REUSE_DTD
#define NGX_HTTP_XSLT_REUSE_DTD 1
#endif
typedef struct {
u_char *name;
void *data;
} ngx_http_xslt_file_t;
typedef struct {
ngx_array_t dtd_files; /* ngx_http_xslt_file_t */
ngx_array_t sheet_files; /* ngx_http_xslt_file_t */
} ngx_http_xslt_filter_main_conf_t;
typedef struct {
xsltStylesheetPtr stylesheet;
ngx_array_t params; /* ngx_http_complex_value_t */
} ngx_http_xslt_sheet_t;
typedef struct {
xmlDtdPtr dtd;
ngx_array_t sheets; /* ngx_http_xslt_sheet_t */
ngx_hash_t types;
ngx_array_t *types_keys;
} ngx_http_xslt_filter_loc_conf_t;
typedef struct {
xmlDocPtr doc;
xmlParserCtxtPtr ctxt;
xmlSAXHandler *sax;
ngx_http_request_t *request;
ngx_array_t params;
ngx_uint_t done; /* unsigned done:1; */
} ngx_http_xslt_filter_ctx_t;
static ngx_int_t ngx_http_xslt_send(ngx_http_request_t *r,
ngx_http_xslt_filter_ctx_t *ctx, ngx_buf_t *b);
static ngx_int_t ngx_http_xslt_add_chunk(ngx_http_request_t *r,
ngx_http_xslt_filter_ctx_t *ctx, ngx_buf_t *b);
static void ngx_http_xslt_sax_start_document(void *data);
static void ngx_http_xslt_sax_end_document(void *data);
static void ngx_http_xslt_sax_internal_subset(void *data, const xmlChar *name,
const xmlChar *externalId, const xmlChar *systemId);
static void ngx_http_xslt_sax_external_subset(void *data, const xmlChar *name,
const xmlChar *externalId, const xmlChar *systemId);
static void ngx_http_xslt_sax_entity_decl(void *data, const xmlChar *name,
int type, const xmlChar *publicId, const xmlChar *systemId,
xmlChar *content);
static void ngx_http_xslt_sax_attribute_decl(void *data, const xmlChar *elem,
const xmlChar *fullname, int type, int def, const xmlChar *defaultValue,
xmlEnumerationPtr tree);
static void ngx_http_xslt_sax_element_decl(void *data, const xmlChar * name,
int type, xmlElementContentPtr content);
static void ngx_http_xslt_sax_notation_decl(void *data, const xmlChar *name,
const xmlChar *publicId, const xmlChar *systemId);
static void ngx_http_xslt_sax_unparsed_entity_decl(void *data,
const xmlChar *name, const xmlChar *publicId, const xmlChar *systemId,
const xmlChar *notationName);
static void ngx_http_xslt_sax_start_element(void *data,
const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI,
int nb_namespaces, const xmlChar **namespaces, int nb_attributes,
int nb_defaulted, const xmlChar **attributes);
static void ngx_http_xslt_sax_end_element(void *data,
const xmlChar * localname ATTRIBUTE_UNUSED,
const xmlChar * prefix ATTRIBUTE_UNUSED,
const xmlChar * URI ATTRIBUTE_UNUSED);
static void ngx_http_xslt_sax_characters(void *data, const xmlChar *p, int len);
static void ngx_http_xslt_sax_cdata_block(void *data, const xmlChar *p,
int len);
static xmlEntityPtr ngx_http_xslt_sax_get_entity(void *data,
const xmlChar *name);
static xmlEntityPtr ngx_http_xslt_sax_get_parameter_entity(void *data,
const xmlChar *name);
static xmlParserInputPtr ngx_http_xslt_sax_resolve_entity(void *data,
const xmlChar *publicId, const xmlChar *systemId);
static void ngx_http_xslt_sax_reference(void *data, const xmlChar *name);
static void ngx_http_xslt_sax_comment(void *data, const xmlChar *value);
static void ngx_http_xslt_sax_processing_instruction(void *data,
const xmlChar *target, const xmlChar *pidata);
static int ngx_http_xslt_sax_is_standalone(void *data);
static int ngx_http_xslt_sax_has_internal_subset(void *data);
static int ngx_http_xslt_sax_has_external_subset(void *data);
static void ngx_cdecl ngx_http_xslt_sax_error(void *data, const char *msg, ...);
static ngx_buf_t *ngx_http_xslt_apply_stylesheet(ngx_http_request_t *r,
ngx_http_xslt_filter_ctx_t *ctx);
static ngx_int_t ngx_http_xslt_params(ngx_http_request_t *r,
ngx_http_xslt_filter_ctx_t *ctx, ngx_array_t *params);
static u_char *ngx_http_xslt_content_type(xsltStylesheetPtr s);
static u_char *ngx_http_xslt_encoding(xsltStylesheetPtr s);
static void ngx_http_xslt_cleanup(void *data);
static char *ngx_http_xslt_entities(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_xslt_stylesheet(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static void ngx_http_xslt_cleanup_dtd(void *data);
static void ngx_http_xslt_cleanup_stylesheet(void *data);
static void *ngx_http_xslt_filter_create_main_conf(ngx_conf_t *cf);
static void *ngx_http_xslt_filter_create_conf(ngx_conf_t *cf);
static char *ngx_http_xslt_filter_merge_conf(ngx_conf_t *cf, void *parent,
void *child);
static ngx_int_t ngx_http_xslt_filter_init(ngx_conf_t *cf);
static void ngx_http_xslt_filter_exit(ngx_cycle_t *cycle);
ngx_str_t ngx_http_xslt_default_types[] = {
ngx_string("text/xml"),
ngx_null_string
};
static ngx_command_t ngx_http_xslt_filter_commands[] = {
{ ngx_string("xml_entities"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_http_xslt_entities,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("xslt_stylesheet"),
NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
ngx_http_xslt_stylesheet,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("xslt_types"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
ngx_http_types_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_xslt_filter_loc_conf_t, types_keys),
&ngx_http_xslt_default_types[0] },
ngx_null_command
};
static ngx_http_module_t ngx_http_xslt_filter_module_ctx = {
NULL, /* preconfiguration */
ngx_http_xslt_filter_init, /* postconfiguration */
ngx_http_xslt_filter_create_main_conf, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
ngx_http_xslt_filter_create_conf, /* create location configuration */
ngx_http_xslt_filter_merge_conf /* merge location configuration */
};
ngx_module_t ngx_http_xslt_filter_module = {
NGX_MODULE_V1,
&ngx_http_xslt_filter_module_ctx, /* module context */
ngx_http_xslt_filter_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
ngx_http_xslt_filter_exit, /* exit process */
ngx_http_xslt_filter_exit, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
static ngx_int_t
ngx_http_xslt_header_filter(ngx_http_request_t *r)
{
ngx_http_xslt_filter_ctx_t *ctx;
ngx_http_xslt_filter_loc_conf_t *conf;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"xslt filter header");
if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED) {
return ngx_http_next_header_filter(r);
}
conf = ngx_http_get_module_loc_conf(r, ngx_http_xslt_filter_module);
if (conf->sheets.nelts == 0
|| ngx_http_test_content_type(r, &conf->types) == NULL)
{
return ngx_http_next_header_filter(r);
}
ctx = ngx_http_get_module_ctx(r, ngx_http_xslt_filter_module);
if (ctx) {
return ngx_http_next_header_filter(r);
}
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_xslt_filter_ctx_t));
if (ctx == NULL) {
return NGX_ERROR;
}
ngx_http_set_ctx(r, ctx, ngx_http_xslt_filter_module);
r->main_filter_need_in_memory = 1;
return NGX_OK;
}
static ngx_int_t
ngx_http_xslt_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
int wellFormed;
ngx_chain_t *cl;
ngx_http_xslt_filter_ctx_t *ctx;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"xslt filter body");
if (in == NULL) {
return ngx_http_next_body_filter(r, in);
}
ctx = ngx_http_get_module_ctx(r, ngx_http_xslt_filter_module);
if (ctx == NULL || ctx->done) {
return ngx_http_next_body_filter(r, in);
}
for (cl = in; cl; cl = cl->next) {
if (ngx_http_xslt_add_chunk(r, ctx, cl->buf) != NGX_OK) {
if (ctx->ctxt->myDoc){
#if (NGX_HTTP_XSLT_REUSE_DTD)
ctx->ctxt->myDoc->extSubset = NULL;
#endif
xmlFreeDoc(ctx->ctxt->myDoc);
}
xmlFreeParserCtxt(ctx->ctxt);
return ngx_http_xslt_send(r, ctx, NULL);
}
if (cl->buf->last_buf || cl->buf->last_in_chain) {
ctx->doc = ctx->ctxt->myDoc;
#if (NGX_HTTP_XSLT_REUSE_DTD)
ctx->doc->extSubset = NULL;
#endif
wellFormed = ctx->ctxt->wellFormed;
xmlFreeParserCtxt(ctx->ctxt);
if (wellFormed) {
return ngx_http_xslt_send(r, ctx,
ngx_http_xslt_apply_stylesheet(r, ctx));
}
xmlFreeDoc(ctx->doc);
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"not well formed XML document");
return ngx_http_xslt_send(r, ctx, NULL);
}
}
return NGX_OK;
}
static ngx_int_t
ngx_http_xslt_send(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx,
ngx_buf_t *b)
{
ngx_int_t rc;
ngx_chain_t out;
ngx_pool_cleanup_t *cln;
ctx->done = 1;
if (b == NULL) {
return ngx_http_filter_finalize_request(r, NULL,
NGX_HTTP_INTERNAL_SERVER_ERROR);
}
cln = ngx_pool_cleanup_add(r->pool, 0);
if (cln == NULL) {
ngx_free(b->pos);
return ngx_http_filter_finalize_request(r, NULL,
NGX_HTTP_INTERNAL_SERVER_ERROR);
}
if (r == r->main) {
r->headers_out.content_length_n = b->last - b->pos;
if (r->headers_out.content_length) {
r->headers_out.content_length->hash = 0;
r->headers_out.content_length = NULL;
}
ngx_http_clear_last_modified(r);
}
rc = ngx_http_next_header_filter(r);
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
ngx_free(b->pos);
return rc;
}
cln->handler = ngx_http_xslt_cleanup;
cln->data = b->pos;
out.buf = b;
out.next = NULL;
return ngx_http_next_body_filter(r, &out);
}
static ngx_int_t
ngx_http_xslt_add_chunk(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx,
ngx_buf_t *b)
{
int err;
xmlSAXHandler *sax;
xmlParserCtxtPtr ctxt;
if (ctx->ctxt == NULL) {
ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL);
if (ctxt == NULL) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"xmlCreatePushParserCtxt() failed");
return NGX_ERROR;
}
ctx->sax = ngx_palloc(r->pool, sizeof(xmlSAXHandler));
if (ctx->sax == NULL) {
return NGX_ERROR;
}
sax = ctxt->sax;
ngx_memcpy(ctx->sax, sax, sizeof(xmlSAXHandler));
sax->startDocument = ngx_http_xslt_sax_start_document;
sax->endDocument = ngx_http_xslt_sax_end_document;
sax->internalSubset = ngx_http_xslt_sax_internal_subset;
sax->externalSubset = ngx_http_xslt_sax_external_subset;
sax->entityDecl = ngx_http_xslt_sax_entity_decl;
sax->attributeDecl = ngx_http_xslt_sax_attribute_decl;
sax->elementDecl = ngx_http_xslt_sax_element_decl;
sax->notationDecl = ngx_http_xslt_sax_notation_decl;
sax->unparsedEntityDecl = ngx_http_xslt_sax_unparsed_entity_decl;
sax->setDocumentLocator = NULL;
sax->startElementNs = ngx_http_xslt_sax_start_element;
sax->endElementNs = ngx_http_xslt_sax_end_element;
sax->characters = ngx_http_xslt_sax_characters;
sax->ignorableWhitespace = ngx_http_xslt_sax_characters;
sax->cdataBlock = ngx_http_xslt_sax_cdata_block;
sax->getEntity = ngx_http_xslt_sax_get_entity;
sax->resolveEntity = ngx_http_xslt_sax_resolve_entity;
sax->getParameterEntity = ngx_http_xslt_sax_get_parameter_entity;
sax->reference = ngx_http_xslt_sax_reference;
sax->comment = ngx_http_xslt_sax_comment;
sax->processingInstruction = ngx_http_xslt_sax_processing_instruction;
sax->isStandalone = ngx_http_xslt_sax_is_standalone;
sax->hasInternalSubset = ngx_http_xslt_sax_has_internal_subset;
sax->hasExternalSubset = ngx_http_xslt_sax_has_external_subset;
sax->warning = NULL;
sax->error = ngx_http_xslt_sax_error;
sax->fatalError = ngx_http_xslt_sax_error;
ctxt->userData = ctx;
ctxt->replaceEntities = 1;
ctxt->loadsubset = 1;
ctx->ctxt = ctxt;
ctx->request = r;
}
err = xmlParseChunk(ctx->ctxt, (char *) b->pos, (int) (b->last - b->pos),
(b->last_buf) || (b->last_in_chain));
if (err == 0) {
b->pos = b->last;
return NGX_OK;
}
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"xmlParseChunk() failed, error:%d", err);
return NGX_ERROR;
}
static void
ngx_http_xslt_sax_start_document(void *data)
{
ngx_http_xslt_filter_ctx_t *ctx = data;
ctx->sax->startDocument(ctx->ctxt);
}
static void
ngx_http_xslt_sax_end_document(void *data)
{
ngx_http_xslt_filter_ctx_t *ctx = data;
ctx->sax->endDocument(ctx->ctxt);
}
static void
ngx_http_xslt_sax_internal_subset(void *data, const xmlChar *name,
const xmlChar *externalId, const xmlChar *systemId)
{
ngx_http_xslt_filter_ctx_t *ctx = data;
ctx->sax->internalSubset(ctx->ctxt, name, externalId, systemId);
}
static void
ngx_http_xslt_sax_external_subset(void *data, const xmlChar *name,
const xmlChar *externalId, const xmlChar *systemId)
{
ngx_http_xslt_filter_ctx_t *ctx = data;
xmlDocPtr doc;
xmlDtdPtr dtd;
ngx_http_request_t *r;
ngx_http_xslt_filter_loc_conf_t *conf;
r = ctx->request;
conf = ngx_http_get_module_loc_conf(r, ngx_http_xslt_filter_module);
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"xslt filter extSubset: \"%s\" \"%s\" \"%s\"",
name ? name : (xmlChar *) "",
externalId ? externalId : (xmlChar *) "",
systemId ? systemId : (xmlChar *) "");
doc = ctx->ctxt->myDoc;
#if (NGX_HTTP_XSLT_REUSE_DTD)
dtd = conf->dtd;
#else
dtd = xmlCopyDtd(conf->dtd);
if (dtd == NULL) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"xmlCopyDtd() failed");
return;
}
if (doc->children == NULL) {
xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
} else {
xmlAddPrevSibling(doc->children, (xmlNodePtr) dtd);
}
#endif
doc->extSubset = dtd;
}
static void
ngx_http_xslt_sax_entity_decl(void *data, const xmlChar *name, int type,
const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
{
ngx_http_xslt_filter_ctx_t *ctx = data;
ctx->sax->entityDecl(ctx->ctxt, name, type, publicId, systemId, content);
}
static void
ngx_http_xslt_sax_attribute_decl(void *data, const xmlChar *elem,
const xmlChar *fullname, int type, int def, const xmlChar *defaultValue,
xmlEnumerationPtr tree)
{
ngx_http_xslt_filter_ctx_t *ctx = data;
ctx->sax->attributeDecl(ctx->ctxt, elem, fullname, type, def, defaultValue,
tree);
}
static void
ngx_http_xslt_sax_element_decl(void *data, const xmlChar * name, int type,
xmlElementContentPtr content)
{
ngx_http_xslt_filter_ctx_t *ctx = data;
ctx->sax->elementDecl(ctx->ctxt, name, type, content);
}
static void
ngx_http_xslt_sax_notation_decl(void *data, const xmlChar *name,
const xmlChar *publicId, const xmlChar *systemId)
{
ngx_http_xslt_filter_ctx_t *ctx = data;
ctx->sax->notationDecl(ctx->ctxt, name, publicId, systemId);
}
static void
ngx_http_xslt_sax_unparsed_entity_decl(void *data, const xmlChar *name,
const xmlChar *publicId, const xmlChar *systemId,
const xmlChar *notationName)
{
ngx_http_xslt_filter_ctx_t *ctx = data;
ctx->sax->unparsedEntityDecl(ctx->ctxt, name, publicId, systemId,
notationName);
}
static void
ngx_http_xslt_sax_start_element(void *data, const xmlChar *localname,
const xmlChar *prefix, const xmlChar *URI, int nb_namespaces,
const xmlChar **namespaces, int nb_attributes, int nb_defaulted,
const xmlChar **attributes)
{
ngx_http_xslt_filter_ctx_t *ctx = data;
ctx->sax->startElementNs(ctx->ctxt, localname, prefix, URI, nb_namespaces,
namespaces, nb_attributes, nb_defaulted, attributes);
}
static void
ngx_http_xslt_sax_end_element(void *data,
const xmlChar * localname ATTRIBUTE_UNUSED,
const xmlChar * prefix ATTRIBUTE_UNUSED,
const xmlChar * URI ATTRIBUTE_UNUSED)
{
ngx_http_xslt_filter_ctx_t *ctx = data;
ctx->sax->endElementNs(ctx->ctxt, localname, prefix, URI);
}
static void
ngx_http_xslt_sax_characters(void *data, const xmlChar *p, int len)
{
ngx_http_xslt_filter_ctx_t *ctx = data;
ctx->sax->characters(ctx->ctxt, p, len);
}
static void
ngx_http_xslt_sax_cdata_block(void *data, const xmlChar *p, int len)
{
ngx_http_xslt_filter_ctx_t *ctx = data;
ctx->sax->cdataBlock(ctx->ctxt, p, len);
}
static xmlEntityPtr
ngx_http_xslt_sax_get_entity(void *data, const xmlChar *name)
{
ngx_http_xslt_filter_ctx_t *ctx = data;
return ctx->sax->getEntity(ctx->ctxt, name);
}
static xmlEntityPtr
ngx_http_xslt_sax_get_parameter_entity(void *data, const xmlChar *name)
{
ngx_http_xslt_filter_ctx_t *ctx = data;
return ctx->sax->getParameterEntity(ctx->ctxt, name);
}
static xmlParserInputPtr
ngx_http_xslt_sax_resolve_entity(void *data, const xmlChar *publicId,
const xmlChar *systemId)
{
ngx_http_xslt_filter_ctx_t *ctx = data;
return ctx->sax->resolveEntity(ctx->ctxt, publicId, systemId);
}
static void
ngx_http_xslt_sax_reference(void *data, const xmlChar *name)
{
ngx_http_xslt_filter_ctx_t *ctx = data;
ctx->sax->reference(ctx->ctxt, name);
}
static void
ngx_http_xslt_sax_comment(void *data, const xmlChar *value)
{
ngx_http_xslt_filter_ctx_t *ctx = data;
ctx->sax->comment(ctx->ctxt, value);
}
static void
ngx_http_xslt_sax_processing_instruction(void *data, const xmlChar *target,
const xmlChar *pidata)
{
ngx_http_xslt_filter_ctx_t *ctx = data;
ctx->sax->processingInstruction(ctx->ctxt, target, pidata);
}
static int
ngx_http_xslt_sax_is_standalone(void *data)
{
ngx_http_xslt_filter_ctx_t *ctx = data;
return ctx->sax->isStandalone(ctx->ctxt);
}
static int
ngx_http_xslt_sax_has_internal_subset(void *data)
{
ngx_http_xslt_filter_ctx_t *ctx = data;
return ctx->sax->hasInternalSubset(ctx->ctxt);
}
static int
ngx_http_xslt_sax_has_external_subset(void *data)
{
ngx_http_xslt_filter_ctx_t *ctx = data;
return ctx->sax->hasExternalSubset(ctx->ctxt);
}
static void ngx_cdecl
ngx_http_xslt_sax_error(void *data, const char *msg, ...)
{
ngx_http_xslt_filter_ctx_t *ctx = data;
size_t n;
va_list args;
u_char buf[NGX_MAX_ERROR_STR];
buf[0] = '\0';
va_start(args, msg);
n = (size_t) vsnprintf((char *) buf, NGX_MAX_ERROR_STR, msg, args);
va_end(args);
while (--n && (buf[n] == CR || buf[n] == LF)) { /* void */ }
ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0,
"libxml2 error: \"%*s\"", n + 1, buf);
}
static ngx_buf_t *
ngx_http_xslt_apply_stylesheet(ngx_http_request_t *r,
ngx_http_xslt_filter_ctx_t *ctx)
{
int len, rc, doc_type;
u_char *type, *encoding;
ngx_buf_t *b;
ngx_uint_t i;
xmlChar *buf;
xmlDocPtr doc, res;
ngx_http_xslt_sheet_t *sheet;
ngx_http_xslt_filter_loc_conf_t *conf;
conf = ngx_http_get_module_loc_conf(r, ngx_http_xslt_filter_module);
sheet = conf->sheets.elts;
doc = ctx->doc;
/* preallocate array for 4 params */
if (ngx_array_init(&ctx->params, r->pool, 4 * 2 + 1, sizeof(char *))
!= NGX_OK)
{
xmlFreeDoc(doc);
return NULL;
}
for (i = 0; i < conf->sheets.nelts; i++) {
if (ngx_http_xslt_params(r, ctx, &sheet[i].params) != NGX_OK) {
xmlFreeDoc(doc);
return NULL;
}
res = xsltApplyStylesheet(sheet[i].stylesheet, doc, ctx->params.elts);
xmlFreeDoc(doc);
if (res == NULL) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"xsltApplyStylesheet() failed");
return NULL;
}
doc = res;
/* reset array elements */
ctx->params.nelts = 0;
}
/* there must be at least one stylesheet */
if (r == r->main) {
type = ngx_http_xslt_content_type(sheet[i - 1].stylesheet);
} else {
type = NULL;
}
encoding = ngx_http_xslt_encoding(sheet[i - 1].stylesheet);
doc_type = doc->type;
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"xslt filter type: %d t:%s e:%s",
doc_type, type ? type : (u_char *) "(null)",
encoding ? encoding : (u_char *) "(null)");
rc = xsltSaveResultToString(&buf, &len, doc, sheet[i - 1].stylesheet);
xmlFreeDoc(doc);
if (rc != 0) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"xsltSaveResultToString() failed");
return NULL;
}
if (len == 0) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"xsltSaveResultToString() returned zero-length result");
return NULL;
}
b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
if (b == NULL) {
ngx_free(buf);
return NULL;
}
b->pos = buf;
b->last = buf + len;
b->memory = 1;
if (encoding) {
r->headers_out.charset.len = ngx_strlen(encoding);
r->headers_out.charset.data = encoding;
}
if (r != r->main) {
return b;
}
b->last_buf = 1;
if (type) {
len = ngx_strlen(type);
r->headers_out.content_type_len = len;
r->headers_out.content_type.len = len;
r->headers_out.content_type.data = type;
} else if (doc_type == XML_HTML_DOCUMENT_NODE) {
r->headers_out.content_type_len = sizeof("text/html") - 1;
r->headers_out.content_type.len = sizeof("text/html") - 1;
r->headers_out.content_type.data = (u_char *) "text/html";
}
r->headers_out.content_type_lowcase = NULL;
return b;
}
static ngx_int_t
ngx_http_xslt_params(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx,
ngx_array_t *params)
{
u_char *p, *last, *value, *dst, *src, **s;
size_t len;
ngx_uint_t i;
ngx_str_t string;
ngx_http_complex_value_t *param;
param = params->elts;
for (i = 0; i < params->nelts; i++) {
if (ngx_http_complex_value(r, ¶m[i], &string) != NGX_OK) {
return NGX_ERROR;
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"xslt filter param: \"%s\"", string.data);
p = string.data;
last = string.data + string.len - 1;
while (p && *p) {
value = p;
p = (u_char *) ngx_strchr(p, '=');
if (p == NULL) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"invalid libxslt parameter \"%s\"", value);
return NGX_ERROR;
}
*p++ = '\0';
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"xslt filter param name: \"%s\"", value);
s = ngx_array_push(&ctx->params);
if (s == NULL) {
return NGX_ERROR;
}
*s = value;
value = p;
p = (u_char *) ngx_strchr(p, ':');
if (p) {
len = p - value;
*p++ = '\0';
} else {
len = last - value;
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"xslt filter param value: \"%s\"", value);
dst = value;
src = value;
ngx_unescape_uri(&dst, &src, len, 0);
*dst = '\0';
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"xslt filter param unescaped: \"%s\"", value);
s = ngx_array_push(&ctx->params);
if (s == NULL) {
return NGX_ERROR;
}
*s = value;
}
}
s = ngx_array_push(&ctx->params);
if (s == NULL) {
return NGX_ERROR;
}
*s = NULL;
return NGX_OK;
}
static u_char *
ngx_http_xslt_content_type(xsltStylesheetPtr s)
{
u_char *type;
if (s->mediaType) {
return s->mediaType;
}
for (s = s->imports; s; s = s->next) {
type = ngx_http_xslt_content_type(s);
if (type) {
return type;
}
}
return NULL;
}
static u_char *
ngx_http_xslt_encoding(xsltStylesheetPtr s)
{
u_char *encoding;
if (s->encoding) {
return s->encoding;
}
for (s = s->imports; s; s = s->next) {
encoding = ngx_http_xslt_encoding(s);
if (encoding) {
return encoding;
}
}
return NULL;
}
static void
ngx_http_xslt_cleanup(void *data)
{
ngx_free(data);
}
static char *
ngx_http_xslt_entities(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_xslt_filter_loc_conf_t *xlcf = conf;
ngx_str_t *value;
ngx_uint_t i;
ngx_pool_cleanup_t *cln;
ngx_http_xslt_file_t *file;
ngx_http_xslt_filter_main_conf_t *xmcf;
if (xlcf->dtd) {
return "is duplicate";
}
value = cf->args->elts;
xmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_xslt_filter_module);
file = xmcf->dtd_files.elts;
for (i = 0; i < xmcf->dtd_files.nelts; i++) {
if (ngx_strcmp(file[i].name, &value[1].data) == 0) {
xlcf->dtd = file[i].data;
return NGX_CONF_OK;
}
}
cln = ngx_pool_cleanup_add(cf->pool, 0);
if (cln == NULL) {
return NGX_CONF_ERROR;
}
xlcf->dtd = xmlParseDTD(NULL, (xmlChar *) value[1].data);
if (xlcf->dtd == NULL) {
ngx_conf_log_error(NGX_LOG_ERR, cf, 0, "xmlParseDTD() failed");
return NGX_CONF_ERROR;
}
cln->handler = ngx_http_xslt_cleanup_dtd;
cln->data = xlcf->dtd;
file = ngx_array_push(&xmcf->dtd_files);
if (file == NULL) {
return NGX_CONF_ERROR;
}
file->name = value[1].data;
file->data = xlcf->dtd;
return NGX_CONF_OK;
}
static char *
ngx_http_xslt_stylesheet(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_xslt_filter_loc_conf_t *xlcf = conf;
ngx_str_t *value;
ngx_uint_t i, n;
ngx_pool_cleanup_t *cln;
ngx_http_xslt_file_t *file;
ngx_http_xslt_sheet_t *sheet;
ngx_http_complex_value_t *param;
ngx_http_compile_complex_value_t ccv;
ngx_http_xslt_filter_main_conf_t *xmcf;
value = cf->args->elts;
if (xlcf->sheets.elts == NULL) {
if (ngx_array_init(&xlcf->sheets, cf->pool, 1,
sizeof(ngx_http_xslt_sheet_t))
!= NGX_OK)
{
return NGX_CONF_ERROR;
}
}
sheet = ngx_array_push(&xlcf->sheets);
if (sheet == NULL) {
return NGX_CONF_ERROR;
}
ngx_memzero(sheet, sizeof(ngx_http_xslt_sheet_t));
if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) {
return NGX_CONF_ERROR;
}
xmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_xslt_filter_module);
file = xmcf->sheet_files.elts;
for (i = 0; i < xmcf->sheet_files.nelts; i++) {
if (ngx_strcmp(file[i].name, &value[1].data) == 0) {
sheet->stylesheet = file[i].data;
goto found;
}
}
cln = ngx_pool_cleanup_add(cf->pool, 0);
if (cln == NULL) {
return NGX_CONF_ERROR;
}
sheet->stylesheet = xsltParseStylesheetFile(value[1].data);
if (sheet->stylesheet == NULL) {
ngx_conf_log_error(NGX_LOG_ERR, cf, 0,
"xsltParseStylesheetFile(\"%s\") failed",
value[1].data);
return NGX_CONF_ERROR;
}
cln->handler = ngx_http_xslt_cleanup_stylesheet;
cln->data = sheet->stylesheet;
file = ngx_array_push(&xmcf->sheet_files);
if (file == NULL) {
return NGX_CONF_ERROR;
}
file->name = value[1].data;
file->data = sheet->stylesheet;
found:
n = cf->args->nelts;
if (n == 2) {
return NGX_CONF_OK;
}
if (ngx_array_init(&sheet->params, cf->pool, n - 2,
sizeof(ngx_http_complex_value_t))
!= NGX_OK)
{
return NGX_CONF_ERROR;
}
for (i = 2; i < n; i++) {
param = ngx_array_push(&sheet->params);
if (param == NULL) {
return NGX_CONF_ERROR;
}
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
ccv.cf = cf;
ccv.value = &value[i];
ccv.complex_value = param;
ccv.zero = 1;
if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
return NGX_CONF_ERROR;
}
}
return NGX_CONF_OK;
}
static void
ngx_http_xslt_cleanup_dtd(void *data)
{
xmlFreeDtd(data);
}
static void
ngx_http_xslt_cleanup_stylesheet(void *data)
{
xsltFreeStylesheet(data);
}
static void *
ngx_http_xslt_filter_create_main_conf(ngx_conf_t *cf)
{
ngx_http_xslt_filter_main_conf_t *conf;
conf = ngx_palloc(cf->pool, sizeof(ngx_http_xslt_filter_main_conf_t));
if (conf == NULL) {
return NULL;
}
if (ngx_array_init(&conf->dtd_files, cf->pool, 1,
sizeof(ngx_http_xslt_file_t))
!= NGX_OK)
{
return NULL;
}
if (ngx_array_init(&conf->sheet_files, cf->pool, 1,
sizeof(ngx_http_xslt_file_t))
!= NGX_OK)
{
return NULL;
}
return conf;
}
static void *
ngx_http_xslt_filter_create_conf(ngx_conf_t *cf)
{
ngx_http_xslt_filter_loc_conf_t *conf;
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_xslt_filter_loc_conf_t));
if (conf == NULL) {
return NULL;
}
/*
* set by ngx_pcalloc():
*
* conf->dtd = NULL;
* conf->sheets = { NULL };
* conf->types = { NULL };
* conf->types_keys = NULL;
*/
return conf;
}
static char *
ngx_http_xslt_filter_merge_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_xslt_filter_loc_conf_t *prev = parent;
ngx_http_xslt_filter_loc_conf_t *conf = child;
if (conf->dtd == NULL) {
conf->dtd = prev->dtd;
}
if (conf->sheets.nelts == 0) {
conf->sheets = prev->sheets;
}
if (ngx_http_merge_types(cf, conf->types_keys, &conf->types,
prev->types_keys, &prev->types,
ngx_http_xslt_default_types)
!= NGX_OK)
{
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
static ngx_int_t
ngx_http_xslt_filter_init(ngx_conf_t *cf)
{
xmlInitParser();
#if (NGX_HAVE_EXSLT)
exsltRegisterAll();
#endif
ngx_http_next_header_filter = ngx_http_top_header_filter;
ngx_http_top_header_filter = ngx_http_xslt_header_filter;
ngx_http_next_body_filter = ngx_http_top_body_filter;
ngx_http_top_body_filter = ngx_http_xslt_body_filter;
return NGX_OK;
}
static void
ngx_http_xslt_filter_exit(ngx_cycle_t *cycle)
{
xsltCleanupGlobals();
xmlCleanupParser();
}
nginx-0.7.68/src/http/modules/perl/ 000755 001750 001750 00000000000 11501744765 016221 5 ustar 00is is 000000 000000 nginx-0.7.68/src/http/modules/ngx_http_not_modified_filter_module.c 000644 001750 001750 00000006460 11331574432 024707 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#include
#include
#include
static ngx_int_t ngx_http_not_modified_filter_init(ngx_conf_t *cf);
static ngx_http_module_t ngx_http_not_modified_filter_module_ctx = {
NULL, /* preconfiguration */
ngx_http_not_modified_filter_init, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
NULL, /* create location configuration */
NULL /* merge location configuration */
};
ngx_module_t ngx_http_not_modified_filter_module = {
NGX_MODULE_V1,
&ngx_http_not_modified_filter_module_ctx, /* module context */
NULL, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
static ngx_int_t
ngx_http_not_modified_header_filter(ngx_http_request_t *r)
{
time_t ims;
ngx_http_core_loc_conf_t *clcf;
if (r->headers_out.status != NGX_HTTP_OK
|| r != r->main
|| r->headers_in.if_modified_since == NULL
|| r->headers_out.last_modified_time == -1)
{
return ngx_http_next_header_filter(r);
}
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (clcf->if_modified_since == NGX_HTTP_IMS_OFF) {
return ngx_http_next_header_filter(r);
}
ims = ngx_http_parse_time(r->headers_in.if_modified_since->value.data,
r->headers_in.if_modified_since->value.len);
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http ims:%d lm:%d", ims, r->headers_out.last_modified_time);
if (ims != r->headers_out.last_modified_time) {
if (clcf->if_modified_since == NGX_HTTP_IMS_EXACT
|| ims < r->headers_out.last_modified_time)
{
return ngx_http_next_header_filter(r);
}
}
r->headers_out.status = NGX_HTTP_NOT_MODIFIED;
r->headers_out.status_line.len = 0;
r->headers_out.content_type.len = 0;
ngx_http_clear_content_length(r);
ngx_http_clear_accept_ranges(r);
if (r->headers_out.content_encoding) {
r->headers_out.content_encoding->hash = 0;
r->headers_out.content_encoding = NULL;
}
return ngx_http_next_header_filter(r);
}
static ngx_int_t
ngx_http_not_modified_filter_init(ngx_conf_t *cf)
{
ngx_http_next_header_filter = ngx_http_top_header_filter;
ngx_http_top_header_filter = ngx_http_not_modified_header_filter;
return NGX_OK;
}
nginx-0.7.68/src/http/modules/ngx_http_access_module.c 000644 001750 001750 00000014451 11271343065 022141 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#include
#include
#include
typedef struct {
in_addr_t mask;
in_addr_t addr;
ngx_uint_t deny; /* unsigned deny:1; */
} ngx_http_access_rule_t;
typedef struct {
ngx_array_t *rules; /* array of ngx_http_access_rule_t */
} ngx_http_access_loc_conf_t;
static ngx_int_t ngx_http_access_handler(ngx_http_request_t *r);
static char *ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static void *ngx_http_access_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_access_merge_loc_conf(ngx_conf_t *cf,
void *parent, void *child);
static ngx_int_t ngx_http_access_init(ngx_conf_t *cf);
static ngx_command_t ngx_http_access_commands[] = {
{ ngx_string("allow"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF
|NGX_CONF_TAKE1,
ngx_http_access_rule,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("deny"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF
|NGX_CONF_TAKE1,
ngx_http_access_rule,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
ngx_null_command
};
static ngx_http_module_t ngx_http_access_module_ctx = {
NULL, /* preconfiguration */
ngx_http_access_init, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
ngx_http_access_create_loc_conf, /* create location configuration */
ngx_http_access_merge_loc_conf /* merge location configuration */
};
ngx_module_t ngx_http_access_module = {
NGX_MODULE_V1,
&ngx_http_access_module_ctx, /* module context */
ngx_http_access_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_int_t
ngx_http_access_handler(ngx_http_request_t *r)
{
ngx_uint_t i;
struct sockaddr_in *sin;
ngx_http_access_rule_t *rule;
ngx_http_core_loc_conf_t *clcf;
ngx_http_access_loc_conf_t *alcf;
alcf = ngx_http_get_module_loc_conf(r, ngx_http_access_module);
if (alcf->rules == NULL) {
return NGX_DECLINED;
}
/* AF_INET only */
if (r->connection->sockaddr->sa_family != AF_INET) {
return NGX_DECLINED;
}
sin = (struct sockaddr_in *) r->connection->sockaddr;
rule = alcf->rules->elts;
for (i = 0; i < alcf->rules->nelts; i++) {
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"access: %08XD %08XD %08XD",
sin->sin_addr.s_addr, rule[i].mask, rule[i].addr);
if ((sin->sin_addr.s_addr & rule[i].mask) == rule[i].addr) {
if (rule[i].deny) {
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (clcf->satisfy == NGX_HTTP_SATISFY_ALL) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"access forbidden by rule");
}
return NGX_HTTP_FORBIDDEN;
}
return NGX_OK;
}
}
return NGX_DECLINED;
}
static char *
ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_access_loc_conf_t *alcf = conf;
ngx_int_t rc;
ngx_str_t *value;
ngx_cidr_t cidr;
ngx_http_access_rule_t *rule;
if (alcf->rules == NULL) {
alcf->rules = ngx_array_create(cf->pool, 4,
sizeof(ngx_http_access_rule_t));
if (alcf->rules == NULL) {
return NGX_CONF_ERROR;
}
}
rule = ngx_array_push(alcf->rules);
if (rule == NULL) {
return NGX_CONF_ERROR;
}
value = cf->args->elts;
rule->deny = (value[0].data[0] == 'd') ? 1 : 0;
if (value[1].len == 3 && ngx_strcmp(value[1].data, "all") == 0) {
rule->mask = 0;
rule->addr = 0;
return NGX_CONF_OK;
}
rc = ngx_ptocidr(&value[1], &cidr);
if (rc == NGX_ERROR) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"",
&value[1]);
return NGX_CONF_ERROR;
}
if (cidr.family != AF_INET) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"allow\" supports IPv4 only");
return NGX_CONF_ERROR;
}
if (rc == NGX_DONE) {
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
"low address bits of %V are meaningless", &value[1]);
}
rule->mask = cidr.u.in.mask;
rule->addr = cidr.u.in.addr;
return NGX_CONF_OK;
}
static void *
ngx_http_access_create_loc_conf(ngx_conf_t *cf)
{
ngx_http_access_loc_conf_t *conf;
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_access_loc_conf_t));
if (conf == NULL) {
return NULL;
}
return conf;
}
static char *
ngx_http_access_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_access_loc_conf_t *prev = parent;
ngx_http_access_loc_conf_t *conf = child;
if (conf->rules == NULL) {
conf->rules = prev->rules;
}
return NGX_CONF_OK;
}
static ngx_int_t
ngx_http_access_init(ngx_conf_t *cf)
{
ngx_http_handler_pt *h;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
if (h == NULL) {
return NGX_ERROR;
}
*h = ngx_http_access_handler;
return NGX_OK;
}
nginx-0.7.68/src/http/modules/ngx_http_ssl_module.c 000644 001750 001750 00000043024 11331563624 021501 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#include
#include
#include
typedef ngx_int_t (*ngx_ssl_variable_handler_pt)(ngx_connection_t *c,
ngx_pool_t *pool, ngx_str_t *s);
#define NGX_DEFAULT_CIPHERS "HIGH:!ADH:!MD5"
static ngx_int_t ngx_http_ssl_static_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_ssl_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_ssl_add_variables(ngx_conf_t *cf);
static void *ngx_http_ssl_create_srv_conf(ngx_conf_t *cf);
static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf,
void *parent, void *child);
static char *ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static ngx_conf_bitmask_t ngx_http_ssl_protocols[] = {
{ ngx_string("SSLv2"), NGX_SSL_SSLv2 },
{ ngx_string("SSLv3"), NGX_SSL_SSLv3 },
{ ngx_string("TLSv1"), NGX_SSL_TLSv1 },
{ ngx_null_string, 0 }
};
static ngx_conf_enum_t ngx_http_ssl_verify[] = {
{ ngx_string("off"), 0 },
{ ngx_string("on"), 1 },
{ ngx_string("optional"), 2 },
{ ngx_null_string, 0 }
};
static ngx_command_t ngx_http_ssl_commands[] = {
{ ngx_string("ssl"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
ngx_http_ssl_enable,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_ssl_srv_conf_t, enable),
NULL },
{ ngx_string("ssl_certificate"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_ssl_srv_conf_t, certificate),
NULL },
{ ngx_string("ssl_certificate_key"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_ssl_srv_conf_t, certificate_key),
NULL },
{ ngx_string("ssl_dhparam"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_ssl_srv_conf_t, dhparam),
NULL },
{ ngx_string("ssl_protocols"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_1MORE,
ngx_conf_set_bitmask_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_ssl_srv_conf_t, protocols),
&ngx_http_ssl_protocols },
{ ngx_string("ssl_ciphers"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_ssl_srv_conf_t, ciphers),
NULL },
{ ngx_string("ssl_verify_client"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
ngx_conf_set_enum_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_ssl_srv_conf_t, verify),
&ngx_http_ssl_verify },
{ ngx_string("ssl_verify_depth"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_1MORE,
ngx_conf_set_num_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_ssl_srv_conf_t, verify_depth),
NULL },
{ ngx_string("ssl_client_certificate"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_ssl_srv_conf_t, client_certificate),
NULL },
{ ngx_string("ssl_prefer_server_ciphers"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_ssl_srv_conf_t, prefer_server_ciphers),
NULL },
{ ngx_string("ssl_session_cache"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE12,
ngx_http_ssl_session_cache,
NGX_HTTP_SRV_CONF_OFFSET,
0,
NULL },
{ ngx_string("ssl_session_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_sec_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_ssl_srv_conf_t, session_timeout),
NULL },
{ ngx_string("ssl_crl"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_ssl_srv_conf_t, crl),
NULL },
ngx_null_command
};
static ngx_http_module_t ngx_http_ssl_module_ctx = {
ngx_http_ssl_add_variables, /* preconfiguration */
NULL, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
ngx_http_ssl_create_srv_conf, /* create server configuration */
ngx_http_ssl_merge_srv_conf, /* merge server configuration */
NULL, /* create location configuration */
NULL /* merge location configuration */
};
ngx_module_t ngx_http_ssl_module = {
NGX_MODULE_V1,
&ngx_http_ssl_module_ctx, /* module context */
ngx_http_ssl_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_http_variable_t ngx_http_ssl_vars[] = {
{ ngx_string("ssl_protocol"), NULL, ngx_http_ssl_static_variable,
(uintptr_t) ngx_ssl_get_protocol, NGX_HTTP_VAR_CHANGEABLE, 0 },
{ ngx_string("ssl_cipher"), NULL, ngx_http_ssl_static_variable,
(uintptr_t) ngx_ssl_get_cipher_name, NGX_HTTP_VAR_CHANGEABLE, 0 },
{ ngx_string("ssl_session_id"), NULL, ngx_http_ssl_variable,
(uintptr_t) ngx_ssl_get_session_id, NGX_HTTP_VAR_CHANGEABLE, 0 },
{ ngx_string("ssl_client_cert"), NULL, ngx_http_ssl_variable,
(uintptr_t) ngx_ssl_get_certificate, NGX_HTTP_VAR_CHANGEABLE, 0 },
{ ngx_string("ssl_client_raw_cert"), NULL, ngx_http_ssl_variable,
(uintptr_t) ngx_ssl_get_raw_certificate,
NGX_HTTP_VAR_CHANGEABLE, 0 },
{ ngx_string("ssl_client_s_dn"), NULL, ngx_http_ssl_variable,
(uintptr_t) ngx_ssl_get_subject_dn, NGX_HTTP_VAR_CHANGEABLE, 0 },
{ ngx_string("ssl_client_i_dn"), NULL, ngx_http_ssl_variable,
(uintptr_t) ngx_ssl_get_issuer_dn, NGX_HTTP_VAR_CHANGEABLE, 0 },
{ ngx_string("ssl_client_serial"), NULL, ngx_http_ssl_variable,
(uintptr_t) ngx_ssl_get_serial_number, NGX_HTTP_VAR_CHANGEABLE, 0 },
{ ngx_string("ssl_client_verify"), NULL, ngx_http_ssl_variable,
(uintptr_t) ngx_ssl_get_client_verify, NGX_HTTP_VAR_CHANGEABLE, 0 },
{ ngx_null_string, NULL, NULL, 0, 0, 0 }
};
static ngx_str_t ngx_http_ssl_sess_id_ctx = ngx_string("HTTP");
static ngx_int_t
ngx_http_ssl_static_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
ngx_ssl_variable_handler_pt handler = (ngx_ssl_variable_handler_pt) data;
size_t len;
ngx_str_t s;
if (r->connection->ssl) {
(void) handler(r->connection, NULL, &s);
v->data = s.data;
for (len = 0; v->data[len]; len++) { /* void */ }
v->len = len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
return NGX_OK;
}
v->not_found = 1;
return NGX_OK;
}
static ngx_int_t
ngx_http_ssl_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
uintptr_t data)
{
ngx_ssl_variable_handler_pt handler = (ngx_ssl_variable_handler_pt) data;
ngx_str_t s;
if (r->connection->ssl) {
if (handler(r->connection, r->pool, &s) != NGX_OK) {
return NGX_ERROR;
}
v->len = s.len;
v->data = s.data;
if (v->len) {
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
return NGX_OK;
}
}
v->not_found = 1;
return NGX_OK;
}
static ngx_int_t
ngx_http_ssl_add_variables(ngx_conf_t *cf)
{
ngx_http_variable_t *var, *v;
for (v = ngx_http_ssl_vars; v->name.len; v++) {
var = ngx_http_add_variable(cf, &v->name, v->flags);
if (var == NULL) {
return NGX_ERROR;
}
var->get_handler = v->get_handler;
var->data = v->data;
}
return NGX_OK;
}
static void *
ngx_http_ssl_create_srv_conf(ngx_conf_t *cf)
{
ngx_http_ssl_srv_conf_t *sscf;
sscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssl_srv_conf_t));
if (sscf == NULL) {
return NULL;
}
/*
* set by ngx_pcalloc():
*
* sscf->protocols = 0;
* sscf->certificate = { 0, NULL };
* sscf->certificate_key = { 0, NULL };
* sscf->dhparam = { 0, NULL };
* sscf->client_certificate = { 0, NULL };
* sscf->crl = { 0, NULL };
* sscf->ciphers.len = 0;
* sscf->ciphers.data = NULL;
* sscf->shm_zone = NULL;
*/
sscf->enable = NGX_CONF_UNSET;
sscf->prefer_server_ciphers = NGX_CONF_UNSET;
sscf->verify = NGX_CONF_UNSET_UINT;
sscf->verify_depth = NGX_CONF_UNSET_UINT;
sscf->builtin_session_cache = NGX_CONF_UNSET;
sscf->session_timeout = NGX_CONF_UNSET;
return sscf;
}
static char *
ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_ssl_srv_conf_t *prev = parent;
ngx_http_ssl_srv_conf_t *conf = child;
ngx_pool_cleanup_t *cln;
ngx_conf_merge_value(conf->enable, prev->enable, 0);
ngx_conf_merge_value(conf->session_timeout,
prev->session_timeout, 300);
ngx_conf_merge_value(conf->prefer_server_ciphers,
prev->prefer_server_ciphers, 0);
ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols,
(NGX_CONF_BITMASK_SET|NGX_SSL_SSLv3|NGX_SSL_TLSv1));
ngx_conf_merge_uint_value(conf->verify, prev->verify, 0);
ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1);
ngx_conf_merge_str_value(conf->certificate, prev->certificate, "");
ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, "");
ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, "");
ngx_conf_merge_str_value(conf->client_certificate, prev->client_certificate,
"");
ngx_conf_merge_str_value(conf->crl, prev->crl, "");
ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS);
conf->ssl.log = cf->log;
if (conf->enable) {
if (conf->certificate.len == 0) {
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"no \"ssl_certificate\" is defined for "
"the \"ssl\" directive in %s:%ui",
conf->file, conf->line);
return NGX_CONF_ERROR;
}
if (conf->certificate_key.len == 0) {
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"no \"ssl_certificate_key\" is defined for "
"the \"ssl\" directive in %s:%ui",
conf->file, conf->line);
return NGX_CONF_ERROR;
}
} else {
if (conf->certificate.len == 0) {
return NGX_CONF_OK;
}
if (conf->certificate_key.len == 0) {
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"no \"ssl_certificate_key\" is defined "
"for certificate \"%V\"", &conf->certificate);
return NGX_CONF_ERROR;
}
}
if (ngx_ssl_create(&conf->ssl, conf->protocols, conf) != NGX_OK) {
return NGX_CONF_ERROR;
}
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
if (SSL_CTX_set_tlsext_servername_callback(conf->ssl.ctx,
ngx_http_ssl_servername)
== 0)
{
ngx_log_error(NGX_LOG_WARN, cf->log, 0,
"nginx was built with SNI support, however, now it is linked "
"dynamically to an OpenSSL library which has no tlsext support, "
"therefore SNI is not available");
}
#endif
cln = ngx_pool_cleanup_add(cf->pool, 0);
if (cln == NULL) {
return NGX_CONF_ERROR;
}
cln->handler = ngx_ssl_cleanup_ctx;
cln->data = &conf->ssl;
if (ngx_ssl_certificate(cf, &conf->ssl, &conf->certificate,
&conf->certificate_key)
!= NGX_OK)
{
return NGX_CONF_ERROR;
}
if (SSL_CTX_set_cipher_list(conf->ssl.ctx,
(const char *) conf->ciphers.data)
== 0)
{
ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
"SSL_CTX_set_cipher_list(\"%V\") failed",
&conf->ciphers);
}
if (conf->verify) {
if (conf->client_certificate.len == 0) {
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"no ssl_client_certificate for ssl_client_verify");
return NGX_CONF_ERROR;
}
if (ngx_ssl_client_certificate(cf, &conf->ssl,
&conf->client_certificate,
conf->verify_depth)
!= NGX_OK)
{
return NGX_CONF_ERROR;
}
if (ngx_ssl_crl(cf, &conf->ssl, &conf->crl) != NGX_OK) {
return NGX_CONF_ERROR;
}
}
if (conf->prefer_server_ciphers) {
SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
}
/* a temporary 512-bit RSA key is required for export versions of MSIE */
if (ngx_ssl_generate_rsa512_key(&conf->ssl) != NGX_OK) {
return NGX_CONF_ERROR;
}
if (ngx_ssl_dhparam(cf, &conf->ssl, &conf->dhparam) != NGX_OK) {
return NGX_CONF_ERROR;
}
ngx_conf_merge_value(conf->builtin_session_cache,
prev->builtin_session_cache, NGX_SSL_NONE_SCACHE);
if (conf->shm_zone == NULL) {
conf->shm_zone = prev->shm_zone;
}
if (ngx_ssl_session_cache(&conf->ssl, &ngx_http_ssl_sess_id_ctx,
conf->builtin_session_cache,
conf->shm_zone, conf->session_timeout)
!= NGX_OK)
{
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
static char *
ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_ssl_srv_conf_t *sscf = conf;
char *rv;
rv = ngx_conf_set_flag_slot(cf, cmd, conf);
if (rv != NGX_CONF_OK) {
return rv;
}
sscf->file = cf->conf_file->file.name.data;
sscf->line = cf->conf_file->line;
return NGX_CONF_OK;
}
static char *
ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_ssl_srv_conf_t *sscf = conf;
size_t len;
ngx_str_t *value, name, size;
ngx_int_t n;
ngx_uint_t i, j;
value = cf->args->elts;
for (i = 1; i < cf->args->nelts; i++) {
if (ngx_strcmp(value[i].data, "off") == 0) {
sscf->builtin_session_cache = NGX_SSL_NO_SCACHE;
continue;
}
if (ngx_strcmp(value[i].data, "none") == 0) {
sscf->builtin_session_cache = NGX_SSL_NONE_SCACHE;
continue;
}
if (ngx_strcmp(value[i].data, "builtin") == 0) {
sscf->builtin_session_cache = NGX_SSL_DFLT_BUILTIN_SCACHE;
continue;
}
if (value[i].len > sizeof("builtin:") - 1
&& ngx_strncmp(value[i].data, "builtin:", sizeof("builtin:") - 1)
== 0)
{
n = ngx_atoi(value[i].data + sizeof("builtin:") - 1,
value[i].len - (sizeof("builtin:") - 1));
if (n == NGX_ERROR) {
goto invalid;
}
sscf->builtin_session_cache = n;
continue;
}
if (value[i].len > sizeof("shared:") - 1
&& ngx_strncmp(value[i].data, "shared:", sizeof("shared:") - 1)
== 0)
{
len = 0;
for (j = sizeof("shared:") - 1; j < value[i].len; j++) {
if (value[i].data[j] == ':') {
value[i].data[j] = '\0';
break;
}
len++;
}
if (len == 0) {
goto invalid;
}
name.len = len;
name.data = value[i].data + sizeof("shared:") - 1;
size.len = value[i].len - j - 1;
size.data = name.data + len + 1;
n = ngx_parse_size(&size);
if (n == NGX_ERROR) {
goto invalid;
}
if (n < (ngx_int_t) (8 * ngx_pagesize)) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"session cache \"%V\" is too small",
&value[i]);
return NGX_CONF_ERROR;
}
sscf->shm_zone = ngx_shared_memory_add(cf, &name, n,
&ngx_http_ssl_module);
if (sscf->shm_zone == NULL) {
return NGX_CONF_ERROR;
}
continue;
}
goto invalid;
}
if (sscf->shm_zone && sscf->builtin_session_cache == NGX_CONF_UNSET) {
sscf->builtin_session_cache = NGX_SSL_NO_BUILTIN_SCACHE;
}
return NGX_CONF_OK;
invalid:
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid session cache \"%V\"", &value[i]);
return NGX_CONF_ERROR;
}
nginx-0.7.68/src/http/modules/ngx_http_ssi_filter_module.c 000644 001750 001750 00000225107 11501743305 023042 0 ustar 00is is 000000 000000
/*
* Copyright (C) Igor Sysoev
*/
#include
#include
#include
#define NGX_HTTP_SSI_ERROR 1
#define NGX_HTTP_SSI_DATE_LEN 2048
#define NGX_HTTP_SSI_ADD_PREFIX 1
#define NGX_HTTP_SSI_ADD_ZERO 2
typedef struct {
ngx_flag_t enable;
ngx_flag_t silent_errors;
ngx_flag_t ignore_recycled_buffers;
ngx_hash_t types;
size_t min_file_chunk;
size_t value_len;
ngx_array_t *types_keys;
} ngx_http_ssi_loc_conf_t;
typedef struct {
ngx_str_t name;
ngx_uint_t key;
ngx_str_t value;
} ngx_http_ssi_var_t;
typedef struct {
ngx_str_t name;
ngx_chain_t *bufs;
ngx_uint_t count;
} ngx_http_ssi_block_t;
typedef enum {
ssi_start_state = 0,
ssi_tag_state,
ssi_comment0_state,
ssi_comment1_state,
ssi_sharp_state,
ssi_precommand_state,
ssi_command_state,
ssi_preparam_state,
ssi_param_state,
ssi_preequal_state,
ssi_prevalue_state,
ssi_double_quoted_value_state,
ssi_quoted_value_state,
ssi_quoted_symbol_state,
ssi_postparam_state,
ssi_comment_end0_state,
ssi_comment_end1_state,
ssi_error_state,
ssi_error_end0_state,
ssi_error_end1_state
} ngx_http_ssi_state_e;
static ngx_int_t ngx_http_ssi_output(ngx_http_request_t *r,
ngx_http_ssi_ctx_t *ctx);
static void ngx_http_ssi_buffered(ngx_http_request_t *r,
ngx_http_ssi_ctx_t *ctx);
static ngx_int_t ngx_http_ssi_parse(ngx_http_request_t *r,
ngx_http_ssi_ctx_t *ctx);
static ngx_str_t *ngx_http_ssi_get_variable(ngx_http_request_t *r,
ngx_str_t *name, ngx_uint_t key);
static ngx_int_t ngx_http_ssi_evaluate_string(ngx_http_request_t *r,
ngx_http_ssi_ctx_t *ctx, ngx_str_t *text, ngx_uint_t flags);
static ngx_int_t ngx_http_ssi_include(ngx_http_request_t *r,
ngx_http_ssi_ctx_t *ctx, ngx_str_t **params);
static ngx_int_t ngx_http_ssi_stub_output(ngx_http_request_t *r, void *data,
ngx_int_t rc);
static ngx_int_t ngx_http_ssi_set_variable(ngx_http_request_t *r, void *data,
ngx_int_t rc);
static ngx_int_t ngx_http_ssi_echo(ngx_http_request_t *r,
ngx_http_ssi_ctx_t *ctx, ngx_str_t **params);
static ngx_int_t ngx_http_ssi_config(ngx_http_request_t *r,
ngx_http_ssi_ctx_t *ctx, ngx_str_t **params);
static ngx_int_t ngx_http_ssi_set(ngx_http_request_t *r,
ngx_http_ssi_ctx_t *ctx, ngx_str_t **params);
static ngx_int_t ngx_http_ssi_if(ngx_http_request_t *r,
ngx_http_ssi_ctx_t *ctx, ngx_str_t **params);
static ngx_int_t ngx_http_ssi_else(ngx_http_request_t *r,
ngx_http_ssi_ctx_t *ctx, ngx_str_t **params);
static ngx_int_t ngx_http_ssi_endif(ngx_http_request_t *r,
ngx_http_ssi_ctx_t *ctx, ngx_str_t **params);
static ngx_int_t ngx_http_ssi_block(ngx_http_request_t *r,
ngx_http_ssi_ctx_t *ctx, ngx_str_t **params);
static ngx_int_t ngx_http_ssi_endblock(ngx_http_request_t *r,
ngx_http_ssi_ctx_t *ctx, ngx_str_t **params);
static ngx_int_t ngx_http_ssi_date_gmt_local_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t gmt);
static ngx_int_t ngx_http_ssi_preconfiguration(ngx_conf_t *cf);
static void *ngx_http_ssi_create_main_conf(ngx_conf_t *cf);
static char *ngx_http_ssi_init_main_conf(ngx_conf_t *cf, void *conf);
static void *ngx_http_ssi_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_ssi_merge_loc_conf(ngx_conf_t *cf,
void *parent, void *child);
static ngx_int_t ngx_http_ssi_filter_init(ngx_conf_t *cf);
static ngx_command_t ngx_http_ssi_filter_commands[] = {
{ ngx_string("ssi"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_ssi_loc_conf_t, enable),
NULL },
{ ngx_string("ssi_silent_errors"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_ssi_loc_conf_t, silent_errors),
NULL },
{ ngx_string("ssi_ignore_recycled_buffers"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_ssi_loc_conf_t, ignore_recycled_buffers),
NULL },
{ ngx_string("ssi_min_file_chunk"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_size_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_ssi_loc_conf_t, min_file_chunk),
NULL },
{ ngx_string("ssi_value_length"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_size_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_ssi_loc_conf_t, value_len),
NULL },
{ ngx_string("ssi_types"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
ngx_http_types_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_ssi_loc_conf_t, types_keys),
&ngx_http_html_default_types[0] },
ngx_null_command
};
static ngx_http_module_t ngx_http_ssi_filter_module_ctx = {
ngx_http_ssi_preconfiguration, /* preconfiguration */
ngx_http_ssi_filter_init, /* postconfiguration */
ngx_http_ssi_create_main_conf, /* create main configuration */
ngx_http_ssi_init_main_conf, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
ngx_http_ssi_create_loc_conf, /* create location configuration */
ngx_http_ssi_merge_loc_conf /* merge location configuration */
};
ngx_module_t ngx_http_ssi_filter_module = {
NGX_MODULE_V1,
&ngx_http_ssi_filter_module_ctx, /* module context */
ngx_http_ssi_filter_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
static u_char ngx_http_ssi_string[] = "