NIHVIVO-3484 If an expected image file is not found, serve the "missing link" image instead.
This commit is contained in:
parent
a1a2771a05
commit
b223feedb2
2 changed files with 84 additions and 45 deletions
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
package edu.cornell.mannlib.vitro.webapp.filestorage.serving;
|
package edu.cornell.mannlib.vitro.webapp.filestorage.serving;
|
||||||
|
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
|
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
|
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
|
@ -23,6 +21,7 @@ import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet;
|
import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
||||||
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorage;
|
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorage;
|
||||||
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorageSetup;
|
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorageSetup;
|
||||||
import edu.cornell.mannlib.vitro.webapp.filestorage.model.FileInfo;
|
import edu.cornell.mannlib.vitro.webapp.filestorage.model.FileInfo;
|
||||||
|
@ -48,6 +47,9 @@ import edu.cornell.mannlib.vitro.webapp.filestorage.model.FileInfo;
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
public class FileServingServlet extends VitroHttpServlet {
|
public class FileServingServlet extends VitroHttpServlet {
|
||||||
|
/** If we can't locate the requested image, use this one instead. */
|
||||||
|
private static final String PATH_MISSING_LINK_IMAGE = "/images/missingLink.png";
|
||||||
|
|
||||||
private static final Log log = LogFactory.getLog(FileServingServlet.class);
|
private static final Log log = LogFactory.getLog(FileServingServlet.class);
|
||||||
|
|
||||||
private FileStorage fileStorage;
|
private FileStorage fileStorage;
|
||||||
|
@ -78,46 +80,28 @@ public class FileServingServlet extends VitroHttpServlet {
|
||||||
String path = request.getServletPath() + request.getPathInfo();
|
String path = request.getServletPath() + request.getPathInfo();
|
||||||
log.debug("Path is '" + path + "'");
|
log.debug("Path is '" + path + "'");
|
||||||
|
|
||||||
FileInfo fileInfo = FileInfo.instanceFromAliasUrl(
|
/*
|
||||||
request.getFullWebappDaoFactory(), path, getServletContext());
|
* Get the mime type and an InputStream from the file. If we can't, use
|
||||||
log.debug("File info is '" + fileInfo + "'");
|
* the dummy image file instead.
|
||||||
if (fileInfo == null) {
|
*/
|
||||||
String message = "The request path is not valid for the File servlet: '"
|
|
||||||
+ path + "'";
|
|
||||||
log.error(message);
|
|
||||||
response.sendError(SC_INTERNAL_SERVER_ERROR, message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate that the file exists, with the requested URI and filename.
|
|
||||||
String requestedFilename = getFilename(path);
|
|
||||||
String actualFilename = fileInfo.getFilename();
|
|
||||||
if (!actualFilename.equals(requestedFilename)
|
|
||||||
&& !actualFilename.equals(decode(requestedFilename))) {
|
|
||||||
log.warn("The requested filename does not match the "
|
|
||||||
+ "actual filename; request: '" + path + "', actual: '"
|
|
||||||
+ actualFilename + "'");
|
|
||||||
response.sendError(SC_NOT_FOUND, ("File not found: " + path));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the MIME type.
|
|
||||||
String mimeType = fileInfo.getMimeType();
|
|
||||||
|
|
||||||
// Open the actual byte stream.
|
|
||||||
InputStream in;
|
InputStream in;
|
||||||
|
String mimeType = null;
|
||||||
try {
|
try {
|
||||||
in = fileStorage.getInputStream(fileInfo.getBytestreamUri(),
|
FileInfo fileInfo = figureFileInfo(
|
||||||
actualFilename);
|
request.getFullWebappDaoFactory(), path);
|
||||||
} catch (FileNotFoundException e) {
|
mimeType = fileInfo.getMimeType();
|
||||||
log.error("Expected file doesn't exist: " + e);
|
|
||||||
response.sendError(SC_INTERNAL_SERVER_ERROR, e.toString());
|
String actualFilename = findAndValidateFilename(fileInfo, path);
|
||||||
return;
|
|
||||||
|
in = openImageInputStream(fileInfo, actualFilename);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("Failed to serve the file at '" + path + "' -- " + e.getMessage());
|
||||||
|
in = openMissingLinkImage(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Everything is ready and working. Set the status and the content type,
|
* Everything is ready. Set the status and the content type, and send
|
||||||
* and send the image bytes.
|
* the image bytes.
|
||||||
*/
|
*/
|
||||||
response.setStatus(SC_OK);
|
response.setStatus(SC_OK);
|
||||||
|
|
||||||
|
@ -149,10 +133,36 @@ public class FileServingServlet extends VitroHttpServlet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private FileInfo figureFileInfo(WebappDaoFactory fullWadf, String path)
|
||||||
* The filename is the portion of the path after the last slash.
|
throws FileServingException {
|
||||||
*/
|
FileInfo fileInfo = FileInfo.instanceFromAliasUrl(fullWadf, path,
|
||||||
private String getFilename(String path) {
|
getServletContext());
|
||||||
|
if (fileInfo == null) {
|
||||||
|
throw new FileServingException("The request path is not valid "
|
||||||
|
+ "for the File servlet: '" + path + "'");
|
||||||
|
}
|
||||||
|
log.debug("File info is '" + fileInfo + "'");
|
||||||
|
return fileInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Validate that the file exists, with the requested URI and filename. */
|
||||||
|
private String findAndValidateFilename(FileInfo fileInfo, String path)
|
||||||
|
throws FileServingException {
|
||||||
|
String requestedFilename = figureFilename(path);
|
||||||
|
String actualFilename = fileInfo.getFilename();
|
||||||
|
if (!actualFilename.equals(requestedFilename)
|
||||||
|
&& !actualFilename.equals(decode(requestedFilename))) {
|
||||||
|
throw new FileServingException(
|
||||||
|
"The requested filename does not match the "
|
||||||
|
+ "actual filename; request: '" + path
|
||||||
|
+ "', actual: '" + actualFilename + "'");
|
||||||
|
}
|
||||||
|
log.debug("Actual filename is '" + actualFilename + "'");
|
||||||
|
return actualFilename;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The filename is the portion of the path after the last slash. */
|
||||||
|
private String figureFilename(String path) {
|
||||||
int slashHere = path.lastIndexOf('/');
|
int slashHere = path.lastIndexOf('/');
|
||||||
if (slashHere == -1) {
|
if (slashHere == -1) {
|
||||||
return path;
|
return path;
|
||||||
|
@ -161,18 +171,34 @@ public class FileServingServlet extends VitroHttpServlet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** The filename may have been encoded for URL transfer. */
|
||||||
* The filename may have been encoded for URL transfer.
|
|
||||||
*/
|
|
||||||
private String decode(String filename) {
|
private String decode(String filename) {
|
||||||
try {
|
try {
|
||||||
return URLDecoder.decode(filename, "UTF-8");
|
return URLDecoder.decode(filename, "UTF-8");
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
log.error("How did this happen?", e);
|
log.error("No UTF-8 decoder? How did this happen?", e);
|
||||||
return filename;
|
return filename;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private InputStream openImageInputStream(FileInfo fileInfo,
|
||||||
|
String actualFilename) throws IOException {
|
||||||
|
return fileStorage.getInputStream(fileInfo.getBytestreamUri(),
|
||||||
|
actualFilename);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Any suprises when opening the image? Use this one instead. */
|
||||||
|
private InputStream openMissingLinkImage(VitroRequest vreq)
|
||||||
|
throws FileNotFoundException {
|
||||||
|
InputStream stream = vreq.getSession().getServletContext()
|
||||||
|
.getResourceAsStream(PATH_MISSING_LINK_IMAGE);
|
||||||
|
if (stream == null) {
|
||||||
|
throw new FileNotFoundException("No image file at '"
|
||||||
|
+ PATH_MISSING_LINK_IMAGE + "'");
|
||||||
|
}
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A POST request is treated the same as a GET request.
|
* A POST request is treated the same as a GET request.
|
||||||
*/
|
*/
|
||||||
|
@ -182,4 +208,17 @@ public class FileServingServlet extends VitroHttpServlet {
|
||||||
doGet(request, response);
|
doGet(request, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* There was a problem serving the file bytestream.
|
||||||
|
*/
|
||||||
|
private static class FileServingException extends Exception {
|
||||||
|
public FileServingException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileServingException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
BIN
webapp/web/images/missingLink.png
Normal file
BIN
webapp/web/images/missingLink.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.6 KiB |
Loading…
Add table
Add a link
Reference in a new issue