minor #33725 [HttpFoundation] optimize normalization of headers (nicolas-grekas)

This PR was merged into the 4.4 branch.

Discussion
----------

[HttpFoundation] optimize normalization of headers

| Q             | A
| ------------- | ---
| Branch?       | 4.4
| Bug fix?      | no
| New feature?  | no
| Deprecations? | no
| Tickets       | -
| License       | MIT
| Doc PR        | -

I was experimenting with using maps to bypass calls to normalization functions, but that didn't lead to any significant perf improvement.

I still found this, the new call is twice as fast :)

Commits
-------

9c676d37a0 [HttpFoundation] optimize normalization of headers
This commit is contained in:
Fabien Potencier 2019-09-27 07:33:30 +02:00
commit 7a3bfac209
4 changed files with 13 additions and 15 deletions

View File

@ -18,6 +18,9 @@ namespace Symfony\Component\HttpFoundation;
*/ */
class HeaderBag implements \IteratorAggregate, \Countable class HeaderBag implements \IteratorAggregate, \Countable
{ {
protected const UPPER = '_ABCDEFGHIJKLMNOPQRSTUVWXYZ';
protected const LOWER = '-abcdefghijklmnopqrstuvwxyz';
protected $headers = []; protected $headers = [];
protected $cacheControl = []; protected $cacheControl = [];
@ -62,9 +65,7 @@ class HeaderBag implements \IteratorAggregate, \Countable
public function all(/*string $key = null*/) public function all(/*string $key = null*/)
{ {
if (1 <= \func_num_args() && null !== $key = func_get_arg(0)) { if (1 <= \func_num_args() && null !== $key = func_get_arg(0)) {
$key = str_replace('_', '-', strtolower($key)); return $this->headers[strtr($key, self::UPPER, self::LOWER)] ?? [];
return $this->headers[$key] ?? [];
} }
return $this->headers; return $this->headers;
@ -138,7 +139,7 @@ class HeaderBag implements \IteratorAggregate, \Countable
*/ */
public function set($key, $values, $replace = true) public function set($key, $values, $replace = true)
{ {
$key = str_replace('_', '-', strtolower($key)); $key = strtr($key, self::UPPER, self::LOWER);
if (\is_array($values)) { if (\is_array($values)) {
$values = array_values($values); $values = array_values($values);
@ -170,7 +171,7 @@ class HeaderBag implements \IteratorAggregate, \Countable
*/ */
public function has($key) public function has($key)
{ {
return \array_key_exists(str_replace('_', '-', strtolower($key)), $this->all()); return \array_key_exists(strtr($key, self::UPPER, self::LOWER), $this->all());
} }
/** /**
@ -193,7 +194,7 @@ class HeaderBag implements \IteratorAggregate, \Countable
*/ */
public function remove($key) public function remove($key)
{ {
$key = str_replace('_', '-', strtolower($key)); $key = strtr($key, self::UPPER, self::LOWER);
unset($this->headers[$key]); unset($this->headers[$key]);

View File

@ -541,7 +541,7 @@ class Request
foreach ($this->headers->all() as $key => $value) { foreach ($this->headers->all() as $key => $value) {
$key = strtoupper(str_replace('-', '_', $key)); $key = strtoupper(str_replace('-', '_', $key));
if (\in_array($key, ['CONTENT_TYPE', 'CONTENT_LENGTH'])) { if (\in_array($key, ['CONTENT_TYPE', 'CONTENT_LENGTH', 'CONTENT_MD5'], true)) {
$_SERVER[$key] = implode(', ', $value); $_SERVER[$key] = implode(', ', $value);
} else { } else {
$_SERVER['HTTP_'.$key] = implode(', ', $value); $_SERVER['HTTP_'.$key] = implode(', ', $value);

View File

@ -51,7 +51,7 @@ class ResponseHeaderBag extends HeaderBag
{ {
$headers = []; $headers = [];
foreach ($this->all() as $name => $value) { foreach ($this->all() as $name => $value) {
$headers[isset($this->headerNames[$name]) ? $this->headerNames[$name] : $name] = $value; $headers[$this->headerNames[$name] ?? $name] = $value;
} }
return $headers; return $headers;
@ -95,7 +95,7 @@ class ResponseHeaderBag extends HeaderBag
$headers = parent::all(); $headers = parent::all();
if (1 <= \func_num_args() && null !== $key = func_get_arg(0)) { if (1 <= \func_num_args() && null !== $key = func_get_arg(0)) {
$key = str_replace('_', '-', strtolower($key)); $key = strtr($key, self::UPPER, self::LOWER);
return 'set-cookie' !== $key ? $headers[$key] ?? [] : array_map('strval', $this->getCookies()); return 'set-cookie' !== $key ? $headers[$key] ?? [] : array_map('strval', $this->getCookies());
} }
@ -112,7 +112,7 @@ class ResponseHeaderBag extends HeaderBag
*/ */
public function set($key, $values, $replace = true) public function set($key, $values, $replace = true)
{ {
$uniqueKey = str_replace('_', '-', strtolower($key)); $uniqueKey = strtr($key, self::UPPER, self::LOWER);
if ('set-cookie' === $uniqueKey) { if ('set-cookie' === $uniqueKey) {
if ($replace) { if ($replace) {
@ -143,7 +143,7 @@ class ResponseHeaderBag extends HeaderBag
*/ */
public function remove($key) public function remove($key)
{ {
$uniqueKey = str_replace('_', '-', strtolower($key)); $uniqueKey = strtr($key, self::UPPER, self::LOWER);
unset($this->headerNames[$uniqueKey]); unset($this->headerNames[$uniqueKey]);
if ('set-cookie' === $uniqueKey) { if ('set-cookie' === $uniqueKey) {

View File

@ -28,13 +28,10 @@ class ServerBag extends ParameterBag
public function getHeaders() public function getHeaders()
{ {
$headers = []; $headers = [];
$contentHeaders = ['CONTENT_LENGTH' => true, 'CONTENT_MD5' => true, 'CONTENT_TYPE' => true];
foreach ($this->parameters as $key => $value) { foreach ($this->parameters as $key => $value) {
if (0 === strpos($key, 'HTTP_')) { if (0 === strpos($key, 'HTTP_')) {
$headers[substr($key, 5)] = $value; $headers[substr($key, 5)] = $value;
} } elseif (\in_array($key, ['CONTENT_TYPE', 'CONTENT_LENGTH', 'CONTENT_MD5'], true)) {
// CONTENT_* are not prefixed with HTTP_
elseif (isset($contentHeaders[$key])) {
$headers[$key] = $value; $headers[$key] = $value;
} }
} }