Introduced a HeaderUtils class

Christian Schmidt
Contributed by Christian Schmidt in #24699

Parsing HTTP headers is not as trivial as some may think. It requires parsing quoted strings with backslash escaping and ignoring white-space in certain places. We did that in some methods of the HttpFoundation component but the repeated logic was starting to make the code hard to maintain.

That's why in Symfony 4.1 we've introduced a new HeaderUtils class that provides the most common utilities needed when parsing HTTP headers. This is not an internal class, so you can use it in your own code too:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
use Symfony\Component\HttpFoundation\HeaderUtils;

// Splits an HTTP header by one or more separators
HeaderUtils::split('da, en-gb;q=0.8', ',;')
// => array(array('da'), array('en-gb'), array('q', '0.8'))

// Combines an array of arrays into one associative array
HeaderUtils::combine(array(array('foo', 'abc'), array('bar')))
// => array('foo' => 'abc', 'bar' => true)

// Joins an associative array into a string for use in an HTTP header
HeaderUtils::toString(array('foo' => 'abc', 'bar' => true, 'baz' => 'a b c'), ',')
// => 'foo=abc, bar, baz="a b c"'

// Encodes a string as a quoted string, if necessary
HeaderUtils::quote('foo "bar"')
// => 'foo \"bar\"'

// Decodes a quoted string
HeaderUtils::unquote('foo \"bar\"')
// => 'foo "bar"'

Allow to bypass headers when submitting forms in tests

cfjulien
Contributed by cfjulien in #26791

An issue reported by the Mink browser testing project made us realize that you cannot bypass HTTP header information when submitting forms in tests which use the BrowserKit component.

That's why in Symfony 4.1 the submit() method now accepts a third optional argument called $serverParameters which allows you to do things like this:

1
2
3
4
$crawler = $client->request('GET', 'http://www.example.com/foo');
$form = $crawler->filter('input')->form();
$client->submit($form, [], ['HTTP_ACCEPT_LANGUAGE' => 'de']);
// => $client->getRequest()->getServer()['HTTP_ACCEPT_LANGUAGE'] = 'de'

Added support for default values in Accept headers

Javier Eguiluz
Contributed by Javier Eguiluz in #26036

When using the Accept HTTP header it's common to use expressions like .../*, */* and even * to define the default values:

1
Accept: text/plain;q=0.5, text/html, text/*;q=0.8, */*

However, in Symfony versions previous to 4.1 these default values weren't supported:

1
2
3
4
5
6
use Symfony\Component\HttpFoundation\AcceptHeader;

$acceptHeader = AcceptHeader::fromString('text/plain;q=0.5, text/html, text/*;q=0.8, */*');
$quality = $acceptHeader->get('text/xml')->getQuality();
// instead of returning '0.8', this code displays the following error message:
//   Call to a member function getQuality() on null

In Symfony 4.1 all these default values are now properly supported:

1
2
3
4
$acceptHeader = AcceptHeader::fromString('text/plain;q=0.5, text/html, text/*;q=0.8, */*');
$acceptHeader->get('text/xml')->getQuality();        // => 0.8 (because of text/*)
$acceptHeader->get('text/html')->getQuality();       // => 1.0
$acceptHeader->get('application/xml')->getQuality(); // => 1.0 (because of */*)
Published in #Living on the edge