ソケット通信でHTTPブラウザ

ソケット通信の勉強として、HTTPでHTMLを取得するコンソールブラウザみたいなものを、perlで作ってみました。

アプリケーション層のみの実装でいいので、かなり簡単にできてしまうんです。

次回はこれを利用して、動的IPのチェックスクリプトみたいなものを作ろうと思います。

実行は以下のように、URLを第一引数にとって実行します。

./browser.pl http://www.google.cp.jp/

実行するとHTMLのソースが標準出力されます。

ソースは以下。

#!/usr/bin/perl

use strict;
use warnings;
use Socket;
use FileHandle;

my ($host, $port, $path, $sockaddr, $http_ver, $uri);
my @URI_data;

$uri = $ARGV[0];
$http_ver = '1.1';
$host = 'localhost';
$port = getservbyname('http', 'tcp');
$path = '/';

############################
###### メインルーチン ######
############################

### URIを解析 ###
@URI_data = &URI_analy($#ARGV,$uri);
$host = @URI_data[0];
$port = @URI_data[1];
$path = @URI_data[2];

### ソケット生成 ###
$sockaddr = &socket_create($host,$port);

### ソケット通信開始 ###
&socket_connect($sockaddr);

### HTTPと通信 ###
&http_request_get($http_ver,$host.$path);

### ソケット通信終了###
close(SOCKET);



##########################
###### サブルーチン ######
##########################

### URIを解析 ###
sub URI_analy
{
    my $host, $port, $path;
    if($_[0] == 0)
    {
        die "Usage:$0 URI\n";
    }
    else
    {
        $_[1] =~ m!(http:)?(//)?([^:/]*)?(:([0-9]+)?)?(/.*)?!;

        if($3)
        {
            $host = $3;
        }

        if($5)
        {
            $port = $5;
        }

        if($6)
        {
            $path = $6;
        }
    }
    @URI_data = ($host,$port,$path);
    return @URI_data;
}

### ソケット生成 ###
sub socket_create
{
    my $ip, $sockaddr;
    local(*host, *port) = $_;
    $ip = inet_aton($host) || die "host($host) not found.\n";
    $sockaddr = pack_sockaddr_in($port, $ip);
    return $sockaddr;
}

### ソケット通信開始 ###
sub socket_connect
{
    local(*sockaddr) = $_;
    socket(SOCKET, PF_INET, SOCK_STREAM, 0) || die "Error(socket).\n";
    connect(SOCKET, $sockaddr) || die "Error(connect).\n";
    autoflush SOCKET (1);
}

### HTTPと通信 ###
sub http_request_get
{
    local(*http_ver, *host, *path) = $_;
    if($http_ver eq '1.1')
    {
        print SOCKET "GET $path HTTP/1.1\n";
        print SOCKET "Host: $host\n";
        print SOCKET "Connection: close\n\n";
    }
    else
    {
        print SOCKET "GET $path HTTP/1.0\n\n";
    }

    while(chomp($_=<SOCKET>))
    {
        print "$_\n";
    }
}