Browse Source

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
pull/32201/head
Arjen Poutsma 2 years ago
parent
commit
c570f3b2da
  1. 33
      spring-web/src/main/java/org/springframework/http/codec/multipart/PartEventHttpMessageReader.java
  2. 1
      spring-web/src/test/java/org/springframework/http/codec/multipart/PartEventHttpMessageReaderTests.java

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

@ -155,29 +155,22 @@ public class PartEventHttpMessageReader extends LoggingCodecSupport implements H @@ -155,29 +155,22 @@ public class PartEventHttpMessageReader extends LoggingCodecSupport implements H
AtomicInteger partCount = new AtomicInteger();
return allPartsTokens
.windowUntil(t -> t instanceof MultipartParser.HeadersToken, true)
.concatMap(partTokens -> {
if (tooManyParts(partCount)) {
return Mono.error(new DecodingException("Too many parts (" + partCount.get() + "/" +
this.maxParts + " allowed)"));
}
else {
return partTokens.switchOnFirst((signal, flux) -> {
if (signal.hasValue()) {
MultipartParser.HeadersToken headersToken = (MultipartParser.HeadersToken) signal.get();
Assert.state(headersToken != null, "Signal should be headers token");
HttpHeaders headers = headersToken.headers();
Flux<MultipartParser.BodyToken> bodyTokens = flux.ofType(
MultipartParser.BodyToken.class);
return createEvents(headers, bodyTokens);
}
else {
.concatMap(partTokens -> partTokens
.switchOnFirst((signal, flux) -> {
if (!signal.hasValue()) {
// complete or error signal
return flux.cast(PartEvent.class);
}
});
}
});
else if (tooManyParts(partCount)) {
return Mono.error(new DecodingException("Too many parts (" + partCount.get() +
"/" + this.maxParts + " allowed)"));
}
MultipartParser.HeadersToken headersToken = (MultipartParser.HeadersToken) signal.get();
Assert.state(headersToken != null, "Signal should be headers token");
HttpHeaders headers = headersToken.headers();
return createEvents(headers, flux.ofType(MultipartParser.BodyToken.class));
}));
});
}

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

@ -238,6 +238,7 @@ class PartEventHttpMessageReaderTests { @@ -238,6 +238,7 @@ class PartEventHttpMessageReaderTests {
Flux<PartEvent> result = reader.read(forClass(PartEvent.class), request, emptyMap());
StepVerifier.create(result)
.assertNext(form(headers -> assertThat(headers).isEmpty(), "This is implicitly typed plain ASCII text.\r\nIt does NOT end with a linebreak."))
.expectError(DecodingException.class)
.verify();
}

Loading…
Cancel
Save