Skip to content

Commit d6fcad9

Browse files
committed
Add logging to RfcUriParser
See gh-33639
1 parent ef0a21e commit d6fcad9

File tree

1 file changed

+83
-54
lines changed

1 file changed

+83
-54
lines changed

spring-web/src/main/java/org/springframework/web/util/RfcUriParser.java

+83-54
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@
1818

1919
import java.util.Set;
2020

21-
import org.springframework.lang.Contract;
21+
import org.apache.commons.logging.Log;
22+
23+
import org.springframework.core.log.LogDelegateFactory;
2224
import org.springframework.lang.Nullable;
2325
import org.springframework.util.Assert;
2426

2527
/**
26-
* Parser for URI's based on the syntax in RFC 3986.
28+
* Parser for URI's based on RFC 3986 syntax.
2729
*
2830
* @author Rossen Stoyanchev
2931
* @since 6.2
@@ -32,6 +34,8 @@
3234
*/
3335
abstract class RfcUriParser {
3436

37+
private static final Log logger = LogDelegateFactory.getHiddenLog(RfcUriParser.class);
38+
3539

3640
/**
3741
* Parse the given URI string.
@@ -44,19 +48,20 @@ public static UriRecord parse(String uri) {
4448
}
4549

4650

47-
@Contract("false, _ -> fail")
48-
private static void verify(boolean expression, String message) {
51+
private static void verify(boolean expression, InternalParser parser, String message) {
4952
if (!expression) {
50-
fail(message);
53+
fail(parser, message);
5154
}
5255
}
5356

54-
public static void verifyIsHexDigit(char c, String message) {
55-
verify((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || (c >= '0' && c <= '9'), message);
57+
private static void verifyIsHexDigit(char c, InternalParser parser, String message) {
58+
verify((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || (c >= '0' && c <= '9'), parser, message);
5659
}
5760

58-
@Contract("_ -> fail")
59-
private static void fail(String message) {
61+
private static void fail(InternalParser parser, String message) {
62+
if (logger.isTraceEnabled()) {
63+
logger.trace(InvalidUrlException.class.getSimpleName() + ": \"" + message + "\" " + parser);
64+
}
6065
throw new InvalidUrlException(message);
6166
}
6267

@@ -202,7 +207,7 @@ public void handleNext(InternalParser parser, char c, int i) {
202207
parser.captureUser().componentIndex(i + 1);
203208
break;
204209
case '[':
205-
verify(parser.isAtStartOfComponent(), "Bad authority");
210+
verify(parser.isAtStartOfComponent(), parser, "Bad authority");
206211
parser.advanceTo(IPV6);
207212
break;
208213
case '%':
@@ -212,7 +217,7 @@ public void handleNext(InternalParser parser, char c, int i) {
212217
boolean isAllowed = (parser.processCurlyBrackets(c) ||
213218
parser.countDownPercentEncodingInHost(c) ||
214219
HierarchicalUriComponents.Type.URI.isUnreservedOrSubDelimiter(c));
215-
verify(isAllowed, "Bad authority");
220+
verify(isAllowed, parser, "Bad authority");
216221
}
217222
}
218223

@@ -242,13 +247,13 @@ public void handleNext(InternalParser parser, char c, int i) {
242247
case ':':
243248
break;
244249
default:
245-
verifyIsHexDigit(c, "Bad authority");
250+
verifyIsHexDigit(c, parser, "Bad authority");
246251
}
247252
}
248253

249254
@Override
250255
public void handleEnd(InternalParser parser) {
251-
verify(parser.hasHost(), "Bad authority"); // no closing ']'
256+
verify(parser.hasHost(), parser, "Bad authority"); // no closing ']'
252257
}
253258
},
254259

@@ -257,7 +262,7 @@ public void handleEnd(InternalParser parser) {
257262
@Override
258263
public void handleNext(InternalParser parser, char c, int i) {
259264
if (c == '@') {
260-
verify(!parser.hasUser(), "Bad authority");
265+
verify(!parser.hasUser(), parser, "Bad authority");
261266
parser.switchPortForFullPassword().advanceTo(HOST, i + 1);
262267
}
263268
else if (c == '/') {
@@ -274,7 +279,7 @@ else if (HierarchicalUriComponents.Type.URI.isUnreservedOrSubDelimiter(c) || c =
274279
parser.switchPortForPassword().advanceTo(HOST);
275280
return;
276281
}
277-
fail("Bad authority");
282+
fail(parser, "Bad authority");
278283
}
279284
}
280285

@@ -342,7 +347,7 @@ public void handleEnd(InternalParser parser) {
342347

343348
@Override
344349
public void handleNext(InternalParser parser, char c, int i) {
345-
fail("Bad character '*'");
350+
fail(parser, "Bad character '*'");
346351
}
347352

348353
@Override
@@ -422,31 +427,6 @@ public InternalParser(String uri) {
422427
this.uri = uri;
423428
}
424429

425-
/**
426-
* Parse the input string and return a {@link UriRecord} with the results.
427-
*/
428-
public UriRecord parse() {
429-
Assert.isTrue(this.state == State.START && this.index == 0, "Internal Error");
430-
431-
while (hasNext()) {
432-
this.state.handleNext(this, charAtIndex(), this.index);
433-
this.index++;
434-
}
435-
436-
this.state.handleEnd(this);
437-
438-
return new UriRecord(this.scheme, this.isOpaque,
439-
this.user, this.host, this.port, this.path, this.query, this.fragment);
440-
}
441-
442-
public boolean hasNext() {
443-
return (this.index < this.uri.length());
444-
}
445-
446-
public char charAtIndex() {
447-
return this.uri.charAt(this.index);
448-
}
449-
450430
// Check internal state
451431

452432
public boolean hasScheme() {
@@ -469,15 +449,43 @@ public boolean isAtStartOfComponent() {
469449
return (this.index == this.componentIndex);
470450
}
471451

452+
// Top-level parse loop, iterate over chars and delegate to states
453+
454+
public UriRecord parse() {
455+
Assert.isTrue(this.state == State.START && this.index == 0, "Internal Error");
456+
457+
while (hasNext()) {
458+
this.state.handleNext(this, charAtIndex(), this.index);
459+
this.index++;
460+
}
461+
462+
this.state.handleEnd(this);
463+
464+
return new UriRecord(this.scheme, this.isOpaque,
465+
this.user, this.host, this.port, this.path, this.query, this.fragment);
466+
}
467+
468+
public boolean hasNext() {
469+
return (this.index < this.uri.length());
470+
}
471+
472+
public char charAtIndex() {
473+
return this.uri.charAt(this.index);
474+
}
475+
472476
// Transitions and index updates
473477

474478
public void advanceTo(State state) {
479+
if (logger.isTraceEnabled()) {
480+
logger.trace(this.state + " -> " + state + ", " +
481+
"index=" + this.index + ", componentIndex=" + this.componentIndex);
482+
}
475483
this.state = state;
476484
}
477485

478486
public void advanceTo(State state, int componentIndex) {
479-
this.state = state;
480487
this.componentIndex = componentIndex;
488+
advanceTo(state);
481489
}
482490

483491
public InternalParser componentIndex(int componentIndex) {
@@ -498,19 +506,19 @@ public InternalParser resolveIfOpaque() {
498506
}
499507

500508
public InternalParser captureScheme() {
501-
this.scheme = captureComponent().toLowerCase();
509+
this.scheme = captureComponent("scheme").toLowerCase();
502510
return this;
503511
}
504512

505513
public InternalParser captureUser() {
506514
this.inPassword = false;
507-
this.user = captureComponent();
515+
this.user = captureComponent("user");
508516
return this;
509517
}
510518

511519
public InternalParser captureHost() {
512-
verify(this.remainingPercentEncodedChars == 0 && !this.inPassword, "Bad authority");
513-
this.host = captureComponent();
520+
verify(this.remainingPercentEncodedChars == 0 && !this.inPassword, this, "Bad authority");
521+
this.host = captureComponent("host");
514522
return this;
515523
}
516524

@@ -522,29 +530,32 @@ public InternalParser captureHostIfNotEmpty() {
522530
}
523531

524532
public InternalParser capturePort() {
525-
verify(this.openCurlyBracketCount == 0, "Bad authority");
526-
this.port = captureComponent();
533+
verify(this.openCurlyBracketCount == 0, this, "Bad authority");
534+
this.port = captureComponent("port");
527535
return this;
528536
}
529537

530538
public InternalParser capturePath() {
531-
this.path = captureComponent();
539+
this.path = captureComponent("path");
532540
return this;
533541
}
534542

535543
public InternalParser captureQuery() {
536-
this.query = captureComponent();
544+
this.query = captureComponent("query");
537545
return this;
538546
}
539547

540548
public void captureFragmentIfNotEmpty() {
541549
if (this.index > this.componentIndex + 1) {
542-
this.fragment = captureComponent();
550+
this.fragment = captureComponent("fragment");
543551
}
544552
}
545553

546554
public InternalParser switchPortForFullPassword() {
547555
this.user = this.host + ":" + captureComponent();
556+
if (logger.isTraceEnabled()) {
557+
logger.trace("Switching from host/port to user=" + this.user);
558+
}
548559
return this;
549560
}
550561

@@ -553,16 +564,27 @@ public InternalParser switchPortForPassword() {
553564
if (this.host != null) {
554565
this.componentIndex = (this.componentIndex - this.host.length() - 1);
555566
this.host = null;
567+
if (logger.isTraceEnabled()) {
568+
logger.trace("Switching from host/port to username/password");
569+
}
556570
}
557571
return this;
558572
}
559573

574+
private String captureComponent(String logPrefix) {
575+
String value = captureComponent();
576+
if (logger.isTraceEnabled()) {
577+
logger.trace(logPrefix + " set to '" + value + "'");
578+
}
579+
return value;
580+
}
581+
560582
private String captureComponent() {
561583
return this.uri.substring(this.componentIndex, this.index);
562584
}
563585

564586
public InternalParser markPercentEncoding() {
565-
verify(this.remainingPercentEncodedChars == 0, "Bad encoding");
587+
verify(this.remainingPercentEncodedChars == 0, this, "Bad encoding");
566588
this.remainingPercentEncodedChars = 2;
567589
this.inUtf16Sequence = false;
568590
return this;
@@ -578,7 +600,7 @@ public boolean countDownPercentEncodingInHost(char c) {
578600
return false;
579601
}
580602
this.remainingPercentEncodedChars--;
581-
verifyIsHexDigit(c, "Bad authority");
603+
verifyIsHexDigit(c, this, "Bad authority");
582604
return true;
583605
}
584606

@@ -595,7 +617,7 @@ public boolean countDownPercentEncodingInPath(char c) {
595617
return true;
596618
}
597619
this.remainingPercentEncodedChars--;
598-
verifyIsHexDigit(c, "Bad path");
620+
verifyIsHexDigit(c, this, "Bad path");
599621
this.inUtf16Sequence &= (this.remainingPercentEncodedChars > 0);
600622
return true;
601623
}
@@ -615,6 +637,13 @@ else if (c == '}') {
615637
return (this.openCurlyBracketCount > 0);
616638
}
617639

640+
@Override
641+
public String toString() {
642+
return "[State=" + this.state + ", index=" + this.index + ", componentIndex=" + this.componentIndex +
643+
", uri='" + this.uri + "', scheme='" + this.scheme + "', user='" + this.user +
644+
"', host='" + this.host + "', path='" + this.path + "', port='" + this.port +
645+
"', query='" + this.query + "', fragment='" + this.fragment + "']";
646+
}
618647
}
619648

620649
}

0 commit comments

Comments
 (0)