Il protocollo HTTP

Transcript

Il protocollo HTTP
© C. Barberis, G. Malnati, 2011-14
LEZIONE 02 - 04/03/2014
Il protocollo HTTP
Anno Accademico 2013-14
Applicazioni Internet
Il protocollo porta dentro di sè alcune complicazioni.
Argomenti della lezione
© C. Barberis, G. Malnati, 2011-14
Il protocollo HTTP
◦ Richieste
◦ Risposte
◦ Applicazioni HTTP
Aspetti avanzati
◦ Meccanismi
di autenticazione
◦ Gestione delle sessioni
Supporto HTTP in Java
Applicazioni Internet
2
Di per sè è apparentemente banale e pensato per favorire l'interconnessione tra sistemi distribuiti. Diversi RFC, sta per essere approvata la versione 2.0. Il fatto che dal 1999 al 2014 non ci siano stati avanzamenti è indice di bontà del protocollo.
Ad aprile 2014 si introdurranno modifiche per cui gli header che ora
sono testuali verranno compressi in un formato binario, in modo tale
da trasmettere poca roba e migliorare le prestazioni.
Il protocollo HTTP
Hyper-Text Transfer Protocol
◦ Un protocollo applicativo “semplice e leggero” per “sistemi informativi distribuiti ed ipermediali”
© C. Barberis, G. Malnati, 2011-14
Specificato dai documenti “Request for comments”
◦
◦
◦
◦
◦
RFC1945 – HTTP versione 1.0, maggio 1996
RFC 2616 – HTTP versione 1.1, giugno 1999
RFC 2817 – Supporto per TLS, maggio 2000
RFC 5785 – Utilizzo di URI, aprile 2010
RFC 6585 – Codici di stato ulteriori, aprile 2012
HTTP è un protocollo di trasporto che però si appoggia su un protocollo di trasporto (TCP). Vuole essere agnostico rispetto al contenuto trasportato, descrivendo i contenuti, usando politiche di caching
per evitare di fare trasferimenti inutili e implementare meccanismi di
autenticazione, per la verità abbastanza deboli.
In corso la specifica della versione 2.0
◦ Cambiamenti prevalentemente sintattici per ottimizzare le prestazioni
◦ Ratifica prevista per il 2014
Protocollo di trasporto di contenuti generici alla base del web e di tutte le
applicazioni costruite su tale piattaforma
Offre supporto per:
◦ Descrizione dei contenuti
◦ Utilizzo di politiche di caching
◦ Meccanismi di autenticazione
Applicazioni Internet
3
HTTP: caratteristiche base
Protocollo applicativo
◦ Si appoggia ad un protocollo di trasporto esistente: nella maggior
parte dei casi TCP, anche se è possibile utilizzare altri protocolli
(compreso UDP)
© C. Barberis, G. Malnati, 2011-14
Protocollo semplice
◦ Gestisce uno scambio elementare:
◦ Il client invia una richiesta, il server produce una risposta
Protocollo privo di stati
◦ Ogni richiesta fa storia a sé: il server non ha necessità di
ricordare richieste precedenti
Protocollo indipendente dal contenuto
◦ Richiesta e risposta possono incapsulare dati arbitrari, in termini
di contenuto, dimensione, codifica, …
Applicazioni Internet
4
Occupando ISO/OSI 5-6-7 lo chiamaiamo genericamente protocollo
applicativo. E' possibile, mediante minime modifiche, trasportarlo su
UDP.
E' molto semplice: un client invia una richiesta, un server risponde
con una risposta.
E' stato specificatamente pensato per essere privo di stati: lo scambio nasce e muore in sè, non c'è storia precedente che conta. Questo
semplifica notevolmente la storia lato server.
E' indipendente dal contenuto: sia la richiesta che la risposta possono trasportare dati di tipo arbitrario.
Richiesta e risposta sono due blocchi di dati, inviati consecutivamente. Entrambi sono costituiti da una parte iniziale in formato ASCII, seguita da una parte successiva (opzionale) interpretato alla luce di
quanto letto nell'intestazione (caratteri ASCII terminati da \n\r). Una
riga vuota mi dice quando finisce l'intestazione.
Struttura di base
© C. Barberis, G. Malnati, 2011-14
L’interazione di base è costituita dallo scambio
richiesta/risposta
Entrambe sono formate da due parti:
◦ L’intestazione, formata da un insieme di linee di testo,
ciascuna delle quali terminata dalla coppia CR/LF
(0x0d,0x0a)
◦ Il corpo, il cui contenuto (in termini di presenza,
formato, lunghezza, …) è definito dall’intestazione
◦ La due parti sono separate da una linea vuota
Applicazioni Internet
5
Di base questo protocollo modella operazioni nei confronti di un'entità astratta chiamata risorsa. Quando io digito www.polito.it chiedo al
server la risorsa radice del server. Il protocollo non mi dice cos'è
questa risorsa (una pagina, un programma, ...).
URL
Tutte le transazioni HTTP riguardano operazioni su
risorse informative specificate attraverso una URL
Una risorsa è indirizzata da uno schema (http oppure https, il quale
negozia con la controparte un socket TLS). Segue l'hostname, che
viene risolto utilizzando un DNS Server (se non è possibile, si verifica se per caso è un indirizzo IP valido). Dopo l'hostname è possibile
un'estensione per scrivere la porta su cui sono in ascolto. Segue un
path della risorsa, che non è necessariamente reale: sta al server fare il mapping tra path e posizione sul server.
◦ Uniform Resource Locator, (RFC 2396)
© C. Barberis, G. Malnati, 2011-14
Stringa univoca costituita da più sotto-parti:
◦ schema://hostname[:port]/path
◦ Schema indica il protocollo tramite cui interagire ( "http" o
"https")
◦ Hostname [:port] è l’indirizzo in cui il server si trova in attesa di
connessioni (se non indicata, la porta è 80)
◦ Path indica la posizione relativa dell’oggetto all’interno del server
(non è necessariamente un percorso reale)
Una URL relativa comprende solo il path (preceduto da
“/”)
Applicazioni Internet
6
Le risorse possono essere
- documenti statici
- servizi già in esecuzione
* provvedono a elaborare quanto inviato dal client e costruiscono
* una risposta opportuna
Risorse
© C. Barberis, G. Malnati, 2011-14
Termine generico per esprimere il contenuto
informativo che è oggetto della transazione
◦ Possono essere costituite da documenti statici (file presenti sul
server)…
◦ …oppure essere (frammenti di) programmi / servizi la cui
esecuzione produce/consuma il documento trasferito
Lo stesso contenuto può essere reso disponibile dal server in una
pluralità di formati. Nel caso di documenti statici, una possibile idea
è quella per cui il client dice "guarda che io il documento lo vorrei in
spagnolo", e se il server ce l'ha parla in spagnolo.
Più generalmente, i dati possono essere "vestiti" a seconda delle richieste del client (es.: "mandami il dato in formato JSON")
Le risorse possono essere presenti sul server in più
formati:
◦
◦
◦
◦
Utilizzo di diversi linguaggi naturali
Utilizzo di codifiche alternative
Diverso livello di risoluzione
…
Applicazioni Internet
7
Le richieste indicano una risorsa e quale azione si vuole compiere su
di essa. Tutte iniziano con una prima riga particolare, formata da un
verbo scelto da 6 definiti dal server (elencati in seguito), l'URL e con
le regole di un determinato protocollo.
Tutte le righe successive sono sottointestazioni, elencabili in un ordine qualsiasi. E' compito del destinatario rimettersele in ordine e mi
dicono come interpretare la risorsa, come gestire il caching... L'ultima
intestazione è chiusa da una riga bianca.
Dopo la riga bianca c'è il corpo, presente a seconda del verbo utilizzato e, in parte, dalle intestazioni.
Richieste
Ogni richiesta HTTP indica un’azione da svolgere sull’oggetto
definito dalla URL
La prima riga di una richiesta (intestazione) contiene:
© C. Barberis, G. Malnati, 2011-14
◦ L’azione da svolgere
◦ La URL (relativa) dell’oggetto su cui operare
◦ La versione del protocollo usata dal client
Le righe successive contengono:
◦ Ulteriori sotto-intestazioni
◦ Una riga bianca
◦ Il corpo
(se presente)
Host: perchè mai lo devo specificare se ho aperto un socket? Perchè
per esempio io sono Aruba e ospito www.fiat.it e www.lancia.it sulla
stessa macchina.
Keep-Alive: tieni aperta la connessione dopo la fine dello scambio
perchè magari mi scappa di chiederti qualcos'altro.
GET /index.html HTTP/1.1¿
Host: localhost:8000¿
Accept: text/html, image/gif, image/jpeg¿
Connection: keep-alive¿
¿
Applicazioni Internet
8
GET
Chiedo qualcosa e il server mi risponde. Non c'è corpo e può essere
condizionale (io un po' di tempo fa ti ho chiesto index.html, se non è
cambiata dal 30/1/2014 non me la rimandare) oppure parziale (voglio
index.html, ma solo i byte dal 276 al 421).
HEAD
Ottimizzazione di GET. Della risorsa di cui io potrei fare la GET, non
darmi il contenuto ma solo le intestazioni (ti chiedo un filmato, vedo
un po' com'è fatto, poi se non lo so decodificare evito di chiederti tutto il resto). Nè richiesta nè risposta hanno corpo. Uno degli usi possibili è la validazione di un URL.
Possibili azioni (1)
© C. Barberis, G. Malnati, 2011-14
GET
◦ Richiede l’invio della risorsa indicata dalla URL
◦ La richiesta non ha corpo
◦ Si possono effettuare richieste condizionali: la risorsa viene
trasferita solo se ha una caratteristica indicata in un’apposita
intestazione (If-Modified-Since, If-Match, …)
◦ Si possono effettuare richieste parziali: si trasferisce una
porzione della risorsa (Range)
HEAD
◦ Come GET, ma richiede l’invio delle sole intestazioni
corrispondenti all’oggetto indicato dalla URL
◦ Né la richiesta né la risposta hanno un corpo
◦ Permette di validare la correttezza/coerenza di una URL
Applicazioni Internet
9
POST
Io client, a questa risorsa, voglio inviare i seguenti dati. Tu prendili, usali e mandami il documento che ne risulta (lo sviluppatore può implementare questa clausola come ritiene più opportuno). Tipicamente
si usa nel contesto di programmi.
PUT
Il contrario di POST. Io client chiedo a te server di crearmi una risorsa dal nome indicato col seguente contenuto. Tipicamente la risorsa
è il risultato dell'elaborazione di un programma.
Possibili azioni (2)
© C. Barberis, G. Malnati, 2011-14
POST
◦ Invia un insieme di informazioni (contenute nel corpo
della richiesta) alla risorsa indicata dalla URL e
richiede il documento risultante
◦ La risorsa indicata è tipicamente un programma
PUT
◦ Richiede la creazione di una risorsa sul server
(contenuta nel corpo della richiesta) identificata dalla
URL
Applicazioni Internet
10
DELETE
Chiedo al server di distruggermi la risorsa indicata. Solitamente non
ha corpo.
TRACE
Per scopi di debug. Mi manda indietro la catena di richieste che ho
fatto.
OPTIONS
Opzioni lecite sulla risorsa indicata. Offre un modo di fare inspection
sui servizi web ("cosa c'è su www.alfa.com/servizio?" "guarda, c'è
GET, POST, DELETE, PUT")
CONNECT
Implementato per permettere di iniziare una connessione in chiaro
per poi farla diventare crittografata oppure connettermi a un server
proxy.
Possibili azioni (3)
DELETE
◦ Richiede la distruzione della risorsa indicata
© C. Barberis, G. Malnati, 2011-14
TRACE
◦ Utilizzato per scopi di debug
◦ Restituisce una copia del messaggio inviato
OPTIONS
◦ Richiede l'elenco delle azioni che possono essere eseguite
su una data URL
CONNECT
◦ Permette di instaurare una connessione di tipo SSL/TLS
Applicazioni Internet
11
Proprietà delle azioni
Per capire bene la differenza tra PUT e POST bisogna leggere lo
standard e notare che ci sono diverse proprietà. Si parla di azioni
safe se l'esecuzione dell'azione non comporta alterazioni nello stato
interno del server. Un'azione viene chiamata idempotente se eseguendola N volte porta allo stesso risultato che eseguirla una volta.
Sicurezza
◦ Un’azione è sicura (safe) se non genera cambiamenti nello stato interno del
server
HEAD e GET dunque sono tendenzialmente usate quando l'operazione che scatenano è sia sicura che idempotente (trasferimento di un
pezzo di contenuto). POST va bene per quelle azioni nè sicure nè
idempotenti (se io posto due volte un dato in un log voglio ben averlo
due volte). PUT e DELETE è invece usato ad esempio per operazioni di creazioni di file, in quanto idempotenti e non sicure.
Idempotenza
◦ Un’azione è idempotente se l’effetto sul server di più richieste identiche è
lo stesso di quello di una sola richiesta
© C. Barberis, G. Malnati, 2011-14
Date queste definizioni, secondo lo standard
◦ HEAD e GET si usano quando le operazioni soggiacenti sono sia sicure che
idempotenti
◦ POST per operazioni che non sono né idempotenti né sicure
◦ PUT e DELETE per operazioni idempotenti ma non sicure
Complessivamente si possono utilizzare queste azioni per
modellare la semantica CRUD
◦
◦
◦
◦
Create à PUT
Read à GET
Update à POST
Delete à DELETE
Applicazioni Internet
12
Mettendo insieme queste operazioni si ottiene la semantica CRUD,
tipica dei DB. Alla luce di tutto ciò nascono i server RESTful: io posso permettere di interagire con le operazioni che ho in un modo completo. L'overhead è molto basso a fronte, ad esempio, delle stesse
cose fatte con SOAP, in cui comunque devo fare POST, non so se
dall'altra parte cambia stato e altre cose del genere.
Come son fatte le risposte? Intestazione ASCII seguita da una risposta in un qualche formato. Anche qui la prima riga è tutta particolare ed è la linea di stato, che inizia con:
- versione del protocollo usata dal server
- numero di 3 cifre per dire com'è andata
- riga di testo qualsiasi per far capire anche al programmatore
Risposte
© C. Barberis, G. Malnati, 2011-14
Rappresentano il risultato della richiesta
La prima riga della risposta (intestazione) contiene la
linea di stato:
Nelle righe immediatamente successive seguono una serie di intestazioni (nome header: valore), una riga bianca e il corpo se presente.
◦ Versione del protocollo usata dal server
◦ Codice di stato (3 caratteri numerici)
◦ Descrizione testuale del codice
Le linee successive contengono:
◦ Ulteriori sotto-intestazioni
◦ Una riga bianca
◦ Il corpo (se presente)
Applicazioni Internet
HTTP/1.1 200 Ok¿
Content-Type: text/html¿
Date: Sat, 01 Mar 2014 08:22:22 GMT¿
Server: Apache-Coyote/1.1 ¿
Connection: close¿
¿
<HTML> …. </HTML>
13
Codici di stato
Valori su tre cifre che indicano l’esito della richiesta:
© C. Barberis, G. Malnati, 2011-14
◦ La prima cifra rappresenta la classe
◦ Le altre due l’esito specifico
Ø 1xx: Informational
Messaggio inviato mentre
la richiesta si svolge, a
titolo informativo
Ø 2xx: Successful
La richiesta è stata
compresa ed accettata dal
server
Ø 3xx: Redirection
Il client deve eseguire
ulteriori azioni per ottenere
il risultato
Importantissimi da conoscere. Sempre 3 cifre: la prima indica l'esito
generale, le ultime 2 il dettaglio.
Ø 4xx: Client error
Richiesta rifiutata per un
errore causato dal client
(errore sintattico o
richiesta non autorizzata)
Ø 5xx: Server error
Il server non è in grado di
soddisfare la richiesta per
un problema interno
Applicazioni Internet
14
1XX: INFORMATIVE
Vengono mandate, ma non stanno esaurendo il risultato dell'operazione (100 CONTINUE: il client ha cominciato a mandare un po' di richiesta, il server esamina quello che gli sta mandando e se gli piace
manda un 100).
2XX: SUCCESSO
3XX: REDIREZIONE
Il server dice che la risorsa non ce l'ha lui, ma è da un'altra parte. Ti
viene detto che è da un'altra parte (301: MOVED PERMANENTLY,
302: MOVED TEMPORALLY)
4XX: CLIENT ERROR
Non è possibile accontentare la richiesta a causa di una pirlata del
client (404 FILE NOT FOUND: www.regnubblica.it non esiste!)
5XX: SERVER ERROR
L'elaborazione lanciata per provocare la risposta ha provocato un'eccezione (non sono riuscito a connettermi al DB, non ho più memoria,
...). Conviene rispondere 500 per tenersi sul vago e non far sapere i
cazzi miei agli altri: in fase di sviluppo è però comodissimo.
Esempi di codici di stato (1)
100 Continue
◦ Invito al client a spedire il corpo della richiesta
200 Ok
© C. Barberis, G. Malnati, 2011-14
◦ HEAD, GET o POST terminate con successo
201 Created
◦ PUT terminata con successo
301 Moved permanently
◦ URL non valida, il server conosce la nuova posizione
400 Bad request
◦ Errore sintattico nella richiesta
Applicazioni Internet
15
PUT www.polito.it/loremipsum
501 NOT IMPLEMENTED: su questa URL, PUT non ce l'ho. Questo
va bene per i servizi RESTful.
Esempi di codici di stato (2)
401 Unauthorized
◦ Il client non dispone dei privilegi necessari a richiedere la risorsa
403 Forbidden
© C. Barberis, G. Malnati, 2011-14
◦ Richiesta non autorizzabile
404 Not found
◦ URL errata
500 Internal server error
◦ Impossibile evadere la richiesta per un malfunzionamento lato
server
501 Not implemented
◦ Metodo non implementato dal server per la specifica risorsa
Applicazioni Internet
16
Intestazioni
Righe di testo conformi alle specifiche RFC 822
Diverse sottocategorie:
◦ Intestazioni generali
© C. Barberis, G. Malnati, 2011-14
indicano proprietà generali del messaggio trasmesso (richiesta o
risposta) e non riguardano l’entità indicata
◦ Intestazioni relative ad un’entità
Forniscono meta-informazioni sul corpo del messaggio, se presente, o
sulla URL indicata nella richiesta
◦ Intestazioni relative alla richiesta
Descrivono la richiesta ed il client al server
◦ Intestazioni relative alla risposta
Forniscono ulteriori informazioni sull’esito della richiesta
Applicazioni Internet
17
© C. Barberis, G. Malnati, 2011-14
Intestazioni generali
Cache-Control
Connection
Date
Pragma
Trailer
Transfer-Encoding
Upgrade
Via
Warning
Applicazioni Internet
18
© C. Barberis, G. Malnati, 2011-14
Intestazioni di entità
Allow
Content-Encoding
Content-Language
Content-Length
Content-Location
Content-MD5
Content-Range
Content-Type
Expires
Last-Modified
Applicazioni Internet
19
© C. Barberis, G. Malnati, 2011-14
Intestazioni di richiesta
Accept
Accept-Charset
Accept-Encoding
Accept-Language
Authorization
Expect
From
Host
If-Match
Applicazioni Internet
If-Modified-Since
If-None-Match
If-Range
If-Unmodified-Since
Max-Forwards
Proxy-Authorization
Range
Referer
TE
User-Agent
20
Scritte in ASCII secondo l'RFC 822. Sono tante e suddivise in quattro
gruppi:
- generali
* valgono sia per richiesta che per la risposta in quante guardano
* l'interazione nel suo complesso
- proprie della richiesta
- proprie della risposta
---------------------------------------------------------------------------------------------INTESTAZIONI GENERALI
- Cache-Control. HTTP è stato progettato in modo che in mezzo a
User-Agent e Origin-Server ci può essere un oggetto chiamato proxy,
che raccoglie richieste da un gruppo di client e le riforwarda verso un
server. Se tutti alla FIAT guardano www.lastampa.it non faccio 700
connessioni a www.lastampa.it, ma mi viene restituito il contenuto
salvato sul server proxy. Esiste anche il reverse proxy: siccome io
quando contatto www.google.com non mi risponde un solo computer,
vado a finire su un load balancer che prende i byte che gli arrivano e
"li rigira" da una delle altre parti (sia per prestazioni che per sicurezza). Occhio che in alcuni casi non bisogna fare cache (un caso su
tutti, POST).
- Connection: siccome mettere in piedi la connessione "costa", visto
che una pagina HTML contiene risorse che appartengono allo stesso server (come le immagini) non buttiamo giù il socket e comincia
a mandarmi le immagini.
- Date: non sembra ma è importantissimo. Negli Stati Uniti è un macello. Dov'è che sono le 3:45? A New York, San Francisco o nelle
Hawaii?
- Pragma: estensione. Permette di aggiungere comportamenti non
standard definiti in modo più o meno arbitrario.
- Trailer: ha una funzione particolare nel transfer encoding
- Upgrade: introdotto in HTTP 1.1 per "estendere" la connessione
Via: header che serve per spiegare al destinatario che il messaggio
non è giunto direttamente dal client, ma attraverso uno o più server
proxy. Contiene una sequenza separata da virgole di hostname:port
- Warning: segnala potenziali situazioni di potenziali problemi
- Transfer-Encoding: normalmente la comunicazione tra client e server
avviene tutta "di fila". Il body viene mandato tutto di un colpo: ci sono
delle situazioni (tipicamente server > client) in cui non so bene quanti dati devo mandarti e dunque dovrei predisporre un buffer. Problema. Si può dunque negoziare un transfer-encoding di tipo chunked:
tutti i pezzi del body cominciano con un numero ASCII che indica
quanti byte verranno mandati. Capisci che ho finito quando arriva
qualcosa a lunghezza 0. Si usa
--------------------------------------------------------------------------------------------INTESTAZIONI DI ENTITA'
Hanno senso solo se c'è un body.
- Content-Encoding: ti sto mandando un dato gzip, anche se mi hai
chiesto un .txt. Ci guadagnamo in due: io ti mando meno roba, tu la
scarichi prima.
- Content-Language: in quale lingua naturale è stato codificato un
documento
- Content-Length: se non uso trasferimenti chunked, mi dice la lunghezza del contenuto
e così via...
--------------------------------------------------------------------------------------------INTESTAZIONI DI RICHIESTA
- Accept: "di tutti i contenuti che puoi mandare, accetto solo JSON".
Accetta una lista di formati con un grado di preferenza (0 = che merda, 1 = TOP)
- Authorization: serve a mandare la password
- Expect: "mi attendo una particolare risposta, tipo 100"
- Host: definizione del DNS a cui penso di rivolgermi
- If-...-...: fai l'azione solo se...
- Max-Forwards: "non seguirò più di un tot. se tu non sai rispondere"
- Proxy-authorization: un server proxy nel cammino ha bisogno di
una password
- Range: "voglio solo questo gruppo di byte"
- Referer: clicco su un link e in questo campo ci si mette l'URL della
partenza.
- TE: io client accetto le seguenti forme di Transfer Encoding
- User-Agent: dovrebbe identificare il tipo di terminale che il client sta
usando. Problema tornato alla ribalta con i dispositivi mobile e risolto con i CSS3 e le media query (qual è la dimensione minima?)
INTESTAZIONI TIPICHE DELLA RISPOSTA
Alcune di queste hanno a che fare tipicamente col redirect: qual è
la URL con la quale vai a pescare un dato che non è qui? (Location)
Oppure: sono un po' sovraccarico, prova a contattarmi tra un tot. di
secondi (Retry-After).
© C. Barberis, G. Malnati, 2011-14
Intestazioni di risposta
Accept-Ranges
Age
ETag
Location
Proxy-Authenticate
Retry-After
Server
Vary
WWW-Authenticate
Applicazioni Internet
21
Se c'è un corpo, la lunghezza dev'essere nota a priori, per intero o
per chunked in caso di trasferimento chunk. Se il contenuto è compresso, il content length rappresenta la lunghezza del contenuto
compresso, mentre il content type rappresenta il tipo di contenuto
che troverai dopo l'unzip.
Corpo dei messaggi
© C. Barberis, G. Malnati, 2
Insieme di byte trasmesso dopo le intestazioni
◦ La lunghezza è definita in Content-Length
◦ La tipologia di informazione è riportata in ContentType sotto forma di tipo MIME (es: text/html,
image/gif, …)
◦ Il corpo può essere compresso (Content-Encoding)
In questo caso, Content-Length rappresenta la lunghezza del
messaggio codificato (ovvero la lunghezza effettiva del body
contenuto nella risposta e non la lunghezza del messaggio
quando sarà decompresso)
Applicazioni Internet
22
Schema di interazione: GET
Server
© C. Barberis, G. Malnati, 2011-14
Client
t
Applicazioni Internet
23
Schema di interazione: POST
Server
© C. Barberis, G. Malnati, 2011-14
Client
t
Applicazioni Internet
24
Nelle prime versioni del protocollo ogni richiesta apriva un socket e
al termine lo chiudeva. Inefficiente.
Da 1.1 in avanti c'è un meccanismo un po' più furbo.
Richieste e connessioni
Nelle prime versioni del protocollo (0.9, 1.0) ogni richiesta doveva
essere effettuata su una nuova connessione
◦ Generata la risposta, il server abbatteva la connessione
© C. Barberis, G. Malnati, 2011-14
Comportamento semplice che può dare origine ad inefficienze
◦ Il tempo di attivazione e chiusura della connessione può essere lungo
rispetto al tempo di trasferimento (nel caso del TCP occorre scambiare
7 pacchetti)
Occhio che anche se il socket è tenuto vivo, il server non fa nessuna
assunzione circa il fatto che vengano dalla stessa persona e vadano
allo stesso destinatario.
A partire dalla versione 1.1 del protocollo è possibile negoziare
l’utilizzo della stessa connessione per effettuare più richieste
◦ Si utilizza l’intestazione “Connection” con il valore “keep-alive”
◦ Se il client o il server non intendono tenere aperta la connessione,
devono richiederlo esplicitamente indicando il valore “close” per
l’intestazione “Connection”
Anche se provengono dalla stessa connessione, il server considera
le richieste come totalmente indipendenti
Applicazioni Internet
25
Quando mi stufo ti mando una Connection: close. Io controparte ne
prendo atto e chiudiamo la connessione.
Richieste multiple
Server
© C. Barberis, G. Malnati, 2011-14
Client
t
Applicazioni Internet
26
Un macello dal punto di vista della programmazione, perchè bisogna
capire bene cosa sta succedendo.
Richieste sovrapposte
Server
© C. Barberis, G. Malnati, 2011-14
Client
t
Applicazioni Internet
27
User-Agent: il client, colui che genera le richieste
Origin (Server)
- Proxy: aggregatore di contenuti che permette di inoltrare verso il
server le richieste. Può essere trasparente (un passacarte) o non
trasparente (modificando i contenuti, limitando l'accesso, usando una sua memoria cache per limitare i trasferimenti...)
- Gateway: è qualcuno che si annuncia al mondo come server nominato. Il client è convinto di parlare con www.lastampa.it, ma in realtà
non lo fa. E' anche chiamato reverse proxy ed esiste per ragioni di
sicurezza e per "scalabilità".
Applicazioni HTTP
Lo standard prevede quattro possibili ruoli per le applicazioni
che utilizzano HTTP
◦ User-agent
Applicazione che origina le richieste HTTP
© C. Barberis, G. Malnati, 2011-14
◦ (Origin) Server
Applicazione che ospita le risorse trasferibili via HTTP
Accetta richieste e genera le corrispondenti risposte
◦ Proxy
Intermediario scelto esplicitamente dallo user-agent per inoltrare le
richieste ad un server
Può filtrare le richieste, tradurre gli indirizzi, servirsi di una memoria
tampone (cache) per aumentare le prestazioni
◦ Gateway (Reverse Proxy)
Intermediario trasparente allo user-agent (che lo crede l’origin server)
Inoltra le richieste all’origin server effettivo
Applicazioni Internet
LEZIONE 03 - 04/03/2014
28
Quando l'utente si rivolge a www.acme.com in realtà apre un socket
verso il proprio proxy a cui fa una richiesta. A sua volta il proxy può
essere contattato da uno dei più server di acme.com: nel caso si è
passati verosimilmente da un load balancer.
Applicazioni HTTP
proxy.user.net
GET / HTTP/1.1¿
Host: www.acme.com:80¿
Via: 1.1 proxy.user.net ¿
Connection: close¿
¿
© C. Barberis, G. Malnati, 2011-14
www.acme.com
GET http://www.acme.com/ HTTP/1.1¿
Host: www.acme.com:80
Connection: close¿
¿
Applicazioni Internet
a.acme.com
b.acme.com
c.acme.com
GET / HTTP/1.1¿
Host: www.acme.com:80¿
Via: 1.1 proxy.user.net,
1.1 www.acme.com ¿
Connection: close¿
¿
29
Tipi di proxy HTTP
Un proxy funge da intermediario tra client e server
◦ Riceve una richiesta dal client e la inoltra al server in base alla politica di
gestione impostate per i client
◦ Riceve la risposta, eventualmente la filtra e la restituisce al client
Due tipologie:
© C. Barberis, G. Malnati, 2011-14
◦ Proxy trasparenti: la risposta viene inoltrata al client senza modifiche
cache: memorizza le URL maggiormente richieste fornendo una maggiore
efficienza nella gestione delle risposte
filtro: il proxy può filtrare le richieste bloccando l’inoltro verso specifiche URL
per rispondere a esigenze di sicurezza o di controllo degli abusi della rete nel
caso di siti non autorizzati; può restituire un generico messaggio di mancata
autorizzazione.
◦ Proxy non trasparenti
Inoltra tutte le richieste, ma in certi casi può convertire o modificare le
risposte, ad es. togliere o inserire banner pubblicitari, convertire formati poco
diffusi, …
Applicazioni Internet
30
HTTP ha un meccanismo intrinseco per gestire l'autentcazione. Determinate operazioni dunque vengono svolte solo se il client dimostra
di avere le credenziali necessarie.
- Basic Authentication
Semplice ma da non usare mai. Mando una richiesta semplice, senza contenuto. Io server ti rispondo 401, tu client mi mandi user e
password. Se mi piacciono ti mando la risposta giusta, altrimenti
403 FORBIDDEN.
Autenticazione (1)
Meccanismo che consente all’utente di identificarsi presso
il server
© C. Barberis, G. Malnati, 2011-14
◦ Utilizzato in caso di risorse sensibili o su cui esistono restrizioni di
accesso
HTTP mette a disposizione due metodi di autenticazione:
◦ Basic authentication (supportato a partire dalla versione 1.0)
◦ Digest access authentication (supportato dalla versione 1.1)
Il client inoltra la richiesta
◦ La risposta ricevuta contiene il codice 401 (unauthorized) e
l’header WWW-Authenticate che specifica il meccanismo di
autenticazione richiesto dal server (metodo e parametri)
Applicazioni Internet
31
L'idea è che sul server ci sono una serie di risorse che vivono in un
certo realm, in cui vi sono una serie di utenti abilitati. Quando ti rispondo 401 UNAUTHORIZED ti dico il perchè. Il client fa apparire un
popup di dialogo. Si scrivono user e password e si inviano, codificate
in base64, al server.
Piccolo problema: base64 è reversibile. Se qualcuno intercetta la richiesta, con uno sforzo prossimo allo zero decodifica user e password.
Basic Authentication
Ad ogni gruppo di risorse tra loro correlate è associato un contesto di
sicurezza (realm)
◦ Per ogni realm è definita una lista di utenti autorizzati, con le relative password
◦ Per accedere ad una risorsa appartenente ad un dato realm, un browser deve
specificare le necessarie credenziali
© C. Barberis, G. Malnati, 2011-14
Il server, a fronte di una richiesta, invia una risposta contenente:
◦ HTTP/1.x 401 Unauthorized
◦ WWW-Authenticate: Basic realm=“Realm Name”
Il client:
◦ richiede le informazioni di autorizzazione all'utente (user e password)
◦ crea una nuova richiesta, inserendo nell’header le informazioni acquisite
codificate nel formato base64
◦ Nel caso in cui ulteriori richieste ricevano risposte di mancata autorizzazione
indicando lo stesso realm, invierà i dati precedentemente acquisiti
La codifica base64 è reversibile: è possibile intercettare la password
Applicazioni Internet
32
Un po' meglio la digest authentication, che si basa sul meccanismo
di risoluzione di una sfida. Fatto così è un po' povero: se io intercetto
uno scambio buono potrei provare a riproporre la stessa cosa. Per
questo motivo si parte dalla URI che ho richiesto e ci aggiunto un
numero casuale, costruito con un modo più o meno complesso
usando dati tempo-varianti e altre informazioni.
Digest authentication (1)
© C. Barberis, G. Malnati, 2011-14
Invece di inviare la password, è possibile inviare un dato derivato in
modo irreversibile dalla password
◦ Client e server eseguono la derivazione in modo indipendente
◦ Il client invia il proprio risultato al server, che lo confronta con quello
ottenuto localmente
◦ Se coincidono, il client ha dimostrato di conoscere la password senza
inviarla in chiaro
Occorre difendersi da tentativi di proporre la stessa derivazione da
parte di un’eventuale attaccante
◦ La funzione di derivazione ha, come ingresso, la URI della risorsa richiesta
ed un valore “casuale” fornito dal server inizialmente (nonce)
◦ Il nonce può essere derivato da data e ora della richiesta iniziale, dal
checksum del documento, …
◦ Ad ogni risposta di mancata autorizzazione (401) viene inviato un nuovo
nonce
Applicazioni Internet
33
Nel momento in cui io server ti rispondo 401 ti dò le istruzioni per risolvere la sfida. Se il server è fatto bene si accorge che è stato generato proprio da chi mi aspetto, in poco tempo e che la risposta è
coerente.
Digest authentication (2)
© C. Barberis, G. Malnati, 2011-14
Il client invia la richiesta della risorsa
Il server risponde specificando il metodo Digest Authentication e
un valore casuale e univoco (nonce value)
Il client
Anche questo tipo di autenticazione non piace per una serie di complicazioni a livello implementativo.
◦ Richiede all’utente le credenziali (user e password)
◦ Concatena opportunamente le stringhe relative a user, password, nonce
value, metodo HTTP e URI della risorsa richiesta
◦ Calcola il checksum MD5 della stringa ottenuta
◦ Invia la richiesta contente gli header opportuni (stringa MD5, username,
nonce value, …)
Il server:
◦ Conosce la password dell’utente
◦ Usando i valori contenuti nell’header della richiesta, esegue la
derivazione MD5
◦ Confronta il risultato con quello ricevuto ed invia la risposta opportuna
Applicazioni Internet
34
Per questo si tende a fare login applicativo, usando SSL. L'essere
stateless è bellissimo, ma è una fregatura perchè in questo caso mi
converebbe ricordare che uno si è appena loggato. Per questo si introducono le sessioni, modo per riconoscere che un insieme di coppie richieste-risposta non sono indipendenti tra loro, ma fanno riferimento alle stesse entità. Il login è appunto un classico caso: una volta che io mi sono loggato e tu server mi riconosci, mi piacerebbe che
ti ricordassi che sono sempre io.
Gestione delle sessioni
© C. Barberis, G. Malnati, 2011-14
Lo sviluppo di servizi applicativi basati sul protocollo
HTTP richiede la capacità di gestire correttamente
sessioni di lavoro da parte degli utenti
◦ Prenotazione di voli aerei
◦ Acquisto di prodotti in un negozio on-line
◦ …
Poiché HTTP tratta tutte le richieste come tra loro
indipendenti, occorre introdurre – a livello applicativo –
un meccanismo per supportare questa modalità di
lavoro
Applicazioni Internet
35
Di per sè il concetto di sessione non ha niente a che fare con l'autenticazione, in quanto esistono sessioni completamente anonime: se
io metto prodotti in un carrello non mi devo necessariamente loggare.
© C. Barberis, G. Malnati, 2011-
Cos’è una sessione
Un insieme di richieste, provenienti dallo stesso
browser e dirette allo stesso server, confinate in
un dato lasso di tempo, volte ad interagire con
risorse tra loro correlate
Per l’identificazione e la gestione di una sessione
non è necessario identificare l’utente in modo
esplicito: sessione anonima
È possibile creare anche sessioni nominali
Applicazioni Internet
36
L'idea è generare un numero su uno spazio di numeri grande e dirlo
al client. In questo modo tutte le volte che il client manda una richiesta specifica quel numero e il server lo riconosce.
Siccome è 128 bit (o più grande al bisogno), la probabilità di tirarlo a
caso e beccare un altro è bassa. Però può essere copiato.
Logica di gestione
© C. Barberis, G. Malnati, 2011-14
Il Web server associata una richiesta proveniente da un
dato client ad un identificatore univoco (SessionID)
◦ Tale identificatore viene comunicato al client, il quale lo invierà in
tutte le successive richieste
◦ Il server può tenere traccia della sequenza di azioni eseguite dal
client attraverso il SessionID indicato
Nell'ottica di non fare scambi di valore bestiale, anche se quel numero mi viene copiato non è un grosso problema. Questo a patto di farlo durare poco, perchè altrimenti sono dolori.
Il server crea nuove sessioni, invalida quelle vecchie e
definisce politiche di persistenza per le sessioni attive
Dopo un certo periodo di inattività dell’utente
(dell’ordine delle decine di minuti) la sessione “scade” e
ne viene perso lo stato
E' facolta del server crearsi una mappa di azioni fatte relative a quel
determinato sessionID. Se l'utente mi ricontatta entro un tot minuti
con quello stesso numero lo riconosco, altrimenti "non so più chi sia".
Vi è la possibilità di loggare un utente passando da una terza persona (mi loggo col mio account Google ed è Google che mi dà il token
col quale tenere traccia della sessione dell'utente).
Applicazioni Internet
37
Schema di gestione delle sessioni. Concettualmente tutto molto semplice.
Logica di gestione
© C. Barberis, G. Malnati, 2011-14
Richiesta iniziale Generazione di un ID
-
ID
TimeOut Distruzione
della sessione
Richieste ulteriori Accesso ai dati
di sessione
Dati di
sessione
Applicazioni Internet
38
Come lo genero? Tipicamente a caso, per evitare di finire "a casa di
qualcun altro". Occhio che dev'essere random davvero, non 27x + 6.
In campi di estrema sicurezza si usano generatori HW basati su diodo zener, o comunque qualcosa che garantisca alta randomicità.
Identificazione di una sessione
© C. Barberis, G. Malnati, 2011-14
Ogni sessione è identificata da un ID, generato
in modo univoco dal server
Di solito un ID è un numero
◦ generato progressivamente a partire da un valore
dato
◦ generato casualmente in un intervallo molto ampio
La seconda soluzione è più complessa ma anche
più immune ad attacchi da parte di client
“maliziosi”
Applicazioni Internet
39
© C. Barberis, G. Malnati, 2011-14
Gestione dell’ID
Per identificare in modo univoco le richieste
successive provenienti da un client è necessario
trasferirgli l’ID della sessione
Esistono vari modi per farlo:
◦
◦
◦
◦
Passaggio esplicito nel contenuto del documento
Mediante l’uso di cookies
Mediante la tecnica di riscrittura dei link
Coordinando le sessioni dal lato client
Applicazioni Internet
40
PASSAGGIO ESPLICITO
Form, user e password, POST al sito https. Il sito https verifica la
bontà dei dati e dentro i vari link che mi appaiono da loggato mi appare l'ID della sessione (o comunque campi hidden, che di hidden
hanno ben poco perchè posso pacioccarli con Firebug). Un po' becero.
Passaggio Esplicito
© C. Barberis, G. Malnati, 2011-14
Richiede che lato client sia presente del codice
in grado di estrarre il valore passato come
campo della risposta
◦ E utilizzarlo come parametro per formulare le
richieste successive
Può essere implementato come campo hidden
in un form
◦ Oppure essere gestito da codice Javascript
Applicazioni Internet
41
MEDIANTE COOKIE
Un cookie è un'estensione del protocollo HTTP. E' facoltà del server
aggiungere nelle risposte dei Set Cookie, è facoltà del client salvarsi
il contenuto e riproporlo nelle richieste successive con un Cookie:.
Il server indica una data di scadenza per il cookie, ma il client può
decidere di cazziarlo prima del tempo.
© C. Barberis, G. Malnati, 2011-14
Passaggio Mediante Cookie
Un cookie è una coppia (chiave=valore) che un
server può memorizzare in modo transitorio o
semi-permanente su un client
Il client provvede a rimandare automaticamente
il cookie come parte dell’intestazione ogni qual
volta effettua una richiesta al server che lo ha
inviato
Applicazioni Internet
42
Richiesta.
Risposta del server. Giacchè non vedo cookie, negli header ti metto
un Set-Cookie: da qui fino a DATE, tutte le volte che contatti me su
www.abc.com e mi chiedi una cosa qualunque che inizia con /, accludimi 002345.
Passaggio Mediante Cookie
Richiesta iniziale
© C. Barberis, G. Malnati, 2011-14
GET /file.html HTTP/1.0
Accept: text/html
Accept: image/gif
Risposta
HTTP/1.1 200 Ok
Connection: close
Content-Type: text/html
Set-Cookie: ID=002345;expires=DATE;
path=/; domain=www.abc.com
<html>... </html>
Applicazioni Internet
43
Se il client accetta questa cosa qua, manderà delle richieste con
scritto Cookie: ID = 002345. Lo allega fin quando non scade o non è
cancellato.
Un programma applicativo che supporta HTTP deve gestire i Cookie
a manina.
Passaggio Mediante Cookie
Richieste successive
© C. Barberis, G. Malnati, 2011-14
GET /file.html HTTP/1.0
Accept: text/html
Accept: image/gif
Cookie: ID=002345
Il cookie viene allegato dal client ad ogni richiesta fino
che non scade o non viene cancellato esplicitamente
Non tutti i client supportano i cookie
◦ È sempre possibile disabilitarne il funzionamento
Applicazioni Internet
44
Dentro i cookie si aggiungono tipicamente tutta una serie di campi.
Oggi è un po' meno nascosto del solito perchè l'utente viene avvisato. E beh.
Informazioni di un cookie
Oltre alla coppia <nome>=<valore> che contiene
l’informazione principale del cookie, un server può
aggiungere i seguenti campi (separati da ‘;’)
◦ Comment
© C. Barberis, G. Malnati, 2011-14
stringa leggibile di descrizione del cookie
◦ Domain
dominio (DNS) per cui il cookie è valido
◦ Max-Age
durata in secondi del cookie
◦ Path
URI per il quale il cookie è valido
◦ Version
versione della specifica a cui il cookie aderisce
Applicazioni Internet
45
URL REWRITING
Per evitare alcune complessità legate ai cookie si usa l'URL Rewriting. Io server web, prima di mandarti la risposta definitiva alle cose
che mi hai chiesto, ispeziono il documento e tutte le volte che vedo
un link interno al sito lo paciocco aggiungendo il tuo SESSION_ID
(con cancelletto, direttamente nella URL, ...). Questo viene fatto abilitando il comportamento url_rewrite: la cosa ha tutti i costi del caso
e ovviamente funziona solo per le cose HTML.
© C. Barberis, G. Malnati, 2011-14
Riscrittura dei Link
Se un browser non supporta i cookie è possibile
mantenere ugualmente traccia della sessione in corso
riscrivendo opportunamente i link del documento che
deve essere trasferito
Meccanismo adatto solo nel caso di documenti HTML:
◦ A fronte della prima richiesta, il server analizza il testo del
documento che viene inviato verso il client e modifica
automaticamente gli indirizzi “interni” in esso contenuti,
aggiungendo l’informazione relativa alla sessione in corso
◦ Nel corso delle richieste successive, il server estrae il dato di
sessione, lo rende disponibile per un’eventuale elaborazione e lo
re-introduce all’atto della trasmissione della pagina
Applicazioni Internet
46
Un esempio. Il server web, nel mandare indietro la pagina, modifica
i link interni.
Riscrittura dei Link
© C. Barberis, G. Malnati, 2011-14
Il documento
<html> <body> <ul>
<li><a href= “link1.html”>uno</a>
<li><a href= “link2.html”>due</a>
<li><a href=
“http://otherhost/home.html”>tre</a>
</ul> </body></html>
diventa
<html> <body> <ul>
<li><a href=
“link1.html;$ID$002345”>uno</a>
<li><a href=
“link2.html;$ID$002345”>due</a>
<li><a href=
“http://otherhost/home.html”>tre</a>
</ul> </body></html>
Applicazioni Internet
47
Esiste un quarto modo di gestire le sessioni che presuppone l'esistenza di meccanismi di gestione lato client. Tipicamente può essere
interessante nei siti onepage.
Altre Tecniche
© C. Barberis, G. Malnati, 2011-14
I metodi precedenti non richiedono capacità di
elaborazione sul client diversa dalla gestione del
protocollo HTTP
◦ In alcuni casi è possibile eseguire sul client un modulo
opportuno (applet Java, controllo ActiveX, codice Javascript...) in
grado di interfacciarsi direttamente con un server remoto e
svolgere le funzioni di coordinamento della sessione
La tecnologia Ajax realizza sessioni web interattive con
supporto Javascript lato client
◦ Il codice Javascript si occupa di tenere traccia della sessione e di
inviarlo al server
◦ Meccanismo tipicamente adottato da servizi di tipo "single page"
Applicazioni Internet
48
Avendo capito i risvolti dell'HTTP, vediamo ora com'è possibile essere "clienti" dell'HTTP, in Java. Lavorando in Java si possono usare
le librerie del package java.net.* oppure quelle di org.apache.http.*.
Utilizzo di HTTP lato client
Esistono numerose librerie che permettono di gestire
richieste HTTP lato client per i diversi linguaggi di
programmazione
© C. Barberis, G. Malnati, 2011-14
◦ libcurl (curl.haxx.se) è probabilmente la più famosa
Scritta in C, offre elevate prestazioni, supporto per molte funzionalità del
protocollo e può essere utilizzata in moltissimi sistemi operativi e offre
meccanismi di accesso per quasi tutti i linguaggi di programmazione
In Java sono disponibili due implementazioni principali
◦ Le classi contenute nel package java.net.*
Disponibili in tutte le distribuzioni del linguaggio
◦ Quelle del package org.apache.http. *
Disponibile come parte della libreria Apache HttpClient (hc.apache.org)
Applicazioni Internet
49
Di base in java.net c'è tutto. Certo che potrei connettermi al server
aprendo un socket, ma se poi il server mi risponde tentando un trasferimento chunked poi me lo devo gestire io da codice.
Il package java.net
© C. Barberis, G. Malnati, 2011-14
Contiene classi per modellare e gestire connessioni
di rete
◦ Al livello più basso, è possibile stabilire una connessione
verso un host remoto istanziando oggetti di tipo Socket e
DatagramSocket
◦ Il primo apre una connessione TCP verso un server, il
secondo permette di inviare e ricevere datagram UDP
Il programmatore deve farsi carico di tutto il
protocollo applicativo necessario per scambiare
efficacemente dati con il server
◦ Gestendo la sintassi e la semantica delle richieste, la
codifica e l’eventuale frammentazione dei messaggi, gli
errori di comunicazione, l’autenticazione, la crittografia, …
Applicazioni Internet
50
Quindi usiamo le classi che già ci sono per l'HTTP.
- URL
- URLConnection
- HttpURLConnection
Principali classi del package java.net
URL
◦ Modella una risorsa remota
© C. Barberis, G. Malnati, 2011-14
URLConnection
◦ Modella un generico canale di comunicazione verso la risorsa
denotata da una URL
◦ Permette di scambiare (inviare e ricevere) informazioni con la
risorsa
◦ Supporta direttamente operazioni con URL di tipo file:, ftp:, jar:
HttpURLConnection
◦ Sottoclasse di URLConnection che modella scambi attraverso il
protocollo HTTP
Applicazioni Internet
51
How-To di base per FTP
Se la mia risorsa è di tipo file: (quindi accessibile sul file system locale) oppure ftp: oppure jar:
1. Creo un oggetto URL di tipo opportuno
2. Apro una connessione con openConnection() salvandomi il risultato in un oggetto di tipo UrlConnection.
3. Con getInputStream() leggo la risorsa
4. Incapsulo l'InputStream in un BufferedInputStream in modo da minimizzare il salto della barricata tra user mode e kernel mode.
5. Mi preparo un posto in cui scrivere quanto ho letto
6. Leggi un byte fin quando la risorsa non è finita e scrivila.
7. Chiudi gli stream
Esempio
URL url = new URL("ftp://some.host/some.file");
URLConnection urlConnection = url.openConnection();
© C. Barberis, G. Malnati, 2011-14
InputStream in = new BufferedInputStream(
urlConnection.getInputStream());
ByteArrayOutputStream out=new ByteArrayOutputStream();
try {
int i=0;
while ((i=in.read())!=-1) out.write(i);
} finally {
in.close();
out.close();
}
byte[] data= out.toByteArray();
Applicazioni Internet
52
Effettuare una richiesta HTTP 1/2
© C. Barberis, G. Malnati, 2011-14
Nel caso del protocollo HTTP (HTTPS), le operazioni
sono leggermente più complesse
◦ Occorre indicare il metodo con cui interrogare il server
◦ (per default è GET, si possono impostare POST, PUT, HEAD,
DELETE, …)
◦ Occorre configurare la gestione dei cookie (non prevista per
default)
◦ Occorre configurare l’uso di meccanismi di autenticazione (se
implementati a livello HTTP)
◦ Occorre configurare l’uso di un proxy (se richiesto) e l’eventuale
cache delle risposte
53
Rispetto all'esempio visto prima per FTP bisogna fare un casting.
Ai metodi base di UrlConnection sono aggiunti tutta una serie di metodi specifici per HTTP. La risposta che verrà letta dall'output stream
dovrà essere interpretata a seconda del Content Type.
Effettuare una richiesta HTTP 2/2
© C. Barberis, G. Malnati, 2011-14
Quando il protocollo è HTTP, il metodo
openConnection() di URL, restituisce un
oggetto di tipo HttpUrlConnection
◦ È utilizzato per mandare o ricevere flussi di dati la cui
lunghezza è sconosciuta a priori
◦ Oltre ai dati, si possono ottenere informazioni sullo
stato della richiesta e dell’header HTTP
getContentLength(), getResponseCode(), getContentType(),
getContent(),…
La risposta ricevuta deve essere analizzata
coerentemente con il proprio ContentType
◦ Testo semplice, oggetti JSON, XML, immagini, …
Applicazioni Internet
54
How-To GET.
1) Creo la URL.
2) Casto la openConnection()
3) Lavoro sostanzialmente come prima.
Richiedere dati tramite GET
CORRETTA RISPETTO ALL'ORIGINALE
© C. Barberis, G. Malnati, 2011-14
Se poi voglio fare una POST che richiede un body, devo fornire il
body.
Se il metodo scelto richiede l’invio di dati verso il
server, occorre accluderli prima di iniziare a leggere la
risposta
Applicazioni Internet
public byte[] get(String host, int port, String path)
throws IOException {
URL url = new URL("http", host, port, path);
HttpURLConnection conn =
(HttpURLConnection) url.openConnection();
ByteArrayOutputStream out=new ByteArrayOutputStream();
InputStream in = new BufferedInputStream(
conn.getInputStream());
try {
Con HttpURLConnection non devo chiudere i flussi a mano come
prima, ma usare disconnect() - che rilascia le risorse e chiude i flussi - perchè altrimenti vado in deadlock.
int i=0;
while ((i = in.read()) != -1) out.write(i);
}
finally {
conn.disconnect();
out.close();
}
return out.toByteArray();
}Applicazioni Internet
55
Alcuni messaggi di errore sono gestiti automaticamente da HttpURLConnection, in particolare i 3XX fino a 5 livelli per non palleggiare
troppo. Il comportamento è disabilitabile prima di aprire la connessione. Non viene accettato il passaggio in automatico da http a https,
la cosa dev'essere gestita mediante codice applicativo per evitare
che qualcuno faccia injection di qualunque tipo.
Gestire gli errori
Ht
HttpURLConnection
gestisce automaticamente le
richieste di ridirezione verso altri host
© C. Barberis, G. Malnati, 2011-14
Per HTTP è un po' più complicato:
- come lo interrogo? (di default è GET)
- gestisco i cookie? (di default no)
- devo fare autenticazione di base? (devo fornire authenticator)
- voglio un proxy? (di default non si specifica niente)
- voglio cachare? (di default non si fa)
◦ Fino a 5 livelli
◦ Si può disabilitare tramite setFollowsRedirect(false)
◦ Non consente il cambio di protocollo tra http e https (e
viceversa)
Se non è stato possibile generare del contenuto nella risposta, nel
momento in cui chiamo getInputStream() ottengo un'eccezione. Siccome un body viene comunque generato, per evitare misunderstanding quel body lo leggo da un'altra parte.
Nel caso in cui la risposta contenga un codice di
errore (4xx o 5xx), il metodo getInputStream()
lancia un’eccezione
◦ E’ possibile risalire all’errore sia chiedendo esplicitamente
il codice (getResponseCode()) che leggendo il flusso di
errore tramite getErrorStream()
Applicazioni Internet
56
Alle intestazioni accedo tramite alcuni metodi generici, a cui si passa
ad esempio il nome dell'header e viene restituito il valore dell'intestazione.
Accedere alle intestazioni
La risposta porta con sé un insieme di
intestazioni, sotto forma di coppie chiave/valore
© C. Barberis, G. Malnati, 2011-14
◦ Vi si accede tramite i metodi
String getHeaderField(String h)
int getHeaderFieldInt(String h, int default)
long getHeaderFieldDate(String h, long default)
Map<String, List<String>> getHeaderFields()
Applicazioni Internet
57
Come si fa il POST? Beh, devo avere dei dati da spedire che in qualche modo devono essere codificati. Se il sito è progettato per delle
persone, il sito si aspetta dei dati codificati in formato
x-www-form-urlencoded
Le varie coppie (chiave, valore) sono affiancate da una &. Le lettere
restano lettere, i numeri restano numeri, gli spazi diventano + e altri
caratteri diventano %xx.
Inviare dati tramite POST
© C. Barberis, G. Malnati, 2011-14
Prima di iniziare la connessione, occorre
impostare il metodo e preparare i dati da
spedire
◦ Per default, sono codificati secondo lo schema
application/x-www-form-urlencoded
◦ Coppie nome=valore, separate da ‘&’ in cui gli spazi
sono sostituiti da ‘+’ e i caratteri non alfabetici sono
sostituiti da %xx (valore esadecimale del carattere)
Applicazioni Internet
Si raccolgono dunque i dati che si vogliono sottomettere e li mandiamo nel formato che il server si aspetta.
58
How-To POST
1) Preparo la URL a cui spedire
2) openConnection() sulla URL
3) Imposto il setDoInput (body nella richiesta) e il setDoOutput (body
nella risposta) entrambi a TRUE
4) Imposto il metodo a POST
5) Dico che tipo di contenuto sto mandando
6) Quanti byte ti sto mandando?
7) Scrivo i byte del messaggio e chiudo
8) Leggo la risposta. Nel caso immagino che la risposta contenga dei
caratteri.
Inviare dati tramite POST
© C. Barberis, G. Malnati, 2011-14
CORRETTA RISPETTO ALL'ORIGINALE
public String post(String host, int port, String path, String msg) throws
IOException {
URL url = new URL("http", host, port, path);
URLConnection conn = url.openConnection();
conn.setDoInput(true); conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type","x-www-form-urlencoded");
conn.setRequestProperty("Content-Length",""+msg.getBytes().length);
conn.getOutputStream().write(msg.getBytes());
conn.getOutputStream().close();
//legge la risposta
StringBuilder sb = new StringBuilder();
BufferedReader in = new BufferedReader(
new InputStreamReader(
conn.getInputStream()));
String line;
while ((line = in.readLine()) != null)
sb.append(line);
conn.disconnect();
return sb.toString();
}
Applicazioni Internet
Perchè devo fare questo giro da pazzi? Perchè altrimenti devo fare
un giro ancora più da pazzi.
59
Se ho l'autenticazione tra i piedi e magari è basic (posto che non si
deve fare mai) si può fare come indicato sulla slide. Altrimenti si passa un oggetto di tipo Authenticator in cui inserire user e password.
Autenticazione
© C. Barberis, G. Malnati, 2011-14
Un server web può essere configurato per
richiedere le credenziali di accesso ad una data
URL
◦ Possono essere incluse direttamente nella URL, col
seguente formato
http://<user>:<password>@some.server/some.file
◦ È possibile installare un oggetto di tipo Authenticator
per fornire le credenziali quando vengono richieste
Applicazioni Internet
60
How-To Autenticazione
Si prepara un oggetto che estende la classe Authenticator che presuppone l'esistenza di un metodo abstract - dunque da definire - che
si chiama getPasswordAuthentication() e si aspetta uno username
e una password.
L'oggetto così ottenuto viene reso il default authenticator e da questo
momento in avanti, se apriamo una URLConnection verso un sito
che richiede una qualunque forma di autenticazione, verrà invocato
questo oggetto per sottomettere queste credenziali nel modo opportuno.
© C. Barberis, G. Malnati, 2011-14
Autenticazione
Authenticator.setDefault(
new Authenticator() {
protected PasswordAuthentication
getPasswordAuthentication() {
return
new PasswordAuthentication(
username,
password.toCharArray()
);
});
Applicazioni Internet
61
Se il sito gestisce le sessioni coi cookie le devo gestire a manina,
installando un cookie manager.
Gestire i cookie
© C. Barberis, G. Malnati, 2011-14
Spesso, i siti web optano per uno schema di
autenticazione basato sul livello applicativo
◦ Occorre dapprima connettersi inviando (tramite POST) le
proprie credenziali
◦ Successivamente è possibile accedere alle risorse
contenute
Questo richiede identificare la sessione con l’utente
◦ Il metodo più comune è basato sull’uso di cookie che
vengono acclusi alle richieste successive
HttpURLConnection per default non gestisce l’uso
di cookie
◦ È possibile associare un CookieManager al gestore delle
connessioni, attraverso il quale si possono anche iniettare
nuovi cookie
Applicazioni Internet
62
How-To Gestione cookie
Si prepara un oggetto CookieManager e lo si imposta come default
della classe CookieHandler. Da questo momento in avanti tutte le
connessioni che gestiscono cookie passano dal cookie manager.
Inoltre posso forgiarmi dei cookie quando mi gira. Nell'esempio io
creo un cookie per Twitter per fare in modo che le pagine mi vengano restituite in italiano.
Gestire i cookie
© C. Barberis, G. Malnati, 2011-14
CookieManager cookieManager = new CookieManager();
CookieHandler.setDefault(cookieManager);
HttpCookie cookie = new HttpCookie("lang", "it");
cookie.setDomain("twitter.com");
cookie.setPath("/");
cookie.setVersion(0);
cookieManager.getCookieStore().
add(new URI("http://twitter.com/"), cookie);
URL url=new URL("http://twitter.com/");
HttpURLConnection conn =
(HttpURLConnection) url.openConnection();
//il cookie aggiunto viene inviato insieme alla richiesta
Applicazioni Internet
63
Pensa alla wifi del Politecnico. Ti connetti ma vieni rimandato a
wifiauth.polito.it. Come fare? Intanto dobbiamo accorgercene.
Gestire l’accesso alla rete
© C. Barberis, G. Malnati, 2011-14
Alcune reti WiFi richiedono che l’utente effettui
un’autenticazione alla rete, passando per un
browser, prima di dare accesso alle risorse richieste
◦ Questo viene tipicamente implementato forzando una
risposta di tipo 302 (moved temporarely) o 303 (see
other) verso la pagina di login a qualsiasi richiesta venga
effettuata
Si può verificare se questo è necessario in un dato
contesto, effettuando una richiesta ad una URL nota
in fase di avvio dell’applicazione
◦ Se la risorsa ottenuta non ha la stessa URL a cui si è
inoltrata la richiesta, si può aprire il browser ed effettuare
il processo di login
Applicazioni Internet
64
How-To Gestire l'accesso alla rete
Per capire se sono stato agganciato a qualcuno faccio l'equivalente
di un ping a un host ben noto. Ci facciamo dare l'InputStream come
al solito, ma senza leggerlo (perchè altrimenti parte lo scambio effettivo di dati). Si fa un confronto tra l'host indicato e l'host che è contenuto nella risposta. Se sono diversi si apre un mondo: il meglio che
viene è aprire la finestra di un browser :)
© C. Barberis, G. Malnati, 2011-14
Gestire l’accesso alla rete
URL url=new URL("http://well.known.host/");
HttpURLConnection urlConnection =
(HttpURLConnection) url.openConnection();
try {
InputStream in = new BufferedInputStream(
urlConnection.getInputStream());
if (!url.getHost().equals(
urlConnection.getURL().getHost())) {
//Occorre aprire un browser,
//attendere che venga fatta l’autenticazione
//e riprovare a connettersi
}
} finally {
urlConnection.disconnect();
}
Applicazioni Internet
65
L'alternativa più semplice, ma un po' più onerosa a livello di spazio,
è l'uso di Apache HttpClient che dà accesso a tutte le funzionalità
del protocollo. Footprint un po' più rilevante, ma chissenefrega.
A partire da questo prodotto sono stati derivati tutta una serie di
prodotti "interessanti", che fanno più o meno le stesse cose in modalità asincrona.
La libreria Apachee HttpClient
H
© C. Barberis, G. Malnati, 2011-14
Soluzione che offre un accesso al protocollo a
più alto livello
◦ Come la precedente, è basata su un modello di
esecuzione sincrona, bloccante
◦ Offre numerosi punti di accesso alle diverse
funzionalità del protocollo, facilitando l'adattamento
dei comportamenti
◦ Maggiore impatto in termini di memoria
◦ Sono alla base di altre librerie più evolute
(HttpAsyncClient)
Applicazioni Internet
66
HttpClient
How-To HTTP Client
1) Creo un oggetto CloseableHttpClient, oggetto base con cui lavorare.
2) Creo una richiesta, in questo caso GET con un HttpGet che incapsula la mia richiesta
3) Esegui l'oggetto per la GET con execute().
4) Nella risposta ho l'oggetto e il corpo, che posso leggere.
Oggetto ad alto livello in grado di eseguire una o
più richieste HTTP
© C. Barberis, G. Malnati, 2011-14
◦ L’utente fornisce la richiesta
◦ HttpClient fornisce la corrispondente risposta o lancia
un’eccezione
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpget = new HttpGet("http://some.host/path");
CloseableHttpResponse response = httpclient.execute(httpget);
try {
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
try {
// do something useful
} finally {instream.close();}
}
} finally {response.close();}
Applicazioni Internet
Gestione delle risorse molto più naturale, non ci sono storture che
portano a deadlock.
Se per qualche motivo la URL non è raggiungibile viene lanciata una
eccezione.
67
Vi sono classi che costruiscono automaticamente URL del tipo
www.google.it?q=chiave&p=qualcosa&r=qualcosa&s=qualcosa. Di
seguito l'esempio.
Richieste HTTP
Sono modellate da istanze delle classi
corrispondenti ai metodi HTTP
© C. Barberis, G. Malnati, 2011-14
◦ HttpGet, HttpHead, HttpPost, HttpPut, HttpDelete,
HttpOptions, HttpTrace
Il costruttore richiede la URL cui si fa
riferimento
◦ Nel caso di richieste GET, la URL può contenere uno
o più parametri e/o un frammento
◦ La classe URIBuilder permette di creare
dinamicamente la codifica necessaria
Applicazioni Internet
68
© C. Barberis, G. Malnati, 2011-14
Richieste HTTP
URIBuilder builder = new URIBuilder();
builder
.setScheme("http")
.setHost("www.google.com")
.setPath("/search")
.setParameter("q", "httpclient")
.setParameter("btnG", "Google Search")
.setParameter("aq", "f")
.setParameter("oq", "");
URI uri = builder.build();
HttpGet request = new HttpGet(uri);
System.out.println(request.getURI());
http://www.google.com/search?q=httpclient&btnG=Google+Search&aq=f&oq=
Applicazioni Internet
69
Risposte HTTP
© C. Barberis, G. Malnati, 2011-14
La classe ClosableHttpResponse modella le
risposte ricevute da un client
◦ Attraverso i metodi offerti dalla classe è possibile
conoscere la versione del protocollo usata dal server,
il codice di stato, le intestazioni, le richieste di
creazione di cookie, …, che sono state ricevute
Applicazioni Internet
70
Entità HTTP
Richieste e risposte possono incapsulare un
corpo, secondo le regole HTTP
© C. Barberis, G. Malnati, 2011-14
◦ Questo viene modellato dalla libreria attraverso
oggetti di tipo HttpEntity e sue sottoclassi
Metodo
Corpo Richiesta
GET
No
Corpo Risposta
Si
POST
Si
Si
PUT
Si
Si
DELETE
No (*)
No
HEAD
No
No
Applicazioni Internet
71
Entità HTTP
© C. Barberis, G. Malnati, 2011-14
Si accede al contenuto di un’entità in due modi:
◦ Richiedendo il suo InputStream (e rilasciandolo al
termine) con il metodo getContent()
◦ Passando un OutputStream su cui riversare le
informazioni contenute attraverso il metodo
writeTo(OutputStream os)
Si crea un’entità con contenuto (per le
richieste), istanziandone una sottoclasse
◦ StringEntity, ByteArrayEntity, InputStreamEntity,
FileEntity, UrlEncodedFormEntity
Applicazioni Internet
72
Inviare dati tramite POST
List<NameValuePair> formparams =
new ArrayList<NameValuePair>();
© C. Barberis, G. Malnati, 2011-14
formparams.add(
new BasicNameValuePair("param1", "value1"));
formparams.add(
new BasicNameValuePair("param2", "value2"));
UrlEncodedFormEntity entity =
new UrlEncodedFormEntity(formparams, "UTF-8");
HttpPost request =
new HttpPost("http://some.host/some.file");
request.setEntity(entity);
Applicazioni Internet
73