Xpoint
   [напомнить пароль]

Использование Socks при работе с LWP

Иногда при использовании тех или иных сетевых приложений необходимо их настраивать для работы с Socks-прокси.

В случае, если ваше приложение написано на Perl и использует LWP, это становится достаточно сложной задачей (обсуждение этой проблемы можно увидеть в теме Как заставить LWP работать через Socks proxy)

Одним из вариантов является использование собственного модуля, реализующего протокол HTTP. Для этого необходимо, перед тем как будет послан HTTP-запрос, сконфигурировать LWP следующим образом:

LWP::Protocol::implementor('http', 'имя модуля');

По аналогии с модулем LWP::Protocol::http::SocketUnix был создан модуль LWP::Protocol::http::SocksBalancer (еще не зарегистрирован в CPAN).

Перед использованием модуль необходимо сконфигурировать, задав набор прокси-серверов через которые он может соединяться.

TODO: вписать пример использования.

package  LWP::Protocol::http::SocksBalancer;

use strict;
use warnings;
use vars qw( @ISA $VERSION );
use IO::Socket::Socks;
use LWP::Protocol::http;

@ISA = qw( LWP::Protocol::http );

$VERSION = 0.01;

# User must provide a list of proxies before he works with this module
our $SOCKS_SERVERS = [];

# User can change this to more then one.
# In this case getSocket() will call itself trying to get new random connection as many times as you specify.
our $MAX_CONNECT_ATTEMPTS = 1;

# Not sure if changing this to 1 will work as you might think it will - never tested.
our $DEBUG = 0;

sub _new_socket
{
    my($self, $host, $port, $timeout) = @_;
    my $conn_cache = $self->{ua}{conn_cache};
    if ($conn_cache) {
   if (my $sock = $conn_cache->withdraw("http", "$host:$port")) {
       return $sock if $sock && !$sock->can_read(0);
       # if the socket is readable, then either the peer has closed the
       # connection or there are some garbage bytes on it.  In either
       # case we abandon it.
       $sock->close;
   }
    }

    local($^W) = 0;  # IO::Socket::INET can be noisy

    my $sock = $self->getSocket($host, $port);

    unless ($sock) {
   # IO::Socket::INET leaves additional error messages in $@
   die "Can't connect to $host:$port ($@)";
    }

    # perl 5.005's IO::Socket does not have the blocking method.
    eval { $sock->blocking(0); };

    $sock;
}

sub getSocket
{
   my($self, $host, $port, $level) = @_;

   my $number_of_proxies = scalar(@{$SOCKS_SERVERS});
   die "[Configuration Error] You must specify a list of proxies" if $number_of_proxies < 1;

   my $proxy = @{$SOCKS_SERVERS}[rand($number_of_proxies)];

   if ($DEBUG)
   {
      die "Host: ".$proxy->{host}."\nPort: ".$proxy->{port}."\nUsername: ".$proxy->{username}."\nPass: ".$proxy->{pass};
   }

   if (!defined($level))
   {
      $level = 0;
   }

   my $socket = $self->socket_class->new(
                   ProxyAddr=>$proxy->{host},
               ProxyPort=>$proxy->{port},

               AuthType=>'userpass',
               Username=>$proxy->{username},
               Password=>$proxy->{pass},

               ConnectAddr=>$host,
               ConnectPort=>$port,

               SocksDebug => $DEBUG
            );

   if (!$socket && ($level < $MAX_CONNECT_ATTEMPTS)) {
      $socket = $self->getSocket($host, $port, $level + 1);
   }
            
   return $socket;
}

#-----------------------------------------------------------
package LWP::Protocol::http::SocksBalancer::Socket;

use strict;
use warnings;
use vars qw( @ISA );

@ISA = qw(LWP::Protocol::http::SocketMethods Net::HTTP::Methods IO::Socket::Socks);

sub configure {
   my ($self, $cnf) = @_;
   $self->http_configure($cnf);
}

sub http_connect {
   my ($self, $cnf) = @_;
   $self->SUPER::configure($cnf);
}

1;
Powered by POEM™ Engine Copyright © 2002-2005