Skip to content

Commit c62cdef

Browse files
committed
api: Make io.grpc.Uri's setRawFragment public with warnings
1 parent 7b0a7eb commit c62cdef

2 files changed

Lines changed: 67 additions & 2 deletions

File tree

api/src/main/java/io/grpc/Uri.java

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -821,6 +821,13 @@ public Builder setRawQuery(@Nullable String query) {
821821
* <p>The fragment can contain any string of codepoints. Codepoints that can't be encoded
822822
* literally will be percent-encoded for you as UTF-8.
823823
*
824+
* <p>NB: Choose carefully between this method and {@link #setRawFragment(String)}. Many URI
825+
* schemes embed further structure in the fragment that isn't part of the RFC 3986 generic
826+
* syntax. These schemes often use internal delimiters that must be carefully percent-encoded in
827+
* ways that this method doesn't understand. See {@link #getFragment()} for an example. In that
828+
* case, callers should percent-encode externally then call {@link #setRawFragment(String)}
829+
* instead.
830+
*
824831
* <p>This field is optional.
825832
*
826833
* @param fragment the new fragment component, or null to clear this field
@@ -832,9 +839,27 @@ public Builder setFragment(@Nullable String fragment) {
832839
return this;
833840
}
834841

842+
/**
843+
* Specifies the fragment component of the new URI, already percent-encoded, exactly as it will
844+
* appear after the '#' delimiter in the string form of the built URI.
845+
*
846+
* <p>NB: Choose carefully between this method and {@link #setFragment(String)}. {@code
847+
* fragment} must only contain codepoints from RFC 3986's "fragment" character class. Use
848+
* percent-encoding and UTF-8 to represent anything else. In certain cases, you can use {@link
849+
* #setFragment(String)} to have the fragment percent-encoded for you instead, but see that
850+
* method's Javadoc for its limitations.
851+
*
852+
* <p>This field is optional.
853+
*
854+
* @param fragment the new fragment component, or null to clear this field
855+
* @return this, for fluent building
856+
* @throws IllegalArgumentException if 'fragment' contains forbidden characters
857+
*/
835858
@CanIgnoreReturnValue
836-
Builder setRawFragment(String fragment) {
837-
checkPercentEncodedArg(fragment, "fragment", fragmentChars);
859+
public Builder setRawFragment(@Nullable String fragment) {
860+
if (fragment != null) {
861+
checkPercentEncodedArg(fragment, "fragment", fragmentChars);
862+
}
838863
this.fragment = fragment;
839864
return this;
840865
}

api/src/test/java/io/grpc/UriTest.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,46 @@ public void builder_setRawQuery_null() {
643643
assertThat(uri.toString()).isEqualTo("http://host");
644644
}
645645

646+
@Test
647+
public void builder_setRawFragment() {
648+
Uri uri = Uri.newBuilder().setScheme("http").setHost("host").setRawFragment("a%20b").build();
649+
assertThat(uri.getRawFragment()).isEqualTo("a%20b");
650+
assertThat(uri.getFragment()).isEqualTo("a b");
651+
assertThat(uri.toString()).isEqualTo("http://host#a%20b");
652+
}
653+
654+
@Test
655+
public void builder_setRawFragment_null() {
656+
Uri uri =
657+
Uri.newBuilder()
658+
.setScheme("http")
659+
.setHost("host")
660+
.setRawFragment("a%20b")
661+
.setRawFragment(null)
662+
.build();
663+
assertThat(uri.getRawFragment()).isNull();
664+
assertThat(uri.getFragment()).isNull();
665+
assertThat(uri.toString()).isEqualTo("http://host");
666+
}
667+
668+
@Test
669+
public void builder_setRawFragment_invalidCharacters_throws() {
670+
IllegalArgumentException e =
671+
assertThrows(
672+
IllegalArgumentException.class,
673+
() -> Uri.newBuilder().setRawFragment("f[]rag"));
674+
assertThat(e).hasMessageThat().contains("Invalid character in fragment");
675+
}
676+
677+
@Test
678+
public void builder_setRawFragment_invalidPercentEncoding_throws() {
679+
IllegalArgumentException e =
680+
assertThrows(
681+
IllegalArgumentException.class,
682+
() -> Uri.newBuilder().setRawFragment("f%XXragment"));
683+
assertThat(e).hasMessageThat().contains("Invalid");
684+
}
685+
646686
@Test
647687
public void builder_canClearAuthorityComponents() {
648688
Uri uri = Uri.create("s://user@host:80/path").toBuilder().setRawAuthority(null).build();

0 commit comments

Comments
 (0)