001: // Copyright (C) 2003,2004,2005 by Object Mentor, Inc. All rights reserved.
002: // Released under the terms of the GNU General Public License version 2 or later.
003: package fitnesse.responders.files;
004:
005: import fitnesse.http.*;
006: import fitnesse.*;
007: import fitnesse.responders.*;
008: import java.io.*;
009: import java.net.*;
010: import java.util.*;
011: import java.text.ParseException;
012:
013: public class FileResponder implements Responder {
014: private static FileNameMap fileNameMap = URLConnection
015: .getFileNameMap();
016: public String resource;
017: public File requestedFile;
018: public Date lastModifiedDate;
019: public String lastModifiedDateString;
020:
021: public static Responder makeResponder(Request request,
022: String rootPath) throws Exception {
023: String resource = request.getResource();
024:
025: if (fileNameHasSpaces(resource))
026: resource = restoreRealSpacesInFileName(resource);
027:
028: File requestedFile = new File(rootPath + "/" + resource);
029: if (!requestedFile.exists())
030: return new NotFoundResponder();
031:
032: if (requestedFile.isDirectory())
033: return new DirectoryResponder(resource, requestedFile);
034: else
035: return new FileResponder(resource, requestedFile);
036: }
037:
038: public FileResponder(String resource, File requestedFile) {
039: this .resource = resource;
040: this .requestedFile = requestedFile;
041: }
042:
043: public Response makeResponse(FitNesseContext context,
044: Request request) throws Exception {
045: InputStreamResponse response = new InputStreamResponse();
046: determineLastModifiedInfo();
047:
048: if (isNotModified(request))
049: return createNotModifiedResponse();
050: else {
051: response.setBody(requestedFile);
052: setContentType(requestedFile, response);
053: response.setLastModifiedHeader(lastModifiedDateString);
054: }
055: return response;
056: }
057:
058: public static boolean fileNameHasSpaces(String resource) {
059: return resource.indexOf("%20") != 0;
060: }
061:
062: public static String restoreRealSpacesInFileName(String resource)
063: throws Exception {
064: return URLDecoder.decode(resource, "UTF-8");
065: }
066:
067: String getResource() {
068: return resource;
069: }
070:
071: private boolean isNotModified(Request request) {
072: if (request.hasHeader("If-Modified-Since")) {
073: String queryDateString = (String) request
074: .getHeader("If-Modified-Since");
075: try {
076: Date queryDate = SimpleResponse
077: .makeStandardHttpDateFormat().parse(
078: queryDateString);
079: if (!queryDate.before(lastModifiedDate))
080: return true;
081: } catch (ParseException e) {
082: e.printStackTrace();
083: }
084: }
085: return false;
086: }
087:
088: private Response createNotModifiedResponse() {
089: Response response = new SimpleResponse();
090: response.setStatus(304);
091: response.addHeader("Date", SimpleResponse
092: .makeStandardHttpDateFormat().format(new Date()));
093: response.addHeader("Cache-Control", "private");
094: response.setLastModifiedHeader(lastModifiedDateString);
095: return response;
096: }
097:
098: private void determineLastModifiedInfo() {
099: lastModifiedDate = new Date(requestedFile.lastModified());
100: lastModifiedDateString = SimpleResponse
101: .makeStandardHttpDateFormat().format(lastModifiedDate);
102:
103: try // remove milliseconds
104: {
105: lastModifiedDate = SimpleResponse
106: .makeStandardHttpDateFormat().parse(
107: lastModifiedDateString);
108: } catch (java.text.ParseException jtpe) {
109: jtpe.printStackTrace();
110: }
111: }
112:
113: private void setContentType(File file, Response response) {
114: String contentType = getContentType(file.getName());
115: response.setContentType(contentType);
116: }
117:
118: public static String getContentType(String filename) {
119: String contentType = fileNameMap.getContentTypeFor(filename);
120: if (contentType == null) {
121: if (filename.endsWith(".css"))
122: contentType = "text/css";
123: else if (filename.endsWith(".jar"))
124: contentType = "application/x-java-archive";
125: else
126: contentType = "text/plain";
127: }
128: return contentType;
129: }
130: }
|