/* Reattore HTTP Server
Copyright (C) 2002 Michael Hope <michaelh@juju.net.nz>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
$Id: FileInterceptor.java,v 1.18 2003/03/05 04:31:57 michaelh Exp $
*/
package juju.reattore.server.intercept.impl;
import java.io.*;
import java.util.*;
import org.apache.commons.logging.*;
import juju.reattore.protocol.http.*;
import juju.reattore.server.intercept.Interceptor;
import juju.reattore.io.impl.ChannelFileSource;
import juju.reattore.io.ByteSource;
/** Interceptor that serves up files.
@tag files
@group Interceptor
@children ExtMap
*/
public class FileInterceptor
implements Interceptor {
private static Log log = LogFactory.getLog(FileInterceptor.class);
private File baseDir;
/* Or is it indicies? :) */
private List indexes = new ArrayList();
private Map extmap = new HashMap();
/** Create a new FileInterceptor using the given directory as the
base directory.
@param baseDir Base directory for all requests.
*/
public FileInterceptor(String baseDir) {
this.baseDir = new File(baseDir);
}
/** Default Bean constructor.
*/
public FileInterceptor() {
}
/** Set the base directory.
@param baseDir Base directory for all requests.
*/
public void setBaseDir(String baseDir) {
this.baseDir = new File(baseDir);
}
/** Adds a file that the server will try for if a directory is
requested.
@param name The path to try.
*/
public void addDirectoryIndex(String name) {
indexes.add(name);
}
/** Adds a mapping between extension and mime type.
@param map The mapping to add/replace.
*/
public void addExtMap(ExtMap map) {
extmap.put(map.getName(), map.getValue());
}
/** Sets the file that the server will try for if a directory is
requested. Clears the list set by #addDirectoryIndex.
@param name The path to try.
*/
public void setDirectoryIndex(String name) {
indexes.clear();
indexes.add(name);
}
private String guessContentType(File path) {
String name = path.getName();
int idx = name.lastIndexOf('.');
if (idx != -1) {
String ext = name.substring(idx + 1);
String type;
if ((type = (String)extmap.get(ext)) != null) {
return type;
}
else {
return null;
}
}
else {
return null;
}
}
private boolean tryLoad(HttpRequest req, HttpResponse resp, File path) {
log.debug("Opening " + path);
if (path.exists() == false) {
/* Can't find it */
return false;
}
else if (path.canRead() == false) {
resp.setStatus(HttpResponse.SC_FORBIDDEN);
return false;
}
else {
try {
resp.setBody(new ChannelFileSource(path));
resp.setStatus(HttpResponse.SC_OK);
String type = guessContentType(path);
if (type != null) {
resp.setHeader(HttpConstants.CONTENT_TYPE, type);
}
return true;
}
catch (IOException ex) {
log.info("Error while reading " + path, ex);
resp.setStatus(HttpResponse.SC_FORBIDDEN);
return false;
}
}
}
/** @see Interceptor */
public boolean process(HttpRequest req, HttpResponse resp) {
String path = req.getPath();
ByteSource ret;
File serve = new File(baseDir, path);
if (serve.isDirectory()) {
/* Redirect if the request is incomplete. */
if (path.endsWith("/") || path.equals("")) {
for (Iterator i = indexes.iterator(); i.hasNext();) {
if (tryLoad(req, resp, new File(serve, (String)i.next()))) {
return true;
}
}
/* Directory and didn't find the index */
resp.setStatus(HttpResponse.SC_NOT_FOUND);
return false;
}
else {
resp.setStatus(HttpResponse.SC_MOVED_PERMANENTLY);
resp.setHeader(HttpConstants.LOCATION, req.getOriginalPath() + "/");
return true;
}
}
else if (tryLoad(req, resp, serve)) {
/* Found the actual file */
return true;
}
else {
/* Didn't find it */
resp.setStatus(HttpResponse.SC_NOT_FOUND);
return false;
}
}
}