1 /** 2 * Copyright (C) 2011 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.inject.servlet; 18 19 import static org.easymock.EasyMock.createControl; 20 import static org.easymock.EasyMock.expect; 21 22 import com.google.inject.Guice; 23 import com.google.inject.Inject; 24 import com.google.inject.Injector; 25 import com.google.inject.Key; 26 import com.google.inject.Scopes; 27 import com.google.inject.name.Named; 28 import com.google.inject.name.Names; 29 30 import junit.framework.TestCase; 31 32 import org.easymock.IMocksControl; 33 34 import java.io.IOException; 35 36 import javax.servlet.FilterChain; 37 import javax.servlet.FilterConfig; 38 import javax.servlet.ServletContext; 39 import javax.servlet.ServletException; 40 import javax.servlet.ServletRequest; 41 import javax.servlet.ServletResponse; 42 import javax.servlet.http.HttpServlet; 43 import javax.servlet.http.HttpServletRequest; 44 import javax.servlet.http.HttpServletResponse; 45 46 /** Tests to make sure that servlets with a context path are handled right. */ 47 public class ContextPathTest extends TestCase { 48 49 @Inject @Named("foo") 50 private TestServlet fooServlet; 51 52 @Inject @Named("bar") 53 private TestServlet barServlet; 54 55 private IMocksControl globalControl; 56 private Injector injector; 57 private ServletContext servletContext; 58 private FilterConfig filterConfig; 59 private GuiceFilter guiceFilter; 60 61 @Override setUp()62 public final void setUp() throws Exception { 63 injector = Guice.createInjector(new ServletModule() { 64 @Override 65 protected void configureServlets() { 66 bind(TestServlet.class).annotatedWith(Names.named("foo")) 67 .to(TestServlet.class).in(Scopes.SINGLETON); 68 bind(TestServlet.class).annotatedWith(Names.named("bar")) 69 .to(TestServlet.class).in(Scopes.SINGLETON); 70 serve("/foo/*").with(Key.get(TestServlet.class, Names.named("foo"))); 71 serve("/bar/*").with(Key.get(TestServlet.class, Names.named("bar"))); 72 // TODO: add a filter(..) call and validate it is correct 73 } 74 }); 75 injector.injectMembers(this); 76 77 assertNotNull(fooServlet); 78 assertNotNull(barServlet); 79 assertNotSame(fooServlet, barServlet); 80 81 globalControl = createControl(); 82 servletContext = globalControl.createMock(ServletContext.class); 83 filterConfig = globalControl.createMock(FilterConfig.class); 84 85 expect(servletContext.getAttribute(GuiceServletContextListener.INJECTOR_NAME)) 86 .andReturn(injector).anyTimes(); 87 expect(filterConfig.getServletContext()).andReturn(servletContext).anyTimes(); 88 89 globalControl.replay(); 90 91 guiceFilter = new GuiceFilter(); 92 guiceFilter.init(filterConfig); 93 } 94 95 @Override tearDown()96 public final void tearDown() { 97 assertNotNull(fooServlet); 98 assertNotNull(barServlet); 99 100 fooServlet = null; 101 barServlet = null; 102 103 guiceFilter.destroy(); 104 guiceFilter = null; 105 106 injector = null; 107 108 filterConfig = null; 109 servletContext = null; 110 111 globalControl.verify(); 112 } 113 testSimple()114 public void testSimple() throws Exception { 115 IMocksControl testControl = createControl(); 116 TestFilterChain testFilterChain = new TestFilterChain(); 117 HttpServletRequest req = testControl.createMock(HttpServletRequest.class); 118 HttpServletResponse res = testControl.createMock(HttpServletResponse.class); 119 120 expect(req.getMethod()).andReturn("GET").anyTimes(); 121 expect(req.getRequestURI()).andReturn("/bar/foo").anyTimes(); 122 expect(req.getServletPath()).andReturn("/bar/foo").anyTimes(); 123 expect(req.getContextPath()).andReturn("").anyTimes(); 124 125 testControl.replay(); 126 127 guiceFilter.doFilter(req, res, testFilterChain); 128 129 assertFalse(testFilterChain.isTriggered()); 130 assertFalse(fooServlet.isTriggered()); 131 assertTrue(barServlet.isTriggered()); 132 133 testControl.verify(); 134 } 135 136 // 137 // each of the following "runTest" calls takes three path parameters: 138 // 139 // The value of "getRequestURI()" 140 // The value of "getServletPath()" 141 // The value of "getContextPath()" 142 // 143 // these values have been captured using a filter in Apache Tomcat 6.0.32 144 // and are used for real-world values that a servlet container would send into 145 // the GuiceFilter. 146 // 147 // the remaining three booleans are: 148 // 149 // True if the request gets passed down the filter chain 150 // True if the request hits the "foo" servlet 151 // True if the request hits the "bar" sevlet 152 // 153 // After adjusting the request URI for the web app deployment location, all 154 // calls 155 // should always produce the same result. 156 // 157 158 // ROOT Web app, using Tomcat default servlet testRootDefault()159 public void testRootDefault() throws Exception { 160 // fetching /. Should go up the filter chain (only mappings on /foo/* and /bar/*). 161 runTest("/", "/", "", true, false, false); 162 // fetching /bar/. Should hit the bar servlet 163 runTest("/bar/", "/bar/", "", false, false, true); 164 // fetching /foo/xxx. Should hit the foo servlet 165 runTest("/foo/xxx", "/foo/xxx", "", false, true, false); 166 // fetching /xxx. Should go up the chain 167 runTest("/xxx", "/xxx", "", true, false, false); 168 } 169 170 // ROOT Web app, using explicit backing servlet mounted at /* testRootExplicit()171 public void testRootExplicit() throws Exception { 172 // fetching /. Should go up the filter chain (only mappings on /foo/* and /bar/*). 173 runTest("/", "", "", true, false, false); 174 // fetching /bar/. Should hit the bar servlet 175 runTest("/bar/", "", "", false, false, true); 176 // fetching /foo/xxx. Should hit the foo servlet 177 runTest("/foo/xxx", "", "", false, true, false); 178 // fetching /xxx. Should go up the chain 179 runTest("/xxx", "", "", true, false, false); 180 } 181 182 // ROOT Web app, using two backing servlets, mounted at /bar/* and /foo/* testRootSpecific()183 public void testRootSpecific() throws Exception { 184 // fetching /. Should go up the filter chain (only mappings on /foo/* and /bar/*). 185 runTest("/", "/", "", true, false, false); 186 // fetching /bar/. Should hit the bar servlet 187 runTest("/bar/", "/bar", "", false, false, true); 188 // fetching /foo/xxx. Should hit the foo servlet 189 runTest("/foo/xxx", "/foo", "", false, true, false); 190 // fetching /xxx. Should go up the chain 191 runTest("/xxx", "/xxx", "", true, false, false); 192 } 193 194 // Web app located at /webtest, using Tomcat default servlet testWebtestDefault()195 public void testWebtestDefault() throws Exception { 196 // fetching /. Should go up the filter chain (only mappings on /foo/* and /bar/*). 197 runTest("/webtest/", "/", "/webtest", true, false, false); 198 // fetching /bar/. Should hit the bar servlet 199 runTest("/webtest/bar/", "/bar/", "/webtest", false, false, true); 200 // fetching /foo/xxx. Should hit the foo servlet 201 runTest("/webtest/foo/xxx", "/foo/xxx", "/webtest", false, true, false); 202 // fetching /xxx. Should go up the chain 203 runTest("/webtest/xxx", "/xxx", "/webtest", true, false, false); 204 } 205 206 // Web app located at /webtest, using explicit backing servlet mounted at /* testWebtestExplicit()207 public void testWebtestExplicit() throws Exception { 208 // fetching /. Should go up the filter chain (only mappings on /foo/* and /bar/*). 209 runTest("/webtest/", "", "/webtest", true, false, false); 210 // fetching /bar/. Should hit the bar servlet 211 runTest("/webtest/bar/", "", "/webtest", false, false, true); 212 // fetching /foo/xxx. Should hit the foo servlet 213 runTest("/webtest/foo/xxx", "", "/webtest", false, true, false); 214 // fetching /xxx. Should go up the chain 215 runTest("/webtest/xxx", "", "/webtest", true, false, false); 216 } 217 218 // Web app located at /webtest, using two backing servlets, mounted at /bar/* 219 // and /foo/* testWebtestSpecific()220 public void testWebtestSpecific() throws Exception { 221 // fetching /. Should go up the filter chain (only mappings on /foo/* and 222 // /bar/*). 223 runTest("/webtest/", "/", "/webtest", true, false, false); 224 // fetching /bar/. Should hit the bar servlet 225 runTest("/webtest/bar/", "/bar", "/webtest", false, false, true); 226 // fetching /foo/xxx. Should hit the foo servlet 227 runTest("/webtest/foo/xxx", "/foo", "/webtest", false, true, false); 228 // fetching /xxx. Should go up the chain 229 runTest("/webtest/xxx", "/xxx", "/webtest", true, false, false); 230 } 231 runTest(final String requestURI, final String servletPath, final String contextPath, final boolean filterResult, final boolean fooResult, final boolean barResult)232 private void runTest(final String requestURI, final String servletPath, final String contextPath, 233 final boolean filterResult, final boolean fooResult, final boolean barResult) 234 throws Exception { 235 IMocksControl testControl = createControl(); 236 237 barServlet.clear(); 238 fooServlet.clear(); 239 240 TestFilterChain testFilterChain = new TestFilterChain(); 241 HttpServletRequest req = testControl.createMock(HttpServletRequest.class); 242 HttpServletResponse res = testControl.createMock(HttpServletResponse.class); 243 244 expect(req.getMethod()).andReturn("GET").anyTimes(); 245 expect(req.getRequestURI()).andReturn(requestURI).anyTimes(); 246 expect(req.getServletPath()).andReturn(servletPath).anyTimes(); 247 expect(req.getContextPath()).andReturn(contextPath).anyTimes(); 248 249 testControl.replay(); 250 251 guiceFilter.doFilter(req, res, testFilterChain); 252 253 assertEquals(filterResult, testFilterChain.isTriggered()); 254 assertEquals(fooResult, fooServlet.isTriggered()); 255 assertEquals(barResult, barServlet.isTriggered()); 256 257 testControl.verify(); 258 } 259 260 public static class TestServlet extends HttpServlet { 261 private boolean triggered = false; 262 263 @Override doGet(HttpServletRequest req, HttpServletResponse resp)264 public void doGet(HttpServletRequest req, HttpServletResponse resp) { 265 triggered = true; 266 } 267 isTriggered()268 public boolean isTriggered() { 269 return triggered; 270 } 271 clear()272 public void clear() { 273 triggered = false; 274 } 275 } 276 277 public static class TestFilterChain implements FilterChain { 278 private boolean triggered = false; 279 doFilter(ServletRequest request, ServletResponse response)280 public void doFilter(ServletRequest request, ServletResponse response) throws IOException, 281 ServletException { 282 triggered = true; 283 } 284 isTriggered()285 public boolean isTriggered() { 286 return triggered; 287 } 288 clear()289 public void clear() { 290 triggered = false; 291 } 292 } 293 } 294