From 0116864b26eddaf49bebc86f43bf6b1f88f55560 Mon Sep 17 00:00:00 2001 From: datorik Date: Tue, 14 Jul 2026 18:53:19 +0300 Subject: [PATCH 1/7] Code.Content-Type header --- lib/CleantalkSP/SpbctWP/RemoteCalls.php | 52 +++++++++++++++ .../RemoteCallsContentTypeTest.php | 64 +++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 tests/lib/CleantalkSP/SpbctWP/RemoteCalls/RemoteCallsContentTypeTest.php diff --git a/lib/CleantalkSP/SpbctWP/RemoteCalls.php b/lib/CleantalkSP/SpbctWP/RemoteCalls.php index 674ad7990..735f0d8f7 100644 --- a/lib/CleantalkSP/SpbctWP/RemoteCalls.php +++ b/lib/CleantalkSP/SpbctWP/RemoteCalls.php @@ -33,11 +33,63 @@ class RemoteCalls extends \CleantalkSP\Common\RemoteCalls 'spbc_key', ]; + /** Default Content-Type for responses */ + const DEFAULT_CONTENT_TYPE = 'text/plain; charset=UTF-8'; + + /** + * Action Content-Type list + * + * @var array + */ + private static $actionContentTypes = [ + // HTML page + 'debug' => 'text/html; charset=UTF-8', + // JSON payloads + 'update_settings' => 'application/json; charset=UTF-8', + 'post_api_key' => 'application/json; charset=UTF-8', + 'license_update' => 'application/json; charset=UTF-8', + 'scanner__check_dir' => 'application/json; charset=UTF-8', + 'update_pscan_statuses' => 'application/json; charset=UTF-8', + // Binary file download + 'download__quarantine_file' => 'application/octet-stream', + ]; + public function __construct(&$state) { $this->without_token = self::checkWithoutToken(); $this->state = $state; $this->class_name = __CLASS__; + + // Declare the response type before any handler outputs (runs only for RC). + self::sendContentTypeHeader(Request::getString('spbc_remote_call_action')); + } + + /** + * Resolve the full Content-Type header value for action. + * + * @param string $action + * @return string + */ + public static function resolveContentType($action) + { + $action = strtolower((string)$action); + + return isset(self::$actionContentTypes[$action]) + ? self::$actionContentTypes[$action] + : self::DEFAULT_CONTENT_TYPE; + } + + /** + * Send response Content-Type header unless headers. + * + * @param string $action + * @return void + */ + private static function sendContentTypeHeader($action) + { + if (! headers_sent()) { + header('Content-Type: ' . self::resolveContentType($action)); + } } /** diff --git a/tests/lib/CleantalkSP/SpbctWP/RemoteCalls/RemoteCallsContentTypeTest.php b/tests/lib/CleantalkSP/SpbctWP/RemoteCalls/RemoteCallsContentTypeTest.php new file mode 100644 index 000000000..ce6251e65 --- /dev/null +++ b/tests/lib/CleantalkSP/SpbctWP/RemoteCalls/RemoteCallsContentTypeTest.php @@ -0,0 +1,64 @@ +assertSame('text/plain; charset=UTF-8', RemoteCalls::DEFAULT_CONTENT_TYPE); + } + + public function testPlainTextActionsFallBackToDefault() + { + $this->assertSame('text/plain; charset=UTF-8', RemoteCalls::resolveContentType('scanner__controller')); + $this->assertSame('text/plain; charset=UTF-8', RemoteCalls::resolveContentType('launch_background_scan')); + $this->assertSame('text/plain; charset=UTF-8', RemoteCalls::resolveContentType('check_website')); + $this->assertSame('text/plain; charset=UTF-8', RemoteCalls::resolveContentType('update_security_firewall__worker')); + } + + public function testUnknownActionFallsBackToDefault() + { + $this->assertSame('text/plain; charset=UTF-8', RemoteCalls::resolveContentType('no_such_action_at_all')); + $this->assertSame('text/plain; charset=UTF-8', RemoteCalls::resolveContentType('')); + } + + public function testDebugActionRendersHtml() + { + $this->assertSame('text/html; charset=UTF-8', RemoteCalls::resolveContentType('debug')); + } + + public function testJsonActionsUseApplicationJson() + { + foreach (['update_settings', 'post_api_key', 'license_update', 'scanner__check_dir', 'update_pscan_statuses'] as $action) { + $this->assertSame( + 'application/json; charset=UTF-8', + RemoteCalls::resolveContentType($action), + $action . ' must respond as JSON' + ); + } + } + + public function testFileDownloadUsesOctetStreamWithoutCharset() + { + $this->assertSame('application/octet-stream', RemoteCalls::resolveContentType('download__quarantine_file')); + } + + public function testActionNameIsCaseInsensitive() + { + $this->assertSame('text/html; charset=UTF-8', RemoteCalls::resolveContentType('DEBUG')); + $this->assertSame('application/json; charset=UTF-8', RemoteCalls::resolveContentType('Update_Settings')); + } + + public function testNonScalarSafeResolution() + { + $this->assertSame('text/plain; charset=UTF-8', RemoteCalls::resolveContentType(null)); + } +} \ No newline at end of file From c71a6128a661efee7d5ea1e4e6f17ce565597db5 Mon Sep 17 00:00:00 2001 From: Aleksandr Banins Date: Fri, 17 Jul 2026 17:39:53 +0300 Subject: [PATCH 2/7] Action Types Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- lib/CleantalkSP/SpbctWP/RemoteCalls.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/CleantalkSP/SpbctWP/RemoteCalls.php b/lib/CleantalkSP/SpbctWP/RemoteCalls.php index 735f0d8f7..5bcccc4f4 100644 --- a/lib/CleantalkSP/SpbctWP/RemoteCalls.php +++ b/lib/CleantalkSP/SpbctWP/RemoteCalls.php @@ -48,10 +48,9 @@ class RemoteCalls extends \CleantalkSP\Common\RemoteCalls 'update_settings' => 'application/json; charset=UTF-8', 'post_api_key' => 'application/json; charset=UTF-8', 'license_update' => 'application/json; charset=UTF-8', + 'run_service_template_get' => 'application/json; charset=UTF-8', 'scanner__check_dir' => 'application/json; charset=UTF-8', 'update_pscan_statuses' => 'application/json; charset=UTF-8', - // Binary file download - 'download__quarantine_file' => 'application/octet-stream', ]; public function __construct(&$state) From df776aee2dd1417248f4ff463ec91f796cabe54d Mon Sep 17 00:00:00 2001 From: Aleksandr Banins Date: Fri, 17 Jul 2026 17:40:30 +0300 Subject: [PATCH 3/7] Code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- lib/CleantalkSP/SpbctWP/RemoteCalls.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/CleantalkSP/SpbctWP/RemoteCalls.php b/lib/CleantalkSP/SpbctWP/RemoteCalls.php index 5bcccc4f4..eaf44c042 100644 --- a/lib/CleantalkSP/SpbctWP/RemoteCalls.php +++ b/lib/CleantalkSP/SpbctWP/RemoteCalls.php @@ -79,9 +79,9 @@ public static function resolveContentType($action) } /** - * Send response Content-Type header unless headers. + * Send response Content-Type header unless headers have already been sent. * - * @param string $action + * @param mixed $action * @return void */ private static function sendContentTypeHeader($action) From 5bfa45de115683d756a36bdda752e9f0e2109c62 Mon Sep 17 00:00:00 2001 From: Aleksandr Banins Date: Fri, 17 Jul 2026 18:17:18 +0300 Subject: [PATCH 4/7] Code fix Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../SpbctWP/RemoteCalls/RemoteCallsContentTypeTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/lib/CleantalkSP/SpbctWP/RemoteCalls/RemoteCallsContentTypeTest.php b/tests/lib/CleantalkSP/SpbctWP/RemoteCalls/RemoteCallsContentTypeTest.php index ce6251e65..8ee964e8f 100644 --- a/tests/lib/CleantalkSP/SpbctWP/RemoteCalls/RemoteCallsContentTypeTest.php +++ b/tests/lib/CleantalkSP/SpbctWP/RemoteCalls/RemoteCallsContentTypeTest.php @@ -37,7 +37,7 @@ public function testDebugActionRendersHtml() public function testJsonActionsUseApplicationJson() { - foreach (['update_settings', 'post_api_key', 'license_update', 'scanner__check_dir', 'update_pscan_statuses'] as $action) { + foreach (['update_settings', 'post_api_key', 'license_update', 'run_service_template_get', 'scanner__check_dir', 'update_pscan_statuses'] as $action) { $this->assertSame( 'application/json; charset=UTF-8', RemoteCalls::resolveContentType($action), @@ -46,9 +46,9 @@ public function testJsonActionsUseApplicationJson() } } - public function testFileDownloadUsesOctetStreamWithoutCharset() + public function testFileDownloadFallsBackToDefaultBeforeHandlerOverrides() { - $this->assertSame('application/octet-stream', RemoteCalls::resolveContentType('download__quarantine_file')); + $this->assertSame('text/plain; charset=UTF-8', RemoteCalls::resolveContentType('download__quarantine_file')); } public function testActionNameIsCaseInsensitive() From 33727fd475afb76f64f771463231b8d95a1fa1fa Mon Sep 17 00:00:00 2001 From: datorik Date: Fri, 17 Jul 2026 18:17:52 +0300 Subject: [PATCH 5/7] Code. Code review --- lib/CleantalkSP/SpbctWP/RemoteCalls.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/CleantalkSP/SpbctWP/RemoteCalls.php b/lib/CleantalkSP/SpbctWP/RemoteCalls.php index eaf44c042..6fda7e90a 100644 --- a/lib/CleantalkSP/SpbctWP/RemoteCalls.php +++ b/lib/CleantalkSP/SpbctWP/RemoteCalls.php @@ -81,7 +81,7 @@ public static function resolveContentType($action) /** * Send response Content-Type header unless headers have already been sent. * - * @param mixed $action + * @param string $action Remote call action name ('' when absent). * @return void */ private static function sendContentTypeHeader($action) From 207008eb74afa31808d1db71186214ebd8c0840c Mon Sep 17 00:00:00 2001 From: Aleksandr Banins Date: Wed, 22 Jul 2026 16:20:29 +0300 Subject: [PATCH 6/7] Code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- lib/CleantalkSP/SpbctWP/RemoteCalls.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/CleantalkSP/SpbctWP/RemoteCalls.php b/lib/CleantalkSP/SpbctWP/RemoteCalls.php index 6fda7e90a..a882d849f 100644 --- a/lib/CleantalkSP/SpbctWP/RemoteCalls.php +++ b/lib/CleantalkSP/SpbctWP/RemoteCalls.php @@ -66,13 +66,12 @@ public function __construct(&$state) /** * Resolve the full Content-Type header value for action. * - * @param string $action + * @param mixed $action * @return string */ public static function resolveContentType($action) { $action = strtolower((string)$action); - return isset(self::$actionContentTypes[$action]) ? self::$actionContentTypes[$action] : self::DEFAULT_CONTENT_TYPE; From a70d09efdfb53cb4b0f4b5d0f7a2843fa8fe0729 Mon Sep 17 00:00:00 2001 From: datorik Date: Wed, 22 Jul 2026 20:39:01 +0300 Subject: [PATCH 7/7] Code. Code review --- lib/CleantalkSP/SpbctWP/RemoteCalls.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/CleantalkSP/SpbctWP/RemoteCalls.php b/lib/CleantalkSP/SpbctWP/RemoteCalls.php index a882d849f..409dac1e5 100644 --- a/lib/CleantalkSP/SpbctWP/RemoteCalls.php +++ b/lib/CleantalkSP/SpbctWP/RemoteCalls.php @@ -80,7 +80,7 @@ public static function resolveContentType($action) /** * Send response Content-Type header unless headers have already been sent. * - * @param string $action Remote call action name ('' when absent). + * @param mixed $action Remote call action name ('' when absent). * @return void */ private static function sendContentTypeHeader($action)