Lectura obligatorie
HTTP Made Really Easy
Hypertext Transfer Protocol
HTTP cookie
How the web works: HTTP and CGI explained
Cerinte
In cadrul acestui laborator studentii nu vor avea de implementat nimic 🙂 (a se vedea totusi observatiile de la exemplele 7 si 8), dar vor trebuie sa parcurga lectura obligatorie de mai sus. De asemenea, vor parcurge exemplele de mai jos, le vor face functionale si le vor rula pe laptopul personal sau in contul personal de pe serverul linux.scs.ubbcluj.ro, le vor intelege si vor trebui sa explice functionarea acestora. In saptamana 6 este posibila primirea unui test in vederea evaluarii cunostintelor prezentate la curs si in cadrul resurselor bibliografice de mai sus.
Exemplul 1
Fisierul demo.c
, se va compila ca demo.cgi
.
1 2 3 4 5 6 7 |
#include <stdio.h> int main() { printf("Content-type: text/html\n"); printf("\n"); printf("Hello world!"); } |
Exemplul 2
Fisierul contor.cgi
. I se vor atribui drepturi de executie pentru serverul web (o+x).
1 2 3 4 5 6 7 |
#!/bin/bash echo "Content-type: text/html" echo n=`cat contor.txt` n=`expr $n + 1` echo $n > contor.txt echo $n |
Exemplul 3 – Incapsularea parametrilor trimisi din browser prin GET
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<!DOCTYPE html> <html> <head> <title>Query String Demo</title> </head> <body> <form method="GET" action="show_input_data.cgi"> <input type="text" name="nume" placeholder="Nume"><br> <input type="text" name="telefon" placeholder="Telefon"><br> <input type="text" name="varsta" placeholder="Varsta"><br> <input type="submit" value="Trimite"> </form> </body> </html> |
Fisierul show_input_data.c
, se va compila ca show_input_data.cgi
1 2 3 4 5 6 7 |
#include <stdio.h> #include <stdlib.h> int main() { printf("Content-type: text/html\n\n"); printf("Am primit de la browser query string-ul %s", getenv("QUERY_STRING")); } |
In locul variantei de mai sus scrise in C, se poate folosi varianta scrisa ca shell Unix:
1 2 3 4 |
#!/bin/bash echo "Content-type: text/html" echo echo Am primit de la browser query string-ul $QUERY_STRING |
Exemplul 4 – Incapsularea parametrilor trimisi din browser prin POST
Acelasi exemplu ca exemplul 3, dar datele sunt trimise prin POST.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<!DOCTYPE html> <html> <head> <title>Demo submit prin POST</title> </head> <body> <form method="POST" action="show_input_data.cgi"> <input type="text" name="nume" placeholder="Nume"><br> <input type="text" name="telefon" placeholder="Telefon"><br> <input type="text" name="varsta" placeholder="Varsta"><br> <input type="submit" value="Trimite"> </form> </body> </html> |
Fisierul show_input_data.c
, se va compila ca show_input_data.cgi
1 2 3 4 5 6 7 8 9 |
#include <stdio.h> #include <stdio.h> int main() { char line[1000]; printf("Content-type: text/html\n\n"); fgets(line, 1000, stdin); printf("Am primit de la browser %s", line); } |
Exemplul 5 – Incapsularea continutului unui fisier prin POST
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<!DOCTYPE html> <html> <head> <title>Formular input file</title> </head> <body> <form method="POST" action="show_input_data.cgi" enctype="multipart/form-data"> <input type="text" name="dummy1" placeholder="Dummy 1"><br> <input type="file" name="fisier"><br> <input type="text" name="dummy2" placeholder="Dummy 2"><br> <input type="submit" value="Trimite"> </form> </body> </html> |
Fisierul show_input_data.c
, se va compila ca show_input_data.cgi
1 2 3 4 5 6 7 8 9 10 11 |
#include <stdio.h> int main() { char line[1000]; printf("Content-type: text/html\n\n"); while (! feof(stdin)) { fgets(line, 1000, stdin); if (! feof(stdin)) printf("%s<br/>", line); } } |
Exemplul 6 – Afisarea antetelor din cadrul cererii HTTP
Intrebare: Unde puteti gasi si cum puteti vizualiza codul sursa al exemplului 6 de mai sus?
Raspuns: Ar trebui sa stiti pana in acest moment pe baza cunostintelor dobandite :).
Exemplul 7 – URL Decoding
Fisierul decodeURL.c
, se va compila ca decodeURL.cgi
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
#include <stdio.h> #include <string.h> int hexatoint(char c) { if ((c>='a') && (c<='f')) return c - 'a' + 10; if ((c>='A') && (c<='F')) return c - 'A' + 10; return c - '0'; } void decode(char *s) { int i = 0, j; while (s[i] != 0) { if (s[i] == '+') s[i] = ' '; if (s[i] == '%') { char c = 16 * hexatoint(s[i+1]) + hexatoint(s[i+2]); s[i] = c; j = i + 1; do { s[j] = s[j + 2]; j++; } while (s[j] != 0); } i++; } } int main() { char s[] = "http%3A%2F%2Fwww.cs.ubbcluj.ro%2F%7Ebufny%2Fprogramare%2Dweb%2F"; printf("Content-type: text/html\n\n"); printf("Original string: %s<br>\n", s); decode(s); printf("Decoded string: %s", s); } |
Cerinta facultativa pentru extra puncte la laborator: Modificati exemplul de mai sus astfel incat sirul care trebuie decodificat sa fie trimis serverului prin intermediul unui formular.
Exemplul 8 – Managementul sesiunii si caracterul stateless al protocolului HTTP
Fisierul play.c
, se va compila ca play.cgi
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> struct data { int nr; int tries; }; int getIdFromQueryString() { char buffer[2048]; int id; strcpy(buffer, getenv("QUERY_STRING")); sscanf(buffer, "id=%d&", &id); return id; } int getNumberFromQueryString() { char buffer[2048]; int id, nr; strcpy(buffer, getenv("QUERY_STRING")); sscanf(buffer, "id=%d&nr=%d", &id, &nr); return nr; } int init() { int r, id; int code; char filename[100]; struct data d; srand(getpid()); r = random() % 100; do { id = random(); sprintf(filename, "/tmp/%d.txt", id); code = creat(filename, O_CREAT | O_EXCL | 0600); } while (code < 0); d.nr = r; d.tries = 0; write(code, &d, sizeof(d)); close(code); return id; } void destroy(int id) { char filename[100]; sprintf(filename, "/tmp/%d.txt", id); unlink(filename); } int getNumberFromFile(int id) { char filename[100]; int fd; sprintf(filename, "/tmp/%d.txt", id); struct data d; fd = open(filename, O_RDWR); if (fd < 0) return -1; read(fd, &d, sizeof(d)); d.tries++; lseek(fd, 0, SEEK_SET); write(fd, &d, sizeof(d)); close(fd); return d.nr; } int getNoOfTries(int id) { char filename[100]; int fd; sprintf(filename, "/tmp/%d.txt", id); struct data d; fd = open(filename, O_RDONLY); read(fd, &d, sizeof(d)); close(fd); return d.tries; } int isNewUser() { if (getenv("QUERY_STRING") == NULL) return 1; if (strcmp(getenv("QUERY_STRING"), "") == 0) return 1; return 0; } void printForm(int id) { printf("<form action='play.cgi' method='get'>\n"); printf("<input type='hidden' name='id' value='%d'>\n", id); printf("Nr: <input type='text' name='nr'><br>\n"); printf("<input type='submit' value='Trimite'>\n"); printf("</form>");; } int main() { int id, status; if (isNewUser()) { id = init(); status = 0; } else { int nr, nr2; id = getIdFromQueryString(); nr = getNumberFromQueryString(); nr2 = getNumberFromFile(id); if (nr2 == -1) status = 1; else if (nr == nr2) status = 2; else if (nr < nr2) status = 3; else if (nr > nr2) status = 4; } printf("Content-type: text/html\n\n"); printf("<html>\n<body>\n"); switch (status) { case 0 : printf("Ati inceput un joc nou.<br>\n"); printForm(id); break; case 1 : printf("Eroare. Click <a href='play.cgi'>here</a> for a new game!"); break; case 2 : printf("Ati ghicit din %d incercari. Click <a href='play.cgi'>here</a> for a new game!</body></html>", getNoOfTries(id)); destroy(id); break; case 3 : printf("Prea mic!<br>\n"); printForm(id); break; case 4 : printf("Prea mare!<br>\n"); printForm(id); } printf("</body>\n</html>"); } |
Cerinta facultativa pentru extra puncte la laborator: Modificati exemplul de mai sus astfel incat managementul sesiunii sa nu se faca prin intermediul unui input de tip hidden ci prin intermediului unui cookie.
Tutorial pentru a va instala serverul web Apache pe Windows (veti avea nevoie la urmatoarele laboratoare de el, inclusiv la laboratoarele de AJAX, PHP, etc) si de a va “juca” cu protocolul HTTP si exemplele de la acest laborator pe Windows:
- Cautati, download-ati si instalati xampp
- Porniti xampp si din fereastra de control al xampp porniti serverul web Apache. Ar trebui sa vedeti ca acesta ocupa porturile 80 si 443
- Verificati ca functioneaza http://localhost sau https://localhost
- Localizati DocumentRoot-ul serverului web (directorul implicit din care serverul web serveste documente si care corespunde URL-ului http://localhost). Acest folder implicit este c:\xampp\htdocs\, dar poate fi si altul setat cu ajutorul directivei DocumentRoot in cadrul fisierului de configurare httpd.conf al serverului web.
- In orice subfolder din cadrul folderului specificat ca si DocumentRoot, puteti plasa fisiere CGI care trebuie sa fie executabile din perspectiva sistemului de operare (pe sistemul de operare Windows sunt fisiere executabile fisierele cu extensia .com, .exe, .bat)
- ditati fiserului de configurare al serverului web httpd.conf pentru a specifica extensii de fisiere aditionale care sa se comporte ca fisiere CGI (serverul web sa trimita clintului output-ul rezultat in urma executiei acestor fisiere si NU continutul propriu-zis al fisierelor). Pentru aceasta directiva AddHandler din cadrul fiserului de configurare httpd.conf al serverului web ar trebui sa arate in forma urmatoare:
1AddHandler cgi-script .cgi .pl .asp .bat .exe - Restartati serverul web.
Fisier-ul de test pe Windows demo.bat:
1 2 3 4 |
@echo off echo Content-type: text/html echo. echo Hello World! |