EV-WebKit
view release on metacpan or search on metacpan
What is being asked for. "scheme" is WebKit's own nick for the
authentication scheme ("http-basic", "http-digest", ...); "realm" is
the server's realm string, which is what distinguishes two
challenges from the same host.
"for_proxy"
True when the challenge came from a proxy rather than the origin
server.
"is_retry"
True when the credentials you last supplied were rejected. WebKit
re-asks after every rejection, so a handler that answers with the
same pair regardless of this loops forever.
"login($user, $password, persist => $how)"
Answer the challenge. "persist" is 'for-session' (the default --
remembered until this instance closes, so the same realm is not
asked again on every request), 'permanent' (written to the platform
credential store), or 'none'.
"cancel"
lib/EV/WebKit.pm view on Meta::CPAN
weaken(my $ws = $self);
$self->_defer(sub { my ($u) = @_; my $b = $ws or return; $b->go($u) }, $nu);
return undef; # no second view: the navigation happens in this one
});
# HTTP (and proxy) authentication. WITHOUT this connected at all, a 401
# challenge is answered by nobody: WebKit waits, the navigation resolves
# 'timeout' after the full instance timeout, and status() is undef -- so the
# caller cannot even tell a 401 from an unreachable host. Cancelling by
# default turns that into an immediate, legible failure (the server's own
# 401 body, with status 401), and a handler can supply credentials instead.
$self->{on_authenticate} = $o{on_authenticate};
$view->signal_connect(authenticate => sub {
my (undef, $req) = @_;
local $IN_DISPATCH = 1; # runs nested in WebKit's dispatch frame -- see quit
my $self = $wself or return 0; # gone: let WebKit do its default
return 0 if $self->{_dead};
my $host = eval { $req->get_host };
# However the challenge goes unanswered, record WHY: WebKit reports all
# three the same way, as a bare "Load request cancelled".
my $note = sub { $self->{_auth_challenge} = { host => $host, why => $_[0] } if defined $host };
lib/EV/WebKit.pm view on Meta::CPAN
our $VERSION = '0.04';
# A WebKitAuthenticationRequest, valid only for the duration of the
# on_authenticate handler that receives it.
sub _new { bless { r => $_[1] }, $_[0] }
sub host { eval { $_[0]{r}->get_host } }
sub port { eval { $_[0]{r}->get_port } }
sub realm { eval { $_[0]{r}->get_realm } }
sub scheme { eval { $_[0]{r}->get_scheme } }
sub for_proxy { eval { $_[0]{r}->is_for_proxy } ? 1 : 0 }
# True when the credentials just supplied were rejected. A handler that
# ignores it and answers with the same pair again is a loop, since WebKit
# re-asks after every rejection.
sub is_retry { eval { $_[0]{r}->is_retry } ? 1 : 0 }
sub login {
my ($s, $user, $pass) = (shift, shift, shift);
Carp::croak('login: a username and password are required')
if !defined $user || ref $user || !defined $pass || ref $pass;
Carp::croak('login: options must be name => value pairs') if @_ % 2;
my %o = @_;
lib/EV/WebKit.pm view on Meta::CPAN
What is being asked for. C<scheme> is WebKit's own nick for the authentication
scheme (C<http-basic>, C<http-digest>, ...); C<realm> is the server's realm
string, which is what distinguishes two challenges from the same host.
=item C<for_proxy>
True when the challenge came from a proxy rather than the origin server.
=item C<is_retry>
True when the credentials you last supplied were B<rejected>. WebKit re-asks
after every rejection, so a handler that answers with the same pair regardless
of this loops forever.
=item C<< login($user, $password, persist =E<gt> $how) >>
Answer the challenge. C<persist> is C<'for-session'> (the default -- remembered
until this instance closes, so the same realm is not asked again on every
request), C<'permanent'> (written to the platform credential store), or
C<'none'>.
t/45-auth-popup-viewport.t view on Meta::CPAN
on_authenticate => sub {
my ($a) = @_;
push @info, { host => $a->host, port => $a->port, realm => $a->realm,
scheme => $a->scheme, proxy => $a->for_proxy, retry => $a->is_retry };
$a->login('u', 'p');
});
my ($err, $title, $status);
$b->go("http://127.0.0.1:$port/secret", sub {
$err = $_[1]; $title = $b->title; $status = $b->status; EV::break });
TWK::run_with_timeout(30);
is($err, undef, 'a handler that supplies credentials lets the load through') or diag $err;
is($title, 'AUTHED', '...and the server accepted them');
is($status, 200, '...reporting a 200, not the 401');
is(scalar @info, 1, 'the handler ran once');
is($info[0]{host}, '127.0.0.1', 'host is reported');
is($info[0]{port}, $port, 'port is reported');
is($info[0]{realm}, 'probe', 'realm is reported');
is($info[0]{scheme}, 'http-basic','scheme is reported');
is($info[0]{proxy}, 0, 'for_proxy is false for an origin challenge');
is($info[0]{retry}, 0, 'is_retry is false on the first ask');
$b->quit;
}
{
# credentials in the URI are WebKit's own business and must not reach us
my $fired = 0;
my $b = EV::WebKit->new(window => [300,200], timeout => 10,
on_authenticate => sub { $fired++; $_[0]->cancel });
my ($err, $title);
$b->go("http://u:p\@127.0.0.1:$port/secret", sub { $err = $_[1]; $title = $b->title; EV::break });
TWK::run_with_timeout(30);
is($err, undef, 'credentials in the URI still work') or diag $err;
is($title, 'AUTHED', '...reaching the protected page');
is($fired, 0, '...without the handler being consulted');
$b->quit;
}
# Fail-closed, and the three unanswered routes each name themselves. Without
# the cancel these still resolve -- with 'timeout', after the full instance
# timeout -- so the elapsed time is what actually pins "failed closed".
for my $case ([die => sub { die "handler exploded\n" }, qr/handler died/],
[undecided => sub { return }, qr/answered nothing/],
[cancel => sub { $_[0]->cancel }, qr/handler cancelled it/]) {
t/61-cookies.t view on Meta::CPAN
is($err, 'timeout', "$name: uses the module's uniform 'timeout' error")
or diag("err=" . ($err // '(undef)'));
}
}
}
# save_cookies($file, \@uris, $cb): a middle argument that is not an arrayref
# was never looked at again, so save_cookies($file, 'https://one.example/', $cb)
# reported SUCCESS having snapshotted every uri the instance had visited --
# the opposite scope from the one asked for, into a file that holds
# credentials. cookies($uri, $cb), the sibling, takes a bare string, which is
# exactly where that spelling comes from.
{
require File::Temp;
my $sc = EV::WebKit->new(window => [200,150], ephemeral => 1, timeout => 10);
$sc->mock_scheme('sc', sub { ('<p>x</p>', 'text/html') });
my $ready = 0;
$sc->go('sc://a', sub { $ready = 1; EV::break });
TWK::run_with_timeout(20);
ok($ready, 'premise: the instance has navigated somewhere');
( run in 0.964 second using v1.01-cache-2.11-cpan-007c89162af )