Input stream is:
"
··echo "
"
··cat -
··echo "(end of input stream)
"
··exit 0
Когда веб-сервер (в данном случае Apache) получает запрос от веб-клиента, он вызывает указанную программу или сценарий и передает ей множество переменных окружения. Наш сценарий отображает эти данные с помощью команды env
— для максимальной переносимости он вызывает printenv, если env завершится неудачей, используя с этой целью конструкцию ||, — а остальная часть сценария лишь формирует обертку, чтобы вернуть результаты удаленному браузеру через веб-сервер.
Чтобы выполнить код, нужно дать сценарию право на выполнение и поместить его на веб-сервер (о чем подробнее рассказывается выше, в разделе «Запуск сценариев из этой главы»). И затем просто вызвать сохраненный файл .cgi из веб-браузера. Результаты показаны на рис. 8.1.
Рис. 8.1.CGI-окружение сценария командной оболочки
Знание, как Safari идентифицирует себя через переменную HTTP_USER_AGENT, (листинг 8.4) может пригодиться на практике.
Листинг 8.4.Переменная окружения HTTP_USER_AGENT в CGI-сценарии
HTTP_USER_AGENT=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1)
AppleWebKit/601.2.7 (KHTML, like Gecko) Version/9.0.1 Safari/601.2.7
Итак, данный браузер Safari имеет версию 601.2.7, относится к классу браузеров Mozilla 5.0, выполняется в OS X 10.11.1 на компьютере с процессором Intel и использует механизм отображения KHTML. Вся эта информация находится в единственной переменной!
№ 64. Журналирование веб-событий
Можно организовать журналирование событий с помощью CGI-сценария, оформив его как обертку. Представьте, что на вашей веб-странице имеется поле для поиска в DuckDuckGo и вам хотелось бы не просто передавать запросы непосредственно этой поисковой системе, а предварительно регистрировать их в журнале, чтобы потом посмотреть — что ищут посетители в содержимом вашего сайта.
Для начала необходимо написать немного HTML-кода. Поля ввода на веб-страницах заключаются в HTML-тег
, и, когда пользователь отправляет запрос щелчком на кнопке, форма, вместе с данными, введенными пользователем, передается удаленной веб-странице, указанной в атрибуте action формы. Минимальное поле ввода для поиска в DuckDuckGo на любой веб-странице можно реализовать так:
Search DuckDuckGo:
Вместо того чтобы передать строку поиска непосредственно системе DuckDuckGo, нам нужно послать ее сценарию на нашем сервере, который зарегистрирует запрос и затем отправит его серверу DuckDuckGo. Для этого нужно внести в форму одно маленькое изменение: в атрибуте action указать локальный сценарий, а не прямой вызов DuckDuckGo:
···· в /cgi-bin/ или где-то в другом месте — >
Сам CGI-сценарий log-duckduckgo-search удивительно прост, как показано в листинге 8.5.
Листинг 8.5.Сценарий log-duckduckgo-search
#!/bin/bash
# log-duckduckgo-search — получив поисковый запрос, регистрирует шаблон поиска
#·· и затем передает всю последовательность поисковой системе DuckDuckGo
# Каталог и файл, указанные в logfile, должны быть доступны для записи
#·· пользователю, с привилегиями которого выполняется веб-сервер.
logfile="/var/www/wicked/scripts/searchlog.txt"
if [! -f $logfile]; then
··touch $logfile
··chmod a+rw $logfile
fi
if [-w $logfile]; then
··echo "$(date):
$QUERY_STRING" | sed 's/q=//g;s/+/ /g' >> $logfile
fi
echo "Location: https://duckduckgo.com/html/?$QUERY_STRING"
echo ""
exit 0
Наиболее примечательны в этом сценарии элементы, демонстрирующие, как взаимодействуют веб-серверы и веб-клиенты. Информация, введенная в поле поиска, посылается на сервер в переменной QUERY_STRING
и кодируется заменой пробелов знаком + и других не алфавитно-цифровых символов соответствующими последовательностями. Затем перед регистрацией шаблона поиска в журнале все знаки + преобразуются обратно в пробелы. Ни для чего другого шаблон поиска не декодируется, чтобы защититься от любых видов атак, которые мог бы предпринять злоумышленник. (Более подробно об этом рассказывается во введении к данной главе.)
После журналирования веб-браузеру посылается ответ с заголовком Location:, перенаправляющий его на фактическую страницу поиска DuckDuckGo. Обратите внимание, что простого добавления?$QUERY_STRING достаточно, чтобы передать шаблон поиска адресату, каким бы сложным или простым ни был этот шаблон.
Читать дальше