/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.inject.servlet; import static com.google.inject.servlet.ManagedServletPipeline.REQUEST_DISPATCHER_REQUEST; import static org.easymock.EasyMock.anyObject; import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.verify; import com.google.common.collect.Sets; import com.google.inject.Binding; import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.spi.BindingScopingVisitor; import java.io.IOException; import java.util.HashMap; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import junit.framework.TestCase; /** * Ensures servlet spec compliance for CGI-style variables and general path/pattern matching. * * @author Dhanji R. Prasanna (dhanji@gmail com) */ public class ServletDefinitionPathsTest extends TestCase { // Data-driven test. public final void testServletPathMatching() throws IOException, ServletException { servletPath("/index.html", "*.html", "/index.html"); servletPath("/somewhere/index.html", "*.html", "/somewhere/index.html"); servletPath("/somewhere/index.html", "/*", ""); servletPath("/index.html", "/*", ""); servletPath("/", "/*", ""); servletPath("//", "/*", ""); servletPath("/////", "/*", ""); servletPath("", "/*", ""); servletPath("/thing/index.html", "/thing/*", "/thing"); servletPath("/thing/wing/index.html", "/thing/*", "/thing"); } private void servletPath( final String requestPath, String mapping, final String expectedServletPath) throws IOException, ServletException { Injector injector = createMock(Injector.class); Binding binding = createMock(Binding.class); HttpServletRequest request = createMock(HttpServletRequest.class); HttpServletResponse response = createMock(HttpServletResponse.class); expect(binding.acceptScopingVisitor((BindingScopingVisitor) anyObject())).andReturn(true); expect(injector.getBinding(Key.get(HttpServlet.class))).andReturn(binding); final boolean[] run = new boolean[1]; //get an instance of this servlet expect(injector.getInstance(Key.get(HttpServlet.class))) .andReturn( new HttpServlet() { @Override protected void service( HttpServletRequest servletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException { final String path = servletRequest.getServletPath(); assertEquals( String.format("expected [%s] but was [%s]", expectedServletPath, path), expectedServletPath, path); run[0] = true; } }); expect(request.getServletPath()).andReturn(requestPath); replay(injector, binding, request); ServletDefinition servletDefinition = new ServletDefinition( Key.get(HttpServlet.class), UriPatternType.get(UriPatternType.SERVLET, mapping), new HashMap<String, String>(), null); servletDefinition.init(null, injector, Sets.<HttpServlet>newIdentityHashSet()); servletDefinition.doService(request, response); assertTrue("Servlet did not run!", run[0]); verify(injector, binding, request); } // Data-driven test. public final void testPathInfoWithServletStyleMatching() throws IOException, ServletException { pathInfoWithServletStyleMatching("/path/index.html", "/path", "/*", "/index.html", ""); pathInfoWithServletStyleMatching( "/path//hulaboo///index.html", "/path", "/*", "/hulaboo/index.html", ""); pathInfoWithServletStyleMatching("/path/", "/path", "/*", "/", ""); pathInfoWithServletStyleMatching("/path////////", "/path", "/*", "/", ""); // a servlet mapping of /thing/* pathInfoWithServletStyleMatching("/path/thing////////", "/path", "/thing/*", "/", "/thing"); pathInfoWithServletStyleMatching("/path/thing/stuff", "/path", "/thing/*", "/stuff", "/thing"); pathInfoWithServletStyleMatching( "/path/thing/stuff.html", "/path", "/thing/*", "/stuff.html", "/thing"); pathInfoWithServletStyleMatching("/path/thing", "/path", "/thing/*", null, "/thing"); // see external issue 372 pathInfoWithServletStyleMatching( "/path/some/path/of.jsp", "/path", "/thing/*", null, "/some/path/of.jsp"); // *.xx style mapping pathInfoWithServletStyleMatching("/path/thing.thing", "/path", "*.thing", null, "/thing.thing"); pathInfoWithServletStyleMatching("/path///h.thing", "/path", "*.thing", null, "/h.thing"); pathInfoWithServletStyleMatching( "/path///...//h.thing", "/path", "*.thing", null, "/.../h.thing"); pathInfoWithServletStyleMatching("/path/my/h.thing", "/path", "*.thing", null, "/my/h.thing"); // Encoded URLs pathInfoWithServletStyleMatching("/path/index%2B.html", "/path", "/*", "/index+.html", ""); pathInfoWithServletStyleMatching( "/path/a%20file%20with%20spaces%20in%20name.html", "/path", "/*", "/a file with spaces in name.html", ""); pathInfoWithServletStyleMatching( "/path/Tam%C3%A1s%20nem%20m%C3%A1s.html", "/path", "/*", "/Tamás nem más.html", ""); } private void pathInfoWithServletStyleMatching( final String requestUri, final String contextPath, String mapping, final String expectedPathInfo, final String servletPath) throws IOException, ServletException { Injector injector = createMock(Injector.class); Binding binding = createMock(Binding.class); HttpServletRequest request = createMock(HttpServletRequest.class); HttpServletResponse response = createMock(HttpServletResponse.class); expect(binding.acceptScopingVisitor((BindingScopingVisitor) anyObject())).andReturn(true); expect(injector.getBinding(Key.get(HttpServlet.class))).andReturn(binding); final boolean[] run = new boolean[1]; //get an instance of this servlet expect(injector.getInstance(Key.get(HttpServlet.class))) .andReturn( new HttpServlet() { @Override protected void service( HttpServletRequest servletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException { final String path = servletRequest.getPathInfo(); if (null == expectedPathInfo) { assertNull( String.format("expected [%s] but was [%s]", expectedPathInfo, path), path); } else { assertEquals( String.format("expected [%s] but was [%s]", expectedPathInfo, path), expectedPathInfo, path); } //assert memoizer //noinspection StringEquality assertSame("memo field did not work", path, servletRequest.getPathInfo()); run[0] = true; } }); expect(request.getRequestURI()).andReturn(requestUri); expect(request.getServletPath()).andReturn(servletPath).anyTimes(); expect(request.getContextPath()).andReturn(contextPath); expect(request.getAttribute(REQUEST_DISPATCHER_REQUEST)).andReturn(null); replay(injector, binding, request); ServletDefinition servletDefinition = new ServletDefinition( Key.get(HttpServlet.class), UriPatternType.get(UriPatternType.SERVLET, mapping), new HashMap<String, String>(), null); servletDefinition.init(null, injector, Sets.<HttpServlet>newIdentityHashSet()); servletDefinition.doService(request, response); assertTrue("Servlet did not run!", run[0]); verify(injector, binding, request); } // Data-driven test. public final void testPathInfoWithRegexMatching() throws IOException, ServletException { // first a mapping of /* pathInfoWithRegexMatching("/path/index.html", "/path", "/(.)*", "/index.html", ""); pathInfoWithRegexMatching( "/path//hulaboo///index.html", "/path", "/(.)*", "/hulaboo/index.html", ""); pathInfoWithRegexMatching("/path/", "/path", "/(.)*", "/", ""); pathInfoWithRegexMatching("/path////////", "/path", "/(.)*", "/", ""); // a servlet mapping of /thing/* pathInfoWithRegexMatching("/path/thing////////", "/path", "/thing/(.)*", "/", "/thing"); pathInfoWithRegexMatching("/path/thing/stuff", "/path", "/thing/(.)*", "/stuff", "/thing"); pathInfoWithRegexMatching( "/path/thing/stuff.html", "/path", "/thing/(.)*", "/stuff.html", "/thing"); pathInfoWithRegexMatching("/path/thing", "/path", "/thing/(.)*", null, "/thing"); // *.xx style mapping pathInfoWithRegexMatching("/path/thing.thing", "/path", ".*\\.thing", null, "/thing.thing"); pathInfoWithRegexMatching("/path///h.thing", "/path", ".*\\.thing", null, "/h.thing"); pathInfoWithRegexMatching("/path///...//h.thing", "/path", ".*\\.thing", null, "/.../h.thing"); pathInfoWithRegexMatching("/path/my/h.thing", "/path", ".*\\.thing", null, "/my/h.thing"); // path pathInfoWithRegexMatching( "/path/test.com/com.test.MyServletModule", "", "/path/[^/]+/(.*)", "com.test.MyServletModule", "/path/test.com/com.test.MyServletModule"); // Encoded URLs pathInfoWithRegexMatching("/path/index%2B.html", "/path", "/(.)*", "/index+.html", ""); pathInfoWithRegexMatching( "/path/a%20file%20with%20spaces%20in%20name.html", "/path", "/(.)*", "/a file with spaces in name.html", ""); pathInfoWithRegexMatching( "/path/Tam%C3%A1s%20nem%20m%C3%A1s.html", "/path", "/(.)*", "/Tamás nem más.html", ""); } public final void pathInfoWithRegexMatching( final String requestUri, final String contextPath, String mapping, final String expectedPathInfo, final String servletPath) throws IOException, ServletException { Injector injector = createMock(Injector.class); Binding binding = createMock(Binding.class); HttpServletRequest request = createMock(HttpServletRequest.class); HttpServletResponse response = createMock(HttpServletResponse.class); expect(binding.acceptScopingVisitor((BindingScopingVisitor) anyObject())).andReturn(true); expect(injector.getBinding(Key.get(HttpServlet.class))).andReturn(binding); final boolean[] run = new boolean[1]; //get an instance of this servlet expect(injector.getInstance(Key.get(HttpServlet.class))) .andReturn( new HttpServlet() { @Override protected void service( HttpServletRequest servletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException { final String path = servletRequest.getPathInfo(); if (null == expectedPathInfo) { assertNull( String.format("expected [%s] but was [%s]", expectedPathInfo, path), path); } else { assertEquals( String.format("expected [%s] but was [%s]", expectedPathInfo, path), expectedPathInfo, path); } //assert memoizer //noinspection StringEquality assertSame("memo field did not work", path, servletRequest.getPathInfo()); run[0] = true; } }); expect(request.getRequestURI()).andReturn(requestUri); expect(request.getServletPath()).andReturn(servletPath).anyTimes(); expect(request.getContextPath()).andReturn(contextPath); expect(request.getAttribute(REQUEST_DISPATCHER_REQUEST)).andReturn(null); replay(injector, binding, request); ServletDefinition servletDefinition = new ServletDefinition( Key.get(HttpServlet.class), UriPatternType.get(UriPatternType.REGEX, mapping), new HashMap<String, String>(), null); servletDefinition.init(null, injector, Sets.<HttpServlet>newIdentityHashSet()); servletDefinition.doService(request, response); assertTrue("Servlet did not run!", run[0]); verify(injector, binding, request); } }