CGI handleiding

Common Gateway Interface of kortweg CGI is een internettechnologie die communicatie over HTTP mogelijk maakt tussen een client (bijvoorbeeld een browser) en een server (bijvoorbeeld een webserver). We leggen het protocol kort uit, waarbij we gebruik maken van je persoonlijke UGent webshare (webssh.ugent.be).

Een webserver voert HTTP serversoftware uit die antwoordt (response) op vragen (request) van een browser. Doorgaans heeft de HTTP server een bepaalde directory waar de bestanden staan die naar een webbrowser kunnen gestuurd worden vanaf de webserver. Op webssh.ugent.be is dat de directory WWW onder je home directory. De inhoud van het bestand ~/WWW/test.txt kan je dan opvragen met de URL

http://users.ugent.be/~loginnaam/test.txt

waarbij je uiteraard ~loginnaam vervangt door je eigen loginnaam.

CGI breidt het HTTP protocol uit door de eigenaar van de webserver toe te laten om een directory aan te wijzen waarin uitvoerbare scripts kunnen geplaats worden, in plaats van bestanden met een vaste inhoud. Deze directory staat gekend als de CGI directory. Op webssh.ugent.be is dit de directory ~/WWW/cgi-bin. Als een browser een URL gebruikt die wijst naar een bestand in die CGI directory, bijvoorbeeld

http://users.ugent.be/~loginnaam/cgi-bin/demo.cgi

dan zal niet de inhoud van dat bestand naar de browser gestuurd worden, maar zal de HTTP server het script uitvoeren en de uitvoer van het script terugsturen naar de browser. Specifieker gezegd, wordt alles wat het script uitschrijft naar standard output naar de browser teruggestuurd in plaats dat het op de terminal wordt uitgeschreven (via output redirection die door de webserver geregeld wordt). Stel bijvoorbeeld dat je het volgende script op je webshare plaatst op de locatie ~/WWW/cgi/demo.cgi (op de UGent webshare moet het bestand in de CGI directory niet enkel uitvoerbaar zijn, maar ook eindigen op de extensie .cgi).

#!/bin/bash

# send content type: plain text
echo "Content-type: text/plain"

# send empty line
echo

# send overview of all environment variables
set

Als dit script wordt uitgevoerd, dan wordt eerst een regel met de tekst Content-type: text/plain naar standard output geschreven. In het HTTP protocol bestaat het antwoord van een server immers uit twee delen: een header en de body van het antwoord. Deze twee delen worden van elkaar gescheiden door een lege regel. De header bestaat uit een aantal sleutel-waarde paren, waarbij de sleutel een bepaalde eigenschap van het antwoord omschrijft. De sleutel en de bijhorende waarde worden van elkaar gescheiden door een dubbelpunt. De webserver zal zelf verschillende sleutel-waarde paren aan het antwoord toevoegen, aangevuld met sleutel-waarde paren die het script er zelf aan toevoegt. In dit geval geven we aan dat het antwoord platte tekst zal bevatten (en bijvoorbeeld geen HTML5 of JSON of een afbeelding). Daarna schrijft het script dus een lege regel uit om aan te geven dat de header wordt afgesloten. Finaal schrijft het shell script ook nog alle omgevingsvariabelen uit door gebruik te maken van het commando set zonder argumenten. Als je nu met je browser het antwoord bekijkt, dan krijg je iets te zien dat er als volgt uitziet

$ wget -qO- "http://users.ugent.be/~loginnaam/cgi/demo2.cgi"
BASH=/bin/bash
BASHOPTS=cmdhist:complete_fullquote:extquote:force_fignore:hostcomplete:interactive_comments:progcomp:promptvars:sourcepath
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
BASH_CMDS=()
BASH_LINENO=([0]="0")
BASH_SOURCE=([0]="demo2.cgi")
BASH_VERSINFO=([0]="4" [1]="3" [2]="30" [3]="1" [4]="release" [5]="x86_64-pc-linux-gnu")
BASH_VERSION='4.3.30(1)-release'
...

Bovendien laat het CGI protocol ook toe dat een browser informatie naar het script kan sturen via de URL (HTTP GET request) of via een HTTP POST request. Indien je onmiddellijk na de naam van het script een slash en een bijkomende directorynaam toevoegt aan de URL, dan wordt die padnaam opgeslaan in de omgevingsvariabele PATH_INFO voordat het script wordt aangeroepen. Indien er argumenten worden meegestuurd naar het script via een HTTP GET request (aangegeven door een vraagteken na de URL, gevolgd door een reeks naam=waarde paren die van elkaar worden gescheiden door ampersands), dan worden deze argumenten opgeslaan in de omgevingsvariabele QUERY_STRING voor het script wordt aangeroepen. Indien de argumenten naar het script worden doorgestuurd via een HTTP POST request, dan worden ze via standard input doorgegeven aan het script. Het script kan dan op de gepaste manier deze omgevingsvariabelen inlezen en de waarden ervan gebruiken om dynamisch een antwoord te genereren dat naar de browser wordt teruggestuurd.

Als we het bovenstaande CGI script aanroepen via een HTTP GET request waarbij we enkele extra argumenten doorgeven

http://users.ugent.be/~loginnaam/cgi/demo.cgi?x=3&y=4

dan kunnen we die tussen de omgevingsvariabelen terugvinden

$ wget -qO- "http://users.ugent.be/~loginnaam/cgi/demo2.cgi"
BASH=/bin/bash
...
QUERY_STRING='x=3&y=4'
...

Tip: CGI zal standaard enkel de standard output naar de browser sturen. De standard error wordt weggeschreven naar /dev/null wat soms lastig kan zijn bij het debuggen. Je kan tijdens het debuggen exec 2>&1 bovenaan je script toevoegen waardoor ook de standard error in je browservenster zal verschijnen.

Opgave

Voor deze opgave moet je op je UGent homepage een CGI script plaatsen dat de argumenten die werden meegestuurd met de GET request onder elkaar uitschrijft, samen met hun waarde. Het exacte formaat kan je hieronder vinden. Voor deze opgave moet je enkel je UGent gebruikersnaam indienen.

Voorbeeld

$ curl -L "http://users.ugent.be/~loginnaam/cgi-bin/parameters.cgi?a=3&b=5"
De waarde van a is 3
De waarde van b is 5

Bronnen