Câteva milisecunde de HTTP

În articolul de față, Axi va încerca să răspundă la întrebarea: „Ce se întâmplă când utilizatorul introduce o adresă Web (URL—Uniform Resource Locator) în cadrul navigatorului cu intenția de a vizita un anumit sit?”

Înainte de toate, ar trebui să precizăm diverși termeni importanți…

Deoarece Web-ul reprezintă un serviciu al Internet-ului, se bazează pe paradigma client/server.

Interacțiunea dintre clientul și serverul Web

Interacțiunea dintre clientul și serverul Web

Așadar, clientul Web poate fi considerat ca fiind un agent al utilizatorului, acționând – măcar ipotetic – în concordanță cu interesele acestuia. De aceea, din punct de vedere tehnic orice client Web (browser, player multimedia, robot Web al unui motor de căutare, software de oglindire a conținutului etc.) este denumit generic user agent.

Acest agent solicită unui server Web o reprezentare a unei resurse, resursă identificată via o adresă (URL), pe baza regulilor de comunicare stabilite conform unui protocol – mai general, o suită de protocoale, precum stiva TCP/IP folosită de aplicațiile actuale. Existența unei suite de protocoale nu reprezintă o prerogativă a tehnologiei, istoria putând oferi exemple diverse de protocoale (i.e. norme de conduită socială sau etichetă) – o exemplificare poate fi maniera de îmbăiere japoneză.

Serverul Web „ascultă” cereri din partea posibililor clienți și le deservește, în limita posibilităților. Pentru fiecare cerere primită, trimite un cod de stare, urmat de o reprezentare de resursă (fișier text, imagine, arhivă etc.). Această reprezentare respecte un anumit format de date – de exemplu, CSS (Cascading Style Sheets) pentru o foaie de stiluri ori PNG (Portable Network Graphics) pentru o imagine de tip raster – și poate fi efectiv stocată (creată de utilizator) sau poate fi generată de către un program (eventual, grație unui server de aplicații Web precum PHP, cu posibilul concurs al unui framework Web: CakePHP, Django, Ruby on Rails etc.).

O resursă poate avea reprezentări multiple (de exemplu, o reprezentare mai complexă pentru a fi redată de un client Web la nivel de desktop și una mai simplă, optimizată pentru afișarea pe ecranul unui telefon mobil mai modest). Reprezentarea este desemnată via tipuri MIME (Multipurpose Internet Mail Extensions) care definesc un set de tipuri primare (text, imagine, audio, video,…), fiecare având o submulțime de tipuri specifice. Iată câteva exemple: text/html (reprezentare textuală în format HTML), text/css (text în format CSS), image/png (reprezentare a unei imagini în format PNG), application/javascript (program JavaScript se poate fi procesat la nivel de client) etc. Pe baza tipurilor MIME, un browser poate decide cum va procesa (interpreta) diversele resurse în vederea redării.

Vorbind despre protocoale Internet, pentru a simplifica arhitectura de rețea și dezvoltarea de aplicații, așa-numită stivă TCP/IP specifică existența a patru strate importante. Nu vă speriați, acest episod nu e unul de groază – „masochiștii” doritori de-a deveni profesioniști pot parcurge prezentările „venerabile” ale cursului de Rețele de Calculatoare.

Iată aspectele esențiale:

  1. Nivelul accesului la mediu (MAC—medium access control) privește modul de comunicare a pachetelor de date, denumite frame-uri, la nivel de hardware – vizează în principal mediile de transmisie cu/fără fir. Fiecare placă de rețea (network interface) se identifică via o adresă fizică – uzual, numită adresă MAC.
  2. Nivelul rețea e responsabil cu transmisia datelor în cadrul unei rețele și între rețele diferite, inclusiv dirijarea datelor (routing), filtrarea etc. Un rol important îl are protocolul IP (Internet Protocol). Fiecare mașină posedă măcar o adresă IP (denumită și adresă logică) – o succesiune de 4 octeți despărțiți de punct. Deoarece numărul de adrese IP este limitat, iar Internet-ul s-a dezvoltat în ritm exponențial, actualmente ne aflăm în tranziție spre IPv6.
  3. Nivelul transport abstractizează maniera de transfer al datelor de la sursă la destinație. Dacă la nivelul rețea fiecare pachet – termenul consacrat fiind datagramă – era independent și nu se punea problema fiabilității (unele datagrame pot fi distruse pe parcurs, nu contează ordinea sosirii etc.), nivelul transport poate asigura transmiterea datelor sub formă de flux (flow), adică un „șuvoi” continuu folositor când transferăm, de pildă, diverse fișiere. Astfel, se garantează că toate pachetele vor ajunge la destinație în ordinea dorită, fără a fi mutilate ori duplicate – aceste proprietăți dezirabile sunt oferite de protocolul TCP (Transmission Control Protocol). Există, desigur, și posibilitatea de a transporta date fără a ne pune problema fiabilității via protocolul UDP (User Datagram Protocol). Comunicarea are loc abstract prin intermediul a două puncte terminale – situate la expeditor și, respectiv, la destinatar. Fiecare punct terminal reprezintă o pereche <adresă IP, port>, unde acest port (număr stocat pe 2 octeți) identifică o anumită aplicație care trimite/recepționează date. Din punctul de vedere al dezvoltării de aplicații Internet, interfața de programare (API-ul) se bazează pe socket-uri – parcurgeți un ghid excelent.
  4. Nivelul aplicațiilor pune la dispoziție protocoale specifice serviciilor Internet: poștă electronică (e.g., POP—Post Office Protocol), transfer de fișiere (FTP—File Transfer Protocol), acces securizat la distanță (SSH–Secure SHell), conversații în timp-real (IRC—Internet Relay Chat), mesagerie instantanee (XMPP—Extensible Messaging and Presence Protocol) și multe altele. O mențiune particulară trebuie acordată sistemului de nume de domenii (DNS—Domain Name System) care asociază adreselor IP nume simbolice de domenii, mai ușor de reținut de către oameni (intern, calculatoarele folosesc în continuare numere).

Protocoalele care guvernează diversele fațete ale Internet-ului sunt standardizate de IETF—Internet Engineering Task Force.

În cazul spațiului World Wide Web, protocolul este HTTP (HyperText Transfer Protocol) – versiunea în vigoare fiind 1.1, iar următoarea se preconizează a fi 2.0, inspirată și de SPDY.

Revenind la tema însemnării de astăzi, am dori să cunoaștem ce se află în „spatele” unei cereri HTTP. Pentru aceasta, vom recurge la Wireshark, un notoriu instrument de analiză a traficului pe Internet.

Vom presupune că utilizatorul dorește să acceseze situl dedicat materiei „Tehnologii Web”, aflat la adresa http://profs.info.uaic.ro/~busaco/teach/courses/web/. Inspectând traficul de rețea, obținem cele din figura de mai jos:

Dialogul TCP dintre client și server Web

Dialogul TCP dintre client și server Web

Pe baza celor descrise mai sus, putem deduce ușor că frame-ul capturat încapsulează:

  • Date ale protocolului Ethernet care specifică adresele MAC (fizice) ale sursei și destinației.
  • Date ale datagramei IP ce memorează adresele logice ale mașinii client și ale serverului (numele simbolic profs.info.uaic.ro corespunde adresei IP clasice 85.122.23.1; unul dintre frame-urile anterioare reprezenta o cerere DNS prin care navigatorul Web dorea să cunoască această adresă IP).
  • Date ale segmentului TCP incluzând numerele de port ale punctelor terminale corespunzătoare expeditorului și destinatarului. În cazul de față, navigatorul Web via un socket dorește inițierea unei conexiuni la portul 80 folosit în mod normal de serverul Web.

Cadrele 7—9 reprezintă cei trei pași efectuați în stabilirea conexiunii (three-way handshaking) care asigură ulterior transmiterea fluxului de date.

Începând cu cadrul 10, are loc dialogul efectiv purtat între agentul-utilizator și serverul Web conform protocolului HTTP. Cererile adresate de către client sunt desemnate de verbe, cel mai utilizat fiind GET (alte mesaje de cerere pot recurge la POST, PUT, DELETE,…):

Cerere GET emisă de browser

Cerere GET emisă de browser

O cerere GET presupune specificarea resursei dorite (calea ~/busaco/teach/courses/web/), urmată de versiunea de protocol (actualmente, HTTP/1.1) și de caracterele CRLF (Carriage Return și Line Feed) al căror cod ASCII este 10 și 13, respectiv – adică \r\n.

De asemenea, vor fi utilizate diverse câmpuri prezente în antetul mesajului, conform sintaxei NumeCâmp: Valoare CRLF. În exemplul nostru, le putem remarca pe cele mai întâlnite:

  • Host desemnează mașina-gazdă a resursei solicitate; util și pentru a verifica la nivel de proxy dacă reprezentarea resursei dorite nu există deja memorată în cache;
  • Connection indică serverului să păstreze conexiunea deschisă, deoarece ar putea urma alte cereri (desigur, dacă e suprasolicitat serverul Web ar putea să închidă imediat fiecare conexiune);
  • User-Agent indică navigatorul (clientul); fiecare agent-utilizator va avea asociată o „semnătură” – aceasta se regăsește și în fișierele de jurnalizare ale serverului și e utilă și în cazul ignorării unor roboți Web via fișierul robots.txt;
  • Accept enumeră tipurile MIME pe care le acceptă clientul (de pildă, unele navigatoare decrepite ar putea să nu accepte JavaScript), eventual cu o valoare a calității acestora – parametrul q atașat;
  • Accept-Language specifică limba dorită la nivel de client (această valoare poate fi folosită de aplicațiile invocate de server pentru a trimite conținut specific unei anumite limbi);
  • Accept-Encoding se referă la codificarea conținutului; din motive de performanță, serverul poate expedia datele comprimate cu gzip care ulterior vor fi prelucrate de către navigator.

Cererea ilustrată mai sus are următoarea structură:

GET /~busaco/teach/courses/web/ HTTP/1.1
Host: profs.info.uaic.ro
User-Agent: Mozilla/5.0 (Macintosh; 
            Intel Mac OS X 10.8; rv:18.0) 
            Gecko/20100101 Firefox/18.0
Accept: text/html,
        application/xhtml+xml,
        application/xml;q=0.9,
        */*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Connection: keep-alive

Câmpul DNT (Do Not Track) solicită aplicațiilor să nu colecteze date despre utilizator, conform specificației Tracking Preference Expression (în lucru la Consorțiul Web).

Răspunsul serverului Web este oferit de captura-ecran următoare:

Răspuns oferit de serverul Web

Răspuns oferit de serverul Web

În primul rând, serverul Web trebuie să asocieze căii virtuale (specificată în mesajul de cerere HTTP) o cale de directoare reală, conform configurației curente – pentru Apache, a se consulta documentația oficială. De asemenea, pentru a satisface cererea, serverul Web poate invoca alte procese pe baza paradigmei CGI (Common Gateway Interface) și/sau serverelor de aplicații existente.

Conform imaginii anterioare, putem observa că răspunsul include atât diverse meta-date (vezi câmpurile din antetul mesajului), cât și conținutul propriu-zis (reprezentarea trimisă către agentul-utilizator):

  • Date indică data la nivel de server;
  • Server reprezintă „semnătura” serverului Web;
  • Last-Modified specifică data celei mai recente actualizări a reprezentării resursei (poate fi utilă pentru includerea în cache);
  • Content-Encoding semnalează clientului codificarea aleasă (aici, serverul transmite datele compresate cu gzip);
  • Content-Length are ca valoare numărul de octeți transferați (în cazul de față, conținutul e încapsulat de 2 segmente TCP);
  • Content-Type indică tipul MIME al reprezentării ce va fi procesată de client; după cum era de așteptat, e trimis un document HTML;

Codul de stare este 200 Ok (totul a decurs în regulă), dar serverul Web poate emite și alte coduri – a se vizita situl httpstatus.es/.

Răspunsul expediat de server rezultat în urma decompresiei este (câmpurile ETag și Vary sunt folosite pentru păstrarea temporară a datelor – caching):

HTTP/1.1 200 OK
Date: Sun, 10 Feb 2013 10:01:43 GMT
Server: Apache
Last-Modified: Tue, 05 Feb 2013 17:08:57 GMT
ETag: "fa6011-c1f-4d4fd43d9bc40"
Accept-Ranges: bytes
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 1337
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: text/html

<!DOCTYPE html>
<html>
...

Desigur, după caz, browser-ul va analiza codul HTML și va formula și alte cereri HTTP către același sau alt server pentru a prelua diverse resurse de interes (foi de stiluri CSS, imagini, programe JavaScript,…) în vederea redării conținutului. Pentru mai multe detalii referitoare la „viața” unei pagini Web, recomandăm al doilea capitol al cărții Book of Speed.

Cele câteva milisecunde ale fluxului de mesaje HTTP vehiculate prin TCP între clientul și serverul Web sunt ilustrate de diagrama de mai jos generată de Wireshark:

Fluxul de date dintre clientul și serverul Web

Fluxul de date dintre clientul și serverul Web

Alte instrumente Web folositoare, mai ales în ceea ce privește testarea diverselor API-uri publice, sunt hurl.it și Web Sniffer. Suplimentar, pot fi experimentate httpbin sau REDbot.

Drept concluzie, o privire de ansamblu a ceea ce am prezentat mai sus poate fi urmărită în binecunoscutul film demonstrativ Warriors of the Net.

Anunțuri