From 75ef1341ebbc102ce5440338414c7a6aa2679645 Mon Sep 17 00:00:00 2001 From: Andy Miller Date: Thu, 30 Sep 2021 17:39:49 -0600 Subject: [PATCH] Added new HTTP\Client class for more general use --- system/blueprints/config/system.yaml | 90 ++++++++++---- system/config/system.yaml | 12 +- system/src/Grav/Common/GPM/Response.php | 144 +---------------------- system/src/Grav/Common/HTTP/Client.php | 125 ++++++++++++++++++++ system/src/Grav/Common/HTTP/Response.php | 96 +++++++++++++++ 5 files changed, 302 insertions(+), 165 deletions(-) create mode 100644 system/src/Grav/Common/HTTP/Client.php create mode 100644 system/src/Grav/Common/HTTP/Response.php diff --git a/system/blueprints/config/system.yaml b/system/blueprints/config/system.yaml index dffe09902..43679a11e 100644 --- a/system/blueprints/config/system.yaml +++ b/system/blueprints/config/system.yaml @@ -1446,6 +1446,10 @@ form: title: PLUGIN_ADMIN.ADVANCED underline: true + gpm_section: + type: section + title: PLUGIN_ADMIN.GPM_SECTION + gpm.releases: type: toggle label: PLUGIN_ADMIN.GPM_RELEASES @@ -1455,23 +1459,6 @@ form: stable: PLUGIN_ADMIN.STABLE testing: PLUGIN_ADMIN.TESTING - gpm.proxy_url: - type: text - size: medium - placeholder: "e.g. 127.0.0.1:3128" - label: PLUGIN_ADMIN.PROXY_URL - help: PLUGIN_ADMIN.PROXY_URL_HELP - - gpm.method: - type: toggle - label: PLUGIN_ADMIN.GPM_METHOD - highlight: auto - help: PLUGIN_ADMIN.GPM_METHOD_HELP - options: - auto: PLUGIN_ADMIN.AUTO - fopen: PLUGIN_ADMIN.FOPEN - curl: PLUGIN_ADMIN.CURL - gpm.official_gpm_only: type: toggle label: PLUGIN_ADMIN.GPM_OFFICIAL_ONLY @@ -1484,17 +1471,80 @@ form: validate: type: bool - gpm.verify_peer: + http_section: + type: section + title: PLUGIN_ADMIN.HTTP_SECTION + + http.method: type: toggle - label: PLUGIN_ADMIN.GPM_VERIFY_PEER + label: PLUGIN_ADMIN.GPM_METHOD + highlight: auto + help: PLUGIN_ADMIN.GPM_METHOD_HELP + options: + auto: PLUGIN_ADMIN.AUTO + fopen: PLUGIN_ADMIN.FOPEN + curl: PLUGIN_ADMIN.CURL + + http.enable_proxy: + type: toggle + label: PLUGIN_ADMIN.SSL_ENABLE_PROXY highlight: 1 - help: PLUGIN_ADMIN.GPM_VERIFY_PEER_HELP + options: + 1: PLUGIN_ADMIN.YES + 0: PLUGIN_ADMIN.NO + default: true + validate: + type: bool + + http.proxy_url: + type: text + size: medium + placeholder: "e.g. 127.0.0.1:3128" + label: PLUGIN_ADMIN.PROXY_URL + help: PLUGIN_ADMIN.PROXY_URL_HELP + + http.proxy_cert_path: + type: text + size: medium + placeholder: "e.g. /Users/bob/certs/" + label: PLUGIN_ADMIN.PROXY_CERT + help: PLUGIN_ADMIN.PROXY_CERT_HELP + + http.verify_peer: + type: toggle + label: PLUGIN_ADMIN.SSL_VERIFY_PEER + highlight: 1 + help: PLUGIN_ADMIN.SSL_VERIFY_PEER_HELP options: 1: PLUGIN_ADMIN.YES 0: PLUGIN_ADMIN.NO validate: type: bool + http.verify_host: + type: toggle + label: PLUGIN_ADMIN.SSL_VERIFY_HOST + highlight: 1 + help: PLUGIN_ADMIN.SSL_VERIFY_HOST_HELP + options: + 1: PLUGIN_ADMIN.YES + 0: PLUGIN_ADMIN.NO + validate: + type: bool + + http.concurrent_connections: + type: number + size: x-small + label: PLUGIN_ADMIN.HTTP_CONNECTIONS + help: PLUGIN_ADMIN.HTTP_CONNECTIONS_HELP + validate: + min: 1 + max: 20 + + misc_section: + type: section + title: PLUGIN_ADMIN.MISC_SECTION + reverse_proxy_setup: type: toggle label: PLUGIN_ADMIN.REVERSE_PROXY diff --git a/system/config/system.yaml b/system/config/system.yaml index fb5f391f4..140a95246 100644 --- a/system/config/system.yaml +++ b/system/config/system.yaml @@ -184,11 +184,17 @@ session: gpm: releases: stable # Set to either 'stable' or 'testing' - proxy_url: # Configure a manual proxy URL for GPM (eg 127.0.0.1:3128) - method: 'auto' # Either 'curl', 'fopen' or 'auto'. 'auto' will try fopen first and if not available cURL - verify_peer: true # Sometimes on some systems (Windows most commonly) GPM is unable to connect because the SSL certificate cannot be verified. Disabling this setting might help. official_gpm_only: true # By default GPM direct-install will only allow URLs via the official GPM proxy to ensure security +http: + method: auto # Either 'curl', 'fopen' or 'auto'. 'auto' will try fopen first and if not available cURL + enable_proxy: false # Enabled proxy server + proxy_url: # Configure a manual proxy URL for GPM (eg 127.0.0.1:3128) + proxy_cert_path: # Local path to proxy certificate folder containing pem files + concurrent_connections: 5 # Concurrent HTTP connections when multiplexing + verify_peer: true # Enable/Disable SSL verification of peer certificates + verify_host: true # Enable/Disable SSL verification of host certificates + accounts: type: regular # EXPERIMENTAL: Account type: regular or flex storage: file # EXPERIMENTAL: Flex storage type: file or folder diff --git a/system/src/Grav/Common/GPM/Response.php b/system/src/Grav/Common/GPM/Response.php index 47cef7c09..98654b6a1 100644 --- a/system/src/Grav/Common/GPM/Response.php +++ b/system/src/Grav/Common/GPM/Response.php @@ -1,143 +1,3 @@ 'Grav CMS' - ]; - - /** - * Makes a request to the URL by using the preferred method - * - * @param string $uri URL to call - * @param array $overrides An array of parameters for both `curl` and `fopen` - * @param callable|null $callback Either a function or callback in array notation - * @return string The response of the request - * @throws TransportExceptionInterface - */ - public static function get($uri = '', $overrides = [], $callback = null) - { - if (empty($uri)) { - throw new TransportException('missing URI'); - } - - // check if this function is available, if so use it to stop any timeouts - try { - if (Utils::functionExists('set_time_limit')) { - @set_time_limit(0); - } - } catch (Exception $e) { - } - - $config = Grav::instance()['config']; - $referer = defined('GRAV_CLI') ? 'grav_cli' : Grav::instance()['uri']->rootUrl(true); - $options = new HttpOptions(); - - // Set default Headers - $options->setHeaders(array_merge([ 'Referer' => $referer ], self::$headers)); - - // Disable verify Peer if required - $verify_peer = $config->get('system.gpm.verify_peer', true); - if ($verify_peer !== true) { - $options->verifyPeer($verify_peer); - } - - // Set proxy url if provided - $proxy_url = $config->get('system.gpm.proxy_url', false); - if ($proxy_url) { - $options->setProxy($proxy_url); - } - - // Use callback if provided - if ($callback) { - self::$callback = $callback; - $options->setOnProgress([Response::class, 'progress']); - } - - $preferred_method = $config->get('system.gpm.method', 'auto'); - - $settings = array_merge_recursive($options->toArray(), $overrides); - - switch ($preferred_method) { - case 'curl': - $client = new CurlHttpClient($settings); - break; - case 'fopen': - case 'native': - $client = new NativeHttpClient($settings); - break; - default: - $client = HttpClient::create($settings); - } - - $response = $client->request('GET', $uri); - - return $response->getContent(); - } - - - /** - * Is this a remote file or not - * - * @param string $file - * @return bool - */ - public static function isRemote($file) - { - return (bool) filter_var($file, FILTER_VALIDATE_URL); - } - - /** - * Progress normalized for cURL and Fopen - * Accepts a variable length of arguments passed in by stream method - * - * @return void - */ - public static function progress(int $bytes_transferred, int $filesize, array $info) - { - - if ($bytes_transferred > 0) { - $percent = $filesize <= 0 ? 0 : (int)(($bytes_transferred * 100) / $filesize); - - $progress = [ - 'code' => $info['http_code'], - 'filesize' => $filesize, - 'transferred' => $bytes_transferred, - 'percent' => $percent < 100 ? $percent : 100 - ]; - - if (self::$callback !== null) { - call_user_func(self::$callback, $progress); - } - } - } -} +// Create alias for the deprecated class. +class_alias(\Grav\Common\HTTP\Response::class, \Grav\Common\GPM\Response::class); diff --git a/system/src/Grav/Common/HTTP/Client.php b/system/src/Grav/Common/HTTP/Client.php new file mode 100644 index 000000000..d0d524dfb --- /dev/null +++ b/system/src/Grav/Common/HTTP/Client.php @@ -0,0 +1,125 @@ + 'Grav CMS' + ]; + + public static function getClient(array $overrides = [], int $connections = 6, callable $callback = null): HttpClientInterface + { + $config = Grav::instance()['config']; + $options = static::getOptions(); + + // Use callback if provided + if ($callback) { + self::$callback = $callback; + $options->setOnProgress([Response::class, 'progress']); + } + + $settings = array_merge($options->toArray(), $overrides); + $preferred_method = $config->get('system.http.method', $config->get('system.gpm.method', 'auto')); + + switch ($preferred_method) { + case 'curl': + $client = new CurlHttpClient($settings, $connections); + break; + case 'fopen': + case 'native': + $client = new NativeHttpClient($settings, $connections); + break; + default: + $client = HttpClient::create($settings, $connections); + } + + return $client; + } + + /** + * Get HTTP Options + * + * @return HttpOptions + */ + public static function getOptions(): HttpOptions + { + $config = Grav::instance()['config']; + $referer = defined('GRAV_CLI') ? 'grav_cli' : Grav::instance()['uri']->rootUrl(true); + + $options = new HttpOptions(); + + // Set default Headers + $options->setHeaders(array_merge([ 'Referer' => $referer ], self::$headers)); + + // Disable verify Peer if required + $verify_peer = $config->get('system.http.verify_peer', $config->get('system.gpm.verify_peer', null)); + if ($verify_peer !== null) { + $options->verifyPeer($verify_peer); + } + + // Disable verify Host if required + $verify_host = $config->get('system.http.verify_host', null); + if ($verify_host !== null) { + $options->verifyHost($verify_host); + } + + if ($config->get('system.http.enable_proxy', true)) { + // Set proxy url if provided + $proxy_url = $config->get('system.http.proxy_url', $config->get('system.gpm.proxy_url', null)); + if ($proxy_url !== null) { + $options->setProxy($proxy_url); + } + + // Certificate + $proxy_cert = $config->get('system.http.proxy_cert_path', null); + if ($proxy_cert !== null) { + $options->setCaPath($proxy_cert); + } + } + + return $options; + } + + /** + * Progress normalized for cURL and Fopen + * Accepts a variable length of arguments passed in by stream method + * + * @return void + */ + public static function progress(int $bytes_transferred, int $filesize, array $info) + { + + if ($bytes_transferred > 0) { + $percent = $filesize <= 0 ? 0 : (int)(($bytes_transferred * 100) / $filesize); + + $progress = [ + 'code' => $info['http_code'], + 'filesize' => $filesize, + 'transferred' => $bytes_transferred, + 'percent' => $percent < 100 ? $percent : 100 + ]; + + if (self::$callback !== null) { + call_user_func(self::$callback, $progress); + } + } + } +} diff --git a/system/src/Grav/Common/HTTP/Response.php b/system/src/Grav/Common/HTTP/Response.php new file mode 100644 index 000000000..4a0513667 --- /dev/null +++ b/system/src/Grav/Common/HTTP/Response.php @@ -0,0 +1,96 @@ +getContent(); + } + + + /** + * Makes a request to the URL by using the preferred method + * + * @param string $method method to call such as GET, PUT, etc + * @param string $uri URL to call + * @param array $overrides An array of parameters for both `curl` and `fopen` + * @param callable|null $callback Either a function or callback in array notation + * @return ResponseInterface + * @throws TransportExceptionInterface + */ + public static function request(string $method, string $uri, array $overrides = [], callable $callback = null): ResponseInterface + { + if (empty($method)) { + throw new TransportException('missing method (GET, PUT, etc.)'); + } + + if (empty($uri)) { + throw new TransportException('missing URI'); + } + + // check if this function is available, if so use it to stop any timeouts + try { + if (Utils::functionExists('set_time_limit')) { + @set_time_limit(0); + } + } catch (Exception $e) {} + + $client = Client::getClient($overrides, 6, $callback); + + return $client->request($method, $uri); + } + + + /** + * Is this a remote file or not + * + * @param string $file + * @return bool + */ + public static function isRemote($file): bool + { + return (bool) filter_var($file, FILTER_VALIDATE_URL); + } + + +}