From 7cd85873ee321263ff9b4e77fc121dca1c9dae6f Mon Sep 17 00:00:00 2001 From: Philipp Date: Sun, 21 Nov 2021 23:37:17 +0100 Subject: [PATCH] Replace IRespondToRequests with PSR-7 ResponseInterface --- src/App.php | 4 +- src/App/Page.php | 25 ++++++----- src/BaseModule.php | 6 +-- src/Capabilities/ICanCreateResponses.php | 25 ++++++++++- src/Capabilities/ICanHandleRequests.php | 5 ++- src/Capabilities/IRespondToRequests.php | 41 ------------------- src/Module/HTTPException/PageNotFound.php | 4 +- src/Module/NodeInfo110.php | 4 +- src/Module/NodeInfo120.php | 4 +- src/Module/NodeInfo210.php | 5 +-- src/Module/Response.php | 27 ++++++++++-- .../Module/Api/Friendica/NotificationTest.php | 4 +- .../Api/GnuSocial/GnuSocial/VersionTest.php | 2 +- .../Module/Api/GnuSocial/Help/TestTest.php | 4 +- .../Twitter/Account/RateLimitStatusTest.php | 4 +- .../Module/Api/Twitter/SavedSearchesTest.php | 2 +- tests/src/Module/NodeInfoTest.php | 22 ++++------ 17 files changed, 96 insertions(+), 92 deletions(-) delete mode 100644 src/Capabilities/IRespondToRequests.php diff --git a/src/App.php b/src/App.php index d4e3021f82..30194af8e2 100644 --- a/src/App.php +++ b/src/App.php @@ -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); diff --git a/src/App/Page.php b/src/App/Page.php index 7019d45985..1b499f614c 100644 --- a/src/App/Page.php +++ b/src/App/Page.php @@ -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(); diff --git a/src/BaseModule.php b/src/BaseModule.php index 1bf100df69..46f21ed11d 100644 --- a/src/BaseModule.php +++ b/src/BaseModule.php @@ -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(); } /* diff --git a/src/Capabilities/ICanCreateResponses.php b/src/Capabilities/ICanCreateResponses.php index 282458136b..21a7b1bde9 100644 --- a/src/Capabilities/ICanCreateResponses.php +++ b/src/Capabilities/ICanCreateResponses.php @@ -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; } diff --git a/src/Capabilities/ICanHandleRequests.php b/src/Capabilities/ICanHandleRequests.php index ceb580875a..dc608ebbb7 100644 --- a/src/Capabilities/ICanHandleRequests.php +++ b/src/Capabilities/ICanHandleRequests.php @@ -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; } diff --git a/src/Capabilities/IRespondToRequests.php b/src/Capabilities/IRespondToRequests.php deleted file mode 100644 index e023a9e4a1..0000000000 --- a/src/Capabilities/IRespondToRequests.php +++ /dev/null @@ -1,41 +0,0 @@ -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. * diff --git a/src/Module/NodeInfo110.php b/src/Module/NodeInfo110.php index 6681dcc020..4e740ab3fa 100644 --- a/src/Module/NodeInfo110.php +++ b/src/Module/NodeInfo110.php @@ -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)); } } diff --git a/src/Module/NodeInfo120.php b/src/Module/NodeInfo120.php index ea25653779..c8dcbd280d 100644 --- a/src/Module/NodeInfo120.php +++ b/src/Module/NodeInfo120.php @@ -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)); } } diff --git a/src/Module/NodeInfo210.php b/src/Module/NodeInfo210.php index 7501f26c08..43857c87aa 100644 --- a/src/Module/NodeInfo210.php +++ b/src/Module/NodeInfo210.php @@ -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)); } } diff --git a/src/Module/Response.php b/src/Module/Response.php index 4cf9f9667e..9bf9912360 100644 --- a/src/Module/Response.php +++ b/src/Module/Response.php @@ -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); + } } diff --git a/tests/src/Module/Api/Friendica/NotificationTest.php b/tests/src/Module/Api/Friendica/NotificationTest.php index b78715864e..22c498c44b 100644 --- a/tests/src/Module/Api/Friendica/NotificationTest.php +++ b/tests/src/Module/Api/Friendica/NotificationTest.php @@ -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()); } } diff --git a/tests/src/Module/Api/GnuSocial/GnuSocial/VersionTest.php b/tests/src/Module/Api/GnuSocial/GnuSocial/VersionTest.php index 88bce964ca..e5057f09be 100644 --- a/tests/src/Module/Api/GnuSocial/GnuSocial/VersionTest.php +++ b/tests/src/Module/Api/GnuSocial/GnuSocial/VersionTest.php @@ -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()); } } diff --git a/tests/src/Module/Api/GnuSocial/Help/TestTest.php b/tests/src/Module/Api/GnuSocial/Help/TestTest.php index 82ceefec9b..85bc89e003 100644 --- a/tests/src/Module/Api/GnuSocial/Help/TestTest.php +++ b/tests/src/Module/Api/GnuSocial/Help/TestTest.php @@ -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'); } } diff --git a/tests/src/Module/Api/Twitter/Account/RateLimitStatusTest.php b/tests/src/Module/Api/Twitter/Account/RateLimitStatusTest.php index 66821cea16..aa76c1bf53 100644 --- a/tests/src/Module/Api/Twitter/Account/RateLimitStatusTest.php +++ b/tests/src/Module/Api/Twitter/Account/RateLimitStatusTest.php @@ -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'); } } diff --git a/tests/src/Module/Api/Twitter/SavedSearchesTest.php b/tests/src/Module/Api/Twitter/SavedSearchesTest.php index 497a063106..0b20335c48 100644 --- a/tests/src/Module/Api/Twitter/SavedSearchesTest.php +++ b/tests/src/Module/Api/Twitter/SavedSearchesTest.php @@ -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); diff --git a/tests/src/Module/NodeInfoTest.php b/tests/src/Module/NodeInfoTest.php index 3464d7729f..cb16705330 100644 --- a/tests/src/Module/NodeInfoTest.php +++ b/tests/src/Module/NodeInfoTest.php @@ -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);