Fix to use the existing HTTP and FTP mode 7 callback

This commit is contained in:
Ilia Ross
2026-07-14 02:27:10 +02:00
parent a618c2b58e
commit 934073532f
6 changed files with 87 additions and 285 deletions

View File

@@ -39,18 +39,23 @@ else {
$progress_callback_url = $in{'link'};
my @st = stat($cwd);
my $callbacks = {
'tracker_callback' => \&progress_callback,
'address_callback' => &get_download_address_callback(
$access{'download_address_mode'} || 'public',
$access{'download_allowed_addresses'}),
my $address_checker = &get_download_address_callback(
$access{'download_address_mode'} || 'public',
$access{'download_allowed_addresses'});
my $download_callback = sub {
if ($_[0] == 7 && defined($_[1]) && $address_checker) {
my $address_error = &$address_checker(
$host, [ $_[1] ]);
&error(&html_escape($address_error)) if ($address_error);
}
&progress_callback(@_);
};
if ($ssl == 0 || $ssl == 1) {
# HTTP or HTTPS download
&http_download(
$host, $port, $page,
$full, undef,
$callbacks,
$download_callback,
$ssl, $in{'username'},
$in{'password'});
}
@@ -59,7 +64,7 @@ else {
&ftp_download(
$host, $page, $full,
undef,
$callbacks,
$download_callback,
$in{'username'},
$in{'password'}, $port);
}

View File

@@ -149,21 +149,32 @@ subtest 'XHR remote content uses mailbox destination ACL' => sub {
local *parse_http_url = sub {
return ('example.test', 80, '/image.png', 0);
};
my $address_callback = sub { return 'mailbox-acl-callback'; };
my $address_checker = sub {
POSIX::_exit(4)
if ($_[0] ne 'example.test' ||
$_[1]->[0] ne '127.0.0.1');
return 'mailbox-address-blocked';
};
local *get_download_address_callback = sub {
POSIX::_exit(3)
if ($_[0] ne 'listed' || $_[1] ne '10.0.0.0/8');
return $address_callback;
return $address_checker;
};
local *error = sub {
POSIX::_exit($_[0] eq 'mailbox-address-blocked' ? 0 : 1);
};
local *html_escape = sub { return $_[0]; };
local *http_download = sub {
my $callback = $_[5]->{'address_callback'};
POSIX::_exit(&$callback() eq 'mailbox-acl-callback' ? 0 : 1);
my $callback = $_[5];
POSIX::_exit(5) if (ref($callback) ne 'CODE');
&$callback(7, '127.0.0.1');
POSIX::_exit(2);
};
xhr();
POSIX::_exit(2);
POSIX::_exit(6);
}
waitpid($pid, 0);
is($? >> 8, 0, 'XHR passes its callback bundle to HTTP download');
is($? >> 8, 0, 'XHR checks mode 7 through the existing callback');
};
done_testing();

View File

@@ -35,12 +35,19 @@ if ($in{'action'} eq "fetch") {
$url = &html_unescape($url);
my ($host, $port, $page, $ssl) = &parse_http_url($url);
my ($img, $err, $response_headers);
my $callbacks = {
'address_callback' => &get_download_address_callback(
$access{'download_address_mode'} || 'public',
$access{'download_allowed_addresses'}),
my $address_checker = &get_download_address_callback(
$access{'download_address_mode'} || 'public',
$access{'download_allowed_addresses'});
my $download_callback = sub {
if ($_[0] == 7 && defined($_[1]) && $address_checker) {
my $address_error = &$address_checker(
$host, [ $_[1] ]);
&error(&html_escape($address_error))
if ($address_error);
}
};
&http_download($host, $port, $page, \$img, \$err, $callbacks,
&http_download($host, $port, $page, \$img, \$err,
$download_callback,
$ssl, undef, undef, 10, undef, undef,
undef, \$response_headers);
# Check if download worked

View File

@@ -234,161 +234,4 @@ subtest 'download address callback' => sub {
}
};
subtest 'restricted download cache isolation' => sub {
no warnings qw(once redefine);
my $cache_checks = 0;
local *main::check_in_http_cache = sub { $cache_checks++; return; };
local *main::make_http_connection = sub { return 'test connection stopped'; };
my ($dest, $err);
my $callbacks = { 'address_callback' => sub { return undef; } };
main::http_download('8.8.8.8', 80, '/', \$dest, \$err, $callbacks,
0, undef, undef, 0);
is($cache_checks, 0, 'restricted download does not consult shared cache');
is($err, 'test connection stopped', 'download reached mocked connection');
};
subtest 'callback hash dispatches tracker events' => sub {
no warnings qw(once redefine);
my @lines = (
"HTTP/1.0 200 OK\r\n",
"Content-Length: 0\r\n",
"\r\n",
);
local *main::read_http_connection = sub { return shift(@lines); };
local *main::close_http_connection = sub { return 1; };
my @events;
my $callbacks = {
'tracker_callback' => sub { push(@events, $_[0]); },
};
my ($dest, $err);
main::complete_http_download({}, \$dest, \$err, $callbacks, undef,
'8.8.8.8', 80, {}, 0, 1, 0);
is_deeply(\@events, [ 1, 2, 4 ],
'tracker callback receives the existing event sequence');
@lines = (
"HTTP/1.0 200 OK\r\n",
"Content-Length: 0\r\n",
"\r\n",
);
my @legacy_events;
main::complete_http_download({}, \$dest, \$err,
sub { push(@legacy_events, $_[0]); },
undef, '8.8.8.8', 80, {}, 0, 1, 0);
is_deeply(\@legacy_events, [ 1, 2, 4 ],
'legacy callback code refs remain supported');
};
subtest 'callback bundle preserves connected IP event' => sub {
no warnings qw(once redefine);
my ($connection_callback, $download_callbacks);
local *main::make_http_connection = sub {
$connection_callback = $_[8];
return { 'ip' => '93.184.216.34' };
};
local *main::complete_http_download = sub {
$download_callbacks = $_[3];
return 1;
};
my @events;
my $address_callback = sub { return undef; };
my $callbacks = {
'tracker_callback' => sub { push(@events, [ @_ ]); },
'address_callback' => $address_callback,
};
my ($dest, $err);
main::http_download('origin.test', 80, '/', \$dest, \$err, $callbacks,
0, undef, undef, 0, undef, 1);
is_deeply(\@events, [ [ 7, '93.184.216.34' ] ],
'tracker callback receives the connected IP event');
is($connection_callback, $address_callback,
'connection receives the address callback');
is($download_callbacks, $callbacks,
'download receives the complete callback bundle');
};
subtest 'redirect destination policy' => sub {
no warnings qw(once redefine);
my @lines = (
"HTTP/1.0 302 Found\r\n",
"Location: http://127.0.0.1/private\r\n",
"\r\n",
);
local *main::read_http_connection = sub { return shift(@lines); };
local *main::close_http_connection = sub { return 1; };
my ($dest, $err);
my $address_callback = main::get_download_address_callback('public');
my $callbacks = { 'address_callback' => $address_callback };
main::complete_http_download({}, \$dest, \$err, $callbacks, undef,
'8.8.8.8', 80, {}, 0, 1, 0);
like($err, qr/non-public IP address 127\.0\.0\.1/,
'redirect to loopback is blocked before connecting');
};
subtest 'restricted HTTP proxy pins checked address' => sub {
no warnings qw(once redefine);
local %main::gconfig = (http_proxy => 'http://proxy.test:3128');
local *main::is_readonly_mode = sub { return 0; };
local *main::no_proxy = sub { return 0; };
local *main::to_ipaddress = sub {
return $_[0] eq 'origin.test' ? '93.184.216.34' : ();
};
local *main::to_ip6address = sub { return; };
my $wire = '';
local *main::open_socket = sub {
my $name = $_[2];
no strict 'refs';
open(*{"main::$name"}, '>', \$wire) || die $!;
return 1;
};
my $address_callback = main::get_download_address_callback('public');
my $h = main::make_http_connection(
'origin.test', 80, 0, 'GET', '/path',
[ [ 'Host', 'origin.test' ] ], undef, undef,
$address_callback);
main::close_http_connection($h);
like($wire, qr{^GET http://93\.184\.216\.34:80/path HTTP/1\.0\r\n},
'proxy request targets the policy-checked IP');
like($wire, qr/Host: origin\.test\r\n/,
'proxy request preserves the original Host header');
};
subtest 'open_socket destination callback' => sub {
no warnings qw(once redefine);
local *main::to_ipaddress = sub { return '127.0.0.1'; };
local *main::to_ip6address = sub { return; };
my $address_callback = main::get_download_address_callback('public');
my $err;
ok(!main::open_socket('loopback.test', 80, 'TESTSOCK', \$err,
undef, $address_callback),
'socket connection is rejected by its destination callback');
like($err, qr/non-public IP address 127\.0\.0\.1/,
'socket reports the callback rejection');
};
subtest 'restricted FTP proxy pins checked address' => sub {
no warnings qw(once redefine);
local %main::gconfig = (ftp_proxy => 'http://proxy.test:3128');
local *main::is_readonly_mode = sub { return 0; };
local *main::no_proxy = sub { return 0; };
local *main::to_ipaddress = sub {
return $_[0] eq 'origin.test' ? '93.184.216.34' : ();
};
local *main::to_ip6address = sub { return; };
my $wire = '';
local *main::open_socket = sub {
no strict 'refs';
open(*{'main::SOCK'}, '>', \$wire) || die $!;
return 1;
};
local *main::complete_http_download = sub { return 1; };
my $address_callback = main::get_download_address_callback('public');
my $callbacks = { 'address_callback' => $address_callback };
my ($dest, $err);
ok(main::ftp_download('origin.test', '/file', \$dest, \$err, $callbacks,
undef, undef, 21),
'restricted FTP download reaches its proxy');
like($wire, qr{^GET ftp://93\.184\.216\.34/file HTTP/1\.0\r\n},
'FTP proxy request targets the policy-checked IP');
};
done_testing();

View File

@@ -138,10 +138,15 @@ if (!$module_info{'usermin'} && $_[0]->{'webmin_user'}) {
$address_mode = $download_access{'download_address_mode'} || 'public';
$allowed_addresses = $download_access{'download_allowed_addresses'};
}
my $callbacks = {
'tracker_callback' => $_[1],
'address_callback' => &get_download_address_callback(
$address_mode, $allowed_addresses),
my $tracker_callback = $_[1];
my $address_checker = &get_download_address_callback(
$address_mode, $allowed_addresses);
my $download_callback = sub {
if ($_[0] == 7 && defined($_[1]) && $address_checker) {
my $address_error = &$address_checker(undef, [ $_[1] ]);
&error(&html_escape($address_error)) if ($address_error);
}
&$tracker_callback(@_) if ($tracker_callback);
};
for($i=0; $_[0]->{"url_$i"}; $i++) {
$error = undef;
@@ -169,7 +174,7 @@ for($i=0; $_[0]->{"url_$i"}; $i++) {
$_[0]->{"page_$i"},
$path,
\$error,
$callbacks,
$download_callback,
$_[0]->{"ssl_$i"},
$_[0]->{"user_$i"},
$_[0]->{"pass_$i"});
@@ -179,7 +184,7 @@ for($i=0; $_[0]->{"url_$i"}; $i++) {
$_[0]->{"page_$i"},
$path,
\$error,
$callbacks,
$download_callback,
$_[0]->{"user_$i"},
$_[0]->{"pass_$i"});
}

View File

@@ -3349,7 +3349,7 @@ Downloads data from a HTTP url to a local file or string. The parameters are :
=item error - If set to a scalar ref, the function will store any error message in this scalar and return 0 on failure, or 1 on success. If not set, it will simply call the error function if the download fails.
=item callback - If set to a function ref, it will be called after each block of data is received. This is typically set to \&progress_callback, for printing download progress. It can also be a hash ref containing tracker_callback and address_callback function refs. The address callback receives the destination hostname and an array ref of resolved IP addresses, and returns an error message to reject the destination or undef to allow it.
=item callback - If set to a function ref, it will be called after each block of data is received. This is typically set to \&progress_callback, for printing download progress.
=item sslmode - If set to 1, an HTTPS connection is used instead of HTTP.
@@ -3389,13 +3389,6 @@ sub http_download
{
my ($host, $port, $page, $dest, $error, $cbfunc, $ssl, $user, $pass,
$timeout, $osdn, $nocache, $headers, $response_headers) = @_;
my $callbacks = $cbfunc;
my $address_callback;
# Extract known callbacks from an extended callback hash
if (ref($callbacks) eq 'HASH') {
$cbfunc = $callbacks->{'tracker_callback'};
$address_callback = $callbacks->{'address_callback'};
}
if ($gconfig{'debug_what_net'}) {
&webmin_debug_log('HTTP', "host=$host port=$port page=$page ssl=$ssl".
($user ? " user=$user pass=$pass" : "").
@@ -3410,13 +3403,10 @@ if ($osdn) {
&convert_osdn_url($prot.$host.$portstr.$page));
}
# Restricted downloads must not share cached responses with unrestricted ones
$nocache = 1 if ($address_callback);
# Check if we already have cached the URL
my $url = ($ssl ? "https://" : "http://").$host.":".$port.$page;
my $cfile = !$nocache ? &check_in_http_cache($url) : undef;
if ($cfile) {
my $cfile = &check_in_http_cache($url);
if ($cfile && !$nocache) {
# Yes! Copy to dest file or variable
&$cbfunc(6, $url) if ($cbfunc);
if (ref($dest)) {
@@ -3454,8 +3444,7 @@ $main::download_timed_out = undef;
local $SIG{ALRM} = \&download_timeout;
$timeout = 60 if (!defined($timeout));
alarm($timeout) if ($timeout);
my $h = &make_http_connection($host, $port, $ssl, "GET", $page, \@headers,
undef, undef, $address_callback);
my $h = &make_http_connection($host, $port, $ssl, "GET", $page, \@headers);
alarm(0) if ($timeout);
$h = $main::download_timed_out if ($main::download_timed_out);
if (!ref($h)) {
@@ -3464,7 +3453,7 @@ if (!ref($h)) {
else { &error(&html_escape($h)); }
}
&$cbfunc(7, $h->{'ip'}) if ($cbfunc);
&complete_http_download($h, $dest, $error, $callbacks, $osdn, $host, $port,
&complete_http_download($h, $dest, $error, $cbfunc, $osdn, $host, $port,
$headers, $ssl, $nocache, $timeout, $response_headers);
if ((!$error || !$$error) && !$nocache) {
&write_to_http_cache($url, $dest);
@@ -3483,11 +3472,6 @@ sub complete_http_download
{
my ($h, $destfile, $error, $cbfunc, $osdn, $oldhost, $oldport, $headers,
$oldssl, $nocache, $timeout, $response_headers) = @_;
my $callbacks = $cbfunc;
# Extract the tracker callback from an extended callback hash
if (ref($callbacks) eq 'HASH') {
$cbfunc = $callbacks->{'tracker_callback'};
}
# Kept local so that callback funcs # can access them.
local ($line, %header, @headers, $s);
@@ -3561,7 +3545,7 @@ if ($rcode >= 300 && $rcode < 400) {
($page, $params) = split(/\?/, $page);
$page =~ s/ /%20/g;
$page .= "?".$params if (defined($params));
&http_download($host, $port, $page, $destfile, $error, $callbacks, $ssl,
&http_download($host, $port, $page, $destfile, $error, $cbfunc, $ssl,
undef, undef, undef, $osdn, $nocache, $headers);
}
else {
@@ -3708,7 +3692,7 @@ Download data from an FTP site to a local file. The parameters are :
=item error - If set to a string ref, any error message is written into this string and the function returns 0 on failure, 1 on success. Otherwise, error is called on failure.
=item callback - If set to a function ref, it will be called after each block of data is received. This is typically set to \&progress_callback, for printing download progress. It can also be a hash ref containing tracker_callback and address_callback function refs. The address callback receives the destination hostname and an array ref of resolved IP addresses, and returns an error message to reject the destination or undef to allow it.
=item callback - If set to a function ref, it will be called after each block of data is received. This is typically set to \&progress_callback, for printing download progress.
=item user - Username to login to the FTP server as. If missing, Webmin will login as anonymous.
@@ -3725,13 +3709,6 @@ sub ftp_download
{
my ($host, $file, $dest, $error, $cbfunc, $user, $pass, $port, $nocache,
$timeout) = @_;
my $callbacks = $cbfunc;
my $address_callback;
# Extract known callbacks from an extended callback hash
if (ref($callbacks) eq 'HASH') {
$cbfunc = $callbacks->{'tracker_callback'};
$address_callback = $callbacks->{'address_callback'};
}
$port ||= 21;
$timeout = 60 if (!defined($timeout));
if ($gconfig{'debug_what_net'}) {
@@ -3750,13 +3727,10 @@ if (&is_readonly_mode()) {
}
}
# Restricted downloads must not share cached responses with unrestricted ones
$nocache = 1 if ($address_callback);
# Check if we already have cached the URL
my $url = "ftp://".$host.$file;
my $cfile = !$nocache ? &check_in_http_cache($url) : undef;
if ($cfile) {
my $cfile = &check_in_http_cache($url);
if ($cfile && !$nocache) {
# Yes! Copy to dest file or variable
&$cbfunc(6, $url) if ($cbfunc);
if (ref($dest)) {
@@ -3777,21 +3751,9 @@ local $SIG{ALRM} = \&download_timeout;
alarm($timeout) if ($timeout);
my $connected;
if ($gconfig{'ftp_proxy'} =~ /^http:\/\/(\S+):(\d+)/ && !&no_proxy($_[0])) {
my ($ftp_proxy_host, $ftp_proxy_port) = ($1, $2);
my $proxy_address = $host;
if ($address_callback) {
my @addresses;
my $address_error = &check_download_address(
$host, $address_callback, \@addresses);
if ($address_error) {
if ($error) { $$error = $address_error; return 0; }
else { &error(&html_escape($address_error)); }
}
$proxy_address = $addresses[0];
}
# download through http-style proxy
my $error;
if (&open_socket($ftp_proxy_host, $ftp_proxy_port, "SOCK", \$error)) {
if (&open_socket($1, $2, "SOCK", \$error)) {
# Connected OK
if ($main::download_timed_out) {
alarm(0) if ($timeout);
@@ -3806,9 +3768,7 @@ if ($gconfig{'ftp_proxy'} =~ /^http:\/\/(\S+):(\d+)/ && !&no_proxy($_[0])) {
my $esc = $file; $esc =~ s/ /%20/g;
my $up = "${user}:${pass}\@" if ($user);
my $portstr = $port == 21 ? "" : ":$port";
my $proxy_host = $proxy_address;
$proxy_host = "[$proxy_host]" if (&check_ip6address($proxy_host));
print SOCK "GET ftp://${up}${proxy_host}${portstr}${esc} HTTP/1.0\r\n";
print SOCK "GET ftp://${up}${host}${portstr}${esc} HTTP/1.0\r\n";
print SOCK "User-agent: Webmin\r\n";
if ($gconfig{'proxy_user'}) {
my $auth = &encode_base64(
@@ -3818,9 +3778,8 @@ if ($gconfig{'ftp_proxy'} =~ /^http:\/\/(\S+):(\d+)/ && !&no_proxy($_[0])) {
}
print SOCK "\r\n";
&complete_http_download(
{ 'fh' => "SOCK" }, $dest, $error, $callbacks,
undef, undef, undef, undef, 0, $nocache,
undef, undef);
{ 'fh' => "SOCK" }, $dest, $error, $cbfunc,
undef, undef, undef, undef, 0, $nocache);
$connected = 1;
}
elsif (!$gconfig{'proxy_fallback'}) {
@@ -3888,8 +3847,7 @@ if (!$connected) {
defined($epsv) || return 0;
$epsv =~ /\|(\d+)\|/ || return 0;
my $epsvport = $1;
&open_socket($host, $epsvport, CON, $error, undef,
$address_callback) || return 0;
&open_socket($host, $epsvport, CON, $error) || return 0;
}
else {
# request the file over a PASV connection
@@ -3898,8 +3856,7 @@ if (!$connected) {
$pasv =~ /\(([0-9,]+)\)/ || return 0;
@n = split(/,/ , $1);
&open_socket("$n[0].$n[1].$n[2].$n[3]",
$n[4]*256 + $n[5], "CON", $_[3], undef,
$address_callback) || return 0;
$n[4]*256 + $n[5], "CON", $_[3]) || return 0;
}
&ftp_command("RETR $file", 1, $error) || return 0;
@@ -3933,7 +3890,7 @@ if (!$connected) {
close(SOCK);
}
&write_to_http_cache($url, $dest) if (!$nocache);
&write_to_http_cache($url, $dest);
return 1;
}
@@ -4075,7 +4032,7 @@ foreach my $n (split(/\s+/, $gconfig{'noproxy'})) {
return 0;
}
=head2 open_socket(host, port, handle, [&error], [bindip], [&address-callback])
=head2 open_socket(host, port, handle, [&error])
Open a TCP connection to some host and port, using a file handle. The
parameters are :
@@ -4090,16 +4047,12 @@ parameters are :
=item bindip - Local IP address to bind to for outgoing connections
=item address-callback - Optional function called with the hostname and an
array reference of its resolved IP addresses. It must return an error message
to reject the destination, or undef to allow it.
Returns the IP to which the connection was actually made.
=cut
sub open_socket
{
my ($host, $port, $fh, $err, $bindip, $address_callback) = @_;
my ($host, $port, $fh, $err, $bindip) = @_;
$fh = &callers_package($fh);
$bindip ||= $gconfig{'bind_proxy'};
@@ -4107,12 +4060,11 @@ if ($gconfig{'debug_what_net'}) {
&webmin_debug_log('TCP', "host=$host port=$port");
}
# Resolve and validate the same addresses that will be used for connect().
my @ips;
my $address_error = &check_download_address(
$host, $address_callback, \@ips);
if ($address_error) {
my $msg = $address_error;
# Lookup all IPv4 and v6 addresses for the host
my @ips = &to_ipaddress($host);
push(@ips, &to_ip6address($host));
if (!@ips) {
my $msg = "Failed to lookup IP address for $host";
if ($err) { $$err = $msg; return undef; }
else { &error($msg); }
}
@@ -9856,7 +9808,7 @@ return $can_use_http_ssl_cache;
}
=head2 make_http_connection(host, port, ssl, method, page, [&headers],
[bindip], [&certreqs], [&address-callback])
[&certreqs])
Opens a connection to some HTTP server, maybe through a proxy, and returns
a handle object. The handle can then be used to send additional headers
@@ -9880,15 +9832,10 @@ The parameters are :
=item certreqs - A hash ref containing options for remote cert verification
=item address-callback - Optional function called with the destination hostname
and an array reference of its resolved IP addresses. It must return an error
message to reject the destination, or undef to allow it.
=cut
sub make_http_connection
{
my ($host, $port, $ssl, $method, $page, $headers, $bindip, $certreqs,
$address_callback) = @_;
my ($host, $port, $ssl, $method, $page, $headers, $bindip, $certreqs) = @_;
my $htxt;
if (ref($headers) eq 'ARRAY') {
# Headers are name-value pairs
@@ -9908,20 +9855,6 @@ if (&is_readonly_mode()) {
return "HTTP connections not allowed in readonly mode";
}
my $rv = { 'fh' => time().$$ };
my ($http_proxy_host, $http_proxy_port);
if ($gconfig{'http_proxy'} =~ /^http:\/\/(\S+):(\d+)/ &&
!&no_proxy($host)) {
($http_proxy_host, $http_proxy_port) = ($1, $2);
}
my $proxy_host = $host;
if (defined($http_proxy_host) && $address_callback) {
my @addresses;
my $address_error = &check_download_address(
$host, $address_callback, \@addresses);
return $address_error if ($address_error);
$proxy_host = $addresses[0];
}
$proxy_host = "[$proxy_host]" if (&check_ip6address($proxy_host));
if ($ssl) {
# Connect using SSL
&can_use_http_ssl() || return $text{'link_essl'};
@@ -9982,15 +9915,15 @@ if ($ssl) {
$rv->{'ssl_con'} = Net::SSLeay::new($rv->{'ssl_ctx'}) ||
return "Failed to create SSL connection";
my $connected;
if (defined($http_proxy_host)) {
if ($gconfig{'http_proxy'} =~ /^http:\/\/(\S+):(\d+)/ &&
!&no_proxy($host)) {
# Via proxy
my $error;
&open_socket($http_proxy_host, $http_proxy_port,
$rv->{'fh'}, \$error, $bindip);
&open_socket($1, $2, $rv->{'fh'}, \$error, $bindip);
if (!$error) {
# Connected OK
my $fh = $rv->{'fh'};
print $fh "CONNECT $proxy_host:$port HTTP/1.0\r\n";
print $fh "CONNECT $host:$port HTTP/1.0\r\n";
if ($gconfig{'proxy_user'}) {
my $auth = &encode_base64(
"$gconfig{'proxy_user'}:".
@@ -10017,8 +9950,7 @@ if ($ssl) {
if (!$connected) {
# Direct connection
my $error;
my $ip = &open_socket($host, $port, $rv->{'fh'}, \$error, $bindip,
$address_callback);
my $ip = &open_socket($host, $port, $rv->{'fh'}, \$error, $bindip);
return $error if ($error);
$rv->{'ip'} = $ip;
}
@@ -10044,17 +9976,17 @@ if ($ssl) {
else {
# Plain HTTP request
my $connected;
if (defined($http_proxy_host)) {
if ($gconfig{'http_proxy'} =~ /^http:\/\/(\S+):(\d+)/ &&
!&no_proxy($host)) {
# Via a proxy
my $error;
&open_socket($http_proxy_host, $http_proxy_port,
$rv->{'fh'}, \$error, $bindip);
&open_socket($1, $2, $rv->{'fh'}, \$error, $bindip);
if (!$error) {
# Connected OK
$connected = 1;
my $fh = $rv->{'fh'};
my $rtxt = $method." ".
"http://$proxy_host:$port$page HTTP/1.0\r\n";
"http://$host:$port$page HTTP/1.0\r\n";
if ($gconfig{'proxy_user'}) {
my $auth = &encode_base64(
"$gconfig{'proxy_user'}:".
@@ -10072,8 +10004,7 @@ else {
if (!$connected) {
# Connecting directly
my $error;
my $ip = &open_socket($host, $port, $rv->{'fh'}, \$error, $bindip,
$address_callback);
my $ip = &open_socket($host, $port, $rv->{'fh'}, \$error, $bindip);
return $error if ($error);
my $fh = $rv->{'fh'};
$rv->{'ip'} = $ip;