Introduce support for Netty 5 Buffer
This commit introduces support for Netty 5's Buffer, in the form of Netty5DataBuffer. Because of the new API offered by Buffer, several changes have been made to the DataBuffer API: - CloseableDataBuffer is a simpler alternative to PooledDataBuffer, and implemented by Netty5DataBuffer. DataBufferUtils::release can now handle CloseableDataBuffer as well as PooledDataBuffer. - PooledDataBuffer::touch has been moved into a separate interface: TouchableDataBuffer, which is implemented by Netty5DataBuffer. - The capacity of DataBuffers can no longer be reduced, they can only grow larger. As a consequence, DataBuffer::capacity(int) has been deprecated, but ensureWritable (formally ensureCapacity) still exists. - DataBuffer::slice and retainedSlice have been deprecated in favor of split, a new method that ensures that memory regions do not overlap. - DataBuffer::asByteBuffer has been deprecated in favor of toByteBuffer, a new method that returns a copy, instead of shared data. - DataBufferFactory::allocateBuffer has been deprecated in favor of allocateBuffer(int). Closes gh-28874
This commit is contained in:
@@ -102,7 +102,7 @@ class HttpComponentsClientHttpRequest extends AbstractClientHttpRequest {
|
||||
@Override
|
||||
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
|
||||
return doCommit(() -> {
|
||||
this.byteBufferFlux = Flux.from(body).map(DataBuffer::asByteBuffer);
|
||||
this.byteBufferFlux = Flux.from(body).map(DataBuffer::toByteBuffer);
|
||||
return Mono.empty();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -122,8 +122,8 @@ class JdkClientHttpRequest extends AbstractClientHttpRequest {
|
||||
|
||||
private HttpRequest.BodyPublisher toBodyPublisher(Publisher<? extends DataBuffer> body) {
|
||||
Publisher<ByteBuffer> byteBufferBody = (body instanceof Mono ?
|
||||
Mono.from(body).map(DataBuffer::asByteBuffer) :
|
||||
Flux.from(body).map(DataBuffer::asByteBuffer));
|
||||
Mono.from(body).map(DataBuffer::toByteBuffer) :
|
||||
Flux.from(body).map(DataBuffer::toByteBuffer));
|
||||
|
||||
Flow.Publisher<ByteBuffer> bodyFlow = JdkFlowAdapter.publisherToFlowPublisher(byteBufferBody);
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@ import reactor.core.publisher.MonoSink;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||
import org.springframework.core.io.buffer.PooledDataBuffer;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -103,7 +102,7 @@ class JettyClientHttpRequest extends AbstractClientHttpRequest {
|
||||
public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
|
||||
return writeWith(Flux.from(body)
|
||||
.flatMap(Function.identity())
|
||||
.doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release));
|
||||
.doOnDiscard(DataBuffer.class, DataBufferUtils::release));
|
||||
}
|
||||
|
||||
private String getContentType() {
|
||||
@@ -112,7 +111,7 @@ class JettyClientHttpRequest extends AbstractClientHttpRequest {
|
||||
}
|
||||
|
||||
private ContentChunk toContentChunk(DataBuffer buffer, MonoSink<Void> sink) {
|
||||
return new ContentChunk(buffer.asByteBuffer(), new Callback() {
|
||||
return new ContentChunk(buffer.toByteBuffer(), new Callback() {
|
||||
@Override
|
||||
public void succeeded() {
|
||||
DataBufferUtils.release(buffer);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -30,7 +30,6 @@ import org.springframework.core.codec.Encoder;
|
||||
import org.springframework.core.codec.Hints;
|
||||
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.HttpLogging;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ReactiveHttpOutputMessage;
|
||||
@@ -135,15 +134,15 @@ public class EncoderHttpMessageWriter<T> implements HttpMessageWriter<T> {
|
||||
Hints.touchDataBuffer(buffer, hints, logger);
|
||||
message.getHeaders().setContentLength(buffer.readableByteCount());
|
||||
return message.writeWith(Mono.just(buffer)
|
||||
.doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release));
|
||||
.doOnDiscard(DataBuffer.class, DataBufferUtils::release));
|
||||
})
|
||||
.doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release);
|
||||
.doOnDiscard(DataBuffer.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);
|
||||
return Mono.just(buffer).doOnDiscard(DataBuffer.class, DataBufferUtils::release);
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -129,7 +129,7 @@ public class FormHttpMessageReader extends LoggingCodecSupport
|
||||
|
||||
return DataBufferUtils.join(message.getBody(), this.maxInMemorySize)
|
||||
.map(buffer -> {
|
||||
CharBuffer charBuffer = charset.decode(buffer.asByteBuffer());
|
||||
CharBuffer charBuffer = charset.decode(buffer.toByteBuffer());
|
||||
String body = charBuffer.toString();
|
||||
DataBufferUtils.release(buffer);
|
||||
MultiValueMap<String, String> formData = parseFormData(charset, body);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -34,7 +34,6 @@ import org.springframework.core.codec.Hints;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||
import org.springframework.core.io.buffer.PooledDataBuffer;
|
||||
import org.springframework.http.HttpLogging;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ReactiveHttpOutputMessage;
|
||||
@@ -159,7 +158,7 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec
|
||||
result = encodeEvent(sb, data, dataType, mediaType, factory, hints);
|
||||
}
|
||||
|
||||
return result.doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release);
|
||||
return result.doOnDiscard(DataBuffer.class, DataBufferUtils::release);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -38,7 +38,6 @@ import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||
import org.springframework.core.io.buffer.PooledDataBuffer;
|
||||
import org.springframework.core.log.LogFormatUtils;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
@@ -197,7 +196,7 @@ public class MultipartHttpMessageWriter extends MultipartWriterSupport
|
||||
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);
|
||||
.doOnDiscard(DataBuffer.class, DataBufferUtils::release);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
body = body.doOnNext(buffer -> Hints.touchDataBuffer(buffer, hints, logger));
|
||||
|
||||
@@ -321,10 +321,10 @@ final class MultipartParser extends BaseSubscriber<DataBuffer> {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("First boundary found @" + endIdx + " in " + buf);
|
||||
}
|
||||
DataBuffer headersBuf = MultipartUtils.sliceFrom(buf, endIdx);
|
||||
DataBufferUtils.release(buf);
|
||||
DataBuffer preambleBuffer = buf.split(endIdx + 1);
|
||||
DataBufferUtils.release(preambleBuffer);
|
||||
|
||||
changeState(this, new HeadersState(), headersBuf);
|
||||
changeState(this, new HeadersState(), buf);
|
||||
}
|
||||
else {
|
||||
DataBufferUtils.release(buf);
|
||||
@@ -390,13 +390,11 @@ final class MultipartParser extends BaseSubscriber<DataBuffer> {
|
||||
}
|
||||
long count = this.byteCount.addAndGet(endIdx);
|
||||
if (belowMaxHeaderSize(count)) {
|
||||
DataBuffer headerBuf = MultipartUtils.sliceTo(buf, endIdx);
|
||||
DataBuffer headerBuf = buf.split(endIdx + 1);
|
||||
this.buffers.add(headerBuf);
|
||||
DataBuffer bodyBuf = MultipartUtils.sliceFrom(buf, endIdx);
|
||||
DataBufferUtils.release(buf);
|
||||
|
||||
emitHeaders(parseHeaders());
|
||||
changeState(this, new BodyState(), bodyBuf);
|
||||
|
||||
changeState(this, new BodyState(), buf);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -514,32 +512,35 @@ final class MultipartParser extends BaseSubscriber<DataBuffer> {
|
||||
* previous buffer, so we calculate the length and slice the current
|
||||
* and previous buffers accordingly. We then change to {@link HeadersState}
|
||||
* and pass on the remainder of {@code buffer}. If the needle is not found, we
|
||||
* make {@code buffer} the previous buffer.
|
||||
* enqueue {@code buffer}.
|
||||
*/
|
||||
@Override
|
||||
public void onNext(DataBuffer buffer) {
|
||||
int endIdx = this.boundary.match(buffer);
|
||||
if (endIdx != -1) {
|
||||
DataBuffer boundaryBuffer = buffer.split(endIdx + 1);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Boundary found @" + endIdx + " in " + buffer);
|
||||
}
|
||||
int len = endIdx - buffer.readPosition() - this.boundaryLength + 1;
|
||||
int len = endIdx - this.boundaryLength + 1;
|
||||
if (len > 0) {
|
||||
// whole boundary in buffer.
|
||||
// slice off the body part, and flush
|
||||
DataBuffer body = buffer.retainedSlice(buffer.readPosition(), len);
|
||||
DataBuffer body = boundaryBuffer.split(len);
|
||||
DataBufferUtils.release(boundaryBuffer);
|
||||
enqueue(body);
|
||||
flush();
|
||||
}
|
||||
else if (len < 0) {
|
||||
// boundary spans multiple buffers, and we've just found the end
|
||||
// iterate over buffers in reverse order
|
||||
DataBufferUtils.release(boundaryBuffer);
|
||||
DataBuffer prev;
|
||||
while ((prev = this.queue.pollLast()) != null) {
|
||||
int prevLen = prev.readableByteCount() + len;
|
||||
if (prevLen > 0) {
|
||||
// slice body part of previous buffer, and flush it
|
||||
DataBuffer body = prev.retainedSlice(prev.readPosition(), prevLen);
|
||||
DataBuffer body = prev.split(prevLen);
|
||||
DataBufferUtils.release(prev);
|
||||
enqueue(body);
|
||||
flush();
|
||||
@@ -557,10 +558,7 @@ final class MultipartParser extends BaseSubscriber<DataBuffer> {
|
||||
flush();
|
||||
}
|
||||
|
||||
DataBuffer remainder = MultipartUtils.sliceFrom(buffer, endIdx);
|
||||
DataBufferUtils.release(buffer);
|
||||
|
||||
changeState(this, new HeadersState(), remainder);
|
||||
changeState(this, new HeadersState(), buffer);
|
||||
}
|
||||
else {
|
||||
enqueue(buffer);
|
||||
|
||||
@@ -23,7 +23,6 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMessage;
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -85,23 +84,6 @@ abstract class MultipartUtils {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Slices the given buffer to the given index (exclusive).
|
||||
*/
|
||||
public static DataBuffer sliceTo(DataBuffer buf, int idx) {
|
||||
int pos = buf.readPosition();
|
||||
int len = idx - pos + 1;
|
||||
return buf.retainedSlice(pos, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Slices the given buffer from the given index (inclusive).
|
||||
*/
|
||||
public static DataBuffer sliceFrom(DataBuffer buf, int idx) {
|
||||
int len = buf.writePosition() - idx - 1;
|
||||
return buf.retainedSlice(idx + 1, len);
|
||||
}
|
||||
|
||||
public static void closeChannel(Channel channel) {
|
||||
try {
|
||||
if (channel.isOpen()) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 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,6 +32,7 @@ import org.springframework.http.MediaType;
|
||||
import org.springframework.http.codec.LoggingCodecSupport;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.FastByteArrayOutputStream;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
@@ -164,22 +165,24 @@ public class MultipartWriterSupport extends LoggingCodecSupport {
|
||||
|
||||
protected Mono<DataBuffer> generatePartHeaders(HttpHeaders headers, DataBufferFactory bufferFactory) {
|
||||
return Mono.fromCallable(() -> {
|
||||
DataBuffer buffer = bufferFactory.allocateBuffer();
|
||||
FastByteArrayOutputStream bos = new FastByteArrayOutputStream();
|
||||
for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
|
||||
byte[] headerName = entry.getKey().getBytes(getCharset());
|
||||
for (String headerValueString : entry.getValue()) {
|
||||
byte[] headerValue = headerValueString.getBytes(getCharset());
|
||||
buffer.write(headerName);
|
||||
buffer.write((byte)':');
|
||||
buffer.write((byte)' ');
|
||||
buffer.write(headerValue);
|
||||
buffer.write((byte)'\r');
|
||||
buffer.write((byte)'\n');
|
||||
bos.write(headerName);
|
||||
bos.write((byte)':');
|
||||
bos.write((byte)' ');
|
||||
bos.write(headerValue);
|
||||
bos.write((byte)'\r');
|
||||
bos.write((byte)'\n');
|
||||
}
|
||||
}
|
||||
buffer.write((byte)'\r');
|
||||
buffer.write((byte)'\n');
|
||||
return buffer;
|
||||
bos.write((byte)'\r');
|
||||
bos.write((byte)'\n');
|
||||
|
||||
byte[] bytes = bos.toByteArrayUnsafe();
|
||||
return bufferFactory.wrap(bytes);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ import org.springframework.core.codec.Hints;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||
import org.springframework.core.io.buffer.PooledDataBuffer;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ReactiveHttpOutputMessage;
|
||||
import org.springframework.http.codec.HttpMessageWriter;
|
||||
@@ -91,7 +90,7 @@ public class PartEventHttpMessageWriter extends MultipartWriterSupport implement
|
||||
}
|
||||
}))
|
||||
.concatWith(generateLastLine(boundary, outputMessage.bufferFactory()))
|
||||
.doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release);
|
||||
.doOnDiscard(DataBuffer.class, DataBufferUtils::release);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
body = body.doOnNext(buffer -> Hints.touchDataBuffer(buffer, hints, logger));
|
||||
|
||||
@@ -729,7 +729,7 @@ final class PartGenerator extends BaseSubscriber<MultipartParser.Token> {
|
||||
@SuppressWarnings("BlockingMethodInNonBlockingContext")
|
||||
private Mono<Void> writeInternal(DataBuffer dataBuffer) {
|
||||
try {
|
||||
ByteBuffer byteBuffer = dataBuffer.asByteBuffer();
|
||||
ByteBuffer byteBuffer = dataBuffer.toByteBuffer();
|
||||
while (byteBuffer.hasRemaining()) {
|
||||
this.channel.write(byteBuffer);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -27,7 +27,6 @@ import org.springframework.core.codec.Hints;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||
import org.springframework.core.io.buffer.PooledDataBuffer;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ReactiveHttpOutputMessage;
|
||||
@@ -67,7 +66,7 @@ public class PartHttpMessageWriter extends MultipartWriterSupport implements Htt
|
||||
Flux<DataBuffer> body = Flux.from(parts)
|
||||
.concatMap(part -> encodePart(boundary, part, outputMessage.bufferFactory()))
|
||||
.concatWith(generateLastLine(boundary, outputMessage.bufferFactory()))
|
||||
.doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release);
|
||||
.doOnDiscard(DataBuffer.class, DataBufferUtils::release);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
body = body.doOnNext(buffer -> Hints.touchDataBuffer(buffer, hints, logger));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -151,7 +151,7 @@ public class ProtobufDecoder extends ProtobufCodecSupport implements Decoder<Mes
|
||||
|
||||
try {
|
||||
Message.Builder builder = getMessageBuilder(targetType.toClass());
|
||||
ByteBuffer buffer = dataBuffer.asByteBuffer();
|
||||
ByteBuffer buffer = dataBuffer.toByteBuffer();
|
||||
builder.mergeFrom(CodedInputStream.newInstance(buffer), this.extensionRegistry);
|
||||
return builder.build();
|
||||
}
|
||||
@@ -236,7 +236,7 @@ public class ProtobufDecoder extends ProtobufCodecSupport implements Decoder<Mes
|
||||
this.messageBytesToRead -= chunkBytesToRead;
|
||||
|
||||
if (this.messageBytesToRead == 0) {
|
||||
CodedInputStream stream = CodedInputStream.newInstance(this.output.asByteBuffer());
|
||||
CodedInputStream stream = CodedInputStream.newInstance(this.output.toByteBuffer());
|
||||
DataBufferUtils.release(this.output);
|
||||
this.output = null;
|
||||
Message message = getMessageBuilder(this.elementType.toClass())
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -30,10 +30,10 @@ import reactor.core.publisher.Mono;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.codec.HttpMessageEncoder;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.FastByteArrayOutputStream;
|
||||
import org.springframework.util.MimeType;
|
||||
|
||||
/**
|
||||
@@ -86,26 +86,20 @@ public class ProtobufEncoder extends ProtobufCodecSupport implements HttpMessage
|
||||
|
||||
private DataBuffer encodeValue(Message message, DataBufferFactory bufferFactory, boolean delimited) {
|
||||
|
||||
DataBuffer buffer = bufferFactory.allocateBuffer();
|
||||
boolean release = true;
|
||||
FastByteArrayOutputStream bos = new FastByteArrayOutputStream();
|
||||
try {
|
||||
if (delimited) {
|
||||
message.writeDelimitedTo(buffer.asOutputStream());
|
||||
message.writeDelimitedTo(bos);
|
||||
}
|
||||
else {
|
||||
message.writeTo(buffer.asOutputStream());
|
||||
message.writeTo(bos);
|
||||
}
|
||||
release = false;
|
||||
return buffer;
|
||||
byte[] bytes = bos.toByteArrayUnsafe();
|
||||
return bufferFactory.wrap(bytes);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException("Unexpected I/O error while writing to data buffer", ex);
|
||||
}
|
||||
finally {
|
||||
if (release) {
|
||||
DataBufferUtils.release(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -33,6 +33,8 @@ import org.springframework.core.codec.DataBufferDecoder;
|
||||
import org.springframework.core.codec.DataBufferEncoder;
|
||||
import org.springframework.core.codec.Decoder;
|
||||
import org.springframework.core.codec.Encoder;
|
||||
import org.springframework.core.codec.Netty5BufferDecoder;
|
||||
import org.springframework.core.codec.Netty5BufferEncoder;
|
||||
import org.springframework.core.codec.NettyByteBufDecoder;
|
||||
import org.springframework.core.codec.NettyByteBufEncoder;
|
||||
import org.springframework.core.codec.ResourceDecoder;
|
||||
@@ -96,6 +98,8 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure
|
||||
|
||||
static final boolean nettyByteBufPresent;
|
||||
|
||||
static final boolean netty5BufferPresent;
|
||||
|
||||
static final boolean kotlinSerializationJsonPresent;
|
||||
|
||||
static {
|
||||
@@ -107,6 +111,7 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure
|
||||
protobufPresent = ClassUtils.isPresent("com.google.protobuf.Message", classLoader);
|
||||
synchronossMultipartPresent = ClassUtils.isPresent("org.synchronoss.cloud.nio.multipart.NioMultipartParser", classLoader);
|
||||
nettyByteBufPresent = ClassUtils.isPresent("io.netty.buffer.ByteBuf", classLoader);
|
||||
netty5BufferPresent = ClassUtils.isPresent("io.netty5.buffer.api.Buffer", classLoader);
|
||||
kotlinSerializationJsonPresent = ClassUtils.isPresent("kotlinx.serialization.json.Json", classLoader);
|
||||
}
|
||||
|
||||
@@ -344,6 +349,9 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure
|
||||
if (nettyByteBufPresent) {
|
||||
addCodec(this.typedReaders, new DecoderHttpMessageReader<>(new NettyByteBufDecoder()));
|
||||
}
|
||||
if (netty5BufferPresent) {
|
||||
addCodec(this.typedReaders, new DecoderHttpMessageReader<>(new Netty5BufferDecoder()));
|
||||
}
|
||||
addCodec(this.typedReaders, new ResourceHttpMessageReader(new ResourceDecoder()));
|
||||
addCodec(this.typedReaders, new DecoderHttpMessageReader<>(StringDecoder.textPlainOnly()));
|
||||
if (protobufPresent) {
|
||||
@@ -557,6 +565,9 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure
|
||||
if (nettyByteBufPresent) {
|
||||
addCodec(writers, new EncoderHttpMessageWriter<>(new NettyByteBufEncoder()));
|
||||
}
|
||||
if (netty5BufferPresent) {
|
||||
addCodec(writers, new EncoderHttpMessageWriter<>(new Netty5BufferEncoder()));
|
||||
}
|
||||
addCodec(writers, new ResourceHttpMessageWriter());
|
||||
addCodec(writers, new EncoderHttpMessageWriter<>(CharSequenceEncoder.textPlainOnly()));
|
||||
if (protobufPresent) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -181,7 +181,7 @@ public class XmlEventDecoder extends AbstractDecoder<XMLEvent> {
|
||||
public List<? extends XMLEvent> apply(DataBuffer dataBuffer) {
|
||||
try {
|
||||
increaseByteCount(dataBuffer);
|
||||
this.streamReader.getInputFeeder().feedInput(dataBuffer.asByteBuffer());
|
||||
this.streamReader.getInputFeeder().feedInput(dataBuffer.toByteBuffer());
|
||||
List<XMLEvent> events = new ArrayList<>();
|
||||
while (true) {
|
||||
if (this.streamReader.next() == AsyncXMLStreamReader.EVENT_INCOMPLETE) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -29,7 +29,6 @@ import reactor.core.publisher.Mono;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||
import org.springframework.core.io.buffer.PooledDataBuffer;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatusCode;
|
||||
import org.springframework.http.ResponseCookie;
|
||||
@@ -190,7 +189,7 @@ public abstract class AbstractServerHttpResponse implements ServerHttpResponse {
|
||||
try {
|
||||
return writeWithInternal(Mono.fromCallable(() -> buffer)
|
||||
.doOnSubscribe(s -> subscribed.set(true))
|
||||
.doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release));
|
||||
.doOnDiscard(DataBuffer.class, DataBufferUtils::release));
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
return Mono.error(ex);
|
||||
@@ -204,7 +203,7 @@ public abstract class AbstractServerHttpResponse implements ServerHttpResponse {
|
||||
});
|
||||
})
|
||||
.doOnError(t -> getHeaders().clearContentHeaders())
|
||||
.doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release);
|
||||
.doOnDiscard(DataBuffer.class, DataBufferUtils::release);
|
||||
}
|
||||
else {
|
||||
return new ChannelSendOperator<>(body, inner -> doCommit(() -> writeWithInternal(inner)))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -135,7 +135,7 @@ public class JettyHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
||||
|
||||
@Override
|
||||
protected int writeToOutputStream(DataBuffer dataBuffer) throws IOException {
|
||||
ByteBuffer input = dataBuffer.asByteBuffer();
|
||||
ByteBuffer input = dataBuffer.toByteBuffer();
|
||||
int len = input.remaining();
|
||||
ServletResponse response = getNativeResponse();
|
||||
((HttpOutput) response.getOutputStream()).write(input);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -39,7 +39,6 @@ import org.apache.coyote.Response;
|
||||
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -136,29 +135,20 @@ public class TomcatHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
||||
// It's possible InputStream can be wrapped, preventing use of CoyoteInputStream
|
||||
return super.readFromInputStream();
|
||||
}
|
||||
boolean release = true;
|
||||
int capacity = this.bufferSize;
|
||||
DataBuffer dataBuffer = this.factory.allocateBuffer(capacity);
|
||||
try {
|
||||
ByteBuffer byteBuffer = dataBuffer.asByteBuffer(0, capacity);
|
||||
int read = coyoteInputStream.read(byteBuffer);
|
||||
logBytesRead(read);
|
||||
if (read > 0) {
|
||||
dataBuffer.writePosition(read);
|
||||
release = false;
|
||||
return dataBuffer;
|
||||
}
|
||||
else if (read == -1) {
|
||||
return EOF_BUFFER;
|
||||
}
|
||||
else {
|
||||
return AbstractListenerReadPublisher.EMPTY_BUFFER;
|
||||
}
|
||||
ByteBuffer byteBuffer = this.factory.isDirect() ?
|
||||
ByteBuffer.allocateDirect(this.bufferSize) :
|
||||
ByteBuffer.allocate(this.bufferSize);
|
||||
|
||||
int read = coyoteInputStream.read(byteBuffer);
|
||||
logBytesRead(read);
|
||||
if (read > 0) {
|
||||
return this.factory.wrap(byteBuffer);
|
||||
}
|
||||
finally {
|
||||
if (release) {
|
||||
DataBufferUtils.release(dataBuffer);
|
||||
}
|
||||
else if (read == -1) {
|
||||
return EOF_BUFFER;
|
||||
}
|
||||
else {
|
||||
return AbstractListenerReadPublisher.EMPTY_BUFFER;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -233,7 +223,7 @@ public class TomcatHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
||||
|
||||
@Override
|
||||
protected int writeToOutputStream(DataBuffer dataBuffer) throws IOException {
|
||||
ByteBuffer input = dataBuffer.asByteBuffer();
|
||||
ByteBuffer input = dataBuffer.toByteBuffer();
|
||||
int len = input.remaining();
|
||||
ServletResponse response = getNativeResponse();
|
||||
((CoyoteOutputStream) response.getOutputStream()).write(input);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -235,7 +235,7 @@ class UndertowServerHttpResponse extends AbstractListenerServerHttpResponse impl
|
||||
@Override
|
||||
protected void dataReceived(DataBuffer dataBuffer) {
|
||||
super.dataReceived(dataBuffer);
|
||||
this.byteBuffer = dataBuffer.asByteBuffer();
|
||||
this.byteBuffer = dataBuffer.toByteBuffer();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user