Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Переменные заголовка HTTP-запроса
За исключением тех строк из заголовка HTTP-запроса, которые были включены в другие переменные, сервер приделывает строкам префикс HTTP_ и заменяет знаки «-» на «_»: HTTP_ACCEPT Давая запрос на сервер браузер обычно рассчитывает получить информацию определенного формата, и для этого он в заголовке запроса указывает поле Accept. Отсюда скрипту поступает список тех MIME, которые браузер готов принять в качестве ответа от сервера. Пример: HTTP_ACCEPT=text/html, text/plain, image/gif HTTP_USER_AGENT Браузер обычно посылает на сервер и информацию о себе, чтобы базируясь на знании особенностей и недостатков конкретных браузеров CGI -скрипт мог выдать информацию с учетом этого. Например, разные браузеры могут поддерживать или не поддерживать какие-то HTML тэги. Пример: HTTP_USER_AGENT=Mozila/2.01 Gold(Win95; I) HTTP_HOST Имя хоста к которому обращается браузер. Так как физически на одном сервере может находиться сразу много серверов (Виртуальные Хосты), то должен быть способ сообщить серверу к какому именно идет обращение. Скрипт же может в зависимости от этой переменной производить различные действия, если он используется на сайтах сразу нескольких виртуальных хостов. Пример: HTTP_HOST=www.nnov.city.ru Начнем применять на практике усвоенные уроки. #! /usr/bin/perl #vars.cgi sub urldecode{ #очень полезная функция декодирования local($val)=@_; #запроса, будет почти в каждой вашей CGI-программе $val=~s/\+/ /g; $val=~s/%([0-9A-H]{2})/pack(‘C’, hex($1))/ge; return $val; } print " Content-Type: text/html\n\n"; print " < HTML> < HEAD> < TITLE> CGI-Variables< /TITLE> < /HEAD> \n"; print " < BODY> \n"; print " Enter here something: < ISINDEX> < BR> \n"; print " Your request is: $ENV{‘REQUEST_STRING’}< BR> \n"; print " Decoded request is: urldecode($ENV{‘REQUEST_STRING’}) < BR> \n"; print " < HR> \n"; print " Variables: < BR> \n"; print " < I> < B> REQUEST_METHOD< /B> < /I> =$ENV{‘REQUEST_METHOD’} < BR> \n"; print " < I> < B> QUERY_STRING< /B> < /I> =$ENV{‘QUERY_STRING’} < BR> \n"; print " < I> < B> CONTENT_LENGTH< /B> < /I> =$ENV{‘CONTENT_LENGTH’}< BR> \n"; print " < I> < B> CONTENT_TYPE< /B> < /I> =$ENV{‘CONTENT_TYPE’}< BR> \n"; print " < I> < B> GATEWAY_INTERFACE< /B> < /I> =$ENV{‘GATEWAY_INTERFACE’} < BR> \n"; print " < I> < B> REMOTE_ADDR< /B> < /I> =$ENV{‘REMOTE_ADDR’}< BR> \n"; print " < I> < B> REMOTE_HOST< /B> < /I> =$ENV{‘REMOTE_HOST’}< BR> \n"; print " < I> < B> SCRIPT_NAME< /B> < /I> =$ENV{‘SCRIPT_NAME’}< BR> \n"; print " < I> < B> SCRIPT_FILENAME< /B> < /I> =$ENV{‘SCRIPT_FILENAME’} < BR> \n"; print " < I> < B> SERVER_NAME< /B> < /I> =$ENV{‘SERVER_NAME’}< BR> \n"; print " < I> < B> SERVER_PORT< /B> < /I> =$ENV{‘SERVER_PORT’}< BR> \n"; " < I> < B> SERVER_PROTOCOL< /B> < /I> =$ENV{‘SERVER_PROTOCOL’}< BR> \n"; " < I> < B> SERVER_SOFTWARE< /B> < /I> =$ENV{‘SERVER_SOFTWARE’}< BR> \n"; print " < I> < B> HTTP_ACCEPT< /B> < /I> =$ENV{‘HTTP_ACCEPT’}< BR> \n"; " < I> < B> HTTP_USER_AGENT< /B> < /I> =$ENV{‘HTTP_USER_AGENT’}< BR> \n"; print " < I> < B> HTTP_HOST< /B> < /I> =$ENV{‘HTTP_HOST’}< BR> \n"; print " < HR> \n"; print " All enviroment: < BR> \n"; foreach $env_var (keys %ENV){ print " < I> $env_var=$ENV{$env_var}< /I> < BR> \n"; } print " < /BODY> < /HTML> \n"; Так как все ваши.cgi-файлы должны быть исполняемыми, то чтобы облегчить себе жизнь заведите в директории cgi-bin командный файл mkcgi, содержащий: #! /bin/sh #mkcgi chmod +x *.cgi Сделайте его в свою очередь исполняемым chmod +x mkcgi — он сильно упростит вам жизнь. Ну, а теперь запускайте скрипт... Изучив информацию, выдаваемую данным скриптом, вы сможете лучше ориентироваться в переменных окружения CGI. Заголовки запросов и ответов Даже если вы и знаете кое-что о HTTP, все равно не лишнее будет вспомнить о том, как это все работает, тем более на эту информацию придется ориентироваться при написании CGI скриптов. Этапы соединения Первый этап — это когда HTTP — клиент (браузер) соединяется с сервером. Для этого он использует протокол TCP/IP. Соединение происходит к известному клиенту TCP -порту ( 80 — номер порта HTTP (другие сервисы сидят на других портах, например FTP и SMTP на 21 и 25 )). На втором этапе идет запрос клиента: клиент передает заголовок запроса и возможно (в зависимости от метода) тело сообщения запроса. В заголовке обязательно указывается метод URI и версия HTTP и может быть еще несколько необязательных полей. Третий этап — ответ сервера, который опять таки состоит из заголовка, в котором сервер указывает версию HTTP и код статуса, который может говорить об успешном или неуспешном результате и его причинах. Далее идет тело ответа. На четвертым этапе происходит разрыв TCP/IP -соединения. полей. HTTP-запрос Запрос состоит из Строки запроса (она обязательна) и остальных. Синтаксис строки: МЕТОД < SP> URI < SP> HTTP/версия < CRLF> Где < SP> — пробел, < CRLF> — переход на новую строку. Методы HTTP GET Самый часто применяемый метод, в протоколе HTTP/0.9 был единственным методом и применялся для извлечения информации по заданному URI. Может быть условным, если в заголовке указано поле If-Modified-Since: HEAD Почти идентичен GET, но отличается тем, что сервер не возвращает тело объекта, а только его заголовок (метаинформацию). Программы могут применять его для проверки гиперссылок на правильность, доступность и изменения. POST Передает данные для обработки их программой, указанной в URI. Здесь обязательно указывается поле Content-Length: Существуют и другие, реже применяемые методы, например PUT — для сохранения передаваемых данных в указанном URI и DELETE для удаления ресурса. Поля заголовка запроса После строки запроса идут поля заголовка запроса. Поля общего ( general-header ) заголовка (он общий как для запросов, так и для ответов): Date: Указывает дату запроса, например: Date: Sun, 20 Nov 1994 08: 12: 31 GMT MIME-version: Указывает версию MIME (по умолчанию 1.0 ): MIME-version: 1.0 Pragma: Содержит указания для таких промежуточных агентов, как прокси и шлюзы: Pragma: no-cache Поля, относящиеся к запросу (Request-Header): Authorization: Содержит информацию аутентификации: Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== From: Браузер может посылать адрес пользователя серверу: From: quake@doom.ru If-Modified-Since: Используется при методе GET, ресурс возвращается, если он был изменен с указанного момента, может использоваться при кэшировании. If-Modified-Since: Mon 15 Jul 1997 00: 15: 24 GMT Referer: Содержит URL предшествующего ресурса. Referer: http: //www.uic.nnov.ru/~paaa/index.html User-Agent: Программное обеспечение клиента. User-Agent: Mozilla/3.0 Заголовок информации сообщения ( Entity-Header ) применяется как в запросах, так и в ответах (при этом некоторые поля только в ответах). Allow: (в ответе сервера) Список методов, поддерживаемых ресурсом. Allow: GET, HEAD Content-Encoding: Идентифицирует метод кодировки, которым был закодирован ресурс. Content-Encoding: x-gzip Content-Length: Длина тела сообщения. Content-Length: 102 Content-Type: Содержит тип ресурса ( MIME ), для текстовых и кодировку символов (необязательно). Content-Type: text/html; charset=windows-1251 Expires: (в ответе сервера) Дата окончания действия ресурса применяется в кэшировании для запрета кэширования устаревших ресурсов (в ответе). Expires: Tue, 24 Sep 1998 23: 00: 15 GMT Last-Modified: (в ответе сервера) Время последнего обновления ресурса. Last-Modified: Tue, 23 sep 1998 13: 48: 40 GMT Другие поля: Поля Accept: Указывают серверу выдавать только указанные форматы данных, которые клиент может распознать. Accept: Accept: Accept: text/html text/plain image/gif Поле Host: Служит для того, чтобы указать, к какому хосту идет обращение. Данное поле не входит в число обязательных. Однако оно является необходимым в тех случаях, когда одному физическому серверу соответствует несколько виртуальных хостов. Тогда в этом поле указывается какой из виртуальных хостов имеется в виду. Host: www.nnov.city.ru Примеры запросов Простейший запрос: GET /index.html HTTP/1.0 Посложнее: GET /somedir/somedoc.html HTTP/1.0 User-Agent: Mozilla/2.0 Accept: text/html Accept: text/plain Accept: image/gif Передача данных CGI-скрипту через метод GET: GET /~paaa/cgi-bin/test.cgi? name=Dmitry& organization=%D3%ED%E8%E2%E5%F0%F1%E8%F2%E5%F2+%CD%E8% E6%ED%E5%E3%EE+%CD%EE%E2%E3%EE%F0%EE%E4%E0 & Name=& email=& comment= HTTP/1.0 User-Agent: Mozila/2.0 Accept: text/html Accept: image/gif Используя метод POST, данные передаются в теле сообщения за- проса: POST /~paaa/cgi-bin/test.cgi HTTP/1.0 User-Agent: Mozila/2.0 Accept: text/html Accept: image/gif Content-Type: application/x-www-form-urlencoded Content-Length: 131 name=Lesha & organization=%D3%ED%E8%E2%E5%F0%F1%E8%F2%E5%F2+%CD%E8 %E6%ED%E5%E3%EE+%CD%EE%E2%E3%EE%F0%EE%E4%E0& Name= & email= & comment= Ответ HTTP-сервера Ответ идет от сервера. Состоит он из строки состояния и поля ответа. Общий заголовок ( General-Header ), заголовок тела сообщения ( Entity-Header ), которые уже описаны при обсуждении запроса и заголовок ответа ( Response-Header ). Строка состояния имеет следующий формат: HTTP/version < SP> Status-Code < SP> Status-Phrase Где HTTP/version — версия, Status-Code — 3-х значный код, и Status-Phrase — текстовая фраза, поясняющая код. Например: HTTP/1.0 200 Ok 200 — код, означающий успешную обработку запроса, что и поясняет «Ok» Заголовок ответа состоит из полей: Location: Содержит URI ресурса, может быть использован для переключения клиента в другое место, если например ресурс был перемещен в другое место или на другой сервер. Location: http: //www.uic.nnov.ru/newlocation/index.html Server: Информация о программном обеспечении сервера. Server: Apache/1.1 WWW-Autenticate: Параметры аутентификации. WWW-Autenticate: Basic realm=" doomsday" Коды ответов HTTP Более подробное описание всех кодов можно найти в RFC-1945. Несколько примеров: HTTP/1.0 200 Ok Date: Wed, 25 Sep 1998 23: 00: 00 GMT Server: Apache/1.1 MIME-version: 1.0 Last-Modified: Mon 15 Nov 1996 15: 20: 12 GMT Content-Type: text/html Content-Length: 2000 < HTML> < HEAD> < TITLE> Hello< /TITLE> < /HEAD> < BODY bgcolor=" green" text=" yellow" > ...... < /HTML> А вот такое сервер выдаст в неудачном случае: HTTP/1.0 404 Not Found CGI-заголовок В том случае, когда запрашиваемый URI есть CGI -скрипт, сервер, базируясь на данных запроса создает среду переменных CGI и передает управление скрипту. Скрипт должен выдать CGI-заголовок, после которого и идет тело ответа, сгенерированное скриптом. Заголовок ( CGI-Header ) состоит из полей: Content-Type: Должно обязательно присутствовать, если есть тело. Content-Type: text/html Location: Содержит URL ресурса, на который скрипт перенаправляет запрос. Как правило, если присутствует это поле, больше ничего не указывается. Location: http: //www.idsoftware.com/index.html Status: Позволяет CGI скрипту вернуть статус обработки, если это поле не задано, то сервер подразумевает «200 Ok» Status: 404 Not found На базе этой информации сервер и формирует окончательный заголовок, который и передается клиенту. Примеры: Обычно такое выдает скрипт: Content-Type: text/html < HTML> < HEAD> ....... Но иногда такое (когда он служит для перенаправления): Location: http: //www.mustdie.ru/ А вот пример возврата статуса: Content-Type: image/gif Status: 190 Its seems great like a playing doom! WOW! GIF89a........ Nph-скрипты Иногда возникает необходимость чтобы CGI -скрипт сам отвечал напрямую клиенту, минуя разбор заголовка. Это во-первых уменьшает нагрузку на сервер и во-вторых, что самое главное, такой прямой ответ клиенту позволяет скрипту полностью контролировать транзакцию. Для этого существуют nph- скрипты (Not Parse Header), имя скрипта должно начинаться с префикса «nph-». Например: «nph-animate.cgi». Такие скрипты сами формируют HTTP -ответ клиенту, что полезно при анимации: #! /usr/bin/perl #nph-animate.cgi $times = 20; #Заготовьте несколько небольших gif-файлов для этой программы @files = qw(img0.gif img1.gif img2.gif img3.gif); select (STDOUT); $|=1; #autoflush mode on #Generate header print " HTTP/1.0 200 Okay\n"; print " Content-Type: multipart/x-mixed-replace; boundary=mybound-ary\n\n"; print " —myboundary\n"; for ($num=1; $num< =$times; $num++) { foreach $file (@files) { print " Content-Type: image/gif\n\n"; open(PIC, " $file" ); print < PIC>; close(PIC); print " \n—myboundary\n"; sleep(3); } } print " \n—myboundary—\n"; Этот пример выдаст вам анимацию, составленную из нескольких .gif -файлов. Права доступа Сидя в пределах своей домашней директории и качая с Интернета всякую фигню, вы возможно и не задавались некоторыми вопросами, а зря. Ведь немного надо, чтобы попортить нервы начинающему CGI -программисту. Одна из таких вещей — это права доступа. Начнем с того, что в системе Unix каждый пользователь имеет свой идентификатор — число, уникально идентифицирующее его в этой системе (например, логин paaa, а ему соответствует число 1818). Это число внутреннее для операционной системы, для пользования оно представлено как логин, который и соответствует пользователю. Только не надо думать о пользователе как о конкретном человеке, сидящим за клавиатурой, пользователем может быть и какой-нибудь процесс. Важно отметить что пользователь — это определенная область прав доступа, которая ему соответствует. Вы, например, не можете обычно писать и удалять файлы из каталога другого пользователя. Это и дает возможность стабильной работы всей системы. Итак, есть идентификатор пользователя. Также имеется идентификатор группы. Группа служит для выделения пользователей по группам. Например, у пользователей группы users (обычные пользователи) не такие права, как у группы wheels (административная группа). Каждый процесс, который вами запущен (будь то Netscape, терминал, или текстовый редактор), получают ваши идентификаторы пользователя и группы. Таким образом они исполняются от вашего имени. Теперь рассмотрим повнимательнее файловую систему. В Unix с файлом связано много характеристик. Во-первых — в системе нет «ничьих» файлов, все файлы имеют владельца-пользователя и владельца-группу. Любой файл, который вы создаете автоматически получает ваш идентификатор. Поэтому система очень легко отслеживает, чьи это файлы и каталоги. Следующее новшество, по сравнению с DOS — это права доступа к файлу. Их может сменить только тот пользователь, которому принадлежит файл, или супервизор (это в отличии от DOS, где каждая дрянь типа вируса может снять атрибут readonly читать и писать все файлы). Права доступа задаются обычно числом в восьмеричной записи и разбиты на 3 части по 3 бита. Каждая часть задает права доступа для конкретной группы.
В каждой такой категории выделяются 3 права:
Все права и атрибуты очень наглядно показываются командой ls с ключом l. Так как исполнять каталоги бессмысленно, то право на исполнение для них означает право обращаться к файлам из этого каталога. Изменяются права командой chmod, ее синтаксис такой: chmod [u|g|o]{+|-}{r|w|x} file chmod number file Где:
Примеры: chmod +r file.txt #разрешает всем право на чтения файла chmod u+w file.txt #устанавливает для владельца файла право на запись в него chmod +x gbook.cgi #право на исполнение для всех, как для пользователя, группы и для других chmod 0777 cgi-bin #Разрешает самые широкие права доступа для cgi-bin При открытии файла программой, операционная система сравнивает идентификатор пользователя с идентификатором пользователя владельца файла, если они равны, то действуют права пользователя, если не равны, то сравниваются идентификаторы группы, если и они не равны, то действуют права доступа для остальных остальных. В том случае, если у процесса нет достаточных прав, система возвращает ошибку. Следует заметить, что для супервизора root права доступа не проверяются. Можно выполнить скрипт, только если есть права на его исполнение. Вот почему следует давать chmod +x *.cgi, иначе ваши скрипты станут просто недоступными. Но и это еще не все. Ваш скрипт может обращаться к вашим файлам (например ведет базу данных гостевой книги). Все выглядит нормально, но только ничего не работает, файл в который вы намеревались писать, не открывается. Знакомая проблема? Так вот, чтобы вы не мучились в догадках ваш скрипт не может получить доступ к вашим файлам, потому что он выполняется не вами (не с вашим идентификатором), а от имени nobody (непривилегированный пользователь). Эта мера предосторожности направлена на то, чтобы скрипты, взбесившись из-за неправильно переданных параметров (или вообще от глюков), не могли ничего повредить ценного и важного на сервере. Поэтому тем файлам, к которым скрипт по смыслу должен обращаться, нужно присвоить самые широкие права доступа 0777. Например в случае гостевой книги: chmod 0777 guestbook.dat Если также важно чтобы скрипты могли заводить новые файлы в cgi-bin, то нужно дать также права на это: chmod 0777 cgi-bin Если вы видите, что ваш скрипт не может обратиться к какому-то файлу, то это в 99% случаях происходит из-за вашей забывчивости! На самый крайний случай воспользуйтесь setuid -скриптами (к этому делу, если вы на это решились, отнеситесь очень серьезно, так как целые тома по безопасности в Unix посвящены именно setuid -программам). Для общего развития имейте в виду следующую информацию: «Кроме указания прав доступа существуют специальные биты у файла. Это биты установки пользователя и группы. Когда процесс выполняется (простой процесс), то его реальный и эффективный идентификаторы пользователей совпадают, идентификаторы групп тоже». На самом деле значение имеют как раз эффективные значения пользователя и группы, они участвуют в сравнении прав доступа. Нельзя ли их как-то изменить, когда уж совсем нужда заставит? Можно! На этот вопрос дают ответ программы с установленным битом пользователя. Когда система запускает такую программу, она присваивает новому процессу не идентификатор того пользователя, что запустил ее, а идентификатор пользователя-владельца исполняемого файла. Самый классический пример setuid -программ — это программа passwd, предназначенная для смены пароля пользователя. Такие данные, как пароль и прочие характеристики пользователей, хранятся в специальном файле, который имеет огромное значение при входе в систему. Так как это системный файл, то открыть к нему доступ на запись всем — значит подвергнуть всю систему риску, ведь любое неправильное изменение его повлечет катастрофические последствия (в конце концов бывает просто хулиганство). Поэтому доступ к этому файлу закрыт для всех пользователей. А что, если надо сменить пароль? Запускаем программу passwd! Если глянуть на ее атрибуты, то видно, что она принадлежит root-супервизору, и еще имеет установленный бит setuid. Так корректно обходится эта проблема. Если вы все же решили попытаться, то знайте, что сделать программу setuid можно командой: chmod +s myprogramm Примерчик напоследок: эта программа выдает содержимое вашей директории public_html в том случае, если она доступна для чтения и для каждого файла указывает: можно ли его читать, писать и исполнять. Попробуйте сделать ее setuid и посмотрите как изменится результат. #! /usr/bin/perl #listmydir.cgi print " Content-Type: text/html\n\n"; if(! (-r ‘..’)){ print ".. is not allowed for reading; )))))\n"; } else{ @list=glob(‘../*’); foreach(@list){ print " < A href=\”$_\”> $_< /A> "; print " & nbsp; readable" if -r; print " & nbsp; writable" if -w; print " & nbsp; executable" if -x; print " < BR> \n"; } } Генерация ответа Стандарт MIME Стандарт MIME появился в электронной почте ( e-mail ) потому, что остро стала проблема пересылки по e-mail различных данных в различных форматах. Так как HTTP тоже работает с различными типами данных, то тоже использует MIME для своих нужд. Типы MIME состоят из Типа и подтипа. Например: text/plain где text — указывает на наличие текстового содержимого, а plain — уточняет его, как простой текст. Приведенный ниже список (он далеко не полон, типов MIME огромное количество), описывает некоторые часто встречающиеся типы:
Информация о MIME возможно пригодится вам и в том случае, если вы собираетесь работать из ваших скриптов с электронной почтой, но и для WWW она не повредит. Особенно знание Content-Type: Content-Type: Состоит из типа и подтипа. Типы могут быть как стандартные так и экспериментальные, начинающиеся с префикса «x-»: text — текстовые данные. Первый подтип, который включен сюда — это plain, что значит простой текст. Сюда же включен самый ходовой формат html. У типа text как и у многих типов могут быть параметры, главным из них является charset. Он как раз и указывает на раскладку символов, которая применена в тексте, так что если вы хотите указать браузеру какую раскладку применять, то просто укажите charset: Content-Type: text/plain; charset=us-ascii Content-Type: text/html; charset=iso-8859-1 Content-Type: text/html; charset=koi8-r multipart — данные, которые могут состоять из нескольких частей различных типов данных. Поэтому параметром multipart служит boundary, позволяющий указать разделитель. Каждый фрагмент в многочастевом сообщении имеет свой Content-Type: (он может быть также multipart, т.е. допускаются вложенные multipart, главное чтобы boundary были разными). В электронной почте применяется больше multipart/mixed (основной подтип) и multipart/alternative (он отличается тем, что показывается одна из альтернатив, например сообщение шлется в простом и HTML форматах, и почтовая программа показывает часть, которую она способна отобразить). В WWW -программировании распространен x-mixed-replace, который означает, что следующая часть должна заменить предыдущую после подгрузки, что применяется для анимации. Теперь о разделителе. Его надо выбирать так, чтобы он не встретился где-то в данных (т.е. что-то вроде «diUr344rnmvforgefvrg923rghyj2» ). Когда вы задали разделитель, например boundary=«boundary», то когда закончилась одна часть, вы должны выдать строку — boundary, последняя часть — boundary, причем эти разделители должны быть на отдельной строке, а не сливаться с текстом. Пример: MIME-Version: 1.0 Content-Type: multipart/alternative; boundary=" w23renff491nc4rth56u34-9449" —w23renff491nc4rth56u34-9449 Content-Type: text/plain; charset=" koi8-r" Hello, World!! —w23renff491nc4rth56u34-9449 Content-Type: text/html; charset=" us-ascii" < H1> Hello, Word!! < /H1> < HR> < FONT size=+1 color=red> Hello people! < /FONT> —w23renff491nc4rth56u34-9449— message — представляет инкапсулированное почтовое сообщение. Используется в e-mail, а не в WWW. image — некоторое графическое изображение (чаще всего image/ gif или image/jpeg). audio — аудиоданные. video — видеоданные. application — бинарные данные какого-нибудь приложения. В том случае, если данное приложение может быть запущено, браузер запускает его. Например при поступлении данных application/msword браузер спросит: нужно ли запустить Word для просмотра документа. При отсутствии нужного приложения браузер спросит: в каком файле сохранить данные. Подтип octet-stream как раз и означает поток байт информации, который и используется по умолчанию (к сожалению не все так гладко, известен глюк в Netscape Navigator ’е, который вместо того, чтобы сохранить application/octet-stream, пытается его показать как text/plain, и тогда если это сгенерировано из CGI — ни к чему хорошему не приводит) Что касается application, то вы можете тут смело извращаться, используя x- типы данных. Например: application/x-fuck-to-netscape-navigator Часто используемый параметр name позволяет указать имя файла. Например: Content-Type: application/msword; name=" readme.doc" Что полезно при получении файлов через HTTP, причем этот параметр может применяться и для других типов, таких как image или audio. Например: Content-Type: image/gif; name=" myfoto.gif" Content-Transfer-Encoding: Применяется больше в системе электронной почты и обозначает метод кодирования, которым были закодированы данные при передаче сообщения. Например: 7bit 8bit quoted-printable base64 binary x-типы MIME-Version: Указывает версию MIME. Браузеры Теперь поговорим о разных браузерах. Вы знаете, что браузеры бывают разные: разных версий, на разных платформах, поддерживают разные тэги и глюки у них тоже разные. Это могло попортить много нервов WEB -дизайнерам и конечно же — CGI -программистам. Профессионально написанный сайт от просто хорошего отличается тем, что хорошо выглядит не только на экране того браузера, которым пользуется сам его автор, а и на других тоже. Если вы используете JavaScript для своих страничек, то вы уже наверно использовали (или хотя бы вам в голову приходила мысль использовать) свойства navigator.AppName navigator.AppCodeName navigator.app Version navigator.userAgent: < SCRIPT language=" JavaScript" > if(navigator.AppName==" Netscape" ){ /*Сделать что-нибудь специфичное для Netscape*/ } else if(navigator.AppName==" Microsoft Internet Explorer" ){ /*Сделать что-нибудь специфичное для Explorer*/ } else{ /*Не делаем специфичных вещей-хрен его знает с каким браузером мы имеем дело*/ } < /SCRIPT> или < SCRIPT language=" JavaScript" > if((navigator.AppName==" Netscape" )& & (parseFloat (navigator.appVersion)< 3.0)){ document.writeln(”Пользуетесь слишком старым браузером”); } < /SCRIPT> Ну не волнуйтесь вы так! CGI -программисты не в самых худших условиях на этот счет. Вспомните о том, что браузер сам при запросе посылает вам данные о себе и о своей версии. И делает он это для того, чтобы эту информацию можно было учесть. В запросе он указывает User-Agent:, которое и попадает на сервере в переменную среду HTTP_USER_AGENT, которую и можно использовать. Например, если в ней содержится Mozilla/3.01Gold (Win95; I), то значит вы имеете дело с Netscape ( Mozilla — кодовое название Netscape Navigator ’а), версии 3.01Gold. Далее после имени и версии может следовать необязательная информация, как в приведенном примере о платформе Win95 и о том, является ли версия U — для США ( USA ) или I — международной ( International ). Такая информация необязательна (то есть, если браузер послал информацию User-Agent:, то гарантировано рассчитывать вы можете только на Название/Версия ). Допустим, ваш скрипт генерирует какие-то тэги, которые слишком старые браузеры не поддерживают, причем без них не обойдешься, они составляют всю «изюминку» сайта. #! /usr/bin/perl #oldbrowser.cgi print " Content-Type: text/html\n\n"; if(defined ($ENV{‘HTTP_USER_AGENT’})){ $browser=$ENV{‘HTTP_USER_AGENT’}; ($vers)=($browser=~/\/(\d+\.\d+)/); if(($browser=~/mozilla/i)& & ($vers< =2.0)){ print " < HTML> < HEAD> < TITLE> Too old! < /TITLE> < /HEAD> "; print " < BODY bgcolor=\" red\" text=\" black\" > "; print " < CENTER> < H1> Ваш Netscape Слишком старый для этого сайта"; print " (старость не радость; ))< /H1> < /CENTER> "; print " < /BODY> < /HTML> "; exit; } if(($browser=~/msie/i)& & ($vers< =3.0)){ print " < HTML> < HEAD> < TITLE> Too old! < /TITLE> < /HEAD> "; print " < BODY bgcolor=\" red\" text=\" black\" > "; print " < CENTER> < H1> Ваш Explorer устарел"; print " (а не пора ли сделать апгрейд хотя бы до 4.0 версии)< /H1> < /CENTER> "; print " < /BODY> < /HTML> "; exit; } } print " < HTML> < HEAD> ......... "; Ну, уже почувствовали, насколько это здорово?! А вот еще примерчик. Это из разряда того, что тэги бывают разные. Например, в Explorer есть тэг BGSOUND, предназначенный для проигрывания музыки на страничке (в Netscape этого тэга нет, поэтому для втыкания музыки приходится использовать подключаемые модули plugin ). Только не забывайте, что если вы не получили информацию о клиенте (так может быть, если например ваш скрипт вызвала какая-нибудь поисковая машина), то в этом случае не надо делать никаких предположений, а просто пусть ваш скрипт продолжает делать то, что должен был делать. Этот пример позволит выбирать из списка файлов и загружать то, что пользователь хочет. #! /usr/bin/perl #download.cgi sub urldecode{ local($val)=@_; $val=~s/\+/ /g; $val=~s/%([0-9a-hA-H]{2})/pack(‘C’, hex($1))/ge; return $val; } @Filelist=qw(index.html readme.txt jmj00.mid gunshot.wav foto.gif); @Sel_list=(); if($ENV{‘REQUEST_METHOD’} eq ‘GET’){$query=$ENV{‘QUERY_STRING’}; } elsif($ENV{‘REQUEST_METHOD’} eq ‘POST’){sysread(STDIN, $query, $ENV{‘CONTENT_LENGTH’}); } if($query eq ‘’){ #Если никаких данных не подано на обработку, то сгенерируем форму, которую и предложим заполнить пользователю. print " Content-Type: text/html\n\n"; print " < HTML> < HEAD> < TITLE> File Downloading< /TITLE> < /HEAD> "; print " < BODY bgcolor=\" white\" > "; print " Выберите файлы которые вы хотите загрузить: < BR> "; print " < FORM METHOD=\" POST\" > "; print " < SELECT NAME=\" file\" size=4 multiple> "; foreach(@Filelist){ print " < OPTION value=\" $_\" > $_"; } print " < /SELECT> < BR> "; print " < INPUT TYPE=\" Submit\" value=\" Download! \" > "; print " < /FORM> "; print " < /BODY> < /HTML> " } else{ @formfields=split(/& /, $query); foreach(@formfields){ if(/^file=(.*)/){push(@Sel_list, urldecode($1)); } } unless(@Sel_list){ print " Content-Type: text/html\n\n"; print " < HTML> < BODY> < CENTER> < H1> Вы должны выбрать что-то из списка"; print " < /H1> < /CENTER> < /BODY> < /HTML> "; } else{ print " Content-Type: multipart/mixed; boundary= \" bhy3e23r4t34tne-htpo7678nneu4232y213vdg\" \n\n"; print " —bhy3e23r4t34tnehtpo7678nneu4232y213vdg\n"; foreach(@Sel_list){ print " Content-Type: application/x-qwerty; name=\" $_\" \n\n"; open(F, " $_" ); print < F>; close(F); print " \n—bhy3e23r4t34tnehtpo7678nneu4232y213vdg\n"; } print " Content-Type: text/html\n\n"; print " < HTML> < H1> Thats all folks! < /H1> < /HTML> "; print " \n—bhy3e23r4t34tnehtpo7678nneu4232y213 vdg—\n"; } } Обработка форм Пришло время перейти к очень важной теме — обработке форм. При всей простоте (кажущейся) — это едва ли не самое главное предназначение всего стандарта CGI. Куда бы вы не зашли, на любой уважающий себя сайт, везде вы встретите формы, которые вам предложат заполнить. В этом деле можно положится только на CGI, так как Java и JavaScript, выполняющиеся на страничке у клиента не имеют доступа к серверу, на котором находится сайт. Коротко вспомним о том, что происходит при рассматриваемом процессе поближе. Итак, браузер требует у сервера определенный URL (это может быть как простой документ, так и сгенерированный CGI). В этом документе может содержаться форма. Отображая такой документ браузер также выводит элементы формы (кнопки, поля ввода, поля ввода пароля, переключатели, радио-кнопки, списки, текстовые области, скрытые поля). И со всем этим добром пользователь может взаимодействовать. К форме естественно имеет доступ и встроенный язык программирования JavaScript — он может как использовать форму для своих нужд, не передавая CGI, так и помогать пользователю в заполнении формы. После того, как пользователь заполнил форму он нажимает кнопку Submit, которая говорит, что форму надо отправить на сервер. Браузер собирает все имена и значения элементов формы, кодирует их методом urlencode и в зависимости от указанного в тэге FORM метода вызывает GET или POST с указанным URL, передавая ему данные. На сервере CGI -скрипту это попадает (в зависимости от метода) либо в переменную QUERY_STRING, либо на STDIN. Скрипт может проверить данные, занести их в какую-нибудь базу данных, может как yahoo выполнить какой-нибудь поиск, может что-нибудь вычислить... Да мало ли что он может, все зависит только от нашей фантазии. В конце концов скрипт выдает браузеру ответ, который он и отображает. В этом ответе может содержаться все, что вашей душе угодно — от сообщения об удачном или неправильном запросе, до таких ответов, по сравнению с которыми yahoo и altavista повиснут от зависти, главное чтобы вам и тем, кто посещает ваш сайт, это нравилось. А теперь немного о синтаксисе элементов форм, их описании и самое главное особенностях при обработке CGI -скриптом. Итак небольшой экскурс в HTML. FORM < FORM action=" http: //...... cgi" method=" GET" |" POST" enctype=" encodingType" name=" formName" target=" windowName" onSubmit=" Handler" > < /FORM> Атрибуты: action Как раз и задает тот URL, который будет обрабатывать форму, если он опущен, то текущий URL документа (а он-то может быть сгенерирован нашим скриптом). method Задает метод GET или POST. enctype Обычно не задается, для форм он application/x-www-form- urlencod-ed — по умолчанию, и поддерживается всеми CGI скриптами. Но если вы уж очень хотите, чтобы браузер послал вам данные в другом формате (например text/plain ), то можете указать этот тип кодировки, только потом не жалуйтесь, что ваш скрипт не может разделить поля, или вообще начинает глючить, когда пользователь ввел какой-то спецсимвол. name Задается для JavaScript, чтобы обращаться к форме по имени, а не по номеру. Для CGI не играет никакой роли. target Может определять в какой фрейм отправить полученную информацию. Имеет значение во фреймосодержащих документах. Прозрачен для CGI обработки данных. onSubmit Определяет Java Script — обработчик активизации формы. Применяется для проверки Java Script ’ом правильности заполнения. Опять таки прозрачен для CGI. Пример типичной формы: < FORM action=" http: //www.uic.nnov.ru/~paaa/ cgi-bin/test.cgi" method=" POST" > ......... Поля формы......... < /FORM> Форма может содержать элементы. Элементы имеют имена, которые используются для кодирования пар имя=значение. Некоторые элементы не передаются CGI, а используются Java Script для управления, например кнопки. Некоторые поля передаются только в тех случаях, когда в них что-то выбрано, например списки и переключатели. Остальные поля передаются всегда, даже когда они пустые. Например: < FORM action=" http: //www.doom/cgi-bin/test.cgi" > Your Name: < INPUT name=" Name" > < BR> E-Mail: < INPUT name=" Email" > < BR> Are you doomer: < INPUT type=" checkbox" name=" doomer" value=" Yes" > < INPUT type=" submit" value=" Send Form! " > < /FORM> Допустим, вы ввели имя lesha и адрес paaa@uic.nnov.ru, при этом выбрали переключатель. После нажатия кнопки будет отправлен вот такой запрос: http: //www.doom/cgi-bin/test.cgi? Name=lesha& Email=paaa@uic.nnov.ru& doomer=Yes Если же вы не выбрали переключатель, то запрос будет таким: http: //www.doom/cgi-bin/test.cgi? Name=lesha& Email=paaa@uic.nnov.ru Популярное:
|
Последнее изменение этой страницы: 2017-03-03; Просмотров: 1845; Нарушение авторского права страницы