1313namespace Koded \Http ;
1414
1515/**
16- *
17- *
1816 * Content negotiation module.
1917 *
20- * Supported access headers:
18+ * Supported HTTP/1.1 Accept headers:
2119 *
22- * Access
23- * Access -Language
24- * Access -Charset
25- * Access -Encoding
20+ * Accept
21+ * Accept -Language
22+ * Accept -Charset
23+ * Accept -Encoding
2624 *
2725 * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation
2826 */
@@ -59,7 +57,8 @@ public function match(string $accepts): AcceptHeader
5957 * The consuming clients should handle this according to
6058 * their internal logic. This is much better then throwing
6159 * exceptions which must be handled in every place where
62- * match() is called. The client may issue a 406 status code.
60+ * match() is called. For example, the client may issue a
61+ * 406 status code and be done with it.
6362 */
6463 $ types [] = new class ('*;q=0 ' ) extends AcceptHeader {};
6564 }
@@ -101,32 +100,34 @@ public function __construct(string $header)
101100 $ type = array_shift ($ bits );
102101
103102 if (!empty ($ type ) && !preg_match ('~^(\*|[a-z0-9._]+)([/|_-])?(\*|[a-z0-9.\-_+]+)?$~i ' , $ type , $ matches )) {
104- throw new InvalidArgumentException (sprintf ('"%s" is not a valid Access header ' , $ header ), StatusCode::NOT_ACCEPTABLE );
103+ throw new InvalidArgumentException (sprintf ('"%s" is not a valid Access header ' , $ header ),
104+ StatusCode::NOT_ACCEPTABLE );
105105 }
106106
107107 $ this ->separator = $ matches [2 ] ?? '/ ' ;
108108 [$ type , $ subtype ] = explode ($ this ->separator , $ type , 2 ) + [1 => '* ' ];
109109
110110 if ('* ' === $ type && '* ' !== $ subtype ) {
111111 // @see https://tools.ietf.org/html/rfc7231#section-5.3.2
112- throw new InvalidArgumentException (sprintf ('"%s" is not a valid Access header ' , $ header ), StatusCode::NOT_ACCEPTABLE );
112+ throw new InvalidArgumentException (sprintf ('"%s" is not a valid Access header ' , $ header ),
113+ StatusCode::NOT_ACCEPTABLE );
113114 }
114115
115116 // @see https://tools.ietf.org/html/rfc7540#section-8.1.2
116117 $ this ->type = strtolower ($ type );
117118
118119 /* Uses a simple heuristic to check if subtype is part of
119120 * some obscure media type like "vnd.api-v1+json".
121+ *
122+ * NOTE: It is a waste of time to negotiate on the basis
123+ * of obscure parameters while using a meaningless media
124+ * type like "vnd.whatever". But the web world is a big mess
125+ * and this module can handle the Dunning-Kruger effect.
120126 */
121127 $ this ->subtype = explode ('+ ' , $ subtype )[1 ] ?? $ subtype ;
122128 $ this ->catchAll = '* ' === $ this ->type && '* ' === $ this ->subtype ;
123129
124130 parse_str (join ('& ' , $ bits ), $ this ->params );
125- /* NOTE: It is a waste of time to negotiate on the basis
126- * of obscure parameters while using a meaningless media
127- * type like "vnd.whatever". But the IT world is a big
128- * mess for now and this module supports ignorant devs.
129- */
130131 $ this ->quality = (float )($ this ->params ['q ' ] ?? 1 );
131132 unset($ this ->params ['q ' ]);
132133 }
@@ -138,16 +139,10 @@ public function __toString(): string
138139 }
139140
140141
141- public function quality (): float
142- {
143- return $ this ->quality ;
144- }
145-
146-
147142 public function value (): string
148143 {
149144 // The header is explicitly rejected
150- if (0.0 === $ this ->quality () ) {
145+ if (0.0 === $ this ->quality ) {
151146 return '' ;
152147 }
153148
@@ -160,6 +155,12 @@ public function value(): string
160155 }
161156
162157
158+ public function quality (): float
159+ {
160+ return $ this ->quality ;
161+ }
162+
163+
163164 public function weight (): float
164165 {
165166 return $ this ->weight ;
@@ -168,15 +169,16 @@ public function weight(): float
168169 /**
169170 * @internal
170171 *
171- * This method finds the best match from the accept header,
172- * including all the stupidity that may be passed by the
173- * ignorant developers who do not follow RFC standards.
174- *
175172 * @param AcceptHeader $accept The accept header part
176173 * @param AcceptHeader[] $matches Matched types
177174 *
178175 * @return bool TRUE if the accept header part is a match
179176 * against the supported (this) header part
177+ *
178+ * This method finds the best match for the Accept header,
179+ * including all the nonsense that may be passed by the
180+ * developers who do not follow RFC standards.
181+ *
180182 */
181183 public function matches (AcceptHeader $ accept , array &$ matches = null ): bool
182184 {
@@ -193,18 +195,21 @@ public function matches(AcceptHeader $accept, array &$matches = null): bool
193195 $ accept ->type = $ this ->type ;
194196 $ accept ->subtype = $ this ->subtype ;
195197 $ matches [] = $ accept ;
198+
196199 return true ;
197200 }
198201
199202 // Explicitly denied
200203 if (0.0 === $ this ->quality ) {
201204 $ matches [] = clone $ this ;
205+
202206 return true ;
203207 }
204208
205209 // Explicitly denied
206210 if (0.0 === $ accept ->quality ) {
207211 $ matches [] = $ accept ;
212+
208213 return true ;
209214 }
210215
0 commit comments