Created
June 1, 2026 14:22
-
-
Save krisk0/bc9b57176cd8b852aa4b456f853de54d to your computer and use it in GitHub Desktop.
download file via perl IO module
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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