/* vim: set ts=2 et sw=2 cindent fo=qroca: */ package com.globant.katari.core.web; import static org.easymock.EasyMock.*; import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertThat; import static org.hamcrest.CoreMatchers.*; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.junit.Before; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.globant.katari.tools.ListFactory; public class HtmlValidationFilterTest { private static Logger log = LoggerFactory.getLogger(HtmlValidationFilterTest.class); private FilterConfig filterConfig; private HttpServletRequest request; private MockHttpServletResponse response; @Before public final void setUp() throws Exception { // Mocks the context ServletContext context = createMock(ServletContext.class); replay(context); // Mocks the filter config filterConfig = createMock(FilterConfig.class); expect(filterConfig.getServletContext()).andReturn(context); replay(filterConfig); // Mocks the servlet request. request = createNiceMock(HttpServletRequest.class); expect(request.getRequestURI()).andReturn("/test"); replay(request); response = new MockHttpServletResponse(); response.setContentType("text/html"); } /* Tests that the filter succeeds on valid html. */ @Test public final void testDoFilter_validHtml() throws Exception { // Mocks the filter chain. FilterChain chain = new FilterChain() { public void doFilter(final ServletRequest request, final ServletResponse response) throws IOException { log.trace("Entering doFilter"); PrintWriter writer = new PrintWriter(response.getOutputStream()); writer.write( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"" + " \"http://www.w3.org/TR/html4/strict.dtd\">" + " <html><head><title>aa</title></head><body>test</body></html>"); writer.flush(); log.trace("Leaving doFilter"); } }; // Executes the test. HtmlValidationFilter filter = new HtmlValidationFilter(); filter.init(filterConfig); filter.doFilter(request, response, chain); assertThat(response.getStatus(), is(200)); } /* Tests that the filter throws an exception on invalid html. */ @Test public final void testDoFilter_invalidHtml() throws Exception { // Mocks the filter chain. FilterChain chain = new FilterChain() { public void doFilter(final ServletRequest request, final ServletResponse response) throws IOException { log.trace("Entering doFilter"); PrintWriter writer = new PrintWriter(response.getOutputStream()); writer.write( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"" + " \"http://www.w3.org/TR/html4/strict.dtd\">" + " <html><table id='someid'><td id='someid'>" + " <non_existing_attribute></td></html>"); writer.flush(); log.trace("Leaving doFilter"); } }; // Executes the test. HtmlValidationFilter filter = new HtmlValidationFilter(); filter.init(filterConfig); try { filter.doFilter(request, response, chain); assertTrue("Expected ServletException not thrown", true); } catch (ServletException e) { String message = e.getMessage(); assertTrue(message.matches("(?s).*<non_existing_attribute>(?s).*")); } } /* Tests that the filter ignores all errors if disabled. */ @Test public final void testDoFilter_invalidHtmlDisabled() throws Exception { // Mocks the filter chain. FilterChain chain = new FilterChain() { public void doFilter(final ServletRequest request, final ServletResponse response) throws IOException { log.trace("Entering doFilter"); PrintWriter writer = new PrintWriter(response.getOutputStream()); writer.write( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"" + " \"http://www.w3.org/TR/html4/strict.dtd\">" + " <html><table id='someid'><td id='someid'><banana></td></html>"); writer.flush(); log.trace("Leaving doFilter"); } }; // Executes the test. HtmlValidationFilter filter = new HtmlValidationFilter(); filter.setEnabled(false); filter.init(filterConfig); // Would throw an exception if enabled. filter.doFilter(request, response, chain); } /* Tests that the filter ignores based on url pattern list. */ @Test public final void testDoFilter_ignoredUrlPatternList() throws Exception { log.trace("Entering testDoFilter_ignoredUrlPatternList"); request = createNiceMock(HttpServletRequest.class); expect(request.getRequestURI()).andReturn("/ignoredPage/test"); expect(request.getPathInfo()).andReturn("/notTrails/"); replay(request); // Mocks the filter chain. FilterChain chain = new FilterChain() { public void doFilter(final ServletRequest request, final ServletResponse response) throws IOException { log.trace("Entering doFilter"); PrintWriter writer = new PrintWriter(response.getOutputStream()); writer.write( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"" + " \"http://www.w3.org/TR/html4/strict.dtd\">\r\n" + " <html><head><title>aa</title></head><body>" + "<form action='test'>" + " <input type='text' validator='aa'>" + "</form>" + "</body></html>\r\n"); writer.flush(); log.trace("Leaving doFilter"); } }; // Executes the test. HtmlValidationFilter filter = new HtmlValidationFilter(); filter.setEnabled(true); filter.init(filterConfig); filter.setIgnoredUrlpatterns(ListFactory.create(".*/ignoredPage/.*")); // Would throw an exception if enabled. filter.doFilter(request, response, chain); log.trace("Leaving testDoFilter_ignoredUrlPatternList"); } /* Tests that the filter fails with the invalid attribute 'validator'. */ @Test public final void testDoFilter_failOnValidator() throws Exception { log.trace("Entering testDoFilter_failOnValidator"); request = createNiceMock(HttpServletRequest.class); expect(request.getPathInfo()).andReturn("/something/"); expect(request.getRequestURI()).andReturn("/test"); replay(request); // Mocks the filter chain. FilterChain chain = new FilterChain() { public void doFilter(final ServletRequest request, final ServletResponse response) throws IOException { log.trace("Entering doFilter"); PrintWriter writer = new PrintWriter(response.getOutputStream()); writer.write( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"" + " \"http://www.w3.org/TR/html4/strict.dtd\">" + " <html><head><title>aa</title></head><body>" + "<form action='test'>" + " <input type='text' validator='aa'>" + "</form>" + "</body></html>"); writer.flush(); log.trace("Leaving doFilter"); } }; // Executes the test. HtmlValidationFilter filter = new HtmlValidationFilter(); filter.setEnabled(true); filter.init(filterConfig); filter.doFilter(request, response, chain); // Fails with error 500. assertThat(response.getStatus(), is(500)); log.trace("Leaving testDoFilter_failOnValidator"); } /* Tests that the filter considers the invalid attribute 'validator' if * configured to do so. */ @Test public final void testDoFilter_skipValidatorAttribute() throws Exception { log.trace("Entering testDoFilter_skipValidatorAttribute"); request = createNiceMock(HttpServletRequest.class); expect(request.getPathInfo()).andReturn("/something/"); expect(request.getRequestURI()).andReturn("/test"); replay(request); // Mocks the filter chain. FilterChain chain = new FilterChain() { public void doFilter(final ServletRequest request, final ServletResponse response) throws IOException { log.trace("Entering doFilter"); PrintWriter writer = new PrintWriter(response.getOutputStream()); writer.write( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"" + " \"http://www.w3.org/TR/html4/strict.dtd\">\n" + " <html><head><title>aa</title></head><body>\n" + "<form action='test'>\n" + " <input type='text' validator='aa'>\n" + "</form>\n" + "</body></html>\n"); writer.flush(); log.trace("Leaving doFilter"); } }; // Executes the test. HtmlValidationFilter filter = new HtmlValidationFilter(); filter.setEnabled(true); filter.init(filterConfig); filter.setIgnoredAttributePatterns(ListFactory.create("validator")); filter.doFilter(request, response, chain); // Should pass with a 200 status code. assertThat(response.getStatus(), is(200)); log.trace("Leaving testDoFilter_skipValidatorAttribute"); } /* Tests what happens when the user does not call flush on the response or * writer. */ @Test public final void testDoFilter_flushNotCalled() throws Exception { // Mocks the filter chain. FilterChain chain = new FilterChain() { public void doFilter(final ServletRequest request, final ServletResponse response) throws IOException { log.trace("Entering doFilter"); PrintWriter writer = response.getWriter(); writer.write( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"" + " \"http://www.w3.org/TR/html4/strict.dtd\">" + " <html><head><title>aa</title></head><body>test</body></html>"); log.trace("Leaving doFilter"); } }; // Executes the test. HtmlValidationFilter filter = new HtmlValidationFilter(); filter.init(filterConfig); filter.doFilter(request, response, chain); assertThat(response.getStatus(), is(200)); } }