Skip to content

Commit

Permalink
added experimental local_address attribute to Mojo::UserAgent
Browse files Browse the repository at this point in the history
  • Loading branch information
kraih committed Dec 20, 2011
1 parent 164a30d commit f396164
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 17 deletions.
3 changes: 3 additions & 0 deletions Changes
@@ -1,6 +1,9 @@
This file documents the revision history for Perl extension Mojolicious.

2.39 2011-12-20 00:00:00
- Added EXPERIMENTAL local_address attribute to Mojo::UserAgent.
- Added EXPERIMENTAL local_address option to
Mojo::IOLoop::Client->connect.
- Added EXPERIMENTAL close method to Mojo::IOLoop::Stream.
- Added "hello.pl" and "fast.pl" to example scripts.
- Improved documentation. (marcus, vervain, sri)
Expand Down
6 changes: 6 additions & 0 deletions lib/Mojo/IOLoop/Client.pm
Expand Up @@ -60,6 +60,7 @@ sub _connect {
PeerPort => $args->{port} || ($args->{tls} ? 443 : 80),
Proto => 'tcp'
);
$options{LocalAddr} = $args->{local_address} if $args->{local_address};
$options{PeerAddr} =~ s/[\[\]]//g if $options{PeerAddr};
my $class = IPV6 ? 'IO::Socket::IP' : 'IO::Socket::INET';
return $self->emit_safe(error => "Couldn't connect.")
Expand Down Expand Up @@ -228,6 +229,11 @@ Address or host name of the peer to connect to.
Use an already prepared handle.
=item C<local_address>
Local address to bind to. Note that this option is EXPERIMENTAL and might
change without warning!
=item C<port>
Port to connect to.
Expand Down
4 changes: 2 additions & 2 deletions lib/Mojo/Server/Daemon.pm
Expand Up @@ -21,7 +21,7 @@ has max_clients => 1000;
has max_requests => 25;
has websocket_timeout => 300;

my $SOCKET_RE = qr|
my $LISTEN_RE = qr|
^
(http(?:s)?)\:// # Scheme
(.+) # Address
Expand Down Expand Up @@ -192,7 +192,7 @@ sub _listen {
return unless $listen;

# Check listen value
croak qq/Invalid listen value "$listen"/ unless $listen =~ $SOCKET_RE;
croak qq/Invalid listen value "$listen"/ unless $listen =~ $LISTEN_RE;
my $options = {};
my $tls;
$tls = $options->{tls} = 1 if $1 eq 'https';
Expand Down
25 changes: 17 additions & 8 deletions lib/Mojo/UserAgent.pm
Expand Up @@ -17,7 +17,7 @@ use constant DEBUG => $ENV{MOJO_USERAGENT_DEBUG} || 0;
has cert => sub { $ENV{MOJO_CERT_FILE} };
has connect_timeout => 3;
has cookie_jar => sub { Mojo::CookieJar->new };
has [qw/http_proxy https_proxy no_proxy/];
has [qw/http_proxy https_proxy local_address no_proxy/];
has ioloop => sub { Mojo::IOLoop->new };
has keep_alive_timeout => 20;
has key => sub { $ENV{MOJO_KEY_FILE} };
Expand Down Expand Up @@ -215,13 +215,14 @@ sub _connect {
warn "NEW CONNECTION ($scheme:$host:$port)\n" if DEBUG;
weaken $self;
$id = $self->_loop->client(
address => $host,
port => $port,
handle => $id,
timeout => $self->connect_timeout,
tls => $scheme eq 'https' ? 1 : 0,
tls_cert => $self->cert,
tls_key => $self->key,
address => $host,
port => $port,
handle => $id,
local_address => $self->local_address,
timeout => $self->connect_timeout,
tls => $scheme eq 'https' ? 1 : 0,
tls_cert => $self->cert,
tls_key => $self->key,
sub {
my ($loop, $err, $stream) = @_;

Expand Down Expand Up @@ -715,6 +716,14 @@ dropped, defaults to C<20>.
Path to TLS key file, defaults to the value of the C<MOJO_KEY_FILE>
environment variable.
=head2 C<local_address>
my $address = $ua->local_address;
$ua = $ua->local_address('127.0.0.1');
Local address to bind to. Note that this attribute is EXPERIMENTAL and might
change without warning!
=head2 C<log>
my $log = $ua->log;
Expand Down
2 changes: 1 addition & 1 deletion lib/Mojo/UserAgent/Transactor.pm
Expand Up @@ -373,7 +373,7 @@ Versatile general purpose L<Mojo::Transaction::HTTP> builder for requests.
# Custom socket
my $tx = $t->tx(GET => 'http://mojolicio.us');
$tx->connection($socket);
$tx->connection($sock);
$ua->start($tx);
=head2 C<websocket>
Expand Down
27 changes: 26 additions & 1 deletion t/mojo/user_agent_online.t
Expand Up @@ -10,16 +10,24 @@ use Test::More;

plan skip_all => 'set TEST_ONLINE to enable this test (developer only!)'
unless $ENV{TEST_ONLINE};
plan tests => 101;
plan tests => 104;

# "So then I said to the cop, "No, you're driving under the influence...
# of being a jerk"."
use IO::Socket::INET;
use Mojo::IOLoop;
use Mojo::Transaction::HTTP;
use Mojolicious::Lite;
use ojo;

use_ok 'Mojo::UserAgent';

# GET /remote_address
get '/remote_address' => sub {
my $self = shift;
$self->render(text => $self->tx->remote_address);
};

# Make sure user agents dont taint the ioloop
my $loop = Mojo::IOLoop->singleton;
my $ua = Mojo::UserAgent->new;
Expand All @@ -41,6 +49,23 @@ is $code, 301, 'right status';
# Fresh user agent
$ua = Mojo::UserAgent->new;

# Local address
$ua->app(app);
my $sock = IO::Socket::INET->new(
PeerAddr => 'mojolicio.us',
PeerPort => 80,
Proto => 'tcp'
);
my $address = $sock->sockhost;
isnt $address, '127.0.0.1', 'different address';
$ua->local_address('127.0.0.1')->max_connections(0);
is $ua->get('/remote_address')->res->body, '127.0.0.1', 'right address';
$ua->local_address($address);
is $ua->get('/remote_address')->res->body, $address, 'right address';

# Fresh user agent
$ua = Mojo::UserAgent->new;

# Connection refused
$ua->log->level('fatal');
my $tx = $ua->build_tx(GET => 'http://localhost:99999');
Expand Down
9 changes: 4 additions & 5 deletions t/mojo/websocket.t
Expand Up @@ -200,10 +200,9 @@ my $port = $ua->test_server->port;
my $tx = $ua->build_websocket_tx('ws://lalala/socket');
my $finished = 0;
$tx->on(finish => sub { $finished++ });
my $socket =
IO::Socket::INET->new(PeerAddr => '127.0.0.1', PeerPort => $port);
$socket->blocking(0);
$tx->connection($socket);
my $sock = IO::Socket::INET->new(PeerAddr => '127.0.0.1', PeerPort => $port);
$sock->blocking(0);
$tx->connection($sock);
$result = '';
my ($local, $early);
$ua->start(
Expand All @@ -227,7 +226,7 @@ is $early, 1, 'finish event has been emitted at the right time';
ok $result =~ /^lalala(\d+)$/, 'right result';
ok $1 > 100, 'right timeout';
ok $local, 'local port';
is $loop->stream($tx->connection)->handle, $socket, 'right connection id';
is $loop->stream($tx->connection)->handle, $sock, 'right connection id';

# WebSocket /early_start (server directly sends a message)
my $client_flag;
Expand Down

0 comments on commit f396164

Please sign in to comment.