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 17package com.google.inject.servlet; 18 19import static org.easymock.EasyMock.createControl; 20import static org.easymock.EasyMock.expect; 21 22import com.google.inject.Guice; 23import com.google.inject.Inject; 24import com.google.inject.Injector; 25import com.google.inject.Key; 26import com.google.inject.Scopes; 27import com.google.inject.name.Named; 28import com.google.inject.name.Names; 29 30import junit.framework.TestCase; 31 32import org.easymock.IMocksControl; 33 34import java.io.IOException; 35 36import javax.servlet.FilterChain; 37import javax.servlet.FilterConfig; 38import javax.servlet.ServletContext; 39import javax.servlet.ServletException; 40import javax.servlet.ServletRequest; 41import javax.servlet.ServletResponse; 42import javax.servlet.http.HttpServlet; 43import javax.servlet.http.HttpServletRequest; 44import javax.servlet.http.HttpServletResponse; 45 46/** Tests to make sure that servlets with a context path are handled right. */ 47public 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 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 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 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 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 /* 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/* 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 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 /* 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/* 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 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 264 public void doGet(HttpServletRequest req, HttpServletResponse resp) { 265 triggered = true; 266 } 267 268 public boolean isTriggered() { 269 return triggered; 270 } 271 272 public void clear() { 273 triggered = false; 274 } 275 } 276 277 public static class TestFilterChain implements FilterChain { 278 private boolean triggered = false; 279 280 public void doFilter(ServletRequest request, ServletResponse response) throws IOException, 281 ServletException { 282 triggered = true; 283 } 284 285 public boolean isTriggered() { 286 return triggered; 287 } 288 289 public void clear() { 290 triggered = false; 291 } 292 } 293} 294