Merge branch '5.1.x'

This commit is contained in:
Rossen Stoyanchev
2019-04-05 21:53:55 -04:00
11 changed files with 254 additions and 46 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2019 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.
@@ -19,6 +19,7 @@ package org.springframework.web.reactive.resource;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
@@ -31,6 +32,7 @@ import org.springframework.core.io.UrlResource;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriUtils;
/**
* A simple {@code ResourceResolver} that tries to find a resource under the given
@@ -108,6 +110,9 @@ public class PathResourceResolver extends AbstractResourceResolver {
*/
protected Mono<Resource> getResource(String resourcePath, Resource location) {
try {
if (location instanceof ClassPathResource) {
resourcePath = UriUtils.decode(resourcePath, StandardCharsets.UTF_8);
}
Resource resource = location.createRelative(resourcePath);
if (resource.isReadable()) {
if (checkResource(resource, location)) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2019 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.
@@ -21,6 +21,7 @@ import java.util.List;
import reactor.core.publisher.Mono;
import org.springframework.core.io.Resource;
import org.springframework.http.server.RequestPath;
import org.springframework.lang.Nullable;
import org.springframework.web.server.ServerWebExchange;
@@ -40,7 +41,8 @@ public interface ResourceResolver {
* Resolve the supplied request and request path to a {@link Resource} that
* exists under one of the given resource locations.
* @param exchange the current exchange
* @param requestPath the portion of the request path to use
* @param requestPath the portion of the request path to use. This is
* expected to be the encoded path, i.e. {@link RequestPath#value()}.
* @param locations the locations to search in when looking up resources
* @param chain the chain of remaining resolvers to delegate to
* @return the resolved resource or an empty {@code Mono} if unresolved
@@ -53,7 +55,8 @@ public interface ResourceResolver {
* to access the resource that is located at the given <em>internal</em>
* resource path.
* <p>This is useful when rendering URL links to clients.
* @param resourcePath the internal resource path
* @param resourcePath the "internal" resource path to resolve a path for
* public use. This is expected to be the encoded path.
* @param locations the locations to search in when looking up resources
* @param chain the chain of resolvers to delegate to
* @return the resolved public URL path or an empty {@code Mono} if unresolved

View File

@@ -35,6 +35,7 @@ import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.codec.DecodingException;
import org.springframework.core.codec.Hints;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.codec.HttpMessageReader;
@@ -205,7 +206,8 @@ public abstract class AbstractMessageReaderArgumentResolver extends HandlerMetho
HttpMethod method = request.getMethod();
if (contentType == null && method != null && SUPPORTED_METHODS.contains(method)) {
Flux<DataBuffer> body = request.getBody().doOnNext(o -> {
Flux<DataBuffer> body = request.getBody().doOnNext(buffer -> {
DataBufferUtils.release(buffer);
// Body not empty, back to 415..
throw new UnsupportedMediaTypeStatusException(mediaType, this.supportedMediaTypes, elementType);
});

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2019 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.
@@ -32,7 +32,6 @@ import freemarker.template.ObjectWrapper;
import freemarker.template.SimpleHash;
import freemarker.template.Template;
import freemarker.template.Version;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.beans.BeansException;
@@ -42,6 +41,7 @@ import org.springframework.context.ApplicationContextException;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.PooledDataBuffer;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@@ -184,30 +184,34 @@ public class FreeMarkerView extends AbstractUrlBasedView {
protected Mono<Void> renderInternal(Map<String, Object> renderAttributes,
@Nullable MediaType contentType, ServerWebExchange exchange) {
// Expose all standard FreeMarker hash models.
SimpleHash freeMarkerModel = getTemplateModel(renderAttributes, exchange);
return exchange.getResponse().writeWith(Mono
.fromCallable(() -> {
// Expose all standard FreeMarker hash models.
SimpleHash freeMarkerModel = getTemplateModel(renderAttributes, exchange);
if (logger.isDebugEnabled()) {
logger.debug(exchange.getLogPrefix() + "Rendering [" + getUrl() + "]");
}
if (logger.isDebugEnabled()) {
logger.debug(exchange.getLogPrefix() + "Rendering [" + getUrl() + "]");
}
Locale locale = LocaleContextHolder.getLocale(exchange.getLocaleContext());
DataBuffer dataBuffer = exchange.getResponse().bufferFactory().allocateBuffer();
try {
Charset charset = getCharset(contentType);
Writer writer = new OutputStreamWriter(dataBuffer.asOutputStream(), charset);
getTemplate(locale).process(freeMarkerModel, writer);
}
catch (IOException ex) {
DataBufferUtils.release(dataBuffer);
String message = "Could not load FreeMarker template for URL [" + getUrl() + "]";
return Mono.error(new IllegalStateException(message, ex));
}
catch (Throwable ex) {
DataBufferUtils.release(dataBuffer);
return Mono.error(ex);
}
return exchange.getResponse().writeWith(Flux.just(dataBuffer));
Locale locale = LocaleContextHolder.getLocale(exchange.getLocaleContext());
DataBuffer dataBuffer = exchange.getResponse().bufferFactory().allocateBuffer();
try {
Charset charset = getCharset(contentType);
Writer writer = new OutputStreamWriter(dataBuffer.asOutputStream(), charset);
getTemplate(locale).process(freeMarkerModel, writer);
return dataBuffer;
}
catch (IOException ex) {
DataBufferUtils.release(dataBuffer);
String message = "Could not load FreeMarker template for URL [" + getUrl() + "]";
throw new IllegalStateException(message, ex);
}
catch (Throwable ex) {
DataBufferUtils.release(dataBuffer);
throw ex;
}
})
.doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release));
}
private Charset getCharset(@Nullable MediaType mediaType) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2019 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.
@@ -37,9 +37,7 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextException;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.core.io.Resource;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.lang.Nullable;
import org.springframework.scripting.support.StandardScriptEvalException;
import org.springframework.scripting.support.StandardScriptUtils;
@@ -301,8 +299,7 @@ public class ScriptTemplateView extends AbstractUrlBasedView {
protected Mono<Void> renderInternal(
Map<String, Object> model, @Nullable MediaType contentType, ServerWebExchange exchange) {
return Mono.defer(() -> {
ServerHttpResponse response = exchange.getResponse();
return exchange.getResponse().writeWith(Mono.fromCallable(() -> {
try {
ScriptEngine engine = getEngine();
String url = getUrl();
@@ -338,8 +335,7 @@ public class ScriptTemplateView extends AbstractUrlBasedView {
}
byte[] bytes = String.valueOf(html).getBytes(StandardCharsets.UTF_8);
DataBuffer buffer = response.bufferFactory().allocateBuffer(bytes.length).write(bytes);
return response.writeWith(Mono.just(buffer));
return exchange.getResponse().bufferFactory().wrap(bytes); // just wrapping, no allocation
}
catch (ScriptException ex) {
throw new IllegalStateException("Failed to render script template", new StandardScriptEvalException(ex));
@@ -347,7 +343,7 @@ public class ScriptTemplateView extends AbstractUrlBasedView {
catch (Exception ex) {
throw new IllegalStateException("Failed to render script template", ex);
}
});
}));
}
protected String getTemplate(String path) throws IOException {