CGI

Webpage generating programs invoked by server software that operate according to the CGI specification are known as CGI scripts. This specification was quickly adopted and is still supported by all well-known server software, such as ApacheIIS, and (with an extension) node.js based servers.

На практика, всяка програма/скрипт може да бъде CGI софтуер, щом може:
1. да чете от stdin;
2. да пише на stdout;
3. да чете environment променливи от Операционната система и уебсърва;
4. да бъде извиквана от уебсърва.

Идеята на CGI е да бъде стандарт, задаващ как информцията постъпила от клиента към уебсървъра, да бъде предадена към външна програма, която да я обработи, и да я върне на уебсървъра, който да я върне на клиента.

Защо? Защото вече почти винаги, не е достатъчно уебсърва просто да върне някаква статична информация, а трябва да извика допълнителен софтуер, бил той скрипт или компилирана програма, която да свърши доста друга работа, като например – работа с бази данни, комуникация с други сървъри и т.н….

Демек, „мостът“ между уебсърва и скрипта (PHP, Perl…), който най-често (но не задължително) е на сърва, обработващ HTTP заявката.

Затова се говори за общ интерфейс или стандарт. За да могат различни езици за програмиране да работят по унифициран начин с уебсърва, спазвайки този стандарт.

Initially, different server software would use different ways to exchange this information with scripts. As a result, it wasn’t possible to write scripts that would work unmodified for different server software, even though the information being exchanged was the same. Therefore, it was decided to specify a way for exchanging this information: CGI (the Common Gateway Interface, as it defines a common way for server software to interface with scripts). Webpage generating programs invoked by server software that operate according to the CGI specification are known as CGI scripts.

За да може една програма да бъде използвана като CGI програма, трябва да може да чете от стандартният input (stdin), да пише на стандартният output (stdout), и да може да достъпва environment variables на сървъра.

Такава програма може да бъде както скриптове, така и компилирани, изпълними файлове.

CGI Задълженията на уебсърва са:
  • когато уебсърва получи HTTP заявка, той има две възможности – или директно да върне поисканият ресурс, или да извика даденият скрипт/изпълним файл, който да обработи заявката и да върне HTTP резултатът си на уебсърва, който да върне на клиента HTTP респонсът.
  • във вторият случай – да стартира поисканият в рекуста скрипт/изпълним файл.
  • кое от двете да се случи, зависи от конфигурации на уебсърва, с които му казваш „филета с такова разширение – викай този скрипт/изпълним файл…. филета с такова разширение – такъв….“ Демек, по разширение се определя кой да обработи даденият HTTP рекуест.
    Не точно!
    Общата конвенция е, че CGI изпълним файл трябва да е в cgi-bin директорията. По конвенция – всичко що е там трябва да е изпълним файл и се приема за т.н. CGI script.
    A common convention is to have a cgi-bin/ directory at the base of the directory tree and treat all executable files within this directory (and no other, for security) as CGI scripts.
  • да му предаде данните от HTTP заявките (хедъри и бодито)
  • да получи готовият HTTP response (response code, хедъри и бодито) и да го върне на клиента. Което повдига логичният въпрос – ОК, когато скрипт/изпълним файл обработва HTTP заявката, той трябва да зададе response хедърите. Но ако е статичен контент, и няма нужда от гореспоменатите, значи уебсърва отговаря освен разбира се за бодито, така и за responsе хедърите.
един пример

Имаме клиент, който отправя HTTP заявка към сърва, тази заявка по стандарт съдържа т.н. request line, напр. POST /path/to/something HTTP/1.1 , който както се вижда показва HTTP методът, URI-ят и версията на HTTP протоколът.

Добре, но даденият URI показва скриптът/програмата, която да го обработи. Следователно, тя трябва да бъде извикана, както и информацията от HTTP рекуестът трябва да и бъде предадена – хедъри, самите данни…

Уебсървърът… той е просто казано един „портиер“, идват люде при него, този за това, онзи за онова… и той им извиква съответният софтуер, който да ги обслужи. И начинът на викане на съответният софтуер, както и предаването на информацията от даденият човек, към даденият софтуер, това е идеята на CGI.

Портиер, но от малко по-горна категория. Демек, да база това какво точно иска даденият човек като услуга, той вика съответният софтуер, като му предава и документите, които човекът носи със себе си. Демек, не просто „Идете на етаж втори, кабинет 230“, а по-скоро „Искате разрешително за еди какво си, дайте ми бумагите и папките си, аз ей сега ще извикам Иван Иванов от етаж втори, кабинет 230, ще му дам Вашите папки и бумаги, и той ще има грижата като ми върне готовото разрешително, аз да Ви го върна на Вас“.
Нали съм все пак уебсърв… така де… портиер…

E, ако е нещо статично и няма нужда да се вика някой като Иван Иванов, и портиерът може сам да ви помогоне, той ще го направи.

The web server then launches the CGI script in a new computer process, passing the form data to it. The output of the CGI script, usually in the form of HTML, is returned by the script to the Web server, and the server relays it back to the browser as its response to the browser’s request.

Отделно, да не забравяме, че „Иван Иванов“ трябва да върне и служебна информация, под формата на HTTP хедъри, като например, това което връща какъв тип документ е и т.н…
…upon returning, the script must provide all the information required by HTTP for a response to the request: the HTTP status of the request, the document content (if available), the document type (e.g. HTML, PDF, or plain text), et cetera.

Как става самото предаване на HTTP заявката, получена от уебсърва, към CGI софтуера?

Чрез сетване на стойности на т.н. environmet variables.

Демек:
For instance, if a slash and additional directory name(s) are appended to the URL immediately after the name of the script (in this example, /with/additional/path), then that path is stored in the PATH_INFO environment variable before the script is called.
Ето, имаме вече една environment variable сетната със стойност…

Ако имаме query string в URI-я, тогава ще имаме друга environment variable – QUERY_STRING, която ще съдържа всичко от URI след „?“.
Демек, ако имаме URL: http://localhost/i.php?asd=123&qwe=456
QUERY_STRING ще е asd=123&qwe=456
ПРЕДИ СКРИПТЪТ/ИЗПЪЛНИМИЯТ ФАЙЛ да бъде стартиран.

Демек, първо се сетват environment променливите, после се стартира каквото трябва, иначе не би било логично.

Какво са т.н. „environment variables“? Променливи, действащи от страна на компютъра или средата, в която работи даденият процес. Това са применливи-настройки, с които операционната система да зададе определени стойност на даденият процес.

Друго важно за „environment vars“ е , че уебсърва ДОБАВЯ свои към общият брой от тях, а не ги СЪЗДАВА от нищото. Демек, Операционната система си има и доста свои, и без уебсърва.
Some, but not all, of these variables are defined by the CGI standard. Some, such as PATH_INFOQUERY_STRING, and the ones starting with HTTP_, pass information along from the HTTP request.

Има две основни групи env променливи, които са предавани на CGI – server specific и request specific.

CGI, FastCGI и SAPI

CGI – когато уебсървърът получи заявка, стартира даденият CGI софтуер (PHP, Perl, изпълним файл…), който се унищожава след като си свърши работата.

В случаят с PHP, при всяка постъпила HTTP заявка, уебсърва знае кой изпълним файл (напр. EXE ако сме под Windows) да стартира, и да му подаде PHP скрипта, който той да интерпретира и изпълни. И да очаква резултатът, който съответно да върне на клиента.

Това е бавно, защото е свързано всеки път с четене и парсиране на конфиг файлове, зареждане на модули… Oтделно, колкото такива процеси имаме, толкова пъти това се повтаря и за всеки процес, всичко това „яде“ памет и CPU…
For a high number of HTTP requests, the resulting workload can quickly overwhelm the Web server.

Е, има и предимства. Всяка HTTP заявка е отделна за себе си, отделен процес. Стартира се, изпълнява каквото изпълнява, унищожава се и толкоз… Няма как една от тях да счупи останалите.

SAPI – тук CGI програмата е всъщност модул на уебсървъра, който добавя функционалност към него (уебсърва).
За което уебсървът трябва съответно да предостави определен интерфейс, с който да „позволи“ не само на PHP, но и на други модули да сторят това – да се интегрират към него (уебсърва), и да го „разширят“ с функционалности.

Печели се многократно повече скорост, най-малкото защото гореспоменатите действия, като парсиране на конфиг файлове, зареждане на модули и т.н… се случват еднократно, по време на стартиране на уебсървъра. Всякакви INI-та се парсват и зареждат веднъж и траят докато работи уебсърва.

Недостатък е например, че ако се срине даденият модул (PHP в нашият случай), това може да срине целият уебсърв.

Също, трябва ли да промениш някакви настройки – трябва рестарт на уебсърва.

Също, даденият моду, в нашият случай PHP, ще работи с правата на уебсърва, примерно Apache, Nginx… бидейки негов модул, което може да създаде определини проблеми с правата на ниво Операционна система.

FastCGI – тук имаме нещо като подобрена версия на CGI като разликите със CGI са следните:

  1. уебсървърът не комуникира директно с CGI програмата, а използва за посредник FastCGI модул, който модул от своя страна стартира и комуникира посредством TCP с определен брой CGI програми, които могат и да не са на същята уебсървър;
  2. CGI програмите не се унищожават, след като заявката е обслужена, а остават работещи за да чакат други заявки;
  3. След като CGI програмите може и да не са на същата машина, пърформанс скейлването би било много по-лесно.

Литература:

https://fuzzytolerance.info/blog/2006/09/13/2006-09-13-cgi-vs-sapi-vs-fastcgi/