mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-10-04 05:59:12 +00:00
Merge branch '7.0.x'
This commit is contained in:
+2
-1
@@ -74,7 +74,8 @@ public class DefaultSubscriptionRegistry extends AbstractSubscriptionRegistry {
|
||||
|
||||
/** Static evaluation context to reuse. */
|
||||
private static final EvaluationContext messageEvalContext =
|
||||
SimpleEvaluationContext.forPropertyAccessors(new SimpMessageHeaderPropertyAccessor()).build();
|
||||
SimpleEvaluationContext.forPropertyAccessors(new SimpMessageHeaderPropertyAccessor())
|
||||
.withAssignmentDisabled().build();
|
||||
|
||||
|
||||
private PathMatcher pathMatcher = new AntPathMatcher();
|
||||
|
||||
+2
-2
@@ -456,7 +456,7 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler
|
||||
accessor.setLogin(this.systemLogin);
|
||||
accessor.setPasscode(this.systemPasscode);
|
||||
accessor.setHeartbeat(this.systemHeartbeatSendInterval, this.systemHeartbeatReceiveInterval);
|
||||
accessor.setHost(getVirtualHost() != null ? getVirtualHost() : getRelayHost());
|
||||
accessor.setHost(getVirtualHost() != null ? getVirtualHost() : null);
|
||||
accessor.setSessionId(SYSTEM_SESSION_ID);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Forwarding " + accessor.getShortLogMessage(EMPTY_PAYLOAD));
|
||||
@@ -579,7 +579,7 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler
|
||||
stompHeaderAccessor = (stompHeaderAccessor.isMutable() ? stompHeaderAccessor : StompHeaderAccessor.wrap(message));
|
||||
stompHeaderAccessor.setLogin(this.clientLogin);
|
||||
stompHeaderAccessor.setPasscode(this.clientPasscode);
|
||||
stompHeaderAccessor.setHost(getVirtualHost() != null ? getVirtualHost() : getRelayHost());
|
||||
stompHeaderAccessor.setHost(getVirtualHost() != null ? getVirtualHost() : null);
|
||||
RelayConnectionHandler handler = new RelayConnectionHandler(sessionId, stompHeaderAccessor);
|
||||
this.connectionHandlers.put(sessionId, handler);
|
||||
this.stats.incrementConnectCount();
|
||||
|
||||
+21
@@ -98,6 +98,27 @@ class StompBrokerRelayMessageHandlerTests {
|
||||
assertThat(headers2.getHost()).isEqualTo("ABC");
|
||||
}
|
||||
|
||||
@Test
|
||||
void virtualHostDefault() {
|
||||
Message<byte[]> connectMessage = connectMessage("sess1", "joe");
|
||||
MessageHeaderAccessor.getAccessor(connectMessage, StompHeaderAccessor.class).setHost("ABC");
|
||||
|
||||
this.brokerRelay.start();
|
||||
this.brokerRelay.handleMessage(connectMessage("sess1", "joe"));
|
||||
|
||||
assertThat(this.tcpClient.getSentMessages()).hasSize(2);
|
||||
|
||||
StompHeaderAccessor headers1 = this.tcpClient.getSentHeaders(0);
|
||||
assertThat(headers1.getCommand()).isEqualTo(StompCommand.CONNECT);
|
||||
assertThat(headers1.getSessionId()).isEqualTo(StompBrokerRelayMessageHandler.SYSTEM_SESSION_ID);
|
||||
assertThat(headers1.getHost()).isNull();
|
||||
|
||||
StompHeaderAccessor headers2 = this.tcpClient.getSentHeaders(1);
|
||||
assertThat(headers2.getCommand()).isEqualTo(StompCommand.CONNECT);
|
||||
assertThat(headers2.getSessionId()).isEqualTo("sess1");
|
||||
assertThat(headers2.getHost()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void loginAndPasscode() {
|
||||
this.brokerRelay.setSystemLogin("syslogin");
|
||||
|
||||
+15
-9
@@ -135,19 +135,25 @@ abstract class ReactorUriHelper {
|
||||
if (c == '/' || c == '?' || c == '#') {
|
||||
break;
|
||||
}
|
||||
if (c == ':' && (i + 2 < length)) {
|
||||
if (uri.charAt(i + 1) == '/' && uri.charAt(i + 2) == '/') {
|
||||
for (int j = i + 3; j < length; j++) {
|
||||
c = uri.charAt(j);
|
||||
if (c == '/' || c == '?' || c == '#') {
|
||||
builder.append(uri, j, length);
|
||||
return;
|
||||
}
|
||||
if (hasAuthority(uri, c, i, length)) {
|
||||
for (i = i + 3; i < length; i++) {
|
||||
c = uri.charAt(i);
|
||||
if (c == '/' || c == '?' || c == '#') {
|
||||
builder.append(uri, i, length);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (length > 0 && uri.charAt(0) != '/') {
|
||||
builder.append('/');
|
||||
}
|
||||
builder.append(uri);
|
||||
}
|
||||
|
||||
private static boolean hasAuthority(String uri, char c, int i, int length) {
|
||||
return (c == ':' && (i + 2 < length) && (uri.charAt(i + 1) == '/' && uri.charAt(i + 2) == '/'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-3
@@ -148,9 +148,11 @@ public abstract class AbstractMappingContentNegotiationStrategy extends MappingM
|
||||
throws HttpMediaTypeNotAcceptableException {
|
||||
|
||||
if (!isUseRegisteredExtensionsOnly()) {
|
||||
Optional<MediaType> mediaType = MediaTypeFactory.getMediaType("file." + key);
|
||||
if (mediaType.isPresent()) {
|
||||
return mediaType.get();
|
||||
if (key.indexOf('.') == -1) {
|
||||
Optional<MediaType> mediaType = MediaTypeFactory.getMediaType("file." + key);
|
||||
if (mediaType.isPresent()) {
|
||||
return mediaType.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isIgnoreUnknownExtensions()) {
|
||||
|
||||
+6
-15
@@ -57,12 +57,7 @@ public class MappingMediaTypeFileExtensionResolver implements MediaTypeFileExten
|
||||
public MappingMediaTypeFileExtensionResolver(@Nullable Map<String, MediaType> mediaTypes) {
|
||||
if (mediaTypes != null) {
|
||||
Set<String> allFileExtensions = CollectionUtils.newHashSet(mediaTypes.size());
|
||||
mediaTypes.forEach((extension, mediaType) -> {
|
||||
String lowerCaseExtension = extension.toLowerCase(Locale.ROOT);
|
||||
this.mediaTypes.put(lowerCaseExtension, mediaType);
|
||||
addFileExtension(mediaType, lowerCaseExtension);
|
||||
allFileExtensions.add(lowerCaseExtension);
|
||||
});
|
||||
mediaTypes.forEach(this::addMapping);
|
||||
this.allFileExtensions.addAll(allFileExtensions);
|
||||
}
|
||||
}
|
||||
@@ -79,19 +74,15 @@ public class MappingMediaTypeFileExtensionResolver implements MediaTypeFileExten
|
||||
/**
|
||||
* Map an extension to a MediaType. Ignore if extension already mapped.
|
||||
*/
|
||||
protected void addMapping(String extension, MediaType mediaType) {
|
||||
MediaType previous = this.mediaTypes.putIfAbsent(extension, mediaType);
|
||||
protected void addMapping(String key, MediaType mediaType) {
|
||||
key = key.toLowerCase(Locale.ROOT);
|
||||
MediaType previous = this.mediaTypes.putIfAbsent(key, mediaType);
|
||||
if (previous == null) {
|
||||
addFileExtension(mediaType, extension);
|
||||
this.allFileExtensions.add(extension);
|
||||
this.fileExtensions.computeIfAbsent(mediaType, k -> new CopyOnWriteArrayList<>()).add(key);
|
||||
this.allFileExtensions.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
private void addFileExtension(MediaType mediaType, String extension) {
|
||||
this.fileExtensions.computeIfAbsent(mediaType, key -> new CopyOnWriteArrayList<>())
|
||||
.add(extension);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<String> resolveFileExtensions(MediaType mediaType) {
|
||||
|
||||
+39
-88
@@ -453,221 +453,172 @@ public class StandardServletAsyncWebRequest extends ServletWebRequest implements
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
invokeWithLock(this.delegate::flush);
|
||||
}
|
||||
|
||||
private void invokeWithLock(Runnable runnable) {
|
||||
int level = this.asyncWebRequest.tryObtainLock();
|
||||
if (level > -1) {
|
||||
try {
|
||||
this.delegate.flush();
|
||||
runnable.run();
|
||||
}
|
||||
finally {
|
||||
releaseLock(level);
|
||||
if (level > 0) {
|
||||
this.asyncWebRequest.stateLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
int level = this.asyncWebRequest.tryObtainLock();
|
||||
if (level > -1) {
|
||||
try {
|
||||
this.delegate.close();
|
||||
}
|
||||
finally {
|
||||
releaseLock(level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkError() {
|
||||
return this.delegate.checkError();
|
||||
invokeWithLock(this.delegate::close);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int c) {
|
||||
int level = this.asyncWebRequest.tryObtainLock();
|
||||
if (level > -1) {
|
||||
try {
|
||||
this.delegate.write(c);
|
||||
}
|
||||
finally {
|
||||
releaseLock(level);
|
||||
}
|
||||
}
|
||||
invokeWithLock(() -> this.delegate.write(c));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(char[] buf, int off, int len) {
|
||||
int level = this.asyncWebRequest.tryObtainLock();
|
||||
if (level > -1) {
|
||||
try {
|
||||
this.delegate.write(buf, off, len);
|
||||
}
|
||||
finally {
|
||||
releaseLock(level);
|
||||
}
|
||||
}
|
||||
invokeWithLock(() -> this.delegate.write(buf, off, len));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(char[] buf) {
|
||||
this.delegate.write(buf);
|
||||
write(buf, 0, buf.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(String s, int off, int len) {
|
||||
int level = this.asyncWebRequest.tryObtainLock();
|
||||
if (level > -1) {
|
||||
try {
|
||||
this.delegate.write(s, off, len);
|
||||
}
|
||||
finally {
|
||||
releaseLock(level);
|
||||
}
|
||||
}
|
||||
invokeWithLock(() -> this.delegate.write(s, off, len));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(String s) {
|
||||
this.delegate.write(s);
|
||||
}
|
||||
|
||||
private void releaseLock(int level) {
|
||||
if (level > 0) {
|
||||
this.asyncWebRequest.stateLock.unlock();
|
||||
}
|
||||
write(s, 0, s.length());
|
||||
}
|
||||
|
||||
// Plain delegates
|
||||
|
||||
@Override
|
||||
public void print(boolean b) {
|
||||
this.delegate.print(b);
|
||||
write(String.valueOf(b));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(char c) {
|
||||
this.delegate.print(c);
|
||||
write(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(int i) {
|
||||
this.delegate.print(i);
|
||||
write(String.valueOf(i));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(long l) {
|
||||
this.delegate.print(l);
|
||||
write(String.valueOf(l));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(float f) {
|
||||
this.delegate.print(f);
|
||||
write(String.valueOf(f));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(double d) {
|
||||
this.delegate.print(d);
|
||||
write(String.valueOf(d));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(char[] s) {
|
||||
this.delegate.print(s);
|
||||
write(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(String s) {
|
||||
this.delegate.print(s);
|
||||
write(String.valueOf(s));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(Object obj) {
|
||||
this.delegate.print(obj);
|
||||
write(String.valueOf(obj));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void println() {
|
||||
this.delegate.println();
|
||||
invokeWithLock(this.delegate::println);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void println(boolean x) {
|
||||
this.delegate.println(x);
|
||||
invokeWithLock(() -> this.delegate.println(x));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void println(char x) {
|
||||
this.delegate.println(x);
|
||||
invokeWithLock(() -> this.delegate.println(x));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void println(int x) {
|
||||
this.delegate.println(x);
|
||||
invokeWithLock(() -> this.delegate.println(x));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void println(long x) {
|
||||
this.delegate.println(x);
|
||||
invokeWithLock(() -> this.delegate.println(x));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void println(float x) {
|
||||
this.delegate.println(x);
|
||||
invokeWithLock(() -> this.delegate.println(x));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void println(double x) {
|
||||
this.delegate.println(x);
|
||||
invokeWithLock(() -> this.delegate.println(x));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void println(char[] x) {
|
||||
this.delegate.println(x);
|
||||
invokeWithLock(() -> this.delegate.println(x));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void println(String x) {
|
||||
this.delegate.println(x);
|
||||
invokeWithLock(() -> this.delegate.println(x));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void println(Object x) {
|
||||
this.delegate.println(x);
|
||||
invokeWithLock(() -> this.delegate.println(x));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintWriter printf(String format, Object... args) {
|
||||
return this.delegate.printf(format, args);
|
||||
return format(format, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintWriter printf(Locale l, String format, Object... args) {
|
||||
return this.delegate.printf(l, format, args);
|
||||
return format(format, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintWriter format(String format, Object... args) {
|
||||
return this.delegate.format(format, args);
|
||||
invokeWithLock(() -> this.delegate.format(format, args));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintWriter format(Locale l, String format, Object... args) {
|
||||
return this.delegate.format(l, format, args);
|
||||
invokeWithLock(() -> this.delegate.format(format, args));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintWriter append(CharSequence csq) {
|
||||
return this.delegate.append(csq);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintWriter append(CharSequence csq, int start, int end) {
|
||||
return this.delegate.append(csq, start, end);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintWriter append(char c) {
|
||||
return this.delegate.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+32
-4
@@ -35,10 +35,11 @@ import static org.mockito.Mockito.mock;
|
||||
*/
|
||||
class ReactorUriHelperTests {
|
||||
|
||||
private final HttpServerRequest nettyRequest = mock();
|
||||
|
||||
|
||||
@Test
|
||||
void hostnameWithZoneId() throws URISyntaxException {
|
||||
HttpServerRequest nettyRequest = mock();
|
||||
|
||||
given(nettyRequest.scheme()).willReturn("http");
|
||||
given(nettyRequest.hostName()).willReturn("fe80::a%en1");
|
||||
given(nettyRequest.hostPort()).willReturn(80);
|
||||
@@ -50,7 +51,36 @@ class ReactorUriHelperTests {
|
||||
.hasPort(-1)
|
||||
.hasPath("/")
|
||||
.hasToString("http://[fe80::a%25en1]/");
|
||||
}
|
||||
|
||||
@Test
|
||||
void requestUriWithScheme() throws URISyntaxException {
|
||||
given(nettyRequest.scheme()).willReturn("http");
|
||||
given(nettyRequest.hostName()).willReturn("example.org");
|
||||
given(nettyRequest.hostPort()).willReturn(80);
|
||||
given(nettyRequest.uri()).willReturn("http://example.org/path");
|
||||
|
||||
URI uri = ReactorUriHelper.createUri(nettyRequest);
|
||||
assertThat(uri).hasScheme("http")
|
||||
.hasHost("example.org")
|
||||
.hasPort(-1)
|
||||
.hasPath("/path")
|
||||
.hasToString("http://example.org/path");
|
||||
}
|
||||
|
||||
@Test
|
||||
void requestUriWithoutLeadingSlash() throws URISyntaxException {
|
||||
given(nettyRequest.scheme()).willReturn("http");
|
||||
given(nettyRequest.hostName()).willReturn("example.org");
|
||||
given(nettyRequest.hostPort()).willReturn(80);
|
||||
given(nettyRequest.uri()).willReturn("foo/bar");
|
||||
|
||||
URI uri = ReactorUriHelper.createUri(nettyRequest);
|
||||
assertThat(uri).hasScheme("http")
|
||||
.hasHost("example.org")
|
||||
.hasPort(-1)
|
||||
.hasPath("/foo/bar")
|
||||
.hasToString("http://example.org/foo/bar");
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "{displayName}({arguments})")
|
||||
@@ -61,8 +91,6 @@ class ReactorUriHelperTests {
|
||||
"'' | /",
|
||||
})
|
||||
void forwardedPrefix(String forwardedPrefixHeader, String expectedPath) throws URISyntaxException {
|
||||
HttpServerRequest nettyRequest = mock();
|
||||
|
||||
given(nettyRequest.scheme()).willReturn("https");
|
||||
given(nettyRequest.hostName()).willReturn("localhost");
|
||||
given(nettyRequest.hostPort()).willReturn(443);
|
||||
|
||||
+32
-26
@@ -23,9 +23,11 @@ import java.util.Map;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
/**
|
||||
* A test fixture with a test subclass of AbstractMappingContentNegotiationStrategy.
|
||||
@@ -36,7 +38,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
class MappingContentNegotiationStrategyTests {
|
||||
|
||||
@Test
|
||||
void resolveMediaTypes() throws Exception {
|
||||
void resolveMediaTypesFromRegisteredExtensions() throws Exception {
|
||||
Map<String, MediaType> mapping = Collections.singletonMap("json", MediaType.APPLICATION_JSON);
|
||||
TestMappingContentNegotiationStrategy strategy = new TestMappingContentNegotiationStrategy("json", mapping);
|
||||
|
||||
@@ -47,27 +49,7 @@ class MappingContentNegotiationStrategyTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveMediaTypesNoMatch() throws Exception {
|
||||
Map<String, MediaType> mapping = null;
|
||||
TestMappingContentNegotiationStrategy strategy = new TestMappingContentNegotiationStrategy("blah", mapping);
|
||||
|
||||
List<MediaType> mediaTypes = strategy.resolveMediaTypes(null);
|
||||
|
||||
assertThat(mediaTypes).isEqualTo(ContentNegotiationStrategy.MEDIA_TYPE_ALL_LIST);
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveMediaTypesNoKey() throws Exception {
|
||||
Map<String, MediaType> mapping = Collections.singletonMap("json", MediaType.APPLICATION_JSON);
|
||||
TestMappingContentNegotiationStrategy strategy = new TestMappingContentNegotiationStrategy(null, mapping);
|
||||
|
||||
List<MediaType> mediaTypes = strategy.resolveMediaTypes(null);
|
||||
|
||||
assertThat(mediaTypes).isEqualTo(ContentNegotiationStrategy.MEDIA_TYPE_ALL_LIST);
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveMediaTypesHandleNoMatch() throws Exception {
|
||||
void resolveMediaTypesViaFactory() throws Exception {
|
||||
Map<String, MediaType> mapping = null;
|
||||
TestMappingContentNegotiationStrategy strategy = new TestMappingContentNegotiationStrategy("xml", mapping);
|
||||
|
||||
@@ -77,6 +59,34 @@ class MappingContentNegotiationStrategyTests {
|
||||
assertThat(mediaTypes.get(0).toString()).isEqualTo("application/xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveMediaTypesUnknownKey() {
|
||||
Map<String, MediaType> mapping = null;
|
||||
TestMappingContentNegotiationStrategy strategy = new TestMappingContentNegotiationStrategy("blah", mapping);
|
||||
|
||||
assertThatThrownBy(() -> strategy.resolveMediaTypes(null))
|
||||
.isInstanceOf(HttpMediaTypeNotAcceptableException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveMediaTypesInvalidKey() {
|
||||
Map<String, MediaType> mapping = null;
|
||||
TestMappingContentNegotiationStrategy strategy = new TestMappingContentNegotiationStrategy("not.json", mapping);
|
||||
|
||||
assertThatThrownBy(() -> strategy.resolveMediaTypes(null))
|
||||
.isInstanceOf(HttpMediaTypeNotAcceptableException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveMediaTypesNullKey() throws Exception {
|
||||
Map<String, MediaType> mapping = Collections.singletonMap("json", MediaType.APPLICATION_JSON);
|
||||
TestMappingContentNegotiationStrategy strategy = new TestMappingContentNegotiationStrategy(null, mapping);
|
||||
|
||||
List<MediaType> mediaTypes = strategy.resolveMediaTypes(null);
|
||||
|
||||
assertThat(mediaTypes).isEqualTo(ContentNegotiationStrategy.MEDIA_TYPE_ALL_LIST);
|
||||
}
|
||||
|
||||
|
||||
private static class TestMappingContentNegotiationStrategy extends AbstractMappingContentNegotiationStrategy {
|
||||
|
||||
@@ -92,10 +102,6 @@ class MappingContentNegotiationStrategyTests {
|
||||
return this.extension;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MediaType handleNoMatch(NativeWebRequest request, String mappingKey) {
|
||||
return "xml".equals(mappingKey) ? MediaType.APPLICATION_XML : null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+10
-6
@@ -68,13 +68,17 @@ class MappingMediaTypeFileExtensionResolverTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void allFileExtensions() {
|
||||
Map<String, MediaType> mappings = new HashMap<>();
|
||||
mappings.put("json", MediaType.APPLICATION_JSON);
|
||||
mappings.put("JsOn", MediaType.APPLICATION_JSON);
|
||||
mappings.put("jSoN", MediaType.APPLICATION_JSON);
|
||||
void mappingsAreCaseInsensitive() {
|
||||
Map<String, MediaType> map = new HashMap<>();
|
||||
map.put("json", MediaType.APPLICATION_JSON);
|
||||
map.put("JsOn", MediaType.APPLICATION_JSON);
|
||||
map.put("jSoN", MediaType.APPLICATION_JSON);
|
||||
|
||||
MappingMediaTypeFileExtensionResolver resolver = new MappingMediaTypeFileExtensionResolver(map);
|
||||
map.forEach(resolver::addMapping);
|
||||
|
||||
MappingMediaTypeFileExtensionResolver resolver = new MappingMediaTypeFileExtensionResolver(mappings);
|
||||
assertThat(resolver.getAllFileExtensions()).containsExactly("json");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+2
-4
@@ -334,10 +334,8 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
|
||||
logger.trace(exchange.getLogPrefix() + matches.size() + " matching mappings: " + matches);
|
||||
}
|
||||
if (CorsUtils.isPreFlightRequest(exchange.getRequest())) {
|
||||
for (Match match : matches) {
|
||||
if (match.hasCorsConfig()) {
|
||||
return PREFLIGHT_AMBIGUOUS_MATCH;
|
||||
}
|
||||
if (matches.stream().allMatch(Match::hasCorsConfig)) {
|
||||
return PREFLIGHT_AMBIGUOUS_MATCH;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
+1
-1
@@ -149,7 +149,7 @@ public class JettyWebSocketSession extends AbstractWebSocketSession<Session> {
|
||||
if (JettyWebSocketSession.this.handlerCompletionSink != null) {
|
||||
JettyWebSocketSession.this.handlerCompletionSink.tryEmitError(error);
|
||||
}
|
||||
getDelegate().close(StatusCode.SERVER_ERROR, error.getMessage(), Callback.NOOP);
|
||||
getDelegate().close(StatusCode.SERVER_ERROR, null, Callback.NOOP);
|
||||
}
|
||||
|
||||
void onHandleComplete() {
|
||||
|
||||
+8
-3
@@ -131,8 +131,8 @@ class HandlerMethodMappingTests {
|
||||
|
||||
@Test // gh-26490
|
||||
void ambiguousMatchOnPreFlightRequestWithCorsConfig() throws Exception {
|
||||
this.mapping.registerMapping("/f?o", this.handler, this.method1);
|
||||
this.mapping.registerMapping("/fo?", this.handler, this.handler.getClass().getMethod("corsHandlerMethod"));
|
||||
this.mapping.registerMapping("/f?o", this.handler, this.handler.getClass().getMethod("corsHandlerMethod1"));
|
||||
this.mapping.registerMapping("/fo?", this.handler, this.handler.getClass().getMethod("corsHandlerMethod2"));
|
||||
|
||||
MockServerWebExchange exchange = MockServerWebExchange.from(
|
||||
MockServerHttpRequest.options("https://example.org/foo")
|
||||
@@ -256,7 +256,12 @@ class HandlerMethodMappingTests {
|
||||
|
||||
@RequestMapping
|
||||
@CrossOrigin(originPatterns = "*")
|
||||
public void corsHandlerMethod() {
|
||||
public void corsHandlerMethod1() {
|
||||
}
|
||||
|
||||
@RequestMapping
|
||||
@CrossOrigin(originPatterns = "*")
|
||||
public void corsHandlerMethod2() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-4
@@ -409,10 +409,8 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
|
||||
logger.trace(matches.size() + " matching mappings: " + matches);
|
||||
}
|
||||
if (CorsUtils.isPreFlightRequest(request)) {
|
||||
for (Match match : matches) {
|
||||
if (match.hasCorsConfig()) {
|
||||
return PREFLIGHT_AMBIGUOUS_MATCH;
|
||||
}
|
||||
if (matches.stream().allMatch(Match::hasCorsConfig)) {
|
||||
return PREFLIGHT_AMBIGUOUS_MATCH;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
+4
-8
@@ -28,21 +28,17 @@ import org.springframework.web.util.ServletRequestPathUtils;
|
||||
|
||||
/**
|
||||
* Simple {@code Controller} implementation that transforms the virtual
|
||||
* path of a URL into a view name and returns that view.
|
||||
* path of a URL into a view name and returns that view, optionally prepending a
|
||||
* {@link #setPrefix prefix} and/or appending a {@link #setSuffix suffix}.
|
||||
*
|
||||
* <p>Can optionally prepend a {@link #setPrefix prefix} and/or append a
|
||||
* {@link #setSuffix suffix} to build the viewname from the URL filename.
|
||||
*
|
||||
* <p>Find some examples below:
|
||||
* <p>This is intended for use with individually mapped static content pages
|
||||
* such as a home page or an index page. See examples below:
|
||||
* <ol>
|
||||
* <li>{@code "/index" -> "index"}</li>
|
||||
* <li>{@code "/index.html" -> "index"}</li>
|
||||
* <li>{@code "/index.html"} + prefix {@code "pre_"} and suffix {@code "_suf" -> "pre_index_suf"}</li>
|
||||
* <li>{@code "/products/view.html" -> "products/view"}</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p>Thanks to David Barri for suggesting prefix/suffix support!
|
||||
*
|
||||
* @author Alef Arendsen
|
||||
* @author Juergen Hoeller
|
||||
* @author Rob Harrop
|
||||
|
||||
+6
-1
@@ -35,6 +35,7 @@ import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.servlet.resource.ResourceHandlerUtils;
|
||||
|
||||
/**
|
||||
* An extension of Groovy's {@link groovy.text.markup.TemplateConfiguration} and
|
||||
@@ -223,7 +224,11 @@ public class GroovyMarkupConfigurer extends TemplateConfiguration
|
||||
@Override
|
||||
public URL resolveTemplate(String templatePath) throws IOException {
|
||||
Assert.state(this.classLoader != null, "No template ClassLoader available");
|
||||
return GroovyMarkupConfigurer.this.resolveTemplate(this.classLoader, templatePath);
|
||||
String path = ResourceHandlerUtils.normalizeInputPath(templatePath);
|
||||
if (ResourceHandlerUtils.shouldIgnoreInputPath(path)) {
|
||||
throw new IOException("Invalid template path:" + templatePath);
|
||||
}
|
||||
return GroovyMarkupConfigurer.this.resolveTemplate(this.classLoader, path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-5
@@ -142,8 +142,8 @@ class HandlerMethodMappingTests {
|
||||
|
||||
@Test // gh-26490
|
||||
void ambiguousMatchOnPreFlightRequestWithCorsConfig() throws Exception {
|
||||
this.mapping.registerMapping("/f?o", this.handler, this.method1);
|
||||
this.mapping.registerMapping("/fo?", this.handler, this.handler.getClass().getMethod("corsHandlerMethod"));
|
||||
this.mapping.registerMapping("/f?o", this.handler, this.handler.getClass().getMethod("corsHandlerMethod1"));
|
||||
this.mapping.registerMapping("/fo?", this.handler, this.handler.getClass().getMethod("corsHandlerMethod2"));
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("OPTIONS", "/foo");
|
||||
request.addHeader(HttpHeaders.ORIGIN, "https://domain.com");
|
||||
@@ -166,7 +166,7 @@ class HandlerMethodMappingTests {
|
||||
|
||||
@Test
|
||||
void abortInterceptorInPreFlightRequestWithCorsConfig() throws Exception {
|
||||
this.mapping.registerMapping("/foo", this.handler, this.handler.getClass().getMethod("corsHandlerMethod"));
|
||||
this.mapping.registerMapping("/foo", this.handler, this.handler.getClass().getMethod("corsHandlerMethod1"));
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("OPTIONS", "/foo");
|
||||
request.addParameter("abort", "true");
|
||||
@@ -297,7 +297,7 @@ class HandlerMethodMappingTests {
|
||||
@Test
|
||||
void registerCustomHandlerMethod() throws Exception {
|
||||
this.mapping.setCustomerHandlerMethod(true);
|
||||
this.mapping.registerMapping("/foo", this.handler, this.handler.getClass().getMethod("corsHandlerMethod"));
|
||||
this.mapping.registerMapping("/foo", this.handler, this.handler.getClass().getMethod("corsHandlerMethod1"));
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("OPTIONS", "/foo");
|
||||
request.addParameter("abort", "true");
|
||||
@@ -418,7 +418,13 @@ class HandlerMethodMappingTests {
|
||||
|
||||
@RequestMapping
|
||||
@CrossOrigin(originPatterns = "*")
|
||||
public void corsHandlerMethod() {
|
||||
public void corsHandlerMethod1() {
|
||||
}
|
||||
|
||||
@RequestMapping
|
||||
@CrossOrigin(originPatterns = "*")
|
||||
public void corsHandlerMethod2() {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user