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