[HttpFoundation] Add HeaderUtility class
This commit is contained in:
parent
306c5992ec
commit
b435e80cae
@ -52,12 +52,17 @@ class AcceptHeader
|
||||
{
|
||||
$index = 0;
|
||||
|
||||
return new self(array_map(function ($itemValue) use (&$index) {
|
||||
$item = AcceptHeaderItem::fromString($itemValue);
|
||||
$parts = HeaderUtils::split((string) $headerValue, ',;=');
|
||||
|
||||
return new self(array_map(function ($subParts) use (&$index) {
|
||||
$part = array_shift($subParts);
|
||||
$attributes = HeaderUtils::combineParts($subParts);
|
||||
|
||||
$item = new AcceptHeaderItem($part[0], $attributes);
|
||||
$item->setIndex($index++);
|
||||
|
||||
return $item;
|
||||
}, preg_split('/\s*(?:,*("[^"]+"),*|,*(\'[^\']+\'),*|,+)\s*/', $headerValue, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE)));
|
||||
}, $parts));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -40,24 +40,12 @@ class AcceptHeaderItem
|
||||
*/
|
||||
public static function fromString($itemValue)
|
||||
{
|
||||
$bits = preg_split('/\s*(?:;*("[^"]+");*|;*(\'[^\']+\');*|;+)\s*/', $itemValue, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
|
||||
$value = array_shift($bits);
|
||||
$attributes = array();
|
||||
$parts = HeaderUtils::split($itemValue, ';=');
|
||||
|
||||
$lastNullAttribute = null;
|
||||
foreach ($bits as $bit) {
|
||||
if (($start = substr($bit, 0, 1)) === ($end = substr($bit, -1)) && ('"' === $start || '\'' === $start)) {
|
||||
$attributes[$lastNullAttribute] = substr($bit, 1, -1);
|
||||
} elseif ('=' === $end) {
|
||||
$lastNullAttribute = $bit = substr($bit, 0, -1);
|
||||
$attributes[$bit] = null;
|
||||
} else {
|
||||
$parts = explode('=', $bit);
|
||||
$attributes[$parts[0]] = isset($parts[1]) && strlen($parts[1]) > 0 ? $parts[1] : '';
|
||||
}
|
||||
}
|
||||
$part = array_shift($parts);
|
||||
$attributes = HeaderUtils::combineParts($parts, 1);
|
||||
|
||||
return new self(($start = substr($value, 0, 1)) === ($end = substr($value, -1)) && ('"' === $start || '\'' === $start) ? substr($value, 1, -1) : $value, $attributes);
|
||||
return new self($part[0], $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -69,9 +57,7 @@ class AcceptHeaderItem
|
||||
{
|
||||
$string = $this->value.($this->quality < 1 ? ';q='.$this->quality : '');
|
||||
if (count($this->attributes) > 0) {
|
||||
$string .= ';'.implode(';', array_map(function ($name, $value) {
|
||||
return sprintf(preg_match('/[,;=]/', $value) ? '%s="%s"' : '%s=%s', $name, $value);
|
||||
}, array_keys($this->attributes), $this->attributes));
|
||||
$string .= '; '.HeaderUtils::joinAssoc($this->attributes, ';');
|
||||
}
|
||||
|
||||
return $string;
|
||||
|
@ -218,20 +218,15 @@ class BinaryFileResponse extends Response
|
||||
if ('x-accel-redirect' === strtolower($type)) {
|
||||
// Do X-Accel-Mapping substitutions.
|
||||
// @link http://wiki.nginx.org/X-accel#X-Accel-Redirect
|
||||
foreach (explode(',', $request->headers->get('X-Accel-Mapping', '')) as $mapping) {
|
||||
$mapping = explode('=', $mapping, 2);
|
||||
|
||||
if (2 === count($mapping)) {
|
||||
$pathPrefix = trim($mapping[0]);
|
||||
$location = trim($mapping[1]);
|
||||
|
||||
$parts = HeaderUtils::split($request->headers->get('X-Accel-Mapping', ''), ',=');
|
||||
$mappings = HeaderUtils::combineParts($parts);
|
||||
foreach ($mappings as $pathPrefix => $location) {
|
||||
if (substr($path, 0, strlen($pathPrefix)) === $pathPrefix) {
|
||||
$path = $location.substr($path, strlen($pathPrefix));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->headers->set($type, $path);
|
||||
$this->maxlen = 0;
|
||||
} elseif ($request->headers->has('Range')) {
|
||||
|
@ -16,6 +16,7 @@ CHANGELOG
|
||||
`IniSizeFileException`, `NoFileException`, `NoTmpDirFileException`, `PartialFileException` to
|
||||
handle failed `UploadedFile`.
|
||||
* added `MigratingSessionHandler` for migrating between two session handlers without losing sessions
|
||||
* added `HeaderUtils`.
|
||||
|
||||
4.0.0
|
||||
-----
|
||||
|
@ -50,34 +50,20 @@ class Cookie
|
||||
'raw' => !$decode,
|
||||
'samesite' => null,
|
||||
);
|
||||
foreach (explode(';', $cookie) as $part) {
|
||||
if (false === strpos($part, '=')) {
|
||||
$key = trim($part);
|
||||
$value = true;
|
||||
} else {
|
||||
list($key, $value) = explode('=', trim($part), 2);
|
||||
$key = trim($key);
|
||||
$value = trim($value);
|
||||
}
|
||||
if (!isset($data['name'])) {
|
||||
$data['name'] = $decode ? urldecode($key) : $key;
|
||||
$data['value'] = true === $value ? null : ($decode ? urldecode($value) : $value);
|
||||
continue;
|
||||
}
|
||||
switch ($key = strtolower($key)) {
|
||||
case 'name':
|
||||
case 'value':
|
||||
break;
|
||||
case 'max-age':
|
||||
$data['expires'] = time() + (int) $value;
|
||||
break;
|
||||
default:
|
||||
$data[$key] = $value;
|
||||
break;
|
||||
}
|
||||
|
||||
$parts = HeaderUtils::split($cookie, ';=');
|
||||
$part = array_shift($parts);
|
||||
|
||||
$name = $decode ? urldecode($part[0]) : $part[0];
|
||||
$value = isset($part[1]) ? ($decode ? urldecode($part[1]) : $part[1]) : null;
|
||||
|
||||
$data = HeaderUtils::combineParts($parts) + $data;
|
||||
|
||||
if (isset($data['max-age'])) {
|
||||
$data['expires'] = time() + (int) $data['max-age'];
|
||||
}
|
||||
|
||||
return new static($data['name'], $data['value'], $data['expires'], $data['path'], $data['domain'], $data['secure'], $data['httponly'], $data['raw'], $data['samesite']);
|
||||
return new static($name, $value, $data['expires'], $data['path'], $data['domain'], $data['secure'], $data['httponly'], $data['raw'], $data['samesite']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -294,21 +294,9 @@ class HeaderBag implements \IteratorAggregate, \Countable
|
||||
|
||||
protected function getCacheControlHeader()
|
||||
{
|
||||
$parts = array();
|
||||
ksort($this->cacheControl);
|
||||
foreach ($this->cacheControl as $key => $value) {
|
||||
if (true === $value) {
|
||||
$parts[] = $key;
|
||||
} else {
|
||||
if (preg_match('#[^a-zA-Z0-9._-]#', $value)) {
|
||||
$value = '"'.$value.'"';
|
||||
}
|
||||
|
||||
$parts[] = "$key=$value";
|
||||
}
|
||||
}
|
||||
|
||||
return implode(', ', $parts);
|
||||
return HeaderUtils::joinAssoc($this->cacheControl, ',');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -320,12 +308,8 @@ class HeaderBag implements \IteratorAggregate, \Countable
|
||||
*/
|
||||
protected function parseCacheControl($header)
|
||||
{
|
||||
$cacheControl = array();
|
||||
preg_match_all('#([a-zA-Z][a-zA-Z_-]*)\s*(?:=(?:"([^"]*)"|([^ \t",;]*)))?#', $header, $matches, PREG_SET_ORDER);
|
||||
foreach ($matches as $match) {
|
||||
$cacheControl[strtolower($match[1])] = isset($match[3]) ? $match[3] : (isset($match[2]) ? $match[2] : true);
|
||||
}
|
||||
$parts = HeaderUtils::split($header, ',=');
|
||||
|
||||
return $cacheControl;
|
||||
return HeaderUtils::combineParts($parts);
|
||||
}
|
||||
}
|
||||
|
174
src/Symfony/Component/HttpFoundation/HeaderUtils.php
Normal file
174
src/Symfony/Component/HttpFoundation/HeaderUtils.php
Normal file
@ -0,0 +1,174 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpFoundation;
|
||||
|
||||
/**
|
||||
* HTTP header utility functions.
|
||||
*
|
||||
* @author Christian Schmidt <github@chsc.dk>
|
||||
*/
|
||||
class HeaderUtils
|
||||
{
|
||||
/**
|
||||
* This class should not be instantiated.
|
||||
*/
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits an HTTP header by one or more separators.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* HeaderUtils::split("da, en-gb;q=0.8", ",;")
|
||||
* // => array(array("da"), array("en-gb"), array("q", "0.8"))
|
||||
*
|
||||
* @param string $header HTTP header value
|
||||
* @param string $separators List of characters to split on, ordered by
|
||||
* precedence, e.g. ",", ";=", or ",;="
|
||||
*
|
||||
* @return array Nested array with as many levels as there are characters in
|
||||
* $separators
|
||||
*/
|
||||
public static function split(string $header, string $separators): array
|
||||
{
|
||||
$quotedSeparators = preg_quote($separators);
|
||||
|
||||
preg_match_all('
|
||||
/
|
||||
(?!\s)
|
||||
(?:
|
||||
# quoted-string
|
||||
"(?:[^"\\\\]|\\\\.)*(?:"|\\\\|$)
|
||||
|
|
||||
# token
|
||||
[^"'.$quotedSeparators.']+
|
||||
)+
|
||||
(?<!\s)
|
||||
|
|
||||
# separator
|
||||
\s*
|
||||
(?<separator>['.$quotedSeparators.'])
|
||||
\s*
|
||||
/x', trim($header), $matches, PREG_SET_ORDER);
|
||||
|
||||
return self::groupParts($matches, $separators);
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines an array of arrays into one associative array.
|
||||
*
|
||||
* Each of the nested arrays should have one or two elements. The first
|
||||
* value will be used as the keys in the associative array, and the second
|
||||
* will be used as the values, or true if the nested array only contains one
|
||||
* element.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* HeaderUtils::combineParts(array(array("foo", "abc"), array("bar")))
|
||||
* // => array("foo" => "abc", "bar" => true)
|
||||
*/
|
||||
public static function combineParts(array $parts): array
|
||||
{
|
||||
$assoc = array();
|
||||
foreach ($parts as $part) {
|
||||
$name = strtolower($part[0]);
|
||||
$value = $part[1] ?? true;
|
||||
$assoc[$name] = $value;
|
||||
}
|
||||
|
||||
return $assoc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins an associative array into a string for use in an HTTP header.
|
||||
*
|
||||
* The key and value of each entry are joined with "=", and all entries
|
||||
* is joined with the specified separator and an additional space (for
|
||||
* readability). Values are quoted if necessary.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* HeaderUtils::joinAssoc(array("foo" => "abc", "bar" => true, "baz" => "a b c"), ",")
|
||||
* // => 'foo=bar, baz, baz="a b c"'
|
||||
*/
|
||||
public static function joinAssoc(array $assoc, string $separator): string
|
||||
{
|
||||
$parts = array();
|
||||
foreach ($assoc as $name => $value) {
|
||||
if (true === $value) {
|
||||
$parts[] = $name;
|
||||
} else {
|
||||
$parts[] = $name.'='.self::quote($value);
|
||||
}
|
||||
}
|
||||
|
||||
return implode($separator.' ', $parts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a string as a quoted string, if necessary.
|
||||
*
|
||||
* If a string contains characters not allowed by the "token" construct in
|
||||
* the HTTP specification, it is backslash-escaped and enclosed in quotes
|
||||
* to match the "quoted-string" construct.
|
||||
*/
|
||||
public static function quote(string $s): string
|
||||
{
|
||||
if (preg_match('/^[a-z0-9!#$%&\'*.^_`|~-]+$/i', $s)) {
|
||||
return $s;
|
||||
}
|
||||
|
||||
return '"'.addcslashes($s, '"\\"').'"';
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a quoted string.
|
||||
*
|
||||
* If passed an unquoted string that matches the "token" construct (as
|
||||
* defined in the HTTP specification), it is passed through verbatimly.
|
||||
*/
|
||||
public static function unquote(string $s): string
|
||||
{
|
||||
return preg_replace('/\\\\(.)|"/', '$1', $s);
|
||||
}
|
||||
|
||||
private static function groupParts(array $matches, string $separators): array
|
||||
{
|
||||
$separator = $separators[0];
|
||||
$partSeparators = substr($separators, 1);
|
||||
|
||||
$i = 0;
|
||||
$partMatches = array();
|
||||
foreach ($matches as $match) {
|
||||
if (isset($match['separator']) && $match['separator'] === $separator) {
|
||||
++$i;
|
||||
} else {
|
||||
$partMatches[$i][] = $match;
|
||||
}
|
||||
}
|
||||
|
||||
$parts = array();
|
||||
if ($partSeparators) {
|
||||
foreach ($partMatches as $matches) {
|
||||
$parts[] = self::groupParts($matches, $partSeparators);
|
||||
}
|
||||
} else {
|
||||
foreach ($partMatches as $matches) {
|
||||
$parts[] = self::unquote($matches[0][0]);
|
||||
}
|
||||
}
|
||||
|
||||
return $parts;
|
||||
}
|
||||
}
|
@ -1944,8 +1944,16 @@ class Request
|
||||
}
|
||||
|
||||
if ((self::$trustedHeaderSet & self::HEADER_FORWARDED) && $this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED])) {
|
||||
$forwardedValues = $this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]);
|
||||
$forwardedValues = preg_match_all(sprintf('{(?:%s)=(?:"?\[?)([a-zA-Z0-9\.:_\-/]*+)}', self::$forwardedParams[$type]), $forwardedValues, $matches) ? $matches[1] : array();
|
||||
$forwarded = $this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]);
|
||||
$parts = HeaderUtils::split($forwarded, ',;=');
|
||||
$forwardedValues = array();
|
||||
$param = self::$forwardedParams[$type];
|
||||
foreach ($parts as $subParts) {
|
||||
$assoc = HeaderUtils::combineParts($subParts);
|
||||
if (isset($assoc[$param])) {
|
||||
$forwardedValues[] = $assoc[$param];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $ip) {
|
||||
@ -1978,9 +1986,17 @@ class Request
|
||||
$firstTrustedIp = null;
|
||||
|
||||
foreach ($clientIps as $key => $clientIp) {
|
||||
// Remove port (unfortunately, it does happen)
|
||||
if (preg_match('{((?:\d+\.){3}\d+)\:\d+}', $clientIp, $match)) {
|
||||
$clientIps[$key] = $clientIp = $match[1];
|
||||
if (strpos($clientIp, '.')) {
|
||||
// Strip :port from IPv4 addresses. This is allowed in Forwarded
|
||||
// and may occur in X-Forwarded-For.
|
||||
$i = strpos($clientIp, ':');
|
||||
if ($i) {
|
||||
$clientIps[$key] = $clientIp = substr($clientIp, 0, $i);
|
||||
}
|
||||
} elseif ('[' == $clientIp[0]) {
|
||||
// Strip brackets and :port from IPv6 addresses.
|
||||
$i = strpos($clientIp, ']', 1);
|
||||
$clientIps[$key] = $clientIp = substr($clientIp, 1, $i - 1);
|
||||
}
|
||||
|
||||
if (!filter_var($clientIp, FILTER_VALIDATE_IP)) {
|
||||
|
@ -290,13 +290,12 @@ class ResponseHeaderBag extends HeaderBag
|
||||
throw new \InvalidArgumentException('The filename and the fallback cannot contain the "/" and "\\" characters.');
|
||||
}
|
||||
|
||||
$output = sprintf('%s; filename="%s"', $disposition, str_replace('"', '\\"', $filenameFallback));
|
||||
|
||||
$params = array('filename' => $filenameFallback);
|
||||
if ($filename !== $filenameFallback) {
|
||||
$output .= sprintf("; filename*=utf-8''%s", rawurlencode($filename));
|
||||
$params['filename*'] = "utf-8''".rawurlencode($filename);
|
||||
}
|
||||
|
||||
return $output;
|
||||
return $disposition.'; '.HeaderUtils::joinAssoc($params, ';');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -66,7 +66,7 @@ class AcceptHeaderItemTest extends TestCase
|
||||
),
|
||||
array(
|
||||
'text/plain', array('charset' => 'utf-8', 'param' => 'this;should,not=matter', 'footnotes' => 'true'),
|
||||
'text/plain;charset=utf-8;param="this;should,not=matter";footnotes=true',
|
||||
'text/plain; charset=utf-8; param="this;should,not=matter"; footnotes=true',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ class BinaryFileResponseTest extends ResponseTestCase
|
||||
$response = BinaryFileResponse::create($file, 404, array(), true, ResponseHeaderBag::DISPOSITION_INLINE);
|
||||
$this->assertEquals(404, $response->getStatusCode());
|
||||
$this->assertFalse($response->headers->has('ETag'));
|
||||
$this->assertEquals('inline; filename="README.md"', $response->headers->get('Content-Disposition'));
|
||||
$this->assertEquals('inline; filename=README.md', $response->headers->get('Content-Disposition'));
|
||||
}
|
||||
|
||||
public function testConstructWithNonAsciiFilename()
|
||||
@ -66,7 +66,7 @@ class BinaryFileResponseTest extends ResponseTestCase
|
||||
$response = new BinaryFileResponse(__FILE__);
|
||||
$response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, 'föö.html');
|
||||
|
||||
$this->assertSame('attachment; filename="f__.html"; filename*=utf-8\'\'f%C3%B6%C3%B6.html', $response->headers->get('Content-Disposition'));
|
||||
$this->assertSame('attachment; filename=f__.html; filename*=utf-8\'\'f%C3%B6%C3%B6.html', $response->headers->get('Content-Disposition'));
|
||||
}
|
||||
|
||||
public function testSetContentDispositionGeneratesSafeFallbackFilenameForWronglyEncodedFilename()
|
||||
@ -77,7 +77,7 @@ class BinaryFileResponseTest extends ResponseTestCase
|
||||
$response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $iso88591EncodedFilename);
|
||||
|
||||
// the parameter filename* is invalid in this case (rawurldecode('f%F6%F6') does not provide a UTF-8 string but an ISO-8859-1 encoded one)
|
||||
$this->assertSame('attachment; filename="f__.html"; filename*=utf-8\'\'f%F6%F6.html', $response->headers->get('Content-Disposition'));
|
||||
$this->assertSame('attachment; filename=f__.html; filename*=utf-8\'\'f%F6%F6.html', $response->headers->get('Content-Disposition'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -201,6 +201,9 @@ class CookieTest extends TestCase
|
||||
|
||||
$cookie = Cookie::fromString('foo=bar', true);
|
||||
$this->assertEquals(new Cookie('foo', 'bar', 0, '/', null, false, false), $cookie);
|
||||
|
||||
$cookie = Cookie::fromString('foo', true);
|
||||
$this->assertEquals(new Cookie('foo', null, 0, '/', null, false, false), $cookie);
|
||||
}
|
||||
|
||||
public function testFromStringWithHttpOnly()
|
||||
|
@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpFoundation\Tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\HttpFoundation\HeaderUtils;
|
||||
|
||||
class HeaderUtilsTest extends TestCase
|
||||
{
|
||||
public function testSplit()
|
||||
{
|
||||
$this->assertSame(array('foo=123', 'bar'), HeaderUtils::split('foo=123,bar', ','));
|
||||
$this->assertSame(array('foo=123', 'bar'), HeaderUtils::split('foo=123, bar', ','));
|
||||
$this->assertSame(array(array('foo=123', 'bar')), HeaderUtils::split('foo=123; bar', ',;'));
|
||||
$this->assertSame(array(array('foo=123'), array('bar')), HeaderUtils::split('foo=123, bar', ',;'));
|
||||
$this->assertSame(array('foo', '123, bar'), HeaderUtils::split('foo=123, bar', '='));
|
||||
$this->assertSame(array('foo', '123, bar'), HeaderUtils::split(' foo = 123, bar ', '='));
|
||||
$this->assertSame(array(array('foo', '123'), array('bar')), HeaderUtils::split('foo=123, bar', ',='));
|
||||
$this->assertSame(array(array(array('foo', '123')), array(array('bar'), array('foo', '456'))), HeaderUtils::split('foo=123, bar; foo=456', ',;='));
|
||||
$this->assertSame(array(array(array('foo', 'a,b;c=d'))), HeaderUtils::split('foo="a,b;c=d"', ',;='));
|
||||
|
||||
$this->assertSame(array('foo', 'bar'), HeaderUtils::split('foo,,,, bar', ','));
|
||||
$this->assertSame(array('foo', 'bar'), HeaderUtils::split(',foo, bar,', ','));
|
||||
$this->assertSame(array('foo', 'bar'), HeaderUtils::split(' , foo, bar, ', ','));
|
||||
$this->assertSame(array('foo bar'), HeaderUtils::split('foo "bar"', ','));
|
||||
$this->assertSame(array('foo bar'), HeaderUtils::split('"foo" bar', ','));
|
||||
$this->assertSame(array('foo bar'), HeaderUtils::split('"foo" "bar"', ','));
|
||||
|
||||
// These are not a valid header values. We test that they parse anyway,
|
||||
// and that both the valid and invalid parts are returned.
|
||||
$this->assertSame(array(), HeaderUtils::split('', ','));
|
||||
$this->assertSame(array(), HeaderUtils::split(',,,', ','));
|
||||
$this->assertSame(array('foo', 'bar', 'baz'), HeaderUtils::split('foo, "bar", "baz', ','));
|
||||
$this->assertSame(array('foo', 'bar, baz'), HeaderUtils::split('foo, "bar, baz', ','));
|
||||
$this->assertSame(array('foo', 'bar, baz\\'), HeaderUtils::split('foo, "bar, baz\\', ','));
|
||||
$this->assertSame(array('foo', 'bar, baz\\'), HeaderUtils::split('foo, "bar, baz\\\\', ','));
|
||||
}
|
||||
|
||||
public function testCombineAssoc()
|
||||
{
|
||||
$this->assertSame(array('foo' => '123'), HeaderUtils::combineParts(array(array('foo', '123'))));
|
||||
$this->assertSame(array('foo' => true), HeaderUtils::combineParts(array(array('foo'))));
|
||||
$this->assertSame(array('foo' => true), HeaderUtils::combineParts(array(array('Foo'))));
|
||||
$this->assertSame(array('foo' => '123', 'bar' => true), HeaderUtils::combineParts(array(array('foo', '123'), array('bar'))));
|
||||
}
|
||||
|
||||
public function testJoinAssoc()
|
||||
{
|
||||
$this->assertSame('foo', HeaderUtils::joinAssoc(array('foo' => true), ','));
|
||||
$this->assertSame('foo; bar', HeaderUtils::joinAssoc(array('foo' => true, 'bar' => true), ';'));
|
||||
$this->assertSame('foo=123', HeaderUtils::joinAssoc(array('foo' => '123'), ','));
|
||||
$this->assertSame('foo="1 2 3"', HeaderUtils::joinAssoc(array('foo' => '1 2 3'), ','));
|
||||
$this->assertSame('foo="1 2 3", bar', HeaderUtils::joinAssoc(array('foo' => '1 2 3', 'bar' => true), ','));
|
||||
}
|
||||
|
||||
public function testQuote()
|
||||
{
|
||||
$this->assertSame('foo', HeaderUtils::quote('foo'));
|
||||
$this->assertSame('az09!#$%&\'*.^_`|~-', HeaderUtils::quote('az09!#$%&\'*.^_`|~-'));
|
||||
$this->assertSame('"foo bar"', HeaderUtils::quote('foo bar'));
|
||||
$this->assertSame('"foo [bar]"', HeaderUtils::quote('foo [bar]'));
|
||||
$this->assertSame('"foo \"bar\""', HeaderUtils::quote('foo "bar"'));
|
||||
$this->assertSame('"foo \\\\ bar"', HeaderUtils::quote('foo \\ bar'));
|
||||
}
|
||||
|
||||
public function testUnquote()
|
||||
{
|
||||
$this->assertEquals('foo', HeaderUtils::unquote('foo'));
|
||||
$this->assertEquals('az09!#$%&\'*.^_`|~-', HeaderUtils::unquote('az09!#$%&\'*.^_`|~-'));
|
||||
$this->assertEquals('foo bar', HeaderUtils::unquote('"foo bar"'));
|
||||
$this->assertEquals('foo [bar]', HeaderUtils::unquote('"foo [bar]"'));
|
||||
$this->assertEquals('foo "bar"', HeaderUtils::unquote('"foo \"bar\""'));
|
||||
$this->assertEquals('foo "bar"', HeaderUtils::unquote('"foo \"\b\a\r\""'));
|
||||
$this->assertEquals('foo \\ bar', HeaderUtils::unquote('"foo \\\\ bar"'));
|
||||
}
|
||||
}
|
@ -894,7 +894,7 @@ class RequestTest extends TestCase
|
||||
array(array('127.0.0.1'), '127.0.0.1', 'for="_gazonk"', array('127.0.0.1')),
|
||||
array(array('88.88.88.88'), '127.0.0.1', 'for="88.88.88.88:80"', array('127.0.0.1')),
|
||||
array(array('192.0.2.60'), '::1', 'for=192.0.2.60;proto=http;by=203.0.113.43', array('::1')),
|
||||
array(array('2620:0:1cfe:face:b00c::3', '192.0.2.43'), '::1', 'for=192.0.2.43, for=2620:0:1cfe:face:b00c::3', array('::1')),
|
||||
array(array('2620:0:1cfe:face:b00c::3', '192.0.2.43'), '::1', 'for=192.0.2.43, for="[2620:0:1cfe:face:b00c::3]"', array('::1')),
|
||||
array(array('2001:db8:cafe::17'), '::1', 'for="[2001:db8:cafe::17]:4711', array('::1')),
|
||||
);
|
||||
}
|
||||
|
@ -287,12 +287,12 @@ class ResponseHeaderBagTest extends TestCase
|
||||
public function provideMakeDisposition()
|
||||
{
|
||||
return array(
|
||||
array('attachment', 'foo.html', 'foo.html', 'attachment; filename="foo.html"'),
|
||||
array('attachment', 'foo.html', '', 'attachment; filename="foo.html"'),
|
||||
array('attachment', 'foo.html', 'foo.html', 'attachment; filename=foo.html'),
|
||||
array('attachment', 'foo.html', '', 'attachment; filename=foo.html'),
|
||||
array('attachment', 'foo bar.html', '', 'attachment; filename="foo bar.html"'),
|
||||
array('attachment', 'foo "bar".html', '', 'attachment; filename="foo \\"bar\\".html"'),
|
||||
array('attachment', 'foo%20bar.html', 'foo bar.html', 'attachment; filename="foo bar.html"; filename*=utf-8\'\'foo%2520bar.html'),
|
||||
array('attachment', 'föö.html', 'foo.html', 'attachment; filename="foo.html"; filename*=utf-8\'\'f%C3%B6%C3%B6.html'),
|
||||
array('attachment', 'föö.html', 'foo.html', 'attachment; filename=foo.html; filename*=utf-8\'\'f%C3%B6%C3%B6.html'),
|
||||
);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user