8000 [http-foudation] Better accept header parsing · govaniso/symfony@6b601bd · GitHub
[go: up one dir, main page]

Skip to content
.hEHvLI{min-width:0;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}/*!sc*/ .bmcJak{min-width:0;}/*!sc*/ .fyKNMY[data-size="medium"]{color:var(--fgColor-default,var(--color-fg-default,#1F2328));}/*!sc*/ .gUkoLg{-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;}/*!sc*/ .gLSgdJ{font-weight:600;color:var(--fgColor-default,var(--color-fg-default,#1F2328));}/*!sc*/ .gLSgdJ:hover{color:var(--fgColor-default,var(--color-fg-default,#1F2328));}/*!sc*/ .irPhWZ{width:60px;}/*!sc*/ .dNbsEP{width:62px;}/*!sc*/ .kHfwUD{width:60px;height:22px;}/*!sc*/ .bHLmSv{position:absolute;inset:0 -2px;cursor:col-resize;background-color:transparent;-webkit-transition-delay:0.1s;transition-delay:0.1s;}/*!sc*/ .bHLmSv:hover{background-color:var(--bgColor-neutral-muted,var(--color-neutral-muted,rgba(175,184,193,0.2)));}/*!sc*/ data-styled.g1[id="Box-sc-g0xbh4-0"]{content:"hEHvLI,bmcJak,fyKNMY,gUkoLg,gLSgdJ,irPhWZ,dNbsEP,kHfwUD,bHLmSv,"}/*!sc*/ .jjwhNb{position:relative;display:inline-block;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}/*!sc*/ .jjwhNb::after{position:absolute;z-index:1000000;display:none;padding:0.5em 0.75em;font:normal normal 11px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";-webkit-font-smoothing:subpixel-antialiased;color:var(--tooltip-fgColor,var(--fgColor-onEmphasis,var(--color-fg-on-emphasis,#ffffff)));text-align:center;-webkit-text-decoration:none;text-decoration:none;text-shadow:none;text-transform:none;-webkit-letter-spacing:normal;-moz-letter-spacing:normal;-ms-letter-spacing:normal;letter-spacing:normal;word-wrap:break-word;white-space:pre;pointer-events:none;content:attr(aria-label);background:var(--tooltip-bgColor,var(--bgColor-emphasis,var(--color-neutral-emphasis-plus,#24292f)));border-radius:6px;opacity:0;}/*!sc*/ @-webkit-keyframes tooltip-appear{from{opacity:0;}to{opacity:1;}}/*!sc*/ @keyframes tooltip-appear{from{opacity:0;}to{opacity:1;}}/*!sc*/ .jjwhNb:hover::after,.jjwhNb:active::after,.jjwhNb:focus::after,.jjwhNb:focus-within::after{display:inline-block;-webkit-text-decoration:none;text-decoration:none;-webkit-animation-name:tooltip-appear;animation-name:tooltip-appear;-webkit-animation-duration:0.1s;animation-duration:0.1s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;-webkit-animation-delay:0s;animation-delay:0s;}/*!sc*/ .jjwhNb.tooltipped-no-delay:hover::after,.jjwhNb.tooltipped-no-delay:active::after,.jjwhNb.tooltipped-no-delay:focus::after,.jjwhNb.tooltipped-no-delay:focus-within::after{-webkit-animation-delay:0s;animation-delay:0s;}/*!sc*/ .jjwhNb.tooltipped-multiline:hover::after,.jjwhNb.tooltipped-multiline:active::after,.jjwhNb.tooltipped-multiline:focus::after,.jjwhNb.tooltipped-multiline:focus-within::after{display:table-cell;}/*!sc*/ .jjwhNb.tooltipped-s::after,.jjwhNb.tooltipped-se::after,.jjwhNb.tooltipped-sw::after{top:100%;right:50%;margin-top:6px;}/*!sc*/ .jjwhNb.tooltipped-se::after{right:auto;left:50%;margin-left:-16px;}/*!sc*/ .jjwhNb.tooltipped-sw::after{margin-right:-16px;}/*!sc*/ .jjwhNb.tooltipped-n::after,.jjwhNb.tooltipped-ne::after,.jjwhNb.tooltipped-nw::after{right:50%;bottom:100%;margin-bottom:6px;}/*!sc*/ .jjwhNb.tooltipped-ne::after{right:auto;left:50%;margin-left:-16px;}/*!sc*/ .jjwhNb.tooltipped-nw::after{margin-right:-16px;}/*!sc*/ .jjwhNb.tooltipped-s::after,.jjwhNb.tooltipped-n::after{-webkit-transform:translateX(50%);-ms-transform:translateX(50%);transform:translateX(50%);}/*!sc*/ .jjwhNb.tooltipped-w::after{right:100%;bottom:50%;margin-right:6px;-webkit-transform:translateY(50%);-ms-transform:translateY(50%);transform:translateY(50%);}/*!sc*/ .jjwhNb.tooltipped-e::after{bottom:50%;left:100%;margin-left:6px;-webkit-transform:translateY(50%);-ms-transform:translateY(50%);transform:translateY(50%);}/*!sc*/ .jjwhNb.tooltipped-multiline::after{width:-webkit-max-content;width:-moz-max-content;width:max-content;max-width:250px;word-wrap:break-word;white-space:pre-line;border-collapse:separate;}/*!sc*/ .jjwhNb.tooltipped-multiline.tooltipped-s::after,.jjwhNb.tooltipped-multiline.tooltipped-n::after{right:auto;left:50%;-webkit-transform:translateX(-50%);-ms-transform:translateX(-50%);transform:translateX(-50%);}/*!sc*/ .jjwhNb.tooltipped-multiline.tooltipped-w::after,.jjwhNb.tooltipped-multiline.tooltipped-e::after{right:100%;}/*!sc*/ .jjwhNb.tooltipped-align-right-2::after{right:0;margin-right:0;}/*!sc*/ .jjwhNb.tooltipped-align-left-2::after{left:0;margin-left:0;}/*!sc*/ data-styled.g4[id="Tooltip__TooltipBase-sc-17tf59c-0"]{content:"jjwhNb,"}/*!sc*/ .irithh{position:relative;overflow:hidden;-webkit-mask-image:radial-gradient(white,black);mask-image:radial-gradient(white,black);background-color:var(--bgColor-neutral-muted,var(--color-neutral-subtle,rgba(234,238,242,0.5)));border-radius:3px;display:block;height:1.2em;width:60px;}/*!sc*/ .irithh::after{-webkit-animation:crVFvv 1.5s infinite linear;animation:crVFvv 1.5s infinite linear;background:linear-gradient(90deg,transparent,var(--bgColor-neutral-muted,var(--color-neutral-subtle,rgba(234,238,242,0.5))),transparent);content:'';position:absolute;-webkit-transform:translateX(-100%);-ms-transform:translateX(-100%);transform:translateX(-100%);bottom:0;left:0;right:0;top:0;}/*!sc*/ .ihfxfT{position:relative;overflow:hidden;-webkit-mask-image:radial-gradient(white,black);mask-image:radial-gradient(white,black);background-color:var(--bgColor-neutral-muted,var(--color-neutral-subtle,rgba(234,238,242,0.5)));border-radius:3px;display:block;height:1.2em;width:62px;}/*!sc*/ .ihfxfT::after{-webkit-animation:crVFvv 1.5s infinite linear;animation:crVFvv 1.5s infinite linear;background:linear-gradient(90deg,transparent,var(--bgColor-neutral-muted,var(--color-neutral-subtle,rgba(234,238,242,0.5))),transparent);content:'';position:absolute;-webkit-transform:translateX(-100%);-ms-transform:translateX(-100%);transform:translateX(-100%);bottom:0;left:0;right:0;top:0;}/*!sc*/ .kRBfod{position:relative;overflow:hidden;-webkit-mask-image:radial-gradient(white,black);mask-image:radial-gradient(white,black);background-color:var(--bgColor-neutral-muted,var(--color-neutral-subtle,rgba(234,238,242,0.5)));border-radius:3px;display:block;height:1.2em;width:60px;height:22px;}/*!sc*/ .kRBfod::after{-webkit-animation:crVFvv 1.5s infinite linear;animation:crVFvv 1.5s infinite linear;background:linear-gradient(90deg,transparent,var(--bgColor-neutral-muted,var(--color-neutral-subtle,rgba(234,238,242,0.5))),transparent);content:'';position:absolute;-webkit-transform:translateX(-100%);-ms-transform:translateX(-100%);transform:translateX(-100%);bottom:0;left:0;right:0;top:0;}/*!sc*/ data-styled.g22[id="LoadingSkeleton-sc-695d630a-0"]{content:"irithh,ihfxfT,kRBfod,"}/*!sc*/ @-webkit-keyframes crVFvv{0%{-webkit-transform:translateX(-100%);-ms-transform:translateX(-100%);transform:translateX(-100%);}50%{-webkit-transform:translateX(100%);-ms-transform:translateX(100%);transform:translateX(100%);}100%{-webkit-transform:translateX(100%);-ms-transform:translateX(100%);transform:translateX(100%);}}/*!sc*/ @keyframes crVFvv{0%{-webkit-transform:translateX(-100%);-ms-transform:translateX(-100%);transform:translateX(-100%);}50%{-webkit-transform:translateX(100%);-ms-transform:translateX(100%);transform:translateX(100%);}100%{-webkit-transform:translateX(100%);-ms-transform:translateX(100%);transform:translateX(100%);}}/*!sc*/ data-styled.g43[id="sc-keyframes-crVFvv"]{content:"crVFvv,"}/*!sc*/

Commit 6b601bd

Browse files
jfsimonfabpot
authored andcommitted
[http-foudation] Better accept header parsing
1 parent d8f6021 commit 6b601bd

File tree

8 files changed

+650
-36
lines changed

8 files changed

+650
-36
lines changed

UPGRADE-2.2.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
UPGRADE FROM 2.1 to 2.2
2+
=======================
3+
4+
#### Deprecations
5+
6+
* The `Request::splitHttpAcceptHeader()` is deprecated and will be removed in 2.3.
7+
8+
You should now use the `AcceptHeader` class which give you fluent methods to
9+
parse request accept-* headers. Some examples:
10+
11+
```
12+
$accept = AcceptHeader::fromString($request->headers->get('Accept'));
13+
if ($accept->has('text/html') {
14+
$item = $accept->get('html');
15+
$charset = $item->getAttribute('charset', 'utf-8');
16+
$quality = $item->getQuality();
17+
}
18+
19+
// accepts items are sorted by descending quality
20+
$accepts = AcceptHeader::fromString($request->headers->get('Accept'))->all();
21+
22+
```
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\HttpFoundation;
13+
14+
/**
15+
* Represents an Accept-* header.
16+
*
17+
* An accept header is compound with a list of items,
18+
* sorted by descending quality.
19+
*
20+
* @author Jean-François Simon <contact@jfsimon.fr>
21+
*/
22+
class AcceptHeader
23+
{
24+
/**
25+
* @var AcceptHeaderItem[]
26+
*/
27+
private $items = array();
28+
29+
/**
30+
* @var bool
31+
*/
32+
private $sorted = true;
33+
34+
/**
35+
* Constructor.
36+
*
37+
* @param AcceptHeaderItem[] $items
38+
*/
39+
public function __construct(array $items)
40+
{
41+
foreach ($items as $item) {
42+
$this->add($item);
43+
}
44+
}
45+
46+
/**
47+
* Builds an AcceptHeader instance from a string.
48+
*
49+
* @param string $headerValue
50+
*
51+
* @return AcceptHeader
52+
*/
53+
public static function fromString($headerValue)
54+
{
55+
$index = 0;
56+
57+
return new self(array_map(function ($itemValue) use (&$index) {
58+
$item = AcceptHeaderItem::fromString($itemValue);
59+
$item->setIndex($index++);
60+
61+
return $item;
62+
}, preg_split('/\s*(?:,*("[^"]+"),*|,*(\'[^\']+\'),*|,+)\s*/', $headerValue, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE)));
63+
}
64+
65+
/**
66+
* Returns header value's string representation.
67+
*
68+
* @return string
69+
*/
70+
public function __toString()
71+
{
72+
return implode(',', $this->items);
73+
}
74+
75+
/**
76+
* Tests if header has given value.
77+
*
78+
* @param string $value
79+
*
80+
* @return Boolean
81+
*/
82+
public function has($value)
83+
{
84+
return isset($this->items[$value]);
85+
}
86+
87+
/**
88+
* Returns given value's item, if exists.
89+
*
90+
* @param string $value
91+
*
92+
* @return AcceptHeaderItem|null
93+
*/
94+
public function get($value)
95+
{
96+
return isset($this->items[$value]) ? $this->items[$value] : null;
97+
}
98+
99+
/**
100+
* Adds an item.
101+
*
102+
* @param AcceptHeaderItem $item
103+
*
104+
* @return AcceptHeader
105+
*/
106+
public function add(AcceptHeaderItem $item)
107+
{
108+
$this->items[$item->getValue()] = $item;
109+
$this->sorted = false;
110+
111+
return $this;
112+
}
113+
114+
/**
115+
* Returns all items.
116+
*
117+
* @return AcceptHeaderItem[]
118+
*/
119+
public function all()
120+
{
121+
$this->sort();
122+
123+
return $this->items;
124+
}
125+
126+
/**
127+
* Filters items on their value using given regex.
128+
*
129+
* @param string $pattern
130+
*
131+
* @return AcceptHeader
132+
*/
133+
public function filter($pattern)
134+
{
135+
return new self(array_filter($this->items, function (AcceptHeaderItem $item) use ($pattern) {
136+
return preg_match($pattern, $item->getValue());
137+
}));
138+
}
139+
140+
/**
141+
* Returns first item.
142+
*
143+
* @return AcceptHeaderItem|null
144+
*/
145+
public function first()
146+
{
147+
$this->sort();
148+
149+
return !empty($this->items) ? current($this->items) : null;
150+
}
151+
152+
/**
153+
* Sorts items by descending quality
154+
*/
155+
private function sort()
156+
{
157+
if (!$this->sorted) {
158+
uasort($this->items, function ($a, $b) {
159+
$qA = $a->getQuality();
160+
$qB = $b->getQuality();
161+
162+
if ($qA === $qB) {
163+
return $a->getIndex() > $b->getIndex() ? 1 : -1;
164+
}
165+
166+
return $qA > $qB ? -1 : 1;
167+
});
168+
169+
$this->sorted = true;
170+
}
171+
}
172+
}

0 commit comments

Comments
 (0)
0