Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions apisix/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,30 @@ local function build_match_uri_keep_encoded_slash(path, current_uri)
end


-- whether nginx did more than decode the path or merge slashes in $uri,
-- e.g. resolved a dot segment or cut the path at "#"
local function uri_normalized_by_nginx(request_uri, uri)
if request_uri == uri then
return false
end
if core.string.has_prefix(request_uri, uri)
and str_byte(request_uri, #uri + 1) == str_byte("?") then
return false
end

local path = request_uri
local args_pos = core.string.find(path, "?")
if args_pos then
path = str_sub(path, 1, args_pos - 1)
end
local decoded = percent_decode(path, false)
if decoded == uri then
return false
end
return re_gsub(decoded, [[//+]], "/", "jo") ~= uri
end


local function common_phase(phase_name)
local api_ctx = ngx.ctx.api_ctx
if not api_ctx then
Expand Down Expand Up @@ -887,6 +911,13 @@ function _M.http_access_phase()
end
end

-- forward the path the route was matched on; binary allows decoded
-- control chars, proxy_pass escapes them
if not (local_conf.apisix and local_conf.apisix.normalize_uri_like_servlet)
and uri_normalized_by_nginx(api_ctx.var.request_uri, uri) then
ngx.req.set_uri(uri, false, true)
end

-- To prevent being hacked by untrusted request_uri, here we
-- record the normalized but not rewritten uri as request_uri,
-- the original request_uri can be accessed via var.real_request_uri
Expand Down
21 changes: 21 additions & 0 deletions docs/en/latest/router-radixtree.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,27 @@ when either actually rewrites the URI (a stripped trailing slash, a servlet-styl
matching without keeping `%2F`. The fallback is safe; the encoded-slash match
simply does not apply to such requests.

#### 6. Path forwarded to the upstream

Routes are matched on the normalized `$uri`: Nginx percent-decodes the path,
resolves dot segments (including encoded ones such as `..%2F` and `%2e%2e`),
cuts the path at `#` and merges consecutive slashes. When the request path
differs from `$uri` only by percent-encoding or consecutive slashes, APISIX
forwards the original request line to the upstream. Otherwise it forwards the
matched path, escaped by Nginx, with the current query string. For example, a
request to `/admin/..%2Fapi/x` matches a route for `/api/*` and the upstream
receives `/api/x`.

In that case encoded delimiters arrive decoded: `/api/./a%2Fb%3Bc` reaches the
upstream as `/api/a/b;c`, while `/api/a%2Fb` is forwarded as is.

Changes that plugins make to the path or the query string after matching still
apply, and plugins that set the upstream URI, such as `proxy-rewrite`, still
take precedence.

This section does not apply when `normalize_uri_like_servlet` is enabled, which
sets the upstream path itself.

### How to filter route by Nginx built-in variable?

Nginx provides a variety of built-in variables that can be used to filter routes based on certain criteria. Here is an example of how to filter routes by Nginx built-in variables:
Expand Down
10 changes: 10 additions & 0 deletions docs/zh/latest/router-radixtree.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,16 @@ apisix:

该选项会让位于 `delete_uri_tail_slash` 和 `normalize_uri_like_servlet`:等价性检查是与这两个选项处理之后的 URI 比较的,因此当其中任一确实改写了 URI(去掉末尾斜杠、剥离 servlet 风格的 `;` 参数)时,检查将不再成立,请求会回退到普通匹配而不保留 `%2F`。这种回退是安全的,只是保留编码斜杠的匹配对这类请求不再生效。

#### 6. 转发给上游的路径

路由基于归一化后的 `$uri` 进行匹配:Nginx 会对路径进行百分号解码、解析点段(包括 `..%2F`、`%2e%2e` 等编码形式)、在 `#` 处截断路径并合并连续斜杠。当请求路径与 `$uri` 仅在百分号编码或连续斜杠上存在差异时,APISIX 将原始请求行转发给上游。否则,APISIX 会转发经 Nginx 转义的匹配路径,并附带当前的查询字符串。例如,请求 `/admin/..%2Fapi/x` 会匹配 `/api/*` 路由,上游收到的是 `/api/x`。

此时编码的分隔符会以解码后的形式到达上游:`/api/./a%2Fb%3Bc` 到达上游时为 `/api/a/b;c`,而 `/api/a%2Fb` 会原样转发。

插件在匹配之后对路径或查询字符串所做的修改仍然生效,设置上游 URI 的插件(如 `proxy-rewrite`)仍然优先生效。

启用 `normalize_uri_like_servlet` 时,本节不适用,该选项会自行设置上游路径。

### 如何通过 Nginx 内置变量过滤路由

具体参数及使用方式请查看 [radixtree#new](https://github.com/api7/lua-resty-radixtree#new) 文档,下面是一个简单的示例:
Expand Down
Loading
Loading