[FIX][CRITICAL] Замена SimpleDateFormat на thread-safe DateTimeFormatter

This commit is contained in:
Gravit 2020-09-26 04:01:36 +07:00
parent 92df57e491
commit d7519688ee
No known key found for this signature in database
GPG key ID: 98A079490768CCE5
2 changed files with 17 additions and 13 deletions

View file

@ -17,9 +17,9 @@ public static void setUsingEpoll(boolean value) {
public static EventLoopGroup newEventLoopGroup(int threads, String poolName) {
if (epoll)
return new EpollEventLoopGroup(threads, new NettyThreadFactory(poolName));
return new EpollEventLoopGroup(threads);
else
return new NioEventLoopGroup(threads, new NettyThreadFactory(poolName));
return new NioEventLoopGroup(threads);
}
public static ChannelFactory<? extends ServerChannel> getServerSocketChannelFactory() {

View file

@ -17,6 +17,12 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.time.Clock;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.*;
import java.util.*;
import java.util.regex.Pattern;
@ -26,7 +32,7 @@
public class FileServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
public static final SimpleDateFormat dateFormatter;
public static final DateTimeFormatter dateFormatter;
public static final String READ = "r";
public static final int HTTP_CACHE_SECONDS = VerifyHelper.verifyInt(Integer.parseInt(System.getProperty("launcher.fileserver.cachesec", "60")), VerifyHelper.NOT_NEGATIVE, "HttpCache seconds should be positive");
private static final boolean OLD_ALGO = Boolean.parseBoolean(System.getProperty("launcher.fileserver.oldalgo", "true"));
@ -34,8 +40,7 @@ public class FileServerHandler extends SimpleChannelInboundHandler<FullHttpReque
private static final Pattern ALLOWED_FILE_NAME = Pattern.compile("[^-\\._]?[^<>&\\\"]*");
static {
dateFormatter = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT"));
dateFormatter = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US).withZone(ZoneId.of("UTC"));
}
private final Path base;
@ -128,7 +133,7 @@ private static void sendNotModified(ChannelHandlerContext ctx) {
* @param response HTTP response
*/
private static void setDateHeader(FullHttpResponse response) {
response.headers().set(HttpHeaderNames.DATE, dateFormatter.format(new Date(System.currentTimeMillis())));
response.headers().set(HttpHeaderNames.DATE, dateFormatter.format(Instant.ofEpochMilli(System.currentTimeMillis())));
}
/**
@ -139,15 +144,14 @@ private static void setDateHeader(FullHttpResponse response) {
*/
private static void setDateAndCacheHeaders(HttpResponse response, File fileToCache) {
// Date header
Calendar time = new GregorianCalendar();
response.headers().set(HttpHeaderNames.DATE, dateFormatter.format(time.getTime()));
LocalDateTime time = LocalDateTime.now(Clock.systemUTC());
response.headers().set(HttpHeaderNames.DATE, dateFormatter.format(time));
// Add cache headers
time.add(Calendar.SECOND, HTTP_CACHE_SECONDS);
response.headers().set(HttpHeaderNames.EXPIRES, dateFormatter.format(time.getTime()));
response.headers().set(HttpHeaderNames.EXPIRES, dateFormatter.format(time.plus(HTTP_CACHE_SECONDS, ChronoUnit.SECONDS)));
response.headers().set(HttpHeaderNames.CACHE_CONTROL, "private, max-age=" + HTTP_CACHE_SECONDS);
response.headers().set(
HttpHeaderNames.LAST_MODIFIED, dateFormatter.format(new Date(fileToCache.lastModified())));
HttpHeaderNames.LAST_MODIFIED, dateFormatter.format(Instant.ofEpochMilli(fileToCache.lastModified())));
}
/**
@ -209,11 +213,11 @@ public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) thr
// Cache Validation
String ifModifiedSince = request.headers().get(HttpHeaderNames.IF_MODIFIED_SINCE);
if (ifModifiedSince != null && !ifModifiedSince.isEmpty()) {
Date ifModifiedSinceDate = dateFormatter.parse(ifModifiedSince);
TemporalAccessor ifModifiedSinceDate = dateFormatter.parse(ifModifiedSince);
// Only compare up to the second because the datetime format we send to the client
// does not have milliseconds
long ifModifiedSinceDateSeconds = ifModifiedSinceDate.getTime() / 1000;
long ifModifiedSinceDateSeconds = ifModifiedSinceDate.get(ChronoField.INSTANT_SECONDS);
long fileLastModifiedSeconds = file.lastModified() / 1000;
if (ifModifiedSinceDateSeconds == fileLastModifiedSeconds) {
sendNotModified(ctx);