/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.krakenapps.http.internal.service; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.ServletException; import java.io.IOException; import java.io.File; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; import java.net.URLConnection; public final class ResourceServlet extends HttpServlet { @Override public String toString() { return "ResourceServlet [name=" + path + "]"; } private static final long serialVersionUID = 1L; private final String path; public ResourceServlet(String name) { this.path = name; } @Override protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { String target = req.getPathInfo(); if (target == null) { target = ""; } if (target.equals("")) target = "/index.html"; if (!target.startsWith("/")) { target = "/" + target; } String resName = this.path + target; URL url = getServletContext().getResource(resName); if (url == null) { res.sendError(HttpServletResponse.SC_NOT_FOUND); } else { InputStream is = url.openStream(); boolean exists = is != null; if (exists) is.close(); if (!exists) { res.sendError(HttpServletResponse.SC_NOT_FOUND); return; } handle(req, res, url, resName); } } private void handle(HttpServletRequest req, HttpServletResponse res, URL url, String resName) throws IOException { String contentType = getServletContext().getMimeType(resName); if (contentType != null) { res.setContentType(contentType); } long lastModified = getLastModified(url); if (lastModified != 0) { res.setDateHeader("Last-Modified", lastModified); } if (!resourceModified(lastModified, req.getDateHeader("If-Modified-Since"))) { res.setStatus(HttpServletResponse.SC_NOT_MODIFIED); } else { copyResource(url, res); } } private long getLastModified(URL url) { long lastModified = 0; URLConnection conn = null; try { conn = url.openConnection(); lastModified = conn.getLastModified(); } catch (Exception e) { // Do nothing } finally { // if you do not close URL here, server will hold file exclusively // until GC'd. openConnection succeeded even though the file not // found. if (conn != null) try { conn.getInputStream().close(); } catch (IOException e) { // ignore } } if (lastModified == 0) { String filepath = url.getPath(); if (filepath != null) { File f = new File(filepath); if (f.exists()) { lastModified = f.lastModified(); } } } return lastModified; } private boolean resourceModified(long resTimestamp, long modSince) { modSince /= 1000; resTimestamp /= 1000; return resTimestamp == 0 || modSince == -1 || resTimestamp > modSince; } private void copyResource(URL url, HttpServletResponse res) throws IOException { OutputStream os = null; InputStream is = null; try { os = res.getOutputStream(); is = url.openStream(); int len = 0; byte[] buf = new byte[1024]; int n; while ((n = is.read(buf, 0, buf.length)) >= 0) { os.write(buf, 0, n); len += n; } res.setContentLength(len); } finally { if (is != null) { is.close(); } if (os != null) { os.close(); } } } }