From d344d36485cc707b28420801fc26d1e4d9380b2e Mon Sep 17 00:00:00 2001 From: Marcel Werk Date: Fri, 9 Aug 2024 14:44:31 +0200 Subject: [PATCH] Stop using HTTPRequest for package update server requests --- .../templates/packageUpdateUnauthorized.tpl | 8 +- .../PackageInstallationScheduler.class.php | 59 ++++++++---- .../package/PackageUpdateDispatcher.class.php | 75 ++++++++------- ...ckageUpdateUnauthorizedException.class.php | 91 ++++--------------- .../files/lib/util/HTTPRequest.class.php | 2 +- .../util/exception/HTTPException.class.php | 2 +- 6 files changed, 106 insertions(+), 131 deletions(-) diff --git a/wcfsetup/install/files/acp/templates/packageUpdateUnauthorized.tpl b/wcfsetup/install/files/acp/templates/packageUpdateUnauthorized.tpl index dcdb0924c6..09c845212c 100644 --- a/wcfsetup/install/files/acp/templates/packageUpdateUnauthorized.tpl +++ b/wcfsetup/install/files/acp/templates/packageUpdateUnauthorized.tpl @@ -2,7 +2,7 @@ {if $authInsufficient} {lang}wcf.acp.package.update.authInsufficient{/lang} {else} - {lang}wcf.acp.package.update.errorCode.{@$serverReply[statusCode]}{/lang} + {lang}wcf.acp.package.update.errorCode.{$responseStatusCode}{/lang} {/if} {/if} @@ -17,12 +17,12 @@ {/if}
{lang}wcf.acp.package.update.server.url{/lang}
-
{@$updateServer->getHighlightedURL()}
+
{unsafe:$updateServer->getHighlightedURL()}
{lang}wcf.acp.package.update.server.message{/lang}
-
{$serverReply[body]}
+
{$responseMessage}
@@ -51,5 +51,5 @@
- +
diff --git a/wcfsetup/install/files/lib/system/package/PackageInstallationScheduler.class.php b/wcfsetup/install/files/lib/system/package/PackageInstallationScheduler.class.php index 81e5cccd76..d1d8635618 100644 --- a/wcfsetup/install/files/lib/system/package/PackageInstallationScheduler.class.php +++ b/wcfsetup/install/files/lib/system/package/PackageInstallationScheduler.class.php @@ -2,20 +2,21 @@ namespace wcf\system\package; +use GuzzleHttp\Exception\ClientException; +use GuzzleHttp\Psr7\Request; +use GuzzleHttp\RequestOptions; use wcf\data\package\Package; use wcf\data\package\PackageCache; use wcf\data\package\update\PackageUpdate; use wcf\data\package\update\server\PackageUpdateServer; use wcf\system\database\util\PreparedStatementConditionBuilder; -use wcf\system\exception\HTTPUnauthorizedException; use wcf\system\exception\NamedUserException; use wcf\system\exception\SystemException; -use wcf\system\io\File; +use wcf\system\io\HttpFactory; use wcf\system\package\exception\IncoherentUpdatePath; use wcf\system\package\exception\UnknownUpdatePath; use wcf\system\WCF; use wcf\util\FileUtil; -use wcf\util\HTTPRequest; /** * Contains business logic related to preparation of package installations. @@ -266,14 +267,26 @@ final class PackageInstallationScheduler foreach ($packageUpdateVersions as $packageUpdateVersion) { // get auth data $authData = $this->getAuthData($packageUpdateVersion); + $options = []; + if (!empty($authData)) { + $options[RequestOptions::AUTH] = [ + $authData['username'], + $authData['password'], + ]; + } + $client = HttpFactory::makeClient($options); if ($packageUpdateVersion['filename']) { - $request = new HTTPRequest( + $request = new Request( + 'POST', $packageUpdateVersion['filename'], - (!empty($authData) ? ['auth' => $authData] : []), - [ - 'apiVersion' => PackageUpdate::API_VERSION, - ] + ['Content-Type' => 'application/x-www-form-urlencoded'], + \http_build_query( + ['apiVersion' => PackageUpdate::API_VERSION], + '', + '&', + \PHP_QUERY_RFC1738 + ) ); } else { $parameters = [ @@ -285,37 +298,43 @@ final class PackageInstallationScheduler $parameters['instanceId'] = \hash_hmac('sha256', 'api.woltlab.com', \WCF_UUID); } - $request = new HTTPRequest( + $request = new Request( + 'POST', $this->packageUpdateServers[$packageUpdateVersion['packageUpdateServerID']]->getDownloadURL(), - (!empty($authData) ? ['auth' => $authData] : []), - $parameters + ['Content-Type' => 'application/x-www-form-urlencoded'], + \http_build_query( + $parameters, + '', + '&', + \PHP_QUERY_RFC1738 + ) ); } try { - $request->execute(); - } catch (HTTPUnauthorizedException $e) { + $response = $client->send($request); + } catch (ClientException $e) { throw new PackageUpdateUnauthorizedException( - $request, + $e->getResponse()->getStatusCode(), + $e->getResponse()->getHeaders(), + $e->getResponse()->getBody(), $this->packageUpdateServers[$packageUpdateVersion['packageUpdateServerID']], $packageUpdateVersion ); } - $response = $request->getReply(); - // check response - if ($response['statusCode'] != 200) { + if ($response->getStatusCode() !== 200) { throw new SystemException(WCF::getLanguage()->getDynamicVariable( 'wcf.acp.package.error.downloadFailed', ['__downloadPackage' => $package] - ) . ' (' . $response['body'] . ')'); + ) . ' (' . $response->getBody() . ')'); } // write content to tmp file $filename = FileUtil::getTemporaryFilename('package_'); - \file_put_contents($filename, $response['body']); - unset($response['body']); + \file_put_contents($filename, $response->getBody()); + unset($response); // test package $archive = new PackageArchive($filename); diff --git a/wcfsetup/install/files/lib/system/package/PackageUpdateDispatcher.class.php b/wcfsetup/install/files/lib/system/package/PackageUpdateDispatcher.class.php index b3abe9b6d8..414d5b8910 100644 --- a/wcfsetup/install/files/lib/system/package/PackageUpdateDispatcher.class.php +++ b/wcfsetup/install/files/lib/system/package/PackageUpdateDispatcher.class.php @@ -2,7 +2,9 @@ namespace wcf\system\package; +use GuzzleHttp\Exception\ClientException; use GuzzleHttp\Psr7\Request; +use GuzzleHttp\RequestOptions; use Psr\Http\Client\ClientExceptionInterface; use wcf\data\package\Package; use wcf\data\package\update\server\PackageUpdateServer; @@ -11,13 +13,11 @@ use wcf\event\package\PackageUpdateListChanged; use wcf\system\cache\builder\PackageUpdateCacheBuilder; use wcf\system\database\util\PreparedStatementConditionBuilder; use wcf\system\event\EventHandler; -use wcf\system\exception\HTTPUnauthorizedException; use wcf\system\exception\SystemException; use wcf\system\io\HttpFactory; use wcf\system\package\validation\PackageValidationException; use wcf\system\SingletonFactory; use wcf\system\WCF; -use wcf\util\HTTPRequest; use wcf\util\JSON; use wcf\util\StringUtil; use wcf\util\XML; @@ -76,7 +76,7 @@ final class PackageUpdateDispatcher extends SingletonFactory } catch (SystemException $e) { $errorMessage = $e->getMessage(); } catch (PackageUpdateUnauthorizedException $e) { - $body = $e->getRequest()->getReply()['body']; + $body = $e->getResponseMessage(); // Try to find the page . if (\preg_match('~<title>(?<title>.*?)~', $body, $matches)) { @@ -147,23 +147,22 @@ final class PackageUpdateDispatcher extends SingletonFactory */ private function getPackageUpdateXML(PackageUpdateServer $updateServer) { - $settings = []; $authData = $updateServer->getAuthData(); - if ($authData) { - $settings['auth'] = $authData; + $options = []; + if (!empty($authData)) { + $options[RequestOptions::AUTH] = [ + $authData['username'], + $authData['password'], + ]; } - - $request = new HTTPRequest($updateServer->getListURL(), $settings); + $client = HttpFactory::makeClient($options); + $headers = []; $requestedVersion = \wcf\getMinorVersion(); if (PackageUpdateServer::isUpgradeOverrideEnabled()) { $requestedVersion = WCF::AVAILABLE_UPGRADE_VERSION; } - - $request->addHeader( - 'requested-woltlab-suite-version', - $requestedVersion - ); + $headers['requested-woltlab-suite-version'] = $requestedVersion; $apiVersion = $updateServer->apiVersion; if (\in_array($apiVersion, ['2.1', '3.1'])) { @@ -174,26 +173,34 @@ final class PackageUpdateDispatcher extends SingletonFactory ) { $metaData = $updateServer->getMetaData(); if (isset($metaData['list']['etag'])) { - $request->addHeader('if-none-match', $metaData['list']['etag']); + $headers['if-none-match'] = $metaData['list']['etag']; } if (isset($metaData['list']['lastModified'])) { - $request->addHeader('if-modified-since', $metaData['list']['lastModified']); + $headers['if-modified-since'] = $metaData['list']['lastModified']; } } } - try { - $request->execute(); - $reply = $request->getReply(); - } catch (HTTPUnauthorizedException $e) { - throw new PackageUpdateUnauthorizedException($request, $updateServer); - } catch (SystemException $e) { - $reply = $request->getReply(); + $request = new Request( + 'GET', + $updateServer->getListURL(), + $headers + ); - $statusCode = \is_array($reply['statusCode']) ? \reset($reply['statusCode']) : $reply['statusCode']; + try { + $response = $client->send($request); + } catch (ClientException $e) { + throw new PackageUpdateUnauthorizedException( + $e->getResponse()->getStatusCode(), + $e->getResponse()->getHeaders(), + $e->getResponse()->getBody(), + $updateServer, + ); + } + if ($response->getStatusCode() !== 200 && $response->getStatusCode() !== 304) { throw new SystemException( - WCF::getLanguage()->get('wcf.acp.package.update.error.listNotFound') . ' (' . $statusCode . ')' + WCF::getLanguage()->get('wcf.acp.package.update.error.listNotFound') . ' (' . $response->getStatusCode() . ')' ); } @@ -204,8 +211,8 @@ final class PackageUpdateDispatcher extends SingletonFactory ]; // check if server indicates support for a newer API - if ($updateServer->apiVersion !== '3.1' && !empty($reply['httpHeaders']['wcf-update-server-api'])) { - $apiVersions = \explode(' ', \reset($reply['httpHeaders']['wcf-update-server-api'])); + if ($updateServer->apiVersion !== '3.1' && !empty($response->getHeaders()['wcf-update-server-api'])) { + $apiVersions = \explode(' ', \reset($response->getHeaders()['wcf-update-server-api'])); if (\in_array('3.1', $apiVersions)) { $apiVersion = $data['apiVersion'] = '3.1'; } elseif (\in_array('2.1', $apiVersions)) { @@ -215,27 +222,27 @@ final class PackageUpdateDispatcher extends SingletonFactory // parse given package update xml $allNewPackages = false; - if ($apiVersion === '2.0' || $reply['statusCode'] != 304) { - $allNewPackages = $this->parsePackageUpdateXML($updateServer, $reply['body'], $apiVersion); + if ($apiVersion === '2.0' || $response->getStatusCode() != 304) { + $allNewPackages = $this->parsePackageUpdateXML($updateServer, $response->getBody(), $apiVersion); } $metaData = []; if (\in_array($apiVersion, ['2.1', '3.1'])) { - if (empty($reply['httpHeaders']['etag']) && empty($reply['httpHeaders']['last-modified'])) { + if (empty($response->getHeaders()['etag']) && empty($response->getHeaders()['last-modified'])) { throw new SystemException("Missing required HTTP headers 'etag' and 'last-modified'."); } $metaData['list'] = []; - if (!empty($reply['httpHeaders']['etag'])) { - $metaData['list']['etag'] = \reset($reply['httpHeaders']['etag']); + if (!empty($response->getHeaders()['etag'])) { + $metaData['list']['etag'] = \reset($response->getHeaders()['etag']); } - if (!empty($reply['httpHeaders']['last-modified'])) { - $metaData['list']['lastModified'] = \reset($reply['httpHeaders']['last-modified']); + if (!empty($response->getHeaders()['last-modified'])) { + $metaData['list']['lastModified'] = \reset($response->getHeaders()['last-modified']); } } $data['metaData'] = \serialize($metaData); - unset($request, $reply); + unset($request, $response); if ($allNewPackages !== false) { // purge package list diff --git a/wcfsetup/install/files/lib/system/package/PackageUpdateUnauthorizedException.class.php b/wcfsetup/install/files/lib/system/package/PackageUpdateUnauthorizedException.class.php index 808e3c813e..8ac5b02e48 100644 --- a/wcfsetup/install/files/lib/system/package/PackageUpdateUnauthorizedException.class.php +++ b/wcfsetup/install/files/lib/system/package/PackageUpdateUnauthorizedException.class.php @@ -5,64 +5,37 @@ namespace wcf\system\package; use wcf\data\package\update\server\PackageUpdateServer; use wcf\system\exception\UserException; use wcf\system\WCF; -use wcf\util\HTTPRequest; /** - * Credentials for update server are either missing or invalid. + * Handles the case that the credentials for update server are either missing or invalid. * - * @author Alexander Ebert - * @copyright 2001-2019 WoltLab GmbH - * @license GNU Lesser General Public License + * @author Alexander Ebert + * @copyright 2001-2024 WoltLab GmbH + * @license GNU Lesser General Public License */ -class PackageUpdateUnauthorizedException extends UserException +final class PackageUpdateUnauthorizedException extends UserException { /** - * package update version - * @var array - */ - protected $packageUpdateVersion = []; - - /** - * HTTP request object - * @var HTTPRequest - */ - protected $request; - - /** - * package update server object - * @var PackageUpdateServer - */ - protected $updateServer; - - /** - * Creates a new PackageUpdateUnauthorizedException object. - * - * @param HTTPRequest $request - * @param PackageUpdateServer $updateServer - * @param array $packageUpdateVersion + * @param string[] $responseHeaders + * @param mixed[] $packageUpdateVersion */ public function __construct( - HTTPRequest $request, - PackageUpdateServer $updateServer, - array $packageUpdateVersion = [] + private readonly int $responseStatusCode, + private readonly array $responseHeaders, + private readonly string $responseMessage, + private readonly PackageUpdateServer $updateServer, + private readonly array $packageUpdateVersion = [] ) { - $this->request = $request; - $this->updateServer = $updateServer; - $this->packageUpdateVersion = $packageUpdateVersion; } /** * Returns the rendered template. - * - * @return string */ - public function getRenderedTemplate() + public function getRenderedTemplate(): string { - $serverReply = $this->request->getReply(); - $requiresPaidUpgrade = false; if ($this->updateServer->isWoltLabStoreServer() && !empty($this->packageUpdateVersion['pluginStoreFileID'])) { - $requiresPaidUpgrade = ($serverReply['httpHeaders']['wcf-update-server-requires-paid-upgrade'][0] ?? '') === 'true'; + $requiresPaidUpgrade = ($this->responseHeaders['wcf-update-server-requires-paid-upgrade'][0] ?? '') === 'true'; } if ($requiresPaidUpgrade) { @@ -74,7 +47,7 @@ class PackageUpdateUnauthorizedException extends UserException return WCF::getTPL()->fetch('packageUpdateUnauthorizedPaidUpgrade'); } - $authInsufficient = (($serverReply['httpHeaders']['wcf-update-server-auth'][0] ?? '') === 'unauthorized'); + $authInsufficient = (($this->responseHeaders['wcf-update-server-auth'][0] ?? '') === 'unauthorized'); if ($authInsufficient && !empty($this->packageUpdateVersion['pluginStoreFileID'])) { $hasOnlyTrustedServers = true; foreach (PackageUpdateServer::getActiveUpdateServers() as $updateServer) { @@ -97,43 +70,19 @@ class PackageUpdateUnauthorizedException extends UserException WCF::getTPL()->assign([ 'authInsufficient' => $authInsufficient, 'packageUpdateVersion' => $this->packageUpdateVersion, - 'request' => $this->request, 'updateServer' => $this->updateServer, 'serverAuthData' => $this->updateServer->getAuthData(), - 'serverReply' => $serverReply, 'requiresPaidUpgrade' => $requiresPaidUpgrade, + 'responseStatusCode' => $this->responseStatusCode, + 'responseHeaders' => $this->responseHeaders, + 'responseMessage' => $this->responseMessage, ]); return WCF::getTPL()->fetch('packageUpdateUnauthorized'); } - /** - * Returns package update version. - * - * @return array - */ - public function getPackageUpdateVersion() - { - return $this->packageUpdateVersion; - } - - /** - * Returns the HTTP request object. - * - * @return HTTPRequest - */ - public function getRequest() - { - return $this->request; - } - - /** - * Returns package update server object. - * - * @return PackageUpdateServer - */ - public function getUpdateServer() + public function getResponseMessage(): string { - return $this->updateServer; + return $this->responseMessage; } } diff --git a/wcfsetup/install/files/lib/util/HTTPRequest.class.php b/wcfsetup/install/files/lib/util/HTTPRequest.class.php index 9dca0d48c5..50bf70962b 100644 --- a/wcfsetup/install/files/lib/util/HTTPRequest.class.php +++ b/wcfsetup/install/files/lib/util/HTTPRequest.class.php @@ -26,7 +26,7 @@ use wcf\util\exception\HTTPException; * @author Tim Duesterhus * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License - * @deprecated 5.3 - Use Guzzle via \wcf\system\io\HttpFactory. + * @deprecated 5.3 - Use Guzzle via \wcf\system\io\HttpFactory. Will be removed with 7.0. */ final class HTTPRequest { diff --git a/wcfsetup/install/files/lib/util/exception/HTTPException.class.php b/wcfsetup/install/files/lib/util/exception/HTTPException.class.php index aa5ffbe511..0e53ad10a3 100644 --- a/wcfsetup/install/files/lib/util/exception/HTTPException.class.php +++ b/wcfsetup/install/files/lib/util/exception/HTTPException.class.php @@ -14,7 +14,7 @@ use wcf\util\StringUtil; * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * @since 3.0 - * @deprecated 5.3 This exception is intimately tied to HTTPRequest which is deprecated. + * @deprecated 5.3 This exception is intimately tied to HTTPRequest which is deprecated. Will be removed with 7.0. */ class HTTPException extends SystemException implements IExtraInformationException { -- 2.20.1