package io.vertx.ext.web.impl;
import io.vertx.core.MultiMap;
import io.vertx.core.http.HttpHeaders;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.ext.web.RoutingContext;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.regex.Pattern;
public class Utils extends io.vertx.core.impl.Utils {
public static ClassLoader getClassLoader() {
ClassLoader tccl = Thread.currentThread().getContextClassLoader();
return tccl == null ? Utils.class.getClassLoader() : tccl;
}
private static final ZoneId ZONE_GMT = ZoneId.of("GMT");
public static String formatRFC1123DateTime(final long time) {
return DateTimeFormatter.RFC_1123_DATE_TIME.format(Instant.ofEpochMilli(time).atZone(ZONE_GMT));
}
public static long parseRFC1123DateTime(final String header) {
try {
return header == null || header.isEmpty() ? -1 :
LocalDateTime.parse(header, DateTimeFormatter.RFC_1123_DATE_TIME).toInstant(ZoneOffset.UTC).toEpochMilli();
} catch (DateTimeParseException ex) {
return -1;
}
}
public static String pathOffset(String path, RoutingContext context) {
final String rest = context.pathParam("*");
if (rest != null) {
if (rest.length() > 0) {
if (rest.charAt(0) == '/') {
return rest;
} else {
return "/" + rest;
}
} else {
return "/";
}
}
int prefixLen = 0;
String mountPoint = context.mountPoint();
if (mountPoint != null) {
prefixLen = mountPoint.length();
if (mountPoint.charAt(mountPoint.length() - 1) == '/') {
prefixLen--;
}
}
String routePath = context.currentRoute().getPath();
if (routePath != null) {
prefixLen += routePath.length();
if (routePath.charAt(routePath.length() - 1) == '/') {
prefixLen--;
}
}
return prefixLen != 0 ? path.substring(prefixLen) : path;
}
public static long secondsFactor(long millis) {
return millis - (millis % 1000);
}
public static boolean isJsonContentType(String contentType) {
return contentType.contains("application/json") || contentType.contains("+json");
}
public static boolean isXMLContentType(String contentType) {
return contentType.contains("application/xml") || contentType.contains("text/xml") || contentType.contains("+xml");
}
public static void addToMapIfAbsent(MultiMap map, CharSequence key, CharSequence value) {
if (!map.contains(key)) {
map.set(key, value);
}
}
public static void appendToMapIfAbsent(MultiMap map, CharSequence key, CharSequence sep, CharSequence value) {
if (!map.contains(key)) {
map.set(key, value);
} else {
String existing = map.get(key);
map.set(key, existing + sep + value);
}
}
private static final Pattern CACHE_CONTROL_NO_CACHE_REGEXP = Pattern.compile("(?:^|,)\\s*?no-cache\\s*?(?:,|$)");
public static boolean fresh(RoutingContext ctx) {
return fresh(ctx, -1);
}
public static boolean fresh(RoutingContext ctx, long lastModified) {
final HttpServerRequest req = ctx.request();
final HttpServerResponse res = ctx.response();
final String modifiedSince = req.getHeader(HttpHeaders.IF_MODIFIED_SINCE);
final String noneMatch = req.getHeader(HttpHeaders.IF_NONE_MATCH);
if (modifiedSince == null && noneMatch == null) {
return false;
}
final String cacheControl = req.getHeader(HttpHeaders.CACHE_CONTROL);
if (cacheControl != null && CACHE_CONTROL_NO_CACHE_REGEXP.matcher(cacheControl).find()) {
return false;
}
if (noneMatch != null && !"*".equals(noneMatch)) {
final String etag = res.headers().get(HttpHeaders.ETAG);
if (etag == null) {
return false;
}
boolean etagStale = true;
int end = 0;
int start = 0;
loop: for (int i = 0; i < noneMatch.length(); i++) {
switch (noneMatch.charAt(i)) {
case ' ':
if (start == end) {
start = end = i + 1;
}
break;
case ',':
String match = noneMatch.substring(start, end);
if (match.equals(etag) || match.equals("W/" + etag) || ("W/" + match).equals(etag)) {
etagStale = false;
break loop;
}
start = end = i + 1;
break;
default:
end = i + 1;
break;
}
}
if (etagStale) {
return false;
}
}
if (modifiedSince != null) {
if (lastModified == -1) {
lastModified = parseRFC1123DateTime(res.headers().get(HttpHeaders.LAST_MODIFIED));
}
boolean modifiedStale = lastModified == -1 || !(lastModified <= parseRFC1123DateTime(modifiedSince));
return !modifiedStale;
}
return true;
}
}