Какво е CGI
- Не само скриптове за уеб-сървъри!
- Common Gateway Interface - стандартен начин за разширяване на
функционалността на сървъри чрез:
- извикване на външна програма
- предаване на параметри към нея
- четене на резултата от стандартния й изход
- интерпретиране на резултата и предаване към клиента
- Параметрите се предават през обкръжението и на стандартния
вход
- Програмата извежда резултата на стандартния си изход, след като
изведе заглавна част с допълнителна информация в стандартен
формат
CGI срещу PHP/ASP/JSP/… (1/3)
- Всяко CGI приложение се изпълнява в отделен процес!
- Предимства на CGI пред server-parsed езиците:
- може да бъде написано на всякакъв език
- може да бъде изпълнено върху всякакъв уеб-сървър
- може да бъде изпълнено с други привилегии
- не влияе върху стабилността на сървъра
CGI срещу PHP/ASP/JSP/… (2/3)
- Недостатъци на CGI пред server-parsed езиците:
- допълнително натоварване на системата за новия процес
- частен случай: допълнително време за зареждане на
интерпретатор и интерпретиране на самото CGI приложение,
ако то е написано на интерпретируем език — Perl,
Python, Ruby и т.н.
- допълнително натоварване на системата за преноса на
данни
- почти невъзможно споделяне на данни - всяка стъпка в
приложението (всяка заявка) трябва да ги извлича
наново
- частен случай: почти невъзможно споделяне на връзки
към база данни - всеки път трябва да се свързва наново,
което може да отнема време и ресурси
CGI срещу PHP/ASP/JSP/… (3/3)
- Междинен вариант: FastCGI
- един persistent процес, който обработва множество
заявки
- всичко се предава през стандартния вход
- данните могат да бъдат запазвани в процеса
- все пак е изолиран от уеб-сървъра
Изход на CGI приложението (1/2)
- На стандартния изход се извежда заглавна част във вид
„keyword: value“
- Content-Type: какво точно ще върнем на
клиента, стойностите са според спецификациите за MIME
(Multipurpose Internet Mail Extensions, явно дори
по-многоцелеви, отколкото авторите им са предполагали):
- text/plain
- text/plain; charset="windows-1251"
- text/html
- image/gif
- x-application/…
- много други; за повече информация - MIME
RFC-тата или списък от типове, който има в
конфигурацията на всеки уеб-сървър и на
повечето браузъри.
- Content-Length: дължина на резултата в
байтове
Изход на CGI приложението (2/2)
- Content-Length не е строго задължителна за
обикновени CGI приложения, но много помага на сървърите.
Абсолютно задължителна е за FastCGI.
- След заглавната част се извежда празен ред, последван от самото
съдържание на резултата. Ако е зададена
Content-Length, сървърът ще прочете точно
толкова байтове, иначе до края на изхода.
Типове заявки (1/2)
- Променлива REQUEST_METHOD — тип на
заявката, т.е. начин на предаване на параметрите
- Два основни типа, GET и POST
- GET — информацията се предава чрез
променливата QUERY_STRING
- просто извикване
- проста обработка
- обикновено има ограничение на дължината
- по време на работата на CGI приложението всички параметри
се виждат от всеки потребител на системата, който има
право да види обкръжението на процеса (обикновено чрез
„ps -e“)
Типове заявки (2/2)
- POST — информацията се подава на
стандартния вход на програмата
- не толкова просто извикване: трябва да има двупосочна
връзка между родителския процес (сървъра) и
процеса-наследник (CGI приложението)
- почти толкова проста обработка
- няма ограничение за дължината на подаваните данни
- няма начин да бъде подслушан преносът на данни
GET заявки (1/2)
- REQUEST_METHOD="GET"
- Параметрите се подават чрез променливата
QUERY_STRING като двойки var=value,
разделени със символ „амперсанд“ (&)
- Специални символи като амперсанд, знак за равенство, символ за
нов ред и др. се представят с т.нар. URL encoding: знак за
процент, последван от две шестнадесетични цифри (%2F за
„/“, %0D за нов ред и т.н.)
- Символът „+“ означава интервал, а самият плюс се
подава чрез URL encoding като %2B
GET заявки (2/2)
- CGI GET заявки се използват при HTTP
GET заявки, когато всички параметри се подават
след „?“ в URL-то; това се копира почти директно в
съдържанието на QUERY_STRING
- Примери:
Пример: printenv (1/2)
#!/usr/bin/perl -wT
use strict;
my ($q, $s, $len, @vars);
@vars = sort keys %ENV;
$s = '';
$q = $ENV{'QUERY_STRING'};
if (defined($q) && length $q) {
my %v;
foreach (split /\&/, $q) {
my ($var, $val) = split /=/, $_, 2;
$var =~ tr/+/ /;
$val =~ tr/+/ /;
$var =~ s/\%([0-9A-F]{2})/@{[pack("H*", $1)]}/gix;
$val =~ s/\%([0-9A-F]{2})/@{[pack("H*", $1)]}/gix;
$v{$var} = $val if (defined($var) && defined($val));
}
if (defined($v{'vars'})) {
@vars = grep /^\Q$v{vars}\E/, @vars;
}
}
Пример: printenv (2/2)
$s .= join '', map { "$_=$ENV{$_}\n" } @vars;
{
use bytes;
$len = length $s;
};
print "Content-Type: text/plain\nContent-Length: $len\n\n$s";
POST заявки
- REQUEST_METHOD=POST
-
- Всички данни се подават на стандартния вход на програмата като
последователност от редове във формат var=value
- Изключение: multipart/form-data
- Данните се обработват и декодират като при GET
- CGI POST заявки се използват при HTTP
POST — обикновено когато съдържанието е
прекалено дълго за предаване в самото URL или пък по някаква
причина не трябва да се появява в логове и т.н.
- CGI POST заявки с
multipart/form-data са единственият начин за
предаване на файлове към HTTP сървър — или поне
единственият начин, поддържан от всички браузъри и от всички
сървъри преди DAV PUT
POST заявки с multipart съдържание
- REQUEST_METHOD=POST,
CONTENT_TYPE=multipart/form-data
- Всички данни се подават на стандартния вход, но са форматирани
като MIME съобщение (body) с няколко MIME части (body parts)
- В една от частите, обикновено първата, се съдържат дефиниции
на параметри в добрия стар формат var=value
- Останалите части имат различен Content-Type,
който задава тип и име на upload-ваните данни — най-често
се използва за upload-ване на файл.
- Много трудно за обработка на ръка: необходимо е познаване на
MIME, разбиване на MIME body на отделни body parts, декодиране
на всички видове quoted-printable, base64 и други начини за
представяне на нетекстово съдържание и т.н.
CGI на Perl със CGI.pm (1/2)
- CGI.pm — стандартен модул за улесняване на разработката
на CGI приложения на Perl
- По принцип има възможности за показване на HTML forms, но те
на практика не се използват никога освен при много прост дизайн
- Конструктор new() — създава нов CGI.pm
обект, който ще анализира една заявка
- new(string) — анализира
GET заявка, подава се
QUERY_STRING
- new(FILEHANDLE) — анализира
POST заявка, подава се файл, от който
CGI.pm ще прочете данните
- new() — автоматично обработва
GET и POST заявки:
проверява $ENV{'REQUEST_METHOD'}, за
да определи дали да извика
new($ENV{'QUERY_STRING'}) или
new(\*STDIN)
CGI на Perl със CGI.pm (2/2)
- Функция param() — взимане на параметри
на заявката
- param() — масив, съдържащ
имената на параметрите
- param(name) — стойността на
определен параметър
Пример: printenv-cgi
#!/usr/bin/perl -wT
use strict;
use CGI;
my ($cgi, $prefix, $s, $len, @vars);
@vars = sort keys %ENV;
$cgi = new CGI();
$prefix = $cgi->param('vars');
if (defined($prefix)) {
@vars = grep /^\Q$prefix\E/, @vars;
}
$s .= join '', map { "$_=$ENV{$_}\n" } @vars;
{
use bytes;
$len = length $s;
}
print "Content-Type: text/plain\nContent-Length: $len\n\n$s";