Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -28,7 +27,6 @@
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
Expand Down Expand Up @@ -69,18 +67,43 @@ public static <T> Mono<ResponseEntity<List<T>>> mapToEntityList(ClientResponse r
}

/**
* 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());
}
}
if (uri.getRawPath() != null) {
sb.append(uri.getRawPath());
}
return httpMethod.name() + " " + uri;
return sb.toString();
}

}
Original file line number Diff line number Diff line change
@@ -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 ");
}

}