This is an old revision of the document!


Laboratorul 10 - Protocolul HTTP

Lectură laborator

Obiective

In urma parcurgerii acestui laborator, studentul va fi capabil sa:

  • inteleaga cum functioneaza protocolul HTTP
  • inteleaga rolul entitatilor implicate in schimb de mesaje HTTP
  • scrie un client simplu de HTTP
  • interactioneze cu un API public

Contextul laboratorului

Daca acum 10-15 ani aplicatiile si serviciile web nu erau atat de raspandite, astazi sunt prezente pretutindeni. De exemplu, numarul website-urilor a ajuns sa fie aproximativ 2 miliarde si website-urile reprezinta o parte din web.

Pentru a putea patrunde in acest domeniu vast, este nevoie sa intelegem protocolul temelie al web-ului si anume, HTTP.

Protocolul HTTP

Informatii generale

Miliarde de imagini JPEG, pagini HTML, fișiere text, filme în format MPEG, fișiere audio WAV, applet-uri Java și multe altele sunt accesate pe internet în fiecare zi. HTTP este protocolul responsabil cu mutarea acestora rapid, convenabil și fiabil de la serverele web din întreaga lume la browserele web ale utilizatorilor. Deoarece HTTP, este un protocol peste TCP, datele transmisie nu vor fi deteriorate sau amestecate sau pierdute în timpul tranmisiei de date.

HTTP (HyperText Transfer Protocol) este un protocol de nivel 7 din stiva OSI (aplicatie) folosit pentru transferul informatiilor in internet. Este un protocol care opereaza peste date de tip ASCII.

La baza protocolului HTTP stau conceptele de cerere si raspuns. In cazul comunicatiei HTTP, o entitate inainteaza o cerere si cealalta trebuie, obligatoriu, sa ofere un raspuns.

Probabil că utilizați clienți HTTP în fiecare zi. Cel mai comun client este un browser web (de ex. Google Chrome, Mozilla, Internet Explorer, Safari, etc.). Browserele web sunt entitățiile care solicită artefacte HTTP de la servere și le afișează pe ecran. HTTP functioneaza implicit peste portul 80. Versiunea securizata de HTTP, HTTPS, functioneaza implicit peste portul 443. Un server, insa, poate fi configurat sa asculte cereri HTTP pe orice port disponibil.

Cereri HTTP

Cu totii sunteti familiari cu acest format:

Exemplul de mai sus cuprinde:

  • versiunea protocolului
  • host-ul interlocutorului
  • calea de pe serverul interlocutorului unde se va desfasura actiunea
  • parametri aditionali de cerere (optionali)

Ce este prezentat in poza nu este o cerere HTTP, ci preambul unei cereri HTTP. De fapt, in momentul in care se da enter, browserul (sau orice alt client) creaza, bazat pe informatiile oferite, cererea HTTP efectiva.

Formatul cererii este urmatorul:

METODA CALE VERSIUNE_PROTOCOL\r\n
Host: HOST\r\n
Header1: Valoare Header1\r\n
Header2: Valoare Header2\r\n
...
Cookie: cheie1=valoare1; cheie2=valoare2; ...; cheieN=valoareN\r\n
\r\n
DATA

Linia de start contine 3 elemente.

Primul element este metoda folosita. Metodele HTTP sunt verbe ce descriu actiunea ce va fi efectuata asupra entitatii catre care se transmite cererea. Cele mai des utilizate cereri sunt:

  • GET - interogare de resurse
  • POST - aduagare de resurse. De obicei are si date atasate.
  • PUT - modificare de resurse. De obicei are si date atasate.
  • DELETE - stergere de resurse

Al doilea element este reprezentat de calea si parametrii de cerere (daca exista) unde se va actiona asupra resursei, pe server. In cazul in care exista parametri de cerere, acestia trebuie separati de restul caii prin ?.

Al treilea element este reprezentat de versiunea protocolului de HTTP folosita. Implicit, din motive de securitate, este folosit HTTPS. Pentru varianta ne-securizata, ultima versiune este HTTP/1.1.

A doua linie descrie host-ul entitatii unde va fi transmisa cererea. Host-ul poate sa fie atat un ip cat si un domeniu.

Host-ul este, de fapt, tot un header. Pentru a omite aceasta linie este necesar sa puneti host-ul in cale, exact cum se scrie in browser. Totusi, este indicat sa tratati host-ul ca linie separata.

Headerele sunt scrise cate unul pe rand. Acestea sunt folosite pentru a transmite informatii aditionale catre interlocutor. Headerele se impart in 3 categorii:

  • Request Headers - descriu modul in care se face cererea si cum se poate raspunde la ea. Exemplu: User-Agent
  • General Headers - descriu informatii cu caracter general care tin de comunicare. Exemplu: Keep-Alive
  • Entity Headers - descriu informatii despre datele (daca exista) atasate cererii. Exemplu: Content-Type si Content-Length

Daca exista data atasata cererii, trebuie specificate, obligatoriu, cele doua headere Content-Type si Content-Length

Cookies sunt scrise inlantuit, delimitat de punct si virgula (mai putin ultima). Implicit, comunicarea HTTP este considerata stateless. Nu se poate face corelatie intre oricare doua cereri succesive. Cookies retin bucati de informatie trimise de la server catre client, pentru a putea fi refolosite in cereri ulterioare.

Cookiurile sunt artefacte care se salvează doar la Client.

Inaintea datelor (sau la finalul cererii, daca nu exista date) se pune intotdeauna \r\n

Data variaza in functie de tipul de data transmis. Cele mai des intalnite tipuri de date transmise sunt:

  • text/html - De exemplu, pagini HTML
  • application/x-www-form-urlencoded - Date de forma key1=value1&key2=value2&…&keyN=valueN. Datele sunt inlantuite prin ”&”
  • application/json - Date de forma JSON (Javascript Object Notation). Folosite des in interactiunea cu API-uri
  • multipart/form-data - Date binare, de exemplu, fisiere

Pe baza informatiilor prezentate mai sus, o varianta simplificata a cererii catre facebook, din exemplu, ar arata asa:

GET /search/top/?q=programare%20%web%202020 HTTPS\r\n
Host: facebook.com\r\n
User-Agent: Mozilla/5.0\r\n
Connection: keep-alive\r\n
Cookie: c_user=XXXXXXXXXX; presence=XXXXXXX\r\n
\r\n

Este obligatoriu sa puneti \r\n la finalul fiecarui rand din cerere, cu exceptia datelor atasate

Un exemplu de implmentare a unei cereri HTTP de tip GET pe baza codului sursă din skeletpoate fi gasit mai jos.

message = compute_get_request(SERVERADDR, "/api/v1/dummy", NULL, NULL, 0);
send_to_server(sockfd, message);
response = receive_from_server(sockfd);
printf("%s\n", response);

Raspunsuri HTTP

Orice cerere HTTP este urmata de un raspuns. Raspunsurile seamana cu cererile din punct de vedere al organizarii. Formatul este urmatorul:

PROTOCOL_VERSION STATUS_CODE STATUS_TEXT\r\n
Header1: Valoare Header1\r\n
Header2: Valoare Header2\r\n
...
HeaderN: Valoare HeaderN\r\n
Set-Cookie: cheie1=valoare1\r\n 
Set-Cookie: cheie2=valoare2\r\n
...
Set-Cookie: cheieN=valoareN\r\n
\r\n
DATA

Linia de start contine 3 elemente.

Pentru implemenatrea unei răspuns de tip HTTP POST pe baza codului skelet, trebuie aplelată funcția compute_post_request cu parametrul content_type = application/x-www-form-urlencoded.

Primul element este reprezentat de versiunea protocolului de HTTP folosit pentru a se raspunde.

Al doilea element este reprezentat de statusul raspunsului. Statusul este corelat de reusita, respectiv esecul cererii si de ce s-a intamplat pe entitatea catre care s-a trimis cererea. Exemplu de statusuri des intalnite:

  • 200 - OK
  • 201 - Created
  • 204 - No Content
  • 400 - Bad Request
  • 401 - Unauthorized
  • 403 - Forbidden
  • 404 - Resource Not Found
  • 500 - Internal Server Error

Al treilea element descrie textul care insoteste statusul.

Headerele urmeaza aceeasi structura si descriu acelasi lucru ca si in cazul cererilor.

Cookies sunt setate cate una pe linie. In afara de cheie=valoare, acestea mai au o serie de atribute atasate, precum secure, httpOnly, domain.

Data urmeaza aceeasi structura ca si in cazul cererilor.

Mecanismul de sesiune și antentificare

O sesiune este definită ca o serie de solicitări legate de browser care provin de la același client într-o anumită perioadă de timp. Urmărirea sesiunii leagă împreună o serie de solicitări de browser - gândiți-vă la aceste solicitări ca pagini - care pot avea o anumită semnificație în ansamblu, cum ar fi o aplicație pentru coșul de cumpărături.

Autentificarea de bază HTTP este o metodă simplă de autentificare pentru client prin care acesta furniza un nume de utilizator și o parolă atunci când efectuează o solicitare către server. Acesta este cel mai simplu mod posibil de a impune controlul accesului, deoarece nu necesită module cookie, sesiuni sau orice altceva. Pentru a utiliza acest lucru, clientul trebuie să trimită antetul de autorizare împreună cu fiecare solicitare pe care o face.

Implementarea mecanismului de autentificare folosind codul skelet implică construirea unui mesaj de tip POST care include cei doi parametrii nume și parolă sub forma unui vectori de stringuri.

Suportul de laborator

Va oferim aici un cod sursă schelet pentru realizarea unui client HTTP scris in C. Aveti deja implementata partea de realizare de conexiune, partea de trimitere, respectiv receptionare bytes de la server in helpers.c si buffer.c.

Fisierele in care voi veti lucra sunt client.c si requests.c. In requests va trebui sa implementati scrierea cererilor de tip GET si POST si in client trebuie sa trimiteti cererea proaspat compusa catre destinatie.

Veti interactiona cu doua servere:

  • Serverul principal scris de noi aflat la adresa 34.241.4.235 pe portul 8080
  • API-ul oferit de Openweather Map aflat la adresa api.openweathermap.org pe portul 80

Exerciții

Pornind de la codul disponibil aici, aveți de implementat următoarele cerințe:

  1. Implementati folosind instrucțiunile din îndrumarul de laborator o cerere dummy de tip GET pentru adresa /api/v1/dummy de la serverul principal. <note>

Gasiti aici un exemplu de request GET. </note>

  1. Implementati folosind instrucțiunile din îndrumarul de laborator o cerere dummy de tip POST pentru adresa /api/v1/dummy de la serverul principal cu cu orice conținut pentru date de forma application/x-www-form-urlencoded.

Gasiti aici o captura cu mesaje de tip POST

  1. Ne propunem implementarea unei mecanims de autentificare. Implementați folosind instrucțiunile din îndrumarul de laborator o cerere de tip POST pentru adresa /api/v1/auth/login de pe serverul principal folosind username student si password student. Similar cu task-ul precedent datele trebuie să fie de forma application/x-www-form-urlencoded.
  2. Folosind cookie-ul obtinut la pasul precedent, care poate fi hardcodat, implmentați o cerere de tip GET către adresa /api/v1/weather/key a serverului principal pentru a obține un cheia de conectare la serverul 34.241.4.235.
  3. Folosind cheia de sesiune, implmentați o cerere de tip GET la serverul Openweather Map cu adrese /data/2.5/weather pentru a obține datele despre vreme. Pentru acest task trebuie specificate coordonatele (lat,long) pentru care se dorește obținerea datelor.
  4. Cu date obținute la punctul precedent, implementați o cerere de tip POST la serverul principal pentru verificarea. Pentru acest task trebuie să țineți cont de faptul că datele servite de serverul Openweather Map sunt în format JSON.
  5. Implementați o cerere de tip GET către serverul principal pentru efectuarea delogări (LogOut).

Bonus

  1. Implementați un mecanism prin care dacă clientul este deja autentificat să primească un mesaj de forma “Already logged in!”.
  2. Folositi Postman pentru a testa comenzile HTTP pe care le-ati implementat la laborator. Analizati cererile si raspunsurile primite si identificati elementele din protocol prezentate la curs si laborator.
pc/laboratoare/10.1652114094.txt.gz · Last modified: 2022/05/09 19:34 by vlad_andrei.badoiu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0