package net.sf.jruby.rails.asyncweb.service;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Properties;
import net.sf.jruby.rails.asyncweb.config.RailsConfig;
import org.safehaus.asyncweb.http.HttpRequest;
import org.safehaus.asyncweb.http.HttpResponse;
import org.safehaus.asyncweb.http.HttpService;
import org.safehaus.asyncweb.http.ResponseStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RailsFileService implements HttpService {
private static final String MIME_TYPES_PROPERTIES = "/net/sf/jruby/rails/asyncweb/service/MimeTypes.properties";
private static final int BUFFER_SIZE = 1024 * 2; // 2KB
private static final String DEFAULT_MIME_TYPE = "application/octet-stream";
private static final Logger LOGGER = LoggerFactory.getLogger(RailsFileService.class.getName());
private static final String RFC_2616_FORMAT = "EEE, d MMM yyyy HH:mm:ss z";
private Properties mimeTypes = null;
private RailsConfig railsConfig = null;
public void handleRequest(HttpRequest request) {
try {
HttpResponse response = request.createHttpResponse();
String uri = request.getRequestURI();
File file = railsConfig.convertRequestToFile(uri);
if (modifiedSince(request, file)) {
response.setStatus(ResponseStatus.NOT_MODIFIED);
request.commitResponse(response);
} else {
copy(response, file);
response.setContentType(getMimeType(file.getName()));
response.setStatus(ResponseStatus.OK);
request.commitResponse(response);
}
} catch (FileNotFoundException e) {
request.commitErrorResponse(ResponseStatus.NOT_FOUND);
} catch (IOException ex) {
request.commitErrorResponse(ResponseStatus.INTERNAL_SERVER_ERROR);
}
}
public void setRailsConfig(RailsConfig railsConfig) {
this.railsConfig = railsConfig;
}
public void start() {
try {
if (LOGGER.isDebugEnabled())
LOGGER.debug("{}#start()", getClass().getName());
mimeTypes = new Properties();
mimeTypes.load(getClass().getResourceAsStream(MIME_TYPES_PROPERTIES));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void stop() {
if (LOGGER.isDebugEnabled())
LOGGER.debug("{}#stop()", getClass().getName());
}
private void copy(HttpResponse response, File file) throws IOException {
InputStream in = new FileInputStream(file);
OutputStream out = response.getOutputStream();
try {
int len;
byte[] buff = new byte[BUFFER_SIZE];
while ((len = in.read(buff)) != -1) {
out.write(buff, 0, len);
}
} finally {
in.close();
out.flush();
}
}
private String getMimeType(String filename) {
String type = DEFAULT_MIME_TYPE;
int index = filename.lastIndexOf('.');
if (index > 0 && index < filename.length() - 1) {
String suffix = filename.substring(index + 1);
String mimeType = mimeTypes.getProperty(suffix);
if (mimeType != null)
type = mimeType;
}
return type;
}
private boolean modifiedSince(HttpRequest request, File file) {
try {
String since = request.getHeader("If-Modified-Since");
if (since == null) {
return false;
}
Date date = new SimpleDateFormat(RFC_2616_FORMAT, Locale.US).parse(since);
if (date.getTime() > file.lastModified()) {
return true;
} else {
return false;
}
} catch (ParseException e) {
if (LOGGER.isErrorEnabled()) {
LOGGER.error(e.getMessage());
}
return false;
}
}
}