/*
* Copyright 2013- Yan Bonnel
*
* 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 fr.ybonnel.simpleweb4j.handlers.webjars;
import fr.ybonnel.simpleweb4j.types.ContentTypes;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.nio.file.Paths;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
/**
* Handler to support webjars.
*/
public class WebjarHandler extends AbstractHandler {
/**
* Size of buffer for copy.
*/
private static final int BUFFER_SIZE = 8192;
/**
* Start time.
*/
private final ZonedDateTime startTime = ZonedDateTime.now();
/**
* Handle a request.
*
* @param target The target of the request - either a URI or a name.
* @param baseRequest The original unwrapped request object.
* @param request The request either as the {@link Request}
* object or a wrapper of that request.
* @param response The response as the {@link org.eclipse.jetty.server.Response}
* object or a wrapper of that request.
* @throws IOException in case of IO error.
*/
@Override
public void handle(String target, Request baseRequest,
HttpServletRequest request, HttpServletResponse response)
throws IOException {
if (baseRequest.isHandled()
|| !baseRequest.getPathInfo().startsWith("/webjars/")) {
return;
}
URL classpathUrl = ClassLoader.getSystemResource("META-INF/resources" + baseRequest.getPathInfo());
if (classpathUrl == null) {
return;
}
baseRequest.setHandled(true);
if (baseRequest.getHeader("if-modified-since") != null) {
// webjar are never modified (version is in path).
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
return;
}
// FIXME Use try with resources when jacoco can handle this correctly
InputStream in = getInputStream(classpathUrl);
try {
OutputStream out = response.getOutputStream();
try {
response.setContentType(ContentTypes.get(Paths.get(baseRequest.getPathInfo())));
response.addHeader("cache-control", "public, max-age=31536000");
response.addHeader("last-modified", startTime.format(DateTimeFormatter.RFC_1123_DATE_TIME));
response.addHeader("expires",
ZonedDateTime.now().plusWeeks(1).format(DateTimeFormatter.RFC_1123_DATE_TIME));
int count;
byte[] buffer = new byte[BUFFER_SIZE];
while ((count = in.read(buffer)) > 0) {
out.write(buffer, 0, count);
}
} finally {
out.close();
}
} finally {
in.close();
}
}
/**
* Open an input stream from an URL.
* @param url url to open.
* @return input stream opened.
* @throws IOException in cas of IO error.
*/
protected InputStream getInputStream(URL url) throws IOException {
return url.openStream();
}
}