Skip to content

Commit d518a7d

Browse files
committed
AbstractListenerReadPublisher continues after 0 bytes
If we read 0 bytes, e.g. chunked encoding markup read but not the actual data within it, don't stop reading since the server may or may not consider it necessary to call onDataAvailable again. Instead, we keep on reading, and although isReady likely returns false on the next iteration, it eliminates ambiguity and ensures the server will call onDataAvailable when more data arrives. Closes gh-28241
1 parent 24cd3c1 commit d518a7d

File tree

2 files changed

+17
-8
lines changed

2 files changed

+17
-8
lines changed

spring-web/src/main/java/org/springframework/http/server/reactive/AbstractListenerReadPublisher.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -26,6 +26,8 @@
2626
import org.reactivestreams.Subscription;
2727
import reactor.core.publisher.Operators;
2828

29+
import org.springframework.core.io.buffer.DataBuffer;
30+
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
2931
import org.springframework.core.log.LogDelegateFactory;
3032
import org.springframework.lang.Nullable;
3133
import org.springframework.util.Assert;
@@ -56,6 +58,8 @@ public abstract class AbstractListenerReadPublisher<T> implements Publisher<T> {
5658
*/
5759
protected static Log rsReadLogger = LogDelegateFactory.getHiddenLog(AbstractListenerReadPublisher.class);
5860

61+
final static DataBuffer EMPTY_BUFFER = DefaultDataBufferFactory.sharedInstance.allocateBuffer(0);
62+
5963

6064
private final AtomicReference<State> state = new AtomicReference<>(State.UNSUBSCRIBED);
6165

@@ -180,15 +184,20 @@ public final void onError(Throwable ex) {
180184

181185
/**
182186
* Read and publish data one at a time until there is no more data, no more
183-
* demand, or perhaps we completed in the mean time.
187+
* demand, or perhaps we completed meanwhile.
184188
* @return {@code true} if there is more demand; {@code false} if there is
185189
* no more demand or we have completed.
186190
*/
187191
private boolean readAndPublish() throws IOException {
188192
long r;
189193
while ((r = this.demand) > 0 && (this.state.get() != State.COMPLETED)) {
190194
T data = read();
191-
if (data != null) {
195+
if (data == EMPTY_BUFFER) {
196+
if (rsReadLogger.isTraceEnabled()) {
197+
rsReadLogger.trace(getLogPrefix() + "0 bytes read, trying again");
198+
}
199+
}
200+
else if (data != null) {
192201
if (r != Long.MAX_VALUE) {
193202
DEMAND_FIELD_UPDATER.addAndGet(this, -1L);
194203
}

spring-web/src/main/java/org/springframework/http/server/reactive/ServletServerHttpRequest.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -236,10 +236,10 @@ AsyncListener getAsyncListener() {
236236
/**
237237
* Read from the request body InputStream and return a DataBuffer.
238238
* Invoked only when {@link ServletInputStream#isReady()} returns "true".
239-
* @return a DataBuffer with data read, or {@link #EOF_BUFFER} if the input
240-
* stream returned -1, or null if 0 bytes were read.
239+
* @return a DataBuffer with data read, or
240+
* {@link AbstractListenerReadPublisher#EMPTY_BUFFER} if 0 bytes were read,
241+
* or {@link #EOF_BUFFER} if the input stream returned -1.
241242
*/
242-
@Nullable
243243
DataBuffer readFromInputStream() throws IOException {
244244
int read = this.request.getInputStream().read(this.buffer);
245245
logBytesRead(read);
@@ -254,7 +254,7 @@ DataBuffer readFromInputStream() throws IOException {
254254
return EOF_BUFFER;
255255
}
256256

257-
return null;
257+
return AbstractListenerReadPublisher.EMPTY_BUFFER;
258258
}
259259

260260
protected final void logBytesRead(int read) {

0 commit comments

Comments
 (0)