关于 ColdFusion 的 CGI 的未记录的不一致行为 scope/struct
Undocumented inconsistent behavior regarding ColdFusion's CGI scope/struct
我最初发布这个是作为对这个问题的回答,之前关于 Empty CGI.REDIRECT_URL on ColdFusion 2016. After thinking about it, I thought better of it since technically didn't answer the OP's question. Instead I decided to make it into a separate question, even though it's more of a commentary than a question. While this technically might not meet the full requirements of a Minimal, Complete, and Verifiable example 人们可能会给我投反对票,我认为无论如何都是值得的,希望它会变得 更容易为将来可能遇到此问题的 CFer 查找。从而防止他们因为 CGI 的这种特殊行为而撞墙 struct/scope。
话虽如此,CGI struct/scope 与其他 structs/scopes 有一些未记录的不一致行为。请注意,我个人并不认为这一发现是我的功劳,因为我是在一段时间前阅读 Ben Nadel's blog post on this 时偶然发现的。所以我在这里发布的所有信息都在那里已经很详细了,但我想在这里写一个很好的总结。
Undocumented behavior 1 - Unlike other structures, if a CGI struct key doesn't exist, then it won't throw an error when referencing it.
在OP's original question中,他想知道为什么cgi.REDIRECT_URL
存在但为空。正如他最终发现的那样,它实际上从未存在过。作为一个单独的示例,您可以执行这行代码而不会引发错误。不是你所期望的,是吗?
<cfoutout>#cgi.THIS_IS_A_FAKE_KEY#</cfoutout>
那么 CFer 应该做什么?测试密钥是否存在。
<cfif structKeyExists( CGI, 'THIS_IS_A_FAKE_KEY' )>
THIS_IS_A_FAKE_KEY exists
<cfelse>
THIS_IS_A_FAKE_KEY doesn't exist
</cfif>
Undocumented behavior 2 - Unlike other structures, if you dump the CGI struct, it won't display all the key/value pairs, it will only display a defined set of keys.
在 OP's case, he had a custom Apache CGI variable cgi.REDIRECT_URL
that was used in his code prior to upgrading to CF2016 and was able to refer to it directly. However, I'm presuming if he dumped out the cgi
struct, it wouldn't appear in the dump. In Ben Nadel's case 中,他还有一个名为 cgi.document_root
的自定义 cgi
变量,该变量是从负载均衡器传递过来的,可以直接引用它,但他也转储 cgi
内容时无法看到密钥。
那么 CFer 应该做什么?理解这一点并将其牢记在心,这样当您转储 cgi
内容而 key/value 对不存在时,您就不会被咬到。除此之外,其他的就没有了。
我进入了 ColdFusion 的 cfusion.jar
文件。我发现那里有点混乱。
CGI 范围不是人们希望的 structure
形式。
这是处理 CGI 变量调用的方式。例如 <cfoutout>#cgi.THIS_IS_A_FAKE_KEY#</cfoutout>
正常有效的 CGI 作用域变量是此列表中的变量,它们将默认初始化为 ""
。
private static final String[] names ="AUTH_PASSWORD","AUTH_TYPE","AUTH_USER","CERT_COOKIE","CERT_FLAGS","CERT_ISSUER","CERT_KEYSIZE","CERT_SECRETKEYSIZE","CERT_SERIALNUMBER","CERT_SERVER_ISSUER","CERT_SERVER_SUBJECT","CERT_SUBJECT","CF_TEMPLATE_PATH","CONTENT_LENGTH","CONTENT_TYPE","CONTEXT_PATH","GATEWAY_INTERFACE","HTTP_ACCEPT","HTTP_ACCEPT_ENCODING","HTTP_ACCEPT_LANGUAGE","HTTP_CONNECTION","HTTP_COOKIE","HTTP_HOST","HTTP_USER_AGENT","HTTP_REFERER","HTTP_URL","HTTPS","HTTPS_KEYSIZE","HTTPS_SECRETKEYSIZE","HTTPS_SERVER_ISSUER","HTTPS_SERVER_SUBJECT","LOCAL_ADDR","PATH_INFO","PATH_TRANSLATED","QUERY_STRING","REMOTE_ADDR","REMOTE_HOST","REMOTE_USER","REQUEST_METHOD","SCRIPT_NAME","SERVER_NAME","SERVER_PORT","SERVER_PORT_SECURE","SERVER_PROTOCOL","SERVER_SOFTWARE","WEB_SERVER_API" };`
此外,所有这些值也来自各种 java 库 javax.servlet
、HttpServletRequest
等
如果经过一些检查后请求的变量不是这些中的任何一个,ColdFusion 将转到请求 headers。您可以使用 getHttpRequestData().headers
查看这些。然后在 cgi
密钥请求中使用连字符 (-
) 而不是下划线 (_
) 查找密钥。 (如果密钥以 http_
开头,那么请求 header 中的密钥将像这样 http_x_forward
在请求 header 中将是 x-forward
)
value = request.getHeader(name.replace('_', '-'));
据我所知,就 ColdFusion 而言,第一点中提到的键是公认的 CGI 范围的一部分。但是当有额外的信息从 Apache 负载平衡器服务器传递到 ColdFusion 时,这些信息最终会出现在请求 header 中。由于 java getHeader
只是 returns 一个空字符串(或数据类型为 undefined
的东西)而不是未定义的错误,ColdFusion 不识别任何键是否定义.
因此,如果密钥 THIS_IS_A_FAKE_KEY
从 Apache 服务器等中介发送到 ColdFusion。您会在 getHttpRequestData().headers['THIS-IS-A-FAKE-KEY']
中找到它,但不会在 CGI
范围转储中找到它。
话虽这么说,但我个人的意见是,最好直接在 getHttpRequestData().headers
中检查自定义 CGI 变量,而不是在范围本身中检查。
编辑 感谢 Ageax 指出我的一个测试用例在我早期对此 post 的修订中无效。
伟大的侦探工作 RRK!所以我决定做一个实验,通过创建两个循环来验证你的发现。第一个循环将显示来自 getHttpRequestData().headers
的 key/value 对,第二个循环通过替换 -
使用来自 cgi
范围的相应 key/value 对执行相同的操作_
。瞧!正如 RRK 所报告的那样,我们可以了解如何通过任一方法获取这些值。我更新了要点并 posted here 给感兴趣的人。
<cfset httpHeaders = getHttpRequestData().headers>
<h3>getHttpRequestData().headers</h3>
<cfloop collection="#httpHeaders#" item="key" >
<cfoutput><strong>#Key#</strong> : #httpHeaders[key]#<br></cfoutput>
</cfloop>
<h3>cgi keys dash to underscore</h3>
<cfloop collection="#httpHeaders#" item="key" >
<cfset keyUnderscore = replace(key, "-", "_", "all")>
<cfoutput><strong>#keyUnderscore#</strong> : #cgi[keyUnderscore]#<br></cfoutput>
</cfloop>
我最初发布这个是作为对这个问题的回答,之前关于 Empty CGI.REDIRECT_URL on ColdFusion 2016. After thinking about it, I thought better of it since technically didn't answer the OP's question. Instead I decided to make it into a separate question, even though it's more of a commentary than a question. While this technically might not meet the full requirements of a Minimal, Complete, and Verifiable example 人们可能会给我投反对票,我认为无论如何都是值得的,希望它会变得 更容易为将来可能遇到此问题的 CFer 查找。从而防止他们因为 CGI 的这种特殊行为而撞墙 struct/scope。
话虽如此,CGI struct/scope 与其他 structs/scopes 有一些未记录的不一致行为。请注意,我个人并不认为这一发现是我的功劳,因为我是在一段时间前阅读 Ben Nadel's blog post on this 时偶然发现的。所以我在这里发布的所有信息都在那里已经很详细了,但我想在这里写一个很好的总结。
Undocumented behavior 1 - Unlike other structures, if a CGI struct key doesn't exist, then it won't throw an error when referencing it.
在OP's original question中,他想知道为什么cgi.REDIRECT_URL
存在但为空。正如他最终发现的那样,它实际上从未存在过。作为一个单独的示例,您可以执行这行代码而不会引发错误。不是你所期望的,是吗?
<cfoutout>#cgi.THIS_IS_A_FAKE_KEY#</cfoutout>
那么 CFer 应该做什么?测试密钥是否存在。
<cfif structKeyExists( CGI, 'THIS_IS_A_FAKE_KEY' )>
THIS_IS_A_FAKE_KEY exists
<cfelse>
THIS_IS_A_FAKE_KEY doesn't exist
</cfif>
Undocumented behavior 2 - Unlike other structures, if you dump the CGI struct, it won't display all the key/value pairs, it will only display a defined set of keys.
在 OP's case, he had a custom Apache CGI variable cgi.REDIRECT_URL
that was used in his code prior to upgrading to CF2016 and was able to refer to it directly. However, I'm presuming if he dumped out the cgi
struct, it wouldn't appear in the dump. In Ben Nadel's case 中,他还有一个名为 cgi.document_root
的自定义 cgi
变量,该变量是从负载均衡器传递过来的,可以直接引用它,但他也转储 cgi
内容时无法看到密钥。
那么 CFer 应该做什么?理解这一点并将其牢记在心,这样当您转储 cgi
内容而 key/value 对不存在时,您就不会被咬到。除此之外,其他的就没有了。
我进入了 ColdFusion 的 cfusion.jar
文件。我发现那里有点混乱。
CGI 范围不是人们希望的 structure
形式。
这是处理 CGI 变量调用的方式。例如 <cfoutout>#cgi.THIS_IS_A_FAKE_KEY#</cfoutout>
正常有效的 CGI 作用域变量是此列表中的变量,它们将默认初始化为
""
。private static final String[] names ="AUTH_PASSWORD","AUTH_TYPE","AUTH_USER","CERT_COOKIE","CERT_FLAGS","CERT_ISSUER","CERT_KEYSIZE","CERT_SECRETKEYSIZE","CERT_SERIALNUMBER","CERT_SERVER_ISSUER","CERT_SERVER_SUBJECT","CERT_SUBJECT","CF_TEMPLATE_PATH","CONTENT_LENGTH","CONTENT_TYPE","CONTEXT_PATH","GATEWAY_INTERFACE","HTTP_ACCEPT","HTTP_ACCEPT_ENCODING","HTTP_ACCEPT_LANGUAGE","HTTP_CONNECTION","HTTP_COOKIE","HTTP_HOST","HTTP_USER_AGENT","HTTP_REFERER","HTTP_URL","HTTPS","HTTPS_KEYSIZE","HTTPS_SECRETKEYSIZE","HTTPS_SERVER_ISSUER","HTTPS_SERVER_SUBJECT","LOCAL_ADDR","PATH_INFO","PATH_TRANSLATED","QUERY_STRING","REMOTE_ADDR","REMOTE_HOST","REMOTE_USER","REQUEST_METHOD","SCRIPT_NAME","SERVER_NAME","SERVER_PORT","SERVER_PORT_SECURE","SERVER_PROTOCOL","SERVER_SOFTWARE","WEB_SERVER_API" };`
此外,所有这些值也来自各种 java 库
javax.servlet
、HttpServletRequest
等如果经过一些检查后请求的变量不是这些中的任何一个,ColdFusion 将转到请求 headers。您可以使用
getHttpRequestData().headers
查看这些。然后在cgi
密钥请求中使用连字符 (-
) 而不是下划线 (_
) 查找密钥。 (如果密钥以http_
开头,那么请求 header 中的密钥将像这样http_x_forward
在请求 header 中将是x-forward
)value = request.getHeader(name.replace('_', '-'));
据我所知,就 ColdFusion 而言,第一点中提到的键是公认的 CGI 范围的一部分。但是当有额外的信息从 Apache 负载平衡器服务器传递到 ColdFusion 时,这些信息最终会出现在请求 header 中。由于 java getHeader
只是 returns 一个空字符串(或数据类型为 undefined
的东西)而不是未定义的错误,ColdFusion 不识别任何键是否定义.
因此,如果密钥 THIS_IS_A_FAKE_KEY
从 Apache 服务器等中介发送到 ColdFusion。您会在 getHttpRequestData().headers['THIS-IS-A-FAKE-KEY']
中找到它,但不会在 CGI
范围转储中找到它。
话虽这么说,但我个人的意见是,最好直接在 getHttpRequestData().headers
中检查自定义 CGI 变量,而不是在范围本身中检查。
编辑 感谢 Ageax 指出我的一个测试用例在我早期对此 post 的修订中无效。
伟大的侦探工作 RRK!所以我决定做一个实验,通过创建两个循环来验证你的发现。第一个循环将显示来自 getHttpRequestData().headers
的 key/value 对,第二个循环通过替换 -
使用来自 cgi
范围的相应 key/value 对执行相同的操作_
。瞧!正如 RRK 所报告的那样,我们可以了解如何通过任一方法获取这些值。我更新了要点并 posted here 给感兴趣的人。
<cfset httpHeaders = getHttpRequestData().headers>
<h3>getHttpRequestData().headers</h3>
<cfloop collection="#httpHeaders#" item="key" >
<cfoutput><strong>#Key#</strong> : #httpHeaders[key]#<br></cfoutput>
</cfloop>
<h3>cgi keys dash to underscore</h3>
<cfloop collection="#httpHeaders#" item="key" >
<cfset keyUnderscore = replace(key, "-", "_", "all")>
<cfoutput><strong>#keyUnderscore#</strong> : #cgi[keyUnderscore]#<br></cfoutput>
</cfloop>