Skip to content

Commit 9fcffed

Browse files
committed
api: Add io.grpc.Uri.Builder#setRawAuthority
1 parent 78566ff commit 9fcffed

File tree

2 files changed

+93
-17
lines changed

2 files changed

+93
-17
lines changed

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

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -245,23 +245,7 @@ public static Uri create(String s) {
245245
break;
246246
}
247247
}
248-
String authority = s.substring(authorityStart, i);
249-
250-
// 3.2.1. UserInfo. Easy, because '@' cannot appear unencoded inside userinfo or host.
251-
int userInfoEnd = authority.indexOf('@');
252-
if (userInfoEnd >= 0) {
253-
builder.setRawUserInfo(authority.substring(0, userInfoEnd));
254-
}
255-
256-
// 3.2.2/3. Host/Port.
257-
int hostStart = userInfoEnd >= 0 ? userInfoEnd + 1 : 0;
258-
int portStartColon = findPortStartColon(authority, hostStart);
259-
if (portStartColon < 0) {
260-
builder.setRawHost(authority.substring(hostStart));
261-
} else {
262-
builder.setRawHost(authority.substring(hostStart, portStartColon));
263-
builder.setRawPort(authority.substring(portStartColon + 1));
264-
}
248+
builder.setRawAuthority(s.substring(authorityStart, i));
265249
}
266250

267251
// 3.3. Path: Whatever is left before '?' or '#'.
@@ -963,6 +947,51 @@ Builder setRawPort(String port) {
963947
return this;
964948
}
965949

950+
/**
951+
* Specifies the userinfo, host and port URI components all at once using a single string.
952+
*
953+
* <p>This setter is "raw" in the sense that special characters in userinfo and host must be
954+
* passed in percent-encoded. See <a
955+
* href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2">RFC 3986 3.2</a> for the set
956+
* of characters allowed in each component of an authority.
957+
*
958+
* <p>There's no "cooked" method to set authority like for other URI components because
959+
* authority is a *compound* URI component whose userinfo, host and port components are
960+
* delimited with special characters '@' and ':'. But the first two of those components can
961+
* themselves contain these delimiters so we need percent-encoding to parse them unambiguously.
962+
*
963+
* @param authority an RFC 3986 authority string that will be used to set userinfo, host and
964+
* port, or null to clear all three of those components
965+
*/
966+
@CanIgnoreReturnValue
967+
public Builder setRawAuthority(@Nullable String authority) {
968+
if (authority == null) {
969+
setUserInfo(null);
970+
setHost((String) null);
971+
setPort(-1);
972+
} else {
973+
// UserInfo. Easy because '@' cannot appear unencoded inside userinfo or host.
974+
int userInfoEnd = authority.indexOf('@');
975+
if (userInfoEnd >= 0) {
976+
setRawUserInfo(authority.substring(0, userInfoEnd));
977+
} else {
978+
setUserInfo(null);
979+
}
980+
981+
// Host/Port.
982+
int hostStart = userInfoEnd >= 0 ? userInfoEnd + 1 : 0;
983+
int portStartColon = findPortStartColon(authority, hostStart);
984+
if (portStartColon < 0) {
985+
setRawHost(authority.substring(hostStart));
986+
setPort(-1);
987+
} else {
988+
setRawHost(authority.substring(hostStart, portStartColon));
989+
setRawPort(authority.substring(portStartColon + 1));
990+
}
991+
}
992+
return this;
993+
}
994+
966995
/** Builds a new instance of {@link Uri} as specified by the setters. */
967996
public Uri build() {
968997
checkState(scheme != null, "Missing required scheme.");

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

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,53 @@ public void builder_canClearAllOptionalFields() {
627627
assertThat(uri.toString()).isEqualTo("http:");
628628
}
629629

630+
@Test
631+
public void builder_canClearAuthorityComponents() {
632+
Uri uri = Uri.create("s://user@host:80/path").toBuilder().setRawAuthority(null).build();
633+
assertThat(uri.toString()).isEqualTo("s:/path");
634+
}
635+
636+
@Test
637+
public void builder_canSetEmptyAuthority() {
638+
Uri uri = Uri.create("s://user@host:80/path").toBuilder().setRawAuthority("").build();
639+
assertThat(uri.toString()).isEqualTo("s:///path");
640+
}
641+
642+
@Test
643+
public void builder_canSetRawAuthority() {
644+
Uri uri = Uri.newBuilder().setScheme("http").setRawAuthority("user@host:1234").build();
645+
assertThat(uri.getUserInfo()).isEqualTo("user");
646+
assertThat(uri.getHost()).isEqualTo("host");
647+
assertThat(uri.getPort()).isEqualTo(1234);
648+
}
649+
650+
@Test
651+
public void builder_setRawAuthorityPercentDecodes() {
652+
Uri uri =
653+
Uri.newBuilder()
654+
.setScheme("http")
655+
.setRawAuthority("user:user%40user@host%40host%3Ahost")
656+
.build();
657+
assertThat(uri.getUserInfo()).isEqualTo("user:user@user");
658+
assertThat(uri.getHost()).isEqualTo("host@host:host");
659+
assertThat(uri.getPort()).isEqualTo(-1);
660+
}
661+
662+
@Test
663+
public void builder_setRawAuthorityReplacesAllComponents() {
664+
Uri uri =
665+
Uri.newBuilder()
666+
.setScheme("http")
667+
.setUserInfo("user")
668+
.setHost("host")
669+
.setPort(1234)
670+
.setRawAuthority("other")
671+
.build();
672+
assertThat(uri.getUserInfo()).isNull();
673+
assertThat(uri.getHost()).isEqualTo("other");
674+
assertThat(uri.getPort()).isEqualTo(-1);
675+
}
676+
630677
@Test
631678
public void toString_percentEncodingMultiChar() throws URISyntaxException {
632679
Uri uri =

0 commit comments

Comments
 (0)