Ari Rantala -> Oppaat -> Apache Web-palvelin: muistiinpanot

1 . Yleistä

  • Webissä (HTTP-protokolla) tapahtuva digitaalinen vallankumous -> Web-palvelimet merkittävimpiä palvelinsovelluksia
  • "Uudet" laajennokset esim. WebDAV korostavat merkitystä
  • Apache merkittävin Linuxin päällä ajettava palvelinsovellus
  • Apachen "markkinaosuus" noin 35% <URL: http://news.netcraft.com/archives/web_server_survey.html > (2015)

Apache Software Foundationin (ASF) Apache-projektin kehittämän Apache web-palvelimen kehitystyö aloitettiin maaliskuussa 1995. Apachen ensimmäinen versio pohjautui sen hetken käytetyimmän web-palvelimen, eli NCSA 1.3  palvelimen lähdekoodiin. Apachen nimi tulee sanoista "A PAtCHy server" (paikattu palvelin), koska se perustui valmiiseen NSCA-koodiin sekä siihen tehtyihin korjauksiin eli paikkoihin (eng. patch). Apache on ollut vuosia selkeästi käytetyin web-palvelinohjelmisto. Apache on ilmainen ja sen lähdekoodi on avoin.


1.1 Apachen ominaisuudet tiivistettynä

  • Tehokas
  • Tietoturvallinen
  • Saatavilla lähdekoodeineen ilmaiseksi
  • Muokattavissa hyvin moniin käyttötarkoituksiin
    • Uusien moduulien lisääminen ja Apachen toiminnan laajentaminen mahdollista.
  • Graafiset työkalut hallinnointiin ovat vaatimattomia.

Apache on perinteisesti haarauttanut (fork) palvelinprosessinsa haluttuun määrään lapsiprosesseja etukäteen (prefork). Tätä "prefork"-mallia käytetään kaikissa Apache 1.x -sarjan palvelimissa sekä oletuksena uudemmissa 2.x -sarjan Unix- ja Linux-versioissa. Näitä lapsiprosesseja pidetään aina käynnissä vapaana (idle) alustustiedostoissa määrätty määrä. Asiakkailta (yleensä selaimelta) tuleviin HTTP-pyyntöihin vastaavat juuri nämä httpd-lapsiprosessit. Näin ollen palvelinprosessin käynnistykseen ei kulu aikaa pyynnön tapahtuessa. Jokaista HTTP-pyyntöä palvelee oma prosessi. Kun palvelevien httpd-prosessien määrä lisääntyy, Apache käynnistää yhä uusia vapaita prosesseja odottamaan pyyntöjä.

Linuxissa prosessien käsittely on tehokasta, mutta joissakin järjestelmissä menettely heikentää suorituskykyä kuorman (pyyntöjen) kasvaessa. Apache 2 tarjoaa "prefork"-menetelmän lisäksi käytettäväksi nk. "worker"-menetelmää, jossa yksi lapsiprosessi voi säikeiden avulla käsitellä useita pyyntöjä. Väitetään, että Apache 2:n suorituskyky on huomattavasti parempi verrrattuna versioihin 1.3 erityisesti Windows-järjestelmissä.

1.2 HTTP-protokolla - Yleistä

HTTP (HyperText Transfer Protocol) on Web-asiakkaan ja -palvelimen keskinäiseen tiedonsiirtoon käyttämä yhteyskäytäntö. Standardoitua käytäntöä tarvitaan, että eri valmistajien palvelin- ja asiakasohjelmistot olisivat yhteensopivia keskenään. Käytettyjä versioita ovat HTTP 1.0 ja protokollan uusin versio HTTP 1.1 Nimestään huolimatta HTTP-protokolla ei rajoitu pelkästään HTML-dokumenttien siirtämiseen. Käytännössä sillä voi siirtää monenlaista dataa. Palvelin kertoo yleensä oikein konfiguroituna siirrettävän datan tyypin Content-Type-otsakkeessa.

1.3 HTTP-siirtotapahtuma

Web-palvelin kuuntelee Web-asiakkaiden asiakaspyyntöjä valitussa portissa. HTTP-siirtotapahtuma alkaa siitä, kun Web-palvelin saa asiakkaalta pyynnön. Web-palvelin käsittelee sen  ja normaalisti palauttaa selaimelle datan. Selain yrittää sitten esittää saadun datan parhaan kykynsä mukaan.

HTTP-siirtotapahtuma koostuu kahdesta HTTP-viestistä (HTTP message), jotka ovat:

  1. Asiakaspyyntö (HTTP request), jonka sisältönä on
    • Pyyntörivi (Request-Line)
    • HTTP-otsakkeet
    • Data
  2. Palvelimen vastaus (HTTP response), jonka sisältönä on
    • Tilarivi (Status-Line)
    • HTTP-otsakkeet
    • Data


kuva05_01.gif

Asiakaspyyntö

HTTP-asiakaspyyntö etenee seuraavassa muodossa

  1. Asiakas ottaa yhteyden halutun palvelimen tiettyyn porttiin (yleensä 80)
  2. Asiakas lähettää HTTP-komennon (pyyntörivi), jonka kolmesta välilyönnillä erotetusta kentästä löytyy
    • käytettävä metodi
    • pyydettävä dokumentti
    • HTTP:n versio

      Esimerkki:
      GET /manual/ HTTP/1.0
  3. Asiakas lähettää mahdolliset HTTP-otsakkeet riveittäin. Kukin rivi koostuu otsakkeen nimestä, kaksoispisteestä, välilyönnistä ja otsakkeen arvosta ja rivinvaihtomerkistä (CRLF).  Esimerkiksi Web-selain voi kertoa näin nimensä, hyväksymänsä dokumenttityypit, toivomansa kielen jne.

    Esimerkki:
    User-Agent: Mozilla/3.01Gold (Win95; I)
    Accept: image/gif, image/jpeg jne.
    Accept-Language: fi
  4. Asiakas lähettää rivinvaihtomerkin (CRLF ~ tyhjä rivi)
  5. Asiakas voi lähettää muuta dataa. Näin tapahtuu esimerkiksi silloin, kun Web-selain lähettää HTML-lomakkeen sisältämän datan POST-metodilla.
  6. Pyyntö päättyy kahteen peräkkäiseen rivinvaihtomerkkiin. Jos tämä tehdään jo otsakkeiden lähettämisen jälkeen kohdassa 4, niin kohdan 5 muuta dataa ei tällöin lähetetä.

Palvelimen vastaus

Kun asiakas on lähettänyt HTTP-pyynnön, palvelin vastaa siihen. Palvelimen vastaus etenee seuraavassa muodossa:

  1. Palvelin vastaa tilarivillä, jonka kolmesta välilyönnillä erotetusta kentästä löytyy
    • HTTP:n versio
    • tilakoodi
    • tilakoodin tekstimuotoinen selitys

      Tyypillisesti onnistuneeseen pyyntöön vastataan:
      HTTP/1.0 200 OK
  2. Palvelin (tai palvelinskripti) lähettää mahdolliset HTTP-otsakkeet riveittäin. Kukin rivi koostuu otsakkeen nimestä, kaksoispisteestä, välilyönnistä ja otsakkeen arvosta ja rivinvaihtomerkistä (CRLF). Tyypillisesti voidaan kertoa esimerkiksi vastauksen luontiaika, tietoja palvelimesta ja palautettavan dokumentin sisältötyyppi.

    Date: Mon, 08 Oct 2007 18:47:01 GMT
    Server: Apache/2.0.54 (Fedora)
    Content-Type: text/html
  3. Palvelin lähettää rivinvaihtomerkin (CRLF ~ tyhjä rivi)
  4. Pyynnön onnistuessa vastaukseksi lähetetään mahdollisesti haluttu data, joka voi olla esimerkiksi
    • staattinen tiedosto: HTML-dokumentti, kuvatiedosto, Excel-asiakirja, zip-tiedosto jne.
    • PHP-skriptin generoima HTML-dokumentti, kuvatiedosto jne.

Huomioita

HTTP on tilaton protokolla. Peräkkäisten siirtotapahtumien välillä ei ole mahdollista pitää tilatietoa protokollan avulla.

  • Tapahtumien seuranta ei kuormita HTTP:tä.
  • Jokainen tapahtuma aloitetaan alusta.
  • Web-sovellusten ohjelmointi hankalaa

Mainittakoon erikseen, että HTTP 1.1-protokolla mahdollistaa yhteyden pitämisen auki, vaikka siirtotapahtuma on ohi. Näin varsinaista yhteyttä ei tarvitse muodostaa uudelleen lisäpyyntöjä varten. Tämä nopeuttaa tavanomaisten HTML-dokumenttien siirtoa, koska ne sisältävät yleensä HTML-koodin lisäksi useita kuvia. Tällöin dokumentti kaikkine kuvineen voidaan mahdollisesti siirtää yhdellä ainoalla HTTP-yhteydellä. Tässäkin tapauksessa jokainen dokumenttiin kuuluva tiedosto siirrettään käyttäen omaa HTTP-siirtotapahtumaa. HTTP 1.0-protokollan tapauksessa asiakkaan on lähetettävä otsake Connection: Keep Alive,jotta palvelin pitäisi yhteyden auki siirtotapahtuman jälkeen.

1.4 Esimerkkejä HTTP-siirtotapahtumista

Tässä kappaleessa esitetään HTTP-siirtotapahtumia lähinnä pääteyhteydellä emuloiden. Näissä esimerkeissä Web-selaimen normaalisti muodostoma asiakaspyyntö kirjoitetaan käsin. Asiakasohjelmana toimivaksi pääteohjelmaksi sopii mikä tahansa telnet-ohjelma. Pääteohjelmalla voi keskustella HTTP-protokollan mukaisesti ottamalla aluksi yksinkertaisesti yhteyttä Web-palvelimen TCP-porttiin. Kokeiltaessa esimerkkejä ne eivät välttämättä toimi täysin samoin. Tämä johtuu esimerkiksi siitä, että käytettävä Web-palvelimen konfiguraatio saattaa olla testaushetkellä hieman erilainen.

Esimerkki: HTTP/1.1

Kirjoitetaan esim. Linuxin komentoriviltä komento telnet netisto.fi 80, jolla avataan yhteys käytettävän palvelimen porttiin 80. IP-numeron ja portin tilalla voi olla minkä tahansa julkisenkin Web-palvelimen tiedot. Yhteyden syntymisen merkiksi telnet-ohjelma tulostaa kolme riviä ja palvelin jää odottamaan, mitä asiaa asiakkaalla on. HTTP-protokollan mukaisesti ensin on lähetettävä pyyntörivi. Tässä tapauksessa pyydetään Web-palvelimen juurihakemistosta dokumenttia index.htm. Tässä esimerkissä HTTP-otsakkeita ja dataa ei lähetetä. Asiakaspyyntö kuitataan toisellakin rivinvaihdolla, jolloin Web-palvelin vastaa standardin mukaisesti tilarivillä, HTTP-otsakkeilla ja varsinaisella datalla. Lopulta yhteys katkaistiin automaattisesti. Tästä kaikesta tavallinen Web-selailija yleensä näkee vain muotoillun data-osan eli varsinaisen HTML-dokumentin.

Host-otsake on pakollinen HTTP/1.1-protokollab versiossa:

$ telnet netisto.fi 80
Trying 217.30.180.57...
Connected to netisto.fi.
Escape character is '^]'.
GET /index.php HTTP/1.1
Host: netisto.fi

HTTP/1.1 200 OK
Date: Mon, 08 Oct 2007 18:47:01 GMT
Server: Apache/2.0.54 (Fedora)
Last-Modified: Mon, 28 May 2007 04:44:18 GMT
ETag: "f60b3e-17ec-66da4c80"
Accept-Ranges: bytes
Content-Length: 6124
Connection: close
Content-Type: text/html

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Ari Rantala: Etusivu</title
...

Connection closed by foreign host.

Samaa esimerkkiä voi kokeilla (hieman työläämmin) Windowsin telnetillä seuraavasti:

  • Käynnistä/Suorita
  • kirjoitetaan Avaa-kenttään esim. telnet joku.ip.numero 80
  • valitaab Terminal/Preferences ja valitse Local Echo, jotta kirjoittamasi tekstit näkyisivät
  • kirjoitetaan  ylimmälle riville pyyntösi esim. GET /hello.htm HTTP/1.0, jossa haettavan dokumentin voi valita palvelinkohtaisesti.
  • hyväksytään pyyntö kahdella rivinvaihdolla.

Esimerkki: HTTP/1.1  / Palvelimen aikakatkaisu

Jotkin "isommat palvelimet" katkaisevat HTTP-siirtotapahtuman, jos asiakas ei saa esitettyä pyyntyä kokonaisuudessaan tietyn ajan kuluessa TCP-yhteyden aukaisemisesta. Kokeile esim. osoitteeseen www.intel.com. Kirjoita pyyntörivi kokonaisuudessaan, paina ENTER ja jää hetkeksi odottelemaan:
$ telnet www.intel.com 80
Trying 217.212.252.145...
Connected to www.intel.com.
Escape character is '^]'.
GET / HTTP/1.1

HTTP/1.0 408 Request Time-out
Server: AkamaiGHost
...

The server timed out while waiting for the browser's request.<P>
...
Connection closed by foreign host.
$

Esimerkki uudelleenohjauksesta

Tässä esimerkissä palvelimen vastaus on 301 Moved Permanently. HTTP-otsakkeissa lähetetään palvelun uusi sijainti Location: http://netisto.fi/ottelu/ Vaikka mukana seuraa asiasta tavanomainen HTML-sivukin, niin yleisimmät selaimet eivät sitä näytä, vaan siirtyvät (lähettävät pyynnön) otsakkeen perusteella suoraan uuteen osoitteeseen.

$ telnet netisto.fi 80
Trying 217.30.180.57...
Connected to netisto.fi.
Escape character is '^]'.
GET /ottelu HTTP/1.1
Host: netisto.fi

HTTP/1.1 301 Moved Permanently
Date: Mon, 08 Oct 2007 18:56:21 GMT
Server: Apache/2.0.54 (Fedora)
Location: http://netisto.fi/ottelu/
Content-Length: 309
Connection: close
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>301 Moved Permanently</title>
</head><body>
<h1>Moved Permanently</h1>
<p>The document has moved <a href="http://netisto.fi/ottelu/">here</a>.</p>
<hr>
<address>Apache/2.0.54 (Fedora) Server at netisto.fi Port 80</address>
</body></html>
Connection closed by foreign host.


Esimerkki: HEAD-metodi

Pyyntömetodina voi olla HEAD. Tällöin palvelin ei lähetä dataa, vaan ainoastaan tilarivin ja HTTP-otsakkeet. Kokeile:

HEAD / HTTP/1.1

Esimerkki: POST-metodi

Viimeisessä esimerkissä havainnollistetaan POST-metodia. Data-alueessa syötetään nimi-arvo-parina "abc=123&def=456", joka lomakkeen tapauksessa tarkoittaisi sitä, että esim. abc-nimiseen tekstinsyöttökenttään olisi kirjoitettu arvoksi "123" ja def-nimiseen kenttään "456".

$ telnet netisto.fi 80
Trying 217.30.180.57 ...
Connected to netisto.fi.
Escape character is '^]'.
POST /nayta-http-data.php HTTP/1.1
Host: netisto.fi
Content-type: application/x-www-form-urlencoded
Content-length: 15
Connection: close

abc=123&def=456

HTTP/1.1 200 OK
Date: Sun, 26 Sep 2012 17:09:19 GMT
Server: Apache
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html

cb
<h3>HTTP-otsakkeet</h3>
<li>HTTP_CONNECTION = close</li>
<li>HTTP_HOST = netisto.fi</li>
<h3>GET-metodilla saapunut data</h3>
<h3>POST-metodilla saapunut data</h3>
<li>abc = 123</li>
<li>def = 456</li>


0

Connection closed by foreign host.

$

Asianomaisen datan näyttää skripti nayta-http-data.php, jonka ohjelmalistaus on alla. Skriptin toiminnan ymmärtäminen ei ole tässä vaiheessa tarpeellista.

<?php

header('Content-type: text/html');

echo "<h3>HTTP-otsakkeet</h3>\n";
foreach($_SERVER as $h=>$v)
if(ereg('HTTP_(.+)',$h,$hp))
echo "<li>$h = $v</li>\n";

echo "<h3>GET-metodilla saapunut data</h3>\n";
foreach($_GET as $h=>$v)
echo "<li>$h = $v</li>\n";

echo "<h3>POST-metodilla saapunut data</h3>\n";
foreach($_POST as $h=>$v)
echo "<li>$h = $v</li>\n";

?>


1.5 HTTP-otsakkeiden ja tilakoodien ryhmittelystä

HTTP-otsakkeet ryhmitellään käyttötarkoituksensa mukaan:

  • yleisiin otsakkeisiin, jotka ovat yhteisiä asiakkaalle ja palvelimelle. Esim:
    • Cache-Control: no-cache
      Pyyntö olla tallentamatta dokumenttia (data) välimuistiin.
    • Connection: close
      Asiakas tai palvelin haluaa lopettaa yhteyden.
  • Dataotsakkeisiin, jotka antavat informaatioita pyynnön tai vastauksen dataosasta.
    • Content_Lenght: 26
  • Asiakkaan pyyntöotsakkeisiin, esimerkiksi:
    • User-Agent: Mozilla/3.01Gold (Win95; I)
    • Accept-Language: en
  • Palvelimen vastausotsakkeisiin, esimerkiksi:
    • Server: Apache/1.3.20 (Unix) PHP/4.0.6
    • Location: http://www.domain.invalid/uusi/

Tilakoodeista

Web-palvelimen lähettämällä tilarivillä kerrotaan mm. onnistuiko pyyntö tai mahdollinen syy epäonnistumiseen. Nämä tilatiedot annetaan

  • palvelimen vastauskoodina ja
  • "selväkielisinä" tekstinä

Vastauksen tilakoodit ovat jaettu

  • informatiivisiin: 100-199
  • onnistuneisiin pyyntöihin: 200-299
  • uudelleen ohjattuihin: 300-399
  • virheellisiin asiakkaan pyyntöihin: 400-499
  • palvelimen virhekoodeihin (pyyntö oli kunnollinen, mutta sitä ei pystytty käsittelemään): 500-599

Mainittakoon muutamia esimerkkejä:

  • 100 Continue: Pyynnön alkuosa saatu. Asiakas voi jatkaa pyyntöä.
  • 200 OK: Asiakkaan pyyntö onnistui.
  • 204 No Content: Vastauksessa ei ole sisältöä eli dataosaa.
  • 301 Moved Permanently: Pyydetty URL on siirretty pysyvästi. Location-otsake kertoo uuden sijainnin.
  • 400 Bad Request: Asiakkaan pyynnössä syntaksivirhe.
  • 403 Forbidden: Asiakkaalla ei ole oikeuksia dokumenttiin. Palvelin ei halua tai voi kertoa syytä tähän. Tyypillisesti esim. palvelimella olevien Web-dokumenttien (mahdollisesti virheellisesti asetetut) käyttöoikeudet estävät dokumentin palauttamista.
  • 404 Not Found: Haluttua dokumenttia ei löydy.
  • 500 Internal Server Error: Palvelimen tai suoritettavan ohjelman toiminnassa virhe.