#!/usr/bin/perl -W

# TP protocole HTTP
#
# Question 2
#
# Antoine Miné
# 20/04/2007

use Socket;      # pour avoir l'équivalent Perl de socket.h
use IO::Handle;  # pour avoir autoflush


$url = $ARGV[0] or die "utilisation: $0 URL";

# format d'une URL: protocole://serveur:port/page (cf. RFC 2396)
# le port est optionnel
# cette expression gère adresses textes et IPv4, mais pas IPv6 (cf. RFC 2732)
($protocole, $serveur, undef, $port, $page) =
    $url =~ /^([a-z]+):\/\/([a-z0-9.-]+)(:(\d*))?(\/.*)$/;

# port 80 par défaut
$port = 80 if ! defined $port;

# vérification de l'URL
die "URL mal formée $url" unless 
    defined $protocole && defined $serveur && 
    defined $port      && defined $page;
die "protocole $protocole inconnu" unless $protocole eq "http";

# détermination de l'adresse IP du serveur
$ip_serveur = gethostbyname($serveur) ||
    die "IP du serveur $serveur introuvable";

# transformation au format interne utilisable par connect
$addr_sin = sockaddr_in($port, $ip_serveur);

# création d'une socket TCP/IP
socket(SOCKET, PF_INET, SOCK_STREAM, 0) || die "échec de socket: $!";

# le tampon de SOCKET sera vidé après chaque appel à print
autoflush SOCKET 1;

# connection au serveur
connect(SOCKET, $addr_sin) || die "échec de connect: $!";

# envoie d'une requête HTTP (cf. RFC 2616)
print SOCKET "GET $page HTTP/1.1\r\n";
print SOCKET "Host: $serveur:port\r\n";
print SOCKET "User-Agent: httpget\r\n";
print SOCKET "Connection: close\r\n";
print SOCKET "\r\n";

# lit et vérifie le statu de la réponse
$statu = <SOCKET>;
($code, $texte) = $statu =~ /^HTTP\/[0-9.]+ (\d+) ([^\n\r]*)/;
die "erreur $code $texte" unless $code == 200;

# saute les en-têtes de la réponse
while (<SOCKET>) {
    last if $_ eq "\r\n";
}

# copie la page sur la sortie standard
while (<SOCKET>) {
    print "$_";
}
