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 RepoFileResponder implements Responder {
014:
015: public static final String RESPONDER_KEY = "~";
016:
017: private static FileNameMap fileNameMap = URLConnection
018: .getFileNameMap();
019:
020: public String resource;
021:
022: public File requestedFile;
023:
024: public Date lastModifiedDate;
025:
026: public String lastModifiedDateString;
027:
028: public static Responder makeResponder(Request request,
029: String rootPath) throws Exception {
030:
031: // Strip the ~ if present
032: String resource = request.getResource();
033: if (resource.indexOf('~') == 0) {
034: resource = resource.substring(1);
035: }
036:
037: if (fileNameHasSpaces(resource))
038: resource = restoreRealSpacesInFileName(resource);
039:
040: File requestedFile = new File(rootPath + "/" + resource);
041: if (!requestedFile.exists())
042: return new NotFoundResponder();
043:
044: if (requestedFile.isDirectory())
045: return new DirectoryResponder(resource, requestedFile);
046: else
047: return new RepoFileResponder(resource, requestedFile);
048: }
049:
050: public RepoFileResponder(String resource, File requestedFile) {
051: this .resource = resource;
052: this .requestedFile = requestedFile;
053: }
054:
055: public Response makeResponse(FitNesseContext context,
056: Request request) throws Exception {
057: InputStreamResponse response = new InputStreamResponse();
058: determineLastModifiedInfo();
059:
060: if (isNotModified(request))
061: return createNotModifiedResponse();
062: else {
063: response.setBody(requestedFile);
064: setContentType(requestedFile, response);
065: response.setLastModifiedHeader(lastModifiedDateString);
066: }
067: return response;
068: }
069:
070: public static boolean fileNameHasSpaces(String resource) {
071: return resource.indexOf("%20") != 0;
072: }
073:
074: public static String restoreRealSpacesInFileName(String resource)
075: throws Exception {
076: return URLDecoder.decode(resource, "UTF-8");
077: }
078:
079: String getResource() {
080: return resource;
081: }
082:
083: private boolean isNotModified(Request request) {
084: if (request.hasHeader("If-Modified-Since")) {
085: String queryDateString = (String) request
086: .getHeader("If-Modified-Since");
087: try {
088: Date queryDate = Response.makeStandardHttpDateFormat()
089: .parse(queryDateString);
090: if (!queryDate.before(lastModifiedDate))
091: return true;
092: } catch (ParseException e) {
093: e.printStackTrace();
094: }
095: }
096: return false;
097: }
098:
099: private Response createNotModifiedResponse() {
100: Response response = new SimpleResponse();
101: response.setStatus(304);
102: response.addHeader("Date", Response
103: .makeStandardHttpDateFormat().format(new Date()));
104: response.addHeader("Cache-Control", "private");
105: response.setLastModifiedHeader(lastModifiedDateString);
106: return response;
107: }
108:
109: private void determineLastModifiedInfo() {
110: lastModifiedDate = new Date(requestedFile.lastModified());
111: lastModifiedDateString = Response.makeStandardHttpDateFormat()
112: .format(lastModifiedDate);
113:
114: try // remove milliseconds
115: {
116: lastModifiedDate = Response.makeStandardHttpDateFormat()
117: .parse(lastModifiedDateString);
118: } catch (java.text.ParseException jtpe) {
119: jtpe.printStackTrace();
120: }
121: }
122:
123: private void setContentType(File file, Response response) {
124: String contentType = getContentType(file.getName());
125: response.setContentType(contentType);
126: }
127:
128: public static String getContentType(String filename) {
129: String contentType = fileNameMap.getContentTypeFor(filename);
130: if (contentType == null) {
131: if (filename.endsWith(".css")) {
132: contentType = "text/css";
133: } else if (filename.endsWith(".jar")) {
134: contentType = "application/x-java-archive";
135: } else if (filename.endsWith(".html")
136: || filename.endsWith(".htm")) {
137: contentType = "text/html";
138: } else {
139: contentType = "text/plain";
140: }
141: }
142: return contentType;
143: }
144: }
|