Skip to content

Commit

Permalink
Test PageViewProxy, adding web server
Browse files Browse the repository at this point in the history
Fix empty header in PageViewProxy.
  • Loading branch information
Kajetan Dvoracek committed Mar 24, 2022
1 parent bc018a6 commit 2f67253
Show file tree
Hide file tree
Showing 8 changed files with 258 additions and 1 deletion.
29 changes: 29 additions & 0 deletions Build/Test/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,34 @@ services:
tmpfs:
- /var/lib/mysql/:rw,noexec,nosuid

web:
image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest
user: "${HOST_UID}:${HOST_GID}"
stop_grace_period: 1s
volumes:
- ${DLF_ROOT}:${DLF_ROOT}
extra_hosts:
- "host.docker.internal:host-gateway"
ports:
- "8000:8000"
# NOTE: For testing PageViewProxy, we need another web server web:8001 that
# can be requested from TYPO3 running on web:8000.
# Setting PHP_CLI_SERVER_WORKERS wouldn't seem to work consistently.
command: >
/bin/sh -c "
if [ ${PHP_XDEBUG_ON} -eq 0 ]; then
XDEBUG_MODE=\"off\" \
php -S web:8000 -t ${DLF_ROOT} ${DLF_ROOT}/Tests/routeFunctionalInstance.php &
php -S web:8001 -t ${DLF_ROOT}
else
XDEBUG_MODE=\"debug,develop\" \
XDEBUG_TRIGGER=\"foo\" \
XDEBUG_CONFIG=\"client_port=${PHP_XDEBUG_PORT} client_host=host.docker.internal\" \
php -S web:8000 -t ${DLF_ROOT} ${DLF_ROOT}/Tests/routeFunctionalInstance.php &
php -S web:8001 -t ${DLF_ROOT}
fi
"
composer_install:
image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest
user: "${HOST_UID}:${HOST_GID}"
Expand All @@ -40,6 +68,7 @@ services:
image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest
links:
- ${DBMS}
- web
user: "${HOST_UID}:${HOST_GID}"
volumes:
- ${DLF_ROOT}:${DLF_ROOT}
Expand Down
5 changes: 4 additions & 1 deletion Classes/Plugin/Eid/PageViewProxy.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,10 @@ protected function copyHeaders(

foreach ($headerNames as $headerName) {
$headerValues = $fromResponse->getHeader($headerName);
$result = $result->withAddedHeader($headerName, $headerValues);
// Don't include empty header field when not present
if (!empty($headerValues)) {
$result = $result->withAddedHeader($headerName, $headerValues);
}
}

return $result;
Expand Down
3 changes: 3 additions & 0 deletions Tests/Fixtures/PageViewProxy/echo_user_agent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?php

echo $_SERVER['HTTP_USER_AGENT'];
1 change: 1 addition & 0 deletions Tests/Fixtures/PageViewProxy/test.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This is some plain text test file.
36 changes: 36 additions & 0 deletions Tests/Functional/Api/PageViewProxyDisabledTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace Kitodo\Dlf\Tests\Functional\Api;

use Kitodo\Dlf\Tests\Functional\FunctionalTestCase;
use TYPO3\CMS\Core\Utility\GeneralUtility;

class PageViewProxyDisabledTest extends FunctionalTestCase
{
protected $disableJsonWrappedResponse = true;

protected function queryProxy(array $query, string $method = 'GET')
{
$query['eID'] = 'tx_dlf_pageview_proxy';

return $this->httpClient->request($method, '', [
'query' => $query,
]);
}

/**
* @test
*/
public function cannotAccessPageWhenProxyIsDisabled(): void
{
$targetUrl = 'http://web:8001/Tests/Fixtures/PageViewProxy/test.txt';
$uHash = GeneralUtility::hmac($targetUrl, 'PageViewProxy');

$response = $this->queryProxy([
'url' => $targetUrl,
'uHash' => $uHash,
]);

$this->assertEquals(404, $response->getStatusCode());
}
}
128 changes: 128 additions & 0 deletions Tests/Functional/Api/PageViewProxyTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
<?php

namespace Kitodo\Dlf\Tests\Functional\Api;

use GuzzleHttp\Client as HttpClient;
use Kitodo\Dlf\Tests\Functional\FunctionalTestCase;
use TYPO3\CMS\Core\Utility\GeneralUtility;

class PageViewProxyTest extends FunctionalTestCase
{
protected $disableJsonWrappedResponse = true;

protected function getDlfConfiguration()
{
return array_merge(parent::getDlfConfiguration(), [
'enableInternalProxy' => true,
]);
}

protected function queryProxy(array $query, string $method = 'GET')
{
$query['eID'] = 'tx_dlf_pageview_proxy';

return $this->httpClient->request($method, '', [
'query' => $query,
]);
}

/**
* @test
*/
public function cannotAccessFileUrl(): void
{
$response = $this->queryProxy([
'url' => 'file:///etc/passwd',
]);

$this->assertEquals(400, $response->getStatusCode());
}

/**
* @test
*/
public function cannotAccessUrlWithoutUrlHash(): void
{
$response = $this->queryProxy([
'url' => 'http://web:8001/Tests/Fixtures/PageViewProxy/test.txt',
]);

$this->assertEquals(401, $response->getStatusCode());
}

/**
* @test
*/
public function cannotAccessUrlWithInvalidUrlHash(): void
{
$response = $this->queryProxy([
'url' => 'http://web:8001/Tests/Fixtures/PageViewProxy/test.txt',
'uHash' => 'nottherealhash',
]);

$this->assertEquals(401, $response->getStatusCode());
}

/**
* @test
*/
public function canAccessPageWithUrlHash(): void
{
$targetUrl = 'http://web:8001/Tests/Fixtures/PageViewProxy/test.txt';
$uHash = GeneralUtility::hmac($targetUrl, 'PageViewProxy');

$response = $this->queryProxy([
'url' => $targetUrl,
'uHash' => $uHash,
]);

$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals('This is some plain text test file.' . "\n", (string) $response->getBody());
}

/**
* @test
*/
public function cannotSendPostRequest(): void
{
$targetUrl = 'http://web:8001/Tests/Fixtures/PageViewProxy/test.txt';
$uHash = GeneralUtility::hmac($targetUrl, 'PageViewProxy');

$response = $this->queryProxy([
'url' => $targetUrl,
'uHash' => $uHash,
], 'POST');

$this->assertEquals(405, $response->getStatusCode());
}

/**
* @test
*/
public function sendsUserAgentToTarget(): void
{
$targetUrl = 'http://web:8001/Tests/Fixtures/PageViewProxy/echo_user_agent.php';
$uHash = GeneralUtility::hmac($targetUrl, 'PageViewProxy');

$response = $this->queryProxy([
'url' => $targetUrl,
'uHash' => $uHash,
]);

$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals('Kitodo.Presentation Proxy', (string) $response->getBody());
}

/**
* @test
*/
public function canQueryOptions(): void
{
$response = $this->queryProxy([], 'OPTIONS');

$this->assertGreaterThanOrEqual(200, $response->getStatusCode());
$this->assertLessThan(300, $response->getStatusCode());

$this->assertNotEmpty($response->getHeader('Access-Control-Allow-Methods'));
}
}
32 changes: 32 additions & 0 deletions Tests/Functional/FunctionalTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Kitodo\Dlf\Tests\Functional;

use GuzzleHttp\Client as HttpClient;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings;
Expand Down Expand Up @@ -31,21 +32,52 @@ class FunctionalTestCase extends \TYPO3\TestingFramework\Core\Functional\Functio
],
];

/**
* By default, the testing framework wraps responses into a JSON object
* that contains status code etc. as fields. Set this field to true to avoid
* this behavior by not loading the json_response extension.
*
* @var bool
*/
protected $disableJsonWrappedResponse = false;

/** @var ObjectManager */
protected $objectManager;

/**
* @var string
*/
protected $baseUrl;

/**
* @var HttpClient
*/
protected $httpClient;

public function __construct()
{
parent::__construct();

$this->configurationToUseInTestInstance['EXTENSIONS']['dlf'] = $this->getDlfConfiguration();

if ($this->disableJsonWrappedResponse) {
$this->frameworkExtensionsToLoad = array_filter($this->frameworkExtensionsToLoad, function ($ext) {
return $ext !== 'Resources/Core/Functional/Extensions/json_response';
});
}
}

public function setUp(): void
{
parent::setUp();

$this->objectManager = GeneralUtility::makeInstance(ObjectManager::class);

$this->baseUrl = 'http://web:8000/public/typo3temp/var/tests/functional-' . $this->identifier . '/';
$this->httpClient = new HttpClient([
'base_uri' => $this->baseUrl,
'http_errors' => false,
]);
}

protected function getDlfConfiguration()
Expand Down
25 changes: 25 additions & 0 deletions Tests/routeFunctionalInstance.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

// This router script dynamically sets TYPO3_PATH_ROOT to a TYPO3 test instance,
// then yields control back to PHP server to let it serve the requested file.
//
// In functional tests, this allows us to access the TYPO3 instance via the web
// server. Manually setting TYPO3_PATH_ROOT is necessary because test instances
// merely symlink into "$DLF_ROOT/public/" source files, so TYPO3 would detect
// that as root and not use the correct typo3conf folder.
//
// The TYPO3_PATH_ROOT apparently needs to be absolute, or TYPO3 may throw an
// error about missing extension configuration.

$matches = [];
preg_match("@.*/(?:acceptance|functional-[a-z0-9]+)@", $_SERVER['REQUEST_URI'], $matches);

if (!empty($matches)) {
$root = realpath($_SERVER['DOCUMENT_ROOT'] . $matches[0]);
if ($root !== false) {
putenv('TYPO3_PATH_ROOT=' . $root);
putenv('TYPO3_PATH_APP=' . $root);
}
}

return false;

0 comments on commit 2f67253

Please sign in to comment.