// Copyright (C) 2003-2009 by Object Mentor, Inc. All rights reserved.
// Released under the terms of the CPL Common Public License version 1.0.
package fitnesse.responders.files;
import java.io.File;
import java.io.IOException;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Locale;
import fitnesse.FitNesseContext;
import fitnesse.http.InputStreamResponse;
import fitnesse.http.MockRequest;
import fitnesse.http.MockResponseSender;
import fitnesse.http.Response;
import fitnesse.http.SimpleResponse;
import fitnesse.testutil.FitNesseUtil;
import fitnesse.testutil.SampleFileUtility;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static fitnesse.responders.files.FileResponder.isInFilesDirectory;
import static org.junit.Assert.*;
import static util.RegexTestCase.*;
public class FileResponderTest {
MockRequest request;
private final String HTTP_DATE_REGEXP = "[SMTWF][a-z]{2}\\,\\s[0-9]{2}\\s[JFMASOND][a-z]{2}\\s[0-9]{4}\\s[0-9]{2}\\:[0-9]{2}\\:[0-9]{2}\\sGMT";
private Response response;
private FitNesseContext context;
private FileResponder responder;
private Locale saveLocale;
// Example: "Tue, 02 Apr 2003 22:18:49 GMT"
@Before
public void setUp() throws Exception {
request = new MockRequest();
context = FitNesseUtil.makeTestContext();
SampleFileUtility.makeSampleFiles(context.getRootPagePath());
response = null;
saveLocale = Locale.getDefault();
FitNesseUtil.makeTestContext();
responder = new FileResponder();
}
@After
public void tearDown() throws Exception {
if (response != null) response.sendTo(new MockResponseSender());
SampleFileUtility.deleteSampleFiles(context.getRootPagePath());
Locale.setDefault(saveLocale);
}
@Test
public void testFileContent() throws Exception {
request.setResource("files/testFile1");
response = responder.makeResponse(context, request);
assertEquals(InputStreamResponse.class, response.getClass());
MockResponseSender sender = new MockResponseSender();
sender.doSending(response);
assertSubString("file1 content", sender.sentData());
}
@Test
public void testClasspathResourceContent() throws Exception {
request.setResource("files/fitnesse/testresource.txt");
response = responder.makeResponse(context, request);
MockResponseSender sender = new MockResponseSender();
sender.doSending(response);
assertSubString("test resource content", sender.sentData());
}
@Test
public void testSpacesInFileName() throws Exception {
request.setResource("files/test%20File%20With%20Spaces%20In%20Name");
responder = new FileResponder();
responder.makeResponse(context, request);
assertEquals(context.getRootPagePath() + File.separator + "files" + File.separator + "test File With Spaces In Name", responder.requestedFile.getPath());
}
@Test
public void testUrlEncodedSpacesInFileName() throws Exception {
request.setResource("files/file4%20with%20spaces%32.txt");
responder.makeResponse(context, request);
assertEquals("files/file4 with spaces2.txt", responder.resource);
}
@Test
public void testLastModifiedHeader() throws Exception {
Locale.setDefault(Locale.US);
request.setResource("files/testFile1");
response = responder.makeResponse(context, request);
String lastModifiedHeader = response.getHeader("Last-Modified");
assertMatches(HTTP_DATE_REGEXP, lastModifiedHeader);
}
@Test
public void testLastModifiedHeaderForClasspathResources() throws Exception {
Locale.setDefault(Locale.US);
request.setResource("files/fitnesse/css/fitnesse.css");
response = responder.makeResponse(context, request);
String lastModifiedHeader = response.getHeader("Last-Modified");
assertMatches(HTTP_DATE_REGEXP, lastModifiedHeader);
}
private void test304IfNotModified(String resource) throws Exception {
Locale.setDefault(Locale.US);
Calendar now = new GregorianCalendar();
now.add(Calendar.DATE, -1);
String yesterday = SimpleResponse.makeStandardHttpDateFormat().format(now.getTime());
now.add(Calendar.DATE, 2);
String tomorrow = SimpleResponse.makeStandardHttpDateFormat().format(now.getTime());
request.setResource(resource);
request.addHeader("If-Modified-Since", yesterday);
response = responder.makeResponse(context, request);
assertEquals(200, response.getStatus());
request.setResource(resource);
request.addHeader("If-Modified-Since", tomorrow);
SimpleResponse notModifiedResponse = (SimpleResponse) responder.makeResponse(context, request);
assertEquals(304, notModifiedResponse.getStatus());
assertEquals("", notModifiedResponse.getContent());
assertMatches(HTTP_DATE_REGEXP, notModifiedResponse.getHeader("Date"));
assertNotNull(notModifiedResponse.getHeader("Cache-Control"));
assertNull(notModifiedResponse.getHeader("Content-Type"));
}
@Test
public void test304IfNotModifiedForFiles() throws Exception {
test304IfNotModified("files/testFile1");
}
@Test
public void test304IfNotModifiedForClasspathResources() throws Exception {
test304IfNotModified("files/fitnesse/css/fitnesse.css");
}
@Test
public void testRecoverFromUnparseableDateInIfNotModifiedHeader() throws Exception {
request.setResource("files/testFile1");
request.addHeader("If-Modified-Since", "Unparseable Date");
response = responder.makeResponse(context, request);
assertEquals(200, response.getStatus());
}
@Test
public void testNotFoundFile() throws Exception {
request.setResource("files/something/that/aint/there");
Response response = responder.makeResponse(context, request);
assertEquals(404, response.getStatus());
assertHasRegexp("files/something/that/aint/there", ((SimpleResponse) response).getContent());
}
@Test
public void testCssMimeType() throws Exception {
SampleFileUtility.addFile(context.getRootPagePath(), "/files/fitnesse.css", "body{color: red;}");
request.setResource("files/fitnesse.css");
response = responder.makeResponse(context, request);
assertEquals("text/css", response.getContentType());
}
@Test
public void testNavigationBackToFrontPage() throws Exception {
request.setResource("files/");
response = responder.makeResponse(context, request);
MockResponseSender sender = new MockResponseSender();
sender.doSending(response);
assertSubString("href=\"/FrontPage\"", sender.sentData());
}
@Test
public void shouldTellIfFileIsInFilesFolder() throws IOException {
File rootPath = new File("./FitNesseRoot");
assertTrue(isInFilesDirectory(rootPath, new File(rootPath, "files")));
assertTrue(isInFilesDirectory(rootPath, new File(rootPath, "files/subfile")));
assertFalse(isInFilesDirectory(rootPath, new File(rootPath, "files/..")));
assertFalse(isInFilesDirectory(rootPath, new File("files")));
}
@Test
public void shouldNotDealWithDirectoryOutsideFilesFolder() throws Exception {
request.setResource("/files/../../");
Response response = responder.makeResponse(context, request);
assertEquals(400, response.getStatus());
}
@Test
public void shouldNotDealWithEscapedDirectoryOutsideFilesFolder() throws Exception {
request.setResource("/files/..%2f/");
Response response = responder.makeResponse(context, request);
assertEquals(400, response.getStatus());
}
}