Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion src/Http/Adapter/Swoole/Request.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Utopia\Http\Adapter\Swoole;

use Swoole\Http\Request as SwooleRequest;
use Stringable;
use Utopia\Http\Request as UtopiaRequest;

class Request extends UtopiaRequest
Expand Down Expand Up @@ -287,7 +288,9 @@ public function getCookie(string $key, string $default = ''): string
*/
public function getHeader(string $key, string $default = ''): string
{
return $this->swoole->header[$key] ?? $default;
$key = strtolower($key);

return $this->normalizeHeaderValue($this->swoole->header[$key] ?? $default, $default);
}

/**
Expand Down Expand Up @@ -324,6 +327,27 @@ public function getSwooleRequest(): SwooleRequest
return $this->swoole;
}

private function normalizeHeaderValue(mixed $value, string $default): string
{
if (is_array($value)) {
for ($i = count($value) - 1; $i >= 0; $i--) {
$candidate = $value[$i];

if (is_scalar($candidate) || $candidate instanceof Stringable) {
return (string) $candidate;
}
Comment on lines +333 to +338
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Numeric-index traversal assumes sequential array

The loop accesses $value[$i] where $i counts down from count($value)-1. If Swoole ever returns an associative (non-sequential) array for a multi-valued header, these accesses will produce Undefined array key warnings in PHP 8 and return null, causing the loop to silently fall through to $default. Using array_values() to re-index first makes this robust:

Suggested change
for ($i = count($value) - 1; $i >= 0; $i--) {
$candidate = $value[$i];
if (is_scalar($candidate) || $candidate instanceof Stringable) {
return (string) $candidate;
}
foreach (array_reverse(array_values($value)) as $candidate) {
if (is_scalar($candidate) || $candidate instanceof Stringable) {
return (string) $candidate;
}
}

}

return $default;
}

if (is_scalar($value) || $value instanceof Stringable) {
return (string) $value;
}

return $default;
}

/**
* Generate input
*
Expand Down
47 changes: 47 additions & 0 deletions tests/SwooleRequestTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace Utopia\Http\Tests;

use PHPUnit\Framework\TestCase;
use Utopia\Http\Adapter\Swoole\Request;

class SwooleRequestTest extends TestCase
{
private ?Request $request = null;

public function setUp(): void
{
if (!class_exists(\Swoole\Http\Request::class)) {
$this->markTestSkipped('The Swoole extension is required for this test.');
}

/** @var \Swoole\Http\Request $swooleRequest */
$swooleRequest = new \Swoole\Http\Request();
$swooleRequest->header = [];

$this->request = new Request($swooleRequest);
}

public function tearDown(): void
{
$this->request = null;
}

public function testCanGetScalarHeaders(): void
{
$this->request?->getSwooleRequest()->header = [
'x-replaced-path' => '/gateway',
];

$this->assertEquals('/gateway', $this->request?->getHeader('x-replaced-path'));
}

public function testCanNormalizeArrayHeaders(): void
{
$this->request?->getSwooleRequest()->header = [
'x-replaced-path' => ['/client', '/gateway'],
];

$this->assertEquals('/gateway', $this->request?->getHeader('x-replaced-path'));
}
Comment on lines +30 to +46
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Missing test cases for default value and case-insensitive lookup

The new tests cover scalar and array values, but two additional cases are worth adding:

  • A missing header should return the provided $default (not '').
  • getHeader should be case-insensitive on the key (getHeader('X-Replaced-Path') vs getHeader('x-replaced-path')).

Without the case-insensitive test, the new strtolower call in getHeader has no coverage.

}
Loading