Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package libzypp for openSUSE:Factory checked 
in at 2022-10-15 16:35:01
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/libzypp (Old)
 and      /work/SRC/openSUSE:Factory/.libzypp.new.2275 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "libzypp"

Sat Oct 15 16:35:01 2022 rev:464 rq:1010957 version:17.31.3

Changes:
--------
--- /work/SRC/openSUSE:Factory/libzypp/libzypp.changes  2022-10-10 
18:44:50.530904768 +0200
+++ /work/SRC/openSUSE:Factory/.libzypp.new.2275/libzypp.changes        
2022-10-15 16:36:19.785990821 +0200
@@ -1,0 +2,27 @@
+Fri Oct 14 14:09:51 CEST 2022 - m...@suse.de
+
+- Improve download of optional files (fixes #416)
+- Do not use geoip rewrites if the repo has explicit country
+  settings.
+- Implement geoIP feature for zypp.
+  This patch adds a feature to rewrite request URLs to the repo
+  servers by querying a geoIP file from download.opensuse.org. This
+  file can return a redirection target depending on the clients IP
+  adress, this way we can directly contact a local mirror of d.o.o
+  instead. The redir target stays valid for 24hrs.
+  This feature can be disabled in zypp.conf by setting
+  'download.use_geoip_mirror = false'.
+- Use a dynamic fallback for BLKSIZE in downloads.
+  When not receiving a blocklist via metalink file from the server
+  MediaMultiCurl used to fallback to a fixed, relatively small
+  BLKSIZE. This patch changes the fallback into a dynamic value
+  based on the filesize using a similar metric as the MirrorCache
+  implementation on the server side.
+- Skip media.1/media download for http repo status calc.
+  This patch allows zypp to skip a extra media.1/media download to
+  calculate if a repository needs to be refreshed. This
+  optimisation only takes place if the repo does specify only
+  downloading base urls.
+- version 17.31.3 (22)
+
+-------------------------------------------------------------------

Old:
----
  libzypp-17.31.2.tar.bz2

New:
----
  libzypp-17.31.3.tar.bz2

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

Other differences:
------------------
++++++ libzypp.spec ++++++
--- /var/tmp/diff_new_pack.RvlBcU/_old  2022-10-15 16:36:20.597992772 +0200
+++ /var/tmp/diff_new_pack.RvlBcU/_new  2022-10-15 16:36:20.601992782 +0200
@@ -43,7 +43,7 @@
 %bcond_with enable_preview_single_rpmtrans_as_default_for_zypper
 
 Name:           libzypp
-Version:        17.31.2
+Version:        17.31.3
 Release:        0
 License:        GPL-2.0-or-later
 URL:            https://github.com/openSUSE/libzypp

++++++ libzypp-17.31.2.tar.bz2 -> libzypp-17.31.3.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-17.31.2/VERSION.cmake 
new/libzypp-17.31.3/VERSION.cmake
--- old/libzypp-17.31.2/VERSION.cmake   2022-10-05 18:39:29.000000000 +0200
+++ new/libzypp-17.31.3/VERSION.cmake   2022-10-14 15:34:44.000000000 +0200
@@ -61,8 +61,8 @@
 SET(LIBZYPP_MAJOR "17")
 SET(LIBZYPP_COMPATMINOR "22")
 SET(LIBZYPP_MINOR "31")
-SET(LIBZYPP_PATCH "2")
+SET(LIBZYPP_PATCH "3")
 #
-# LAST RELEASED: 17.31.2 (22)
+# LAST RELEASED: 17.31.3 (22)
 # (The number in parenthesis is LIBZYPP_COMPATMINOR)
 #=======
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-17.31.2/package/libzypp.changes 
new/libzypp-17.31.3/package/libzypp.changes
--- old/libzypp-17.31.2/package/libzypp.changes 2022-10-05 18:39:29.000000000 
+0200
+++ new/libzypp-17.31.3/package/libzypp.changes 2022-10-14 15:34:44.000000000 
+0200
@@ -1,4 +1,31 @@
 -------------------------------------------------------------------
+Fri Oct 14 14:09:51 CEST 2022 - m...@suse.de
+
+- Improve download of optional files (fixes #416)
+- Do not use geoip rewrites if the repo has explicit country
+  settings.
+- Implement geoIP feature for zypp.
+  This patch adds a feature to rewrite request URLs to the repo
+  servers by querying a geoIP file from download.opensuse.org. This
+  file can return a redirection target depending on the clients IP
+  adress, this way we can directly contact a local mirror of d.o.o
+  instead. The redir target stays valid for 24hrs.
+  This feature can be disabled in zypp.conf by setting
+  'download.use_geoip_mirror = false'.
+- Use a dynamic fallback for BLKSIZE in downloads.
+  When not receiving a blocklist via metalink file from the server
+  MediaMultiCurl used to fallback to a fixed, relatively small
+  BLKSIZE. This patch changes the fallback into a dynamic value
+  based on the filesize using a similar metric as the MirrorCache
+  implementation on the server side.
+- Skip media.1/media download for http repo status calc.
+  This patch allows zypp to skip a extra media.1/media download to
+  calculate if a repository needs to be refreshed. This
+  optimisation only takes place if the repo does specify only
+  downloading base urls.
+- version 17.31.3 (22)
+
+-------------------------------------------------------------------
 Wed Oct  5 18:02:15 CEST 2022 - m...@suse.de
 
 - Resolver: Fix missing --[no]-recommends initialization in
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-17.31.2/po/it.po new/libzypp-17.31.3/po/it.po
--- old/libzypp-17.31.2/po/it.po        2022-07-07 14:19:44.000000000 +0200
+++ new/libzypp-17.31.3/po/it.po        2022-10-14 15:34:44.000000000 +0200
@@ -15,8 +15,8 @@
 "Project-Id-Version: zypp\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2022-03-14 15:21+0100\n"
-"PO-Revision-Date: 2022-03-04 18:12+0000\n"
-"Last-Translator: Davide Aiello <davide.aie...@novilingulists.com>\n"
+"PO-Revision-Date: 2022-10-13 23:13+0000\n"
+"Last-Translator: Paolo Za <zapa...@email.it>\n"
 "Language-Team: Italian <https://l10n.opensuse.org/projects/libzypp/master/it/";
 ">\n"
 "Language: it\n"
@@ -4608,11 +4608,11 @@
 
 #: zypp/target/rpm/RpmDb.cc:1271
 msgid "Package header is not signed!"
-msgstr ""
+msgstr "L'intestazione del pacchetto non ?? firmata!"
 
 #: zypp/target/rpm/RpmDb.cc:1273
 msgid "Package payload is not signed!"
-msgstr ""
+msgstr "Il contenuto del pacchetto non ?? firmato!"
 
 #. Translator: %s = name of an rpm package. A list of diffs follows
 #. this message.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-17.31.2/zypp/CMakeLists.txt 
new/libzypp-17.31.3/zypp/CMakeLists.txt
--- old/libzypp-17.31.2/zypp/CMakeLists.txt     2022-07-07 14:19:45.000000000 
+0200
+++ new/libzypp-17.31.3/zypp/CMakeLists.txt     2022-10-14 15:34:44.000000000 
+0200
@@ -248,7 +248,7 @@
   media/MediaDIR.cc
   media/MediaDISK.cc
   media/MediaCIFS.cc
-  media/MediaNetworkCommonHandler.h
+  media/MediaNetworkCommonHandler.cc
   media/MediaCurl.cc
   media/MediaMultiCurl.cc
   media/MediaISO.cc
@@ -265,6 +265,7 @@
   media/MediaCIFS.h
   media/MediaCurl.h
   media/MediaMultiCurl.h
+  media/MediaNetworkCommonHandler.h
   media/MediaDIR.h
   media/MediaDISK.h
   media/MediaException.h
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-17.31.2/zypp/MediaSetAccess.cc 
new/libzypp-17.31.3/zypp/MediaSetAccess.cc
--- old/libzypp-17.31.2/zypp/MediaSetAccess.cc  2022-07-29 11:57:20.000000000 
+0200
+++ new/libzypp-17.31.3/zypp/MediaSetAccess.cc  2022-10-14 15:34:44.000000000 
+0200
@@ -183,8 +183,7 @@
   {
     try
     {
-      if ( doesFileExist( file, media_nr ) )
-        return provideFile( OnMediaLocation( file, media_nr ), 
PROVIDE_NON_INTERACTIVE );
+      return provideFile( OnMediaLocation( file, media_nr ).setOptional( true 
), PROVIDE_NON_INTERACTIVE );
     }
     catch ( const media::MediaFileNotFoundException & excpt_r )
     { ZYPP_CAUGHT( excpt_r ); }
@@ -205,7 +204,8 @@
 
     ManagedFile tmpFile = filesystem::TmpFile::asManagedFile();
 
-    Pathname file = access.provideFile( OnMediaLocation(path, 1), options );
+    bool optional { options & PROVIDE_NON_INTERACTIVE };
+    Pathname file = access.provideFile( OnMediaLocation(path, 1).setOptional( 
optional ), options );
 
     //prevent the file from being deleted when MediaSetAccess gets out of scope
     if ( filesystem::hardlinkCopy(file, tmpFile) != 0 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-17.31.2/zypp/RepoInfo.cc 
new/libzypp-17.31.3/zypp/RepoInfo.cc
--- old/libzypp-17.31.2/zypp/RepoInfo.cc        2022-07-07 14:19:45.000000000 
+0200
+++ new/libzypp-17.31.3/zypp/RepoInfo.cc        2022-10-14 15:34:44.000000000 
+0200
@@ -27,6 +27,7 @@
 #include <zypp/Pathname.h>
 #include <zypp/ZConfig.h>
 #include <zypp/repo/RepoMirrorList.h>
+#include <zypp/repo/SUSEMediaVerifier.h>
 #include <zypp/ExternalProgram.h>
 
 #include <zypp/base/IOStream.h>
@@ -1047,6 +1048,24 @@
     return str << "GpgCheck::UNKNOWN";
   }
 
+  bool RepoInfo::requireStatusWithMediaFile () const
+  {
+    bool canSkipMediaCheck = std::all_of( baseUrlsBegin(), baseUrlsEnd(), []( 
const zypp::Url &url ) { return url.schemeIsDownloading(); });
+
+    const auto &mDataPath = metadataPath();
+    if ( canSkipMediaCheck && !mDataPath.empty() ) {
+      zypp::Pathname mediafile = mDataPath/"media.1/media";
+
+      zypp::repo::SUSEMediaVerifier lverifier { mediafile };
+      if ( lverifier ) {
+        canSkipMediaCheck = lverifier.totalMedia() == 1;
+      }
+    }
+
+    DBG << "Can SKIP media.1/media check for status calc: " << 
canSkipMediaCheck << " for repo " << *this <<  std::endl;
+    return !canSkipMediaCheck;
+  }
+
   /////////////////////////////////////////////////////////////////
 } // namespace zypp
 ///////////////////////////////////////////////////////////////////
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-17.31.2/zypp/RepoInfo.h 
new/libzypp-17.31.3/zypp/RepoInfo.h
--- old/libzypp-17.31.2/zypp/RepoInfo.h 2022-07-07 14:19:45.000000000 +0200
+++ new/libzypp-17.31.3/zypp/RepoInfo.h 2022-10-14 15:34:44.000000000 +0200
@@ -521,6 +521,12 @@
       LocaleSet getLicenseLocales( const std::string & name_r ) const;
      //@}
 
+      /**
+       * Returns true if this repository requires the media.1/media file to be 
included
+       * in the metadata status and repo status calculations.
+       */
+      bool requireStatusWithMediaFile () const;
+
     public:
       /**
        * Write a human-readable representation of this RepoInfo object
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-17.31.2/zypp/RepoManager.cc 
new/libzypp-17.31.3/zypp/RepoManager.cc
--- old/libzypp-17.31.2/zypp/RepoManager.cc     2022-07-07 14:19:45.000000000 
+0200
+++ new/libzypp-17.31.3/zypp/RepoManager.cc     2022-10-14 15:34:44.000000000 
+0200
@@ -17,6 +17,7 @@
 #include <list>
 #include <map>
 #include <algorithm>
+#include <chrono>
 
 #include <solv/solvversion.h>
 
@@ -42,6 +43,7 @@
 
 #include <zypp/parser/RepoFileReader.h>
 #include <zypp/parser/ServiceFileReader.h>
+#include <zypp/parser/xml/Reader.h>
 #include <zypp/repo/ServiceRepos.h>
 #include <zypp/repo/yum/Downloader.h>
 #include <zypp/repo/susetags/Downloader.h>
@@ -668,6 +670,8 @@
 
     repo::ServiceType probeService( const Url & url ) const;
 
+    void refreshGeoIPData ();
+
   private:
     void saveService( ServiceInfo & service ) const;
 
@@ -928,7 +932,9 @@
     switch ( repokind.toEnum() )
     {
       case RepoType::RPMMD_e :
-        status = RepoStatus( productdatapath/"repodata/repomd.xml") && 
RepoStatus( mediarootpath/"media.1/media" );
+        status = RepoStatus( productdatapath/"repodata/repomd.xml");
+        if ( info.requireStatusWithMediaFile() )
+          status = status && RepoStatus( mediarootpath/"media.1/media" );
         break;
 
       case RepoType::YAST2_e :
@@ -997,6 +1003,8 @@
     {
       MIL << "Check if to refresh repo " << info.alias() << " at " << url << " 
(" << info.type() << ")" << endl;
 
+      refreshGeoIPData();
+
       // first check old (cached) metadata
       Pathname mediarootpath = rawcache_path_for_repoinfo( _options, info );
       filesystem::assert_dir( mediarootpath );
@@ -1120,6 +1128,9 @@
     assert_alias(info);
     assert_urls(info);
 
+    // make sure geoIP data is up 2 date
+    refreshGeoIPData();
+
     // we will throw this later if no URL checks out fine
     RepoException rexception( info, PL_("Valid metadata not found at specified 
URL",
                                         "Valid metadata not found at specified 
URLs",
@@ -1265,8 +1276,8 @@
   {
     ProgressData progress(100);
     progress.sendTo(progressfnc);
-
-    filesystem::recursive_rmdir(rawcache_path_for_repoinfo(_options, info));
+    filesystem::recursive_rmdir( ZConfig::instance().geoipCachePath() );
+    filesystem::recursive_rmdir( rawcache_path_for_repoinfo(_options, info) );
     progress.toMax();
   }
 
@@ -2538,6 +2549,134 @@
     return repo::ServiceType::NONE;
   }
 
+  void RepoManager::Impl::refreshGeoIPData ()
+  {
+    try  {
+
+      if ( !ZConfig::instance().geoipEnabled() ) {
+        MIL << "GeoIp disabled via ZConfig, not refreshing the GeoIP 
information." << std::endl;
+        return;
+      }
+
+      // for applications like packageKit that are running very long we 
remember the last time when we checked
+      // for geoIP data. We don't want to query this over and over again.
+      static auto lastCheck = std::chrono::steady_clock::time_point::min();
+      if ( lastCheck != std::chrono::steady_clock::time_point::min()
+          && (std::chrono::steady_clock::now() - lastCheck) < 
std::chrono::hours(24) )
+        return;
+
+      lastCheck = std::chrono::steady_clock::now();
+
+      const auto &geoIPCache = ZConfig::instance().geoipCachePath();
+
+      if ( filesystem::assert_dir( geoIPCache ) != 0 ) {
+        MIL << "Unable to create cache directory for GeoIP." << std::endl;
+        return;
+      }
+
+      if ( !PathInfo(geoIPCache).userMayRWX() ) {
+        MIL << "No access rights for the GeoIP cache directory." << std::endl;
+        return;
+      }
+
+      // remove all older cache entries
+      filesystem::dirForEachExt( geoIPCache, []( const Pathname &dir, const 
filesystem::DirEntry &entry ){
+        if ( entry.type != filesystem::FT_FILE )
+          return true;
+
+        PathInfo pi( dir/entry.name );
+        auto age = std::chrono::system_clock::now() - 
std::chrono::system_clock::from_time_t( pi.mtime() );
+        if ( age < std::chrono::hours(24) )
+          return true;
+
+        MIL << "Removing GeoIP file for " << entry.name << " since it's older 
than 24hrs." << std::endl;
+        filesystem::unlink( dir/entry.name );
+        return true;
+      });
+
+      // go over all configured hostnames
+      const auto &hosts = ZConfig::instance().geoipHostnames();
+      std::for_each( hosts.begin(), hosts.end(), [ & ]( const std::string 
&hostname ) {
+
+        // do not query files that are still there
+        if ( zypp::PathInfo( geoIPCache / hostname ).isExist() )  {
+          MIL << "Skipping GeoIP request for " << hostname << " since a valid 
cache entry exists." << std::endl;
+          return;
+        }
+
+        MIL << "Query GeoIP for " << hostname << std::endl;
+
+        zypp::Url url;
+        try
+        {
+          url.setHost(hostname);
+          url.setScheme("https");
+        }
+        catch(const zypp::Exception &e )
+        {
+          ZYPP_CAUGHT(e);
+          MIL << "Ignoring invalid GeoIP hostname: " << hostname << std::endl;
+          return;
+        }
+
+        zypp::ManagedFile file;
+        try {
+
+          // query the file from the server
+          MediaSetAccess acc( url );
+          file = zypp::ManagedFile (acc.provideOptionalFile("/geoip"), 
filesystem::unlink );
+
+        } catch ( const zypp::Exception &e  ) {
+          ZYPP_CAUGHT(e);
+          MIL << "Failed to query GeoIP from hostname: " << hostname << 
std::endl;
+          return;
+        }
+        if ( !file->empty() ) {
+
+          constexpr auto writeHostToFile = []( const Pathname &fName, const 
std::string &host ){
+            std::ofstream out;
+            out.open( fName.asString(), std::ios_base::trunc );
+            if ( out.is_open() ) {
+              out << host << std::endl;
+            } else {
+              MIL << "Failed to create/open GeoIP cache file " << fName << 
std::endl;
+            }
+          };
+
+          std::string geoipMirror;
+          try {
+            xml::Reader reader( *file );
+            if ( reader.seekToNode( 1, "host" ) ) {
+              const auto &str = reader.nodeText().asString();
+
+              // make a dummy URL to ensure the hostname is valid
+              zypp::Url testUrl;
+              testUrl.setHost(str);
+              testUrl.setScheme("https");
+
+              if ( testUrl.isValid() ) {
+                MIL << "Storing geoIP redirection: " << hostname << " -> " << 
str << std::endl;
+                geoipMirror = str;
+              }
+
+            } else {
+              MIL << "No host entry or empty file returned for GeoIP, 
remembering for 24hrs" << std::endl;
+            }
+          } catch ( const zypp::Exception &e ) {
+            ZYPP_CAUGHT(e);
+            MIL << "Empty or invalid GeoIP file, not requesting again for 
24hrs" << std::endl;
+          }
+
+          writeHostToFile( geoIPCache / hostname, geoipMirror );
+        }
+      });
+
+    } catch ( const zypp::Exception &e ) {
+      ZYPP_CAUGHT(e);
+      MIL << "Failed to query GeoIP data." << std::endl;
+    }
+  }
+
   ///////////////////////////////////////////////////////////////////
   //
   //   CLASS NAME : RepoManager
@@ -2697,6 +2836,9 @@
   void RepoManager::modifyService( const std::string & oldAlias, const 
ServiceInfo & service )
   { return _pimpl->modifyService( oldAlias, service ); }
 
+  void RepoManager::refreshGeoIp ()
+  { return _pimpl->refreshGeoIPData(); }
+
   ////////////////////////////////////////////////////////////////////////////
 
   std::ostream & operator<<( std::ostream & str, const RepoManager & obj )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-17.31.2/zypp/RepoManager.h 
new/libzypp-17.31.3/zypp/RepoManager.h
--- old/libzypp-17.31.2/zypp/RepoManager.h      2022-07-07 14:19:45.000000000 
+0200
+++ new/libzypp-17.31.3/zypp/RepoManager.h      2022-10-14 15:34:44.000000000 
+0200
@@ -634,6 +634,12 @@
     void modifyService( const ServiceInfo & service )
     { modifyService( service.alias(), service ); }
 
+    /*!
+     * Checks with configured geoIP servers ( usually download.opensuse.org ) 
if there is new geoip data available, caches the results
+     * in the metadata cache for 24hrs.
+     */
+    void refreshGeoIp ();
+
   private:
     /**
      * Functor thats filter RepoInfo by service which it belongs to.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-17.31.2/zypp/ZConfig.cc 
new/libzypp-17.31.3/zypp/ZConfig.cc
--- old/libzypp-17.31.2/zypp/ZConfig.cc 2022-07-07 14:19:45.000000000 +0200
+++ new/libzypp-17.31.3/zypp/ZConfig.cc 2022-10-14 15:34:44.000000000 +0200
@@ -415,6 +415,8 @@
         , pkgGpgCheck                  ( indeterminate )
         , apply_locks_file             ( true )
         , pluginsPath                  ( "/usr/lib/zypp/plugins" )
+        , geoipEnabled ( true )
+        , geoipHosts { "download.opensuse.org" }
       {
         MIL << "libzypp: " LIBZYPP_VERSION_STRING << endl;
         if ( PathInfo(_parsedZyppConf).isExist() )
@@ -518,6 +520,9 @@
                 {
                   download_mediaMountdir.restoreToDefault( Pathname(value) );
                 }
+                else if ( entry == "download.use_geoip_mirror") {
+                  geoipEnabled = str::strToBool( value, geoipEnabled );
+                }
                 else if ( entry == "commit.downloadMode" )
                 {
                   commit_downloadMode.set( deserializeDownloadMode( value ) );
@@ -712,6 +717,10 @@
 
     Option<Pathname> pluginsPath;
 
+    bool geoipEnabled;
+
+    std::vector<std::string> geoipHosts;
+
     /* Other config singleton instances */
     MediaConfig &_mediaConf = MediaConfig::instance();
 
@@ -1024,6 +1033,18 @@
   Pathname ZConfig::needrebootPath() const
   { return configPath()/"needreboot.d"; }
 
+  void ZConfig::setGeoipEnabled( bool enable )
+  { _pimpl->geoipEnabled = enable; }
+
+  bool ZConfig::geoipEnabled () const
+  { return _pimpl->geoipEnabled; }
+
+  Pathname ZConfig::geoipCachePath() const
+  { return builtinRepoCachePath()/"geoip.d"; }
+
+  const std::vector<std::string> ZConfig::geoipHostnames () const
+  { return _pimpl->geoipHosts; }
+
   Pathname ZConfig::varsPath() const
   {
     return ( _pimpl->cfg_vars_path.empty()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-17.31.2/zypp/ZConfig.h 
new/libzypp-17.31.3/zypp/ZConfig.h
--- old/libzypp-17.31.2/zypp/ZConfig.h  2022-07-07 14:19:45.000000000 +0200
+++ new/libzypp-17.31.3/zypp/ZConfig.h  2022-10-14 15:34:44.000000000 +0200
@@ -224,6 +224,28 @@
       Pathname needrebootPath() const;
 
       /**
+       * Enables or disables the use of the geoip feature of 
download.opensuse.org
+       */
+      void setGeoipEnabled( bool enable = true );
+
+      /**
+       * Returns true if zypp should use the geoip feature of 
download.opensuse.org
+       */
+      bool geoipEnabled () const;
+
+      /**
+       * Path where the geoip caches are kept (/var/cache/zypp/geoip)
+       */
+      Pathname geoipCachePath() const;
+
+      /**
+       * All hostnames we want to rewrite using the geoip feature. The \ref 
RepoManager
+       * will try to query each hostname via: https://hostname/geoip to 
receive a redirection
+       * target for requests to the given hostname. The geoip targets are 
cached in \ref geoipCachePath.
+       */
+      const std::vector<std::string> geoipHostnames () const;
+
+      /**
        * Path containing custom repo variable definitions 
(configPath()/vars.d).
        * \see \ref zypp::repo::RepoVarExpand Repo variable expander
        * \ingroup g_ZC_CONFIGFILES
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-17.31.2/zypp/media/MediaCurl.cc 
new/libzypp-17.31.3/zypp/media/MediaCurl.cc
--- old/libzypp-17.31.2/zypp/media/MediaCurl.cc 2022-07-08 12:42:06.000000000 
+0200
+++ new/libzypp-17.31.3/zypp/media/MediaCurl.cc 2022-10-14 15:34:44.000000000 
+0200
@@ -42,6 +42,83 @@
 
 namespace internal {
   using namespace zypp;
+  /// Optional files will send no report until data are actually received (we 
know it exists).
+  struct OptionalDownloadProgressReport : public 
callback::ReceiveReport<media::DownloadProgressReport>
+  {
+    OptionalDownloadProgressReport( bool isOptional=false )
+    : _oldRec { Distributor::instance().getReceiver() }
+    , _isOptional { isOptional }
+    { connect(); }
+
+    ~OptionalDownloadProgressReport()
+    { if ( _oldRec ) Distributor::instance().setReceiver( *_oldRec ); else 
Distributor::instance().noReceiver(); }
+
+    void reportbegin() override
+    { if ( _oldRec ) _oldRec->reportbegin(); }
+
+    void reportend() override
+    { if ( _oldRec ) _oldRec->reportend(); }
+
+    void report( const UserData & userData_r = UserData() ) override
+    { if ( _oldRec ) _oldRec->report( userData_r ); }
+
+
+    void start( const Url & file_r, Pathname localfile_r ) override
+    {
+      if ( not _oldRec ) return;
+      if ( _isOptional ) {
+        // delay start until first data are received.
+        _startFile      = file_r;
+        _startLocalfile = std::move(localfile_r);
+        return;
+      }
+      _oldRec->start( file_r, localfile_r );
+    }
+
+    bool progress( int value_r, const Url & file_r, double dbps_avg_r = -1, 
double dbps_current_r = -1 ) override
+    {
+      if ( not _oldRec ) return true;
+      if ( notStarted() ) {
+        if ( not ( value_r || dbps_avg_r || dbps_current_r ) )
+          return true;
+        sendStart();
+      }
+      return _oldRec->progress( value_r, file_r, dbps_avg_r, dbps_current_r );
+    }
+
+    Action problem( const Url & file_r, Error error_r, const std::string & 
description_r ) override
+    {
+      if ( not _oldRec || notStarted() ) return ABORT;
+      return _oldRec->problem( file_r, error_r, description_r );
+    }
+
+    void finish( const Url & file_r, Error error_r, const std::string & 
reason_r ) override
+    {
+      if ( not _oldRec || notStarted() ) return;
+      _oldRec->finish( file_r, error_r, reason_r );
+    }
+
+  private:
+    // _isOptional also indicates the delayed start
+    bool notStarted() const
+    { return _isOptional; }
+
+    void sendStart()
+    {
+      if ( _isOptional ) {
+        // we know _oldRec is valid...
+        _oldRec->start( std::move(_startFile), std::move(_startLocalfile) );
+        _isOptional = false;
+      }
+    }
+
+  private:
+    Receiver *const _oldRec;
+    bool     _isOptional;
+    Url      _startFile;
+    Pathname _startLocalfile;
+  };
+
   struct ProgressData
   {
     ProgressData( CURL *_curl, time_t _timeout = 0, const zypp::Url & _url = 
zypp::Url(),
@@ -626,20 +703,6 @@
   disconnect();
 }
 
-Url MediaCurl::getFileUrl( const Pathname & filename_r ) const
-{
-  // Simply extend the URLs pathname. An 'absolute' URL path
-  // is achieved by encoding the leading '/' in an URL path:
-  //   URL: ftp://user@server          -> ~user
-  //   URL: ftp://user@server/         -> ~user
-  //   URL: ftp://user@server//                -> ~user
-  //   URL: ftp://user@server/%2F      -> /
-  //                         ^- this '/' is just a separator
-  Url newurl( _url );
-  newurl.setPathName( ( Pathname("./"+_url.getPathName()) / filename_r 
).asString().substr(1) );
-  return newurl;
-}
-
 ///////////////////////////////////////////////////////////////////
 
 void MediaCurl::getFile( const OnMediaLocation &file ) const
@@ -656,6 +719,8 @@
 
   const auto &filename = srcFile.filename();
 
+  // Optional files will send no report until data are actually received (we 
know it exists).
+  OptionalDownloadProgressReport reportfilter( srcFile.optional() );
   callback::SendReport<DownloadProgressReport> report;
 
   Url fileurl(getFileUrl(filename));
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-17.31.2/zypp/media/MediaCurl.h 
new/libzypp-17.31.3/zypp/media/MediaCurl.h
--- old/libzypp-17.31.2/zypp/media/MediaCurl.h  2022-07-07 14:19:45.000000000 
+0200
+++ new/libzypp-17.31.3/zypp/media/MediaCurl.h  2022-10-14 15:34:44.000000000 
+0200
@@ -110,7 +110,7 @@
     };
 
   protected:
-//     /** Callback sending just an alive trigger to the UI, without stats 
(e.g. during metalink download). */
+    /** Callback sending just an alive trigger to the UI, without stats (e.g. 
during metalink download). */
     static int aliveCallback( void *clientp, double dltotal, double dlnow, 
double ultotal, double ulnow );
     /** Callback reporting download progress. */
     static int progressCallback( void *clientp, double dltotal, double dlnow, 
double ultotal, double ulnow );
@@ -126,11 +126,6 @@
      * \throws MediaCurlSetOptException if there is a problem
      **/
     virtual void setupEasy();
-    /**
-     * concatenate the attach url and the filename to a complete
-     * download url
-     **/
-    Url getFileUrl(const Pathname & filename) const;
 
     /**
      * Evaluates a curl return code and throws the right MediaException
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-17.31.2/zypp/media/MediaHandler.h 
new/libzypp-17.31.3/zypp/media/MediaHandler.h
--- old/libzypp-17.31.2/zypp/media/MediaHandler.h       2022-07-07 
14:19:45.000000000 +0200
+++ new/libzypp-17.31.3/zypp/media/MediaHandler.h       2022-10-14 
15:34:44.000000000 +0200
@@ -427,7 +427,7 @@
          * \throws MediaException
          *
          **/
-        virtual bool getDoesFileExist( const Pathname & filename ) const = 0;
+        virtual bool getDoesFileExist( const Pathname & filename ) const =   0;
 
   protected:
 
@@ -717,5 +717,3 @@
 
 
 #endif // ZYPP_MEDIA_MEDIAHANDLERL_H
-
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-17.31.2/zypp/media/MediaMultiCurl.cc 
new/libzypp-17.31.3/zypp/media/MediaMultiCurl.cc
--- old/libzypp-17.31.2/zypp/media/MediaMultiCurl.cc    2022-07-07 
14:19:45.000000000 +0200
+++ new/libzypp-17.31.3/zypp/media/MediaMultiCurl.cc    2022-10-14 
15:34:44.000000000 +0200
@@ -121,6 +121,9 @@
   void run(std::vector<Url> &urllist);
 
 protected:
+
+  static size_t makeBlksize ( size_t filesize );
+
   friend class multifetchworker;
 
   const MediaMultiCurl *_context;
@@ -139,6 +142,7 @@
   bool _havenewjob;
 
   size_t _blkno;
+  size_t _defaultBlksize = 0; //< The blocksize to use if the metalink file 
does not specify one
   off_t _blkoff;
   size_t _activeworkers;
   size_t _lookupworkers;
@@ -164,7 +168,6 @@
 };
 
 constexpr auto MIN_REQ_MIRRS = 4;
-constexpr auto BLKSIZE       = 131072;
 constexpr auto MAXURLS       = 10;
 
 //////////////////////////////////////////////////////////////////////
@@ -707,18 +710,19 @@
   MediaBlockList *blklist = _request->_blklist;
   if (!blklist)
     {
-      _blksize = BLKSIZE;
+      _blksize = _request->_defaultBlksize;
       if (_request->_filesize != off_t(-1))
-        {
-          if (_request->_blkoff >= _request->_filesize)
-            {
-              stealjob();
-              return;
-            }
-          _blksize = _request->_filesize - _request->_blkoff;
-          if (_blksize > BLKSIZE)
-            _blksize = BLKSIZE;
-        }
+      {
+        if (_request->_blkoff >= _request->_filesize)
+          {
+            stealjob();
+            return;
+          }
+        _blksize = _request->_filesize - _request->_blkoff;
+        if (_blksize > _request->_defaultBlksize)
+          _blksize = _request->_defaultBlksize;
+      }
+      DBG << "No BLOCKLIST falling back to chunk size: " <<  
_request->_defaultBlksize << std::endl;
     }
   else
     {
@@ -734,8 +738,10 @@
           _request->_blkoff = blk.off;
         }
       _blksize = blk.off + blk.size - _request->_blkoff;
-      if (_blksize > BLKSIZE && !blklist->haveChecksum(_request->_blkno))
-        _blksize = BLKSIZE;
+      if (_blksize > _request->_defaultBlksize && 
!blklist->haveChecksum(_request->_blkno)) {
+        DBG << "Block: "<< _request->_blkno << " has no checksum falling back 
to default blocksize: " <<  _request->_defaultBlksize << std::endl;
+        _blksize = _request->_defaultBlksize;
+      }
     }
   _blkno = _request->_blkno;
   _blkstart = _request->_blkoff;
@@ -791,6 +797,7 @@
   _report = report;
   _blklist = blklist;
   _filesize = filesize;
+  _defaultBlksize = makeBlksize( filesize );
   _multi = multi;
   _stealing = false;
   _havenewjob = false;
@@ -1156,6 +1163,15 @@
     }
 }
 
+inline size_t multifetchrequest::makeBlksize ( size_t filesize )
+{
+  // this case should never happen because we never start a multi download if 
we do not know the filesize beforehand
+  if ( filesize == 0 )  return 2 * 1024 * 1024;
+  else if ( filesize < 2*256*1024 ) return filesize;
+  else if ( filesize < 8*1024*1024 ) return 256*1024;
+  else if ( filesize < 256*1024*1024 ) return 1024*1024;
+  return 4*1024*1024;
+}
 
 //////////////////////////////////////////////////////////////////////
 
@@ -1610,4 +1626,3 @@
 
   } // namespace media
 } // namespace zypp
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/libzypp-17.31.2/zypp/media/MediaNetworkCommonHandler.cc 
new/libzypp-17.31.3/zypp/media/MediaNetworkCommonHandler.cc
--- old/libzypp-17.31.2/zypp/media/MediaNetworkCommonHandler.cc 1970-01-01 
01:00:00.000000000 +0100
+++ new/libzypp-17.31.3/zypp/media/MediaNetworkCommonHandler.cc 2022-10-14 
15:34:44.000000000 +0200
@@ -0,0 +1,96 @@
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+/** \file zypp/media/MediaNetworkCommonHandler.cc
+ *
+*/
+
+#include "MediaNetworkCommonHandler.h"
+
+#include <zypp/ZConfig.h>
+#include <zypp-core/fs/PathInfo.h>
+#include <zypp/base/Logger.h>
+#include <zypp-core/base/Regex.h>
+
+#include <fstream>
+
+namespace zypp::media
+{
+  zypp::Url MediaNetworkCommonHandler::findGeoIPRedirect ( const zypp::Url 
&url )
+  {
+    try {
+      const auto &conf = ZConfig::instance();
+      if ( !conf.geoipEnabled() ) {
+        MIL << "GeoIp rewrites disabled via ZConfig." << std::endl;
+        return Url();
+      }
+
+      if ( !( url.getQueryParam("COUNTRY").empty() && 
url.getQueryParam("AVOID_COUNTRY").empty() )) {
+        MIL << "GeoIp rewrites disabled since the baseurl " << url << " uses 
an explicit country setting." << std::endl;
+        return Url();
+      }
+
+      const auto &hostname = url.getHost();
+      auto geoipFile = conf.geoipCachePath() / hostname ;
+      if ( PathInfo( geoipFile ).isFile() ) {
+
+        MIL << "Found GeoIP file for host: " << hostname << std::endl;
+
+        std::ifstream in( geoipFile.asString() );
+        if (!in.is_open()) {
+          MIL << "Failed to open GeoIP for host: " << hostname << std::endl;
+          return Url();
+        }
+
+        try {
+          std::string newHost;
+          in >> newHost;
+
+          Url newUrl = url;
+          newUrl.setHost( newHost );
+
+          MIL << "Found GeoIP rewrite: " << hostname << " -> " << newHost << 
std::endl;
+
+          return newUrl;
+
+        } catch ( const zypp::Exception &e ) {
+          ZYPP_CAUGHT(e);
+          MIL << "No valid GeoIP rewrite target found for " << url << 
std::endl;
+        }
+      }
+    } catch ( const zypp::Exception &e ) {
+      ZYPP_CAUGHT(e);
+      MIL << "Failed to query GeoIP data, url rewriting disabled." << 
std::endl;
+    }
+
+    // no rewrite
+    return Url();
+  }
+
+  Url MediaNetworkCommonHandler::getFileUrl( const Pathname & filename_r ) 
const
+  {
+    static const zypp::str::regex 
invalidRewrites("^.*\\/repomd.xml(.asc|.key)?$|^\\/geoip$");
+
+    const bool canRedir = _redirTarget.isValid() && 
!invalidRewrites.matches(filename_r.asString());
+    const auto &baseUrl = ( canRedir ) ? _redirTarget : _url;
+
+    if ( canRedir )
+      MIL << "Redirecting " << filename_r << " request to geoip location." << 
std::endl;
+
+    // Simply extend the URLs pathname. An 'absolute' URL path
+    // is achieved by encoding the leading '/' in an URL path:2
+    //   URL: ftp://user@server                -> ~user
+    //   URL: ftp://user@server/               -> ~user
+    //   URL: ftp://user@server//              -> ~user
+    //   URL: ftp://user@server/%2F    -> /
+    //                         ^- this '/' is just a separator
+    Url newurl( baseUrl );
+    newurl.setPathName( ( Pathname("./"+baseUrl.getPathName()) / filename_r 
).asString().substr(1) );
+    return newurl;
+  }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/libzypp-17.31.2/zypp/media/MediaNetworkCommonHandler.h 
new/libzypp-17.31.3/zypp/media/MediaNetworkCommonHandler.h
--- old/libzypp-17.31.2/zypp/media/MediaNetworkCommonHandler.h  2022-07-07 
14:19:45.000000000 +0200
+++ new/libzypp-17.31.3/zypp/media/MediaNetworkCommonHandler.h  2022-10-14 
15:34:44.000000000 +0200
@@ -35,6 +35,8 @@
                                  const Pathname & urlpath_below_attachpoint_r,
                                  const bool       does_download_r )
       : MediaHandler( url_r, attach_point_r, urlpath_below_attachpoint_r, 
does_download_r )
+      , _redirTarget( findGeoIPRedirect(url_r) )
+
       {}
 
     public:
@@ -42,7 +44,23 @@
       { return _settings; }
 
     protected:
+
+      /**
+       * concatenate the attach url and the filename to a complete
+       * download url
+       **/
+      Url getFileUrl(const Pathname & filename) const;
+
+
+      /**
+       * Rewrites the baseURL to the geoIP target if one is found in the 
metadata cache,
+       * otherwise simply returns the url again.
+       */
+      static zypp::Url findGeoIPRedirect ( const zypp::Url &url );
+
+    protected:
       mutable TransferSettings _settings;
+      Url _redirTarget;
     };
 
   } // namespace media
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-17.31.2/zypp/repo/Downloader.cc 
new/libzypp-17.31.3/zypp/repo/Downloader.cc
--- old/libzypp-17.31.2/zypp/repo/Downloader.cc 2022-07-29 11:57:20.000000000 
+0200
+++ new/libzypp-17.31.3/zypp/repo/Downloader.cc 2022-10-14 15:34:44.000000000 
+0200
@@ -221,6 +221,3 @@
 
 }// ns repo
 } // ns zypp
-
-
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-17.31.2/zypp/repo/SUSEMediaVerifier.cc 
new/libzypp-17.31.3/zypp/repo/SUSEMediaVerifier.cc
--- old/libzypp-17.31.2/zypp/repo/SUSEMediaVerifier.cc  2022-07-07 
14:19:45.000000000 +0200
+++ new/libzypp-17.31.3/zypp/repo/SUSEMediaVerifier.cc  2022-10-14 
15:34:44.000000000 +0200
@@ -163,6 +163,12 @@
       SEC << smvData << endl;
       SEC << ref.protocol() << " " <<  Url::schemeIsVolatile( ref.protocol() ) 
<< endl;
 
+      // if we have a downloading URL and can do relaxed verification we do 
not check the media file again
+      if ( relaxed && Url::schemeIsDownloading( ref.protocol() ) )  {
+        DBG << "Skipping verification due to downloading medium" << std::endl;
+        return ret;
+      }
+
       Pathname mediaFile { _pimpl->mediaFilePath() };
       try {
         ref.provideFile( OnMediaLocation(mediaFile) );
@@ -201,4 +207,3 @@
 
   } // namespace repo
 } // namespace zypp
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-17.31.2/zypp/repo/yum/Downloader.cc 
new/libzypp-17.31.3/zypp/repo/yum/Downloader.cc
--- old/libzypp-17.31.2/zypp/repo/yum/Downloader.cc     2022-07-07 
14:19:45.000000000 +0200
+++ new/libzypp-17.31.3/zypp/repo/yum/Downloader.cc     2022-10-14 
15:34:44.000000000 +0200
@@ -16,6 +16,7 @@
 
 #include "Downloader.h"
 #include <zypp/repo/MediaInfoDownloader.h>
+#include <zypp/repo/SUSEMediaVerifier.h>
 #include <zypp-core/base/UserRequestException>
 #include <zypp/parser/xml/Reader.h>
 #include <zypp/parser/yum/RepomdFileReader.h>
@@ -62,6 +63,9 @@
             deltafile = fn;
         }
       }
+      if ( !deltafile.empty() )
+        return dir/deltafile;
+
       return deltafile;
     }
   } // namespace
@@ -200,8 +204,9 @@
 
   RepoStatus Downloader::status( MediaSetAccess & media_r )
   {
-    RepoStatus ret { media_r.provideOptionalFile( repoInfo().path() / 
"/repodata/repomd.xml" ) };
-    if ( !ret.empty() )        // else: mandatory master index is missing
+    const auto & ri = repoInfo();
+    RepoStatus ret { media_r.provideOptionalFile( ri.path() / 
"/repodata/repomd.xml" ) };
+    if ( !ret.empty() && ri.requireStatusWithMediaFile() )     // else: 
mandatory master index is missing
       ret = ret && RepoStatus( media_r.provideOptionalFile( "/media.1/media" ) 
);
     // else: mandatory master index is missing -> stay empty
     return ret;
@@ -209,6 +214,3 @@
 } // namespace yum
 } // namespace repo
 } // namespace zypp
-
-
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-17.31.2/zypp.conf 
new/libzypp-17.31.3/zypp.conf
--- old/libzypp-17.31.2/zypp.conf       2022-07-07 14:19:45.000000000 +0200
+++ new/libzypp-17.31.3/zypp.conf       2022-10-14 15:34:44.000000000 +0200
@@ -258,6 +258,21 @@
 ## download.media_mountdir = /var/adm/mount
 
 ##
+## Whether to use the geoip feature of download.opensuse.org
+##
+## Valid values: boolean
+## Default value: true
+##
+## The media backend can rewrite download requests to the geographically 
closest availble mirror.
+## Which exact mirror is used will be determined by requesting a "geoip" file 
from download.opensuse.org
+## via a HTTP GET request to https://download.opensuse.org/geoip , the server 
will use the clients IP to
+## determine the closest mirror if available.
+## Some specific files are however excluded from this redirection due to 
security reasons, especially the
+## repo metdata index and it's key and checksum files: repomd.xml, 
repomd.xml.key and repomd.xml.asc
+##
+## download.use_geoip_mirror = true
+
+##
 ## Signature checking (repo metadata and downloaded rpm packages)
 ##
 ##   boolean   gpgcheck        (default: on)

Reply via email to