Skip to content

Commit

Permalink
HTTPCORE-770: Introduced plusAsBlank parameter for dynamic configur…
Browse files Browse the repository at this point in the history
…ation

- Added `plusAsBlank` flag to `URIBuilder` to dynamically configure whether '+' should be interpreted as a space in query parameters.
- Implemented `setPlusAsBlank` method to update the flag and re-parse the query accordingly.
  • Loading branch information
arturobernalg committed Sep 15, 2024
1 parent 6da87d3 commit 1f20dd1
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 1 deletion.
31 changes: 30 additions & 1 deletion httpcore5/src/main/java/org/apache/hc/core5/net/URIBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ public static URIBuilder loopbackAddress() {
private String fragment;
private String encodedFragment;

private boolean plusAsBlank;

/**
* Constructs an empty instance.
*/
Expand Down Expand Up @@ -192,6 +194,33 @@ public Charset getCharset() {
return charset;
}

/**
* Sets whether the plus sign ('+') should be interpreted as a blank space (' ') when parsing
* the query parameters of the URI.
* <p>
* In HTTP URLs, query strings may contain spaces encoded as '+' characters or as '%20'.
* This flag controls whether '+' is interpreted as a space or remains as a plus sign.
* </p>
*
* <p>
* If the query string was already set, calling this method will re-parse the query
* using the updated flag. This ensures that the query parameters are processed correctly
* based on the specified interpretation of the '+' character.
* </p>
*
* @param plusAsBlank {@code true} to interpret '+' as a space, {@code false} to keep '+' as a literal plus sign.
* @return this {@link URIBuilder} instance for method chaining.
* @since 5.4
*/
public URIBuilder setPlusAsBlank(final boolean plusAsBlank) {
this.plusAsBlank = plusAsBlank;
// Re-parse the query string using the updated flag
if (this.encodedQuery != null) {
this.queryParams = parseQuery(this.encodedQuery, this.charset, this.plusAsBlank);
}
return this;
}

private static final char QUERY_PARAM_SEPARATOR = '&';
private static final char PARAM_VALUE_SEPARATOR = '=';
private static final char PATH_SEPARATOR = '/';
Expand Down Expand Up @@ -402,7 +431,7 @@ private void digestURI(final URI uri, final Charset charset) {
this.pathSegments = parsePath(uri.getRawPath(), charset);
this.pathRootless = uri.getRawPath() == null || !uri.getRawPath().startsWith("/");
this.encodedQuery = uri.getRawQuery();
this.queryParams = parseQuery(uri.getRawQuery(), charset, false);
this.queryParams = parseQuery(uri.getRawQuery(), charset, this.plusAsBlank);
this.encodedFragment = uri.getRawFragment();
this.fragment = uri.getFragment();
this.charset = charset;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -973,4 +973,30 @@ void testHttpUriWithEmptyHost() {
.setFragment("fragment");
Assertions.assertThrows(URISyntaxException.class, uribuilder::build);
}

@Test
void testSetPlusAsBlank() throws Exception {
// Case 1: Plus as blank, "+" should be treated as space
URIBuilder uriBuilder = new URIBuilder("http://localhost?param=hello+world")
.setPlusAsBlank(true);
List<NameValuePair> params = uriBuilder.getQueryParams();
Assertions.assertEquals("hello world", params.get(0).getValue());

// Case 2: Plus as plus, "+" should remain "+"
uriBuilder = new URIBuilder("http://localhost?param=hello+world")
.setPlusAsBlank(false);
params = uriBuilder.getQueryParams();
Assertions.assertEquals("hello+world", params.get(0).getValue());

// Case 3: '%20' always interpreted as space
uriBuilder = new URIBuilder("http://localhost?param=hello%20world")
.setPlusAsBlank(true);
params = uriBuilder.getQueryParams();
Assertions.assertEquals("hello world", params.get(0).getValue());

uriBuilder = new URIBuilder("http://localhost?param=hello%20world")
.setPlusAsBlank(false);
params = uriBuilder.getQueryParams();
Assertions.assertEquals("hello world", params.get(0).getValue());
}
}

0 comments on commit 1f20dd1

Please sign in to comment.