Skip to content

Instantly share code, notes, and snippets.

@krisk0
Created June 1, 2026 14:22
Show Gist options
  • Select an option

  • Save krisk0/bc9b57176cd8b852aa4b456f853de54d to your computer and use it in GitHub Desktop.

Select an option

Save krisk0/bc9b57176cd8b852aa4b456f853de54d to your computer and use it in GitHub Desktop.
download file via perl IO module
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket::INET;
use IO::Socket::SSL;
my $proxy_host = 'proxy.boss.com';
my $proxy_port = 3128;
my $dest_host = 'github.com';
my $dest_port = 443;
my $path = '/AUTHOR/REPOSITORY/archive/refs/heads/master.zip';
my $filename = '/tmp/master.zip';
sub read_chunked_response {
my ($sock) = @_;
my $body = '';
while (1) {
# Читаем размер текущего чанка (шестнадцатеричное число + \r\n)
my $size_line = '';
while (<$sock>) {
$size_line .= $_;
last if /\r\n$/;
}
chomp($size_line);
$size_line =~ s/\r$//;
# Преобразуем размер из hex в десятичное
my $chunk_size = hex($size_line);
# Если размер 0 — конец потока
last if $chunk_size == 0;
# Читаем ровно $chunk_size байт данных
my $data = '';
my $bytes_read = 0;
while ($bytes_read < $chunk_size) {
my $chunk;
my $ret = sysread($sock, $chunk, $chunk_size - $bytes_read);
die "Read error" unless defined $ret;
last unless $ret;
$data .= $chunk;
$bytes_read += $ret;
}
# Добавляем прочитанные данные к телу ответа
$body .= $data;
# Пропускаем \r\n после данных чанка
<$sock>; # читаем и игнорируем \r\n
}
return $body;
}
sub download_with_redirects {
my ($host, $port, $path, $redirect_count) = @_;
$redirect_count ||= 0;
if ($redirect_count > 5) {
die "Too many redirects\n";
}
# Подключаемся к прокси
my $sock = IO::Socket::INET->new(
PeerAddr => $proxy_host,
PeerPort => $proxy_port,
Proto => 'tcp'
) or die "Cannot connect to proxy: $!";
print $sock "CONNECT $host:$port HTTP/1.1\r\n";
print $sock "Host: $host\r\n";
print $sock "\r\n";
my $connect_resp = '';
while (<$sock>) {
$connect_resp .= $_;
last if /^\s*$/;
}
unless ($connect_resp =~ /^HTTP\/1\.\d\s+200/) {
close $sock;
die "Proxy CONNECT failed: $connect_resp";
}
# Устанавливаем SSL
my $ssl_sock = IO::Socket::SSL->start_SSL(
$sock,
SSL_startHandshake => 1,
PeerHost => $host
) or die "SSL handshake failed: $SSL_ERROR";
# Отправляем запрос
print $ssl_sock "GET $path HTTP/1.1\r\n";
print $ssl_sock "Host: $host\r\n";
print $ssl_sock "User-Agent: Perl\r\n";
print $ssl_sock "Connection: close\r\n";
print $ssl_sock "\r\n";
# Читаем заголовки
my $headers = '';
while (<$ssl_sock>) {
$headers .= $_;
last if /^\s*$/;
}
# Проверяем статус
unless ($headers =~ /^HTTP\/1\.\d\s+200\s+OK/i) {
if ($headers =~ /^HTTP\/1\.\d\s+(\d+)/) {
my $status = $1;
if ($status == 301 || $status == 302) {
# Обработка редиректов
if ($headers =~ /^Location:\s*(.*?)\r?$/im) {
my $new_url = $1;
if ($new_url =~ m!^https?://([^/]+)(.*)$!) {
my $new_host = $1;
my $new_path = $2 || '/';
return download_with_redirects($new_host, 443, $new_path, $redirect_count + 1);
} else {
die "Invalid redirect URL: $new_url\n";
}
} else {
die "Redirect without Location header\n";
}
} else {
die "HTTP error: $status\n";
}
} else {
die "Invalid response from server\n";
}
}
# Проверяем, используется ли chunked encoding
my $is_chunked = $headers =~ /Transfer-Encoding:\s*chunked/i;
my $body;
if ($is_chunked) {
$body = read_chunked_response($ssl_sock);
} else {
# Обычный режим: читаем до закрытия соединения
$body = '';
my $chunk;
while (sysread($ssl_sock, $chunk, 8192)) {
$body .= $chunk;
}
}
close $ssl_sock;
return $body;
}
# Запускаем загрузку
my $content = download_with_redirects($dest_host, $dest_port, $path);
# Сохраняем файл
open(my $fh, '>', $filename) or die "Can't open file: $!\n";
binmode $fh;
print $fh $content;
close $fh;
print "File saved as $filename (size: " . length($content) . " bytes)\n";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment