package com.vtence.molecule.middlewares;
import com.vtence.molecule.Request;
import com.vtence.molecule.Response;
import com.vtence.molecule.http.HttpDate;
import com.vtence.molecule.http.HttpMethod;
import java.time.Instant;
import java.util.function.Consumer;
import static com.vtence.molecule.http.HeaderNames.CONTENT_LENGTH;
import static com.vtence.molecule.http.HeaderNames.CONTENT_TYPE;
import static com.vtence.molecule.http.HeaderNames.ETAG;
import static com.vtence.molecule.http.HeaderNames.IF_MODIFIED_SINCE;
import static com.vtence.molecule.http.HeaderNames.IF_NONE_MATCH;
import static com.vtence.molecule.http.HeaderNames.LAST_MODIFIED;
import static com.vtence.molecule.http.HttpMethod.GET;
import static com.vtence.molecule.http.HttpMethod.HEAD;
import static com.vtence.molecule.http.HttpStatus.NOT_MODIFIED;
import static com.vtence.molecule.http.HttpStatus.OK;
import static com.vtence.molecule.lib.BinaryBody.empty;
public class ConditionalGet extends AbstractMiddleware {
public void handle(Request request, Response response) throws Exception {
forward(request, response).whenSuccessful(conditionalGet(request));
}
private Consumer<Response> conditionalGet(Request request) {
return response -> {
if (supported(request.method()) && ok(response) && stillFresh(request, response)) {
response.body(empty());
response.removeHeader(CONTENT_TYPE);
response.removeHeader(CONTENT_LENGTH);
response.status(NOT_MODIFIED);
}
};
}
private boolean supported(HttpMethod method) {
return method == GET || method == HEAD;
}
private boolean ok(Response response) {
return response.statusCode() == OK.code;
}
private boolean stillFresh(Request request, Response response) {
String etag = request.header(IF_NONE_MATCH);
Instant lastTimeSeen = parseDate(request.header(IF_MODIFIED_SINCE));
if (etag == null && lastTimeSeen == null) return false;
if (lastTimeSeen != null && modifiedSince(lastTimeSeen, response)) return false;
if (etag != null && !current(etag, response)) return false;
return true;
}
private Instant parseDate(String date) {
if (date == null) return null;
try {
return HttpDate.parse(date);
} catch (IllegalArgumentException unsupportedDateFormat) {
return null;
}
}
private boolean modifiedSince(Instant modifiedSince, Response response) {
Instant lastModified = parseDate(response.header(LAST_MODIFIED));
return !modifiedSince.equals(lastModified);
}
private boolean current(String noneMatch, Response response) {
String etag = response.header(ETAG);
return (etag != null) && etag.equals(noneMatch);
}
}