|
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