EchoProperties.java
/*
* Copyright (c) 2007-2026 MetaSolutions AB
*
* 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
*
* http://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.entrystore.rest.springboot.configuration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.bind.DefaultValue;
import org.springframework.util.unit.DataSize;
/**
* Bindings for {@code entrystore.echo.*}, consumed by {@code EchoService} to cap the payload
* {@code POST /echo} will reflect and by {@code StatusService} to report that cap.
*
* <p>The default is the constant this key replaced, so existing deployments see no change. The cap is
* checked against the already-spooled {@code MultipartFile}, so it bounds what is read back into
* memory rather than what is accepted off the wire — {@code spring.servlet.multipart.max-file-size}
* governs the latter and must stay at or above this value for the 413 to come from here rather than
* from Jetty as a 400.
*/
@ConfigurationProperties(prefix = "entrystore.echo")
public record EchoProperties(@DefaultValue("10MB") DataSize maxFileSize) {
/**
* Bounds per-request heap. {@code EchoService} reads the payload back as a UTF-8 {@code String} and
* the response then HTML-escapes it, so peak heap is a multiple of this cap rather than equal to it,
* on an endpoint that is reachable without authentication.
*/
private static final DataSize MAX_FILE_SIZE_CEILING = DataSize.ofMegabytes(64);
public EchoProperties {
if (maxFileSize == null || maxFileSize.toBytes() < 1) {
throw new IllegalArgumentException(
"entrystore.echo.max-file-size must be positive, got " + maxFileSize);
}
if (maxFileSize.compareTo(MAX_FILE_SIZE_CEILING) > 0) {
// Ceiling spelled in MB rather than via DataSize.toString(), which renders raw bytes: the
// operator writes this key as "64MB", so that is what the remedy should read as.
throw new IllegalArgumentException("entrystore.echo.max-file-size must not exceed "
+ MAX_FILE_SIZE_CEILING.toMegabytes() + "MB — the payload is held in memory and "
+ "echoed back, got " + maxFileSize);
}
}
}