-
Notifications
You must be signed in to change notification settings - Fork 38.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Add maxInMemorySize property to Decoder and HttpMessageReader implementations that aggregate input to trigger DataBufferLimitException when reached. - For codecs that call DataBufferUtils#join, there is now an overloaded variant with a maxInMemorySize extra argument. Internally, a custom LimitedDataBufferList is used to count and enforce the limit. - Jackson2Tokenizer and XmlEventDecoder support those limits per streamed JSON object. See gh-23884
- Loading branch information
1 parent
ce0b012
commit 89d053d
Showing
16 changed files
with
672 additions
and
68 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
37 changes: 37 additions & 0 deletions
37
spring-core/src/main/java/org/springframework/core/io/buffer/DataBufferLimitException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/* | ||
* Copyright 2002-2019 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. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package org.springframework.core.io.buffer; | ||
|
||
/** | ||
* Exception that indicates the cumulative number of bytes consumed from a | ||
* stream of {@link DataBuffer DataBuffer}'s exceeded some pre-configured limit. | ||
* This can be raised when data buffers are cached and aggregated, e.g. | ||
* {@link DataBufferUtils#join}. Or it could also be raised when data buffers | ||
* have been released but a parsed representation is being aggregated, e.g. async | ||
* parsing with Jackson. | ||
* | ||
* @author Rossen Stoyanchev | ||
* @since 5.1.11 | ||
*/ | ||
@SuppressWarnings("serial") | ||
public class DataBufferLimitException extends IllegalStateException { | ||
|
||
|
||
public DataBufferLimitException(String message) { | ||
super(message); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
157 changes: 157 additions & 0 deletions
157
spring-core/src/main/java/org/springframework/core/io/buffer/LimitedDataBufferList.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
/* | ||
* Copyright 2002-2019 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. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package org.springframework.core.io.buffer; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collection; | ||
import java.util.List; | ||
import java.util.function.Predicate; | ||
|
||
import reactor.core.publisher.Flux; | ||
|
||
/** | ||
* Custom {@link List} to collect data buffers with and enforce a | ||
* limit on the total number of bytes buffered. For use with "collect" or | ||
* other buffering operators in declarative APIs, e.g. {@link Flux}. | ||
* | ||
* <p>Adding elements increases the byte count and if the limit is exceeded, | ||
* {@link DataBufferLimitException} is raised. {@link #clear()} resets the | ||
* count. Remove and set are not supported. | ||
* | ||
* <p><strong>Note:</strong> This class does not automatically release the | ||
* buffers it contains. It is usually preferable to use hooks such as | ||
* {@link Flux#doOnDiscard} that also take care of cancel and error signals, | ||
* or otherwise {@link #releaseAndClear()} can be used. | ||
* | ||
* @author Rossen Stoyanchev | ||
* @since 5.1.11 | ||
*/ | ||
@SuppressWarnings("serial") | ||
public class LimitedDataBufferList extends ArrayList<DataBuffer> { | ||
|
||
private final int maxByteCount; | ||
|
||
private int byteCount; | ||
|
||
|
||
public LimitedDataBufferList(int maxByteCount) { | ||
this.maxByteCount = maxByteCount; | ||
} | ||
|
||
|
||
@Override | ||
public boolean add(DataBuffer buffer) { | ||
boolean result = super.add(buffer); | ||
if (result) { | ||
updateCount(buffer.readableByteCount()); | ||
} | ||
return result; | ||
} | ||
|
||
@Override | ||
public void add(int index, DataBuffer buffer) { | ||
super.add(index, buffer); | ||
updateCount(buffer.readableByteCount()); | ||
} | ||
|
||
@Override | ||
public boolean addAll(Collection<? extends DataBuffer> collection) { | ||
boolean result = super.addAll(collection); | ||
collection.forEach(buffer -> updateCount(buffer.readableByteCount())); | ||
return result; | ||
} | ||
|
||
@Override | ||
public boolean addAll(int index, Collection<? extends DataBuffer> collection) { | ||
boolean result = super.addAll(index, collection); | ||
collection.forEach(buffer -> updateCount(buffer.readableByteCount())); | ||
return result; | ||
} | ||
|
||
private void updateCount(int bytesToAdd) { | ||
if (this.maxByteCount < 0) { | ||
return; | ||
} | ||
if (bytesToAdd > Integer.MAX_VALUE - this.byteCount) { | ||
raiseLimitException(); | ||
} | ||
else { | ||
this.byteCount += bytesToAdd; | ||
if (this.byteCount > this.maxByteCount) { | ||
raiseLimitException(); | ||
} | ||
} | ||
} | ||
|
||
private void raiseLimitException() { | ||
// Do not release here, it's likely down via doOnDiscard.. | ||
throw new DataBufferLimitException( | ||
"Exceeded limit on max bytes to buffer : " + this.maxByteCount); | ||
} | ||
|
||
@Override | ||
public DataBuffer remove(int index) { | ||
throw new UnsupportedOperationException(); | ||
} | ||
|
||
@Override | ||
public boolean remove(Object o) { | ||
throw new UnsupportedOperationException(); | ||
} | ||
|
||
@Override | ||
protected void removeRange(int fromIndex, int toIndex) { | ||
throw new UnsupportedOperationException(); | ||
} | ||
|
||
@Override | ||
public boolean removeAll(Collection<?> c) { | ||
throw new UnsupportedOperationException(); | ||
} | ||
|
||
@Override | ||
public boolean removeIf(Predicate<? super DataBuffer> filter) { | ||
throw new UnsupportedOperationException(); | ||
} | ||
|
||
@Override | ||
public DataBuffer set(int index, DataBuffer element) { | ||
throw new UnsupportedOperationException(); | ||
} | ||
|
||
@Override | ||
public void clear() { | ||
this.byteCount = 0; | ||
super.clear(); | ||
} | ||
|
||
/** | ||
* Shortcut to {@link DataBufferUtils#release release} all data buffers and | ||
* then {@link #clear()}. | ||
*/ | ||
public void releaseAndClear() { | ||
forEach(buf -> { | ||
try { | ||
DataBufferUtils.release(buf); | ||
} | ||
catch (Throwable ex) { | ||
// Keep going.. | ||
} | ||
}); | ||
clear(); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.