Недокументированное непоследовательное поведение в отношении области/структуры CGI ColdFusion.

Первоначально я разместил это как ответ на этот вопрос ранее относительно Empty CGI.REDIRECT_URL на ColdFusion 2016. Подумав об этом, я передумал, поскольку технически не ответил на вопрос ОП. Вместо этого я решил выделить его в отдельный вопрос, хотя это скорее комментарий, чем вопрос. Хотя технически это может не соответствовать всем требованиям минимального, полного и проверяемого примера, и люди могут дать мне отрицательные голоса, я решил в любом случае оно того стоило в надежде, что его станет легче найти для будущих CF-специалистов, которые могут столкнуться с этим. Таким образом, они не могут биться головой о стену об этом своеобразном поведении структуры/области CGI.

При этом структура/область CGI имеет некоторое недокументированное непоследовательное поведение по сравнению с другими структурами/областями. Обратите внимание, что я лично не беру на себя ответственность за это открытие, поскольку я столкнулся с этим некоторое время назад, прочитав запись в блоге Бена Наделя по этому поводу. Итак, вся информация, которую я публикую здесь, уже подробно описана там, но я хотел написать хорошее резюме здесь, на SO.

Недокументированное поведение 1. В отличие от других структур, если ключ структуры CGI не существует, при обращении к нему не возникает ошибка.

В исходном вопросе OP он задавался вопросом, почему 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>

Недокументированное поведение 2. В отличие от других структур, если вы выгрузите структуру CGI, она не отобразит все пары ключ/значение, а только определенный набор ключей.

В случае OP у него была пользовательская переменная Apache CGI cgi.REDIRECT_URL, которая использовался в его коде до обновления до CF2016 и мог ссылаться на него напрямую. Однако я предполагаю, что если бы он выгрузил структуру cgi, она не появилась бы в дампе. В в случае с Беном Наделем, у него также была пользовательская переменная cgi с именем cgi.document_root, которая была передана из балансировщика нагрузки и могла ссылаться на нее напрямую, но он также не мог видеть key при сбросе содержимого cgi.

Так что же делать CFer? Поймите это и сохраните это в глубине души, чтобы вас не укусили, когда вы сбрасываете содержимое cgi, а пары ключ/значение там нет. Кроме этого, не более того.


person user9263373    schedule 15.02.2018    source источник
comment
Это большой вопрос. Меня это уже давно беспокоит. Мой сервер Apache передает HTTP_X_FORWARDED серверу CF. Но когда я сбрасываю это, я могу найти строку в области CGI. Но CGI.HTTP_X_FORWARDED дает мне значение. Это действительно ужасно.   -  person rrk    schedule 15.02.2018
comment
Попытался заглянуть под капот. Но большая часть этих вещей, связанных с Java, пролетела прямо у меня над головой.   -  person rrk    schedule 15.02.2018
comment
Только что узнал, что область CGI работает следующим образом: сначала она сканирует саму область, а затем, если не найдена, сканирует заголовки запроса (getHttpRequestData()). Но в заголовках запроса ключи будут другими, что означает, что символы подчеркивания (_) в области запроса будут дефисами (-). Это означает, что cgi.THIS_IS_A_FAKE_KEY фактически извлекает данные из getHttpRequestData().headers['THIS-IS-A-FAKE-KEY']. Теперь вопрос: Почему?; Понятия не имею.   -  person rrk    schedule 15.02.2018


Ответы (2)


Я вошел в файл cfusion.jar ColdFusion. То, что я там нашел, было немного запутанным.

Объем CGI не имеет формы structure, на которую можно было бы надеяться.

Вот как обрабатывается вызов переменной CGI. например <cfoutout>#cgi.THIS_IS_A_FAKE_KEY#</cfoutout>

  1. Обычные допустимые переменные области видимости 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 и т. д.

  2. Если запрошенная переменная не является ни одной из них после небольшой проверки, ColdFusion переходит к заголовкам запроса. Вы можете увидеть их, используя getHttpRequestData().headers. Затем ищет там ключ с дефисами (-) вместо символов подчеркивания (_) в запросе ключа cgi. (Если ключ начинается с http_, то ключ в заголовках запроса будет без него, например, http_x_forward в заголовке запроса будет x-forward)

     value = request.getHeader(name.replace('_', '-'));
    

Насколько я понимаю, что касается ColdFusion, ключи, упомянутые в первом пункте, признаны частью области CGI. Но когда дополнительная информация передается с сервера балансировки нагрузки Apache в ColdFusion, она попадает в заголовки запроса. Поскольку java getHeader просто возвращает пустую строку (или что-то с типом данных undefined) вместо неопределенной ошибки, ColdFusion не определяет, определен ли какой-либо из ключей.

Поэтому, если ключ THIS_IS_A_FAKE_KEY отправляется в ColdFusion от посредника, такого как сервер Apache. Вы найдете это в getHttpRequestData().headers['THIS-IS-A-FAKE-KEY'], но не в дампе области CGI.

При этом мое личное мнение таково, что лучше проверять непосредственно в getHttpRequestData().headers наличие пользовательских переменных CGI, а не в самой области видимости.

person rrk    schedule 15.02.2018
comment
Отличная детективная работа! Проголосуйте и пометьте как правильный. - person user9263373; 15.02.2018

EDIT Спасибо Ageax за указание на то, что один из моих тестовых случаев был недействителен в моей предыдущей редакции этого поста.

Отличная детективная работа RRK! Поэтому я решил провести эксперимент, чтобы проверить ваши выводы, создав две петли. Первый цикл будет отображать пары ключ/значение из getHttpRequestData().headers, а второй цикл сделает то же самое, используя соответствующие пары ключ/значение из области cgi, заменив - на _. Вуаля! как сообщает RRK, мы видим, как вы можете получить значения любым из этих методов. Я обновил суть и разместил здесь для всех, кто заинтересован.

<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>
person user9263373    schedule 15.02.2018
comment
Почему вы говорите, что запись через точку непоследовательна? Я бы не ожидал, что динамический ключ, такой как #cgi.keyUnderscore#, будет оцениваться правильно, без жесткого кодирования (CGI.HTTP_ACCEPT) или использования структурной нотации, как во втором цикле. - person SOS; 15.02.2018
comment
@Ageax Спасибо, что указали мне на это! Иногда я зацикливаюсь на выводах, не понимая, что мой тест недействителен. Хороший улов и спасибо. Позже обновлю пост и исправлю. - person user9263373; 15.02.2018
comment
Не все ли мы! Хотя нить отличная. Всегда интересно копаться во внутренней работе CF :) - person SOS; 15.02.2018