Compare commits

...

9 Commits

Author SHA1 Message Date
Alexey Berezhok
842ddd80b1 Fixes 2026-07-19 00:23:35 +03:00
Alexey Berezhok
252170f667 Doc fixes 2026-07-01 23:49:42 +03:00
Alexey Berezhok
bf484db84e Remove debug include on build 2026-06-29 12:12:35 +03:00
Alexey Berezhok
1b37117a09 Update documentation 2026-06-27 00:32:35 +03:00
Alexey Berezhok
da7c38a0c6 Added GlobalLocationRewriteEngine 2026-06-27 00:24:56 +03:00
Alexey Berezhok
7b16ebc72f Fixed pass parameter on redirect 2026-06-26 01:03:37 +03:00
Alexey Berezhok
2cb396b1d0 - Added evaluation variables in docroot 2026-06-24 02:08:54 +03:00
Alexey Berezhok
c74ae3bec6 Fixed build of module package 2026-06-23 00:13:38 +03:00
Alexey Berezhok
7ed459c2ac Fixed build of module package 2026-06-23 00:12:18 +03:00
9 changed files with 490 additions and 71 deletions

2
.gitignore vendored
View File

@@ -6,5 +6,7 @@ logs
nginx-1.25.3 nginx-1.25.3
.zed .zed
tmpbuild tmpbuild
BUILDINFO.txt

View File

@@ -188,6 +188,7 @@ server {
} }
} }
```
Или сборка руками с помощью сборочного скрипта, вызывать в корне проекта: Или сборка руками с помощью сборочного скрипта, вызывать в корне проекта:

View File

@@ -15,6 +15,54 @@ The following directives are available in this module:
| Context | Available Levels | | Context | Available Levels |
|----------------|---------------------------------------------| |----------------|---------------------------------------------|
| `main`, `server`, `location` | ✓ All three levels supported | | `main`, `server`, `location` | ✓ All three levels supported |
| `GlobalLocation` | ✓ Global location level (new) |
**Syntax:**
```nginx
RewriteEngine on|off
```
**Possible Values:**
- `on` - Enable rewrite engine
- `off` - Disable rewrite engine (default)
**Example in nginx.conf:**
```nginx
http {
server {
RewriteEngine on;
location /blog/ {
# Rules apply here
}
location /static/ {
RewriteEngine off; # Disable for this location
}
}
}
```
**GlobalLocation Configuration (new):**
The `GlobalLocationRewriteEngine` directive allows setting the rewrite engine state for server-level locations:
```nginx
http {
server {
GlobalLocationRewriteEngine on;
# All locations in this server inherit the global setting
location /blog/ {
# RewriteEngine is enabled by default
}
location /static/ {
RewriteEngine off; # Override for this location if needed
}
}
}
```
**Syntax:** **Syntax:**
```nginx ```nginx
@@ -395,17 +443,18 @@ RewriteFallBack /handler.php?lang=ru
## Configuration Levels Summary ## Configuration Levels Summary
| Directive | http/main | server | location | .htaccess | | Directive | http/main | server | location | .htaccess |
|-----------------|-----------|--------|----------|-----------| |--------------------------|-----------|--------|----------|-----------|
| RewriteEngine | ✓ | ✓ | ✓ | ✓ | | RewriteEngine | ✓ | ✓ | ✓ | ✓ |
| RewriteRule | - | ✓ | | | | GlobalLocationRewriteEngine | - | ✓ | - | - |
| RewriteCond | - | ✓ | ✓ | ✓ | | RewriteRule | - | ✓ | ✓ | ✓ |
| RewriteBase | - | - | ✓ | ✓ | | RewriteCond | - | | ✓ | ✓ |
| RewriteOptions | | | ✓ | - | | RewriteBase | - | - | ✓ | |
| RewriteMap | - | ✓ | - | - | | RewriteOptions | | ✓ | | - |
| HtaccessEnable | | ✓ | - | - | | RewriteMap | - | ✓ | - | - |
| HtaccessName | ✓ | ✓ | - | - | | HtaccessEnable | ✓ | ✓ | - | - |
| RewriteFallBack | | | - | | | HtaccessName | | | - | - |
| RewriteFallBack | ✗ | ✗ | - | ✓ |
--- ---
@@ -458,6 +507,15 @@ The `RewriteFallBack` directive allows customizing the fallback path used when a
--- ---
### GlobalLocationRewriteEngine Directive (new)
The `GlobalLocationRewriteEngine` directive allows setting the rewrite engine state for server-level locations:
1. **Scope:** Configured only at the server block level within http context
2. **Inheritance:** All new locations inherit the global configuration by default
3. **Override Support:** Individual locations can still override the global setting with their own `RewriteEngine` directive
---
## Notes ## Notes
- Rewrite rules are processed in order as defined in configuration or `.htaccess` files - Rewrite rules are processed in order as defined in configuration or `.htaccess` files

View File

@@ -42,6 +42,27 @@ http {
} }
``` ```
**Конфигурация GlobalLocation (новое):**
Директива `GlobalLocationRewriteEngine` позволяет установить состояние движка переписывания для всех location этого сервера:
```nginx
http {
server {
GlobalLocationRewriteEngine on;
# Все location в этом сервере наследуют глобальную настройку
location /blog/ {
# RewriteEngine включён по умолчанию
}
location /static/ {
RewriteEngine off; # Можно переопределить для этой локации
}
}
}
```
--- ---
@@ -400,19 +421,29 @@ RewriteFallBack /handler.php?lang=ru
--- ---
### Директива GlobalLocationRewriteEngine (новое)
Директива `GlobalLocationRewriteEngine` позволяет установить состояние движка переписывания для всех location этого сервера:
1. **Область применения:** Настраивается только на уровне server внутри http контекста
2. **Наследование:** Все новые location наследуют глобальную конфигурацию по умолчанию
3. **Переопределение:** Отдельные location могут переопределить глобальную настройку своей собственной директивой `RewriteEngine`
---
## Сводка уровней конфигурации ## Сводка уровней конфигурации
| Директива | http/main | server | location | .htaccess | | Директива | http/main | server | location | .htaccess |
|------------------|-----------|--------|----------|-----------| |-------------------------------|-----------|--------|----------|-----------|
| RewriteEngine | ✓ | ✓ | ✓ | ✓ | | RewriteEngine | ✓ | ✓ | ✓ | ✓ |
| RewriteRule | - | ✓ | | | | GlobalLocationRewriteEngine | - | ✓ | - | - |
| RewriteCond | - | ✓ | ✓ | ✓ | | RewriteRule | - | ✓ | ✓ | ✓ |
| RewriteBase | - | - | ✓ | ✓ | | RewriteCond | - | | ✓ | ✓ |
| RewriteOptions | | | ✓ | - | | RewriteBase | - | - | ✓ | |
| RewriteMap | - | ✓ | - | - | | RewriteOptions | | ✓ | | - |
| HtaccessEnable | | ✓ | - | - | | RewriteMap | - | ✓ | - | - |
| HtaccessName | ✓ | ✓ | - | - | | HtaccessEnable | ✓ | ✓ | - | - |
| RewriteFallBack | | | - | | | HtaccessName | | | - | - |
| RewriteFallBack | ✗ | ✗ | - | ✓ |
--- ---
@@ -465,6 +496,13 @@ RewriteRule ^(.*)$ index.php?route=$1 [QSA,L]
1. **Кеширование:** Путь отката из `.htaccess` кэшируется на каждый запрос, чтобы избежать повторного разборов. 1. **Кеширование:** Путь отката из `.htaccess` кэшируется на каждый запрос, чтобы избежать повторного разборов.
2. **Логика отката:** Когда `try_files` завершается неудачей, модуль перенаправляет на заданный откат вместо `/index.php`. 2. **Логика отката:** Когда `try_files` завершается неудачей, модуль перенаправляет на заданный откат вместо `/index.php`.
3. **Сохранение строки запроса:** Исходная строка запроса сохраняется и добавляется к пути отката. 3. **Сохранение строки запроса:** Исходная строка запроса сохраняется и добавляется к пути отката.
### Директива GlobalLocationRewriteEngine (новое)
Директива `GlobalLocationRewriteEngine` позволяет установить состояние движка переписывания для всех location этого сервера:
1. **Область применения:** Настраивается только на уровне server внутри http контекста
2. **Наследование:** Все новые location наследуют глобальную конфигурацию по умолчанию
3. **Переопределение:** Отдельные location могут переопределить глобальную настройку своей собственной директивой `RewriteEngine`
``` ```
--- ---

149
extract_nginx_args.py Executable file
View File

@@ -0,0 +1,149 @@
#!/usr/bin/env python3
"""
Extract nginx configure arguments from `nginx -V` output.
Correctly handles quoted arguments with balanced single quotes.
Returns the parsed command line for use in package_preparer.sh.
"""
import subprocess
import sys
def parse_args(text):
"""
Разбить строку аргументов на список, корректно обрабатывая одинарные кавычки.
Пример:
--with-cc-opt='-O2 -g' --with-ld-opt='...'
должно разобиться на два элемента, а не на несколько битых строк.
"""
args = []
current = ""
in_single_quotes = False
for char in text:
if char == "'":
# Переходим в режим одинарных кавычек или выходим из него,
# и добавляем кавычку в текущий аргумент
in_single_quotes = not in_single_quotes
current += char
continue
if char == " " and not in_single_quotes:
# Пробел вне кавычек - конец аргумента
if current.strip():
args.append(current.strip())
current = ""
else:
# Добавляем символ в текущий аргумент
current += char
# Последний аргумент, если остался
if current.strip():
args.append(current.strip())
return args
def main(nginx_src_dir="."):
"""
Запустить nginx -V и извлечь аргументы конфигурации.
Args:
nginx_src_dir: каталог с исходниками nginx (обычно ./nginx-VER)
Returns:
0 на успех, 1 на ошибку. Вывод аргументов в stderr для использования bash скриптом.
"""
# Запускаем nginx -V через PATH, вывод идёт в stderr!
print(f"Running nginx -V...", file=sys.stderr)
try:
result = subprocess.run(["nginx", "-V"], capture_output=True, text=True)
except FileNotFoundError as e:
print(f"Error: Could not find 'nginx' in PATH: {e}", file=sys.stderr)
print("Make sure nginx is installed and added to PATH.", file=sys.stderr)
return 1
# Используем stderr вместо stdout!
output = result.stderr
if not output:
print(
f"Error: empty output from nginx -V. Return code: {result.returncode}",
file=sys.stderr,
)
return 1
# Ищем строку с configure arguments
for line in output.split("\n"):
if "configure arguments:" in line:
# Извлекаем всё после "configure arguments:"
config_line = line.split("configure arguments:", 1)[1]
# Парсим аргументы с учётом кавычек
args_list = parse_args(config_line)
print(f"Found configure arguments.", file=sys.stderr)
print(f"Parsed {len(args_list)} arguments.", file=sys.stderr)
for arg in args_list:
print(arg, file=sys.stderr)
# Удаляем параметры --add-dynamic-module, --with-ld-opt и все --with-*module
args_to_remove = ["--add-dynamic-module", "--with-ld-opt"]
filtered_args = []
for arg in args_list:
should_skip = False
for remove_arg in args_to_remove:
if arg.startswith(remove_arg):
should_skip = True
break
# Проверка на паттерн --with-*module
if not should_skip and arg.startswith("--with-"):
suffix = arg[7:] # Убираем "--with-"
if any(suffix.endswith(m) for m in ["module", "=dynamic"]):
should_skip = True
if not should_skip:
filtered_args.append(arg)
args_list = filtered_args
# Добавляем наш модуль в конец
args_list.append("--add-dynamic-module=../modules/mod_rewrite")
#args_list.append("--with-debug")
print(f"Added --add-dynamic-module=../modules/mod_rewrite", file=sys.stderr)
# Формируем команду configure и выводим в stderr
cmd_line = "./configure " + " ".join(args_list)
print("=== GENERATED CONFIGURE COMMAND ===", file=sys.stderr)
print(cmd_line, file=sys.stdout)
# Execute the generated configure command
result = subprocess.run(
cmd_line, shell=True, capture_output=True, text=True
)
# Print stdout and stderr of the configure command
if result.stdout:
print(result.stdout, file=sys.stdout)
if result.stderr:
print(result.stderr, file=sys.stderr)
if result.returncode != 0:
print(
f"Error: configure command failed with return code {result.returncode}",
file=sys.stderr,
)
return 1
return 0
print("Error: configure arguments line not found in nginx output", file=sys.stderr)
return 1
if __name__ == "__main__":
nginx_src_dir = "."
if len(sys.argv) > 1:
nginx_src_dir = sys.argv[1]
exit_code = main(nginx_src_dir)
sys.exit(exit_code)

View File

@@ -479,12 +479,11 @@ ngx_rewrite_apply_rule(ngx_rewrite_rule_t *rule, ngx_rewrite_ctx_t *ctx, ngx_str
"mod_rewrite: rewrite \"%V\" -> \"%V\" (flags=0x%xd, code=%d)", "mod_rewrite: rewrite \"%V\" -> \"%V\" (flags=0x%xd, code=%d)",
&ctx->uri, &newuri, rule->flags, rule->forced_responsecode); &ctx->uri, &newuri, rule->flags, rule->forced_responsecode);
/* Split out query string */
{ ngx_str_t new_args = r->args;
ngx_str_t new_args = r->args; ngx_rewrite_splitout_queryargs(r, &newuri, rule->flags, &new_args);
ngx_rewrite_splitout_queryargs(r, &newuri, rule->flags, &new_args); r->args = new_args;
r->args = new_args;
}
/* Check for absolute URI → redirect */ /* Check for absolute URI → redirect */
if (rule->flags & RULEFLAG_FORCEREDIRECT) { if (rule->flags & RULEFLAG_FORCEREDIRECT) {
@@ -539,7 +538,7 @@ ngx_rewrite_apply_rule(ngx_rewrite_rule_t *rule, ngx_rewrite_ctx_t *ctx, ngx_str
} }
} }
len = scheme.len + 3 + host.len + newuri.len + 3; len = scheme.len + 3 + host.len + newuri.len + 3 + new_args.len + 2;
if (port) { if (port) {
len += 6; /* :NNNNN */ len += 6; /* :NNNNN */
} }
@@ -568,6 +567,10 @@ ngx_rewrite_apply_rule(ngx_rewrite_rule_t *rule, ngx_rewrite_ctx_t *ctx, ngx_str
*p++ = '/'; *p++ = '/';
} }
p = ngx_cpymem(p, newuri.data, newuri.len); p = ngx_cpymem(p, newuri.data, newuri.len);
if (new_args.len > 0) {
*p++ = '?';
p = ngx_cpymem(p, new_args.data, new_args.len);
}
newuri.data = start; newuri.data = start;
newuri.len = p - start; newuri.len = p - start;
} }
@@ -587,8 +590,32 @@ ngx_rewrite_apply_rule(ngx_rewrite_rule_t *rule, ngx_rewrite_ctx_t *ctx, ngx_str
} }
ctx->redirect_url = newuri; ctx->redirect_url = newuri;
/* Append old query args if present */
if (new_args.len > 0 && ctx->redirect_url.data != NULL && ctx->redirect_url.len > 0) {
u_char *tmp_data;
size_t combined_len = ctx->redirect_url.len + 1 + new_args.len;
tmp_data = ngx_pnalloc(r->pool, combined_len);
if (tmp_data) {
u_char *start = tmp_data;
tmp_data = ngx_cpymem(tmp_data, ctx->redirect_url.data, ctx->redirect_url.len);
*tmp_data++ = '&';
tmp_data = ngx_cpymem(tmp_data, new_args.data, new_args.len);
ctx->redirect_url.data = start;
ctx->redirect_url.len = combined_len;
}
}
ctx->redirect_code = code; ctx->redirect_code = code;
/* Update URI to include appended args (for subsequent processing) */
ctx->uri = newuri; ctx->uri = newuri;
if (ctx->redirect_url.len > 0 && ctx->redirect_url.data != NULL
&& ngx_strcmp(ctx->uri.data, ctx->redirect_url.data) != 0) {
/* redirect_url has more data (args appended), copy it */
ctx->uri.data = ctx->redirect_url.data;
ctx->uri.len = ctx->redirect_url.len;
}
return RULE_RC_MATCH; return RULE_RC_MATCH;
} }
@@ -628,6 +655,7 @@ ngx_rewrite_apply_rule(ngx_rewrite_rule_t *rule, ngx_rewrite_ctx_t *ctx, ngx_str
} }
ctx->uri = newuri; ctx->uri = newuri;
ngx_str_null(&ctx->redirect_url); ngx_str_null(&ctx->redirect_url);
ctx->redirect_code = 0; ctx->redirect_code = 0;

View File

@@ -223,6 +223,8 @@ typedef struct {
/* Fallback to index.php with query string after try_files miss */ /* Fallback to index.php with query string after try_files miss */
ngx_int_t fallback_to_index; // 0|1: enable fallback mechanism ngx_int_t fallback_to_index; // 0|1: enable fallback mechanism
unsigned fallback_to_index_set:1; unsigned fallback_to_index_set:1;
ngx_int_t glstate;
unsigned glstate_set:1;
} ngx_http_apache_rewrite_srv_conf_t; } ngx_http_apache_rewrite_srv_conf_t;
/* /*

View File

@@ -35,6 +35,8 @@ static ngx_int_t ngx_http_apache_rewrite_postconfiguration(ngx_conf_t *cf);
static char *ngx_http_rewrite_engine(ngx_conf_t *cf, ngx_command_t *cmd, static char *ngx_http_rewrite_engine(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf); void *conf);
static char *ngx_http_rewrite_engine_global(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_rewrite_rule(ngx_conf_t *cf, ngx_command_t *cmd, static char *ngx_http_rewrite_rule(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf); void *conf);
static char *ngx_http_rewrite_cond(ngx_conf_t *cf, ngx_command_t *cmd, static char *ngx_http_rewrite_cond(ngx_conf_t *cf, ngx_command_t *cmd,
@@ -92,6 +94,12 @@ static ngx_command_t ngx_http_apache_rewrite_commands[] = {
0, 0,
0, 0,
NULL }, NULL },
{ ngx_string("GlobalLocationRewriteEngine"),
NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_http_rewrite_engine_global,
0,
0,
NULL },
{ ngx_string("RewriteRule"), { ngx_string("RewriteRule"),
NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE23, NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE23,
@@ -272,13 +280,11 @@ ngx_http_apache_rewrite_merge_srv_conf(ngx_conf_t *cf,
return NGX_CONF_OK; return NGX_CONF_OK;
} }
static ngx_http_apache_rewrite_loc_conf_t *
static void * ngx_http_apache_rewrite_create_loc_conf_(ngx_pool_t *pool){
ngx_http_apache_rewrite_create_loc_conf(ngx_conf_t *cf)
{
ngx_http_apache_rewrite_loc_conf_t *conf; ngx_http_apache_rewrite_loc_conf_t *conf;
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_apache_rewrite_loc_conf_t)); conf = ngx_pcalloc(pool, sizeof(ngx_http_apache_rewrite_loc_conf_t));
if (conf == NULL) { if (conf == NULL) {
return NULL; return NULL;
} }
@@ -286,8 +292,8 @@ ngx_http_apache_rewrite_create_loc_conf(ngx_conf_t *cf)
conf->state = ENGINE_DISABLED; conf->state = ENGINE_DISABLED;
conf->options = OPTION_NONE; conf->options = OPTION_NONE;
conf->rules = ngx_array_create(cf->pool, 4, sizeof(ngx_rewrite_rule_t)); conf->rules = ngx_array_create(pool, 4, sizeof(ngx_rewrite_rule_t));
conf->pending_conds = ngx_array_create(cf->pool, 4, conf->pending_conds = ngx_array_create(pool, 4,
sizeof(ngx_rewrite_cond_t)); sizeof(ngx_rewrite_cond_t));
if (conf->rules == NULL || conf->pending_conds == NULL) { if (conf->rules == NULL || conf->pending_conds == NULL) {
@@ -299,6 +305,12 @@ ngx_http_apache_rewrite_create_loc_conf(ngx_conf_t *cf)
return conf; return conf;
} }
static void *
ngx_http_apache_rewrite_create_loc_conf(ngx_conf_t *cf)
{
return ngx_http_apache_rewrite_create_loc_conf_(cf->pool);
}
static char * static char *
ngx_http_apache_rewrite_merge_loc_conf(ngx_conf_t *cf, ngx_http_apache_rewrite_merge_loc_conf(ngx_conf_t *cf,
@@ -775,6 +787,9 @@ ngx_htaccess_search_upward(ngx_http_request_t *r, u_char *docroot, size_t docroo
u_char *path_buf = (u_char *)ngx_palloc(r->pool, current_path->len + 1 + htaccess_name_len); u_char *path_buf = (u_char *)ngx_palloc(r->pool, current_path->len + 1 + htaccess_name_len);
size_t current_pos; size_t current_pos;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"mod_rewrite: try to find .htaccess %s, uri=\"%V\"", path_buf, &r->uri);
if (!path_buf) { if (!path_buf) {
return NGX_ERROR; return NGX_ERROR;
} }
@@ -792,6 +807,8 @@ ngx_htaccess_search_upward(ngx_http_request_t *r, u_char *docroot, size_t docroo
/* Iterate upward from current directory up to docroot */ /* Iterate upward from current directory up to docroot */
while (1) { while (1) {
/* Check if file exists at this level */ /* Check if file exists at this level */
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"mod_rewrite: try to find(1) .htaccess %s, uri=\"%V\"", path_buf, &r->uri);
struct stat st; struct stat st;
if (stat((char *)path_buf, &st) == 0 && ngx_is_file(&st)) { if (stat((char *)path_buf, &st) == 0 && ngx_is_file(&st)) {
/* Found .htaccess! */ /* Found .htaccess! */
@@ -812,6 +829,8 @@ ngx_htaccess_search_upward(ngx_http_request_t *r, u_char *docroot, size_t docroo
if (last_slash == NULL) { if (last_slash == NULL) {
/* Reached DocRoot without finding htaccess */ /* Reached DocRoot without finding htaccess */
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"mod_rewrite: try to find .htaccess %s, uri=\"%V\" error(1)", path_buf, &r->uri);
return NGX_ERROR; return NGX_ERROR;
} }
@@ -820,6 +839,8 @@ ngx_htaccess_search_upward(ngx_http_request_t *r, u_char *docroot, size_t docroo
if (current_pos < docroot_len) { if (current_pos < docroot_len) {
/* Reached or passed DocRoot - no htaccess found */ /* Reached or passed DocRoot - no htaccess found */
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"mod_rewrite: try to find .htaccess %s, uri=\"%V\" error(2)", path_buf, &r->uri);
return NGX_ERROR; return NGX_ERROR;
} }
@@ -1485,6 +1506,7 @@ ngx_http_apache_rewrite_location_handler(ngx_http_request_t *r)
ngx_str_t baseurl_htacess = ngx_null_string; ngx_str_t baseurl_htacess = ngx_null_string;
ngx_int_t options_htaccess = -1; ngx_int_t options_htaccess = -1;
ngx_int_t state_htaccess = -1; ngx_int_t state_htaccess = -1;
ngx_int_t global_enabled = 0;
(void)options_htaccess; (void)options_htaccess;
@@ -1492,12 +1514,30 @@ ngx_http_apache_rewrite_location_handler(ngx_http_request_t *r)
sconf = ngx_http_get_module_srv_conf(r, ngx_http_apache_rewrite_module); sconf = ngx_http_get_module_srv_conf(r, ngx_http_apache_rewrite_module);
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (lcf == NULL || lcf->state != ENGINE_ENABLED) { if (sconf != NULL && sconf->glstate_set == 1 && sconf->glstate == ENGINE_ENABLED) {
return NGX_DECLINED; global_enabled = 1;
} }
if (lcf == NULL || lcf->state != ENGINE_ENABLED) {
if (global_enabled == 1) {
if (lcf == NULL) {
lcf = ngx_http_apache_rewrite_create_loc_conf_(r->pool);
}
if (lcf == NULL) {
return NGX_DECLINED;
}
} else {
return NGX_DECLINED;
}
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"mod_rewrite: location handler engine enabled in location, uri=\"%V\"", &r->uri);
/* Check htaccess parsing enable */ /* Check htaccess parsing enable */
if (!sconf->htaccess_enable_set || sconf->htaccess_enable != 1) { if (!sconf->htaccess_enable_set || sconf->htaccess_enable != 1) {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"mod_rewrite: location handler htaccess disabled, uri=\"%V\"", &r->uri);
/* Use only location rules */ /* Use only location rules */
if (lcf->rules->nelts == 0) { if (lcf->rules->nelts == 0) {
return NGX_DECLINED; return NGX_DECLINED;
@@ -1533,20 +1573,56 @@ ngx_http_apache_rewrite_location_handler(ngx_http_request_t *r)
u_char *htaccess_name = sconf->htaccess_name.data ? (u_char *)sconf->htaccess_name.data : (u_char *)".htaccess"; u_char *htaccess_name = sconf->htaccess_name.data ? (u_char *)sconf->htaccess_name.data : (u_char *)".htaccess";
size_t htaccess_name_len = sconf->htaccess_name.data ? sconf->htaccess_name.len : 9; size_t htaccess_name_len = sconf->htaccess_name.data ? sconf->htaccess_name.len : 9;
/* Build initial path: docroot + r->uri */
ngx_str_t current_path; ngx_str_t current_path;
rc = ngx_htaccess_build_path(r, clcf->root.data, clcf->root.len, &current_path, htaccess_name, htaccess_name_len); ngx_str_t evaluated_root = {0, NULL};
size_t evaluated_root_len = 0;
/* Check if root contains variables and evaluate them */
if (clcf->root_lengths != NULL) {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"mod_rewrite: root has script variables, evaluating");
/* Run the script to evaluate variables in clcf->root */
if (ngx_http_script_run(r, &evaluated_root,
clcf->root_lengths->elts, 0,
clcf->root_values->elts) == NULL) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"mod_rewrite: failed to evaluate root path script");
return NGX_ERROR;
}
evaluated_root_len = evaluated_root.len > 0 ? evaluated_root.len : 0;
/* LOG: Show evaluated root */
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"mod_rewrite: evaluated root path len=%uz", evaluated_root_len);
} else {
/* LOG: No script variables in root */
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"mod_rewrite: root has no script variables, using clcf->root directly");
}
/* Build initial path: docroot + r->uri using evaluated or original root */
rc = ngx_htaccess_build_path(r,
evaluated_root.data ? evaluated_root.data : clcf->root.data,
evaluated_root.len > 0 ? evaluated_root.len : clcf->root.len,
&current_path, htaccess_name, htaccess_name_len);
ngx_str_t htaccess_docroot = ngx_null_string; ngx_str_t htaccess_docroot = ngx_null_string;
/* Remove last component (filename) to search from parent directory */ /* Remove last component (filename) to search from parent directory */
if (rc == NGX_OK && current_path.len > 0) { if (rc == NGX_OK && current_path.len > 0) {
/* Search upward for .htaccess file */ /* Search upward for .htaccess file - use evaluated root here too! */
rc = ngx_htaccess_search_upward(r, clcf->root.data, clcf->root.len, &current_path, rc = ngx_htaccess_search_upward(r,
htaccess_name, htaccess_name_len, &htaccess_path); evaluated_root.data ? evaluated_root.data : clcf->root.data,
evaluated_root.len > 0 ? evaluated_root.len : clcf->root.len,
&current_path, htaccess_name, htaccess_name_len,
&htaccess_path);
if (rc == NGX_ERROR) { if (rc == NGX_ERROR) {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"mod_rewrite: location handler .htaccess not found, uri=\"%V\"", &r->uri);
/* File not found — use only location rules */ /* File not found — use only location rules */
ctx = ngx_http_get_module_ctx(r, ngx_http_apache_rewrite_module); ctx = ngx_http_get_module_ctx(r, ngx_http_apache_rewrite_module);
if (ctx && ctx->end) { if (ctx && ctx->end) {
@@ -1558,18 +1634,35 @@ ngx_http_apache_rewrite_location_handler(ngx_http_request_t *r)
return ngx_process_rules_result(rc, ctx, r, 0); return ngx_process_rules_result(rc, ctx, r, 0);
} }
htaccess_docroot.data = ngx_pcalloc(r->pool, htaccess_path.len); /* LOG: Show found htaccess path */
size_t htaccess_docroot_vlen = htaccess_path.len - (clcf->root.len + 1) - htaccess_name_len; if (rc == NGX_OK && htaccess_path.data) {
if ((long)htaccess_docroot_vlen < 0) htaccess_docroot_vlen = 0; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
ngx_memcpy(htaccess_docroot.data, htaccess_path.data + clcf->root.len + 1, htaccess_docroot_vlen); "mod_rewrite: found .htaccess at: %V", &htaccess_path);
} else {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"mod_rewrite: .htaccess not found, uri=%V", &r->uri);
}
htaccess_docroot.len = htaccess_path.len - (clcf->root.len + 1) - htaccess_name_len; /* Extract htaccess_docroot path - now correctly works with evaluated root */
size_t used_root_len = (evaluated_root.len > 0) ? evaluated_root.len : clcf->root.len;
htaccess_docroot.data = ngx_pcalloc(r->pool, htaccess_path.len);
size_t htaccess_docroot_vlen = htaccess_path.len - (used_root_len + 1) - htaccess_name_len;
if ((long)htaccess_docroot_vlen < 0) htaccess_docroot_vlen = 0;
ngx_memcpy(htaccess_docroot.data, htaccess_path.data + used_root_len + 1, htaccess_docroot_vlen);
htaccess_docroot.len = htaccess_path.len - (used_root_len + 1) - htaccess_name_len;
} else {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"mod_rewrite: failed to build current path for .htaccess search");
} }
/* Check if htaccess file exists */ /* Check if htaccess file exists */
struct stat st; struct stat st;
if (!htaccess_path.data || stat((char *)htaccess_path.data, &st) == -1) { if (!htaccess_path.data || stat((char *)htaccess_path.data, &st) == -1) {
/* File does not exist — use only location rules */ /* File does not exist — use only location rules */
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"mod_rewrite: location handler .htaccess nto found by stat, uri=\"%V\"", &r->uri);
if (lcf->rules->nelts == 0) { if (lcf->rules->nelts == 0) {
return NGX_DECLINED; return NGX_DECLINED;
} }
@@ -1641,6 +1734,9 @@ ngx_http_apache_rewrite_location_handler(ngx_http_request_t *r)
/* If no cached rules, parse .htaccess file */ /* If no cached rules, parse .htaccess file */
if (combined_rules == NULL) { if (combined_rules == NULL) {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"mod_rewrite: location handler rules from .htaccess not in cache reread, .htaccess=\"%V\"", &htaccess_path);
parsed_rules = ngx_htaccess_parse_file_from_ha(r, &htaccess_path); parsed_rules = ngx_htaccess_parse_file_from_ha(r, &htaccess_path);
if (!parsed_rules){ if (!parsed_rules){
@@ -1660,11 +1756,17 @@ ngx_http_apache_rewrite_location_handler(ngx_http_request_t *r)
/* Store in cache — add/update entry in linked list */ /* Store in cache — add/update entry in linked list */
ngx_htaccess_update_cache(r, htaccess_path, st.st_mtime, parsed_rules); ngx_htaccess_update_cache(r, htaccess_path, st.st_mtime, parsed_rules);
} else {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"mod_rewrite: location handler get rules from cache .htaccess, .htaccess=\"%V\"", &htaccess_path);
} }
if (state_htaccess == ENGINE_DISABLED) if (state_htaccess == ENGINE_DISABLED)
return NGX_DECLINED; return NGX_DECLINED;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"mod_rewrite: location handler engine enabled in .htaccess, .htaccess=\"%V\"", &htaccess_path);
/* Ensure ctx exists */ /* Ensure ctx exists */
if (ctx == NULL) { if (ctx == NULL) {
ctx = ngx_pcalloc(r->pool, sizeof(ngx_rewrite_ctx_t)); ctx = ngx_pcalloc(r->pool, sizeof(ngx_rewrite_ctx_t));
@@ -1685,7 +1787,8 @@ ngx_http_apache_rewrite_location_handler(ngx_http_request_t *r)
/* Combine location rules with .htaccess rules (.htaccess has priority - added first) */ /* Combine location rules with .htaccess rules (.htaccess has priority - added first) */
ngx_int_t final_rc; ngx_int_t final_rc;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"mod_rewrite: location handler rules from .htaccess found %d, .htaccess=\"%V\"", combined_rules->nelts, &htaccess_path);
if (combined_rules->nelts > 0 && lcf->rules->nelts > 0) { if (combined_rules->nelts > 0 && lcf->rules->nelts > 0) {
/* Create combined array: htaccess rules first, then location rules */ /* Create combined array: htaccess rules first, then location rules */
ngx_array_t *final_rules = ngx_array_create(r->pool, ngx_array_t *final_rules = ngx_array_create(r->pool,
@@ -2177,6 +2280,48 @@ ngx_http_rewrite_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return NGX_CONF_OK; return NGX_CONF_OK;
} }
/*
* GlobalLocationRewriteEngine on|off
*/
static char *
ngx_http_rewrite_engine_global(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_str_t *value;
ngx_http_apache_rewrite_srv_conf_t *sconf = NULL;
value = cf->args->elts;
/* Определяем контекст: проверяем cmd_type */
if (cf->cmd_type & NGX_HTTP_SRV_CONF) {
/* Server контекст */
sconf = ngx_http_conf_get_module_srv_conf(cf,
ngx_http_apache_rewrite_module);
if (sconf == NULL) {
return NGX_CONF_OK;
}
if (ngx_strcasecmp(value[1].data, (u_char *) "on") == 0) {
sconf->glstate = ENGINE_ENABLED;
sconf->glstate_set = 1;
} else if (ngx_strcasecmp(value[1].data, (u_char *) "off") == 0) {
sconf->glstate = ENGINE_DISABLED;
sconf->glstate_set = 1;
} else {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"GlobalLocationRewriteEngine: invalid value \"%V\"", &value[1]);
return NGX_CONF_ERROR;
}
} else {
/* Непредвиденный контекст */
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"GlobalLocationRewriteEngine: unexpected context");
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
/* /*
* Helper: strip surrounding brackets [...] * Helper: strip surrounding brackets [...]

View File

@@ -84,7 +84,7 @@ prepare)
--transform='s,^,nginx-mod-rewrite-'$pkg_ver'/modules/,' --transform='s,^,nginx-mod-rewrite-'$pkg_ver'/modules/,'
tar -rf "tmpbuild/nginx-mod-rewrite-$pkg_ver.tar" \ tar -rf "tmpbuild/nginx-mod-rewrite-$pkg_ver.tar" \
-C . LICENSE package_preparer.sh \ -C . LICENSE package_preparer.sh extract_nginx_args.py \
--transform='s,^,nginx-mod-rewrite-'$pkg_ver'/,' --transform='s,^,nginx-mod-rewrite-'$pkg_ver'/,'
gzip -f "tmpbuild/nginx-mod-rewrite-$pkg_ver.tar" gzip -f "tmpbuild/nginx-mod-rewrite-$pkg_ver.tar"
@@ -176,14 +176,14 @@ installdeps)
# Determine package manager and install nginx # Determine package manager and install nginx
if command -v dnf >/dev/null 2>&1; then if command -v dnf >/dev/null 2>&1; then
PKG_MGR="dnf" PKG_MGR="dnf"
$PKG_MGR install -y nginx openssl-devel pcre-devel zlib-devel rpm-build gcc gcc-c++ make wget $PKG_MGR install -y nginx openssl-devel pcre-devel zlib-devel rpm-build gcc gcc-c++ make wget python3
elif command -v yum >/dev/null 2>&1; then elif command -v yum >/dev/null 2>&1; then
PKG_MGR="yum" PKG_MGR="yum"
$PKG_MGR install -y nginx openssl-devel pcre-devel zlib-devel rpm-build gcc gcc-c++ make wget $PKG_MGR install -y nginx openssl-devel pcre-devel zlib-devel rpm-build gcc gcc-c++ make wget python3
elif command -v apt-get >/dev/null 2>&1; then elif command -v apt-get >/dev/null 2>&1; then
PKG_MGR="apt-get" PKG_MGR="apt-get"
apt-get update apt-get update
$PKG_MGR install -y nginx debhelper-compat dh-autoreconf libssl-dev libpcre2-dev zlib1g-dev make gcc build-essential wget $PKG_MGR install -y nginx debhelper-compat dh-autoreconf libssl-dev libpcre2-dev zlib1g-dev make gcc build-essential wget python3
else else
echo "Unsupported package manager." echo "Unsupported package manager."
exit 1 exit 1
@@ -191,15 +191,19 @@ installdeps)
;; ;;
installmod) installmod)
if command -v dnf >/dev/null 2>&1 || command -v yum >/dev/null 2>&1; then if command -v dnf >/dev/null 2>&1 || command -v yum >/dev/null 2>&1; then
mkdir -p /usr/share/nginx/modules /etc/nginx/modules mkdir -p /usr/share/nginx/modules /usr/lib64/nginx/modules/
cp *.so /usr/lib64/nginx/modules/ cp *.so /usr/lib64/nginx/modules/
echo 'load_module "/usr/lib64/nginx/modules/ngx_http_apache_rewrite_module.so";' \ if [ ! -e "/usr/share/nginx/modules/ngx_http_apache_rewrite_module.conf" ]; then
> /usr/share/nginx/modules/ngx_http_apache_rewrite_module.conf echo 'load_module "/usr/lib64/nginx/modules/ngx_http_apache_rewrite_module.so";' \
> /usr/share/nginx/modules/ngx_http_apache_rewrite_module.conf
fi
else else
mkdir -p /usr/share/nginx/modules/ /etc/nginx/modules mkdir -p /usr/share/nginx/modules/ /etc/nginx/modules
cp *.so /usr/share/nginx/modules/ cp *.so /usr/share/nginx/modules/
echo 'load_module "/usr/share/nginx/modules/ngx_http_apache_rewrite_module.so";' \ if [ ! -e "/etc/nginx/modules/ngx_http_apache_rewrite_module.conf" ]; then
> /etc/nginx/modules/ngx_http_apache_rewrite_module.conf echo 'load_module "/usr/share/nginx/modules/ngx_http_apache_rewrite_module.so";' \
> /etc/nginx/modules/ngx_http_apache_rewrite_module.conf
fi
fi fi
;; ;;
packageprep) packageprep)
@@ -209,14 +213,14 @@ packageprep)
# Determine package manager and install nginx # Determine package manager and install nginx
if command -v dnf >/dev/null 2>&1; then if command -v dnf >/dev/null 2>&1; then
PKG_MGR="dnf" PKG_MGR="dnf"
$PKG_MGR install -y nginx openssl-devel pcre-devel zlib-devel rpm-build gcc gcc-c++ make wget $PKG_MGR install -y nginx openssl-devel pcre-devel zlib-devel rpm-build gcc gcc-c++ make wget python3
elif command -v yum >/dev/null 2>&1; then elif command -v yum >/dev/null 2>&1; then
PKG_MGR="yum" PKG_MGR="yum"
$PKG_MGR install -y nginx openssl-devel pcre-devel zlib-devel rpm-build gcc gcc-c++ make wget $PKG_MGR install -y nginx openssl-devel pcre-devel zlib-devel rpm-build gcc gcc-c++ make wget python3
elif command -v apt-get >/dev/null 2>&1; then elif command -v apt-get >/dev/null 2>&1; then
PKG_MGR="apt-get" PKG_MGR="apt-get"
apt-get update apt-get update
$PKG_MGR install -y nginx debhelper-compat dh-autoreconf libssl-dev libpcre2-dev zlib1g-dev make gcc build-essential wget $PKG_MGR install -y nginx debhelper-compat dh-autoreconf libssl-dev libpcre2-dev zlib1g-dev make gcc build-essential wget python3
else else
echo "Unsupported package manager." echo "Unsupported package manager."
exit 1 exit 1
@@ -329,13 +333,6 @@ build)
exit 1 exit 1
fi fi
NGINX_VER_OUTPUT=$(nginx -V 2>&1)
CONFIG_ARGS=$(echo "$NGINX_VER_OUTPUT" | awk -F'configure arguments: ' '{print $2}')
if [ -z "$CONFIG_ARGS" ]; then
echo "Could not retrieve nginx configuration arguments."
exit 1
fi
echo "Retrieved configure arguments: $CONFIG_ARGS" echo "Retrieved configure arguments: $CONFIG_ARGS"
# Change to nginx source directory # Change to nginx source directory
@@ -346,9 +343,8 @@ build)
fi fi
cd "$SRC_DIR" || exit 1 cd "$SRC_DIR" || exit 1
# Run configure with saved arguments and add mod_rewrite
read -ra CONFIG_ARRAY <<< "$CONFIG_ARGS" python3 ../extract_nginx_args.py
./configure "${CONFIG_ARRAY[@]}" --add-dynamic-module=../modules/mod_rewrite
make modules make modules
cp objs/ngx_http_apache_rewrite_module.so ../ cp objs/ngx_http_apache_rewrite_module.so ../
;; ;;