@@ -204,96 +204,105 @@ enum ForwardedParseState {
204204
205205 @ Override
206206 public InetAddress apply (String headerValue ) {
207- String [] entries = headerValue .split ("," );
208- for (int i = entries .length - 1 ; i >= 0 ; i --) {
209- String entry = entries [i ].trim ();
210- InetAddress resultPrivate = null ;
211- ForwardedParseState state = ForwardedParseState .BETWEEN ;
212- // https://datatracker.ietf.org/doc/html/rfc7239#section-4
213- int pos = 0 ;
214- int end = entry .length ();
215- // compiler requires that these two be initialized:
216- int start = 0 ;
217- boolean considerValue = false ;
218- while (pos < end ) {
219- char c = entry .charAt (pos );
220- switch (state ) {
221- case BETWEEN :
222- if (c == ' ' || c == ';' || c == ',' ) {
207+ int end = headerValue .length ();
208+ int entryEnd = end ;
209+ // Parse entries right-to-left, separated by ','
210+ for (int i = end - 1 ; i >= -1 ; i --) {
211+ if (i == -1 || headerValue .charAt (i ) == ',' ) {
212+ int entryStart = i + 1 ;
213+ // skip leading spaces
214+ while (entryStart < entryEnd && headerValue .charAt (entryStart ) == ' ' ) {
215+ entryStart ++;
216+ }
217+ String entry = headerValue .substring (entryStart , entryEnd );
218+ InetAddress resultPrivate = null ;
219+ ForwardedParseState state = ForwardedParseState .BETWEEN ;
220+ // https://datatracker.ietf.org/doc/html/rfc7239#section-4
221+ int pos = 0 ;
222+ int entryLen = entry .length ();
223+ // compiler requires that these two be initialized:
224+ int start = 0 ;
225+ boolean considerValue = false ;
226+ while (pos < entryLen ) {
227+ char c = entry .charAt (pos );
228+ switch (state ) {
229+ case BETWEEN :
230+ if (c == ' ' || c == ';' || c == ',' ) {
231+ break ;
232+ }
233+ start = pos ;
234+ state = ForwardedParseState .KEY ;
223235 break ;
224- }
225- start = pos ;
226- state = ForwardedParseState .KEY ;
227- break ;
228- case KEY :
229- if (c != '=' ) {
236+ case KEY :
237+ if (c != '=' ) {
238+ break ;
239+ }
240+ state = ForwardedParseState .BEFORE_VALUE ;
241+ if (pos - start == 3 ) {
242+ String key = entry .substring (start , pos );
243+ considerValue = key .equalsIgnoreCase ("for" );
244+ } else {
245+ considerValue = false ;
246+ }
230247 break ;
231- }
232-
233- state = ForwardedParseState .BEFORE_VALUE ;
234- if (pos - start == 3 ) {
235- String key = entry .substring (start , pos );
236- considerValue = key .equalsIgnoreCase ("for" );
237- } else {
238- considerValue = false ;
239- }
240- break ;
241- case BEFORE_VALUE :
242- if (c == '"' ) {
243- start = pos + 1 ;
244- state = ForwardedParseState .VALUE_QUOTED ;
245- } else if (c == ' ' || c == ';' || c == ',' ) {
246- // empty value
247- state = ForwardedParseState .BETWEEN ;
248- } else {
249- start = pos ;
250- state = ForwardedParseState .VALUE_TOKEN ;
251- }
252- break ;
253- case VALUE_TOKEN :
254- {
255- int tokenEnd ;
256- if (c == ' ' || c == ';' || c == ',' ) {
257- tokenEnd = pos ;
258- } else if (pos + 1 == end ) {
259- tokenEnd = end ;
248+ case BEFORE_VALUE :
249+ if (c == '"' ) {
250+ start = pos + 1 ;
251+ state = ForwardedParseState .VALUE_QUOTED ;
252+ } else if (c == ' ' || c == ';' || c == ',' ) {
253+ // empty value
254+ state = ForwardedParseState .BETWEEN ;
260255 } else {
261- break ;
256+ start = pos ;
257+ state = ForwardedParseState .VALUE_TOKEN ;
262258 }
263-
264- if (considerValue ) {
265- InetAddress ipAddr = parseIpAddressAndMaybePort (entry .substring (start , tokenEnd ));
266- if (ipAddr != null ) {
267- if (isIpAddrPrivate (ipAddr )) {
268- if (resultPrivate == null ) {
269- resultPrivate = ipAddr ;
259+ break ;
260+ case VALUE_TOKEN :
261+ {
262+ int tokenEnd ;
263+ if (c == ' ' || c == ';' || c == ',' ) {
264+ tokenEnd = pos ;
265+ } else if (pos + 1 == entryLen ) {
266+ tokenEnd = entryLen ;
267+ } else {
268+ break ;
269+ }
270+ if (considerValue ) {
271+ InetAddress ipAddr =
272+ parseIpAddressAndMaybePort (entry .substring (start , tokenEnd ));
273+ if (ipAddr != null ) {
274+ if (isIpAddrPrivate (ipAddr )) {
275+ if (resultPrivate == null ) {
276+ resultPrivate = ipAddr ;
277+ }
278+ } else {
279+ return ipAddr ;
270280 }
271- } else {
272- return ipAddr ;
273281 }
274282 }
283+ state = ForwardedParseState .BETWEEN ;
284+ break ;
275285 }
276- state = ForwardedParseState .BETWEEN ;
277- break ;
278- }
279- case VALUE_QUOTED :
280- if (c == '"' ) {
281- if (considerValue ) {
282- InetAddress ipAddr = parseIpAddressAndMaybePort (entry .substring (start , pos ));
283- if (ipAddr != null && !isIpAddrPrivate (ipAddr )) {
284- return ipAddr ;
286+ case VALUE_QUOTED :
287+ if (c == '"' ) {
288+ if (considerValue ) {
289+ InetAddress ipAddr = parseIpAddressAndMaybePort (entry .substring (start , pos ));
290+ if (ipAddr != null && !isIpAddrPrivate (ipAddr )) {
291+ return ipAddr ;
292+ }
285293 }
294+ state = ForwardedParseState .BETWEEN ;
295+ } else if (c == '\\' ) {
296+ pos ++;
286297 }
287- state = ForwardedParseState .BETWEEN ;
288- } else if (c == '\\' ) {
289- pos ++;
290- }
291- break ;
298+ break ;
299+ }
300+ pos ++;
292301 }
293- pos ++;
294- }
295- if ( resultPrivate != null ) {
296- return resultPrivate ;
302+ if ( resultPrivate != null ) {
303+ return resultPrivate ;
304+ }
305+ entryEnd = i ;
297306 }
298307 }
299308 return null ;
0 commit comments