Replace IRespondToRequests with PSR-7 ResponseInterface

This commit is contained in:
Philipp Holzer 2021-11-21 23:37:17 +01:00
parent ca5c40c97e
commit 7cd85873ee
Signed by: nupplaPhil
GPG key ID: 24A7501396EB5432
17 changed files with 96 additions and 92 deletions

View file

@ -24,6 +24,7 @@ namespace Friendica;
use Exception;
use Friendica\App\Arguments;
use Friendica\App\BaseURL;
use Friendica\Capabilities\ICanCreateResponses;
use Friendica\Core\Config\Factory\Config;
use Friendica\Module\Maintenance;
use Friendica\Security\Authentication;
@ -42,6 +43,7 @@ use Friendica\Util\DateTimeFormat;
use Friendica\Util\HTTPSignature;
use Friendica\Util\Profiler;
use Friendica\Util\Strings;
use GuzzleHttp\Psr7\Response;
use Psr\Log\LoggerInterface;
/**
@ -702,7 +704,7 @@ class App
// Let the module run it's internal process (init, get, post, ...)
$response = $module->run($_POST, $_REQUEST);
if ($response->getType() === $response::TYPE_HTML) {
if ($response->getHeaderLine('X-RESPONSE-TYPE') === ICanCreateResponses::TYPE_HTML) {
$page->run($this, $this->baseURL, $this->args, $this->mode, $response, $this->l10n, $this->profiler, $this->config, $pconfig);
} else {
$page->exit($response);

View file

@ -25,7 +25,6 @@ use ArrayAccess;
use DOMDocument;
use DOMXPath;
use Friendica\App;
use Friendica\Capabilities\IRespondToRequests;
use Friendica\Content\Nav;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues;
@ -37,6 +36,7 @@ use Friendica\Network\HTTPException;
use Friendica\Util\Network;
use Friendica\Util\Strings;
use Friendica\Util\Profiler;
use Psr\Http\Message\ResponseInterface;
/**
* Contains the page specific environment variables for the current Page
@ -337,19 +337,19 @@ class Page implements ArrayAccess
* - module content
* - hooks for content
*
* @param IRespondToRequests $response The Module response class
* @param ResponseInterface $response The Module response class
* @param Mode $mode The Friendica execution mode
*
* @throws HTTPException\InternalServerErrorException
*/
private function initContent(IRespondToRequests $response, Mode $mode)
private function initContent(ResponseInterface $response, Mode $mode)
{
// initialise content region
if ($mode->isNormal()) {
Hook::callAll('page_content_top', $this->page['content']);
}
$this->page['content'] .= $response->getContent();
$this->page['content'] .= (string)$response->getBody();
}
/**
@ -374,19 +374,22 @@ class Page implements ArrayAccess
/**
* Directly exit with the current response (include setting all headers)
*
* @param IRespondToRequests $response
* @param ResponseInterface $response
*/
public function exit(IRespondToRequests $response)
public function exit(ResponseInterface $response)
{
foreach ($response->getHeaders() as $key => $header) {
if (is_array($header)) {
$header_str = implode(',', $header);
}
if (empty($key)) {
header($header);
header($header_str);
} else {
header("$key: $header");
header("$key: $header_str");
}
}
echo $response->getContent();
echo $response->getBody();
}
/**
@ -396,14 +399,14 @@ class Page implements ArrayAccess
* @param BaseURL $baseURL The Friendica Base URL
* @param Arguments $args The Friendica App arguments
* @param Mode $mode The current node mode
* @param IRespondToRequests $response The Response of the module class, including type, content & headers
* @param ResponseInterface $response The Response of the module class, including type, content & headers
* @param L10n $l10n The l10n language class
* @param IManageConfigValues $config The Configuration of this node
* @param IManagePersonalConfigValues $pconfig The personal/user configuration
*
* @throws HTTPException\InternalServerErrorException|HTTPException\ServiceUnavailableException
*/
public function run(App $app, BaseURL $baseURL, Arguments $args, Mode $mode, IRespondToRequests $response, L10n $l10n, Profiler $profiler, IManageConfigValues $config, IManagePersonalConfigValues $pconfig)
public function run(App $app, BaseURL $baseURL, Arguments $args, Mode $mode, ResponseInterface $response, L10n $l10n, Profiler $profiler, IManageConfigValues $config, IManagePersonalConfigValues $pconfig)
{
$moduleName = $args->getModuleName();

View file

@ -24,7 +24,6 @@ namespace Friendica;
use Friendica\App\Router;
use Friendica\Capabilities\ICanHandleRequests;
use Friendica\Capabilities\ICanCreateResponses;
use Friendica\Capabilities\IRespondToRequests;
use Friendica\Core\Hook;
use Friendica\Core\L10n;
use Friendica\Core\Logger;
@ -33,6 +32,7 @@ use Friendica\Module\Response;
use Friendica\Module\Special\HTTPException as ModuleHTTPException;
use Friendica\Network\HTTPException;
use Friendica\Util\Profiler;
use Psr\Http\Message\ResponseInterface;
use Psr\Log\LoggerInterface;
/**
@ -171,7 +171,7 @@ abstract class BaseModule implements ICanHandleRequests
/**
* {@inheritDoc}
*/
public function run(array $post = [], array $request = []): IRespondToRequests
public function run(array $post = [], array $request = []): ResponseInterface
{
// @see https://github.com/tootsuite/mastodon/blob/c3aef491d66aec743a3a53e934a494f653745b61/config/initializers/cors.rb
if (substr($request['pagename'] ?? '', 0, 12) == '.well-known/') {
@ -239,7 +239,7 @@ abstract class BaseModule implements ICanHandleRequests
break;
}
return $this->response;
return $this->response->generate();
}
/*

View file

@ -3,9 +3,24 @@
namespace Friendica\Capabilities;
use Friendica\Network\HTTPException\InternalServerErrorException;
use Psr\Http\Message\ResponseInterface;
interface ICanCreateResponses extends IRespondToRequests
interface ICanCreateResponses
{
const TYPE_HTML = 'html';
const TYPE_XML = 'xml';
const TYPE_JSON = 'json';
const TYPE_ATOM = 'atom';
const TYPE_RSS = 'rss';
const ALLOWED_TYPES = [
self::TYPE_HTML,
self::TYPE_XML,
self::TYPE_JSON,
self::TYPE_ATOM,
self::TYPE_RSS
];
/**
* Adds a header entry to the module response
*
@ -30,4 +45,12 @@ interface ICanCreateResponses extends IRespondToRequests
* @throws InternalServerErrorException
*/
public function setType(string $type, ?string $content_type = null): void;
/**
* Creates a PSR-7 compliant interface
* @see https://www.php-fig.org/psr/psr-7/
*
* @return ResponseInterface
*/
public function generate(): ResponseInterface;
}

View file

@ -3,6 +3,7 @@
namespace Friendica\Capabilities;
use Friendica\Network\HTTPException;
use Psr\Http\Message\ResponseInterface;
/**
* This interface provides the capability to handle requests from clients and returns the desired outcome
@ -13,9 +14,9 @@ interface ICanHandleRequests
* @param array $post The $_POST content (in case of POST)
* @param array $request The $_REQUEST content (in case of GET, POST)
*
* @return IRespondToRequests responding to the request handling
* @return ResponseInterface responding to the request handling
*
* @throws HTTPException\InternalServerErrorException
*/
public function run(array $post = [], array $request = []): IRespondToRequests;
public function run(array $post = [], array $request = []): ResponseInterface;
}

View file

@ -1,41 +0,0 @@
<?php
namespace Friendica\Capabilities;
interface IRespondToRequests
{
const TYPE_HTML = 'html';
const TYPE_XML = 'xml';
const TYPE_JSON = 'json';
const TYPE_ATOM = 'atom';
const TYPE_RSS = 'rss';
const ALLOWED_TYPES = [
self::TYPE_HTML,
self::TYPE_XML,
self::TYPE_JSON,
self::TYPE_ATOM,
self::TYPE_RSS
];
/**
* Returns all set headers during the module execution
*
* @return string[]
*/
public function getHeaders(): array;
/**
* Returns the output of the module (mixed content possible)
*
* @return mixed
*/
public function getContent();
/**
* Returns the response type
*
* @return string
*/
public function getType(): string;
}

View file

@ -22,9 +22,9 @@
namespace Friendica\Module\HTTPException;
use Friendica\BaseModule;
use Friendica\Capabilities\IRespondToRequests;
use Friendica\DI;
use Friendica\Network\HTTPException;
use Psr\Http\Message\ResponseInterface;
class PageNotFound extends BaseModule
{
@ -33,7 +33,7 @@ class PageNotFound extends BaseModule
throw new HTTPException\NotFoundException(DI::l10n()->t('Page not found.'));
}
public function run(array $post = [], array $request = []): IRespondToRequests
public function run(array $post = [], array $request = []): ResponseInterface
{
/* The URL provided does not resolve to a valid module.
*

View file

@ -23,7 +23,7 @@ namespace Friendica\Module;
use Friendica\App;
use Friendica\BaseModule;
use Friendica\Capabilities\IRespondToRequests;
use Friendica\Capabilities\ICanCreateResponses;
use Friendica\Core\Addon;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\L10n;
@ -98,7 +98,7 @@ class NodeInfo110 extends BaseModule
$nodeinfo['metadata']['explicitContent'] = $this->config->get('system', 'explicit_content', false) == true;
$this->response->setType(IRespondToRequests::TYPE_JSON);
$this->response->setType(ICanCreateResponses::TYPE_JSON);
$this->response->addContent(json_encode($nodeinfo, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
}
}

View file

@ -23,7 +23,7 @@ namespace Friendica\Module;
use Friendica\App;
use Friendica\BaseModule;
use Friendica\Capabilities\IRespondToRequests;
use Friendica\Capabilities\ICanCreateResponses;
use Friendica\Core\Addon;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\L10n;
@ -90,7 +90,7 @@ class NodeInfo120 extends BaseModule
$nodeinfo['metadata']['explicitContent'] = $this->config->get('system', 'explicit_content', false) == true;
$this->response->setType(IRespondToRequests::TYPE_JSON, 'application/json; charset=utf-8');
$this->response->setType(ICanCreateResponses::TYPE_JSON, 'application/json; charset=utf-8');
$this->response->addContent(json_encode($nodeinfo, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
}
}

View file

@ -23,11 +23,10 @@ namespace Friendica\Module;
use Friendica\App;
use Friendica\BaseModule;
use Friendica\Capabilities\IRespondToRequests;
use Friendica\Capabilities\ICanCreateResponses;
use Friendica\Core\Addon;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\L10n;
use Friendica\Core\System;
use Friendica\Model\Nodeinfo;
use Friendica\Util\Profiler;
use Psr\Log\LoggerInterface;
@ -89,7 +88,7 @@ class NodeInfo210 extends BaseModule
$nodeinfo['services']['inbound'][] = 'imap';
}
$this->response->setType(IRespondToRequests::TYPE_JSON, 'application/json; charset=utf-8');
$this->response->setType(ICanCreateResponses::TYPE_JSON, 'application/json; charset=utf-8');
$this->response->addContent(json_encode($nodeinfo, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
}
}

View file

@ -3,8 +3,8 @@
namespace Friendica\Module;
use Friendica\Capabilities\ICanCreateResponses;
use Friendica\Capabilities\IRespondToRequests;
use Friendica\Network\HTTPException\InternalServerErrorException;
use Psr\Http\Message\ResponseInterface;
class Response implements ICanCreateResponses
{
@ -19,7 +19,7 @@ class Response implements ICanCreateResponses
/**
* @var string
*/
protected $type = IRespondToRequests::TYPE_HTML;
protected $type = ICanCreateResponses::TYPE_HTML;
/**
* {@inheritDoc}
@ -68,7 +68,7 @@ class Response implements ICanCreateResponses
*/
public function setType(string $type, ?string $content_type = null): void
{
if (!in_array($type, IRespondToRequests::ALLOWED_TYPES)) {
if (!in_array($type, ICanCreateResponses::ALLOWED_TYPES)) {
throw new InternalServerErrorException('wrong type');
}
@ -94,4 +94,25 @@ class Response implements ICanCreateResponses
{
return $this->type;
}
/**
* {@inheritDoc}
*/
public function generate(): ResponseInterface
{
$headers = [];
foreach ($this->headers as $key => $header) {
if (empty($key)) {
$headers[] = $header;
} else {
$headers[] = "$key: $header";
}
}
// Setting the response type as an X-header for direct usage
$headers['X-RESPONSE-TYPE'] = $this->type;
return new \GuzzleHttp\Psr7\Response(200, $this->headers, $this->content);
}
}

View file

@ -68,7 +68,7 @@ XML;
$notification = new Notification(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'xml']);
$response = $notification->run();
self::assertXmlStringEqualsXmlString($assertXml, $response->getContent());
self::assertXmlStringEqualsXmlString($assertXml, (string)$response->getBody());
}
public function testWithJsonResult()
@ -76,6 +76,6 @@ XML;
$notification = new Notification(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'json']);
$response = $notification->run();
self::assertJson($response->getContent());
self::assertJson($response->getBody());
}
}

View file

@ -13,6 +13,6 @@ class VersionTest extends ApiTest
$version = new Version(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'json']);
$response = $version->run();
self::assertEquals('"0.9.7"', $response->getContent());
self::assertEquals('"0.9.7"', $response->getBody());
}
}

View file

@ -13,7 +13,7 @@ class TestTest extends ApiTest
$test = new Test(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'json']);
$response = $test->run();
self::assertEquals('"ok"', $response->getContent());
self::assertEquals('"ok"', $response->getBody());
}
public function testXml()
@ -21,6 +21,6 @@ class TestTest extends ApiTest
$test = new Test(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'xml']);
$response = $test->run();
self::assertxml($response->getContent(), 'ok');
self::assertxml($response->getBody(), 'ok');
}
}

View file

@ -13,7 +13,7 @@ class RateLimitStatusTest extends ApiTest
$rateLimitStatus = new RateLimitStatus(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'json']);
$response = $rateLimitStatus->run();
$result = json_decode($response->getContent());
$result = json_decode($response->getBody());
self::assertEquals(150, $result->remaining_hits);
self::assertEquals(150, $result->hourly_limit);
@ -25,6 +25,6 @@ class RateLimitStatusTest extends ApiTest
$rateLimitStatus = new RateLimitStatus(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'xml']);
$response = $rateLimitStatus->run();
self::assertXml($response->getContent(), 'hash');
self::assertXml($response->getBody(), 'hash');
}
}

View file

@ -13,7 +13,7 @@ class SavedSearchesTest extends ApiTest
$savedSearch = new SavedSearches(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'json']);
$response = $savedSearch->run();
$result = json_decode($response->getContent());
$result = json_decode($response->getBody());
self::assertEquals(1, $result[0]->id);
self::assertEquals(1, $result[0]->id_str);

View file

@ -2,7 +2,6 @@
namespace Friendica\Test\src\Module;
use Friendica\Capabilities\IRespondToRequests;
use Friendica\DI;
use Friendica\Module\NodeInfo110;
use Friendica\Module\NodeInfo120;
@ -19,11 +18,10 @@ class NodeInfoTest extends FixtureTest
$nodeinfo = new NodeInfo110(DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), $response, DI::config(), []);
$response = $nodeinfo->run();
self::assertEquals(IRespondToRequests::TYPE_JSON, $response->getType());
self::assertJson($response->getContent());
self::assertEquals(['Content-type' => 'application/json'], $response->getHeaders());
self::assertJson($response->getBody());
self::assertEquals(['Content-type' => ['application/json']], $response->getHeaders());
$json = json_decode($response->getContent());
$json = json_decode($response->getBody());
self::assertEquals('1.0', $json->version);
@ -43,11 +41,10 @@ class NodeInfoTest extends FixtureTest
$nodeinfo = new NodeInfo120(DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), $response, DI::config(), []);
$response = $nodeinfo->run();
self::assertEquals(IRespondToRequests::TYPE_JSON, $response->getType());
self::assertJson($response->getContent());
self::assertEquals(['Content-type' => 'application/json; charset=utf-8'], $response->getHeaders());
self::assertJson($response->getBody());
self::assertEquals(['Content-type' => ['application/json; charset=utf-8']], $response->getHeaders());
$json = json_decode($response->getContent());
$json = json_decode($response->getBody());
self::assertEquals('2.0', $json->version);
@ -66,11 +63,10 @@ class NodeInfoTest extends FixtureTest
$nodeinfo = new NodeInfo210(DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), $response, DI::config(), []);
$response = $nodeinfo->run();
self::assertEquals(IRespondToRequests::TYPE_JSON, $response->getType());
self::assertJson($response->getContent());
self::assertEquals(['Content-type' => 'application/json; charset=utf-8'], $response->getHeaders());
self::assertJson($response->getBody());
self::assertEquals(['Content-type' => ['application/json; charset=utf-8']], $response->getHeaders());
$json = json_decode($response->getContent());
$json = json_decode($response->getBody());
self::assertEquals('1.0', $json->version);