Set User-Agent as header without middleware

Signed-off-by: Daniel Kesselberg <mail@danielkesselberg.de>
This commit is contained in:
Daniel Kesselberg 2019-02-24 14:48:05 +01:00
parent 5df12cbf47
commit 2708d26407
No known key found for this signature in database
GPG Key ID: 36E3664E099D0614
4 changed files with 104 additions and 97 deletions

View File

@ -25,13 +25,11 @@ declare(strict_types=1);
namespace OC\Http\Client; namespace OC\Http\Client;
use GuzzleHttp\Client as GuzzleClient; use GuzzleHttp\Client as GuzzleClient;
use GuzzleHttp\HandlerStack; use GuzzleHttp\RequestOptions;
use GuzzleHttp\Middleware;
use OCP\Http\Client\IClient; use OCP\Http\Client\IClient;
use OCP\Http\Client\IResponse; use OCP\Http\Client\IResponse;
use OCP\ICertificateManager; use OCP\ICertificateManager;
use OCP\IConfig; use OCP\IConfig;
use Psr\Http\Message\RequestInterface;
/** /**
* Class Client * Class Client
@ -45,9 +43,6 @@ class Client implements IClient {
private $config; private $config;
/** @var ICertificateManager */ /** @var ICertificateManager */
private $certificateManager; private $certificateManager;
private $configured = false;
/** @var HandlerStack */
private $stack;
/** /**
* @param IConfig $config * @param IConfig $config
@ -57,66 +52,57 @@ class Client implements IClient {
public function __construct( public function __construct(
IConfig $config, IConfig $config,
ICertificateManager $certificateManager, ICertificateManager $certificateManager,
GuzzleClient $client, GuzzleClient $client
HandlerStack $stack
) { ) {
$this->config = $config; $this->config = $config;
$this->client = $client; $this->client = $client;
$this->stack = $stack;
$this->certificateManager = $certificateManager; $this->certificateManager = $certificateManager;
} }
/** private function buildRequestOptions(array $options): array {
* Sets the default options to the client $defaults = [
*/ RequestOptions::PROXY => $this->getProxyUri(),
private function setDefaultOptions() { RequestOptions::VERIFY => $this->getCertBundle(),
if ($this->configured) {
return;
}
$this->configured = true;
$this->stack->push(Middleware::mapRequest(function (RequestInterface $request) {
return $request
->withHeader('User-Agent', 'Nextcloud Server Crawler');
}));
}
private function getRequestOptions() {
$options = [
'verify' => $this->getCertBundle(),
]; ];
$proxyUri = $this->getProxyUri();
if ($proxyUri !== '') { $options = array_merge($defaults, $options);
$options['proxy'] = $proxyUri;
if (!isset($options[RequestOptions::HEADERS]['User-Agent'])) {
$options[RequestOptions::HEADERS]['User-Agent'] = 'Nextcloud Server Crawler';
} }
return $options; return $options;
} }
private function getCertBundle() { private function getCertBundle(): string {
if ($this->certificateManager->listCertificates() !== []) { if ($this->certificateManager->listCertificates() !== []) {
return $this->certificateManager->getAbsoluteBundlePath(); return $this->certificateManager->getAbsoluteBundlePath();
} else {
// If the instance is not yet setup we need to use the static path as
// $this->certificateManager->getAbsoluteBundlePath() tries to instantiiate
// a view
if ($this->config->getSystemValue('installed', false)) {
return $this->certificateManager->getAbsoluteBundlePath(null);
} else {
return \OC::$SERVERROOT . '/resources/config/ca-bundle.crt';
}
} }
// If the instance is not yet setup we need to use the static path as
// $this->certificateManager->getAbsoluteBundlePath() tries to instantiiate
// a view
if ($this->config->getSystemValue('installed', false)) {
return $this->certificateManager->getAbsoluteBundlePath(null);
}
return \OC::$SERVERROOT . '/resources/config/ca-bundle.crt';
} }
/** /**
* Get the proxy URI * Get the proxy URI
* *
* @return string * @return string|null
*/ */
private function getProxyUri(): string { private function getProxyUri(): ?string {
$proxyHost = $this->config->getSystemValue('proxy', null); $proxyHost = $this->config->getSystemValue('proxy', null);
$proxyUserPwd = $this->config->getSystemValue('proxyuserpwd', null); $proxyUserPwd = $this->config->getSystemValue('proxyuserpwd', null);
$proxyUri = '';
if ($proxyHost === null && $proxyUserPwd === null) {
return null;
}
$proxyUri = '';
if ($proxyUserPwd !== null) { if ($proxyUserPwd !== null) {
$proxyUri .= $proxyUserPwd . '@'; $proxyUri .= $proxyUserPwd . '@';
} }
@ -157,8 +143,7 @@ class Client implements IClient {
* @throws \Exception If the request could not get completed * @throws \Exception If the request could not get completed
*/ */
public function get(string $uri, array $options = []): IResponse { public function get(string $uri, array $options = []): IResponse {
$this->setDefaultOptions(); $response = $this->client->request('get', $uri, $this->buildRequestOptions($options));
$response = $this->client->request('get', $uri, array_merge($this->getRequestOptions(), $options));
$isStream = isset($options['stream']) && $options['stream']; $isStream = isset($options['stream']) && $options['stream'];
return new Response($response, $isStream); return new Response($response, $isStream);
} }
@ -188,8 +173,7 @@ class Client implements IClient {
* @throws \Exception If the request could not get completed * @throws \Exception If the request could not get completed
*/ */
public function head(string $uri, array $options = []): IResponse { public function head(string $uri, array $options = []): IResponse {
$this->setDefaultOptions(); $response = $this->client->request('head', $uri, $this->buildRequestOptions($options));
$response = $this->client->request('head', $uri, array_merge($this->getRequestOptions(), $options));
return new Response($response); return new Response($response);
} }
@ -223,12 +207,11 @@ class Client implements IClient {
* @throws \Exception If the request could not get completed * @throws \Exception If the request could not get completed
*/ */
public function post(string $uri, array $options = []): IResponse { public function post(string $uri, array $options = []): IResponse {
$this->setDefaultOptions();
if (isset($options['body']) && is_array($options['body'])) { if (isset($options['body']) && is_array($options['body'])) {
$options['form_params'] = $options['body']; $options['form_params'] = $options['body'];
unset($options['body']); unset($options['body']);
} }
$response = $this->client->request('post', $uri, array_merge($this->getRequestOptions(), $options)); $response = $this->client->request('post', $uri, $this->buildRequestOptions($options));
return new Response($response); return new Response($response);
} }
@ -262,8 +245,7 @@ class Client implements IClient {
* @throws \Exception If the request could not get completed * @throws \Exception If the request could not get completed
*/ */
public function put(string $uri, array $options = []): IResponse { public function put(string $uri, array $options = []): IResponse {
$this->setDefaultOptions(); $response = $this->client->request('put', $uri, $this->buildRequestOptions($options));
$response = $this->client->request('put', $uri, array_merge($this->getRequestOptions(), $options));
return new Response($response); return new Response($response);
} }
@ -297,12 +279,10 @@ class Client implements IClient {
* @throws \Exception If the request could not get completed * @throws \Exception If the request could not get completed
*/ */
public function delete(string $uri, array $options = []): IResponse { public function delete(string $uri, array $options = []): IResponse {
$this->setDefaultOptions(); $response = $this->client->request('delete', $uri, $this->buildRequestOptions($options));
$response = $this->client->request('delete', $uri, array_merge($this->getRequestOptions(), $options));
return new Response($response); return new Response($response);
} }
/** /**
* Sends a options request * Sends a options request
* *
@ -333,8 +313,7 @@ class Client implements IClient {
* @throws \Exception If the request could not get completed * @throws \Exception If the request could not get completed
*/ */
public function options(string $uri, array $options = []): IResponse { public function options(string $uri, array $options = []): IResponse {
$this->setDefaultOptions(); $response = $this->client->request('options', $uri, $this->buildRequestOptions($options));
$response = $this->client->request('options', $uri, array_merge($this->getRequestOptions(), $options));
return new Response($response); return new Response($response);
} }
} }

View File

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace OC\Http\Client; namespace OC\Http\Client;
use GuzzleHttp\Client as GuzzleClient; use GuzzleHttp\Client as GuzzleClient;
use GuzzleHttp\HandlerStack;
use OCP\Http\Client\IClient; use OCP\Http\Client\IClient;
use OCP\Http\Client\IClientService; use OCP\Http\Client\IClientService;
use OCP\ICertificateManager; use OCP\ICertificateManager;
@ -55,6 +54,6 @@ class ClientService implements IClientService {
* @return Client * @return Client
*/ */
public function newClient(): IClient { public function newClient(): IClient {
return new Client($this->config, $this->certificateManager, new GuzzleClient(), HandlerStack::create()); return new Client($this->config, $this->certificateManager, new GuzzleClient());
} }
} }

View File

@ -9,7 +9,6 @@
namespace Test\Http\Client; namespace Test\Http\Client;
use GuzzleHttp\Client as GuzzleClient; use GuzzleHttp\Client as GuzzleClient;
use GuzzleHttp\HandlerStack;
use OC\Http\Client\Client; use OC\Http\Client\Client;
use OC\Http\Client\ClientService; use OC\Http\Client\ClientService;
use OCP\ICertificateManager; use OCP\ICertificateManager;
@ -19,12 +18,16 @@ use OCP\IConfig;
* Class ClientServiceTest * Class ClientServiceTest
*/ */
class ClientServiceTest extends \Test\TestCase { class ClientServiceTest extends \Test\TestCase {
public function testNewClient() { public function testNewClient(): void {
/** @var IConfig $config */
$config = $this->createMock(IConfig::class); $config = $this->createMock(IConfig::class);
/** @var ICertificateManager $certificateManager */
$certificateManager = $this->createMock(ICertificateManager::class); $certificateManager = $this->createMock(ICertificateManager::class);
$expected = new Client($config, $certificateManager, new GuzzleClient(), HandlerStack::create());
$clientService = new ClientService($config, $certificateManager); $clientService = new ClientService($config, $certificateManager);
$this->assertEquals($expected, $clientService->newClient()); $this->assertEquals(
new Client($config, $certificateManager, new GuzzleClient()),
$clientService->newClient()
);
} }
} }

View File

@ -8,7 +8,6 @@
namespace Test\Http\Client; namespace Test\Http\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Response; use GuzzleHttp\Psr7\Response;
use OC\Http\Client\Client; use OC\Http\Client\Client;
use OC\Security\CertificateManager; use OC\Security\CertificateManager;
@ -33,19 +32,18 @@ class ClientTest extends \Test\TestCase {
public function setUp() { public function setUp() {
parent::setUp(); parent::setUp();
$this->config = $this->createMock(IConfig::class); $this->config = $this->createMock(IConfig::class);
$this->guzzleClient = $this->getMockBuilder('\GuzzleHttp\Client') $this->guzzleClient = $this->getMockBuilder(\GuzzleHttp\Client::class)
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMock(); ->getMock();
$this->certificateManager = $this->createMock(ICertificateManager::class); $this->certificateManager = $this->createMock(ICertificateManager::class);
$this->client = new Client( $this->client = new Client(
$this->config, $this->config,
$this->certificateManager, $this->certificateManager,
$this->guzzleClient, $this->guzzleClient
HandlerStack::create()
); );
} }
public function testGetProxyUri() { public function testGetProxyUri(): void {
$this->config $this->config
->expects($this->at(0)) ->expects($this->at(0))
->method('getSystemValue') ->method('getSystemValue')
@ -56,10 +54,10 @@ class ClientTest extends \Test\TestCase {
->method('getSystemValue') ->method('getSystemValue')
->with('proxyuserpwd', null) ->with('proxyuserpwd', null)
->willReturn(null); ->willReturn(null);
$this->assertSame('', self::invokePrivate($this->client, 'getProxyUri')); $this->assertNull(self::invokePrivate($this->client, 'getProxyUri'));
} }
public function testGetProxyUriProxyHostEmptyPassword() { public function testGetProxyUriProxyHostEmptyPassword(): void {
$this->config $this->config
->expects($this->at(0)) ->expects($this->at(0))
->method('getSystemValue') ->method('getSystemValue')
@ -73,7 +71,7 @@ class ClientTest extends \Test\TestCase {
$this->assertSame('foo', self::invokePrivate($this->client, 'getProxyUri')); $this->assertSame('foo', self::invokePrivate($this->client, 'getProxyUri'));
} }
public function testGetProxyUriProxyHostWithPassword() { public function testGetProxyUriProxyHostWithPassword(): void {
$this->config $this->config
->expects($this->at(0)) ->expects($this->at(0))
->method('getSystemValue') ->method('getSystemValue')
@ -87,7 +85,7 @@ class ClientTest extends \Test\TestCase {
$this->assertSame('username:password@foo', self::invokePrivate($this->client, 'getProxyUri')); $this->assertSame('username:password@foo', self::invokePrivate($this->client, 'getProxyUri'));
} }
private function setUpDefaultRequestOptions() { private function setUpDefaultRequestOptions(): void {
$this->config $this->config
->expects($this->at(0)) ->expects($this->at(0))
->method('getSystemValue') ->method('getSystemValue')
@ -106,11 +104,14 @@ class ClientTest extends \Test\TestCase {
$this->defaultRequestOptions = [ $this->defaultRequestOptions = [
'verify' => '/my/path.crt', 'verify' => '/my/path.crt',
'proxy' => 'foo' 'proxy' => 'foo',
'headers' => [
'User-Agent' => 'Nextcloud Server Crawler'
]
]; ];
} }
public function testGet() { public function testGet(): void {
$this->setUpDefaultRequestOptions(); $this->setUpDefaultRequestOptions();
$this->guzzleClient->method('request') $this->guzzleClient->method('request')
@ -119,12 +120,15 @@ class ClientTest extends \Test\TestCase {
$this->assertEquals(1337, $this->client->get('http://localhost/', [])->getStatusCode()); $this->assertEquals(1337, $this->client->get('http://localhost/', [])->getStatusCode());
} }
public function testGetWithOptions() { public function testGetWithOptions(): void {
$this->setUpDefaultRequestOptions(); $this->setUpDefaultRequestOptions();
$options = [ $options = [
'verify' => false, 'verify' => false,
'proxy' => 'bar' 'proxy' => 'bar',
'headers' => [
'User-Agent' => 'Nextcloud Server Crawler'
]
]; ];
$this->guzzleClient->method('request') $this->guzzleClient->method('request')
@ -133,7 +137,7 @@ class ClientTest extends \Test\TestCase {
$this->assertEquals(1337, $this->client->get('http://localhost/', $options)->getStatusCode()); $this->assertEquals(1337, $this->client->get('http://localhost/', $options)->getStatusCode());
} }
public function testPost() { public function testPost(): void {
$this->setUpDefaultRequestOptions(); $this->setUpDefaultRequestOptions();
$this->guzzleClient->method('request') $this->guzzleClient->method('request')
@ -142,12 +146,15 @@ class ClientTest extends \Test\TestCase {
$this->assertEquals(1337, $this->client->post('http://localhost/', [])->getStatusCode()); $this->assertEquals(1337, $this->client->post('http://localhost/', [])->getStatusCode());
} }
public function testPostWithOptions() { public function testPostWithOptions(): void {
$this->setUpDefaultRequestOptions(); $this->setUpDefaultRequestOptions();
$options = [ $options = [
'verify' => false, 'verify' => false,
'proxy' => 'bar' 'proxy' => 'bar',
'headers' => [
'User-Agent' => 'Nextcloud Server Crawler'
]
]; ];
$this->guzzleClient->method('request') $this->guzzleClient->method('request')
@ -156,7 +163,7 @@ class ClientTest extends \Test\TestCase {
$this->assertEquals(1337, $this->client->post('http://localhost/', $options)->getStatusCode()); $this->assertEquals(1337, $this->client->post('http://localhost/', $options)->getStatusCode());
} }
public function testPut() { public function testPut(): void {
$this->setUpDefaultRequestOptions(); $this->setUpDefaultRequestOptions();
$this->guzzleClient->method('request') $this->guzzleClient->method('request')
@ -165,12 +172,15 @@ class ClientTest extends \Test\TestCase {
$this->assertEquals(1337, $this->client->put('http://localhost/', [])->getStatusCode()); $this->assertEquals(1337, $this->client->put('http://localhost/', [])->getStatusCode());
} }
public function testPutWithOptions() { public function testPutWithOptions(): void {
$this->setUpDefaultRequestOptions(); $this->setUpDefaultRequestOptions();
$options = [ $options = [
'verify' => false, 'verify' => false,
'proxy' => 'bar' 'proxy' => 'bar',
'headers' => [
'User-Agent' => 'Nextcloud Server Crawler'
]
]; ];
$this->guzzleClient->method('request') $this->guzzleClient->method('request')
@ -179,7 +189,7 @@ class ClientTest extends \Test\TestCase {
$this->assertEquals(1337, $this->client->put('http://localhost/', $options)->getStatusCode()); $this->assertEquals(1337, $this->client->put('http://localhost/', $options)->getStatusCode());
} }
public function testDelete() { public function testDelete(): void {
$this->setUpDefaultRequestOptions(); $this->setUpDefaultRequestOptions();
$this->guzzleClient->method('request') $this->guzzleClient->method('request')
@ -188,12 +198,15 @@ class ClientTest extends \Test\TestCase {
$this->assertEquals(1337, $this->client->delete('http://localhost/', [])->getStatusCode()); $this->assertEquals(1337, $this->client->delete('http://localhost/', [])->getStatusCode());
} }
public function testDeleteWithOptions() { public function testDeleteWithOptions(): void {
$this->setUpDefaultRequestOptions(); $this->setUpDefaultRequestOptions();
$options = [ $options = [
'verify' => false, 'verify' => false,
'proxy' => 'bar' 'proxy' => 'bar',
'headers' => [
'User-Agent' => 'Nextcloud Server Crawler'
]
]; ];
$this->guzzleClient->method('request') $this->guzzleClient->method('request')
@ -202,7 +215,7 @@ class ClientTest extends \Test\TestCase {
$this->assertEquals(1337, $this->client->delete('http://localhost/', $options)->getStatusCode()); $this->assertEquals(1337, $this->client->delete('http://localhost/', $options)->getStatusCode());
} }
public function testOptions() { public function testOptions(): void {
$this->setUpDefaultRequestOptions(); $this->setUpDefaultRequestOptions();
$this->guzzleClient->method('request') $this->guzzleClient->method('request')
@ -211,12 +224,15 @@ class ClientTest extends \Test\TestCase {
$this->assertEquals(1337, $this->client->options('http://localhost/', [])->getStatusCode()); $this->assertEquals(1337, $this->client->options('http://localhost/', [])->getStatusCode());
} }
public function testOptionsWithOptions() { public function testOptionsWithOptions(): void {
$this->setUpDefaultRequestOptions(); $this->setUpDefaultRequestOptions();
$options = [ $options = [
'verify' => false, 'verify' => false,
'proxy' => 'bar' 'proxy' => 'bar',
'headers' => [
'User-Agent' => 'Nextcloud Server Crawler'
]
]; ];
$this->guzzleClient->method('request') $this->guzzleClient->method('request')
@ -225,7 +241,7 @@ class ClientTest extends \Test\TestCase {
$this->assertEquals(1337, $this->client->options('http://localhost/', $options)->getStatusCode()); $this->assertEquals(1337, $this->client->options('http://localhost/', $options)->getStatusCode());
} }
public function testHead() { public function testHead(): void {
$this->setUpDefaultRequestOptions(); $this->setUpDefaultRequestOptions();
$this->guzzleClient->method('request') $this->guzzleClient->method('request')
@ -234,12 +250,15 @@ class ClientTest extends \Test\TestCase {
$this->assertEquals(1337, $this->client->head('http://localhost/', [])->getStatusCode()); $this->assertEquals(1337, $this->client->head('http://localhost/', [])->getStatusCode());
} }
public function testHeadWithOptions() { public function testHeadWithOptions(): void {
$this->setUpDefaultRequestOptions(); $this->setUpDefaultRequestOptions();
$options = [ $options = [
'verify' => false, 'verify' => false,
'proxy' => 'bar' 'proxy' => 'bar',
'headers' => [
'User-Agent' => 'Nextcloud Server Crawler'
]
]; ];
$this->guzzleClient->method('request') $this->guzzleClient->method('request')
@ -248,9 +267,9 @@ class ClientTest extends \Test\TestCase {
$this->assertEquals(1337, $this->client->head('http://localhost/', $options)->getStatusCode()); $this->assertEquals(1337, $this->client->head('http://localhost/', $options)->getStatusCode());
} }
public function testSetDefaultOptionsWithNotInstalled() { public function testSetDefaultOptionsWithNotInstalled(): void {
$this->config $this->config
->expects($this->at(0)) ->expects($this->at(2))
->method('getSystemValue') ->method('getSystemValue')
->with('installed', false) ->with('installed', false)
->willReturn(false); ->willReturn(false);
@ -260,11 +279,15 @@ class ClientTest extends \Test\TestCase {
->willReturn([]); ->willReturn([]);
$this->assertEquals([ $this->assertEquals([
'verify' => \OC::$SERVERROOT . '/resources/config/ca-bundle.crt' 'verify' => \OC::$SERVERROOT . '/resources/config/ca-bundle.crt',
], self::invokePrivate($this->client, 'getRequestOptions')); 'proxy' => null,
'headers' => [
'User-Agent' => 'Nextcloud Server Crawler'
]
], self::invokePrivate($this->client, 'buildRequestOptions', [[]]));
} }
public function testSetDefaultOptionsWithProxy() { public function testSetDefaultOptionsWithProxy(): void {
$this->config $this->config
->expects($this->at(0)) ->expects($this->at(0))
->method('getSystemValue') ->method('getSystemValue')
@ -283,7 +306,10 @@ class ClientTest extends \Test\TestCase {
$this->assertEquals([ $this->assertEquals([
'verify' => '/my/path.crt', 'verify' => '/my/path.crt',
'proxy' => 'foo' 'proxy' => 'foo',
], self::invokePrivate($this->client, 'getRequestOptions')); 'headers' => [
'User-Agent' => 'Nextcloud Server Crawler'
]
], self::invokePrivate($this->client, 'buildRequestOptions', [[]]));
} }
} }