|
12 | 12 |
|
13 | 13 | namespace chillerlan\HTTP\Utils;
|
14 | 14 |
|
15 |
| -use function array_keys, array_values, count, explode, implode, |
16 |
| - is_array, is_numeric, is_string, strtolower, trim, ucfirst; |
| 15 | +use InvalidArgumentException; |
| 16 | +use function array_keys, array_values, count, explode, implode, is_array, |
| 17 | + is_numeric, is_scalar, is_string, str_replace, strtolower, trim, ucfirst; |
17 | 18 |
|
18 | 19 | /**
|
19 | 20 | *
|
@@ -48,27 +49,29 @@ public static function normalize(iterable $headers):array{
|
48 | 49 |
|
49 | 50 | // array received from Message::getHeaders()
|
50 | 51 | if(is_array($val)){
|
51 |
| - foreach($val as $line){ |
| 52 | + foreach(self::trimValues($val) as $line){ |
52 | 53 | $normalized[$key][$name($line)] = trim($line);
|
53 | 54 | }
|
54 | 55 | }
|
55 | 56 | else{
|
56 |
| - $normalized[$key][$name($val)] = trim($val); |
| 57 | + $val = self::trimValues([$val])[0]; |
| 58 | + |
| 59 | + $normalized[$key][$name($val)] = $val; |
57 | 60 | }
|
58 | 61 | }
|
59 | 62 | // combine header fields with the same name
|
60 | 63 | // https://datatracker.ietf.org/doc/html/rfc7230#section-3.2
|
61 | 64 | else{
|
62 | 65 |
|
63 |
| - // the key is named, so we assume $val holds the header values only, either as string or array |
64 |
| - if(is_array($val)){ |
65 |
| - $val = implode(', ', array_values($val)); |
| 66 | + if(!is_array($val)){ |
| 67 | + $val = [$val]; |
66 | 68 | }
|
67 | 69 |
|
68 |
| - $val = trim((string)($val ?? '')); |
| 70 | + /** @noinspection PhpParamsInspection */ |
| 71 | + $val = implode(', ', array_values(self::trimValues($val))); |
69 | 72 |
|
70 | 73 | // skip if the header already exists but the current value is empty
|
71 |
| - if(isset($normalized[$key]) && empty($val)){ |
| 74 | + if(isset($normalized[$key]) && $val === ''){ |
72 | 75 | continue;
|
73 | 76 | }
|
74 | 77 |
|
@@ -117,25 +120,33 @@ protected static function normalizeKV(mixed $value):array{
|
117 | 120 | * OWS = *( SP / HTAB )
|
118 | 121 | *
|
119 | 122 | * @see https://tools.ietf.org/html/rfc7230#section-3.2.4
|
| 123 | + * @see https://github.com/advisories/GHSA-wxmh-65f7-jcvw |
120 | 124 | */
|
121 | 125 | public static function trimValues(iterable $values):iterable{
|
122 | 126 |
|
123 | 127 | foreach($values as &$value){
|
124 |
| - $value = trim((string)($value ?? ''), " \t"); |
| 128 | + |
| 129 | + if(!is_scalar($value) && $value !== null){ |
| 130 | + throw new InvalidArgumentException('value is expected to be scalar or null'); |
| 131 | + } |
| 132 | + |
| 133 | + $value = trim(str_replace(["\r", "\n"], '', (string)($value ?? ''))); |
125 | 134 | }
|
126 | 135 |
|
127 | 136 | return $values;
|
128 | 137 | }
|
129 | 138 |
|
130 | 139 | /**
|
131 | 140 | * Normalizes a header name, e.g. "con TENT- lenGTh" -> "Content-Length"
|
| 141 | + * |
| 142 | + * @see https://github.com/advisories/GHSA-wxmh-65f7-jcvw |
132 | 143 | */
|
133 | 144 | public static function normalizeHeaderName(string $name):string{
|
134 |
| - $parts = explode('-', $name); |
| 145 | + // we'll remove any spaces as well as CRLF in the name, e.g. "con tent" -> "content" |
| 146 | + $parts = explode('-', str_replace([' ', "\r", "\n"], '', $name)); |
135 | 147 |
|
136 | 148 | foreach($parts as &$part){
|
137 |
| - // we'll remove any spaces in the name part, e.g. "con tent" -> "content" |
138 |
| - $part = ucfirst(strtolower(str_replace(' ', '', trim($part)))); |
| 149 | + $part = ucfirst(strtolower(trim($part))); |
139 | 150 | }
|
140 | 151 |
|
141 | 152 | return implode('-', $parts);
|
|
0 commit comments