Skip to content

Commit 1e3472b

Browse files
committed
api: Delete io.grpc.Uri#getQuery and Builder#setQuery
1 parent b38df6c commit 1e3472b

2 files changed

Lines changed: 61 additions & 45 deletions

File tree

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

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -546,24 +546,18 @@ public String getRawPath() {
546546
return path;
547547
}
548548

549-
/**
550-
* Returns the percent-decoded "query" component of this URI, or null if not present.
551-
*
552-
* <p>NB: This method assumes the query was encoded as UTF-8, although RFC 3986 doesn't specify an
553-
* encoding.
554-
*
555-
* <p>Decoding errors are indicated by a {@code '\u005CuFFFD'} unicode replacement character in
556-
* the output. Callers who want to detect and handle errors in some other way should call {@link
557-
* #getRawQuery()}, {@link #percentDecode(CharSequence)}, then decode the bytes for themselves.
558-
*/
559-
@Nullable
560-
public String getQuery() {
561-
return percentDecodeAssumedUtf8(query);
562-
}
563-
564549
/**
565550
* Returns the query component of this URI in its originally parsed, possibly percent-encoded
566-
* form, without any leading '?' character.
551+
* form, without any leading '?' character, or null if not present.
552+
*
553+
* <p>The query component can only be read in its raw form. That’s because virtually everyone uses
554+
* query as a container for structured data, with some additional layer of encoding not present in
555+
* RFC-3986. Like 'application/x-www-form-urlencoded', which encodes key/value pairs like so:
556+
* <code>?k1=v1&k2=v+2</code>. The encoding of these containers always has characters that take on
557+
* a special delimiter meaning when not percent-encoded and a literal meaning when they are (like
558+
* '&', '=' and '+' above). Since it matters whether a character was percent encoded or not,
559+
* offering a '#getQuery()' method that percent-decodes everything like we do for other components
560+
* would be error-prone.
567561
*/
568562
@Nullable
569563
public String getRawQuery() {
@@ -776,25 +770,31 @@ public Builder setRawPath(String path) {
776770
}
777771

778772
/**
779-
* Specifies the query component of the new URI (not including the leading '?').
773+
* Specifies the query component of the new URI, possibly percent-encoded, exactly as it will
774+
* appear in the string form of the built URI.
780775
*
781-
* <p>Query can contain any string of codepoints. Codepoints that can't be encoded literally
782-
* will be percent-encoded for you as UTF-8.
776+
* <p>'query' must only contain codepoints from RFC 3986's "query" character class. Any other
777+
* characters must be percent-encoded using UTF-8. Do not include the leading '?' delimiter.
778+
*
779+
* <p>The query component can only be provided in its raw form. That’s because virtually
780+
* everyone uses query as a container for structured data, with some additional layer of
781+
* encoding not present in RFC-3986. Like 'application/x-www-form-urlencoded', which encodes
782+
* key/ value pairs like so: <code>?k1=v1&k2=v+2</code>. The encoding of these containers always
783+
* has characters that take on a special delimiter meaning when not percent-encoded and a
784+
* literal meaning when they are (like '&', '=' and '+' above). Since 'query' must have already
785+
* been carefully percent-encoded externally, a '#setQuery(String)' method that percent-encodes
786+
* an assumed-cooked string would be error-prone.
783787
*
784788
* <p>This field is optional.
785789
*
786790
* @param query the new query component, or null to clear this field
787791
* @return this, for fluent building
788792
*/
789793
@CanIgnoreReturnValue
790-
public Builder setQuery(@Nullable String query) {
791-
this.query = percentEncode(query, queryChars);
792-
return this;
793-
}
794-
795-
@CanIgnoreReturnValue
796-
Builder setRawQuery(String query) {
797-
checkPercentEncodedArg(query, "query", queryChars);
794+
public Builder setRawQuery(@Nullable String query) {
795+
if (query != null) {
796+
checkPercentEncodedArg(query, "query", queryChars);
797+
}
798798
this.query = query;
799799
return this;
800800
}

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

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public void parse_allComponents() throws URISyntaxException {
4242
assertThat(uri.getPort()).isEqualTo(443);
4343
assertThat(uri.getRawPort()).isEqualTo("0443");
4444
assertThat(uri.getPath()).isEqualTo("/path");
45-
assertThat(uri.getQuery()).isEqualTo("query");
45+
assertThat(uri.getRawQuery()).isEqualTo("query");
4646
assertThat(uri.getFragment()).isEqualTo("fragment");
4747
assertThat(uri.toString()).isEqualTo("scheme://user@host:0443/path?query#fragment");
4848
assertThat(uri.isAbsolute()).isFalse(); // Has a fragment.
@@ -56,7 +56,7 @@ public void parse_noAuthority() throws URISyntaxException {
5656
assertThat(uri.getScheme()).isEqualTo("scheme");
5757
assertThat(uri.getAuthority()).isNull();
5858
assertThat(uri.getPath()).isEqualTo("/path");
59-
assertThat(uri.getQuery()).isEqualTo("query");
59+
assertThat(uri.getRawQuery()).isEqualTo("query");
6060
assertThat(uri.getFragment()).isEqualTo("fragment");
6161
assertThat(uri.toString()).isEqualTo("scheme:/path?query#fragment");
6262
assertThat(uri.isAbsolute()).isFalse(); // Has a fragment.
@@ -102,7 +102,7 @@ public void parse_noQuery() throws URISyntaxException {
102102
assertThat(uri.getScheme()).isEqualTo("scheme");
103103
assertThat(uri.getAuthority()).isEqualTo("authority");
104104
assertThat(uri.getPath()).isEqualTo("/path");
105-
assertThat(uri.getQuery()).isNull();
105+
assertThat(uri.getRawQuery()).isNull();
106106
assertThat(uri.getFragment()).isEqualTo("fragment");
107107
assertThat(uri.toString()).isEqualTo("scheme://authority/path#fragment");
108108
}
@@ -113,7 +113,7 @@ public void parse_noFragment() throws URISyntaxException {
113113
assertThat(uri.getScheme()).isEqualTo("scheme");
114114
assertThat(uri.getAuthority()).isEqualTo("authority");
115115
assertThat(uri.getPath()).isEqualTo("/path");
116-
assertThat(uri.getQuery()).isEqualTo("query");
116+
assertThat(uri.getRawQuery()).isEqualTo("query");
117117
assertThat(uri.getFragment()).isNull();
118118
assertThat(uri.toString()).isEqualTo("scheme://authority/path?query");
119119
assertThat(uri.isAbsolute()).isTrue();
@@ -125,7 +125,7 @@ public void parse_emptyPathWithAuthority() throws URISyntaxException {
125125
assertThat(uri.getScheme()).isEqualTo("scheme");
126126
assertThat(uri.getAuthority()).isEqualTo("authority");
127127
assertThat(uri.getPath()).isEmpty();
128-
assertThat(uri.getQuery()).isNull();
128+
assertThat(uri.getRawQuery()).isNull();
129129
assertThat(uri.getFragment()).isNull();
130130
assertThat(uri.toString()).isEqualTo("scheme://authority");
131131
assertThat(uri.isAbsolute()).isTrue();
@@ -139,7 +139,7 @@ public void parse_rootless() throws URISyntaxException {
139139
assertThat(uri.getScheme()).isEqualTo("mailto");
140140
assertThat(uri.getAuthority()).isNull();
141141
assertThat(uri.getPath()).isEqualTo("[email protected]");
142-
assertThat(uri.getQuery()).isEqualTo("subject=raise");
142+
assertThat(uri.getRawQuery()).isEqualTo("subject=raise");
143143
assertThat(uri.getFragment()).isNull();
144144
assertThat(uri.toString()).isEqualTo("mailto:[email protected]?subject=raise");
145145
assertThat(uri.isAbsolute()).isTrue();
@@ -153,7 +153,7 @@ public void parse_emptyPath() throws URISyntaxException {
153153
assertThat(uri.getScheme()).isEqualTo("scheme");
154154
assertThat(uri.getAuthority()).isNull();
155155
assertThat(uri.getPath()).isEmpty();
156-
assertThat(uri.getQuery()).isNull();
156+
assertThat(uri.getRawQuery()).isNull();
157157
assertThat(uri.getFragment()).isNull();
158158
assertThat(uri.toString()).isEqualTo("scheme:");
159159
assertThat(uri.isAbsolute()).isTrue();
@@ -165,7 +165,7 @@ public void parse_emptyPath() throws URISyntaxException {
165165
public void parse_emptyQuery() {
166166
Uri uri = Uri.create("scheme:?");
167167
assertThat(uri.getScheme()).isEqualTo("scheme");
168-
assertThat(uri.getQuery()).isEmpty();
168+
assertThat(uri.getRawQuery()).isEmpty();
169169
}
170170

171171
@Test
@@ -322,7 +322,6 @@ public void parse_decoding() throws URISyntaxException {
322322
assertThat(uri.getPort()).isEqualTo(1234);
323323
assertThat(uri.getPath()).isEqualTo("/p ath");
324324
assertThat(uri.getRawPath()).isEqualTo("/p%20ath");
325-
assertThat(uri.getQuery()).isEqualTo("q uery");
326325
assertThat(uri.getRawQuery()).isEqualTo("q%20uery");
327326
assertThat(uri.getFragment()).isEqualTo("f ragment");
328327
assertThat(uri.getRawFragment()).isEqualTo("f%20ragment");
@@ -336,9 +335,8 @@ public void parse_decodingNonAscii() throws URISyntaxException {
336335

337336
@Test
338337
public void parse_decodingPercent() throws URISyntaxException {
339-
Uri uri = Uri.parse("s://a/p%2520ath?q%25uery#f%25ragment");
338+
Uri uri = Uri.parse("s://a/p%2520ath#f%25ragment");
340339
assertThat(uri.getPath()).isEqualTo("/p%20ath");
341-
assertThat(uri.getQuery()).isEqualTo("q%uery");
342340
assertThat(uri.getFragment()).isEqualTo("f%ragment");
343341
}
344342

@@ -420,7 +418,7 @@ public void toString_percentEncoding() throws URISyntaxException {
420418
.setScheme("s")
421419
.setHost("a b")
422420
.setPath("/p ath")
423-
.setQuery("q uery")
421+
.setRawQuery("q%20uery")
424422
.setFragment("f ragment")
425423
.build();
426424
assertThat(uri.toString()).isEqualTo("s://a%20b/p%20ath?q%20uery#f%20ragment");
@@ -440,7 +438,6 @@ public void parse_transparentRoundTrip_ipLiteral() {
440438
assertThat(uri.getRawPath()).isEqualTo("/%4a%4B%2f%2F");
441439
assertThat(uri.getPathSegments()).containsExactly("JK//");
442440
assertThat(uri.getRawQuery()).isEqualTo("%4c%4D");
443-
assertThat(uri.getQuery()).isEqualTo("LM");
444441
assertThat(uri.getRawFragment()).isEqualTo("%4e%4F");
445442
assertThat(uri.getFragment()).isEqualTo("NO");
446443
}
@@ -459,7 +456,6 @@ public void parse_transparentRoundTrip_regName() {
459456
assertThat(uri.getRawPath()).isEqualTo("/%4a%4B%2f%2F");
460457
assertThat(uri.getPathSegments()).containsExactly("JK//");
461458
assertThat(uri.getRawQuery()).isEqualTo("%4c%4D");
462-
assertThat(uri.getQuery()).isEqualTo("LM");
463459
assertThat(uri.getRawFragment()).isEqualTo("%4e%4F");
464460
assertThat(uri.getFragment()).isEqualTo("NO");
465461
}
@@ -529,7 +525,7 @@ public void builder_encodingWithAllowedReservedChars() throws URISyntaxException
529525
.setUserInfo("u@")
530526
.setHost("a[]")
531527
.setPath("/p:/@")
532-
.setQuery("q/?")
528+
.setRawQuery("q/?")
533529
.setFragment("f/?")
534530
.build();
535531
assertThat(uri.toString()).isEqualTo("s://u%40@a%5B%5D/p:/@?q/?#f/?");
@@ -600,7 +596,7 @@ public void builder_normalizesCaseWhereAppropriate() {
600596
.setScheme("hTtP") // #section-3.1 says producers (Builder) should normalize to lower.
601597
.setHost("aBc") // #section-3.2.2 says producers (Builder) should normalize to lower.
602598
.setPath("/CdE") // #section-6.2.2.1 says the rest are assumed to be case-sensitive
603-
.setQuery("fGh")
599+
.setRawQuery("fGh")
604600
.setFragment("IjK")
605601
.build();
606602
assertThat(uri.toString()).isEqualTo("http://abc/CdE?fGh#IjK");
@@ -621,12 +617,32 @@ public void builder_canClearAllOptionalFields() {
621617
.setPath("")
622618
.setUserInfo(null)
623619
.setPort(-1)
624-
.setQuery(null)
620+
.setRawQuery(null)
625621
.setFragment(null)
626622
.build();
627623
assertThat(uri.toString()).isEqualTo("http:");
628624
}
629625

626+
@Test
627+
public void builder_setRawQuery() {
628+
Uri uri = Uri.newBuilder().setScheme("http").setHost("host").setRawQuery("%61=b&c=%64").build();
629+
assertThat(uri.getRawQuery()).isEqualTo("%61=b&c=%64");
630+
assertThat(uri.toString()).isEqualTo("http://host?%61=b&c=%64");
631+
}
632+
633+
@Test
634+
public void builder_setRawQuery_null() {
635+
Uri uri =
636+
Uri.newBuilder()
637+
.setScheme("http")
638+
.setHost("host")
639+
.setRawQuery("a=b")
640+
.setRawQuery(null)
641+
.build();
642+
assertThat(uri.getRawQuery()).isNull();
643+
assertThat(uri.toString()).isEqualTo("http://host");
644+
}
645+
630646
@Test
631647
public void builder_canClearAuthorityComponents() {
632648
Uri uri = Uri.create("s://user@host:80/path").toBuilder().setRawAuthority(null).build();
@@ -692,7 +708,7 @@ public void toString_percentEncodingLiteralPercent() throws URISyntaxException {
692708
.setScheme("s")
693709
.setHost("a")
694710
.setPath("/p%20ath")
695-
.setQuery("q%uery")
711+
.setRawQuery("q%25uery")
696712
.setFragment("f%ragment")
697713
.build();
698714
assertThat(uri.toString()).isEqualTo("s://a/p%2520ath?q%25uery#f%25ragment");

0 commit comments

Comments
 (0)