ap_expr 表达式解析器
在先前版本的 Apache HTTP Server中,有几个用于表达式的语法变体用于在 Apache HTTP Server的不同模块中表达条件。 自 Apache HTTP Server 2.4.x以来,只有一个称为 ap_expr 的单一变体用于所有配置伪指令。 本文档描述了 HTTP Server中新的 ap_expr 表达式解析器。
Backus-Naur Form 表示法中的语法
Backus-Naur Form (BNF) 是一种无上下文语法的表示法技术,通常用于描述计算中使用的语言的语法。 在大多数情况下,表达式用于表示布尔值。 对于这些, BNF 中的起点是 expr。 但是,一些伪指令接受求值为字符串值的表达式。 对于这些, BNF 中的起始点是字符串。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
变量
表达式解析器提供了格式为%{HTTP_HOST}的多个变量。 请注意,变量的值可能取决于对其进行求值的请求处理的阶段。 例如,<If> 指令中使用的表达式会在验证之前进行评估。 因此,在此情况下将不会设置%{REMOTE_USER} 。
以下变量提供了命名为 HTTP 的请求标头的值。 可以使用 req 函数获取其他头的值 (请参阅下文)。 使用这些变量可能会导致头名称被添加到 HTTP 响应的 Vary 头中,除非接受表达式的指令另有说明。 req_novary 函数 (见下文) 可用于规避这种行为。
| 名称 |
|---|
| Http_accept |
| Http_cookie |
| 已转发 HTTP_FORWARD |
| Http_host |
| http_proxy_connection |
| Http_referer |
| 用户代理 |
示例:
# Compare the host name to example.com and redirect to www.example.com if it matches
<If "%{HTTP_HOST} == 'example.com'">
Redirect permanent "/" "http://www.example.com/"
</If>
| 名称 | 描述 |
|---|---|
| REQUEST_METHOD | 接收请求的 HTTP 方法(如 GET) |
| 请求方案 | 请求 URI 的方案部分 |
| REQUEST_URI | 请求 URI 的路径部分 |
| DOCUMENT_URI | 与 REQUEST_URI 相同 |
| 请求文件名 | 与请求匹配的文件或脚本的完整本地文件系统路径 (如果在引用 REQUEST_FILENAME 时服务器已确定此路径)。 否则,例如在虚拟主机上下文中使用时,与 REQUEST_URI 的值相同 |
| 脚本文件名称 | 与 REQUEST_FILENAME 相同 |
| 最后修改 | 上次修改文件的日期和时间,格式为 20101231235959 ,如果在引用 LAST_MODIFIED 时服务器已确定此日期和时间。 |
| 路径信息 | 尾部路径名信息,请参见AcceptPathInfo |
| QUERY_STRING | 当前请求的查询字符串 |
| IS_SUBREQ | 如果当前请求是子请求,那么为 "true" ,否则为 "false" |
| 请求 | 完整请求行 (例如, "GET /index.html HTTP/1.1") |
| REMOTE_ADDR | 远程主机的 IP 地址 |
| remote_port | 远程主机的端口 |
| 远程主机 | 远程主机的主机名 |
| REMOTE_USER | 已通过身份验证的用户名(如果有)(在 <If> 时不可用 |
| 远程身份 | mod_ident 设置的用户名 |
| SERVER_NAME | 当前虚拟主机的 ServerName |
| SERVER_PORT | 当前虚拟主机的服务器端口,请参阅 ServerName |
| 服务器管理 | 当前虚拟主机的 ServerAdmin |
| 服务器协议 | 请求使用的协议 (例如 HTTP/1.1)。 在某些类型的内部子请求中,此变量的值为。 |
| 文档根 | 当前虚拟主机的 DocumentRoot |
| AUTH_TYPE | 配置的 "AuthType(例如 "basic) |
| 内容类型 | 响应的内容类型(在 <If> 中不可用) |
| 处理程序 | 创建响应的 处理程序 的名称 |
| HTTPS | "on" (如果请求使用 https) , "off" (否则) |
| IPV6 | "on" (如果连接使用 IPv6) , "off" (否则) |
| REQUEST_STATUS | HTTP 请求的错误状态(在 <If> 时不可用) |
| REQUEST_LOG_ID | 请求的错误日志 ID(参见ErrorLogFormat |
| CONN_LOG_ID | 连接的错误日志 ID(参见ErrorLogFormat |
| conn_remote_addr | 连接的对等 IP 地址 (请参阅 mod_remoteip 模块) |
| 上下文前缀 | |
| 上下文文档根 |
示例:
# Force text/plain if requesting a file with the query string contains 'forcetext'
<If "%{QUERY_STRING} =~ /forcetext/">
ForceType text/plain
</If>
| 名称 | 描述 |
|---|---|
| 时间 _ 年 | 本年度 (例如 2010 年) |
| 时间 (TIME_MON) | 当月 (01 , ... , 12) |
| 时间-DAY | 当月日 (01 , ...) |
| 时间/小时 | 当前时间的小时部分 (00 , ... , 23) |
| 时间最小值 | 当前时间的分钟部分 |
| 时间-SEC | 当前时间的第二部分 |
| 时间 (TIME_WDAY) | 星期几 (从星期天的 0 开始) |
| 时间 | 格式为 20101231235959 的日期和时间 |
| 服务器软件 | 服务器版本字符串 |
| API_VERSION | API 版本的日期 (模块幻数) |
有关更多变量信息,请参阅 HTTP Server 。
示例:
# Only allow access to this content during business hours
<Directory "/www/webserver/htdocs/business">
Require expr %{TIME_HOUR} -gt 9 && %{TIME_HOUR} -lt 17
</Directory>二元运算符
二进制运算符的形式为"-a-zA-Z]a-zA-Z0-9_]+",即一个减号和至少两个字符。 名称不区分大小写。
| 名称 | 备用 | 描述 |
|---|---|---|
| == | = | 字符串等同性 |
| != | 字符串不等式 | |
| < | 字符串小于 | |
| <= | 字符串小于或等于 | |
| > | 字符串大于 | |
| >= | 字符串大于或等于 | |
| =~ | 字符串与正则表达式匹配 | |
| !~ | 字符串与正则表达式不匹配 | |
| -等式 | eq | 整数等同性 |
| -内 | ne | 整数不等式 |
| -我不需要 | lt | 整数小于 |
| -勒 | le | 整数小于或等于 |
| -gt | 格特 | 整数大于 |
| -盖 | ge | 大于或等于整数 |
| 名称 | 描述 |
|---|---|
| -ip匹配 | IP 地址与地址/网络掩码匹配 |
| -字符串匹配 | 左字符串与右字符串 (包含通配符 * ,? , []) 给出的模式匹配 |
| -字符串匹配 | 与 -strmatch 相同,但不区分大小写 |
| -fnmatch | 与 -strmatch 相同,但通配符不匹配斜杠 |
示例:
# Compare the IP address of the remote host to 127.0.0.1/8 and redirect to localhost:8080 if it matches
<If "%{REMOTE_ADDR} -ipmatch '127.0.0.1/8'">
Redirect permanent "/" "http://localhost:8080/"
</If>一元运算符
一元运算符只有一个参数,形式为"-a-zA-Z]",即一个减号和一个字符。 该名称区分大小写。
| 名称 | 描述 | 受限 |
|---|---|---|
| -d | 该参数被视为文件名。 如果该文件存在并且是目录,那么为 True | 是 |
| -e | 该参数被视为文件名。 如果文件 (或目录或特殊) 存在,那么为 True | 是 |
| -f | 该参数被视为文件名。 如果该文件存在并且是常规文件,那么为 True | 是 |
| -s | 该参数被视为文件名。 如果文件存在且不为空,那么为 True | 是 |
| -L | 该参数被视为文件名。 如果文件存在并且是符号链接,那么为 True | 是 |
| -h | 该参数被视为文件名。 如果文件存在且为符号链接,则为 True(与-L)相同) | 是 |
| -F | 如果字符串是有效文件,那么为 True ,可通过服务器当前为该路径配置的所有访问控制进行访问。 注: 这将使用内部子请求来执行检查,因此请谨慎使用该检查-这可能会影响服务器的性能!
|
|
| -U | 如果 string 是一个有效的 URL ,可通过服务器当前为该路径配置的所有访问控制访问,则为 True。 注: 这将使用内部子请求来执行检查,因此请谨慎使用该检查-这可能会影响服务器的性能!
|
|
| -A | -U的别名 | |
| -n | 如果字符串不为空,那么为 True | |
| -z | 如果字符串为空,那么为 True | |
| -T | False (如果字符串为空) , "0" , "off" , "false" 或 "no" (不区分大小写)。 否则为真。 | |
| -R | 与 "%{REMOTE_ADDR} -ipmatch ..." 相同, 但效率更高 |
示例:
# Check result of URI mapping by running in Directory context with -f
<Directory "/www/webserver/htdocs">
AddEncoding x-gzip gz
<If "-f '%{REQUEST_FILENAME}.unzipme' && ! %{HTTP:Accept-Encoding} =~ /gzip/">
SetOutputFilter INFLATE
</If>
</Directory>函数
正常的字符串值函数采用一个字符串作为自变量,并返回一个字符串。 函数名不区分大小写。
| 名称 | 描述 | 受限 | 特殊注意事项 |
|---|---|---|---|
| 请求, HTTP | 获取 HTTP 请求标头;标头名称可添加到 Vary 标头上(见下文) | ||
| 要求 | 与需求职位相同,但头名称不会添加到 Vary 头 | ||
| 代表 | 获取 HTTP 响应标头(大多数响应标头在 <If> 期间尚未设置) | ||
| 列根夫 | 查找请求环境变量 (作为快捷方式, v 也可用于访问变量) | 订购 | |
| 奥森夫 | 查找操作系统环境变量 | ||
| 注意 | 查找请求注释 | 订购 | |
| env | 返回注释, reqenv 和 osenv 的第一个匹配项 | 订购 | |
| tolower | 将字符串转换为小写 | ||
| toupper | 将字符串转换为大写 | ||
| 转义 | 对 %hex 编码中的特殊字符进行转义 | ||
| unescape | 取消对 %hex 编码字符串的转义,仅保留编码斜杠; 如果找到 %00 ,那么返回空字符串 | ||
| base64 | 使用 base64 编码对字符串进行编码 | ||
| unbase64 | 解码 base64 编码的字符串,如果找到 0x00 ,那么返回截断的字符串 | ||
| md5 | 使用 MD5对字符串进行散列,然后使用十六进制编码对散列进行编码 | ||
| sha1 | 使用 SHA1对字符串进行散列,然后使用十六进制编码对散列进行编码 | ||
| 文件 | 从文件中读取内容 (包括行尾,如果存在) | 是 | 受限 |
| 菲勒莫德 | 返回文件的上次修改时间 (如果文件不存在或不是常规文件,那么返回 0) | 受限 | |
| Filesize | 文件的返回大小 (如果文件不存在或不是常规文件,那么返回 0) | 是 | 受限 |
在最终列中标记为 "排序" 的函数需要对服务器的不同组件进行排序进行一些考虑,尤其是当在相对早期求值的 <If> 伪指令中使用该函数时。
环境变量排序
在 <If> 条件中查找环境变量时,请务必考虑请求处理中发生此解析的非常早的时间。 作为准则,在虚拟主机上下文 (目录,位置, htaccess) 外部定义的任何伪指令都不可能还没有执行的机会。 虚拟主机作用域中的SetEnvIf是在该决议之前运行的一条指令。
在 <If>外部使用 reqenv 时,通常稍后会发生解析,但确切的计时取决于已在其中使用表达式的伪指令。
使用函数 req 或 http 时,头名称将自动添加到 HTTP 响应的 Vary 头中,除非接受表达式的指令另有说明。 req_novary 函数可用于防止将名称添加到 Vary 头中。
除了字符串值函数之外,还有列表值函数以一个字符串作为参数并返回一个 wordlist ,即一个字符串列表。 可将 wordlist 与特殊的 in 运算符一起使用 (请参阅下文)。 函数名不区分大小写。 没有内置列表值函数。
示例:
# Compare the host name to example.com and redirect to www.example.com if it matches
<If "%{HTTP_HOST} == 'example.com'">
Redirect permanent "/" "http://www.example.com/"
</If>
# Force text/plain if requesting a file with the query string contains 'forcetext'
<If "%{QUERY_STRING} =~ /forcetext/">
ForceType text/plain
</If>
# Only allow access to this content during business hours
<Directory "/foo/bar/business">
Require expr %{TIME_HOUR} -gt 9 && %{TIME_HOUR} -lt 17
</Directory>
# Check a HTTP header for a list of values
<If "%{HTTP:X-example-header} in { 'foo', 'bar', 'baz' }">
Header set matched true
</If>
# Check an environment variable for a regular expression, negated.
<If "! reqenv('REDIRECT_FOO') =~ /bar/">
Header set matched true
</If>
# Check result of URI mapping by running in Directory context with -f
<Directory "/var/www">
AddEncoding x-gzip gz
<If "-f '%{REQUEST_FILENAME}.unzipme' && ! %{HTTP:Accept-Encoding} =~ /gzip/">
SetOutputFilter INFLATE
</If>
</Directory>
# Check against the client IP
<If "-R '192.168.1.0/24'">
Header set matched true
</If>
# Function examples in boolean context
<If "md5('foo') == 'acbd18db4cc2f85cedef654fccc4a4d8'">
Header set checksum-matched true
</If>
# Function example in string context
Header set foo-checksum "expr=%{md5:foo}"
# This delays the evaluation of the condition clause compared to <If>
Header always set CustomHeader my-value "expr=%{REQUEST_URI} =~ m#^/special_path\.php$#"
# Conditional logging
CustomLog logs/access-errors.log common "expr=%{REQUEST_STATUS} >= 400"
CustomLog logs/access-errors-specific.log common "expr=%{REQUEST_STATUS} -in {'405','410'}"
其他
| 名称 | 备用 | 描述 |
|---|---|---|
| 入门 | 在 | 包含在 wordlist 中的字符串 |
| /regexp/ | m#regexp# | 正则表达式 (第二种形式允许与/不同的定界符) |
| /regexp/i | #regexp#i | 不区分大小写的正则表达式 |
| $0... $9 | 正则表达式反向引用 |
示例:
# Check a HTTP header for a list of values
<If "%{HTTP:X-example-header} in { 'foo', 'bar', 'baz' }">
Header set matched true
</If>