From 8e660b9042f5203111b9d447cdd4fd90854661cf Mon Sep 17 00:00:00 2001 From: Andrew Madden Date: Mon, 9 Jan 2023 10:47:40 +1100 Subject: [PATCH] Issue #88 Use local_aws middleware to manage requests with proxies * Also fixes unit tests to be consistent if test server sets proxy in config.php. --- classes/esrequest.php | 85 +++++----------------------- tests/esrequest_test.php | 119 ++++----------------------------------- version.php | 6 +- 3 files changed, 28 insertions(+), 182 deletions(-) diff --git a/classes/esrequest.php b/classes/esrequest.php index ff550fa..212e09f 100644 --- a/classes/esrequest.php +++ b/classes/esrequest.php @@ -24,6 +24,8 @@ namespace search_elastic; +use local_aws\local\guzzle_helper; + defined('MOODLE_INTERNAL') || die(); require_once($CFG->dirroot . '/local/aws/sdk/aws-autoloader.php'); @@ -57,67 +59,13 @@ public function __construct($handler = false) { $this->config = get_config('search_elastic'); $this->signing = (isset($this->config->signing) ? (bool)$this->config->signing : false); - // Allow the caller to instansite the Guzzle client - // with a custom handler. + // Allow the caller to instantiate the Guzzle client with a custom handler. + $config = []; if ($handler) { - $this->client = new \GuzzleHttp\Client(['handler' => $handler]); - } else { - $this->client = new \GuzzleHttp\Client(); + $config['handler'] = $handler; } - } - - /** - * Constructs the Guzzle Proxy settings array - * based on Moodle's server proxy admin settings. - * - * @return array $proxy Proxy settings for Guzzle to use. - */ - private function proxyconstruct() { - global $CFG; - $proxy = array(); - $options = array(); - $protocol = 'tcp'; - $auth = ''; - $server = ''; - $uri = ''; - - if (! empty ( $CFG->proxyhost )) { - // Set the server details. - if (empty ( $CFG->proxyport )) { - $server = $CFG->proxyhost; - } else { - $server = $CFG->proxyhost . ':' . $CFG->proxyport; - } - - // Set the authentication details. - if (! empty ( $CFG->proxyuser ) and ! empty ( $CFG->proxypassword )) { - $auth = $CFG->proxyuser . ':' . $CFG->proxypassword . '@'; - } - - // Set the proxy type. - if (! empty ( $CFG->proxytype ) && $CFG->proxytype == 'SOCKS5') { - $protocol = 'socks5'; - } - - // Construct proxy URI. - $uri = $protocol . '://' . $auth . $server; - - // Populate proxy options array. - $options['http'] = $uri; - $options['https'] = $uri; - - // Set excluded domains. - if (! empty ($CFG->proxybypass) ) { - $nospace = preg_replace('/\s/', '', $CFG->proxybypass); - $options['no'] = explode(',', $nospace); - } - - // Finally populate proxy settings array. - $proxy['proxy'] = $options; - - } - - return $proxy; + $this->client = new \GuzzleHttp\Client($config); + $this->client = guzzle_helper::configure_client_proxy($this->client); } /** @@ -163,9 +111,9 @@ private function signrequest($request) { * @param array $proxy * @return \GuzzleHttp\Psr7\Response */ - private function http_action($psr7request, $proxy) { + private function http_action($psr7request) { try { - $response = $this->client->send($psr7request, $proxy); + $response = $this->client->send($psr7request); } catch (\GuzzleHttp\Exception\BadResponseException $e) { $response = $e->getResponse(); } catch (\GuzzleHttp\Exception\GuzzleException $e) { @@ -184,13 +132,12 @@ private function http_action($psr7request, $proxy) { */ public function get($url) { $psr7request = new \GuzzleHttp\Psr7\Request('GET', $url); - $proxy = $this->proxyconstruct(); if ($this->signing) { $psr7request = $this->signrequest($psr7request); } - $response = $this->http_action($psr7request, $proxy); + $response = $this->http_action($psr7request); return $response; @@ -206,13 +153,12 @@ public function get($url) { public function put($url, $params=null) { $headers = ['content-type' => 'application/json']; $psr7request = new \GuzzleHttp\Psr7\Request('PUT', $url, $headers, $params); - $proxy = $this->proxyconstruct(); if ($this->signing) { $psr7request = $this->signrequest($psr7request); } - $response = $this->http_action($psr7request, $proxy); + $response = $this->http_action($psr7request); return $response; @@ -227,13 +173,12 @@ public function put($url, $params=null) { public function post($url, $params) { $headers = ['content-type' => 'application/json']; $psr7request = new \GuzzleHttp\Psr7\Request('POST', $url, $headers, $params); - $proxy = $this->proxyconstruct(); if ($this->signing) { $psr7request = $this->signrequest($psr7request); } - $response = $this->http_action($psr7request, $proxy); + $response = $this->http_action($psr7request); return $response; @@ -257,9 +202,8 @@ public function postfile($url, $file) { ]); $psr7request = new \GuzzleHttp\Psr7\Request('POST', $url, $headers, $multipart); - $proxy = $this->proxyconstruct(); - $response = $this->http_action($psr7request, $proxy); + $response = $this->http_action($psr7request); return $response; @@ -273,13 +217,12 @@ public function postfile($url, $file) { */ public function delete($url) { $psr7request = new \GuzzleHttp\Psr7\Request('DELETE', $url); - $proxy = $this->proxyconstruct(); if ($this->signing) { $psr7request = $this->signrequest($psr7request); } - $response = $this->http_action($psr7request, $proxy); + $response = $this->http_action($psr7request); return $response; diff --git a/tests/esrequest_test.php b/tests/esrequest_test.php index 1a8e0f0..8be74a5 100644 --- a/tests/esrequest_test.php +++ b/tests/esrequest_test.php @@ -361,109 +361,15 @@ public function test_signed_delete() { } - /** - * Test that Guzzle proxy array is correctly constructed - * from Moodle Proxy settings. - */ - public function test_proxy_construct() { - $this->resetAfterTest(true); - set_config('proxyhost', 'localhost'); - set_config('proxyport', 3128); - set_config('proxybypass', 'localhost, 127.0.0.1'); - - // We're testing a private method, so we need to setup reflector magic. - $method = new ReflectionMethod('\search_elastic\esrequest', 'proxyconstruct'); - $method->setAccessible(true); // Allow accessing of private method. - $proxy = $method->invoke(new \search_elastic\esrequest); // Get result of invoked method. - - $expected = ['proxy' => ['http' => 'tcp://localhost:3128', - 'https' => 'tcp://localhost:3128', - 'no' => ['localhost', '127.0.0.1']]]; - - $this->assertEquals($expected, $proxy, $canonicalize = true); - } - - /** - * Test that Guzzle proxy array is correctly constructed - * from Moodle Proxy settings. - * With proxy authentication. - */ - public function test_proxy_construct_auth() { - $this->resetAfterTest(true); - set_config('proxyhost', 'localhost'); - set_config('proxyport', 3128); - set_config('proxybypass', 'localhost, 127.0.0.1'); - set_config('proxyuser', 'user1'); - set_config('proxypassword', 'password'); - - // We're testing a private method, so we need to setup reflector magic. - $method = new ReflectionMethod('\search_elastic\esrequest', 'proxyconstruct'); - $method->setAccessible(true); // Allow accessing of private method. - $proxy = $method->invoke(new \search_elastic\esrequest); // Get result of invoked method. - - $expected = ['proxy' => ['http' => 'tcp://user1:password@localhost:3128', - 'https' => 'tcp://user1:password@localhost:3128', - 'no' => ['localhost', '127.0.0.1']]]; - - $this->assertEquals($expected, $proxy, $canonicalize = true); - } - - /** - * Test that Guzzle proxy array is correctly constructed - * from Moodle Proxy settings. - * With proxy authentication and no proxy bypass. - */ - public function test_proxy_construct_no_bypass() { - $this->resetAfterTest(true); - set_config('proxyhost', 'localhost'); - set_config('proxyport', 3128); - set_config('proxybypass', ''); - set_config('proxyuser', 'user1'); - set_config('proxypassword', 'password'); - - // We're testing a private method, so we need to setup reflector magic. - $method = new ReflectionMethod('\search_elastic\esrequest', 'proxyconstruct'); - $method->setAccessible(true); // Allow accessing of private method. - $proxy = $method->invoke(new \search_elastic\esrequest); // Get result of invoked method. - - $expected = ['proxy' => ['http' => 'tcp://user1:password@localhost:3128', - 'https' => 'tcp://user1:password@localhost:3128']]; - - $this->assertEquals($expected, $proxy, $canonicalize = true); - } - - /** - * Test that Guzzle proxy array is correctly constructed - * from Moodle Proxy settings. - * Using socks as the protocol. - */ - public function test_proxy_construct_socks() { - $this->resetAfterTest(true); - set_config('proxyhost', 'localhost'); - set_config('proxyport', 3128); - set_config('proxybypass', 'localhost, 127.0.0.1'); - set_config('proxytype', 'SOCKS5'); - - // We're testing a private method, so we need to setup reflector magic. - $method = new ReflectionMethod('\search_elastic\esrequest', 'proxyconstruct'); - $method->setAccessible(true); // Allow accessing of private method. - $proxy = $method->invoke(new \search_elastic\esrequest); // Get result of invoked method. - - $expected = ['proxy' => ['http' => 'socks5://localhost:3128', - 'https' => 'socks5://localhost:3128', - 'no' => ['localhost', '127.0.0.1']]]; - - $this->assertEquals($expected, $proxy, $canonicalize = true); - } - /** * Test esrequest get with proxy functionality */ public function test_proxy_get() { + global $CFG; $this->resetAfterTest(true); - set_config('proxyhost', 'localhost'); - set_config('proxyport', 3128); - set_config('proxybypass', 'localhost, 127.0.0.1'); + $CFG->proxyhost = 'proxy.com'; + $CFG->proxyport = 3128; + $CFG->proxybypass = 'localhost, 127.0.0.1'; $container = []; $history = Middleware::history($container); @@ -477,24 +383,21 @@ public function test_proxy_get() { // Add the history middleware to the handler stack. $stack->push($history); - $url = 'http://localhost:8080/foo?bar=blerg'; + $url = 'http://example.com:8080/foo?bar=blerg'; $client = new \search_elastic\esrequest($stack); - $response = $client->get($url); + $client->get($url); $request = $container[0]['request']; - $hostheader = $request->getHeader('Host'); - $proxy = $container[0]['options']['proxy']; - $expected = ['http' => 'tcp://localhost:3128', - 'https' => 'tcp://localhost:3128', - 'no' => ['localhost', '127.0.0.1']]; + $lastrequestoptions = $mock->getLastOptions(); + $this->assertArrayHasKey('proxy', $lastrequestoptions); + $expected = 'proxy.com:3128'; // Check the results. $this->assertEquals('http', $request->getUri()->getScheme()); - $this->assertEquals('localhost', $request->getUri()->getHost()); + $this->assertEquals('example.com', $request->getUri()->getHost()); $this->assertEquals('8080', $request->getUri()->getPort()); $this->assertEquals('/foo', $request->getUri()->getPath()); $this->assertEquals('bar=blerg', $request->getUri()->getQuery()); - $this->assertEquals($expected, $proxy, $canonicalize = true); - + $this->assertEquals($expected, $lastrequestoptions['proxy']); } } diff --git a/version.php b/version.php index e31fa7a..5b18828 100644 --- a/version.php +++ b/version.php @@ -24,12 +24,12 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2022011600; -$plugin->release = '3.10 Build (2022011600)'; // Build same as version. +$plugin->version = 2022011601; +$plugin->release = '3.10 Build (2022011601)'; // Build same as version. $plugin->requires = 2016052304; $plugin->component = 'search_elastic'; $plugin->maturity = MATURITY_STABLE; $plugin->dependencies = array( - 'local_aws' => 2020061500 + 'local_aws' => 2023010900, ); $plugin->supported = [310, 311]; // A range of branch numbers of supported moodle versions.