Skip to content

Commit c570f3b

Browse files
committed
Fix off-by-one error in PartEvent part count
This commit fixes an off-by-one error in the PartEventHttpMessageReader, so that it no longer counts empty windows. Closes gh-32122
1 parent 0fdf759 commit c570f3b

File tree

2 files changed

+14
-20
lines changed

2 files changed

+14
-20
lines changed

spring-web/src/main/java/org/springframework/http/codec/multipart/PartEventHttpMessageReader.java

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -155,29 +155,22 @@ public Flux<PartEvent> read(ResolvableType elementType, ReactiveHttpInputMessage
155155
AtomicInteger partCount = new AtomicInteger();
156156
return allPartsTokens
157157
.windowUntil(t -> t instanceof MultipartParser.HeadersToken, true)
158-
.concatMap(partTokens -> {
159-
if (tooManyParts(partCount)) {
160-
return Mono.error(new DecodingException("Too many parts (" + partCount.get() + "/" +
161-
this.maxParts + " allowed)"));
162-
}
163-
else {
164-
return partTokens.switchOnFirst((signal, flux) -> {
165-
if (signal.hasValue()) {
166-
MultipartParser.HeadersToken headersToken = (MultipartParser.HeadersToken) signal.get();
167-
Assert.state(headersToken != null, "Signal should be headers token");
168-
169-
HttpHeaders headers = headersToken.headers();
170-
Flux<MultipartParser.BodyToken> bodyTokens = flux.ofType(
171-
MultipartParser.BodyToken.class);
172-
return createEvents(headers, bodyTokens);
173-
}
174-
else {
158+
.concatMap(partTokens -> partTokens
159+
.switchOnFirst((signal, flux) -> {
160+
if (!signal.hasValue()) {
175161
// complete or error signal
176162
return flux.cast(PartEvent.class);
177163
}
178-
});
179-
}
180-
});
164+
else if (tooManyParts(partCount)) {
165+
return Mono.error(new DecodingException("Too many parts (" + partCount.get() +
166+
"/" + this.maxParts + " allowed)"));
167+
}
168+
MultipartParser.HeadersToken headersToken = (MultipartParser.HeadersToken) signal.get();
169+
Assert.state(headersToken != null, "Signal should be headers token");
170+
171+
HttpHeaders headers = headersToken.headers();
172+
return createEvents(headers, flux.ofType(MultipartParser.BodyToken.class));
173+
}));
181174
});
182175
}
183176

spring-web/src/test/java/org/springframework/http/codec/multipart/PartEventHttpMessageReaderTests.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ void tooManyParts() {
238238
Flux<PartEvent> result = reader.read(forClass(PartEvent.class), request, emptyMap());
239239

240240
StepVerifier.create(result)
241+
.assertNext(form(headers -> assertThat(headers).isEmpty(), "This is implicitly typed plain ASCII text.\r\nIt does NOT end with a linebreak."))
241242
.expectError(DecodingException.class)
242243
.verify();
243244
}

0 commit comments

Comments
 (0)