Skip to content
Merged
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
36 changes: 35 additions & 1 deletion src/main/php/web/Headers.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*
* @see https://en.wikipedia.org/wiki/List_of_HTTP_header_fields
* @see https://en.wikipedia.org/wiki/Content_negotiation
* @test xp://web.unittest.HeadersTest
* @test web.unittest.HeadersTest
*/
abstract class Headers {

Expand Down Expand Up @@ -95,6 +95,40 @@ protected function next($input, &$offset) {
};
}

/**
* Returns a new parser for quality-factor headers, e.g.:
*
* `Accept-Encoding: deflate, gzip;q=1.0, *;q=0.5`
*
* @return self
*/
public static function qfactors() {
return new class() extends Headers {
protected function next($input, &$offset) {
$weighted= [];
$q= 1.0;
do {
$s= strcspn($input, ',;', $offset);
$value= ltrim(substr($input, $offset, $s), ' ');
$offset+= $s + 1;

$c= $input[$offset - 1] ?? null;
if (';' === $c) {
$weighted[$value]= (float)(Headers::pairs()->next($input, $offset)['q'] ?? $q);
$c= $input[$offset - 1] ?? null;
} else {
$weighted[$value]= $q;
}

$q-= 0.0001;
} while ($c);

arsort($weighted, SORT_NUMERIC);
return $weighted;
}
};
}

/**
* Returns a new parser for headers with key/value pairs
*
Expand Down
16 changes: 10 additions & 6 deletions src/test/php/web/unittest/HeadersTest.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,16 @@ public function refresh($header) {
#[Test]
public function accept() {
Assert::equals(
[
new Parameterized('text/html', []),
new Parameterized('application/json', ['q' => '0.9']),
new Parameterized('*/*', ['q' => '0.8']),
],
Headers::values(Headers::parameterized())->parse('text/html, application/json;q=0.9, */*;q=0.8')
['text/html' => 1.0, 'application/json' => 0.9, '*/*' => 0.8],
Headers::qfactors()->parse('text/html, application/json;q=0.9, */*;q=0.8')
);
}

#[Test]
public function accept_encoding() {
Assert::equals(
['deflate' => 1.0, 'gzip' => 1.0, '*' => 0.5],
Headers::qfactors()->parse('deflate, gzip;q=1.0, *;q=0.5')
);
}

Expand Down