# HG changeset patch # User Igor Sysoev # Date 1097507223 0 # Node ID 23fb87bddda14ce9faec90f774085634106aded4 # Parent f40362e47689b7f61eb5fe4e6a40b22efc8c91cb nginx-0.1.1-RELEASE import *) Feature: the gzip_types directive. *) Feature: the tcp_nodelay directive. *) Feature: the send_lowat directive is working not only on OSes that support kqueue NOTE_LOWAT, but also on OSes that support SO_SNDLOWAT. *) Feature: the setproctitle() emulation for Linux and Solaris. *) Bugfix: the "Location" header rewrite bug fixed while the proxying. *) Bugfix: the ngx_http_chunked_module module may get caught in an endless loop. *) Bugfix: the /dev/poll module bugs fixed. *) Bugfix: the responses were corrupted when the temporary files were used while the proxying. *) Bugfix: the unescaped requests were passed to the backend. *) Bugfix: while the build configuration on Linux 2.4 the --with-poll_module parameter was required. diff --git a/auto/init b/auto/init --- a/auto/init +++ b/auto/init @@ -36,3 +36,29 @@ else ngx_n= ngx_c='\c' fi + + + +if test ! -f Makefile; then + + cat << END > Makefile + +build: + \$(MAKE) -f $OBJS/Makefile + +install: + \$(MAKE) -f $OBJS/Makefile install + +clean: + rm -rf Makefile $OBJS + +upgrade: + $SBIN_PATH -t + kill -USR2 \`cat $PID_PATH\` + sleep 1 + test -f $PID_PATH.newbin + kill -WINCH \`cat $PID_PATH\` + +END + +fi diff --git a/auto/install b/auto/install --- a/auto/install +++ b/auto/install @@ -38,28 +38,3 @@ if [ ".$ERROR_LOG_PATH" != "." ]; then END fi - - -if test ! -f Makefile; then - - cat << END > Makefile - -build: - \$(MAKE) -f $OBJS/Makefile - -install: - \$(MAKE) -f $OBJS/Makefile install - -clean: - rm -rf Makefile $OBJS - -upgrade: - $SBIN_PATH -t - kill -USR2 \`cat $PID_PATH\` - sleep 1 - test -f $PID_PATH.newbin - kill -WINCH \`cat $PID_PATH\` - -END - -fi diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -138,6 +138,7 @@ UNIX_SRCS="$CORE_SRCS $EVENT_SRCS \ src/os/unix/ngx_shared.c \ src/os/unix/ngx_process.c \ src/os/unix/ngx_daemon.c \ + src/os/unix/ngx_setproctitle.c \ src/os/unix/ngx_posix_init.c \ src/os/unix/ngx_process_cycle.c" diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml --- a/docs/xml/nginx/changes.xml +++ b/docs/xml/nginx/changes.xml @@ -1,979 +1,123 @@ - - - - - + + - + - - -mod_accel не определял и не патчил EAPI, если собирался вместе -с mod_ssl-2.8.13-1.3.27+. - - -mod_accel did not detect and patch broken EAPI when built with -mod_ssl-2.8.13-1.3.27+. - - + + -при проксировании с помощью модуля mod_rewrite mod_accel -поддерживает переписывание заголовков "Location" и "Refresh" с помощью -этого же модуля и -для этого -указывает имя бэкенда в переменной -среды "ACCEL_REWRITE". +директива gzip_types. -when request is proxied with the help of mod_rewrite module mod_accel -set the backend name in the "ACCEL_RWRITE" enviroment variable and -supports the rewriting of "Location" and "Refresh" headers with the help of -mod_rewrite module. +the gzip_types directive. -mod_accel переписывает содержимое заголовка "Destination", -если имя хоста в этом заголовке совпадает с содержимым -заголовка "Host", или же если URI не абсолютный. - - -mod_accel now rewrites "Destination" header if the host name in this header -is as in "Host" header or if the destination URI is not absolute. - - - - - -mod_accel зацикливался в случае, если клиент запрашивал byte range, -а бэкенд не передавал кэшируемый ответ полностью. - - -mod_accel went into an endless loop if the client requested the byte range -and the backend did not send the full cachable response. - - - - - - - - - - -сделана проверка и патч для EAPI из mod_ssl-2.8.13-1.3.27+. - - -broken EAPI from mod_ssl-2.8.13-1.3.27+ now is checked and patched. - - - - - -директива AccelSetXURI не работала. - - -AccelSetXURI directive did not work. - - - - - - - - - - -бэкенды, использующие named-based вирутальные хосты, не были доступны -через _the_same_host_. - - -backends that use named-based virtual hosts can not be accessed via -_the_same_host_. - - - - - - - - - - -AccelReverse работает и для запросов, проксированных через AccelPass. +директива tcp_nodelay. -AccelReverse works for AccelPass'ed requests too. - - - - - -action remove в accel-cachemgr не работал с URL, в которых символы -кодировались в виде %XX. - - -accel-cachemgr's remove action did not work with URLs with characters -endcoded as %XX. - - - - - - - - - - -флаги дополнительных модулей R, Q и F залипали в кэше до тех пор, пока -файл не удалялся из кэша. - - -additional modules R, Q and F flags were sticky until cache file was -not removed from cache. - - - - - -не работал action remove в accel-cachemgr. - - -accel-cachemgr's remove action did not work. - - - - - -давно неменяемые документы не кэшировались, если для кэширования -использовался AccelLastModifiedFactor. - - -long invariable documents were not cached if AccelLastModifiedFactor -was used to choose cache time. - - - - - - - - - - -если в URL, созданным модулем mod_rewrite, находились -символы в виде %XX, -то они передавались бэкенду в раскрытом виде. - - -if mod_rewrite created URL contained characters encoded as %XX then -they was passed to backend unescaped. - - - - - -ключ -DMOD_REWRITE_DISABLE_TO_PROXY_SUBREQ. - - --DMOD_REWRITE_DISABLE_TO_PROXY_SUBREQ switch was added. +the tcp_nodelay directive. -переменная среды ACCEL_NOCACHE. +директива send_lowat работает не только на платформах, поддерживающих +kqueue NOTE_LOWAT, но и на всех, поддерживающих SO_SNDLOWAT. -ACCEL_NOCACHE enviroment variable was added. - - - - - - - - - - -в директиве FreezeStart. - - -in FreezeStart directive. +the send_lowat directive is working not only on OSes that support +kqueue NOTE_LOWAT, but also on OSes that support SO_SNDLOWAT. -директива AccelCacheSetCookie. +эмуляция setproctitle() для Linux и Solaris. -AccelCacheSetCookie directive. - - - - - -AccelCacheRoot не понимал параметры в кавычках. - - -AccelCacheRoot did not understand quoted parameters. +the setproctitle() emulation for Linux and Solaris. -модуль mod_freeze не замораживал схемы, если они указаны в -одинарных кавычках. +ошибка при переписывании заголовка "Location" при проксировании. -mod_freeze did not freeze schemas if they was quoted in apostrophes. +the "Location" header rewrite bug fixed while the proxing. -модуль mod_freeze не замораживал тэг style, параметр style и -схему behavior:. +ошибка в модуле ngx_http_chunked_module, приводившая к зацикливанию. -mod_freeze did not freeze style tag, style parameter and behavior: schema. +the ngx_http_chunked_module module bug fixed that caused an endless loop. -последовательность вида <<script не замораживалась модулем mod_freeze. - - -<<script sequence was not frozen by mod_freeze. - - - - - -оптимизирован алгоритм поиска в модуле mod_freeze. - - -mod_freeze's search algorithm was optimized. - - - - - - - - - - -флаги дополнительных модулей R, Q и F не выставлялись, -если запрос был некэшируемым. - - -additional modules R, Q and F flags were not set -if request was not cachable. - - - - - -директива AccelPassXAccel. - - -AccelPassXAccel directive. - - - - - -модуль mod_freeze. - - -mod_freeze module. - - - - - - - - - - -директива "AccelPassServer off" в Apache-1.3.26 вообще не выдавала -заголовок "Server". +ошибки в модуле /dev/poll. -"AccelPassServer off" did not send any "Server" header in Apache-1.3.26. - - - - - -документация по mod_accel копируется в /manual/mod/mod_accel.html. - - -mod_accel Russian documentation is copied in /manual/mod/mod_accel.html. - - - - - - - - - - -параметр MP в директиве AccelPass работал некорректно, если также -был задал параметр PH или использовалось специальное имя _the_same_host_. - - -AccelPass MP parameter was worked incorrectly if used with PH parameter -or with special _the_same_host_ host name. - - - - - - - - - - -во время плавного (graceful) рестарта мог произойти segmentation fault -в основном процессе, если все рабочие слоты были заняты. - - -segmentation fault can occur in main process while graceful restart -when all child slots were busy. - - - - - - - - - - -директивы AccelRetry5XX и AccelSetXURI. - - -AccelRetry5XX and AccelSetXURI directives were added. - - - - - -заметки accel_request_body и accel_rewrite_response. - - -accel_request_body and accel_rewrite_response notes were added. +the /dev/poll module bugs fixed. -mod_accel не собирался компилятором aCC на платформе HP-UX. -Спасибо Marko Asplund, aspakronodoc.fi. - - -mod_accel is not built by aCC on HP-UX.
-Thanks to Marko Asplund, aspakronodoc.fi. -
-
- - - -косметические правки. +при проксировании и использовании временных файлов ответы портились. -code clean up. - - - -
- - - - - - -если в URL перед аргументами находились символы в виде %XX, -то они передавались бэкенду в раскрытом виде. - - -if URL before arguments contained characters encoded as %XX then -they was passed to backend unescaped. - - - - - - - - - - -в директиве AccelPass можно использовать специальное -имя хоста _the_same_host_. - - -special hostname _the_same_host_ can be used in AccelPass directive. +the responses were corrupted when the temporary files were used +while the proxing. -не работало ограничение количества соединений и ждущих процессов -при использовании флага PH в директиве AccelPass. +бэкенду передавались запросы с неперекодированными символами. -limition of connections and waiting processes does not work -if PH flag in AccelPass directive was used. - - - - - -директива AccelPassServer. - - -AccelPassServer directive was added. +the unescaped requests were passed to the backend. - - - - - -если модули mod_quoted или mod_randban были собраны статически -или подгружались с помощью LoadModule, но не были добавлены -директивой AddModule после директивы ClearModuleList, то -директивы этих модулей не воспринимались. -Если же директивы этих модулей не использовались в конфигурационных файлах, -то при любых запросах, обрабатываемых модулем mod_accel, -происходил segmentation fault. +на Linux 2.4 при конфигурации сборки нужно было обязательно использовать +параметр --with-poll_module. -if mod_quoted or mod_randban modules were statically build -or were loaded with LoadModule directive and were not added -with AddModule directive after ClearModuleList directive then -their directives were unrecognized. -If their directives were not used in configration files -then any request handled by mod_accel caused segmentation fault. +while the build configuration on Linux 2.4 the --with-poll_module parameter +was required. - - - - -некорректно обрабатывались ответы бэкенда с большими заголовками. - - -backend response with big header was incorrectly handled. - - - - - -игнорируются строки типа "HTTP/1.0 200 OK" в середине заголовка ответа -бэкенда. Добавлена запись в ErrorLog некорректных заголовков в ответе -бэкенда. - - -lines like "HTTP/1.0 200 OK" are ignored in middle of backend response header. -Incorrect backend header lines are logged in ErrorLog. - - - - - -директива AccelInvalidate, accel-cachemgr и заголовки типа -"Pragma: no-cache" не обновляли кэш, -если задана директива "AccelUnlinkNoCached off". - - -AccelInvalidate directive, accel-cachemgr and headers like -"Pragma: no-cache" did not refresh cache -if AccelUnlinkNoCached directive was off. - - - - - -порядок наследования AccelPass изменён, сначала проверяются -директивы из виртуального сервера, а затем из основного. - - -merge order of AccelPass directive is changed. Virtual server direcitves -are checked first. - - - - - - - - - - -не корректировался порт в заголовках "Location" и "Refresh" -если использовался флаг PH в директиве AccelPass и номера портов -фронтенда и бэкенда отличались. - - -port was not corrected in "Location" and "Refresh" headers -if PH flag in AccelPass directive was used and frontend and backend -port numbers were not the same. - - - - - - - - - - -флаг PH в директиве AccelPass. - - -PH flag was added in AccelPass directive. - - - - - - - - - - -упразднена директива AccelContentTail. - - -AccelContentTail directive was removed. - - - - - -если перезаписываемая строка попадала на границу буфера, mod_randban -мог некорректно поменять случайное число. - - -mod_randban can incorrectly change random value if string to rewrite -was on buffer edge. - - + -Совместимость с Apache 1.3.23. - - -Apache 1.3.23 compatibility. - - - - - -если в конфигурации AccelPass описан Location в виде /proxied/, -то при запросе /proxied возвращается редирект на URL с добавленным -слэшом - /proxied/. - - -if Location is specified in AccelPass as /proxied/ then -on request /proxied redirect is returned to URL with slash added - /proxied/. - - - - - -не возвращалась ошибка, если не удавалось создать временный файл -для хранения тела запроса POST. - - -error was not returned if POST request body temporary file creation was failed. - - - - - - - - - - -директива AccelReverse. +Первая публично доступная версия. -AccelReverse directive was added. - - - - - - - - - - -на Solaris 7 и FreeBSD 2.x большие ответы передавались не до конца. - - -big repsonses was truncated on Solaris 7 and FreeBSD 2.x. - - - - - - - - - - -скорректированы некоторые сообщения об ошибках. - - -some error messages was corrected. - - - - - -если клиент в запросе POST обрывал соединение, -то бэкенду передавалось неполное тело запроса. -Теперь mod_accel в такой ситуации не соединяется с бэкендом. - - -if client aborted connection while POST -then backend received incompleted request body. -Now mod_accel doesn't connect to backend in this situation. - - - - - -mod_accel не собирался без библиотеки mm. - - -mod_accel did not build without mm library. +The first public version. - - - - -в сообщения об ошибках добавлен URL, который передаётся бэкенду. - - -backend URL was added in error messages. - - - - - -третий параметр в директиве AccelBusyLock. - - -third parameter was added in AccelBusyLock directory. - - - - - -порядок загрузки модулей mod_accel, mod_randban, mod_quoted -и mod_ssl не важен. - - -load order of mod_accel, mod_randban, mod_quoted and mod_ssl -has no meaning now. - - - - - -добавлен параметр --with-patch в configure.
-Упразднены параметры --without-mod_charset и --without-mod_ssl. -
- ---with-patch directive was added in configure.
---without-mod_charset and --without-mod_ssl directives is removed. -
-
- - - -улучшение портабильности. - - -portability enhancement. - - - -
- - - - - - -во флаге MP директивы AccelPass можно указывать тэг. - - -MP flag of AccelPass directive can have tag. - - - - - -при использовании проксирования (флаг P) в директиве -RewriteRule модуля mod_rewrite можно использовать флаг MP. - - -MP flag can be used in mod_rewrite module RewriteRule -directive when proxing is specified (P flag). - - - - - -при указании времени кэширования с помощью директив -AccelDefaultExpire или AccelLastModifiedFactor ответ не сохранялся -в кэш, если разница во времени между фронтендом и бэкендом была -больше время кэширования. - - -if time to cache is specified in AccelDefaultExpire or -AccelLastModifiedFactor directive and time difference between -frontend and backend is more then specified time then answer -was not saved in cache. - - - - - - - - - - -директива AccelIgnoreAuth. - - -AccelIgnoreAuth directive was added. - - - - - -при использовании проксирования (флаг P) в директиве -RewriteRule модуля mod_rewrite модуль mod_proxy дублировал -строку аргументов. - - -mod_proxy module duplicated argument string when proxing -is specified in mod_rewrite module RewriteRule directive (P flag). - - - - - - - - - - -если бэкендов несколько и с одним из них соединение -не было установлено, то информация об этой попытке в заметки -%{accel*}x не добавлялась. - - -if there are several backends and connection with one of them -was not established then %{accel*}x notes did not contain state of it. - - - - - -при получении от бэкенда большого заголовка происходил -segmentation fault. - - -backend big header caused segmentation fault. - - - - - -в accel-cachemgr добавлены два состояния - invalid -и no_accelerated. - - -two status codes - invalid and no_accelerated was added -in accel-cachemgr. - - - - - -директива RewriteRule модуля mod_rewrite с флагом [P] -работала только при использовании в SSI. - - -mod_rewrite module RewriteRule directive with flag [P] -worked in SSI enviroment only. - - - - - - - - - - -Изменения в директиве AccelCacheCookie: -Добавлены параметр "all", запрещающие параметры и регулярные выражения. -В одной директиве может быть указано несколько параметров. -Директивы из вложенных блоков не объединяются. -Имена cookie сортируются в алфавитном порядке. - - -Changes in AccelCacheCookie directive: -"all" parameter, supressing parameters and regular expressions was added. -There can be several parameters in one directive. -Directives is not merged. -Cookie names is sorted in alphabetical order. - - - - - -Изменения в директиве AccelNoPass: -Регулярное выражение может быть нечуствительно к регистру. -Между символом "~" и регулярным выражением не должно быть пробела. -В одной директиве может быть указано несколько параметров. - - -Changes in AccelNoPass directive: -Regular expression can be case-insensitive. -There should not be space between "~" symbol and regular expression. -There can be several parameters in one directive. - - - - - - - - - - -директива AccelCacheCookie. - - -AccelCacheCookie directive was added. - - - - - -заметка accel_nocache. - - -accel_nocache note was added. - - - - - -обработчик accel-cachemgr. - - -accel-cachemgr handler was added. - - - - - -при запросе нескольких невозрастающих byteranges мог -выдаваться неверный ответ. - - -answer may be wrong if request contains several non-growing -byteranges. - - - - - -заметка %{accel_r}x не записывалась в лог. - - -%{accel_r}x note was not logged. - - - - - -если ответ некэшируемый, то при преждевременном обрыве -соединения с клиентом соединение с бэкендом не закрывалось сразу. - - -if response is not cachable and client prematurely closes -connection then connection to backend was not closed at once. - - - - - - - - - - -ошибка в accel_read_and_check_writable() вызывала нагрузку на процессор. - - -bug in accel_read_and_check_writable() caused high CPU usage. - - - - - - - - - - -Первая версия.
-Тестировалась на Apache 1.3.14, 1.3.17, 1.3.19, 1.3.20 на -FreeBSD 3.4, 4.2. -
- -First release.
-Tested with Apache 1.3.14, 1.3.17, 1.3.19, 1.3.20 on FreeBSD 3.4, 4.2. -
-
- -
-
diff --git a/src/core/nginx.c b/src/core/nginx.c --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -11,7 +11,8 @@ static ngx_int_t ngx_add_inherited_sockets(ngx_cycle_t *cycle); -static ngx_int_t ngx_getopt(ngx_master_ctx_t *ctx, ngx_cycle_t *cycle); +static ngx_int_t ngx_getopt(ngx_cycle_t *cycle, int argc, char *const *argv); +static ngx_int_t ngx_save_argv(ngx_cycle_t *cycle, int argc, char *const *argv); static void *ngx_core_module_create_conf(ngx_cycle_t *cycle); static char *ngx_core_module_init_conf(ngx_cycle_t *cycle, void *conf); static char *ngx_set_user(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -96,13 +97,12 @@ ngx_module_t ngx_core_module = { ngx_uint_t ngx_max_module; -int main(int argc, char *const *argv) +int main(int argc, char *const *argv, char *const *envp) { - ngx_int_t i; - ngx_log_t *log; - ngx_cycle_t *cycle, init_cycle; - ngx_core_conf_t *ccf; - ngx_master_ctx_t ctx; + ngx_int_t i; + ngx_log_t *log; + ngx_cycle_t *cycle, init_cycle; + ngx_core_conf_t *ccf; #if defined __FreeBSD__ ngx_debug_init(); @@ -132,15 +132,15 @@ int main(int argc, char *const *argv) init_cycle.log = log; ngx_cycle = &init_cycle; - ngx_memzero(&ctx, sizeof(ngx_master_ctx_t)); - ctx.argc = argc; - ctx.argv = argv; - if (!(init_cycle.pool = ngx_create_pool(1024, log))) { return 1; } - if (ngx_getopt(&ctx, &init_cycle) == NGX_ERROR) { + if (ngx_getopt(&init_cycle, argc, argv) == NGX_ERROR) { + return 1; + } + + if (ngx_save_argv(&init_cycle, argc, argv) == NGX_ERROR) { return 1; } @@ -219,10 +219,10 @@ int main(int argc, char *const *argv) #endif if (ngx_process == NGX_PROCESS_MASTER) { - ngx_master_process_cycle(cycle, &ctx); + ngx_master_process_cycle(cycle); } else { - ngx_single_process_cycle(cycle, &ctx); + ngx_single_process_cycle(cycle); } return 0; @@ -276,7 +276,7 @@ static ngx_int_t ngx_add_inherited_socke ngx_pid_t ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv) { - char *env[2], *var, *p; + char *env[3], *var, *p; ngx_uint_t i; ngx_pid_t pid; ngx_exec_ctx_t ctx; @@ -300,7 +300,25 @@ ngx_pid_t ngx_exec_new_binary(ngx_cycle_ ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, "inherited: %s", var); env[0] = var; + +#if (NGX_SETPROCTITLE_USES_ENV) + + /* allocate spare 300 bytes for the new binary process title */ + + env[1] = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; + + env[2] = NULL; + +#else + env[1] = NULL; + +#endif + ctx.envp = (char *const *) &env; pid = ngx_execute(cycle, &ctx); @@ -311,38 +329,38 @@ ngx_pid_t ngx_exec_new_binary(ngx_cycle_ } -static ngx_int_t ngx_getopt(ngx_master_ctx_t *ctx, ngx_cycle_t *cycle) +static ngx_int_t ngx_getopt(ngx_cycle_t *cycle, int argc, char *const *argv) { ngx_int_t i; - for (i = 1; i < ctx->argc; i++) { - if (ctx->argv[i][0] != '-') { + for (i = 1; i < argc; i++) { + if (argv[i][0] != '-') { ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, - "invalid option: \"%s\"", ctx->argv[i]); + "invalid option: \"%s\"", argv[i]); return NGX_ERROR; } - switch (ctx->argv[i][1]) { + switch (argv[i][1]) { case 't': ngx_test_config = 1; break; case 'c': - if (ctx->argv[i + 1] == NULL) { + if (argv[i + 1] == NULL) { ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "the option: \"%s\" requires file name", - ctx->argv[i]); + argv[i]); return NGX_ERROR; } - cycle->conf_file.data = (u_char *) ctx->argv[++i]; + cycle->conf_file.data = (u_char *) argv[++i]; cycle->conf_file.len = ngx_strlen(cycle->conf_file.data); break; default: ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, - "invalid option: \"%s\"", ctx->argv[i]); + "invalid option: \"%s\"", argv[i]); return NGX_ERROR; } } @@ -360,6 +378,43 @@ static ngx_int_t ngx_getopt(ngx_master_c } +static ngx_int_t ngx_save_argv(ngx_cycle_t *cycle, int argc, char *const *argv) +{ + size_t len; + ngx_int_t i; + + ngx_os_argv = (char **) argv; + + ngx_argc = argc; + +#if __FreeBSD__ + + ngx_argv = (char **) argv; + +#else + + if (!(ngx_argv = ngx_alloc((argc + 1) * sizeof(char *), cycle->log))) { + return NGX_ERROR; + } + + for (i = 0; i < argc; i++) { + len = ngx_strlen(argv[i]) + 1; + + if (!(ngx_argv[i] = ngx_alloc(len, cycle->log))) { + return NGX_ERROR; + } + + ngx_cpystrn((u_char *) ngx_argv[i], (u_char *) argv[i], len); + } + + ngx_argv[i] = NULL; + +#endif + + return NGX_OK; +} + + static void *ngx_core_module_create_conf(ngx_cycle_t *cycle) { ngx_core_conf_t *ccf; @@ -407,6 +462,7 @@ static char *ngx_core_module_init_conf(n #if !(WIN32) +#if 0 if (ccf->user == (uid_t) NGX_CONF_UNSET) { pwd = getpwnam("nobody"); @@ -427,10 +483,11 @@ static char *ngx_core_module_init_conf(n ccf->group = grp->gr_gid; } +#endif if (ccf->pid.len == 0) { ccf->pid.len = sizeof(NGX_PID_PATH) - 1; - ccf->pid.data = NGX_PID_PATH; + ccf->pid.data = (u_char *) NGX_PID_PATH; } if (ngx_conf_full_name(cycle, &ccf->pid) == NGX_ERROR) { @@ -478,7 +535,7 @@ static char *ngx_set_user(ngx_conf_t *cf pwd = getpwnam((const char *) value[1].data); if (pwd == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, - "getpwnam(%s) failed", value[1].data); + "getpwnam(\"%s\") failed", value[1].data); return NGX_CONF_ERROR; } @@ -491,7 +548,7 @@ static char *ngx_set_user(ngx_conf_t *cf grp = getgrnam((const char *) value[2].data); if (grp == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, - "getgrnam(%s) failed", value[1].data); + "getgrnam(\"%s\") failed", value[2].data); return NGX_CONF_ERROR; } diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,7 +8,7 @@ #define _NGINX_H_INCLUDED_ -#define NGINX_VER "nginx/0.1.0" +#define NGINX_VER "nginx/0.1.1" #define NGINX_VAR "NGINX" #define NGX_NEWPID_EXT ".newbin" diff --git a/src/core/ngx_buf.c b/src/core/ngx_buf.c --- a/src/core/ngx_buf.c +++ b/src/core/ngx_buf.c @@ -152,7 +152,8 @@ void ngx_chain_update_chains(ngx_chain_t continue; } - (*busy)->buf->pos = (*busy)->buf->last = (*busy)->buf->start; + (*busy)->buf->pos = (*busy)->buf->start; + (*busy)->buf->last = (*busy)->buf->start; tl = *busy; *busy = (*busy)->next; diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h --- a/src/core/ngx_conf_file.h +++ b/src/core/ngx_conf_file.h @@ -57,7 +57,7 @@ #define NGX_CONF_OK NULL -#define NGX_CONF_ERROR (void *) -1 +#define NGX_CONF_ERROR (char *) -1 #define NGX_CONF_BLOCK_DONE 1 #define NGX_CONF_FILE_DONE 2 diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -313,18 +313,6 @@ void ngx_close_connection(ngx_connection ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed"); return; } - -#if (NGX_OPENSSL) - - if (c->ssl) { - if (ngx_ssl_shutdown(c) == NGX_AGAIN) { - c->read->event_handler = ngx_ssl_close_handler; - c->write->event_handler = ngx_ssl_close_handler; - return; - } - } - -#endif if (c->read->timer_set) { ngx_del_timer(c->read); diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -120,7 +120,12 @@ struct ngx_connection_s { unsigned single_connection:1; unsigned unexpected_eof:1; unsigned timedout:1; + + unsigned sendfile:1; + unsigned sndlowat:1; + unsigned tcp_nodelay:1; signed tcp_nopush:2; + #if (HAVE_IOCP) unsigned accept_context_updated:1; #endif diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -615,6 +615,9 @@ void ngx_reopen_files(ngx_cycle_t *cycle ngx_uint_t i; ngx_list_part_t *part; ngx_open_file_t *file; +#if !(WIN32) + ngx_file_info_t fi; +#endif part = &cycle->open_files.part; file = part->elts; @@ -672,6 +675,35 @@ void ngx_reopen_files(ngx_cycle_t *cycle file[i].name.data); } } + + if (ngx_file_info((const char *) file[i].name.data, &fi) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + ngx_file_info_n " \"%s\" failed", + file[i].name.data); + + if (ngx_close_file(fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", + file[i].name.data); + } + } + + if ((fi.st_mode & (S_IRUSR|S_IWUSR)) != (S_IRUSR|S_IWUSR)) { + + fi.st_mode |= (S_IRUSR|S_IWUSR); + + if (chmod((const char *) file[i].name.data, fi.st_mode) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "chmod \"%s\" failed", + file[i].name.data); + + if (ngx_close_file(fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", + file[i].name.data); + } + } + } } if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) { diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c --- a/src/core/ngx_output_chain.c +++ b/src/core/ngx_output_chain.c @@ -228,8 +228,15 @@ static ngx_int_t ngx_output_chain_copy_b src->pos += size; dst->last += size; - if (src->in_file) { + if (src->in_file && sendfile) { + dst->in_file = 1; + dst->file = src->file; + dst->file_pos = src->file_pos; src->file_pos += size; + dst->file_last = src->file_pos; + + } else { + dst->in_file = 0; } if (src->last_buf && src->pos == src->last) { @@ -258,11 +265,18 @@ static ngx_int_t ngx_output_chain_copy_b } } - src->file_pos += n; dst->last += n; - if (!sendfile) { + if (sendfile) { + dst->in_file = 1; + dst->file = src->file; + dst->file_pos = src->file_pos; + src->file_pos += size; + dst->file_last = src->file_pos; + + } else { dst->in_file = 0; + src->file_pos += n; } if (src->last_buf && src->file_pos == src->file_last) { diff --git a/src/core/ngx_palloc.c b/src/core/ngx_palloc.c --- a/src/core/ngx_palloc.c +++ b/src/core/ngx_palloc.c @@ -77,13 +77,14 @@ void *ngx_palloc(ngx_pool_t *pool, size_ ngx_pool_large_t *large, *last; if (size <= (size_t) NGX_MAX_ALLOC_FROM_POOL - && size <= (size_t) (pool->end - (char *) pool) - sizeof(ngx_pool_t)) + && size <= (size_t) (pool->end - (char *) pool) + - (size_t) ngx_align(sizeof(ngx_pool_t))) { for (p = pool, n = pool->next; /* void */; p = n, n = n->next) { m = ngx_align(p->last); if ((size_t) (p->end - m) >= size) { - p->last = m + size ; + p->last = m + size; return m; } @@ -100,8 +101,8 @@ void *ngx_palloc(ngx_pool_t *pool, size_ } p->next = n; - m = n->last; - n->last += size; + m = ngx_align(n->last); + n->last = m + size; return m; } diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -128,7 +128,7 @@ void ngx_md5_text(u_char *text, u_char * } -void ngx_encode_base64(ngx_str_t *src, ngx_str_t *dst) +void ngx_encode_base64(ngx_str_t *dst, ngx_str_t *src) { u_char *d, *s; size_t len; @@ -168,7 +168,7 @@ void ngx_encode_base64(ngx_str_t *src, n } -ngx_int_t ngx_decode_base64(ngx_str_t *src, ngx_str_t *dst) +ngx_int_t ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src) { size_t len; u_char *d, *s; @@ -231,54 +231,55 @@ ngx_int_t ngx_decode_base64(ngx_str_t *s } -#if 0 -char *ngx_psprintf(ngx_pool_t *p, const char *fmt, ...) +ngx_int_t ngx_escape_uri(u_char *dst, u_char *src, size_t size) { - va_list args; + ngx_int_t n; + ngx_uint_t i; + static u_char hex[] = "0123456789abcdef"; + static uint32_t escape[] = + { 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ - va_start(args, fmt); + /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ + 0x80000021, /* 1000 0000 0000 0000 0000 0000 0010 0001 */ + + /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + + /* ~}| {zyx wvut srqp onml kjih gfed cba` */ + 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */ - while (*fmt) { - switch(*fmt++) { - case '%': - switch(*fmt++) { - case 's': - s = va_arg(args, char *); - n += ngx_strlen(s); - break; + 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 (dst == NULL) { + + /* find the number of the characters to be escaped */ - default: - n++; - } - default: - n++; - } + n = 0; + + for (i = 0; i < size; i++) { + if (escape[*src >> 5] & (1 << (*src & 0x1f))) { + n++; + } + src++; + } + + return n; } - str = ngx_palloc(p, n); - - va_start(args, fmt); + for (i = 0; i < size; i++) { + if (escape[*src >> 5] & (1 << (*src & 0x1f))) { + *dst++ = '%'; + *dst++ = hex[*src >> 4]; + *dst++ = hex[*src & 0xf]; + src++; - for (i = 0; i < n; i++) { - switch(*fmt++) { - case '%': - switch(*fmt++) { - case 's': - s = va_arg(args, char *); - while (str[i++] = s); - break; - - default: - n++; - } - default: - str[i] = *fmt; - } + } else { + *dst++ = *src++; + } } - len += ngx_vsnprintf(errstr + len, sizeof(errstr) - len - 1, fmt, args); - - va_end(args); - + return NGX_OK; } -#endif diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h --- a/src/core/ngx_string.h +++ b/src/core/ngx_string.h @@ -60,6 +60,7 @@ typedef struct { * icc may also inline several mov's of a zeroed register for small blocks. */ #define ngx_memzero(buf, n) memset(buf, 0, n) +#define ngx_memset(buf, c, n) memset(buf, c, n) /* msvc and icc compile memcpy() to the inline "rep movs" */ #define ngx_memcpy(dst, src, n) memcpy(dst, src, n) @@ -80,8 +81,9 @@ void ngx_md5_text(u_char *text, u_char * #define ngx_base64_encoded_length(len) (((len + 2) / 3) * 4) #define ngx_base64_decoded_length(len) (((len + 3) / 4) * 3) -void ngx_encode_base64(ngx_str_t *src, ngx_str_t *dst); -ngx_int_t ngx_decode_base64(ngx_str_t *src, ngx_str_t *dst); +void ngx_encode_base64(ngx_str_t *dst, ngx_str_t *src); +ngx_int_t ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src); +ngx_int_t ngx_escape_uri(u_char *dst, u_char *src, size_t size); #define ngx_qsort qsort diff --git a/src/event/modules/ngx_devpoll_module.c b/src/event/modules/ngx_devpoll_module.c --- a/src/event/modules/ngx_devpoll_module.c +++ b/src/event/modules/ngx_devpoll_module.c @@ -202,13 +202,7 @@ static int ngx_devpoll_add_event(ngx_eve #endif #if (NGX_READ_EVENT != POLLIN) - if (event == NGX_READ_EVENT) { - event = POLLOUT; -#if (NGX_WRITE_EVENT != POLLOUT) - } else { - event = POLLIN; -#endif - } + event = (event == NGX_READ_EVENT) ? POLLIN : POLLOUT; #endif #if (NGX_DEBUG) @@ -218,6 +212,7 @@ static int ngx_devpoll_add_event(ngx_eve #endif ev->active = 1; + return ngx_devpoll_set_event(ev, event, 0); } @@ -229,6 +224,10 @@ static int ngx_devpoll_del_event(ngx_eve c = ev->data; +#if (NGX_READ_EVENT != POLLIN) + event = (event == NGX_READ_EVENT) ? POLLIN : POLLOUT; +#endif + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, "devpoll del event: fd:%d ev:%04X", c->fd, event); @@ -242,13 +241,9 @@ static int ngx_devpoll_del_event(ngx_eve return NGX_OK; } - /* we need to restore the second event if it exists */ + /* restore the paired event if it exists */ - if (event == NGX_READ_EVENT) { - if (ev->accept) { - return NGX_OK; - } - + if (event == POLLIN) { e = c->write; event = POLLOUT; @@ -257,7 +252,7 @@ static int ngx_devpoll_del_event(ngx_eve event = POLLIN; } - if (e) { + if (e && e->active) { return ngx_devpoll_set_event(e, event, 0); } @@ -273,7 +268,7 @@ static int ngx_devpoll_set_event(ngx_eve c = ev->data; ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0, - "devpoll fd:%d ev:%d fl:%d", c->fd, event, flags); + "devpoll fd:%d ev:%04X fl:%04X", c->fd, event, flags); if (nchanges >= max_changes) { ngx_log_error(NGX_LOG_WARN, ev->log, 0, diff --git a/src/event/modules/ngx_rtsig_module.c b/src/event/modules/ngx_rtsig_module.c --- a/src/event/modules/ngx_rtsig_module.c +++ b/src/event/modules/ngx_rtsig_module.c @@ -131,10 +131,6 @@ static ngx_int_t ngx_rtsig_init(ngx_cycl { ngx_rtsig_conf_t *rtscf; - if (ngx_poll_module_ctx.actions.init(cycle) == NGX_ERROR) { - return NGX_ERROR; - } - rtscf = ngx_event_get_conf(cycle->conf_ctx, ngx_rtsig_module); sigemptyset(&set); @@ -170,7 +166,9 @@ static ngx_int_t ngx_rtsig_init(ngx_cycl static void ngx_rtsig_done(ngx_cycle_t *cycle) { - ngx_poll_module_ctx.actions.done(cycle); + ngx_free(overflow_list); + + overflow_list = NULL; } @@ -697,7 +695,7 @@ static ngx_int_t ngx_rtsig_process_overf * the new overflow. * * Learn the /proc/sys/kernel/rtsig-max value because - * it can be changed sisnce the last checking. + * it can be changed since the last checking. */ name[0] = CTL_KERN; diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -461,6 +461,39 @@ static ngx_int_t ngx_event_process_init( } +ngx_int_t ngx_send_lowat(ngx_connection_t *c, size_t lowat) +{ + int sndlowat; + +#if (HAVE_LOWAT_EVENT) + + if (ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) { + c->write->available = lowat; + return NGX_OK; + } + +#endif + + if (lowat == 0 || c->sndlowat) { + return NGX_OK; + } + + sndlowat = (int) lowat; + + if (setsockopt(c->fd, SOL_SOCKET, SO_SNDLOWAT, + (const void *) &sndlowat, sizeof(int)) == -1) + { + ngx_connection_error(c, ngx_socket_errno, + "setsockopt(SO_SNDLOWAT) failed"); + return NGX_ERROR; + } + + c->sndlowat = 1; + + return NGX_OK; +} + + static char *ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { int m; diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -207,7 +207,7 @@ typedef struct { ngx_int_t (*add_conn)(ngx_connection_t *c); ngx_int_t (*del_conn)(ngx_connection_t *c, u_int flags); - ngx_int_t (*process_changes)(ngx_cycle_t *cycle, ngx_uint_t try); + ngx_int_t (*process_changes)(ngx_cycle_t *cycle, ngx_uint_t nowait); ngx_int_t (*process_events)(ngx_cycle_t *cycle); ngx_int_t (*init)(ngx_cycle_t *cycle); @@ -479,6 +479,9 @@ int ngx_event_post_acceptex(ngx_listenin #endif +ngx_int_t ngx_send_lowat(ngx_connection_t *c, size_t lowat); + + /* used in ngx_log_debugX() */ #define ngx_event_ident(p) ((ngx_connection_t *) (p))->fd @@ -497,7 +500,7 @@ ngx_inline static int ngx_handle_read_ev { if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { - /* kqueue */ + /* kqueue, epoll */ if (!rev->active && !rev->ready) { if (ngx_add_event(rev, NGX_READ_EVENT, NGX_CLEAR_EVENT) @@ -531,7 +534,7 @@ ngx_inline static int ngx_handle_read_ev } } - /* aio, iocp, epoll, rtsig */ + /* aio, iocp, rtsig */ return NGX_OK; } @@ -563,14 +566,25 @@ ngx_inline static int ngx_handle_level_r } -ngx_inline static int ngx_handle_write_event(ngx_event_t *wev, u_int flags) +ngx_inline static int ngx_handle_write_event(ngx_event_t *wev, size_t lowat) { + ngx_connection_t *c; + + if (lowat) { + c = wev->data; + + if (ngx_send_lowat(c, lowat) == NGX_ERROR) { + return NGX_ERROR; + } + } + if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { - /* kqueue */ + /* kqueue, epoll */ if (!wev->active && !wev->ready) { - if (ngx_add_event(wev, NGX_WRITE_EVENT, NGX_CLEAR_EVENT|flags) + if (ngx_add_event(wev, NGX_WRITE_EVENT, + NGX_CLEAR_EVENT | (lowat ? NGX_LOWAT_EVENT : 0)) == NGX_ERROR) { return NGX_ERROR; @@ -602,7 +616,7 @@ ngx_inline static int ngx_handle_write_e } } - /* aio, iocp, epoll, rtsig */ + /* aio, iocp, rtsig */ return NGX_OK; } diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -72,6 +72,13 @@ ngx_int_t ngx_ssl_recv(ngx_connection_t return n; } + if (!SSL_is_init_finished(c->ssl->ssl)) { + handshake = "in SSL handshake"; + + } else { + handshake = ""; + } + sslerr = SSL_get_error(c->ssl->ssl, n); err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; @@ -91,13 +98,6 @@ ngx_int_t ngx_ssl_recv(ngx_connection_t #endif } - if (!SSL_is_init_finished(c->ssl->ssl)) { - handshake = "in SSL handshake"; - - } else { - handshake = ""; - } - c->ssl->no_rcv_shut = 1; if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) { @@ -240,8 +240,9 @@ ngx_chain_t *ngx_ssl_send_chain(ngx_conn static ngx_int_t ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size) { - int n, sslerr; - ngx_err_t err; + int n, sslerr; + ngx_err_t err; + char *handshake; ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL to write: %d", size); @@ -265,13 +266,21 @@ static ngx_int_t ngx_ssl_write(ngx_conne } if (sslerr == SSL_ERROR_WANT_READ) { + + if (!SSL_is_init_finished(c->ssl->ssl)) { + handshake = "in SSL handshake"; + + } else { + handshake = ""; + } + ngx_log_error(NGX_LOG_ALERT, c->log, err, "SSL wants to read%s", handshake); return NGX_ERROR; #if 0 return NGX_AGAIN; +#endif } -#endif c->ssl->no_rcv_shut = 1; diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c --- a/src/event/ngx_event_pipe.c +++ b/src/event/ngx_event_pipe.c @@ -64,8 +64,7 @@ ngx_int_t ngx_event_pipe(ngx_event_pipe_ if (p->downstream->fd != -1) { wev = p->downstream->write; - wev->available = p->send_lowat; - if (ngx_handle_write_event(wev, NGX_LOWAT_EVENT) == NGX_ERROR) { + if (ngx_handle_write_event(wev, p->send_lowat) == NGX_ERROR) { return NGX_ABORT; } @@ -302,16 +301,41 @@ ngx_int_t ngx_event_pipe_read_upstream(n ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe buf"); } - for (cl = p->in; cl; cl = cl->next) { + for (cl = p->busy; cl; cl = cl->next) { ngx_log_debug3(NGX_LOG_DEBUG_EVENT, p->log, 0, - "pipe buf in " PTR_FMT ", pos " PTR_FMT ", size: %d", + "pipe buf busy " PTR_FMT ", pos " PTR_FMT ", size: %d", cl->buf->start, cl->buf->pos, cl->buf->last - cl->buf->pos); } - for (cl = p->busy; cl; cl = cl->next) { + for (cl = p->out; cl; cl = cl->next) { + if (cl->buf->in_file && cl->buf->temporary) { + ngx_log_debug5(NGX_LOG_DEBUG_EVENT, p->log, 0, + "pipe buf out shadow " + PTR_FMT ", pos " PTR_FMT ", size: %d " + "file: " OFF_T_FMT ", size: %d", + cl->buf->start, cl->buf->pos, + cl->buf->last - cl->buf->pos, + cl->buf->file_pos, + cl->buf->file_last - cl->buf->file_pos); + + } else if (cl->buf->in_file) { + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0, + "pipe buf out file " OFF_T_FMT ", size: %d", + cl->buf->file_pos, + cl->buf->file_last - cl->buf->file_pos); + } else { + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, p->log, 0, + "pipe buf out " PTR_FMT ", pos " PTR_FMT + ", size: %d", + cl->buf->start, cl->buf->pos, + cl->buf->last - cl->buf->pos); + } + } + + for (cl = p->in; cl; cl = cl->next) { ngx_log_debug3(NGX_LOG_DEBUG_EVENT, p->log, 0, - "pipe buf busy " PTR_FMT ", pos " PTR_FMT ", size: %d", + "pipe buf in " PTR_FMT ", pos " PTR_FMT ", size: %d", cl->buf->start, cl->buf->pos, cl->buf->last - cl->buf->pos); } @@ -337,7 +361,9 @@ ngx_int_t ngx_event_pipe_read_upstream(n if (p->free_bufs) { for (cl = p->free_raw_bufs; cl; cl = cl->next) { - ngx_pfree(p->pool, cl->buf->start); + if (cl->buf->shadow == NULL) { + ngx_pfree(p->pool, cl->buf->start); + } } } } @@ -597,8 +623,11 @@ static ngx_int_t ngx_event_pipe_write_ch ngx_chain_add_link(p->out, p->last_out, cl); if (b->last_shadow) { - b->shadow->last = b->shadow->pos = b->shadow->start; + b->shadow->pos = b->shadow->start; + b->shadow->last = b->shadow->start; + ngx_alloc_link_and_set_buf(tl, b->shadow, p->pool, NGX_ABORT); + *last_free = tl; last_free = &tl->next; } @@ -650,28 +679,24 @@ ngx_inline static void ngx_event_pipe_re { ngx_buf_t *b, *next; - if (buf->shadow == NULL) { + b = buf->shadow; + + if (b == NULL) { return; } - b = buf->shadow; - while (!b->last_shadow) { next = b->shadow; - b->in_file = 0; - b->temp_file = 0; - b->flush = 0; - b->zerocopy_busy = 0; + b->temporary = 0; + b->recycled = 0; b->shadow = NULL; b = next; } - b->in_file = 0; - b->temp_file = 0; - b->flush = 0; - b->zerocopy_busy = 0; + b->temporary = 0; + b->recycled = 0; b->last_shadow = 0; b->shadow = NULL; diff --git a/src/http/modules/ngx_http_chunked_filter.c b/src/http/modules/ngx_http_chunked_filter.c --- a/src/http/modules/ngx_http_chunked_filter.c +++ b/src/http/modules/ngx_http_chunked_filter.c @@ -83,10 +83,12 @@ static ngx_int_t ngx_http_chunked_body_f size += ngx_buf_size(cl->buf); - ngx_test_null(tl, ngx_alloc_chain_link(r->pool), NGX_ERROR); - tl->buf = cl->buf; - *ll = tl; - ll = &tl->next; + if (cl->buf->flush || ngx_buf_in_memory(cl->buf) || cl->buf->in_file) { + ngx_test_null(tl, ngx_alloc_chain_link(r->pool), NGX_ERROR); + tl->buf = cl->buf; + *ll = tl; + ll = &tl->next; + } if (cl->next == NULL) { break; diff --git a/src/http/modules/ngx_http_gzip_filter.c b/src/http/modules/ngx_http_gzip_filter.c --- a/src/http/modules/ngx_http_gzip_filter.c +++ b/src/http/modules/ngx_http_gzip_filter.c @@ -15,6 +15,8 @@ typedef struct { ngx_flag_t enable; ngx_flag_t no_buffer; + ngx_array_t *types; /* array of ngx_http_gzip_type_t */ + ngx_bufs_t bufs; ngx_uint_t http_version; @@ -27,6 +29,12 @@ typedef struct { } ngx_http_gzip_conf_t; +typedef struct { + ngx_str_t name; + ngx_uint_t enable; +} ngx_http_gzip_type_t; + + #define NGX_HTTP_GZIP_PROXIED_OFF 0x0002 #define NGX_HTTP_GZIP_PROXIED_EXPIRED 0x0004 #define NGX_HTTP_GZIP_PROXIED_NO_CACHE 0x0008 @@ -57,10 +65,6 @@ typedef struct { unsigned flush:4; unsigned redo:1; unsigned done:1; -#if 0 - unsigned pass:1; - unsigned blocked:1; -#endif size_t zin; size_t zout; @@ -86,6 +90,8 @@ static ngx_int_t ngx_http_gzip_filter_in 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_set_types(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static char *ngx_http_gzip_set_window(ngx_conf_t *cf, void *post, void *data); static char *ngx_http_gzip_set_hash(ngx_conf_t *cf, void *post, void *data); @@ -138,6 +144,13 @@ static ngx_command_t ngx_http_gzip_filt 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_gzip_set_types, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + { 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, @@ -211,7 +224,7 @@ ngx_module_t ngx_http_gzip_filter_modul ngx_http_gzip_filter_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ ngx_http_gzip_filter_init, /* init module */ - NULL /* init child */ + NULL /* init process */ }; @@ -247,15 +260,20 @@ static ngx_http_output_body_filter_pt static ngx_int_t ngx_http_gzip_header_filter(ngx_http_request_t *r) { + ngx_uint_t i, found; ngx_http_gzip_ctx_t *ctx; ngx_http_gzip_conf_t *conf; + ngx_http_gzip_type_t *type; 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_OK + && r->headers_out.status != NGX_HTTP_FORBIDDEN + && r->headers_out.status != NGX_HTTP_NOT_FOUND) || r->header_only || r->http_version < conf->http_version + || r->headers_out.content_type == NULL || (r->headers_out.content_encoding && r->headers_out.content_encoding->value.len) || r->headers_in.accept_encoding == NULL @@ -267,11 +285,21 @@ static ngx_int_t ngx_http_gzip_header_fi return ngx_http_next_header_filter(r); } - /* TODO: "text/html" -> custom types */ - if (r->headers_out.content_type - && ngx_strncasecmp(r->headers_out.content_type->value.data, - "text/html", 9) != 0) - { + + found = 0; + type = conf->types->elts; + + for (i = 0; i < conf->types->nelts; i++) { + if (r->headers_out.content_type->value.len >= type[i].name.len + && ngx_strncasecmp(r->headers_out.content_type->value.data, + type[i].name.data, type[i].name.len) == 0) + { + found = 1; + break; + } + } + + if (!found) { return ngx_http_next_header_filter(r); } @@ -572,15 +600,9 @@ static ngx_int_t ngx_http_gzip_body_filt ctx->bufs++; } else { -#if 0 - ctx->blocked = 1; -#endif break; } -#if 0 - ctx->blocked = 0; -#endif ctx->zstream.next_out = ctx->out_buf->pos; ctx->zstream.avail_out = conf->bufs.size; } @@ -646,10 +668,6 @@ static ngx_int_t ngx_http_gzip_body_filt *ctx->last_out = cl; ctx->last_out = &cl->next; -#if 0 - ctx->pass = 1; -#endif - break; } @@ -712,9 +730,6 @@ static ngx_int_t ngx_http_gzip_body_filt ctx->zstream.avail_out = 0; ctx->done = 1; -#if 0 - ctx->pass = 1; -#endif break; } @@ -725,47 +740,10 @@ static ngx_int_t ngx_http_gzip_body_filt *ctx->last_out = cl; ctx->last_out = &cl->next; -#if 0 - ctx->pass = 1; -#endif - break; } } -#if 0 - - /* OLD CODE */ - - if (ctx->out) { - if (ctx->pass) { - ctx->pass = 0; - - } else if (last == NGX_AGAIN) { - return last; - } - - } else if (ctx->busy->buf && ngx_buf_size(ctx->busy->buf)) { - if (last != NGX_NONE) { - return last; - } - - } else if (ctx->blocked) { - if (last != NGX_NONE) { - return last; - } - - } else { - if (last == NGX_NONE) { - return NGX_OK; - } - - return last; - } -#endif - - /* NEW CODE */ - if (last == NGX_AGAIN) { return NGX_AGAIN; } @@ -774,8 +752,6 @@ static ngx_int_t ngx_http_gzip_body_filt return NGX_OK; } - /**/ - last = ngx_http_next_body_filter(r, ctx->out); /* @@ -866,7 +842,7 @@ static u_char *ngx_http_gzip_log_ratio(n (float) ctx->zin / ctx->zout); #endif - /* we prefer do not use FPU */ + /* we prefer do not use the FPU */ zint = (ngx_uint_t) (ctx->zin / ctx->zout); zfrac = (ngx_uint_t) ((ctx->zin * 100 / ctx->zout) % 100); @@ -947,6 +923,8 @@ static void *ngx_http_gzip_create_conf(n conf->bufs.num = 0; conf->proxied = 0; + conf->types = NULL; + */ conf->enable = NGX_CONF_UNSET; @@ -969,6 +947,8 @@ static char *ngx_http_gzip_merge_conf(ng ngx_http_gzip_conf_t *prev = parent; ngx_http_gzip_conf_t *conf = child; + ngx_http_gzip_type_t *type; + ngx_conf_merge_value(conf->enable, prev->enable, 0); ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 4, ngx_pagesize); @@ -986,6 +966,77 @@ static char *ngx_http_gzip_merge_conf(ng ngx_conf_merge_value(conf->min_length, prev->min_length, 0); ngx_conf_merge_value(conf->no_buffer, prev->no_buffer, 0); + if (conf->types == NULL) { + if (prev->types == NULL) { + conf->types = ngx_array_create(cf->pool, 1, + sizeof(ngx_http_gzip_type_t)); + if (conf->types == NULL) { + return NGX_CONF_ERROR; + } + + if (!(type = ngx_array_push(conf->types))) { + return NGX_CONF_ERROR; + } + + type->name.len = sizeof("text/html") - 1; + type->name.data = (u_char *) "text/html"; + type->enable = 1; + + } else { + conf->types = prev->types; + } + } + + return NGX_CONF_OK; +} + + +static char *ngx_http_gzip_set_types(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + ngx_http_gzip_conf_t *gcf = conf; + + ngx_str_t *value; + ngx_uint_t i; + ngx_http_gzip_type_t *type; + + if (gcf->types == NULL) { + gcf->types = ngx_array_create(cf->pool, 5, + sizeof(ngx_http_gzip_type_t)); + if (gcf->types == NULL) { + return NGX_CONF_ERROR; + } + + if (!(type = ngx_array_push(gcf->types))) { + return NGX_CONF_ERROR; + } + + type->name.len = sizeof("text/html") - 1; + type->name.data = (u_char *) "text/html"; + type->enable = 1; + } + + value = cf->args->elts; + + for (i = 1; i < cf->args->nelts; i++) { + + if (ngx_strcmp(value[i].data, "text/html") == 0) { + continue; + } + + if (!(type = ngx_array_push(gcf->types))) { + return NGX_CONF_ERROR; + } + + type->name.len = value[i].len; + + if (!(type->name.data = ngx_palloc(cf->pool, type->name.len + 1))) { + return NGX_CONF_ERROR; + } + + ngx_cpystrn(type->name.data, value[i].data, type->name.len + 1); + } + return NGX_CONF_OK; } diff --git a/src/http/modules/ngx_http_userid_filter.c b/src/http/modules/ngx_http_userid_filter.c --- a/src/http/modules/ngx_http_userid_filter.c +++ b/src/http/modules/ngx_http_userid_filter.c @@ -257,7 +257,7 @@ static ngx_int_t ngx_http_userid_get_uid src.data = start; dst.data = (u_char *) ctx->uid_got; - if (ngx_decode_base64(&src, &dst) == NGX_ERROR) { + if (ngx_decode_base64(&dst, &src) == NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client sent invalid userid cookie \"%s\"", cookies[i]->value.data); @@ -358,7 +358,7 @@ static ngx_int_t ngx_http_userid_set_uid src.data = (u_char *) ctx->uid_set; dst.data = p; - ngx_encode_base64(&src, &dst); + ngx_encode_base64(&dst, &src); p += dst.len; diff --git a/src/http/modules/proxy/ngx_http_proxy_handler.c b/src/http/modules/proxy/ngx_http_proxy_handler.c --- a/src/http/modules/proxy/ngx_http_proxy_handler.c +++ b/src/http/modules/proxy/ngx_http_proxy_handler.c @@ -29,6 +29,11 @@ static char *ngx_http_proxy_set_pass(ngx static char *ngx_http_proxy_parse_upstream(ngx_str_t *url, ngx_http_proxy_upstream_conf_t *u); +static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data); + +static ngx_conf_post_t ngx_http_proxy_lowat_post = + { ngx_http_proxy_lowat_check } ; + static ngx_conf_bitmask_t next_upstream_masks[] = { { ngx_string("error"), NGX_HTTP_PROXY_FT_ERROR }, @@ -79,6 +84,13 @@ static ngx_command_t ngx_http_proxy_com offsetof(ngx_http_proxy_loc_conf_t, send_timeout), NULL }, + { ngx_string("proxy_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_proxy_loc_conf_t, send_lowat), + &ngx_http_proxy_lowat_post }, + { ngx_string("proxy_preserve_host"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -877,6 +889,7 @@ static void *ngx_http_proxy_create_loc_c conf->connect_timeout = NGX_CONF_UNSET_MSEC; conf->send_timeout = NGX_CONF_UNSET_MSEC; + conf->send_lowat = NGX_CONF_UNSET_SIZE; conf->preserve_host = NGX_CONF_UNSET; conf->set_x_real_ip = NGX_CONF_UNSET; @@ -920,6 +933,7 @@ static char *ngx_http_proxy_merge_loc_co ngx_conf_merge_msec_value(conf->connect_timeout, prev->connect_timeout, 60000); 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_value(conf->preserve_host, prev->preserve_host, 0); ngx_conf_merge_value(conf->set_x_real_ip, prev->set_x_real_ip, 0); @@ -1073,17 +1087,21 @@ static char *ngx_http_proxy_set_pass(ngx value = cf->args->elts; if (ngx_strncasecmp(value[1].data, "http://", 7) != 0) { - return "invalid URL prefix"; + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid URL prefix"); + return NGX_CONF_ERROR; } - ngx_test_null(lcf->upstream, - ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_upstream_conf_t)), - NGX_CONF_ERROR); + lcf->upstream = ngx_pcalloc(cf->pool, + sizeof(ngx_http_proxy_upstream_conf_t)); + if (lcf->upstream == NULL) { + return NGX_CONF_ERROR; + } lcf->upstream->url.len = value[1].len; if (!(lcf->upstream->url.data = ngx_palloc(cf->pool, value[1].len + 1))) { return NGX_CONF_ERROR; } + ngx_cpystrn(lcf->upstream->url.data, value[1].data, value[1].len + 1); value[1].data += 7; @@ -1092,11 +1110,14 @@ static char *ngx_http_proxy_set_pass(ngx err = ngx_http_proxy_parse_upstream(&value[1], lcf->upstream); if (err) { - return err; + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, err); + return NGX_CONF_ERROR; } - ngx_test_null(host, ngx_palloc(cf->pool, lcf->upstream->host.len + 1), - NGX_CONF_ERROR); + if (!(host = ngx_palloc(cf->pool, lcf->upstream->host.len + 1))) { + return NGX_CONF_ERROR; + } + ngx_cpystrn(host, lcf->upstream->host.data, lcf->upstream->host.len + 1); /* AF_INET only */ @@ -1115,11 +1136,12 @@ static char *ngx_http_proxy_set_pass(ngx /* MP: ngx_shared_palloc() */ - ngx_test_null(lcf->peers, - ngx_pcalloc(cf->pool, - sizeof(ngx_peers_t) - + sizeof(ngx_peer_t) * (i - 1)), - NGX_CONF_ERROR); + lcf->peers = ngx_pcalloc(cf->pool, + sizeof(ngx_peers_t) + sizeof(ngx_peer_t) * (i - 1)); + + if (lcf->peers == NULL) { + return NGX_CONF_ERROR; + } lcf->peers->number = i; @@ -1130,9 +1152,12 @@ static char *ngx_http_proxy_set_pass(ngx lcf->peers->peers[i].port = lcf->upstream->port; len = INET_ADDRSTRLEN + lcf->upstream->port_text.len + 1; - ngx_test_null(lcf->peers->peers[i].addr_port_text.data, - ngx_palloc(cf->pool, len), - NGX_CONF_ERROR); + + lcf->peers->peers[i].addr_port_text.data = + ngx_palloc(cf->pool, len); + if (lcf->peers->peers[i].addr_port_text.data == NULL) { + return NGX_CONF_ERROR; + } len = ngx_inet_ntop(AF_INET, &lcf->peers->peers[i].addr, @@ -1153,8 +1178,9 @@ static char *ngx_http_proxy_set_pass(ngx /* MP: ngx_shared_palloc() */ - ngx_test_null(lcf->peers, ngx_pcalloc(cf->pool, sizeof(ngx_peers_t)), - NGX_CONF_ERROR); + if (!(lcf->peers = ngx_pcalloc(cf->pool, sizeof(ngx_peers_t)))) { + return NGX_CONF_ERROR; + } lcf->peers->number = 1; @@ -1165,9 +1191,11 @@ static char *ngx_http_proxy_set_pass(ngx len = lcf->upstream->host.len + lcf->upstream->port_text.len + 1; - ngx_test_null(lcf->peers->peers[0].addr_port_text.data, - ngx_palloc(cf->pool, len + 1), - NGX_CONF_ERROR); + lcf->peers->peers[0].addr_port_text.data = + ngx_palloc(cf->pool, len + 1); + if (lcf->peers->peers[0].addr_port_text.data == NULL) { + return NGX_CONF_ERROR; + } len = lcf->upstream->host.len; @@ -1278,3 +1306,34 @@ static char *ngx_http_proxy_parse_upstre return "invalid port in upstream URL"; } + + +static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data) +{ +#if __FreeBSD__ + + ssize_t *np = data; + + if (*np >= ngx_freebsd_net_inet_tcp_sendspace) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"proxy_send_lowat\" must be less than %d " + "(sysctl net.inet.tcp.sendspace)", + ngx_freebsd_net_inet_tcp_sendspace); + + return NGX_CONF_ERROR; + } + + +#else + +#if 0 + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "\"proxy_send_lowat\" is not supported, ignored"); + + *np = 0; +#endif + +#endif + + return NGX_CONF_OK; +} diff --git a/src/http/modules/proxy/ngx_http_proxy_handler.h b/src/http/modules/proxy/ngx_http_proxy_handler.h --- a/src/http/modules/proxy/ngx_http_proxy_handler.h +++ b/src/http/modules/proxy/ngx_http_proxy_handler.h @@ -54,6 +54,7 @@ typedef struct { typedef struct { + size_t send_lowat; size_t header_buffer_size; size_t busy_buffers_size; size_t max_temp_file_size; diff --git a/src/http/modules/proxy/ngx_http_proxy_header.c b/src/http/modules/proxy/ngx_http_proxy_header.c --- a/src/http/modules/proxy/ngx_http_proxy_header.c +++ b/src/http/modules/proxy/ngx_http_proxy_header.c @@ -164,24 +164,26 @@ static int ngx_http_proxy_rewrite_locati return NGX_ERROR; } - /* - * we do not set r->headers_out.location to avoid the handling - * the local redirects without a host name by ngx_http_header_filter() - */ - -#if 0 - r->headers_out.location = location; -#endif - if (uc->url.len > loc->value.len || ngx_rstrncmp(loc->value.data, uc->url.data, uc->url.len) != 0) { + + /* + * 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() + */ + *location = *loc; return NGX_OK; } /* TODO: proxy_reverse */ + r->headers_out.location = location; + + location->key.len = 0; + location->key.data = NULL; + location->value.len = uc->location->len + (loc->value.len - uc->url.len) + 1; if (!(location->value.data = ngx_palloc(r->pool, location->value.len))) { diff --git a/src/http/modules/proxy/ngx_http_proxy_parse.c b/src/http/modules/proxy/ngx_http_proxy_parse.c --- a/src/http/modules/proxy/ngx_http_proxy_parse.c +++ b/src/http/modules/proxy/ngx_http_proxy_parse.c @@ -155,6 +155,9 @@ int ngx_http_proxy_parse_status_line(ngx case ' ': state = sw_status_text; break; + case '.': /* IIS may send 403.1, 403.2, etc */ + state = sw_status_text; + break; case CR: state = sw_almost_done; break; diff --git a/src/http/modules/proxy/ngx_http_proxy_upstream.c b/src/http/modules/proxy/ngx_http_proxy_upstream.c --- a/src/http/modules/proxy/ngx_http_proxy_upstream.c +++ b/src/http/modules/proxy/ngx_http_proxy_upstream.c @@ -115,6 +115,7 @@ int ngx_http_proxy_request_upstream(ngx_ static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p) { size_t len; + ngx_int_t escape; ngx_uint_t i; ngx_buf_t *b; ngx_chain_t *chain; @@ -133,14 +134,20 @@ static ngx_chain_t *ngx_http_proxy_creat len = r->method_name.len; } + if (r->quoted_uri) { + escape = 2 * ngx_escape_uri(NULL, r->uri.data + uc->location->len, + r->uri.len - uc->location->len); + } else { + escape = 0; + } + len += uc->uri.len - + r->uri.len - uc->location->len + + r->uri.len - uc->location->len + escape + 1 + r->args.len /* 1 is for "?" */ + sizeof(http_version) - 1 + sizeof(connection_close_header) - 1 + 2; /* 2 is for "\r\n" at the header end */ - if (p->lcf->preserve_host && r->headers_in.host) { len += sizeof(host_header) - 1 + r->headers_in.host_name_len @@ -218,9 +225,16 @@ static ngx_chain_t *ngx_http_proxy_creat b->last = ngx_cpymem(b->last, uc->uri.data, uc->uri.len); - b->last = ngx_cpymem(b->last, - r->uri.data + uc->location->len, - r->uri.len - uc->location->len); + if (escape) { + ngx_escape_uri(b->last, r->uri.data + uc->location->len, + r->uri.len - uc->location->len); + b->last += r->uri.len - uc->location->len + escape; + + } else { + b->last = ngx_cpymem(b->last, + r->uri.data + uc->location->len, + r->uri.len - uc->location->len); + } if (r->args.len > 0) { *(b->last++) = '?'; @@ -422,7 +436,7 @@ static void ngx_http_proxy_init_upstream p->upstream->output_chain_ctx = output; - output->sendfile = r->sendfile; + output->sendfile = r->connection->sendfile; output->pool = r->pool; output->bufs.num = 1; output->tag = (ngx_buf_tag_t) &ngx_http_proxy_module; @@ -737,8 +751,7 @@ static void ngx_http_proxy_send_request( if (rc == NGX_AGAIN) { ngx_add_timer(c->write, p->lcf->send_timeout); - c->write->available = /* STUB: lowat */ 0; - if (ngx_handle_write_event(c->write, NGX_LOWAT_EVENT) == NGX_ERROR) { + if (ngx_handle_write_event(c->write, p->lcf->send_lowat) == NGX_ERROR) { ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } @@ -1172,6 +1185,7 @@ static void ngx_http_proxy_send_response r = p->request; r->headers_out.status = p->upstream->status; + r->headers_out.status_line = p->upstream->status_line; #if 0 r->headers_out.content_length_n = -1; @@ -1298,11 +1312,10 @@ static void ngx_http_proxy_send_response */ ep->cyclic_temp_file = 1; - r->sendfile = 0; + r->connection->sendfile = 0; } else { ep->cyclic_temp_file = 0; - r->sendfile = 1; } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); diff --git a/src/http/ngx_http_copy_filter.c b/src/http/ngx_http_copy_filter.c --- a/src/http/ngx_http_copy_filter.c +++ b/src/http/ngx_http_copy_filter.c @@ -79,7 +79,7 @@ ngx_int_t ngx_http_copy_filter(ngx_http_ ngx_http_create_ctx(r, ctx, ngx_http_copy_filter_module, sizeof(ngx_output_chain_ctx_t), NGX_ERROR); - ctx->sendfile = r->sendfile; + ctx->sendfile = r->connection->sendfile; ctx->need_in_memory = r->filter_need_in_memory; ctx->need_in_temp = r->filter_need_temporary; diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -204,6 +204,13 @@ static ngx_command_t ngx_http_core_comm 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, @@ -505,11 +512,11 @@ ngx_int_t ngx_http_find_location_config( r->connection->log->log_level = clcf->err_log->log_level; } - if (!(ngx_io.flags & NGX_IO_SENDFILE) || !clcf->sendfile) { - r->sendfile = 0; + if ((ngx_io.flags & NGX_IO_SENDFILE) && clcf->sendfile) { + r->connection->sendfile = 1; } else { - r->sendfile = 1; + r->connection->sendfile = 0; } if (!clcf->tcp_nopush) { @@ -1387,6 +1394,7 @@ static void *ngx_http_core_create_loc_co lcf->client_body_timeout = NGX_CONF_UNSET_MSEC; lcf->sendfile = 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; @@ -1477,6 +1485,7 @@ static char *ngx_http_core_merge_loc_con prev->client_body_timeout, 60000); ngx_conf_merge_value(conf->sendfile, prev->sendfile, 0); ngx_conf_merge_value(conf->tcp_nopush, prev->tcp_nopush, 0); + ngx_conf_merge_value(conf->tcp_nodelay, prev->tcp_nodelay, 0); 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, @@ -1795,9 +1804,9 @@ static char *ngx_set_error_log(ngx_conf_ static char *ngx_http_lowat_check(ngx_conf_t *cf, void *post, void *data) { -#if (HAVE_LOWAT_EVENT) + ssize_t *np = data; - ssize_t *np = data; +#if __FreeBSD__ if (*np >= ngx_freebsd_net_inet_tcp_sendspace) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, @@ -1808,11 +1817,13 @@ static char *ngx_http_lowat_check(ngx_co return NGX_CONF_ERROR; } -#else +#elif !(HAVE_SO_SNDLOWAT) ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "\"send_lowat\" is not supported, ignored"); + *np = 0; + #endif return NGX_CONF_OK; diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -172,6 +172,7 @@ struct ngx_http_core_loc_conf_s { 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 msie_padding; /* msie_padding */ diff --git a/src/http/ngx_http_header_filter.c b/src/http/ngx_http_header_filter.c --- a/src/http/ngx_http_header_filter.c +++ b/src/http/ngx_http_header_filter.c @@ -150,6 +150,7 @@ static ngx_int_t ngx_http_header_filter( len = sizeof("HTTP/1.x ") - 1 + 2 + 2; /* status line */ + if (r->headers_out.status_line.len) { len += r->headers_out.status_line.len; #if (NGX_SUPPRESS_WARN) diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -217,8 +217,11 @@ ngx_int_t ngx_http_parse_request_line(ng state = sw_http_09; break; case '.': + r->complex_uri = 1; + state = sw_uri; + break; case '%': - r->complex_uri = 1; + r->quoted_uri = 1; state = sw_uri; break; case '/': @@ -259,7 +262,7 @@ ngx_int_t ngx_http_parse_request_line(ng state = sw_after_slash_in_uri; break; case '%': - r->complex_uri = 1; + r->quoted_uri = 1; state = sw_uri; break; case '?': @@ -522,7 +525,7 @@ ngx_int_t ngx_http_parse_header_line(ngx break; } - /* IIS can send duplicate "HTTP/1.1 ..." lines */ + /* IIS may send the duplicate "HTTP/1.1 ..." lines */ if (ch == '/' && r->proxy && p - r->header_start == 5 diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -550,7 +550,7 @@ static void ngx_http_process_request_lin return; } - if (r->complex_uri) { + if (r->complex_uri || r->quoted_uri) { rc = ngx_http_parse_complex_uri(r); if (rc == NGX_HTTP_INTERNAL_SERVER_ERROR) { @@ -1318,8 +1318,7 @@ static void ngx_http_set_write_handler(n ngx_add_timer(wev, clcf->send_timeout); } - wev->available = clcf->send_lowat; - if (ngx_handle_write_event(wev, NGX_LOWAT_EVENT) == NGX_ERROR) { + if (ngx_handle_write_event(wev, clcf->send_lowat) == NGX_ERROR) { ngx_http_close_request(r, 0); ngx_http_close_connection(r->connection); } @@ -1354,9 +1353,7 @@ void ngx_http_writer(ngx_event_t *wev) ngx_http_core_module); ngx_add_timer(wev, clcf->send_timeout); - wev->available = clcf->send_lowat; - - if (ngx_handle_write_event(wev, NGX_LOWAT_EVENT) == NGX_ERROR) { + if (ngx_handle_write_event(wev, clcf->send_lowat) == NGX_ERROR) { ngx_http_close_request(r, 0); ngx_http_close_connection(r->connection); } @@ -1371,9 +1368,8 @@ void ngx_http_writer(ngx_event_t *wev) clcf = ngx_http_get_module_loc_conf(r->main ? r->main : r, ngx_http_core_module); - wev->available = clcf->send_lowat; - - if (ngx_handle_write_event(wev, NGX_LOWAT_EVENT) == NGX_ERROR) { + + if (ngx_handle_write_event(wev, clcf->send_lowat) == NGX_ERROR) { ngx_http_close_request(r, 0); ngx_http_close_connection(r->connection); } @@ -1394,9 +1390,7 @@ void ngx_http_writer(ngx_event_t *wev) ngx_add_timer(wev, clcf->send_timeout); } - wev->available = clcf->send_lowat; - - if (ngx_handle_write_event(wev, NGX_LOWAT_EVENT) == NGX_ERROR) { + if (ngx_handle_write_event(wev, clcf->send_lowat) == NGX_ERROR) { ngx_http_close_request(r, 0); ngx_http_close_connection(r->connection); } @@ -1541,6 +1535,7 @@ static ngx_int_t ngx_http_read_discarded static void ngx_http_set_keepalive(ngx_http_request_t *r) { + int tcp_nodelay; ngx_int_t i; ngx_buf_t *b, *f; ngx_event_t *rev, *wev; @@ -1684,7 +1679,26 @@ static void ngx_http_set_keepalive(ngx_h ngx_http_close_connection(c); return; } + c->tcp_nopush = NGX_TCP_NOPUSH_UNSET; + + } else { + if (clcf->tcp_nodelay && !c->tcp_nodelay) { + tcp_nodelay = 1; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay"); + + 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_close_connection(c); + return; + } + + c->tcp_nodelay = 1; + } } #if 0 @@ -2055,6 +2069,18 @@ void ngx_http_close_connection(ngx_conne ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "close http connection: %d", c->fd); +#if (NGX_OPENSSL) + + if (c->ssl) { + if (ngx_ssl_shutdown(c) == NGX_AGAIN) { + c->read->event_handler = ngx_ssl_close_handler; + c->write->event_handler = ngx_ssl_close_handler; + return; + } + } + +#endif + #if (NGX_STAT_STUB) (*ngx_stat_active)--; #endif diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -307,8 +307,10 @@ struct ngx_http_request_s { /* URI is not started with '/' - "GET http://" */ unsigned unusual_uri:1; #endif - /* URI with "/.", "%" and on Win32 with "//" */ + /* URI with "/." and on Win32 with "//" */ unsigned complex_uri:1; + /* URI with "%" */ + unsigned quoted_uri:1; unsigned header_timeout_set:1; unsigned proxy:1; @@ -320,9 +322,6 @@ struct ngx_http_request_s { #endif unsigned pipeline:1; - /* can we use sendfile ? */ - unsigned sendfile:1; - unsigned plain_http:1; unsigned chunked:1; unsigned header_only:1; diff --git a/src/imap/ngx_imap_proxy.c b/src/imap/ngx_imap_proxy.c --- a/src/imap/ngx_imap_proxy.c +++ b/src/imap/ngx_imap_proxy.c @@ -333,8 +333,7 @@ static void ngx_imap_proxy_handler(ngx_e } if (n == NGX_AGAIN || n < (ssize_t) size) { - dst->write->available = 0; - if (ngx_handle_write_event(dst->write, NGX_LOWAT_EVENT) + if (ngx_handle_write_event(dst->write, /* TODO: LOWAT */ 0) == NGX_ERROR) { ngx_imap_proxy_close_session(s); diff --git a/src/os/unix/ngx_errno.c b/src/os/unix/ngx_errno.c --- a/src/os/unix/ngx_errno.c +++ b/src/os/unix/ngx_errno.c @@ -49,7 +49,8 @@ ngx_int_t ngx_strerror_r(int err, char * str = strerror_r(err, errstr, size); if (str != errstr) { - return ngx_cpystrn(errstr, str, size) - (u_char *) errstr; + return ngx_cpystrn((u_char *) errstr, (u_char *) str, size) + - (u_char *) errstr; } for (len = 0; len < size; len++) { diff --git a/src/os/unix/ngx_freebsd.h b/src/os/unix/ngx_freebsd.h --- a/src/os/unix/ngx_freebsd.h +++ b/src/os/unix/ngx_freebsd.h @@ -11,7 +11,6 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit); - extern int ngx_freebsd_kern_osreldate; extern int ngx_freebsd_hw_ncpu; extern int ngx_freebsd_net_inet_tcp_sendspace; diff --git a/src/os/unix/ngx_freebsd_config.h b/src/os/unix/ngx_freebsd_config.h --- a/src/os/unix/ngx_freebsd_config.h +++ b/src/os/unix/ngx_freebsd_config.h @@ -34,13 +34,13 @@ #include #include +#include /* TCP_NODELAY, TCP_NOPUSH */ #include #include #include /* setproctitle() before 4.1 */ #include #include -#include /* TCP_NOPUSH */ #if __FreeBSD_version < 400017 diff --git a/src/os/unix/ngx_freebsd_init.c b/src/os/unix/ngx_freebsd_init.c --- a/src/os/unix/ngx_freebsd_init.c +++ b/src/os/unix/ngx_freebsd_init.c @@ -193,6 +193,7 @@ ngx_int_t ngx_os_init(ngx_log_t *log) ngx_ncpu = ngx_freebsd_hw_ncpu; } + return ngx_posix_init(log); } @@ -221,5 +222,6 @@ void ngx_os_status(ngx_log_t *log) } } + ngx_posix_status(log); } diff --git a/src/os/unix/ngx_linux.h b/src/os/unix/ngx_linux.h --- a/src/os/unix/ngx_linux.h +++ b/src/os/unix/ngx_linux.h @@ -8,6 +8,9 @@ #define _NGX_LINUX_H_INCLUDED_ +ngx_int_t ngx_init_setproctitle(ngx_log_t *log); +void ngx_setproctitle(char *title); + ngx_chain_t *ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit); diff --git a/src/os/unix/ngx_linux_config.h b/src/os/unix/ngx_linux_config.h --- a/src/os/unix/ngx_linux_config.h +++ b/src/os/unix/ngx_linux_config.h @@ -39,13 +39,13 @@ #include #include +#include /* TCP_NODELAY, TCP_CORK */ #include #include #include /* tzset() */ #include #include -#include /* TCP_CORK */ #include @@ -94,8 +94,10 @@ extern ssize_t sendfile(int s, int fd, i #define HAVE_SELECT_CHANGE_TIMEOUT 1 #endif - -#define ngx_setproctitle(title) +#ifndef NGX_SETPROCTITLE_USES_ENV +#define NGX_SETPROCTITLE_USES_ENV 1 +#define NGX_SETPROCTITLE_PAD '\0' +#endif #endif /* _NGX_LINUX_CONFIG_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_linux_init.c b/src/os/unix/ngx_linux_init.c --- a/src/os/unix/ngx_linux_init.c +++ b/src/os/unix/ngx_linux_init.c @@ -30,7 +30,8 @@ ngx_os_io_t ngx_os_io = { ngx_int_t ngx_os_init(ngx_log_t *log) { - int name[2], len; + int name[2]; + size_t len; name[0] = CTL_KERN; name[1] = KERN_OSTYPE; @@ -63,6 +64,8 @@ ngx_int_t ngx_os_init(ngx_log_t *log) } + ngx_init_setproctitle(log); + return ngx_posix_init(log); } @@ -76,5 +79,6 @@ void ngx_os_status(ngx_log_t *log) ngx_log_error(NGX_LOG_INFO, log, 0, "sysctl(KERN_RTSIGMAX): %d", ngx_linux_rtsig_max); + ngx_posix_status(log); } diff --git a/src/os/unix/ngx_process.c b/src/os/unix/ngx_process.c --- a/src/os/unix/ngx_process.c +++ b/src/os/unix/ngx_process.c @@ -12,10 +12,15 @@ static void ngx_execute_proc(ngx_cycle_t *cycle, void *data); -ngx_int_t ngx_process_slot; -ngx_socket_t ngx_channel; -ngx_int_t ngx_last_process; -ngx_process_t ngx_processes[NGX_MAX_PROCESSES]; + +int ngx_argc; +char **ngx_argv; +char **ngx_os_argv; + +ngx_int_t ngx_process_slot; +ngx_socket_t ngx_channel; +ngx_int_t ngx_last_process; +ngx_process_t ngx_processes[NGX_MAX_PROCESSES]; ngx_pid_t ngx_spawn_process(ngx_cycle_t *cycle, @@ -231,8 +236,23 @@ void ngx_process_get_status() return; } +#if (SOLARIS) + + /* + * Solaris always calls the signal handler for each exited process + * despite waitpid() may be already called for this process + */ + + if (err == NGX_ECHILD) { + ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, errno, + "waitpid() failed"); + } + +#endif + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, errno, "waitpid() failed"); + return; } diff --git a/src/os/unix/ngx_process.h b/src/os/unix/ngx_process.h --- a/src/os/unix/ngx_process.h +++ b/src/os/unix/ngx_process.h @@ -56,6 +56,9 @@ void ngx_process_get_status(void); #define ngx_sched_yield() sched_yield() +extern int ngx_argc; +extern char **ngx_argv; +extern char **ngx_os_argv; extern ngx_pid_t ngx_pid; extern ngx_socket_t ngx_channel; diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c --- a/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c @@ -14,7 +14,7 @@ static void ngx_start_worker_processes(n ngx_int_t type); static void ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo); static ngx_uint_t ngx_reap_childs(ngx_cycle_t *cycle); -static void ngx_master_exit(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx); +static void ngx_master_exit(ngx_cycle_t *cycle); static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data); static void ngx_channel_handler(ngx_event_t *ev); #if (NGX_THREADS) @@ -55,7 +55,7 @@ ngx_int_t ngx_threads_n; u_char master_process[] = "master process"; -void ngx_master_process_cycle(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx) +void ngx_master_process_cycle(ngx_cycle_t *cycle) { char *title; u_char *p; @@ -90,16 +90,16 @@ void ngx_master_process_cycle(ngx_cycle_ size = sizeof(master_process); - for (i = 0; i < ctx->argc; i++) { - size += ngx_strlen(ctx->argv[i]) + 1; + for (i = 0; i < ngx_argc; i++) { + size += ngx_strlen(ngx_argv[i]) + 1; } title = ngx_palloc(cycle->pool, size); p = ngx_cpymem(title, master_process, sizeof(master_process) - 1); - for (i = 0; i < ctx->argc; i++) { + for (i = 0; i < ngx_argc; i++) { *p++ = ' '; - p = ngx_cpystrn(p, (u_char *) ctx->argv[i], size); + p = ngx_cpystrn(p, (u_char *) ngx_argv[i], size); } ngx_setproctitle(title); @@ -149,7 +149,7 @@ void ngx_master_process_cycle(ngx_cycle_ } if (!live && (ngx_terminate || ngx_quit)) { - ngx_master_exit(cycle, ctx); + ngx_master_exit(cycle); } if (ngx_terminate) { @@ -231,7 +231,7 @@ void ngx_master_process_cycle(ngx_cycle_ if (ngx_change_binary) { ngx_change_binary = 0; ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "changing binary"); - ngx_new_binary = ngx_exec_new_binary(cycle, ctx->argv); + ngx_new_binary = ngx_exec_new_binary(cycle, ngx_argv); } if (ngx_noaccept) { @@ -244,14 +244,10 @@ void ngx_master_process_cycle(ngx_cycle_ } -void ngx_single_process_cycle(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx) +void ngx_single_process_cycle(ngx_cycle_t *cycle) { ngx_uint_t i; -#if 0 - ngx_setproctitle("single worker process"); -#endif - ngx_init_temp_number(); for (i = 0; ngx_modules[i]; i++) { @@ -269,7 +265,7 @@ void ngx_single_process_cycle(ngx_cycle_ ngx_process_events(cycle); if (ngx_terminate || ngx_quit) { - ngx_master_exit(cycle, ctx); + ngx_master_exit(cycle); } if (ngx_reconfigure) { @@ -547,7 +543,7 @@ static ngx_uint_t ngx_reap_childs(ngx_cy } -static void ngx_master_exit(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx) +static void ngx_master_exit(ngx_cycle_t *cycle) { ngx_delete_pidfile(cycle); diff --git a/src/os/unix/ngx_process_cycle.h b/src/os/unix/ngx_process_cycle.h --- a/src/os/unix/ngx_process_cycle.h +++ b/src/os/unix/ngx_process_cycle.h @@ -19,19 +19,13 @@ #define NGX_CMD_REOPEN 5 -typedef struct { - int argc; - char *const *argv; -} ngx_master_ctx_t; - - #define NGX_PROCESS_SINGLE 0 #define NGX_PROCESS_MASTER 1 #define NGX_PROCESS_WORKER 2 -void ngx_master_process_cycle(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx); -void ngx_single_process_cycle(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx); +void ngx_master_process_cycle(ngx_cycle_t *cycle); +void ngx_single_process_cycle(ngx_cycle_t *cycle); extern ngx_uint_t ngx_process; diff --git a/src/os/unix/ngx_setproctitle.c b/src/os/unix/ngx_setproctitle.c new file mode 100644 --- /dev/null +++ b/src/os/unix/ngx_setproctitle.c @@ -0,0 +1,143 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include + + +#if (NGX_SETPROCTITLE_USES_ENV) + +/* + * To change the process title in Linux and Solaris we have to set argv[1] + * to NULL and to copy the title to the same place where the argv[0] points to. + * However, argv[0] may be too small to hold a new title. Fortunately, Linux + * and Solaris store argv[] and environ[] one after another. So we should + * ensure that is the continuous memory and then we allocate the new memory + * for environ[] and copy it. After this we could use the memory starting + * from argv[0] for our process title. + * + * The Solaris's standard /bin/ps does not show the changed process title. + * You have to use "/usr/ucb/ps -w" instead. Besides, the UCB ps dos not + * show a new title if its length less than the origin command line length. + * To avoid it we append to a new title the origin command line in the + * parenthesis. + */ + +extern char **environ; + +static char *ngx_os_argv_last; + +ngx_int_t ngx_init_setproctitle(ngx_log_t *log) +{ + char *p; + size_t size; + ngx_uint_t i; + + size = 0; + + for (i = 0; environ[i]; i++) { + size += ngx_strlen(environ[i]) + 1; + } + + if (!(p = ngx_alloc(size, log))) { + return NGX_ERROR; + } + + ngx_os_argv_last = ngx_os_argv[0]; + + for (i = 0; ngx_os_argv[i]; i++) { + if (ngx_os_argv_last == ngx_os_argv[i]) { + ngx_os_argv_last = ngx_os_argv[i] + ngx_strlen(ngx_os_argv[i]) + 1; + } + } + + for (i = 0; environ[i]; i++) { + if (ngx_os_argv_last == environ[i]) { + + size = ngx_strlen(environ[i]) + 1; + ngx_os_argv_last = environ[i] + size; + + ngx_cpystrn(p, environ[i], size); + environ[i] = p; + p += size; + } + } + + ngx_os_argv_last--; + + return NGX_OK; +} + + +void ngx_setproctitle(char *title) +{ + u_char *p; + +#if (SOLARIS) + + ngx_int_t i; + size_t size; + +#endif + + ngx_os_argv[1] = NULL; + + p = ngx_cpystrn((u_char *) ngx_os_argv[0], "nginx: ", + ngx_os_argv_last - ngx_os_argv[0]); + + p = ngx_cpystrn(p, (u_char *) title, ngx_os_argv_last - (char *) p); + +#if (SOLARIS) + + size = 0; + + for (i = 0; i < ngx_argc; i++) { + size += ngx_strlen(ngx_argv[i]) + 1; + } + + if (size > (size_t) ((char *) p - ngx_os_argv[0])) { + + /* + * ngx_setproctitle() is too rare operation so we use + * the non-optimized copies + */ + + p = ngx_cpystrn(p, (u_char *) " (", ngx_os_argv_last - (char *) p); + + for (i = 0; i < ngx_argc; i++) { + p = ngx_cpystrn(p, (u_char *) ngx_argv[i], + ngx_os_argv_last - (char *) p); + p = ngx_cpystrn(p, (u_char *) " ", ngx_os_argv_last - (char *) p); + } + + if (*(p - 1) == ' ') { + *(p - 1) = ')'; + } + } + +#endif + + if (ngx_os_argv_last - (char *) p) { + ngx_memset(p, NGX_SETPROCTITLE_PAD, ngx_os_argv_last - (char *) p); + } + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, + "setproctitle: \"%s\"", ngx_os_argv[0]); +} + + +#elif !defined(ngx_setproctitle) + +ngx_int_t ngx_init_setproctitle(ngx_log_t *log) +{ + return NGX_OK; +} + +void ngx_setproctitle(char *title) +{ +} + +#endif diff --git a/src/os/unix/ngx_socket.c b/src/os/unix/ngx_socket.c --- a/src/os/unix/ngx_socket.c +++ b/src/os/unix/ngx_socket.c @@ -16,7 +16,7 @@ * ioctl() and fcntl() are syscalls on at least FreeBSD 2.x, Linux 2.2 * and Solaris 7. * - * ioctl() in Linux 2.4 and 2.6 uses BKL, however fcntl(F_SETFL) uses it too. + * ioctl() in Linux 2.4 and 2.6 uses BKL, however, fcntl(F_SETFL) uses it too. */ diff --git a/src/os/unix/ngx_solaris.h b/src/os/unix/ngx_solaris.h --- a/src/os/unix/ngx_solaris.h +++ b/src/os/unix/ngx_solaris.h @@ -8,6 +8,10 @@ #define _NGX_SOLARIS_H_INCLUDED_ +ngx_int_t ngx_init_setproctitle(ngx_log_t *log); +void ngx_setproctitle(char *title); + + ngx_chain_t *ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit); diff --git a/src/os/unix/ngx_solaris_config.h b/src/os/unix/ngx_solaris_config.h --- a/src/os/unix/ngx_solaris_config.h +++ b/src/os/unix/ngx_solaris_config.h @@ -40,10 +40,10 @@ #include #include +#include /* TCP_NODELAY */ #include #include -#include #include #include /* IOV_MAX */ #include @@ -64,6 +64,11 @@ #endif +#if (HAVE_SENDFILE) +#include +#endif + + #if (HAVE_AIO) #include #endif @@ -80,7 +85,16 @@ #endif -#define ngx_setproctitle(title) +#ifndef HAVE_SO_SNDLOWAT +/* setsockopt(SO_SNDLOWAT) returns error "Option not supported by protocol" */ +#define HAVE_SO_SNDLOWAT 0 +#endif + + +#ifndef NGX_SETPROCTITLE_USES_ENV +#define NGX_SETPROCTITLE_USES_ENV 1 +#define NGX_SETPROCTITLE_PAD ' ' +#endif #endif /* _NGX_SOLARIS_CONFIG_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_solaris_init.c b/src/os/unix/ngx_solaris_init.c --- a/src/os/unix/ngx_solaris_init.c +++ b/src/os/unix/ngx_solaris_init.c @@ -53,6 +53,9 @@ ngx_int_t ngx_os_init(ngx_log_t *log) return NGX_ERROR; } + ngx_init_setproctitle(log); + + return ngx_posix_init(log); } diff --git a/src/os/unix/ngx_solaris_sendfilev_chain.c b/src/os/unix/ngx_solaris_sendfilev_chain.c --- a/src/os/unix/ngx_solaris_sendfilev_chain.c +++ b/src/os/unix/ngx_solaris_sendfilev_chain.c @@ -32,6 +32,10 @@ ngx_chain_t *ngx_solaris_sendfilev_chain return in; } + if (!c->sendfile) { + return ngx_writev_chain(c, in, limit); + } + send = 0; complete = 0; diff --git a/src/os/win32/ngx_process.c b/src/os/win32/ngx_process.c --- a/src/os/win32/ngx_process.c +++ b/src/os/win32/ngx_process.c @@ -8,6 +8,11 @@ #include +int ngx_argc; +char **ngx_argv; +char **ngx_os_argv; + + ngx_pid_t ngx_execute(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx) { return /* STUB */ 0; diff --git a/src/os/win32/ngx_process.h b/src/os/win32/ngx_process.h --- a/src/os/win32/ngx_process.h +++ b/src/os/win32/ngx_process.h @@ -32,8 +32,11 @@ ngx_pid_t ngx_execute(ngx_cycle_t *cycle #define ngx_sched_yield() Sleep(0) +extern int ngx_argc; +extern char **ngx_argv; +extern char **ngx_os_argv; -extern ngx_pid_t ngx_pid; +extern ngx_pid_t ngx_pid; #endif /* _NGX_PROCESS_H_INCLUDED_ */ diff --git a/src/os/win32/ngx_process_cycle.c b/src/os/win32/ngx_process_cycle.c --- a/src/os/win32/ngx_process_cycle.c +++ b/src/os/win32/ngx_process_cycle.c @@ -38,7 +38,7 @@ sig_atomic_t ngx_change_binary; -void ngx_master_process_cycle(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx) +void ngx_master_process_cycle(ngx_cycle_t *cycle) { ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "master mode is not supported"); @@ -46,7 +46,7 @@ void ngx_master_process_cycle(ngx_cycle_ } -void ngx_single_process_cycle(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx) +void ngx_single_process_cycle(ngx_cycle_t *cycle) { ngx_int_t i; diff --git a/src/os/win32/ngx_process_cycle.h b/src/os/win32/ngx_process_cycle.h --- a/src/os/win32/ngx_process_cycle.h +++ b/src/os/win32/ngx_process_cycle.h @@ -12,21 +12,13 @@ #include -typedef struct { - ngx_file_t pid; - u_char *name; - int argc; - char *const *argv; -} ngx_master_ctx_t; - - #define NGX_PROCESS_SINGLE 0 #define NGX_PROCESS_MASTER 1 #define NGX_PROCESS_WORKER 2 -void ngx_master_process_cycle(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx); -void ngx_single_process_cycle(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx); +void ngx_master_process_cycle(ngx_cycle_t *cycle); +void ngx_single_process_cycle(ngx_cycle_t *cycle); extern ngx_uint_t ngx_process;