mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Avoid redundant URI object creation in WebClientUtils
Prior to this commit, WebClientUtils.getRequestDescription() created a new URI object on every invocation. Since the URI constructor includes validation and parsing, which is already performed by the parameter URI object, this was unnecessarily expensive for a logging utility. This commit reuses the original URI's string representation to avoid redundant parsing. This commit also strips userInfo, query, and fragment from the log description even if URIs contain only userInfo or fragment (without a query). Closes gh-36641 Signed-off-by: 박동윤 (Park Dong-Yun) <ehddbs7458@gmail.com>
This commit is contained in:
committed by
Brian Clozel
parent
be70e1c5a7
commit
865cf3c117
+31
-8
@@ -17,7 +17,6 @@
|
||||
package org.springframework.web.reactive.function.client;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@@ -28,7 +27,6 @@ import reactor.core.publisher.Mono;
|
||||
import org.springframework.core.codec.CodecException;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Internal methods shared between {@link DefaultWebClient} and
|
||||
@@ -69,18 +67,43 @@ abstract class WebClientUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a String representation of the request details for logging purposes.
|
||||
* Return a String representation of the request details for logging purposes
|
||||
* in "METHOD URI" format.
|
||||
* For the Security purpose, URI is returned in encoded format,
|
||||
* while userInfo, query, and fragment is stripped out.
|
||||
* @since 6.0.16
|
||||
*/
|
||||
public static String getRequestDescription(HttpMethod httpMethod, URI uri) {
|
||||
if (StringUtils.hasText(uri.getQuery())) {
|
||||
try {
|
||||
uri = new URI(uri.getScheme(), null, uri.getHost(), uri.getPort(), uri.getPath(), null, null);
|
||||
StringBuilder sb = new StringBuilder()
|
||||
.append(httpMethod.name()).append(" ");
|
||||
|
||||
// also handles Opaque URI, which has only schemeSpecificPart
|
||||
if (uri.getRawUserInfo() == null && uri.getRawQuery() == null && uri.getRawFragment() == null) {
|
||||
return sb.append(uri).toString();
|
||||
}
|
||||
|
||||
if (uri.getScheme() != null) {
|
||||
sb.append(uri.getScheme()).append(':');
|
||||
}
|
||||
if (uri.getHost() != null) {
|
||||
sb.append("//");
|
||||
String host = uri.getHost();
|
||||
// IPv6 handling
|
||||
if (host.indexOf(':') >= 0 && !host.startsWith("[") && !host.endsWith("]")) {
|
||||
sb.append('[').append(host).append(']');
|
||||
}
|
||||
catch (URISyntaxException ignored) {
|
||||
else {
|
||||
sb.append(host);
|
||||
}
|
||||
|
||||
if (uri.getPort() != -1) {
|
||||
sb.append(':').append(uri.getPort());
|
||||
}
|
||||
}
|
||||
return httpMethod.name() + " " + uri;
|
||||
if (uri.getRawPath() != null) {
|
||||
sb.append(uri.getRawPath());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2002-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.reactive.function.client;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link WebClientUtils#getRequestDescription}.
|
||||
*
|
||||
* @author Park Dong-Yun
|
||||
*/
|
||||
class WebClientUtilsTests {
|
||||
|
||||
@Test
|
||||
void stripsQueryParams() {
|
||||
URI uri = URI.create("https://api.example.com/search?q=test&page=1");
|
||||
assertThat(WebClientUtils.getRequestDescription(HttpMethod.GET, uri))
|
||||
.isEqualTo("GET https://api.example.com/search");
|
||||
}
|
||||
|
||||
@Test
|
||||
void noQueryReturnsAsIs() {
|
||||
URI uri = URI.create("https://api.example.com/health");
|
||||
assertThat(WebClientUtils.getRequestDescription(HttpMethod.GET, uri))
|
||||
.isEqualTo("GET https://api.example.com/health");
|
||||
}
|
||||
|
||||
@Test
|
||||
void preservesPort() {
|
||||
URI uri = URI.create("https://api.example.com:8443/path?q=1");
|
||||
assertThat(WebClientUtils.getRequestDescription(HttpMethod.GET, uri))
|
||||
.isEqualTo("GET https://api.example.com:8443/path");
|
||||
}
|
||||
|
||||
@Test
|
||||
void remainsPathEncodedWhenStrippingQuery() {
|
||||
URI uri = URI.create("https://host/hello%20world?q=1");
|
||||
assertThat(WebClientUtils.getRequestDescription(HttpMethod.GET, uri))
|
||||
.isEqualTo("GET https://host/hello%20world");
|
||||
}
|
||||
|
||||
@Test
|
||||
void stripsUserInfoWithQuery() {
|
||||
URI uri = URI.create("https://admin:secret@host/api?token=abc");
|
||||
assertThat(WebClientUtils.getRequestDescription(HttpMethod.GET, uri))
|
||||
.isEqualTo("GET https://host/api");
|
||||
}
|
||||
|
||||
@Test
|
||||
void stripsUserInfoWithoutQuery() {
|
||||
URI uri = URI.create("https://admin:secret@host/api");
|
||||
assertThat(WebClientUtils.getRequestDescription(HttpMethod.GET, uri))
|
||||
.isEqualTo("GET https://host/api");
|
||||
}
|
||||
|
||||
@Test
|
||||
void stripsFragmentWithQuery() {
|
||||
URI uri = URI.create("https://host/page?q=1#section");
|
||||
assertThat(WebClientUtils.getRequestDescription(HttpMethod.GET, uri))
|
||||
.isEqualTo("GET https://host/page");
|
||||
}
|
||||
|
||||
@Test
|
||||
void stripsFragmentWithoutQuery() {
|
||||
URI uri = URI.create("https://host/page#section");
|
||||
assertThat(WebClientUtils.getRequestDescription(HttpMethod.GET, uri))
|
||||
.isEqualTo("GET https://host/page");
|
||||
}
|
||||
|
||||
@Test
|
||||
void questionMarkInFragmentNotTreatedAsQuery() {
|
||||
URI uri = URI.create("https://host/page#frag?param=value");
|
||||
assertThat(WebClientUtils.getRequestDescription(HttpMethod.GET, uri))
|
||||
.isEqualTo("GET https://host/page");
|
||||
}
|
||||
|
||||
@Test
|
||||
void ipv6Host() {
|
||||
URI uri = URI.create("http://[::1]:8080/path?q=1");
|
||||
assertThat(WebClientUtils.getRequestDescription(HttpMethod.GET, uri))
|
||||
.isEqualTo("GET http://[::1]:8080/path");
|
||||
}
|
||||
|
||||
@Test
|
||||
void opaqueUriUnchanged() {
|
||||
URI uri = URI.create("mailto:user@example.com?subject=hello");
|
||||
assertThat(WebClientUtils.getRequestDescription(HttpMethod.GET, uri))
|
||||
.isEqualTo("GET mailto:user@example.com?subject=hello");
|
||||
}
|
||||
|
||||
@Test
|
||||
void relativeUri() {
|
||||
URI uri = URI.create("/api/search?q=test");
|
||||
assertThat(WebClientUtils.getRequestDescription(HttpMethod.GET, uri))
|
||||
.isEqualTo("GET /api/search");
|
||||
}
|
||||
|
||||
@Test
|
||||
void prefixesHttpMethod() {
|
||||
URI uri = URI.create("https://host/resource?v=1");
|
||||
assertThat(WebClientUtils.getRequestDescription(HttpMethod.POST, uri))
|
||||
.startsWith("POST ");
|
||||
assertThat(WebClientUtils.getRequestDescription(HttpMethod.DELETE, uri))
|
||||
.startsWith("DELETE ");
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user