@@ -30,58 +30,49 @@ public static function normalize(iterable $headers):array{
30
30
31
31
foreach ($ headers as $ key => $ val ){
32
32
33
- // the key is numeric, so $val is either a string or an array
33
+ // the key is numeric, so $val is either a string or an array that contains both
34
34
if (is_numeric ($ key )){
35
- // "key: val"
36
- if (is_string ($ val )){
37
- $ header = explode (': ' , $ val , 2 );
35
+ [$ key , $ val ] = self ::normalizeKV ($ val );
38
36
39
- if (count ($ header ) !== 2 ){
40
- continue ;
41
- }
42
-
43
- $ key = $ header [0 ];
44
- $ val = $ header [1 ];
37
+ if ($ key === null ){
38
+ continue ;
45
39
}
46
- // [$key, $val], ["key" => $key, "val" => $val]
47
- elseif (is_array ($ val ) && !empty ($ val )){
48
- $ key = array_keys ($ val )[0 ];
49
- $ val = array_values ($ val )[0 ];
50
-
51
- // skip if the key is numeric
52
- if (is_numeric ($ key )){
53
- continue ;
40
+ }
41
+
42
+ $ key = self ::normalizeHeaderName ($ key );
43
+
44
+ // cookie headers may appear multiple times - we'll just collect the last value here
45
+ // https://datatracker.ietf.org/doc/html/rfc6265#section-5.2
46
+ if ($ key === 'Set-Cookie ' ){
47
+ $ name = fn (string $ v ):string => trim (strtolower (explode ('= ' , $ v , 2 )[0 ]));
48
+
49
+ // array received from Message::getHeaders()
50
+ if (is_array ($ val )){
51
+ foreach ($ val as $ line ){
52
+ $ normalized [$ key ][$ name ($ line )] = trim ($ line );
54
53
}
55
54
}
56
55
else {
57
- continue ;
56
+ $ normalized [ $ key ][ $ name ( $ val )] = trim ( $ val ) ;
58
57
}
59
58
}
60
- // the key is named, so we assume $val holds the header values only, either as string or array
59
+ // combine header fields with the same name
60
+ // https://datatracker.ietf.org/doc/html/rfc7230#section-3.2
61
61
else {
62
+
63
+ // the key is named, so we assume $val holds the header values only, either as string or array
62
64
if (is_array ($ val )){
63
65
$ val = implode (', ' , array_values ($ val ));
64
66
}
65
- }
66
67
67
- $ key = self ::normalizeHeaderName ($ key );
68
- $ val = trim ((string )($ val ?? '' ));
68
+ $ val = trim ((string )($ val ?? '' ));
69
69
70
- // skip if the header already exists but the current value is empty
71
- if (isset ($ normalized [$ key ]) && empty ($ val )){
72
- continue ;
73
- }
70
+ // skip if the header already exists but the current value is empty
71
+ if (isset ($ normalized [$ key ]) && empty ($ val )){
72
+ continue ;
73
+ }
74
74
75
- // cookie headers may appear multiple times
76
- // https://tools.ietf.org/html/rfc6265#section-4.1.2
77
- if ($ key === 'Set-Cookie ' ){
78
- // we'll just collect the last value here and leave parsing up to you :P
79
- $ normalized [$ key ][strtolower (explode ('= ' , $ val , 2 )[0 ])] = $ val ;
80
- }
81
- // combine header fields with the same name
82
- // https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
83
- else {
84
- isset ($ normalized [$ key ]) && !empty ($ normalized [$ key ])
75
+ !empty ($ normalized [$ key ])
85
76
? $ normalized [$ key ] .= ', ' .$ val
86
77
: $ normalized [$ key ] = $ val ;
87
78
}
@@ -90,6 +81,33 @@ public static function normalize(iterable $headers):array{
90
81
return $ normalized ;
91
82
}
92
83
84
+ /**
85
+ * Extracts a key:value pair from the given value and returns it as 2-element array.
86
+ * If the key cannot be parsed, both array values will be `null`.
87
+ */
88
+ protected static function normalizeKV (mixed $ value ):array {
89
+
90
+ // "key: val"
91
+ if (is_string ($ value )){
92
+ $ kv = explode (': ' , $ value , 2 );
93
+
94
+ if (count ($ kv ) === 2 ){
95
+ return $ kv ;
96
+ }
97
+ }
98
+ // [$key, $val], ["key" => $key, "val" => $val]
99
+ elseif (is_array ($ value ) && !empty ($ value )){
100
+ $ key = array_keys ($ value )[0 ];
101
+ $ val = array_values ($ value )[0 ];
102
+
103
+ if (is_string ($ key )){
104
+ return [$ key , $ val ];
105
+ }
106
+ }
107
+
108
+ return [null , null ];
109
+ }
110
+
93
111
/**
94
112
* Trims whitespace from the header values.
95
113
*
0 commit comments