use of org.springframework.core.codec.Hints in project spring-framework by spring-projects.
the class MultipartHttpMessageWriter method writeMultipart.
private Mono<Void> writeMultipart(MultiValueMap<String, ?> map, ReactiveHttpOutputMessage outputMessage, @Nullable MediaType mediaType, Map<String, Object> hints) {
byte[] boundary = generateMultipartBoundary();
mediaType = getMultipartMediaType(mediaType, boundary);
outputMessage.getHeaders().setContentType(mediaType);
LogFormatUtils.traceDebug(logger, traceOn -> Hints.getLogPrefix(hints) + "Encoding " + (isEnableLoggingRequestDetails() ? LogFormatUtils.formatValue(map, !traceOn) : "parts " + map.keySet() + " (content masked)"));
DataBufferFactory bufferFactory = outputMessage.bufferFactory();
Flux<DataBuffer> body = Flux.fromIterable(map.entrySet()).concatMap(entry -> encodePartValues(boundary, entry.getKey(), entry.getValue(), bufferFactory)).concatWith(generateLastLine(boundary, bufferFactory)).doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release);
if (logger.isDebugEnabled()) {
body = body.doOnNext(buffer -> Hints.touchDataBuffer(buffer, hints, logger));
}
return outputMessage.writeWith(body);
}
use of org.springframework.core.codec.Hints in project spring-framework by spring-projects.
the class ResourceHttpMessageWriter method writeResource.
private Mono<Void> writeResource(Resource resource, ResolvableType type, @Nullable MediaType mediaType, ReactiveHttpOutputMessage message, Map<String, Object> hints) {
HttpHeaders headers = message.getHeaders();
MediaType resourceMediaType = getResourceMediaType(mediaType, resource, hints);
headers.setContentType(resourceMediaType);
if (headers.getContentLength() < 0) {
long length = lengthOf(resource);
if (length != -1) {
headers.setContentLength(length);
}
}
return zeroCopy(resource, null, message, hints).orElseGet(() -> {
Mono<Resource> input = Mono.just(resource);
DataBufferFactory factory = message.bufferFactory();
Flux<DataBuffer> body = this.encoder.encode(input, factory, type, resourceMediaType, hints);
if (logger.isDebugEnabled()) {
body = body.doOnNext(buffer -> Hints.touchDataBuffer(buffer, hints, logger));
}
return message.writeWith(body);
});
}
use of org.springframework.core.codec.Hints in project spring-framework by spring-projects.
the class EncoderHttpMessageWriter method write.
@Override
public Mono<Void> write(Publisher<? extends T> inputStream, ResolvableType elementType, @Nullable MediaType mediaType, ReactiveHttpOutputMessage message, Map<String, Object> hints) {
MediaType contentType = updateContentType(message, mediaType);
Flux<DataBuffer> body = this.encoder.encode(inputStream, message.bufferFactory(), elementType, contentType, hints);
if (inputStream instanceof Mono) {
return body.singleOrEmpty().switchIfEmpty(Mono.defer(() -> {
message.getHeaders().setContentLength(0);
return message.setComplete().then(Mono.empty());
})).flatMap(buffer -> {
Hints.touchDataBuffer(buffer, hints, logger);
message.getHeaders().setContentLength(buffer.readableByteCount());
return message.writeWith(Mono.just(buffer).doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release));
}).doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release);
}
if (isStreamingMediaType(contentType)) {
return message.writeAndFlushWith(body.map(buffer -> {
Hints.touchDataBuffer(buffer, hints, logger);
return Mono.just(buffer).doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release);
}));
}
if (logger.isDebugEnabled()) {
body = body.doOnNext(buffer -> Hints.touchDataBuffer(buffer, hints, logger));
}
return message.writeWith(body);
}
use of org.springframework.core.codec.Hints in project spring-framework by spring-projects.
the class AbstractMessageReaderArgumentResolver method readBody.
/**
* Read the body from a method argument with {@link HttpMessageReader}.
* @param bodyParam represents the element type for the body
* @param actualParam the actual method argument type; possibly different
* from {@code bodyParam}, e.g. for an {@code HttpEntity} argument
* @param isBodyRequired true if the body is required
* @param bindingContext the binding context to use
* @param exchange the current exchange
* @return a Mono with the value to use for the method argument
* @since 5.0.2
*/
protected Mono<Object> readBody(MethodParameter bodyParam, @Nullable MethodParameter actualParam, boolean isBodyRequired, BindingContext bindingContext, ServerWebExchange exchange) {
ResolvableType bodyType = ResolvableType.forMethodParameter(bodyParam);
ResolvableType actualType = (actualParam != null ? ResolvableType.forMethodParameter(actualParam) : bodyType);
Class<?> resolvedType = bodyType.resolve();
ReactiveAdapter adapter = (resolvedType != null ? getAdapterRegistry().getAdapter(resolvedType) : null);
ResolvableType elementType = (adapter != null ? bodyType.getGeneric() : bodyType);
isBodyRequired = isBodyRequired || (adapter != null && !adapter.supportsEmpty());
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
MediaType contentType = request.getHeaders().getContentType();
MediaType mediaType = (contentType != null ? contentType : MediaType.APPLICATION_OCTET_STREAM);
Object[] hints = extractValidationHints(bodyParam);
if (mediaType.isCompatibleWith(MediaType.APPLICATION_FORM_URLENCODED)) {
if (logger.isDebugEnabled()) {
logger.debug("Form data is accessed via ServerWebExchange.getFormData() in WebFlux.");
}
return Mono.error(new ResponseStatusException(HttpStatus.UNSUPPORTED_MEDIA_TYPE));
}
if (logger.isDebugEnabled()) {
logger.debug(exchange.getLogPrefix() + (contentType != null ? "Content-Type:" + contentType : "No Content-Type, using " + MediaType.APPLICATION_OCTET_STREAM));
}
for (HttpMessageReader<?> reader : getMessageReaders()) {
if (reader.canRead(elementType, mediaType)) {
Map<String, Object> readHints = Hints.from(Hints.LOG_PREFIX_HINT, exchange.getLogPrefix());
if (adapter != null && adapter.isMultiValue()) {
if (logger.isDebugEnabled()) {
logger.debug(exchange.getLogPrefix() + "0..N [" + elementType + "]");
}
Flux<?> flux = reader.read(actualType, elementType, request, response, readHints);
flux = flux.onErrorResume(ex -> Flux.error(handleReadError(bodyParam, ex)));
if (isBodyRequired) {
flux = flux.switchIfEmpty(Flux.error(() -> handleMissingBody(bodyParam)));
}
if (hints != null) {
flux = flux.doOnNext(target -> validate(target, hints, bodyParam, bindingContext, exchange));
}
return Mono.just(adapter.fromPublisher(flux));
} else {
// Single-value (with or without reactive type wrapper)
if (logger.isDebugEnabled()) {
logger.debug(exchange.getLogPrefix() + "0..1 [" + elementType + "]");
}
Mono<?> mono = reader.readMono(actualType, elementType, request, response, readHints);
mono = mono.onErrorResume(ex -> Mono.error(handleReadError(bodyParam, ex)));
if (isBodyRequired) {
mono = mono.switchIfEmpty(Mono.error(() -> handleMissingBody(bodyParam)));
}
if (hints != null) {
mono = mono.doOnNext(target -> validate(target, hints, bodyParam, bindingContext, exchange));
}
return (adapter != null ? Mono.just(adapter.fromPublisher(mono)) : Mono.from(mono));
}
}
}
// No compatible reader but body may be empty..
HttpMethod method = request.getMethod();
if (contentType == null && SUPPORTED_METHODS.contains(method)) {
Flux<DataBuffer> body = request.getBody().doOnNext(buffer -> {
DataBufferUtils.release(buffer);
// Body not empty, back toy 415..
throw new UnsupportedMediaTypeStatusException(mediaType, getSupportedMediaTypes(elementType), elementType);
});
if (isBodyRequired) {
body = body.switchIfEmpty(Mono.error(() -> handleMissingBody(bodyParam)));
}
return (adapter != null ? Mono.just(adapter.fromPublisher(body)) : Mono.from(body));
}
return Mono.error(new UnsupportedMediaTypeStatusException(mediaType, getSupportedMediaTypes(elementType), elementType));
}
Aggregations