UN SINGOLO COMPONENTE... ? • Finora ci siamo concentrati su un singolo programma = un singolo componente – si leggono i dati di ingresso ... – ... si elabora (computazione) ... – ... si scrivono i risultati in uscita. • Ma oggi quasi mai un’applicazione consiste in un singolo componente! – un componente acquista molto più valore se può cooperare a creare progetti più grandi – elaborazione distribuita su rete ARCHITETTURE MULTI-COMPONENTE • componenti software e hardware eterogenei • ogni componente fornisce servizi agli altri componenti e usa i servizi da essi forniti • necessità di protocolli di comunicazione • esecuzione distribuita nel tempo e nello spazio ARCHITETTURA CLIENTE / SERVITORE Servitore: • un qualunque ente computazionale capace di nascondere la propria organizzazione interna • presentando ai clienti una precisa interfaccia per lo scambio di informazioni Cliente: • qualunque ente in grado di invocare uno o più servitori per svolgere il proprio compito IL MODELLO INTERNET Cliente = browser Web – Internet Explorer, Netscape Navigator, ... Browser Web (cliente) Server Web rete Internet Servitore = server Web (sul sito) IL PROTOCOLLO DI COMUNICAZIONE HTTP: HyperText Transfer Protocol 1) il cliente invia al server l’identificatore della pagina richiesta (URL) http://www.unibo.it/studenti/stud.html 2) il server recupera il file corrispondente a quella pagina... ..../studenti/stud.html 3) ... e lo invia al cliente (byte per byte) IL PROTOCOLLO DI COMUNICAZIONE Browser Web (cliente) http://..../studenti/stud.html 1 3 Server Web 2 IL PROTOCOLLO DI COMUNICAZIONE HTTP: HyperText Transfer Protocol Pregio: • è un protocollo molto semplice da gestire e da implementare Difetto: • nella versione base, è poco flessibile – il contenuto delle pagine web è prefissato – il server non fa alcuna elaborazione, si limita a prendere un file e spedirlo HTTP: ESTENSIONI Obiettivo: • dare al server la possibilità di rispondere a una richiesta in modo “personalizzato” e flessibile (non solo fisso a priori) – esempio: fornire i risultati di una ricerca Come? • rendendo il server capace di eseguire un programma per rispondere alla richiesta. CGI: Common Gateway Interface HTTP: ESTENSIONI Risultato: • qualunque programma può fornire i suoi servizi sul web – non più solo su un computer isolato! • non importa il linguaggio in cui è scritto • non importa come elabora (computazione) • importa che gestisca input e output nei modi previsti dagli standard, ossia che segua il MODELLO DI COORDINAZIONE previsto. HTTP + CGI Con CGI, HTTP diviene aperto e flessibile: 1) il cliente invia al server l’URL della pagina richiesta, che però non è una vera pagina, ma il nome di un programma (xxxx): http://www.unibo.it/cgi-bin/xxxx 2) il server esegue il programma xxxx... ..../cgi-bin/xxxx 3) ... e invia il risultato al cliente. HTTP + CGI Browser Web (cliente) http://..../cgi-bin/xxxx 1 3 Server Web 2 Programma xxxx HTTP + CGI Quindi: • è il programma che risponde al cliente, non più il server (fa solo da tramite) • tutto quello che il programma scrive sullo standard output viene trasferito “pari pari” al cliente (il browser Web) – semplice testo, testo HTML, immagini, altro... • si può trasferire di tutto: basta che il cliente sappia come trattare quello che gli arriva. CGI: UN MINI-ESEMPIO Un programma C che stampa “Hello World”... main(){ printf(“Hello World!”); } ... CGI: UN MINI-ESEMPIO ... portato “sulla rete”: Fondamentale il “doppio a capo” main(){ printf(“Content-type: text/plain\n\n”); printf(“Hello World!”); } forma standard per avvertire il browser di “cosa gli sta arrivando” (in questo caso testo semplice, senza formattazioni particolari) MINI-ESEMPIO: VARIANTE Un programma C che stampa “Hello World” come pagina HTML Questa volta stiamo inviando testo HTML main(){ printf(“Content-type: text/html\n\n”); printf(“<H1>Here we are!</H1>”); printf(“<P><H2>Hello World!</H2>”); fflush(stdout); “doppio a capo” } opportuno svuotare il buffer di output per garantire che tutto il testo sia effettivamente inviato UNA PRECISAZIONE • Questi programmi devono essere compilati come normali programmi da console, non come programmi (pseudo-) grafici! – il server presuppone di poter parlare col programma tramite i normali canali di I/O, non tramite finestre di un qualche tipo! • Quindi, non si può usare il Turbo C! • Occorre DJgpp – o un qualunque compilatore C che produca eseguibili “da linea di comando” (DOS-like) E PER FARE LE PROVE..? • Non è necessario avere accesso a un server web situato chissà dove • È possibile installarne uno localmente, sul proprio computer – ce ne sono a decine in rete, molti gratuiti... – ...ma non tutti supportano bene le CGI! • Sul sito del corso trovate Vq Server – un web server scritto in Java (richiede Java per funzionare), molto completo, e gratuito! HTTP + CGI • Al momento, però, il programma non riceve dati di ingresso, quindi ha un output fisso! • Invece, vogliamo che il cliente (browser) possa inviare al programma opportuni dati di ingresso per guidarne l’elaborazione. Come fare? Due possibili modi: – con il sub-protocollo GET – con il sub-protocollo POST INVIO DI DATI con GET • Il cliente invia i dati appendendoli all’URL – un punto interrogativo come separatore iniziale – seguito da qualunque cosa, ma senza spazi! http://www.unibo.it/cgi-bin/xxxx?dati • il server pone tutto ciò che segue il ? nella variabile di ambiente QUERY_STRING • il programma può recuperarla con la funzione di libreria getenv() [in stdlib]: char *s = getenv("QUERY_STRING") ESEMPIO Un programma C che ristampa quello che riceve (eco): main(){ char *st = getenv("QUERY_STRING"); printf(“Content-type: text/plain\n\n”); printf(“Buongiorno %s !”, st); fflush(stdout); Ricordare il } “doppio a capo” ristampa la stringa st che ha ricevuto ESEMPIO Il browser può invocarlo ad esempio così: ristampa la stringa che ha ricevuto L’URL ha la forma: .../cgi-bin/... .../cgi/.... UNA RIFLESSIONE SULL’ESEMPIO • Certo, questo esempio è estremamente banale, perfino inutile... • ..ma dimostra che “portare un programma sul Web” è semplicissimo basta rispettare il modello di coordinazione previsto dallo standard (qui, CGI) • Anche un programma che da solo sarebbe stato di modesta utilità, portato sul Web può essere utile ad altri – diventa accessibile da tutto il mondo! I MODULI (FORM) • In pratica, nessuno si sogna di scrivere i dati nell’URL “a mano” • Tipicamente, l’utente compila un modulo grafico e preme un bottone per inviare i dati UN “FORM” scritto in HTML • Il risultato è che il cliente (browser): – prepara la stringa dati da inviare – la appende al ? nel modo previsto I MODULI (FORM) Qui si scrive il testo da inviare al programma Quando si preme il bottone, il testo viene inviato MODULI... E RISULTATI La stringa inviata ha una forma particolare: Campo=Valore Riscrive esattamente la stringa ricevuta RISULTATI... E MODULI Questo campo di testo si chiamava testo Il testo scritto era PaolinoPaperino Perciò, la stringa inviata è stata testo=PaolinoPaperino IL MODULO (HTML) <TITLE> Esempio di form </TITLE> <H1> Esempio di form </H1> Protocollo GET <FORM METHOD="GET" ACTION="http://localhost/cgi/enrico /prova0.exe" > Azione da compieInserisci il testo: re quando si preme <INPUT NAME="testo"> il pulsante invio e poi premi invio: <INPUT TYPE="submit" VALUE="invio"> </FORM> IL MODULO (HTML) <TITLE> Esempio di form </TITLE> <H1> Esempio di form </H1> <FORM METHOD="GET" Il campo di testo ACTION="http://localhost/cgi/enrico Il pulsante che (di nome testo) /prova0.exe" > attiva l’azione (tipo submit), chiamato Inserisci il testo: <INPUT NAME="testo"> invio nel modulo e poi premi invio: <INPUT TYPE="submit" VALUE="invio"> </FORM> INVIO DI DATI CON I MODULI • Dunque, quando si compila un modulo, la stringa inviata al programma (con GET) ha sempre la forma standard seguente: ...?nome1=valore1&nome2=valore2&... dove – nome1, nome2, ... sono i nomi dei campi (di testo, di selezione,...) – valore1, valore2, ... sono i testi effettivamente scritti nei rispettivi campi UN MODULO PIÙ COMPLESSO Due campi di testo, denominati rispettivamente Nome e Cognome Due pulsanti, chiamati conferma e annulla (il primo invia, il secondo cancella il modulo) IL RISULTATO La stringa inviata ha la forma standard Nome=Paolino&Cognome=Paperino IL MODULO PIÙ COMPLESSO (HTML) <H1> Esempio di form </H1> Un diverso programma <FORM METHOD="GET" ACTION="http://localhost/cgi/prova1.exe" > Inserire i seguenti dati:<p> Inserire il nome: <INPUT NAME="Nome"><br> Inserire il cognome: <INPUT NAME="Cognome"> <p> i due campi di testo <INPUT TYPE="submit" VALUE="conferma"> <INPUT TYPE="reset" VALUE="annulla"> </FORM> i due pulsanti (il tipo submit invia, il tipo reset cancella il modulo) IL PROGRAMMA Il programma riceve una stringa in forma standard e deve estrarre i vari pezzi main(){ char cognome[80], nome[80], *st; printf("Content-type: text/plain\n\n"); st = getenv("QUERY_STRING"); estrai(st, "Nome", nome); estrai(st, "Cognome", cognome); printf("Buongiorno %s %s!\n\n", nome, cognome); I nomi dei campi di testo del modulo } (attenzione: devono essere identici!) IL PROGRAMMA La funzione estrai(char*, char*, char*) int estrai(char s[], char parametro[], char valore[]) { const char separatore = '&'; char *fine, *pos = strstr(s,parametro); if (pos==NULL) return 1; /* non c’è */ pos += strlen(parametro)+1; fine = strchr(pos,separatore); if (fine==NULL) fine = pos + strlen(pos); strncpy(valore,pos,fine-pos); valore[fine-pos]='\0'; return 0; } IL PROGRAMMA La funzione estrai(char*, char*, char*) int estrai(char s[], char parametro[], char valore[]) { parametro=valore const char separatore = '&'; ci si *fine, posiziona*pos dopo = l’= strstr(s,parametro); parametro=valore& char if (pos==NULL) return 1;si cerca /* non c’è (se */ c’è) l’& finale pos += strlen(parametro)+1; fine = strchr(pos,separatore); if (fine==NULL) fine = pos + strlen(pos); strncpy(valore,pos,fine-pos); valore[fine-pos]='\0'; finalmente0;si ricopia in se l’& finale non c’è, si return valore il pezzo che serve prende fino a fine stringa } Da GET a POST • Finora, per inviare dati al programma CGI abbiamo sfruttato il sub-protocollo GET – Pro: è semplice, è facile da gestire – Contro: è inadatto a inviare molti dati (la variabile QUERY_STRING ha limiti di lunghezza) • Questi limiti si superano con il sub-protocollo POST – i dati sono inviati sullo standard input del programma – richiede obbligatoriamente un modulo (form) per inviare i dati (non si possono appendere all’URL) INVIO DI DATI con POST • È indispensabile usare un modulo (form) • Quando si preme il pulsante di invio, il browser invia i dati al server... • .. che li ridirige sul canale d’input standard del programma – i dati si possono quindi recuperare con normali letture da input – non si passa più dalle variabili di ambiente del sistema operativo, quindi non ci sono limiti di dimensione INVIO DI DATI con POST Quale formato usa POST per inviare i dati? • di norma, usa lo stesso formato di GET: nome1=valore1&nome2=valore2&... • Se però si specifica un particolare tipo di codifica (enctype), il browser usa quello • Ad esempio, con enctype="multipart/form-data” il browser invia i dati su righe separate, uno per riga, separati da righe speciali e righe vuote. LO STESSO MODULO DI POCO FA Due campi di testo, denominati rispettivamente Nome e Cognome Due pulsanti, chiamati conferma e annulla (il primo invia, il secondo cancella il modulo) ...CHE USA POST (CASO BASE) <H1> Esempio di form </H1> Un terzo programma <FORM METHOD="POST" ACTION="http://localhost/cgi/prova2.exe" > Inserire i seguenti dati:<p> Inserire il nome: <INPUT NAME="Nome"><br> Inserire il cognome: <INPUT NAME="Cognome"> <p> <INPUT TYPE="submit" VALUE="conferma"> <INPUT TYPE="reset" VALUE="annulla"> </FORM> IL PROGRAMMA Il programma fa l’eco di tutto ciò che riceve: main(){ char buf[1024]; printf("Content-type: text/plain\n\n"); printf("Risposta:\n\n"); while(gets(buf)) printf("%s\n", buf); } Ipotesi: righe non più lunghe di 1024 caratteri IL RISULTATO (NEL CASO BASE) Niente più dati appesi all’URL La stringa inviata ha la forma standard Nome=Paolino&Cognome=Paperino IL POST “multipart/form-data” <H1> Esempio di form </H1> Lo stesso programma <FORM METHOD="POST" ACTION="http://localhost/cgi/prova2.exe" enctype="multipart/form-data" > Inserire i seguenti dati:<p> Una diversa codifica Inserire il nome: <INPUT NAME="Nome"><br> Inserire il cognome: <INPUT NAME="Cognome"> <p> <INPUT TYPE="submit" VALUE="conferma"> <INPUT TYPE="reset" VALUE="annulla"> </FORM> ... E IL DIVERSO RISULTATO I dati sono inviati uno per riga, separati da righe speciali e da una riga vuota IL CODICE FISCALE.. SUL WEB!! Ricordate l’esercizio sul codice fiscale? • una delle varianti prevedeva proprio il formato di dati tipico di GET e POST (caso base) • adottando tale formato di input, il programma può essere “portato sul Web” senza sforzo... • ...e immediatamente un servizio importante risulta disponibile a tutti!