[liblwp-protocol-https-perl] 01/04: added patch to fix https_proxy (Closes: #129528, #622212)
dod at debian.org
dod at debian.org
Sat Nov 30 17:06:26 UTC 2013
This is an automated email from the git hooks/post-receive script.
dod pushed a commit to branch master
in repository liblwp-protocol-https-perl.
commit e6b4047fec38d172e60a68d0af3c68ecb6f3f29c
Author: Dominique Dumont <dod at debian.org>
Date: Wed Nov 27 16:38:06 2013 +0100
added patch to fix https_proxy (Closes: #129528, #622212)
---
debian/patches/fix-https-proxy | 361 +++++++++++++++++++++++++++++++++++++++++
debian/patches/series | 1 +
2 files changed, 362 insertions(+)
diff --git a/debian/patches/fix-https-proxy b/debian/patches/fix-https-proxy
new file mode 100644
index 0000000..533fa8c
--- /dev/null
+++ b/debian/patches/fix-https-proxy
@@ -0,0 +1,361 @@
+Description:Fix https proxy
+ part 2 of https-proxy fix
+Author: Steffen Ullrich
+From:https://github.com/libwww-perl/lwp-protocol-https/pull/7
+Applied-Upstream:yes
+--- a/MANIFEST
++++ b/MANIFEST
+@@ -4,5 +4,6 @@
+ README
+ lib/LWP/Protocol/https.pm Access with HTTP/1.1 protocol over SSL
+ t/apache.t
++t/https_proxy.t
+ META.yml Module YAML meta-data (added by MakeMaker)
+ META.json Module JSON meta-data (added by MakeMaker)
+--- a/lib/LWP/Protocol/https.pm
++++ b/lib/LWP/Protocol/https.pm
+@@ -5,6 +5,7 @@
+
+ require LWP::Protocol::http;
+ our @ISA = qw(LWP::Protocol::http);
++require Net::HTTPS;
+
+ sub socket_type
+ {
+@@ -83,10 +84,24 @@
+ $res->header("Client-SSL-Socket-Class" => $Net::HTTPS::SSL_SOCKET_CLASS);
+ }
+
++# upgrade plain socket to SSL, used for CONNECT tunnel when proxying https
++# will only work if the underlying socket class of Net::HTTPS is
++# IO::Socket::SSL, but code will only be called in this case
++if ( $Net::HTTPS::SSL_SOCKET_CLASS->can('start_SSL')) {
++ *_upgrade_sock = sub {
++ my ($self,$sock,$url) = @_;
++ $sock = LWP::Protocol::https::Socket->start_SSL( $sock,
++ SSL_verifycn_name => $url->host,
++ $self->_extra_sock_opts,
++ );
++ $@ = LWP::Protocol::https::Socket->errstr if ! $sock;
++ return $sock;
++ }
++}
++
+ #-----------------------------------------------------------
+ package LWP::Protocol::https::Socket;
+
+-require Net::HTTPS;
+ our @ISA = qw(Net::HTTPS LWP::Protocol::http::SocketMethods);
+
+ 1;
+--- /dev/null
++++ b/t/https_proxy.t
+@@ -0,0 +1,308 @@
++#!/usr/bin/perl
++
++# to run test with Net::SSL as backend set environment
++# PERL_NET_HTTPS_SSL_SOCKET_CLASS=Net::SSL
++
++use strict;
++use warnings;
++use Test::More;
++use File::Temp 'tempfile';
++use IO::Socket::INET;
++use IO::Select;
++use Socket 'MSG_PEEK';
++use LWP::UserAgent;
++use LWP::Protocol::https;
++
++plan skip_all => "fork not implemented on this platform" if
++ grep { $^O =~m{$_} } qw( MacOS VOS vmesa riscos amigaos );
++
++eval { require IO::Socket::SSL }
++ and $IO::Socket::SSL::VERSION >= 1.953
++ and eval { require IO::Socket::SSL::Utils }
++ or plan skip_all => "no recent version of IO::Socket::SSL::Utils";
++IO::Socket::SSL::Utils->import;
++
++# create CA -------------------------------------------------------------
++my ($cacert,$cakey) = CERT_create( CA => 1 );
++my $cafile = do {
++ my ($fh,$fname) = tempfile( CLEANUP => 1 );
++ print $fh PEM_cert2string($cacert);
++ $fname
++};
++
++# create two web servers ------------------------------------------------
++my (@server, at saddr);
++for my $i (0,1) {
++ my $server = IO::Socket::INET->new(
++ LocalAddr => '127.0.0.1',
++ LocalPort => 0, # let system pick port
++ Listen => 10
++ ) or die "failed to create INET listener";
++ my $saddr = $server->sockhost.':'.$server->sockport;
++ $server[$i] = $server;
++ $saddr[$i] = $saddr;
++}
++
++my @childs;
++END { kill 9, at childs if @childs };
++defined( my $pid = fork()) or die "fork failed: $!";
++
++# child process runs _server and exits
++if ( ! $pid ) {
++ @childs = ();
++ exit( _server());
++}
++
++# parent continues with closed server sockets
++push @childs,$pid;
++ at server = ();
++
++# check which SSL implementation Net::HTTPS uses
++# Net::SSL behaves different than the default IO::Socket::SSL
++my $netssl = $Net::HTTPS::SSL_SOCKET_CLASS eq 'Net::SSL';
++
++# do some tests ----------------------------------------------------------
++my %ua;
++$ua{noproxy} = LWP::UserAgent->new(
++ keep_alive => 10, # size of connection cache
++ # server does not know the expected name and returns generic certificate
++ ssl_opts => { verify_hostname => 0 }
++);
++
++$ua{proxy} = LWP::UserAgent->new(
++ keep_alive => 10, # size of connection cache
++ ssl_opts => {
++ # Net::SSL cannot verify hostnames :(
++ verify_hostname => $netssl ? 0: 1,
++ SSL_ca_file => $cafile
++ }
++);
++$ua{proxy_nokeepalive} = LWP::UserAgent->new(
++ keep_alive => 0,
++ ssl_opts => {
++ # Net::SSL cannot verify hostnames :(
++ verify_hostname => $netssl ? 0: 1,
++ SSL_ca_file => $cafile
++ }
++);
++$ENV{http_proxy} = $ENV{https_proxy} = "http://foo:bar\@$saddr[0]";
++$ua{proxy}->env_proxy;
++$ua{proxy_nokeepalive}->env_proxy;
++if ($netssl) {
++ # Net::SSL cannot get user/pass from proxy url
++ $ENV{HTTPS_PROXY_USERNAME} = 'foo';
++ $ENV{HTTPS_PROXY_PASSWORD} = 'bar';
++}
++
++my @tests = (
++ # the expected ids are connid.reqid[tunnel_auth][req_auth]@sslhost
++ # because we run different sets of test depending on the SSL class
++ # used by Net::HTTPS we replace connid with a letter and later
++ # match it to a number
++
++ # keep-alive for non-proxy http
++ # requests to same target use same connection, even if intermixed
++ [ 'noproxy', "http://$saddr[0]/foo",'A.1 at nossl' ],
++ [ 'noproxy', "http://$saddr[0]/bar",'A.2 at nossl' ], # reuse conn#1
++ [ 'noproxy', "http://$saddr[1]/foo",'B.1 at nossl' ],
++ [ 'noproxy', "http://$saddr[1]/bar",'B.2 at nossl' ], # reuse conn#2
++ [ 'noproxy', "http://$saddr[0]/tor",'A.3 at nossl' ], # reuse conn#1 again
++ [ 'noproxy', "http://$saddr[1]/tor",'B.3 at nossl' ], # reuse conn#2 again
++ # keep-alive for proxy http
++ # use the same proxy connection for all even if the target host differs
++ [ 'proxy', "http://foo/foo",'C.1.auth at nossl' ],
++ [ 'proxy', "http://foo/bar",'C.2.auth at nossl' ],
++ [ 'proxy', "http://bar/foo",'C.3.auth at nossl' ],
++ [ 'proxy', "http://bar/bar",'C.4.auth at nossl' ],
++ [ 'proxy', "http://foo/tor",'C.5.auth at nossl' ],
++ [ 'proxy', "http://bar/tor",'C.6.auth at nossl' ],
++ # keep-alive for non-proxy https
++ # requests to same target use same connection, even if intermixed
++ [ 'noproxy', "https://$saddr[0]/foo",'D.1 at direct.ssl.access' ],
++ [ 'noproxy', "https://$saddr[0]/bar",'D.2 at direct.ssl.access' ],
++ [ 'noproxy', "https://$saddr[1]/foo",'E.1 at direct.ssl.access' ],
++ [ 'noproxy', "https://$saddr[1]/bar",'E.2 at direct.ssl.access' ],
++ [ 'noproxy', "https://$saddr[0]/tor",'D.3 at direct.ssl.access' ],
++ [ 'noproxy', "https://$saddr[1]/tor",'E.3 at direct.ssl.access' ],
++ # keep-alive for proxy https
++ ! $netssl ? (
++ # note that we reuse proxy conn#C in first request. Although the last id
++ # from this conn was C.6 the new one is C.8, because request C.7 was the
++ # socket upgrade via CONNECT request
++ [ 'proxy', "https://foo/foo",'C.8.Tauth at foo' ],
++ [ 'proxy', "https://foo/bar",'C.9.Tauth at foo' ],
++ # if the target of the tunnel is different we need another connection
++ # note that it starts with F.2, because F.1 is the CONNECT request which
++ # established the tunnel
++ [ 'proxy', "https://bar/foo",'F.2.Tauth at bar' ],
++ [ 'proxy', "https://bar/bar",'F.3.Tauth at bar' ],
++ [ 'proxy', "https://foo/tor",'C.10.Tauth at foo' ],
++ [ 'proxy', "https://bar/tor",'F.4.Tauth at bar' ],
++ ):(
++ # Net::SSL will cannot reuse socket for CONNECT, but once inside tunnel
++ # keep-alive is possible
++ [ 'proxy', "https://foo/foo",'G.2.Tauth at foo' ],
++ [ 'proxy', "https://foo/bar",'G.3.Tauth at foo' ],
++ [ 'proxy', "https://bar/foo",'F.2.Tauth at bar' ],
++ [ 'proxy', "https://bar/bar",'F.3.Tauth at bar' ],
++ [ 'proxy', "https://foo/tor",'G.4.Tauth at foo' ],
++ [ 'proxy', "https://bar/tor",'F.4.Tauth at bar' ],
++ ),
++ # non-keep alive for proxy https
++ [ 'proxy_nokeepalive', "https://foo/foo",'H.2.Tauth at foo' ],
++ [ 'proxy_nokeepalive', "https://foo/bar",'I.2.Tauth at foo' ],
++ [ 'proxy_nokeepalive', "https://bar/foo",'J.2.Tauth at bar' ],
++ [ 'proxy_nokeepalive', "https://bar/bar",'K.2.Tauth at bar' ],
++);
++plan tests => 2*@tests;
++
++my (%conn2id,%id2conn);
++for my $test (@tests) {
++ my ($uatype,$url,$expect_id) = @$test;
++ my $ua = $ua{$uatype} or die "no such ua: $uatype";
++
++ # Net::SSL uses only the environment to decide about proxy, so we need the
++ # proxy/non-proxy environment for each request
++ if ( $netssl && $url =~m{^https://} ) {
++ $ENV{https_proxy} = $uatype =~m{^proxy} ? "http://$saddr[0]":""
++ }
++
++ my $response = $ua->get($url) or die "no response";
++ if ( $response->is_success
++ and ( my $body = $response->content()) =~m{^ID: *(\d+)\.(\S+)}m ) {
++ my $id = [ $1,$2 ];
++ my $xid = [ $expect_id =~m{(\w+)\.(\S+)} ];
++ if ( my $x = $id2conn{$id->[0]} ) {
++ $id->[0] = $x;
++ } elsif ( ! $conn2id{$xid->[0]} ) {
++ $conn2id{ $xid->[0] } = $id->[0];
++ $id2conn{ $id->[0] } = $xid->[0];
++ $id->[0] = $xid->[0];
++ }
++ is("$id->[0].$id->[1]",$expect_id,"$uatype $url -> $expect_id")
++ or diag($response->as_string);
++ # inside proxy tunnel and for non-proxy there should be only absolute
++ # URI in request w/o scheme
++ my $expect_rqurl = $url;
++ $expect_rqurl =~s{^\w+://[^/]+}{}
++ if $uatype eq 'noproxy' or $url =~m{^https://};
++ my ($rqurl) = $body =~m{^GET (\S+) HTTP/}m;
++ is($rqurl,$expect_rqurl,"URL in request -> $expect_rqurl");
++ } else {
++ die "unexpected response: ".$response->as_string
++ }
++}
++
++# ------------------------------------------------------------------------
++# simple web server with keep alive and SSL, which can also simulate proxy
++# ------------------------------------------------------------------------
++sub _server {
++ my $connid = 0;
++ my %certs; # generated certificates
++
++ ACCEPT:
++ my ($server) = IO::Select->new(@server)->can_read();
++ my $cl = $server->accept or goto ACCEPT;
++
++ # peek into socket to determine if this is direct SSL or not
++ # minimal request is "GET / HTTP/1.1\n\n"
++ my $buf = '';
++ while (length($buf)<15) {
++ my $lbuf;
++ if ( ! IO::Select->new($cl)->can_read(30)
++ or ! defined recv($cl,$lbuf,20,MSG_PEEK)) {
++ warn "not enough data for request ($buf): $!";
++ goto ACCEPT;
++ }
++ $buf .= $lbuf;
++ }
++ my $ssl_host = '';
++ if ( $buf !~m{\A[A-Z]{3,} } ) {
++ # does not look like HTTP, assume direct SSL
++ $ssl_host = "direct.ssl.access";
++ }
++
++ $connid++;
++
++ defined( my $pid = fork()) or die "failed to fork: $!";
++ if ( $pid ) {
++ push @childs,$pid;
++ goto ACCEPT; # wait for next connection
++ }
++
++ # child handles requests
++ @server = ();
++ my $reqid = 0;
++ my $tunnel_auth = '';
++
++ SSL_UPGRADE:
++ if ( $ssl_host ) {
++ my ($cert,$key) = @{
++ $certs{$ssl_host} ||= do {
++ diag("creating cert for $ssl_host");
++ my ($c,$k) = CERT_create(
++ subject => { commonName => $ssl_host },
++ issuer_cert => $cacert,
++ issuer_key => $cakey,
++ # just reuse cakey as key for certificate
++ key => $cakey,
++ );
++ [ $c,$k ];
++ };
++ };
++
++ IO::Socket::SSL->start_SSL( $cl,
++ SSL_server => 1,
++ SSL_cert => $cert,
++ SSL_key => $key,
++ ) or do {
++ diag("SSL handshake failed: ".IO::Socket::SSL->errstr);
++ exit(1);
++ };
++ }
++
++ REQUEST:
++ # read header
++ my $req = '';
++ while (<$cl>) {
++ $_ eq "\r\n" and last;
++ $req .= $_;
++ }
++ $reqid++;
++ my $req_auth = $req =~m{^Proxy-Authorization:}mi ? '.auth':'';
++
++ if ( $req =~m{\ACONNECT ([^\s:]+)} ) {
++ if ( $ssl_host ) {
++ diag("CONNECT inside SSL tunnel");
++ exit(1);
++ }
++ $ssl_host = $1;
++ $tunnel_auth = $req_auth ? '.Tauth':'';
++ #diag($req);
++
++ # simulate proxy and establish SSL tunnel
++ print $cl "HTTP/1.0 200 ok\r\n\r\n";
++ goto SSL_UPGRADE;
++ }
++
++ if ( $req =~m{^Content-length: *(\d+)}mi ) {
++ read($cl,my $buf,$1) or die "eof while reading request body";
++ }
++ my $keep_alive =
++ $req =~m{^(?:Proxy-)?Connection: *(?:(keep-alive)|close)}mi ? $1 :
++ $req =~m{\A.*HTTP/1\.1} ? 1 :
++ 0;
++
++ # just echo request back, including connid and reqid
++ my $body = "ID: $connid.$reqid$tunnel_auth$req_auth\@"
++ . ( $ssl_host || 'nossl' )."\n"
++ . "---------\n$req";
++ print $cl "HTTP/1.1 200 ok\r\nContent-type: text/plain\r\n"
++ . "Connection: ".( $keep_alive ? 'keep-alive':'close' )."\r\n"
++ . "Content-length: ".length($body)."\r\n"
++ . "\r\n"
++ . $body;
++
++ goto REQUEST if $keep_alive;
++ exit(0); # done handling requests
++}
diff --git a/debian/patches/series b/debian/patches/series
index 0df6cbf..a062ed3 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1 +1,2 @@
+fix-https-proxy
cert.patch
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-perl/packages/liblwp-protocol-https-perl.git
More information about the Pkg-perl-cvs-commits
mailing list