pkp / pkp-lib

The library used by PKP's applications OJS, OMP and OPS, open source software for scholarly publishing.
https://pkp.sfu.ca
GNU General Public License v3.0
306 stars 445 forks source link

Make version check resilient to HTTP client exceptions #10018

Closed asmecher closed 4 months ago

asmecher commented 4 months ago

Describe the bug When OJS can't access the PKP website's version descriptor in order to check what the latest version of OJS is, it can result in a fatal exception, rendering the admin interface unreachable. (It's probably the same with the Plugin Gallery XML fetch.)

To Reproduce Steps to reproduce the behavior:

  1. Knock the PKP website offline. (Please don't!)
  2. Try to access the Administration interface, or Settings > Website.
  3. Check the PHP error log for an exception like:
PHP Fatal error:  Uncaught GuzzleHttp\Exception\RequestException: cURL error 60: SSL certificate problem: certificate has expired (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) for https://pkp.sfu.ca/ojs/xml/ojs-version.xml?id=82DF837D-10AF-412C-9505-F3C4B8F403B6&oai=http%3A%2F%2Flocalhost%2Fgit%2Fojs-stable-3_4_0%2Findex.php%2Findex%2Foai in /home/asmecher/git/ojs-stable-3_4_0/lib/pkp/lib/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php:211
Stack trace:
#0 /home/asmecher/git/ojs-stable-3_4_0/lib/pkp/lib/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php(158): GuzzleHttp\Handler\CurlFactory::createRejection()
#1 /home/asmecher/git/ojs-stable-3_4_0/lib/pkp/lib/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php(110): GuzzleHttp\Handler\CurlFactory::finishError()
#2 /home/asmecher/git/ojs-stable-3_4_0/lib/pkp/lib/vendor/guzzlehttp/guzzle/src/Handler/CurlHandler.php(47): GuzzleHttp\Handler\CurlFactory::finish()
#3 /home/asmecher/git/ojs-stable-3_4_0/lib/pkp/lib/vendor/guzzlehttp/guzzle/src/Handler/Proxy.php(28): GuzzleHttp\Handler\CurlHandler->__invoke()
#4 /home/asmecher/git/ojs-stable-3_4_0/lib/pkp/lib/vendor/guzzlehttp/guzzle/src/Handler/Proxy.php(48): GuzzleHttp\Handler\Proxy::GuzzleHttp\Handler\{closure}()
#5 /home/asmecher/git/ojs-stable-3_4_0/lib/pkp/lib/vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php(35): GuzzleHttp\Handler\Proxy::GuzzleHttp\Handler\{closure}()
#6 /home/asmecher/git/ojs-stable-3_4_0/lib/pkp/lib/vendor/guzzlehttp/guzzle/src/Middleware.php(31): GuzzleHttp\PrepareBodyMiddleware->__invoke()
#7 /home/asmecher/git/ojs-stable-3_4_0/lib/pkp/lib/vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php(71): GuzzleHttp\Middleware::GuzzleHttp\{closure}()
#8 /home/asmecher/git/ojs-stable-3_4_0/lib/pkp/lib/vendor/guzzlehttp/guzzle/src/Middleware.php(63): GuzzleHttp\RedirectMiddleware->__invoke()
#9 /home/asmecher/git/ojs-stable-3_4_0/lib/pkp/lib/vendor/guzzlehttp/guzzle/src/HandlerStack.php(75): GuzzleHttp\Middleware::GuzzleHttp\{closure}()
#10 /home/asmecher/git/ojs-stable-3_4_0/lib/pkp/lib/vendor/guzzlehttp/guzzle/src/Client.php(331): GuzzleHttp\HandlerStack->__invoke()
#11 /home/asmecher/git/ojs-stable-3_4_0/lib/pkp/lib/vendor/guzzlehttp/guzzle/src/Client.php(168): GuzzleHttp\Client->transfer()
#12 /home/asmecher/git/ojs-stable-3_4_0/lib/pkp/lib/vendor/guzzlehttp/guzzle/src/Client.php(187): GuzzleHttp\Client->requestAsync()
#13 /home/asmecher/git/ojs-stable-3_4_0/lib/pkp/classes/file/FileManager.php(298): GuzzleHttp\Client->request()
#14 /home/asmecher/git/ojs-stable-3_4_0/lib/pkp/classes/site/VersionCheck.php(93): PKP\file\FileManager::getStream()
#15 /home/asmecher/git/ojs-stable-3_4_0/lib/pkp/lib/vendor/elcobvg/laravel-opcache/src/Repository.php(25): PKP\site\VersionCheck::PKP\site\{closure}()
#16 /home/asmecher/git/ojs-stable-3_4_0/lib/pkp/lib/vendor/laravel/framework/src/Illuminate/Cache/CacheManager.php(419): ElcoBvg\Opcache\Repository->remember()
#17 /home/asmecher/git/ojs-stable-3_4_0/lib/pkp/lib/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php(338): Illuminate\Cache\CacheManager->__call()
#18 /home/asmecher/git/ojs-stable-3_4_0/lib/pkp/classes/site/VersionCheck.php(92): Illuminate\Support\Facades\Facade::__callStatic()
#19 /home/asmecher/git/ojs-stable-3_4_0/lib/pkp/classes/site/VersionCheck.php(57): PKP\site\VersionCheck::parseVersionXML()
#20 /home/asmecher/git/ojs-stable-3_4_0/lib/pkp/classes/site/VersionCheck.php(188): PKP\site\VersionCheck::getLatestVersion()
#21 /home/asmecher/git/ojs-stable-3_4_0/lib/pkp/pages/management/ManagementHandler.php(148): PKP\site\VersionCheck::checkIfNewVersionExists()
#22 /home/asmecher/git/ojs-stable-3_4_0/lib/pkp/pages/management/ManagementHandler.php(90): PKP\pages\management\ManagementHandler->context()
#23 [internal function]: PKP\pages\management\ManagementHandler->settings()
#24 /home/asmecher/git/ojs-stable-3_4_0/lib/pkp/classes/core/PKPRouter.php(334): call_user_func()
#25 /home/asmecher/git/ojs-stable-3_4_0/lib/pkp/classes/core/PKPPageRouter.php(277): PKP\core\PKPRouter->_authorizeInitializeAndCallRequest()
#26 /home/asmecher/git/ojs-stable-3_4_0/lib/pkp/classes/core/Dispatcher.php(165): PKP\core\PKPPageRouter->route()
#27 /home/asmecher/git/ojs-stable-3_4_0/lib/pkp/classes/core/PKPApplication.php(388): PKP\core\Dispatcher->dispatch()
#28 /home/asmecher/git/ojs-stable-3_4_0/index.php(21): PKP\core\PKPApplication->execute()
#29 {main}
  thrown in /home/asmecher/git/ojs-stable-3_4_0/lib/pkp/lib/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php on line 211

This mode of failure appears to be different than previous -- it appears this outage involved a certificate problem. It can probably be simulated by throwing a similar exception manually.

What application are you using? OJS, OMP or OPS version 3.4.0-x (main probably affected similarly; not sure about stable-3_3_0, as it may not have used Guzzle)

Related forum reports:

jonasraoni commented 4 months ago

@asmecher Please, check if this addresses the issue: https://github.com/pkp/pkp-lib/issues/9767 I didn't check, but AFAICR the plugin gallery received a fix a long time ago.

asmecher commented 4 months ago

No, we experienced this during yesterday's outage, and I verified in the latest stable-3_4_0 that I could reproduce the problem locally.

jonasraoni commented 4 months ago

Hmm, I see this is a different error (SSL certificate problem: certificate has expired), that probably happened due to routing problems (requests to pkp.sfu.ca were landing on the wrong server). Anyway, better to update the catch() to handle everything.

YvesLepidus commented 4 months ago

We updated to TransferException, which is a more generic exception class that covers ConnectException and RequestException.

asmecher commented 4 months ago

Thanks, @YvesLepidus! Merged and cherry-picked forward to main.

jonasraoni commented 4 months ago

Just to give a status:

Possible improvements: