Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package MirrorCache for openSUSE:Factory 
checked in at 2023-01-19 16:44:11
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/MirrorCache (Old)
 and      /work/SRC/openSUSE:Factory/.MirrorCache.new.32243 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "MirrorCache"

Thu Jan 19 16:44:11 2023 rev:23 rq:1059502 version:1.052

Changes:
--------
--- /work/SRC/openSUSE:Factory/MirrorCache/MirrorCache.changes  2023-01-05 
15:01:54.577399206 +0100
+++ /work/SRC/openSUSE:Factory/.MirrorCache.new.32243/MirrorCache.changes       
2023-01-19 16:44:28.333852717 +0100
@@ -1,0 +2,11 @@
+Thu Jan 12 08:43:17 UTC 2023 - Andrii Nikitin <andrii.niki...@suse.com>
+
+- Update to version 1.052:
+  * Detect redirects with remote root (#336)
+  * Add json parsing to FolderSync task (#337)
+  * Redirect Current.iso when no nfs mount (#339)
+  * Improve sorting of files in JavaScript (#340)
+  * Redirect huge files (#342)
+  * Secure last_id for jobs monitoring stat (#341)
+
+-------------------------------------------------------------------

Old:
----
  MirrorCache-1.051.obscpio

New:
----
  MirrorCache-1.052.obscpio

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ MirrorCache.spec ++++++
--- /var/tmp/diff_new_pack.NONKJq/_old  2023-01-19 16:44:29.093856675 +0100
+++ /var/tmp/diff_new_pack.NONKJq/_new  2023-01-19 16:44:29.097856696 +0100
@@ -22,7 +22,7 @@
 %define main_requires %{assetpack_requires} perl(Carp) perl(DBD::Pg) >= 3.7.4 
perl(DBI) >= 1.632 perl(DBIx::Class) >= 0.082801 
perl(DBIx::Class::DynamicDefault) perl(DateTime) perl(Encode) perl(Time::Piece) 
perl(Time::Seconds) perl(Time::ParseDate) perl(DateTime::Format::Pg) 
perl(Exporter) perl(File::Basename) perl(LWP::UserAgent) perl(Mojo::Base) 
perl(Mojo::ByteStream) perl(Mojo::IOLoop) perl(Mojo::JSON) perl(Mojo::Pg) 
perl(Mojo::URL) perl(Mojo::Util) perl(Mojolicious::Commands) 
perl(Mojolicious::Plugin) perl(Mojolicious::Plugin::RenderFile) 
perl(Mojolicious::Static) perl(Net::OpenID::Consumer) perl(POSIX) 
perl(Sort::Versions) perl(URI::Escape) perl(XML::Writer) perl(base) 
perl(constant) perl(diagnostics) perl(strict) perl(warnings) shadow 
rubygem(sass) perl(Net::DNS) perl(LWP::Protocol::https) perl(Digest::SHA) 
perl(Config::IniFiles)
 %define build_requires %{assetpack_requires} rubygem(sass) tidy sysuser-shadow 
sysuser-tools
 Name:           MirrorCache
-Version:        1.051
+Version:        1.052
 Release:        0
 Summary:        WebApp to redirect and manage mirrors
 License:        GPL-2.0-or-later

++++++ MirrorCache-1.051.obscpio -> MirrorCache-1.052.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/MirrorCache-1.051/assets/javascripts/browse.js 
new/MirrorCache-1.052/assets/javascripts/browse.js
--- old/MirrorCache-1.051/assets/javascripts/browse.js  2022-12-29 
10:16:50.000000000 +0100
+++ new/MirrorCache-1.052/assets/javascripts/browse.js  2023-01-12 
09:40:42.000000000 +0100
@@ -8,6 +8,7 @@
         data: 'name',
         className: 'name',
         defaultContent: "",
+        type: "version-string",
         render: function (data, type, row, meta) {
             if(type === 'display'){
                 var d = data;
@@ -76,6 +77,16 @@
         }
     });
 
+    jQuery.extend( jQuery.fn.dataTableExt.oSort, {
+        "version-string-asc" : function (a, b) {
+            return a.localeCompare(b, undefined, { numeric: true, sensitivity: 
'base' });
+        },
+        "version-string-desc" : function (a, b) {
+            return b.localeCompare(a, undefined, { numeric: true, sensitivity: 
'base' });
+        }
+    });
+
+
     var url = $("#browse_api_url").val();
     var table = $('.browsetable');
     var dataTable = table.DataTable({
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/MirrorCache-1.051/lib/MirrorCache/Config.pm 
new/MirrorCache-1.052/lib/MirrorCache/Config.pm
--- old/MirrorCache-1.051/lib/MirrorCache/Config.pm     2022-12-29 
10:16:50.000000000 +0100
+++ new/MirrorCache-1.052/lib/MirrorCache/Config.pm     2023-01-12 
09:40:42.000000000 +0100
@@ -34,6 +34,9 @@
 has redirect     => $ENV{MIRRORCACHE_REDIRECT};
 has redirect_vpn => $ENV{MIRRORCACHE_REDIRECT_VPN};
 
+has redirect_huge  => $ENV{MIRRORCACHE_REDIRECT_HUGE};
+has huge_file_size => int($ENV{MIRRORCACHE_HUGE_FILE_SIZE} // 0) || 
40*1024*1024;
+
 has plugin_status => $ENV{MIRRORCACHE_PLUGIN_STATUS};
 
 has db_provider           => undef;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/MirrorCache-1.051/lib/MirrorCache/Schema/ResultSet/Folder.pm 
new/MirrorCache-1.052/lib/MirrorCache/Schema/ResultSet/Folder.pm
--- old/MirrorCache-1.051/lib/MirrorCache/Schema/ResultSet/Folder.pm    
2022-12-29 10:16:50.000000000 +0100
+++ new/MirrorCache-1.052/lib/MirrorCache/Schema/ResultSet/Folder.pm    
2023-01-12 09:40:42.000000000 +0100
@@ -375,4 +375,31 @@
     $self->delete_cascade($id, 1);
 }
 
+sub add_redirect {
+    my ($self, $pathfrom, $pathto) = @_;
+
+    my $rsource = $self->result_source;
+    my $schema  = $rsource->schema;
+    my $dbh     = $schema->storage->dbh;
+
+    my $sql;
+if ($dbh->{Driver}->{Name} eq 'Pg') {
+    $sql = <<'END_SQL';
+insert into redirect(pathfrom, pathto)
+values (?, ?)
+on conflict(pathfrom) do update set
+pathto = ?
+END_SQL
+} else {
+    $sql = <<'END_SQL';
+insert into redirect(pathfrom, pathto)
+values (?, ?)
+on duplicate key update
+pathto = ?
+END_SQL
+}
+    my $prep = $dbh->prepare($sql);
+    $prep->execute($pathfrom, $pathto, $pathto);
+}
+
 1;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/MirrorCache-1.051/lib/MirrorCache/Schema/ResultSet/Stat.pm 
new/MirrorCache-1.052/lib/MirrorCache/Schema/ResultSet/Stat.pm
--- old/MirrorCache-1.051/lib/MirrorCache/Schema/ResultSet/Stat.pm      
2022-12-29 10:16:50.000000000 +0100
+++ new/MirrorCache-1.052/lib/MirrorCache/Schema/ResultSet/Stat.pm      
2023-01-12 09:40:42.000000000 +0100
@@ -254,4 +254,13 @@
     return ($id, \@folder_ids, \@country_list);
 }
 
+sub secure_max_id {
+    my ($self, $prev_stat_id) = @_;
+    my $max_id = $self->get_column("id")->max;
+
+    $prev_stat_id = $max_id - 100000 if !$prev_stat_id || $max_id - 
$prev_stat_id > 10000 || $prev_stat_id > $max_id;
+    $prev_stat_id = 0 if $prev_stat_id < 0;
+    return $prev_stat_id;
+}
+
 1;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/MirrorCache-1.051/lib/MirrorCache/Task/Cleanup.pm 
new/MirrorCache-1.052/lib/MirrorCache/Task/Cleanup.pm
--- old/MirrorCache-1.051/lib/MirrorCache/Task/Cleanup.pm       2022-12-29 
10:16:50.000000000 +0100
+++ new/MirrorCache-1.052/lib/MirrorCache/Task/Cleanup.pm       2023-01-12 
09:40:42.000000000 +0100
@@ -34,10 +34,24 @@
     my $schema = $app->schema;
     $minion->enqueue('mirror_probe_projects');
 
-    # purge unreferenced folder_diff
+    # detect stalled backstage jobs
     my $sql;
     if ($schema->pg) {
 $sql = <<'END_SQL';
+update minion_jobs set state = 'failed', result = concat("killed; old result: 
", result) where state = 'active' and started < now() - interval '1 hour'
+END_SQL
+    } else {
+$sql = <<'END_SQL';
+update minion_jobs set state = 'failed', result = concat_ws("", "killed; old 
result: ", result) where state = 'active' and started < now() - interval 2 hour
+END_SQL
+}
+    eval {
+        $schema->storage->dbh->prepare($sql)->execute();
+        1;
+    } or $job->note(last_warning_0 => $@, at_0 => datetime_now());
+
+    if ($schema->pg) {
+$sql = <<'END_SQL';
 with DiffToDelete as (
    select fd.id
    from folder_diff fd
@@ -65,7 +79,7 @@
     eval {
         $schema->storage->dbh->prepare($sql)->execute();
         1;
-    } or $job->note(last_warning => $@, at => datetime_now());
+    } or $job->note(last_warning_1 => $@, at_1 => datetime_now());
 
     # delete rows from server_capability_check to avoid overload
     my $sqlservercap;
@@ -84,7 +98,7 @@
     eval {
         $schema->storage->dbh->prepare($sqlservercap)->execute();
         1;
-    } or $job->note(last_warning => $@, at => datetime_now());
+    } or $job->note(last_warning_2 => $@, at_2 => datetime_now());
 
     # delete rows from audit_event
     my $fail_count;
@@ -92,7 +106,7 @@
     eval {
         ($fail_count, $last_warning) = 
$schema->resultset('AuditEvent')->cleanup_audit_events($app);
         $fail_count ? 0 : 1;
-    } or $job->note(last_warning => $last_warning, delete_fail_count => 
$fail_count, at => datetime_now());
+    } or $job->note(last_warning_3 => $last_warning, delete_fail_count => 
$fail_count, at_3 => datetime_now());
 
     # delete rows from stat
     my $sqlstat;
@@ -111,7 +125,7 @@
     eval {
         $schema->storage->dbh->prepare($sqlservercap)->execute();
         1;
-    } or $job->note(last_warning => $@, at => datetime_now());
+    } or $job->note(last_warning_4 => $@, at_4 => datetime_now());
 
 
     return $job->retry({delay => $DELAY});
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/MirrorCache-1.051/lib/MirrorCache/Task/FolderSync.pm 
new/MirrorCache-1.052/lib/MirrorCache/Task/FolderSync.pm
--- old/MirrorCache-1.051/lib/MirrorCache/Task/FolderSync.pm    2022-12-29 
10:16:50.000000000 +0100
+++ new/MirrorCache-1.052/lib/MirrorCache/Task/FolderSync.pm    2023-01-12 
09:40:42.000000000 +0100
@@ -39,11 +39,13 @@
     my $root   = $app->mc->root;
     $job->note($path => 1);
 
-    my $realpath = $root->realpath($path);
+    my $realpath = $root->realpath($path, 1);
     $realpath = $path unless $realpath;
     if ($realpath ne $path) {
         $job->note(realpath => $realpath);
         $job->note($realpath => 1);
+
+        $schema->resultset('Folder')->add_redirect($path, $realpath);
     }
 
     my $folder = $schema->resultset('Folder')->find({path => $realpath});
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/MirrorCache-1.051/lib/MirrorCache/Task/FolderSyncScheduleFromMisses.pm 
new/MirrorCache-1.052/lib/MirrorCache/Task/FolderSyncScheduleFromMisses.pm
--- old/MirrorCache-1.051/lib/MirrorCache/Task/FolderSyncScheduleFromMisses.pm  
2022-12-29 10:16:50.000000000 +0100
+++ new/MirrorCache-1.052/lib/MirrorCache/Task/FolderSyncScheduleFromMisses.pm  
2023-01-12 09:40:42.000000000 +0100
@@ -46,6 +46,9 @@
     my $schema = $app->schema;
     my $limit = 10000;
 
+    $prev_stat_id = $schema->resultset('Stat')->secure_max_id($prev_stat_id);
+    print(STDERR "$pref id after adjust: $prev_stat_id\n") if $MCDEBUG;
+
     my ($stat_id, $folders, $country_list) = 
$schema->resultset('Stat')->path_misses($prev_stat_id, $limit);
     $common_guard = undef;
     my $rs = $schema->resultset('Folder');
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/MirrorCache-1.051/lib/MirrorCache/Task/MirrorCheckFromStat.pm 
new/MirrorCache-1.052/lib/MirrorCache/Task/MirrorCheckFromStat.pm
--- old/MirrorCache-1.051/lib/MirrorCache/Task/MirrorCheckFromStat.pm   
2022-12-29 10:16:50.000000000 +0100
+++ new/MirrorCache-1.052/lib/MirrorCache/Task/MirrorCheckFromStat.pm   
2023-01-12 09:40:42.000000000 +0100
@@ -45,6 +45,8 @@
 
     my $schema = $app->schema;
 
+    $prev_stat_id = $schema->resultset('Stat')->secure_max_id($prev_stat_id);
+
     my ($stat_id, $mirror_id, $country, $url, $folder, $folder_id) = 
$schema->resultset('Stat')->latest_hit($prev_stat_id);
     my $last_run = 0;
     while ($stat_id && $stat_id > $prev_stat_id) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/MirrorCache-1.051/lib/MirrorCache/Task/MirrorScanScheduleFromMisses.pm 
new/MirrorCache-1.052/lib/MirrorCache/Task/MirrorScanScheduleFromMisses.pm
--- old/MirrorCache-1.051/lib/MirrorCache/Task/MirrorScanScheduleFromMisses.pm  
2022-12-29 10:16:50.000000000 +0100
+++ new/MirrorCache-1.052/lib/MirrorCache/Task/MirrorScanScheduleFromMisses.pm  
2023-01-12 09:40:42.000000000 +0100
@@ -47,6 +47,8 @@
     my $schema = $app->schema;
     my $limit = $prev_stat_id ? 1000 : 10;
 
+    $prev_stat_id = $schema->resultset('Stat')->secure_max_id($prev_stat_id);
+
     my ($stat_id, $folder_ids, $country_list) = 
$schema->resultset('Stat')->mirror_misses($prev_stat_id, $limit);
     $common_guard = undef;
     my $rs = $schema->resultset('Folder');
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/MirrorCache-1.051/lib/MirrorCache/WebAPI/Plugin/Dir.pm 
new/MirrorCache-1.052/lib/MirrorCache/WebAPI/Plugin/Dir.pm
--- old/MirrorCache-1.051/lib/MirrorCache/WebAPI/Plugin/Dir.pm  2022-12-29 
10:16:50.000000000 +0100
+++ new/MirrorCache-1.052/lib/MirrorCache/WebAPI/Plugin/Dir.pm  2023-01-12 
09:40:42.000000000 +0100
@@ -27,13 +27,17 @@
 use MirrorCache::Datamodule;
 
 my $root;
+my $mc_config;
 my @top_folders;
 
+my $MCDEBUG = $ENV{MCDEBUG_DIR} // $ENV{MCDEBUG_ALL} // 0;
+
 sub register {
     my $self = shift;
     my $app = shift;
 
     $root = $app->mc->root;
+    $mc_config = $app->mc->config;
 
     if ($ENV{MIRRORCACHE_TOP_FOLDERS}) {
         @top_folders = split /[:,\s]+/, $ENV{MIRRORCACHE_TOP_FOLDERS};
@@ -167,19 +171,25 @@
 
     my $c = $dm->c;
     # each project may have a redirect defined in DB, so all requests are 
redirected for it
-    my $redirect = $c->mcproject->redirect($path, $dm->region);
-    if ($redirect) {
-        $dm->redirect($dm->scheme . '://' . $redirect . $path);
-        $c->stat->redirect_to_region($dm);
-        return 1;
-    }
+    unless ($trailing_slash) {
+        my $redirect = $c->mcproject->redirect($path, $dm->region);
+        if ($redirect) {
+            $dm->redirect($dm->scheme . '://' . $redirect . $path);
+            $c->stat->redirect_to_region($dm);
+            return 1;
+        }
 
-    my $ln = $root->detect_ln($path);
-    if ($ln) {
-        # redirect to the symlink
-        $dm->redirect($dm->route . $ln);
-        $c->stat->redirect_to_region($dm);
-        return 1;
+        $c->log->error('pedantic: ' . ($dm->pedantic // 'undef')) if $MCDEBUG;
+        if ($path =~ m/.*(Media|Current)\.iso(\.sha256(\.asc)?)?/ && 
$dm->pedantic) {
+            my $ln = $root->detect_ln_in_the_same_folder($path);
+            $c->log->error("ln for $path : " . ($ln // 'null')) if $MCDEBUG;
+            if ($ln) {
+                # redirect to the symlink
+                $c->log->error('redirect detected: ' . $ln) if $MCDEBUG;
+                $dm->redirect($dm->route . $ln);
+                return 1;
+            }
+        }
     }
     return undef if $trailing_slash || $path eq '/' || $dm->mirrorlist;
     return undef if $dm->must_render_from_root;
@@ -278,8 +288,6 @@
     return 1;
 }
 
-my $MCDEBUG = $ENV{MCDEBUG_DIR} // $ENV{MCDEBUG_ALL} // 0;
-
 sub _render_from_db {
     my $dm = shift;
     my $c = $dm->c;
@@ -291,7 +299,8 @@
     $c->log->error($c->dumper('$file_pattern_in_folder', 
$file_pattern_in_folder)) if $MCDEBUG;
     if ( (!$trailing_slash && $path ne '/') || $file_pattern_in_folder ) {
         my $f = Mojo::File->new($path);
-        my $dirname = $root->realpath($file_pattern_in_folder? $path : 
$f->dirname);
+        my $dirname = ($file_pattern_in_folder? $path : $f->dirname);
+        $dirname = $root->realpath($dirname);
         $dirname = $dm->root_subtree . ($file_pattern_in_folder? $path : 
$f->dirname) unless $dirname;
         $c->log->error($c->dumper('dirname:', $dirname)) if $MCDEBUG;
         if (my $parent_folder = $rsFolder->find({path => $dirname})) {
@@ -310,7 +319,7 @@
             my $xtra = '';
             $xtra = '.zsync' if $dm->zsync && !$dm->accept_zsync;
             my $file;
-            $c->log->error($c->dumper('parent_folder:', $parent_folder)) if 
$MCDEBUG;
+            $c->log->error($c->dumper('parent_folder:', $parent_folder->path)) 
if $MCDEBUG;
             $file = 
$schema->resultset('File')->find_with_hash($parent_folder->id, $f->basename, 
$xtra, $dm->regex, $dm->glob_regex) if $parent_folder;
             $c->log->error($c->dumper('file:', $f->basename, $file)) if 
$MCDEBUG;
 
@@ -323,6 +332,12 @@
                     $dm->_path($dm->path . '.zsync');
                     $path = $path . '.zsync';
                 }
+
+                $c->log->error($c->dumper('file_size: ', $file->{size} // 
'undef', 'huge_file_size: ', $mc_config->huge_file_size)) if $MCDEBUG;
+                if ($root->is_remote && !$dm->extra && $file->{size} && 
$mc_config->redirect_huge && $mc_config->huge_file_size <= $file->{size}) {
+                    $dm->redirect($dm->scheme . '://' . 
$mc_config->redirect_huge . $path);
+                    return 1;
+                }
                 if ($file->{target}) {
                     # redirect to the symlink
                     $dm->redirect($dm->route . $dirname . '/' . 
$file->{target});
@@ -335,6 +350,7 @@
             }
         }
     } elsif (my $folder = $rsFolder->find_folder_or_redirect($dm->root_subtree 
. $path)) {
+        $c->log->error('found redirect : ', $folder->{pathto}) if $MCDEBUG && 
$folder->{pathto};
         return $dm->redirect($folder->{pathto}) if $folder->{pathto};
         # folder must have trailing slash, otherwise it will be a challenge to 
render links on webpage
         $dm->folder_id($folder->{id});
@@ -353,6 +369,7 @@
     my ($path, $trailing_slash) = $dm->path;
 
     if ($dm->extra) {
+        $c->log->error('guess what to render extra : ', $dm->extra) if 
$MCDEBUG;
         return $root->render_file($dm, $path) if $dm->accept_all && 
!$trailing_slash;
         # the file is unknown, we cannot show generate meither mirrorlist or 
metalink
         my $res = $c->render(status => 425, text => "The file is unknown, 
retry later");
@@ -373,6 +390,7 @@
     # - redirected to another route => we must redirect it as well
     my $path1 = $path . '/';
     my $url1  = $url  . '/'; # let's check if it is a folder
+    my $redirect;
     $ua->head_p($url1, {'User-Agent' => 
'MirrorCache/guess_what_to_render'})->then(sub {
         my $res = shift->res;
 
@@ -394,7 +412,9 @@
                         if ($rootlocation eq substr($location, 0, 
length($rootlocation))) {
                             $location = substr($location, 
length($rootlocation));
                         }
-                        return $dm->redirect($dm->route . $location . 
$trailing_slash)
+                        $c->log->error('redirect guessed: ' . $location . 
$trailing_slash) if $MCDEBUG;
+                        $redirect = 1;
+                        return $dm->redirect($dm->route . $location . 
$trailing_slash);
                     }
                 }
             }
@@ -412,11 +432,13 @@
         $c->app->log->fatal($msg); # it is not fatal, but needed in production 
log
         my $reftx = $tx;
         my $refua = $ua;
-    })->timeout(2)->wait;
+    })->timeout(5)->then(sub {
+        
$c->backstage->enqueue_unless_scheduled_with_parameter_or_limit('folder_sync', 
$path) if $redirect;
+    })->wait;
 }
 
 sub _by_filename {
-   (($b->{dir} // 0) cmp ($a->{dir} // 0)) ||
+   versioncmp(lc($b->{dir} // ''),  lc($a->{dir} // '')) ||
    versioncmp(lc($a->{name} // ''), lc($b->{name} // ''));
 }
 
@@ -484,31 +506,31 @@
         my $basename = $child->{name};
         my $size     = $child->{size};
         my $mtime    = $child->{mtime};
+        my $desc     = $folderDesc{$c->mcbranding}{$dir}{$basename};
         if ($json) {
             push @files, {
                 name  => $basename,
                 size  => $size,
                 mtime => $mtime,
-                desc  => $folderDesc{$c->mcbranding}{$dir}{$basename},
             };
-            next;
-        }
-        $size        = MirrorCache::Utils::human_readable_size($size) if $size;
-        $mtime       = strftime("%d-%b-%Y %H:%M", gmtime($mtime)) if $mtime;
+        } else {
+            $size        = MirrorCache::Utils::human_readable_size($size) if 
$size;
+            $mtime       = strftime("%d-%b-%Y %H:%M", gmtime($mtime)) if 
$mtime;
 
-        my $is_dir    = '/' eq substr($basename, -1)? 1 : 0;
-        my $encoded   = Encode::decode_utf8( './' . $basename );
-        my $mime_type = $dm->mime || 'text/plain';
+            my $is_dir    = '/' eq substr($basename, -1)? 1 : 0;
+            my $encoded   = Encode::decode_utf8( './' . $basename );
+            my $mime_type = $dm->mime || 'text/plain';
 
-        push @files, {
-            url   => $encoded,
-            name  => $basename,
-            size  => $size,
-            type  => $mime_type,
-            mtime => $mtime,
-            dir   => $is_dir,
-            desc  => $folderDesc{$c->mcbranding}{$dir}{$basename},
-        };
+            push @files, {
+                url   => $encoded,
+                name  => $basename,
+                size  => $size,
+                type  => $mime_type,
+                mtime => $mtime,
+                dir   => $is_dir,
+            };
+        }
+        $files[-1]->{desc} = $desc if $desc;
     }
     my @items = sort _by_filename @files;
     return $c->render( json => { data => \@items } ) if $dm->jsontable;
@@ -536,32 +558,31 @@
         $basename = $basename . '/' if $stat && -d $stat;
         my $size     = $stat->size if $stat;
         my $mtime    = $stat->mtime if $stat;
+        my $desc     = $folderDesc{$c->mcbranding}{$dir}{$basename};
         if ($json) {
             push @files, {
                 name  => $basename,
                 size  => $size,
                 mtime => $mtime,
-                desc  => $folderDesc{$c->mcbranding}{$dir}{$basename},
             };
-            next;
-        }
-
-        $size        = MirrorCache::Utils::human_readable_size($size) if $size;
-        $mtime       = strftime("%d-%b-%Y %H:%M", gmtime($mtime)) if $mtime;
+        } else {
+            $size        = MirrorCache::Utils::human_readable_size($size) if 
$size;
+            $mtime       = strftime("%d-%b-%Y %H:%M", gmtime($mtime)) if 
$mtime;
 
-        my $is_dir    = '/' eq substr($basename, -1)? 1 : 0;
-        my $encoded   = Encode::decode_utf8( './' . $basename );
-        my $mime_type = $dm->mime || 'text/plain';
+            my $is_dir    = '/' eq substr($basename, -1)? 1 : 0;
+            my $encoded   = Encode::decode_utf8( './' . $basename );
+            my $mime_type = $dm->mime || 'text/plain';
 
-        push @files, {
-            url   => $encoded,
-            name  => $basename,
-            size  => $size,
-            type  => $mime_type,
-            mtime => $mtime,
-            dir   => $is_dir,
-            desc  => $folderDesc{$c->mcbranding}{$dir}{$basename},
-        };
+            push @files, {
+                url   => $encoded,
+                name  => $basename,
+                size  => $size,
+                type  => $mime_type,
+                mtime => $mtime,
+                dir   => $is_dir,
+            };
+        }
+        $files[-1]->{desc} = $desc if $desc;
     }
     my @items = sort _by_filename @files;
     return $c->render( json => { data => \@items } ) if $dm->jsontable;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/MirrorCache-1.051/lib/MirrorCache/WebAPI/Plugin/RenderFileFromMirror.pm 
new/MirrorCache-1.052/lib/MirrorCache/WebAPI/Plugin/RenderFileFromMirror.pm
--- old/MirrorCache-1.051/lib/MirrorCache/WebAPI/Plugin/RenderFileFromMirror.pm 
2022-12-29 10:16:50.000000000 +0100
+++ new/MirrorCache-1.052/lib/MirrorCache/WebAPI/Plugin/RenderFileFromMirror.pm 
2023-01-12 09:40:42.000000000 +0100
@@ -29,6 +29,7 @@
 use Mojo::IOLoop::Subprocess;
 
 my $MCDEBUG = $ENV{MCDEBUG_RENDER_FILE_FROM_MIRROR} // $ENV{MCDEBUG_ALL} // 0;
+my $mc_config;
 
 sub register {
     my ($self, $app) = @_;
@@ -39,6 +40,7 @@
     $app->helper( 'mirrorcache.render_file' => sub {
         my ($c, $filepath, $dm, $file)= @_;
         $c->log->error($c->dumper('RENDER START', $filepath)) if $MCDEBUG;
+        $mc_config = $app->mc->config;
         my $root = $c->mc->root;
         my $f = Mojo::File->new($filepath);
         my $dirname = $f->dirname;
@@ -111,7 +113,13 @@
         my $baseurl; # just hostname + eventual urldir (without folder and 
file)
         my $fullurl; # baseurl with path and filename
         if ($dm->metalink || $dm->meta4 || $dm->torrent || $dm->zsync || 
$dm->magnet) {
-           $baseurl = $root->is_remote ? $root->location($dm) : 
$root->redirect($dm, $dirname) # we must pass $path here because it potenially 
has impact
+           if (!$root->is_remote) {
+                $baseurl = $root->redirect($dm, $dirname); # we must pass 
$path here because it potenially has impact
+            } elsif ($file->{size} && $mc_config->redirect_huge && 
$mc_config->huge_file_size <= $file->{size}) {
+                $baseurl = $dm->scheme . '://' . $mc_config->redirect_huge . 
$filepath;
+            } else {
+                $baseurl = $root->location($dm);
+            }
         }
         if ($dm->torrent || $dm->zsync || $dm->magnet) {
             if ($baseurl) {
@@ -245,7 +253,11 @@
                 $fileorigin = $ENV{MIRRORCACHE_METALINK_PUBLISHER_URL};
                 $fileorigin = $dm->scheme . "://" . $fileorigin unless 
$fileorigin =~ m/^http/;
             } elsif ($root->is_remote) {
-                $fileorigin = $root->location($dm);
+                if ($file->{size} && $mc_config->redirect_huge && 
$mc_config->huge_file_size <= $file->{size}) {
+                    $fileorigin = $dm->scheme . '://' . 
$mc_config->redirect_huge;
+                } else {
+                    $fileorigin = $root->location($dm);
+                }
             } else {
                 my $redirect = $root->redirect($dm, $filepath);
                 if ($redirect) {
@@ -590,7 +602,7 @@
                 return if $root_included and !$print;
 
                 $writer->comment("File origin location: ") if $print;
-                if ($METALINK_GREEDY && $METALINK_GREEDY <= (100 - 
$preference)) {
+                if ($METALINK_GREEDY && $METALINK_GREEDY <= (100 - 
$preference) || $root_included) {
                     $writer->comment($rooturl . $fullname);
                 } else {
                     $writer->startTag('url', type => 
substr($rooturl,0,$colon), location => uc($dm->root_country), preference => 
$preference);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/MirrorCache-1.051/lib/MirrorCache/WebAPI/Plugin/RootLocal.pm 
new/MirrorCache-1.052/lib/MirrorCache/WebAPI/Plugin/RootLocal.pm
--- old/MirrorCache-1.051/lib/MirrorCache/WebAPI/Plugin/RootLocal.pm    
2022-12-29 10:16:50.000000000 +0100
+++ new/MirrorCache-1.052/lib/MirrorCache/WebAPI/Plugin/RootLocal.pm    
2023-01-12 09:40:42.000000000 +0100
@@ -31,6 +31,8 @@
 my $root_subtree = $ENV{MIRRORCACHE_SUBTREE} // "";
 
 has 'urlredirect';
+has 'urlredirect_huge';
+has 'huge_file_size';
 
 sub register {
     (my $self, $app) = @_;
@@ -42,6 +44,9 @@
     }
 
     $self->urlredirect($app->mcconfig->redirect);
+    $self->urlredirect_huge($app->mcconfig->redirect_huge);
+    $self->huge_file_size($app->mcconfig->huge_file_size);
+
     $app->helper( 'mc.root' => sub { $self; });
 }
 
@@ -106,10 +111,15 @@
     $filepath = "" unless $filepath;
     for my $root (@roots) {
         next unless ( -e $root->[dir] . $root_subtree . $filepath || ( 
$root_subtree && ( -e $root->[dir] . $filepath  ) ) );
+        if ($self->urlredirect_huge) {
+            my $size = -s $root->[dir] . $filepath;
+            return $dm->scheme . "://" . $self->urlredirect_huge if (($size // 
0) >= $self->huge_file_size);
+        }
+
         return $dm->scheme . "://" . $root->[host_vpn] if ($dm->vpn && 
$root->[host_vpn]);
         return $dm->scheme . "://" . $root->[host] if ($root->[host]);
         return $dm->scheme . "://" . $self->urlredirect if 
($self->urlredirect);
-        return undef;
+        last;
     }
     return undef;
 }
@@ -149,7 +159,7 @@
     }
 }
 
-sub _detect_ln {
+sub _detect_ln_in_the_same_folder {
     my ($dir, $file) = @_;
     return undef unless $file && $file =~ m/.*(Media|Current)\.iso(\.sha256)?/;
 
@@ -167,10 +177,10 @@
     return undef;
 }
 
-sub detect_ln {
+sub detect_ln_in_the_same_folder {
     my ($self, $path) = @_;
     my $f = Mojo::File->new($path);
-    my $res = _detect_ln($f->dirname, $f->basename);
+    my $res = _detect_ln_in_the_same_folder($f->dirname, $f->basename);
     return undef unless $res;
     return $f->dirname . '/' . $res;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/MirrorCache-1.051/lib/MirrorCache/WebAPI/Plugin/RootRemote.pm 
new/MirrorCache-1.052/lib/MirrorCache/WebAPI/Plugin/RootRemote.pm
--- old/MirrorCache-1.051/lib/MirrorCache/WebAPI/Plugin/RootRemote.pm   
2022-12-29 10:16:50.000000000 +0100
+++ new/MirrorCache-1.052/lib/MirrorCache/WebAPI/Plugin/RootRemote.pm   
2023-01-12 09:40:42.000000000 +0100
@@ -18,6 +18,7 @@
 use Mojo::Base 'Mojolicious::Plugin';
 use Mojo::Util ('trim');
 use Encode ();
+use Mojo::JSON qw(decode_json);
 use URI::Escape ('uri_unescape');
 use File::Basename;
 use HTML::Parser;
@@ -60,17 +61,39 @@
 }
 
 sub realpath {
-    return undef unless $nfs;
-
-    my ($self, $path) = @_;
+    my ($self, $path, $deep) = @_;
     return undef unless $path;
 
-    my $localpath = $nfs . $path;
-    my $realpathlocal = Cwd::realpath($localpath);
-
-    if ($realpathlocal && (0 == rindex($realpathlocal, $nfs, 0))) {
-        my $realpath = substr($realpathlocal, length($nfs));
-        return $realpath if $realpath ne $path;
+    if ($nfs) {
+        my $localpath = $nfs . $path;
+        my $realpathlocal = Cwd::realpath($localpath);
+
+        if ($realpathlocal && (0 == rindex($realpathlocal, $nfs, 0))) {
+            my $realpath = substr($realpathlocal, length($nfs));
+            return $realpath if $realpath ne $path;
+        }
+    } elsif ($deep) {
+        my $path1 = $path . '/';
+        my $rootlocation = $self->rooturl;
+        my $url = $rootlocation . $path1;
+        my $ua = Mojo::UserAgent->new->max_redirects(0)->request_timeout(1);
+        my $tx = $ua->head($url, {'User-Agent' => 
'MirrorCache/detect_redirect'});
+        my $res = $tx->res;
+
+        # redirect on oneself
+        if ($res->is_redirect && $res->headers) {
+            my $location1 = $res->headers->location;
+            if ($location1 && $path1 ne substr($location1, -length($path1))) {
+                my $i = rindex($location1, $rootlocation, 0);
+                if ($i ne -1) {
+                    # remove trailing slash we added earlier
+                    my $location = substr($location1, 0, -1);
+                    if ($rootlocation eq substr($location, 0, 
length($rootlocation))) {
+                        return substr($location, length($rootlocation));
+                    }
+                }
+            }
+        }
     }
     return undef;
 }
@@ -148,10 +171,28 @@
     return 1;
 };
 
-sub _detect_ln {
-    return undef unless $nfs;
-    my ($dir, $file) = @_;
-    return undef unless $file && $file =~ m/.*(Media|Current)\.iso(\.sha256)?/;
+sub _detect_ln_in_the_same_folder {
+    my ($self, $dir, $file) = @_;
+
+    unless ($nfs) {
+        my $dir1 = $dir . '/';
+        my $rootlocation = $self->rooturl;
+        my $url = $rootlocation . $dir1 . $file;
+        my $ua = Mojo::UserAgent->new->max_redirects(0)->request_timeout(2);
+        my $tx = $ua->head($url, {'User-Agent' => 
'MirrorCache/detect_redirect'});
+        my $res = $tx->res;
+
+        # redirect on oneself
+        if ($res->is_redirect && $res->headers) {
+            my $location = $res->headers->location;
+            my $url1 = $rootlocation . $dir1;
+            if ($location && $url1 eq substr($location, 0, length($url1))) {
+                my $ln = substr($location, length($url1));
+                return $ln if -1 == index($ln, '/');
+            }
+        }
+        return undef;
+    }
 
     my $dest;
     eval {
@@ -168,11 +209,11 @@
     return $res;
 }
 
-sub detect_ln {
-    return undef unless $nfs;
+# this is simillar to self->realpath, just detects symlinks in current folder
+sub detect_ln_in_the_same_folder {
     my ($self, $path) = @_;
     my $f = Mojo::File->new($path);
-    my $res = _detect_ln($f->dirname, $f->basename);
+    my $res = $self->_detect_ln_in_the_same_folder($f->dirname, $f->basename);
     return undef unless $res;
     return $f->dirname . '/' . $res;
 }
@@ -191,10 +232,23 @@
         return 1;
     }
     my $ua   = Mojo::UserAgent->new;
-    my $tx   = $ua->get($self->rooturl . $dir . '/?F=1');
+    my $tx   = $ua->get($self->rooturl . $dir . '/?F=1&json');
     return 0 unless $tx->result->code == 200;
-    # we cannot use mojo dom here because it takes too much RAM for huge html
-    # my $dom = $tx->result->dom;
+
+    return $self->_foreach_filename_json($dir, $sub, $P, $ua, $tx) if -1 < 
index($tx->result->headers->content_type, 'json');
+
+    return $self->_foreach_filename_html($dir, $sub, $P, $ua, $tx);
+}
+
+# we cannot use mojo dom here because it takes too much RAM for huge html
+# my $dom = $tx->result->dom;
+sub _foreach_filename_html {
+    my $self = shift;
+    my $dir  = shift;
+    my $sub  = shift;
+    my $P    = shift;
+    my $ua   = shift;
+    my $tx   = shift;
 
     my $href = '';
     my $href20 = '';
@@ -222,7 +276,7 @@
 
         if ($t && ($href20 eq substr($t,0,20))) {
             if ($desc{name} && (!$P || $desc{name} =~ $P)) {
-                my $target = _detect_ln($dir, $desc{name});
+                my $target = $self->_detect_ln_in_the_same_folder($dir, 
$desc{name});
                 $sub->($desc{name}, $desc{size}, undef, $desc{mtime}, $target);
                 %desc = ();
             }
@@ -263,7 +317,7 @@
         $p->parse($chunk);
     }
     if ($desc{name} && (!$P || $desc{name} =~ $P)) {
-        my $target = detect_ln($dir, $desc{name});
+        my $target = $self->_detect_ln_in_the_same_folder($dir, $desc{name});
         $sub->($desc{name}, $desc{size}, undef, $desc{mtime}, $target);
         %desc = ();
     }
@@ -271,4 +325,32 @@
     return 1;
 }
 
+sub _foreach_filename_json {
+    my $self = shift;
+    my $dir  = shift;
+    my $sub  = shift;
+    my $P    = shift;
+    my $ua   = shift;
+    my $tx   = shift;
+
+    my $cnt = 0;
+
+    my $value = decode_json $tx->result->body;
+    die "JSON top level is not array" unless ref($value) eq 'ARRAY';
+
+    for my $hashref (@{$value}) {
+        my $n = $hashref->{name} // $hashref->{n};
+        $n = $n . '/' if $hashref->{type} // '' eq 'directory' && '/' ne 
substr $n, -1;
+        next unless $n;
+        $sub->(
+            $n,
+            $hashref->{size}  // $hashref->{s},
+            undef,
+            $hashref->{mtime} // $hashref->{m},
+        ) if $sub;
+        $cnt++;
+    }
+    return $cnt;
+}
+
 1;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/MirrorCache-1.051/t/environ/02-files.sh 
new/MirrorCache-1.052/t/environ/02-files.sh
--- old/MirrorCache-1.051/t/environ/02-files.sh 2022-12-29 10:16:50.000000000 
+0100
+++ new/MirrorCache-1.052/t/environ/02-files.sh 2023-01-12 09:40:42.000000000 
+0100
@@ -93,7 +93,8 @@
 # first request will miss
 $mc/curl -I /download/folder1/file3.1.dat | grep 200
 
-$mc/backstage/job folder_sync_schedule_from_misses
+# pass too big value for prev_stat_id and make sure it is automatically 
adjusted
+$mc/backstage/job -e folder_sync_schedule_from_misses -a '["1000000"]'
 $mc/backstage/job folder_sync_schedule
 $mc/backstage/shoot
 $mc/backstage/job mirror_scan_schedule
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/MirrorCache-1.051/t/environ/03-headquarter-subsidiaries-remote.sh 
new/MirrorCache-1.052/t/environ/03-headquarter-subsidiaries-remote.sh
--- old/MirrorCache-1.051/t/environ/03-headquarter-subsidiaries-remote.sh       
2022-12-29 10:16:50.000000000 +0100
+++ new/MirrorCache-1.052/t/environ/03-headquarter-subsidiaries-remote.sh       
2023-01-12 09:40:42.000000000 +0100
@@ -1,22 +1,25 @@
 #!lib/test-in-container-environ.sh
 set -ex
 
-# root : ap9
+# root : ng9
 
 # mc environ by number:
 # 9 - headquarter
 # 6 - NA subsidiary
 # 7 - EU subsidiary
 
-root=$(environ ap9)
+root=$(environ ng9)
 
 mkdir -p $root/dt/{folder1,folder2,folder3}
 echo $root/dt/{folder1,folder2,folder3}/{file1.1,file2.1}.dat | xargs -n 1 
touch
 mkdir $root/dt/folder1/repodata/
 touch $root/dt/folder1/repodata/file1.dat
 SMALL_FILE_SIZE=3
+HUGE_FILE_SIZE=9
+FAKEURL="notexists${RANDOM}.com"
 echo -n 1234 > $root/dt/folder1/repodata/filebig1.1.dat
 echo -n 123  > $root/dt/folder1/repodata/filesmall1.1.dat
+echo -n 123456789 > $root/dt/folder1/repodata/filehuge1.1.dat
 echo repomdcontent > $root/dt/folder1/repodata/repomd.xml
 touch $root/dt/folder1/repodata/repomd.xml.asc
 
@@ -26,6 +29,8 @@
 $mc9/gen_env "MIRRORCACHE_TOP_FOLDERS='folder1 folder2 folder3'" \
     MIRRORCACHE_SCHEDULE_RETRY_INTERVAL=0 \
     MIRRORCACHE_ROOT=http://$($root/print_address) \
+    MIRRORCACHE_REDIRECT_HUGE=$FAKEURL \
+    MIRRORCACHE_HUGE_FILE_SIZE=$HUGE_FILE_SIZE \
     MIRRORCACHE_SMALL_FILE_SIZE=$SMALL_FILE_SIZE \
     MIRRORCACHE_ROOT_NFS=$root/dt
 
@@ -41,6 +46,7 @@
 $mc9/backstage/shoot
 
 hq_address=$(mc9/print_address)
+hq_interface=127.0.0.10
 eu_interface=127.0.0.3
 
 # repodata/repomd.xml is served from root even when asked from EU
@@ -56,9 +62,19 @@
 curl -sI --interface 127.0.0.24    http://$hq_address/geoip     | grep '204 No 
Content'
 
 $mc9/db/start
-$mc9/curl --interface 127.0.0.5 /folder1/repodata/file1.dat.metalink | grep 
'origin="http://127.0.0.1:3190/folder1/repodata/file1.dat.metalink";'
+$mc9/curl --interface $hq_interface /folder1/repodata/file1.dat.metalink | 
grep 'origin="http://127.0.0.1:3190/folder1/repodata/file1.dat.metalink";'
 
-# filebig is redirected to EU
+echo filebig is redirected to EU
 $mc9/curl -I --interface $eu_interface /folder1/repodata/filebig1.1.dat | grep 
'302 Found'
-# filesmall is served right away
+echo filesmall is served right away
 $mc9/curl -I --interface $eu_interface /folder1/repodata/filesmall1.1.dat | 
grep '200 OK'
+
+echo check huge files are redirected to FAKEURL, but we need to scan folder 
first
+$mc9/curl -I --interface $hq_interface 
/download/folder1/repodata/filehuge1.1.dat | grep "Location: 
http://$FAKEURL/folder1/repodata/filehuge1.1.dat";
+$mc9/curl -I --interface $hq_interface 
/download/folder1/repodata/filebig1.1.dat | grep "Location: " | grep 
$($root/print_address)
+
+$mc9/curl --interface $hq_interface 
/download/folder1/repodata/filehuge1.1.dat.meta4 | grep 
"http://$FAKEURL/folder1/repodata/filehuge1.1.dat";
+$mc9/curl --interface $hq_interface 
/download/folder1/repodata/filehuge1.1.dat.mirrorlist | grep 
"http://$FAKEURL/folder1/repodata/filehuge1.1.dat";
+
+echo success
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/MirrorCache-1.051/t/environ/03-headquarter-subsidiaries-weight.sh 
new/MirrorCache-1.052/t/environ/03-headquarter-subsidiaries-weight.sh
--- old/MirrorCache-1.051/t/environ/03-headquarter-subsidiaries-weight.sh       
2022-12-29 10:16:50.000000000 +0100
+++ new/MirrorCache-1.052/t/environ/03-headquarter-subsidiaries-weight.sh       
2023-01-12 09:40:42.000000000 +0100
@@ -52,7 +52,7 @@
 
 # do requests and check that both na instances are being used and instance 2 
is used more frequently
 out=$(
-counter=30
+counter=180
 
 while test $counter -gt 0
 do
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/MirrorCache-1.051/t/environ/03-headquarter-subsidiaries.sh 
new/MirrorCache-1.052/t/environ/03-headquarter-subsidiaries.sh
--- old/MirrorCache-1.051/t/environ/03-headquarter-subsidiaries.sh      
2022-12-29 10:16:50.000000000 +0100
+++ new/MirrorCache-1.052/t/environ/03-headquarter-subsidiaries.sh      
2023-01-12 09:40:42.000000000 +0100
@@ -8,17 +8,21 @@
 # 8 - ASIA subsidiary
 
 SMALL_FILE_SIZE=3
+HUGE_FILE_SIZE=9
+FAKEURL="notexists${RANDOM}.com"
 
 for i in 6 7 8 9; do
     x=$(environ mc$i $(pwd))
     mkdir -p $x/dt/{folder1,folder2,folder3}
     echo -n 1234 > $x/dt/folder1/filebig1.1.dat
     echo -n 123  > $x/dt/folder1/filesmall1.1.dat
+    echo -n 123456789 > $x/dt/folder1/filehuge1.1.dat
     echo '[]'    > $x/dt/folder1/file.json
     eval mc$i=$x
 done
 
 hq_address=$($mc9/print_address)
+hq_interface=127.0.0.10
 na_address=$($mc6/print_address)
 na_interface=127.0.0.2
 eu_address=$($mc7/print_address)
@@ -28,6 +32,8 @@
 
 # deploy db
 $mc9/gen_env MIRRORCACHE_TOP_FOLDERS='folder1 folder2 folder3' \
+             MIRRORCACHE_HUGE_FILE_SIZE=$HUGE_FILE_SIZE \
+             MIRRORCACHE_REDIRECT_HUGE=$FAKEURL \
              MIRRORCACHE_SMALL_FILE_SIZE=$SMALL_FILE_SIZE
 
 $mc9/backstage/shoot
@@ -75,6 +81,9 @@
 curl --interface $na_interface -Is 
http://$hq_address/download/folder1/filebig1.1.dat | grep "Location: 
http://$na_address/download/folder1/filebig1.1.dat";
 curl --interface $na_interface -Is 
http://$hq_address/download/folder1/filesmall1.1.dat | grep "200 OK"
 
+echo check huge files are redirected to FAKEURL
+curl --interface $hq_interface -Is 
http://$hq_address/download/folder1/filehuge1.1.dat | grep "Location: 
http://$FAKEURL/folder1/filehuge1.1.dat";
+
 ct=$($mc9/curl -I /download/folder1/file.json | grep Content-Type)
 [[ "$ct" =~ application/json ]]
 ct=$($mc9/curl -I /folder1/file.json | grep Content-Type)
@@ -96,4 +105,11 @@
 echo unless /download is asked explicitly
 $mc9/curl -H 'User-Agent: Chromium/xyz' /download/folder1/ | grep file.json
 
+echo check metalink/mirrorlist for huge files reference FAKEURL, but need to 
scan them first
+$mc9/backstage/job -e folder_sync_schedule_from_misses
+$mc9/backstage/job -e folder_sync_schedule
+$mc9/backstage/shoot
+curl --interface $hq_interface -s 
http://$hq_address/download/folder1/filehuge1.1.dat.metalink   | grep 
"http://$FAKEURL/folder1/filehuge1.1.dat";
+curl --interface $hq_interface -s 
http://$hq_address/download/folder1/filehuge1.1.dat.mirrorlist | grep 
"http://$FAKEURL/folder1/filehuge1.1.dat";
+
 echo success
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/MirrorCache-1.051/t/environ/04-remote-current-no-nfs.sh 
new/MirrorCache-1.052/t/environ/04-remote-current-no-nfs.sh
--- old/MirrorCache-1.051/t/environ/04-remote-current-no-nfs.sh 1970-01-01 
01:00:00.000000000 +0100
+++ new/MirrorCache-1.052/t/environ/04-remote-current-no-nfs.sh 2023-01-12 
09:40:42.000000000 +0100
@@ -0,0 +1,69 @@
+#!lib/test-in-container-environ.sh
+set -ex
+
+mc=$(environ mc $(pwd))
+
+ap9=$(environ ap9)
+
+$mc/gen_env \
+    MIRRORCACHE_SCHEDULE_RETRY_INTERVAL=0 \
+    MIRRORCACHE_ROOT=http://$($ap9/print_address) \
+
+ap8=$(environ ap8)
+ap7=$(environ ap7)
+
+for x in $ap7 $ap8 $ap9; do
+    mkdir -p $x/dt/{folder1,folder2,folder3}
+    echo $x/dt/{folder1,folder2,folder3}/{file1.1,file2.1}-Media.iso | xargs 
-n 1 touch
+    sha256sum $x/dt/folder1/file1.1-Media.iso > 
$x/dt/folder1/file1.1-Media.iso.sha256
+    echo 111112 > $x/dt/folder1/file2.1-Media.iso
+    sha256sum $x/dt/folder1/file2.1-Media.iso > 
$x/dt/folder1/file2.1-Media.iso.sha256
+    ( cd $x/dt/folder1 && ln -s file1.1-Media.iso file-Media.iso && ln -s 
file1.1-Media.iso.sha256 file-Media.iso.sha256 )
+done
+
+echo '    RewriteEngine On
+    RewriteBase "/"
+    RewriteRule ^folder1/file-Media.iso(.*)?$ folder1/file1.1-Media.iso$1 [R]
+' > $ap9/directory-rewrite.conf
+
+echo 'LoadModule rewrite_module    /usr/lib64/apache2-prefork/mod_rewrite.so' 
> $ap9/extra-rewrite.conf
+
+for x in $ap7 $ap8 $ap9; do
+    $x/start
+done
+
+$mc/start
+$mc/status
+
+$mc/sql "insert into server(hostname,urldir,enabled,country,region) select 
'$($ap7/print_address)','','t','us','na'"
+$mc/sql "insert into server(hostname,urldir,enabled,country,region) select 
'$($ap8/print_address)','','t','us','na'"
+
+$mc/backstage/job -e folder_sync -a '["/folder1"]'
+$mc/backstage/shoot
+
+
+$mc/sql "select * from file"
+
+################################################
+# Test unversioned Media.iso is redirected to file which is metioned inside 
corresponding Media.iso.sha256
+$mc/curl -I /download/folder1/file-Media.iso        | grep -C 10 302 | grep 
/download/folder1/file1.1-Media.iso
+$mc/curl -I /download/folder1/file-Media.iso.sha256 | grep -C 10 302 | grep 
/download/folder1/file1.1-Media.iso.sha256
+$mc/curl -L /download/folder1/file-Media.iso.sha256 | grep -q 
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855  "
+
+echo now change the symlink and make sure redirect changes
+echo '    RewriteEngine On
+    RewriteBase "/"
+    RewriteRule ^folder1/file-Media.iso(.*)?$ folder1/file2.1-Media.iso$1 [R]
+' > $ap9/directory-rewrite.conf
+
+$ap9/stop
+$ap9/start
+
+$mc/backstage/job -e folder_sync -a '["/folder1"]'
+$mc/backstage/shoot
+$mc/curl -I /download/folder1/file-Media.iso        | grep -C 10 302 | grep 
/download/folder1/file2.1-Media.iso
+$mc/curl -I /download/folder1/file-Media.iso.sha256 | grep -C 10 302 | grep 
/download/folder1/file2.1-Media.iso.sha256
+$mc/curl -L /download/folder1/file-Media.iso.sha256 | grep -q 
"2019dd7afaf5759c68cec4d0e7553227657f01c69da168489116a1c48e40270e  "
+
+echo success
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/MirrorCache-1.051/t/environ/04-remote-link.sh 
new/MirrorCache-1.052/t/environ/04-remote-link.sh
--- old/MirrorCache-1.051/t/environ/04-remote-link.sh   2022-12-29 
10:16:50.000000000 +0100
+++ new/MirrorCache-1.052/t/environ/04-remote-link.sh   2023-01-12 
09:40:42.000000000 +0100
@@ -1,7 +1,7 @@
 #!lib/test-in-container-environ.sh
 set -ex
 
-mc=$(environ mc $(pwd))
+mc=$(environ mc9 $(pwd))
 
 ap9=$(environ ap9)
 
@@ -17,7 +17,6 @@
     echo $x/dt/{folder1,folder2,folder3}/{file1.1,file2.1}.dat | xargs -n 1 
touch
 done
 
-ln -s $ap9/dt/folder1 $ap9/dt/link
 echo '    RewriteEngine On
     RewriteBase "/"
     RewriteRule ^link(/.*)?$ folder1$1 [R]
@@ -54,6 +53,7 @@
 $mc/backstage/job folder_sync_schedule
 $mc/backstage/shoot
 $mc/sql_test 2 == "select count(*) from minion_jobs where task = 
'folder_sync_schedule_from_misses' and state = 'finished'"
+$mc/sql_test 1 == "select count(*) from redirect"
 $mc/curl -I /download/link
 $mc/curl -I /download/link | grep -A4 -E '301|302' | grep ': /download/folder1'
 $mc/backstage/job folder_sync_schedule_from_misses
@@ -62,3 +62,22 @@
 $mc/sql_test 3 == "select count(*) from minion_jobs where task = 
'folder_sync_schedule_from_misses' and state = 'finished'"
 $mc/curl -I /download/link
 $mc/curl -I /download/link | grep -A4 -E '301|302' | grep ': /download/folder1'
+
+
+echo now change redirect from /link on remote to /folder2
+
+echo '    RewriteEngine On
+    RewriteBase "/"
+    RewriteRule ^link(/.*)?$ folder2$1 [R]
+' > $ap9/directory-rewrite.conf
+
+$ap9/stop
+$ap9/start
+
+$mc/backstage/job folder_sync_schedule
+$mc/backstage/shoot
+
+$mc/curl -I /download/link
+$mc/curl -I /download/link | grep -A4 -E '301|302' | grep ': /download/folder2'
+
+echo success
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/MirrorCache-1.051/t/environ/04-remote-mc.sh 
new/MirrorCache-1.052/t/environ/04-remote-mc.sh
--- old/MirrorCache-1.051/t/environ/04-remote-mc.sh     1970-01-01 
01:00:00.000000000 +0100
+++ new/MirrorCache-1.052/t/environ/04-remote-mc.sh     2023-01-12 
09:40:42.000000000 +0100
@@ -0,0 +1,223 @@
+#!lib/test-in-container-environ.sh
+set -ex
+
+mc=$(environ mc $(pwd))
+
+# we name it the same way as in test 04-remote-nginx.sh to simplify diff
+ng9=$(environ mc2 $(pwd))
+
+MIRRORCACHE_SCHEDULE_RETRY_INTERVAL=0
+
+$mc/gen_env MIRRORCACHE_PEDANTIC=1 \
+    MIRRORCACHE_ROOT=http://$($ng9/print_address)/download \
+    MIRRORCACHE_SCHEDULE_RETRY_INTERVAL=$MIRRORCACHE_SCHEDULE_RETRY_INTERVAL
+
+ng8=$(environ ng8)
+ng7=$(environ ng7)
+
+for x in $ng7 $ng8 $ng9; do
+    mkdir -p $x/dt/{folder1,folder2,folder3}
+    echo $x/dt/{folder1,folder2,folder3}/{file1.1,file2.1}.dat | xargs -n 1 
touch
+    echo -n 0123456789 > $x/dt/folder1/file2.1.dat
+    $x/start
+done
+
+$mc/start
+$mc/status
+
+$mc/sql "insert into server(hostname,urldir,enabled,country,region) select 
'$($ng7/print_address)','','t','us','na'"
+$mc/sql "insert into server(hostname,urldir,enabled,country,region) select 
'$($ng8/print_address)','','t','us','na'"
+
+# remove folder1/file1.1.dt from ng8
+rm $ng8/dt/folder1/file2.1.dat
+
+# first request redirected to root
+$mc/curl -I /download/folder1/file2.1.dat | grep $($ng9/print_address)
+
+$mc/backstage/job folder_sync_schedule_from_misses
+$mc/backstage/job folder_sync_schedule
+$mc/backstage/shoot
+$mc/backstage/job mirror_scan_schedule
+$mc/backstage/shoot
+
+$mc/db/sql "select * from file"
+test 0  == $($mc/db/sql "select size from file where name='file1.1.dat'")
+test 10 == $($mc/db/sql "select size from file where name='file2.1.dat'")
+
+test 2 == $($mc/db/sql "select count(*) from folder_diff")
+test 1 == $($mc/db/sql "select count(*) from folder_diff_file")
+
+$mc/curl -I /download/folder1/file2.1.dat | grep $($ng7/print_address)
+
+mv $ng7/dt/folder1/file2.1.dat $ng8/dt/folder1/
+
+# gets redirected to root again
+$mc/curl -I /download/folder1/file2.1.dat | grep $($ng9/print_address)
+
+$mc/backstage/job mirror_scan_schedule_from_path_errors
+$mc/backstage/job mirror_scan_schedule
+$mc/backstage/shoot
+
+$mc/curl -H "Accept: */*, application/metalink+xml" 
/download/folder1/file2.1.dat | grep $($ng9/print_address)
+
+# now redirects to ng8
+$mc/curl -I /download/folder1/file2.1.dat | grep $($ng8/print_address)
+
+# now add new file everywhere
+for x in $ng9 $ng7 $ng8; do
+    touch $x/dt/folder1/file3.1.dat
+done
+
+$mc/backstage/job -e folder_sync -a '["/folder1"]'
+$mc/backstage/job mirror_scan_schedule
+$mc/backstage/shoot
+# now expect to hit
+$mc/curl -I /download/folder1/file3.1.dat | grep -E 
"$($ng8/print_address)|$($ng7/print_address)"
+
+# now add new file only on main server and make sure it doesn't try to redirect
+touch $ng9/dt/folder1/file4.dat
+
+$mc/curl -I /download/folder1/file4.dat | grep -E "$($ng9/print_address)"
+$mc/backstage/job folder_sync_schedule
+$mc/backstage/shoot
+$mc/backstage/job mirror_scan_schedule
+$mc/backstage/shoot
+
+test 2 == $($mc/db/sql "select count(*) from folder_diff_server")
+
+cnt="$($mc/db/sql "select count(*) from audit_event")"
+
+$mc/curl -I /download/folder1/file4.dat
+
+# it shouldn't try to probe yet, because scanner didn't find files on the 
mirrors
+test 0 == $($mc/db/sql "select count(*) from audit_event where name = 
'mirror_probe' and id > $cnt")
+
+for x in $ng9 $ng7 $ng8; do
+    mkdir $x/dt/folder1/folder11
+    touch $x/dt/folder1/folder11/file1.1.dat
+done
+
+# this is needed for schedule jobs to retry on next shoot
+$mc/curl -I /download/folder1/folder11/file1.1.dat
+$mc/backstage/job folder_sync_schedule_from_misses
+$mc/backstage/job folder_sync_schedule
+$mc/backstage/shoot
+$mc/backstage/job mirror_scan_schedule
+$mc/backstage/shoot
+
+$mc/curl -I /download/folder1/folder11/file1.1.dat | grep -E 
"$($ng7/print_address)|$($ng8/print_address)"
+$mc/curl /download/folder1/folder11/ | grep file1.1.dat
+
+
+$mc/curl /download/folder1?status=all | grep -E '"recent":"?2"?'| grep -E 
'"not_scanned":"?0"?' | grep -E '"outdated":"?0"?'
+$mc/curl /download/folder1?status=recent | grep $($ng7/print_address) | grep 
$($ng8/print_address)
+test {} == $($mc/curl /download/folder1?status=outdated)
+test {} == $($mc/curl /download/folder1?status=not_scanned)
+
+##################################
+# let's test path distortions
+# remember number of folders in DB
+cnt=$($mc/db/sql "select count(*) from folder")
+$mc/curl -I /download//folder1//file1.1.dat
+$mc/backstage/job folder_sync_schedule_from_misses
+$mc/backstage/job folder_sync_schedule
+$mc/backstage/shoot
+$mc/backstage/job mirror_scan_schedule
+$mc/backstage/shoot
+test $cnt == $($mc/db/sql "select count(*) from folder")
+
+$mc/curl -I /download//folder1//file1.1.dat              | grep -C 10 -P 
'[^/]/folder1/file1.1.dat' | grep 302
+$mc/curl -I /download//folder1///file1.1.dat             | grep -C 10 -P 
'[^/]/folder1/file1.1.dat' | grep 302
+$mc/curl -I /download/./folder1/././file1.1.dat          | grep -C 10 -P 
'[^/]/folder1/file1.1.dat' | grep 302
+$mc/curl -I /download/./folder1/../folder1/./file1.1.dat | grep -C 10 -P 
'[^/]/folder1/file1.1.dat' | grep 302
+##################################
+
+
+##################################
+# test file with colon ':'
+for x in $ng9 $ng7 $ng8; do
+    touch $x/dt/folder1/file:4.dat
+done
+
+# first request will miss
+$mc/curl -I /download/folder1/file:4.dat | grep -E "$($ng9/print_address)"
+
+$mc/db/sql "select s.id, s.hostname, fd.id, fd.hash, fl.name, fd.dt, fl.dt
+from
+folder_diff fd
+join folder_diff_server fds on fd.id = fds.folder_diff_id
+join server s on s.id = fds.server_id
+left join folder_diff_file fdf on fdf.folder_diff_id = fd.id
+left join file fl on fdf.file_id = fl.id
+left join folder f on fd.folder_id = f.id
+order by f.id, s.id, fl.name
+"
+
+# force rescan
+$mc/backstage/job -e folder_sync -a '["/folder1"]'
+$mc/backstage/shoot
+$mc/backstage/job mirror_scan_schedule
+$mc/backstage/shoot
+
+$mc/db/sql "select s.id, s.hostname, fd.id, fd.hash, fl.name, fd.dt, fl.dt
+from
+folder_diff fd
+join folder_diff_server fds on fd.id = fds.folder_diff_id
+join server s on s.id = fds.server_id
+left join folder_diff_file fdf on fdf.folder_diff_id = fd.id
+left join file fl on fdf.file_id = fl.id
+left join folder f on fd.folder_id = f.id
+order by f.id, s.id, fl.name
+"
+
+# now expect to hit
+$mc/curl /download/folder1/ | grep file1.1.dat
+$mc/curl /download/folder1/ | grep file:4.dat
+$mc/curl -I /download/folder1/file:4.dat | grep -E 
"$($ng8/print_address)|$(ng7*/print_address)"
+##################################
+
+f=0123456789012345678901234567890123456789.\(\#@~\)abcdefghijklmnoprst.dat
+e=0123456789012345678901234567890123456789.%28%23%40~%29abcdefghijklmnoprst.dat
+
+for x in $ng9 $ng7 $ng8; do
+    mkdir -p $x/dt/{folder1,folder2,folder3}
+    echo -n 0123456789 > $x/dt/folder1/$f
+done
+
+$mc/backstage/job -e folder_sync -a '["/folder1"]'
+$mc/backstage/shoot
+$mc/backstage/job mirror_scan_schedule
+$mc/backstage/shoot
+
+$mc/curl /download/folder1/ | grep -B2 $f | grep '10 Byte'
+
+##########################
+# add a symlink and make sure size is correct for it as well
+( cd $ng9/dt/folder1 && ln -s $f ln-Media.iso )
+$mc/backstage/job -e folder_sync -a '["/folder1"]'
+$mc/backstage/shoot
+
+$mc/curl /download/folder1/ | grep -B2 ln-Media.iso | grep '10 Byte'
+
+$mc/curl -IL /download/folder1/$e | grep '200 OK'
+$mc/curl -I  /download/folder1/$e | grep -C20 '302 Found' | grep -E 
"$($ng7/print_address)|$($ng8/print_address)" | grep "/folder1/$e"
+
+
+for x in $mc $ng9; do
+  for pattern in 'P=*2.1*' 'GLOB=*2.1*' 'REGEX=.*2\.1.*'; do
+    for extra in '' '&json' '&jsontable'; do
+        echo $x $pattern $extra
+        $x/curl /download/folder1/?$pattern$extra | grep -o file2.1.dat
+        rc=0
+        $x/curl /download/folder1/?$pattern$extra | grep -o file1.1.dat || 
rc=$?
+        test $rc -gt 0
+    done
+  done
+done
+
+$mc/curl "/download/folder1/?GLOB=*2.1*&mirrorlist"     | grep '<li>Filename: 
file2.1.dat</li>'
+$mc/curl "/download/folder1/?REGEX=.*2\.1.*&mirrorlist" | grep '<li>Filename: 
file2.1.dat</li>'
+
+
+echo success
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/MirrorCache-1.051/t/manual/01-download.o.o.sh 
new/MirrorCache-1.052/t/manual/01-download.o.o.sh
--- old/MirrorCache-1.051/t/manual/01-download.o.o.sh   2022-12-29 
10:16:50.000000000 +0100
+++ new/MirrorCache-1.052/t/manual/01-download.o.o.sh   2023-01-12 
09:40:42.000000000 +0100
@@ -6,19 +6,20 @@
 $mc/gen_env MIRRORCACHE_RECKLESS=0 \
     MIRRORCACHE_ROOT=http://download.opensuse.org \
     MIRRORCACHE_REDIRECT=downloadcontent.opensuse.org \
-    MIRRORCACHE_HYPNOTOAD=1 \
+    MIRRORCACHE_HYPNOTOAD=0 \
     MIRRORCACHE_PERMANENT_JOBS="'folder_sync_schedule_from_misses 
folder_sync_schedule mirror_scan_schedule_from_misses 
mirror_scan_schedule_from_path_errors mirror_scan_schedule cleanup 
stat_agg_schedule mirror_check_from_stat'" \
-    MIRRORCACHE_TOP_FOLDERS="'debug distribution tumbleweed factory 
repositories'" \
+    MIRRORCACHE_TOP_FOLDERS="'debug distribution tumbleweed factory 
repositories update'" \
     MIRRORCACHE_AUTH_URL=https://www.opensuse.org/openid/user/ \
     MIRRORCACHE_TRUST_AUTH=127.0.0.2 \
     MIRRORCACHE_PROXY_URL=http://127.0.0.1:3110 \
+    MIRRORCACHE_BRANDING=openSUSE \
     MIRRORCACHE_BACKSTAGE_WORKERS=32
 
-    
 
 $mc/start
 $mc/backstage/start
 $mc/db/sql -f 
dist/salt/profile/mirrorcache/files/usr/share/mirrorcache/sql/mirrors-eu.sql 
mc_test
 
-$mc/backstage/job -e folder_tree -a '["/distribution"]'
-$mc/backstage/job -e folder_tree -a '["/tumbleweed"]'
+# $mc/backstage/job -e folder_tree -a '["/distribution"]'
+# $mc/backstage/job -e folder_tree -a '["/tumbleweed"]'
+# $mc/backstage/job -e folder_tree -a '["/update"]'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/MirrorCache-1.051/templates/dir.html.ep 
new/MirrorCache-1.052/templates/dir.html.ep
--- old/MirrorCache-1.051/templates/dir.html.ep 2022-12-29 10:16:50.000000000 
+0100
+++ new/MirrorCache-1.052/templates/dir.html.ep 2023-01-12 09:40:42.000000000 
+0100
@@ -5,7 +5,7 @@
 % my $full_path = $cur_path;
 % $full_path = $route . $cur_path unless $route eq '/';
 % my @breadcrumbs = split '/', $full_path;
-% my $bc_last = pop @breadcrumbs;
+% my $bc_last = pop @breadcrumbs // '';
 %= include 'layouts/info'
 
 % my $mc_branding = eval '$branding' // '';
@@ -21,11 +21,11 @@
 
 <style type='text/css'>
 
-a {
+tr.td.a {
   display: flex;
 }
 
-a::after{
+tr.td.a::after{
   content: var(--desc);
   color: grey;
   margin-left: auto;

++++++ MirrorCache.obsinfo ++++++
--- /var/tmp/diff_new_pack.NONKJq/_old  2023-01-19 16:44:29.465858613 +0100
+++ /var/tmp/diff_new_pack.NONKJq/_new  2023-01-19 16:44:29.469858633 +0100
@@ -1,5 +1,5 @@
 name: MirrorCache
-version: 1.051
-mtime: 1672305410
-commit: a668bdb9d15d6a15752b6d4b5fb87e3f651096fc
+version: 1.052
+mtime: 1673512842
+commit: 4b3bfe9c1345b5228f40fb6ad75626a67ab7aee5
 

Reply via email to