1 /* 2 * Copyright (C) 2008 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 com.google.inject.servlet.ManagedServletPipeline.REQUEST_DISPATCHER_REQUEST; 20 import static org.easymock.EasyMock.anyObject; 21 import static org.easymock.EasyMock.createMock; 22 import static org.easymock.EasyMock.expect; 23 import static org.easymock.EasyMock.replay; 24 import static org.easymock.EasyMock.verify; 25 26 import com.google.common.collect.Sets; 27 import com.google.inject.Binding; 28 import com.google.inject.Injector; 29 import com.google.inject.Key; 30 import com.google.inject.spi.BindingScopingVisitor; 31 import java.io.IOException; 32 import java.util.HashMap; 33 import javax.servlet.ServletException; 34 import javax.servlet.http.HttpServlet; 35 import javax.servlet.http.HttpServletRequest; 36 import javax.servlet.http.HttpServletResponse; 37 import junit.framework.TestCase; 38 39 /** 40 * Ensures servlet spec compliance for CGI-style variables and general path/pattern matching. 41 * 42 * @author Dhanji R. Prasanna (dhanji@gmail com) 43 */ 44 public class ServletDefinitionPathsTest extends TestCase { 45 46 // Data-driven test. testServletPathMatching()47 public final void testServletPathMatching() throws IOException, ServletException { 48 servletPath("/index.html", "*.html", "/index.html"); 49 servletPath("/somewhere/index.html", "*.html", "/somewhere/index.html"); 50 servletPath("/somewhere/index.html", "/*", ""); 51 servletPath("/index.html", "/*", ""); 52 servletPath("/", "/*", ""); 53 servletPath("//", "/*", ""); 54 servletPath("/////", "/*", ""); 55 servletPath("", "/*", ""); 56 servletPath("/thing/index.html", "/thing/*", "/thing"); 57 servletPath("/thing/wing/index.html", "/thing/*", "/thing"); 58 } 59 servletPath( final String requestPath, String mapping, final String expectedServletPath)60 private void servletPath( 61 final String requestPath, String mapping, final String expectedServletPath) 62 throws IOException, ServletException { 63 64 Injector injector = createMock(Injector.class); 65 Binding binding = createMock(Binding.class); 66 HttpServletRequest request = createMock(HttpServletRequest.class); 67 HttpServletResponse response = createMock(HttpServletResponse.class); 68 69 expect(binding.acceptScopingVisitor((BindingScopingVisitor) anyObject())).andReturn(true); 70 expect(injector.getBinding(Key.get(HttpServlet.class))).andReturn(binding); 71 72 final boolean[] run = new boolean[1]; 73 //get an instance of this servlet 74 expect(injector.getInstance(Key.get(HttpServlet.class))) 75 .andReturn( 76 new HttpServlet() { 77 78 @Override 79 protected void service( 80 HttpServletRequest servletRequest, HttpServletResponse httpServletResponse) 81 throws ServletException, IOException { 82 83 final String path = servletRequest.getServletPath(); 84 assertEquals( 85 String.format("expected [%s] but was [%s]", expectedServletPath, path), 86 expectedServletPath, 87 path); 88 run[0] = true; 89 } 90 }); 91 92 expect(request.getServletPath()).andReturn(requestPath); 93 94 replay(injector, binding, request); 95 96 ServletDefinition servletDefinition = 97 new ServletDefinition( 98 Key.get(HttpServlet.class), 99 UriPatternType.get(UriPatternType.SERVLET, mapping), 100 new HashMap<String, String>(), 101 null); 102 103 servletDefinition.init(null, injector, Sets.<HttpServlet>newIdentityHashSet()); 104 servletDefinition.doService(request, response); 105 106 assertTrue("Servlet did not run!", run[0]); 107 108 verify(injector, binding, request); 109 } 110 111 // Data-driven test. testPathInfoWithServletStyleMatching()112 public final void testPathInfoWithServletStyleMatching() throws IOException, ServletException { 113 pathInfoWithServletStyleMatching("/path/index.html", "/path", "/*", "/index.html", ""); 114 pathInfoWithServletStyleMatching( 115 "/path//hulaboo///index.html", "/path", "/*", "/hulaboo/index.html", ""); 116 pathInfoWithServletStyleMatching("/path/", "/path", "/*", "/", ""); 117 pathInfoWithServletStyleMatching("/path////////", "/path", "/*", "/", ""); 118 119 // a servlet mapping of /thing/* 120 pathInfoWithServletStyleMatching("/path/thing////////", "/path", "/thing/*", "/", "/thing"); 121 pathInfoWithServletStyleMatching("/path/thing/stuff", "/path", "/thing/*", "/stuff", "/thing"); 122 pathInfoWithServletStyleMatching( 123 "/path/thing/stuff.html", "/path", "/thing/*", "/stuff.html", "/thing"); 124 pathInfoWithServletStyleMatching("/path/thing", "/path", "/thing/*", null, "/thing"); 125 126 // see external issue 372 127 pathInfoWithServletStyleMatching( 128 "/path/some/path/of.jsp", "/path", "/thing/*", null, "/some/path/of.jsp"); 129 130 // *.xx style mapping 131 pathInfoWithServletStyleMatching("/path/thing.thing", "/path", "*.thing", null, "/thing.thing"); 132 pathInfoWithServletStyleMatching("/path///h.thing", "/path", "*.thing", null, "/h.thing"); 133 pathInfoWithServletStyleMatching( 134 "/path///...//h.thing", "/path", "*.thing", null, "/.../h.thing"); 135 pathInfoWithServletStyleMatching("/path/my/h.thing", "/path", "*.thing", null, "/my/h.thing"); 136 137 // Encoded URLs 138 pathInfoWithServletStyleMatching("/path/index%2B.html", "/path", "/*", "/index+.html", ""); 139 pathInfoWithServletStyleMatching( 140 "/path/a%20file%20with%20spaces%20in%20name.html", 141 "/path", "/*", "/a file with spaces in name.html", ""); 142 pathInfoWithServletStyleMatching( 143 "/path/Tam%C3%A1s%20nem%20m%C3%A1s.html", "/path", "/*", "/Tamás nem más.html", ""); 144 } 145 pathInfoWithServletStyleMatching( final String requestUri, final String contextPath, String mapping, final String expectedPathInfo, final String servletPath)146 private void pathInfoWithServletStyleMatching( 147 final String requestUri, 148 final String contextPath, 149 String mapping, 150 final String expectedPathInfo, 151 final String servletPath) 152 throws IOException, ServletException { 153 154 Injector injector = createMock(Injector.class); 155 Binding binding = createMock(Binding.class); 156 HttpServletRequest request = createMock(HttpServletRequest.class); 157 HttpServletResponse response = createMock(HttpServletResponse.class); 158 159 expect(binding.acceptScopingVisitor((BindingScopingVisitor) anyObject())).andReturn(true); 160 expect(injector.getBinding(Key.get(HttpServlet.class))).andReturn(binding); 161 162 final boolean[] run = new boolean[1]; 163 //get an instance of this servlet 164 expect(injector.getInstance(Key.get(HttpServlet.class))) 165 .andReturn( 166 new HttpServlet() { 167 168 @Override 169 protected void service( 170 HttpServletRequest servletRequest, HttpServletResponse httpServletResponse) 171 throws ServletException, IOException { 172 173 final String path = servletRequest.getPathInfo(); 174 175 if (null == expectedPathInfo) { 176 assertNull( 177 String.format("expected [%s] but was [%s]", expectedPathInfo, path), path); 178 } else { 179 assertEquals( 180 String.format("expected [%s] but was [%s]", expectedPathInfo, path), 181 expectedPathInfo, 182 path); 183 } 184 185 //assert memoizer 186 //noinspection StringEquality 187 assertSame("memo field did not work", path, servletRequest.getPathInfo()); 188 189 run[0] = true; 190 } 191 }); 192 193 expect(request.getRequestURI()).andReturn(requestUri); 194 195 expect(request.getServletPath()).andReturn(servletPath).anyTimes(); 196 197 expect(request.getContextPath()).andReturn(contextPath); 198 199 expect(request.getAttribute(REQUEST_DISPATCHER_REQUEST)).andReturn(null); 200 201 replay(injector, binding, request); 202 203 ServletDefinition servletDefinition = 204 new ServletDefinition( 205 Key.get(HttpServlet.class), 206 UriPatternType.get(UriPatternType.SERVLET, mapping), 207 new HashMap<String, String>(), 208 null); 209 210 servletDefinition.init(null, injector, Sets.<HttpServlet>newIdentityHashSet()); 211 servletDefinition.doService(request, response); 212 213 assertTrue("Servlet did not run!", run[0]); 214 215 verify(injector, binding, request); 216 } 217 218 // Data-driven test. testPathInfoWithRegexMatching()219 public final void testPathInfoWithRegexMatching() throws IOException, ServletException { 220 // first a mapping of /* 221 pathInfoWithRegexMatching("/path/index.html", "/path", "/(.)*", "/index.html", ""); 222 pathInfoWithRegexMatching( 223 "/path//hulaboo///index.html", "/path", "/(.)*", "/hulaboo/index.html", ""); 224 pathInfoWithRegexMatching("/path/", "/path", "/(.)*", "/", ""); 225 pathInfoWithRegexMatching("/path////////", "/path", "/(.)*", "/", ""); 226 227 // a servlet mapping of /thing/* 228 pathInfoWithRegexMatching("/path/thing////////", "/path", "/thing/(.)*", "/", "/thing"); 229 pathInfoWithRegexMatching("/path/thing/stuff", "/path", "/thing/(.)*", "/stuff", "/thing"); 230 pathInfoWithRegexMatching( 231 "/path/thing/stuff.html", "/path", "/thing/(.)*", "/stuff.html", "/thing"); 232 pathInfoWithRegexMatching("/path/thing", "/path", "/thing/(.)*", null, "/thing"); 233 234 // *.xx style mapping 235 pathInfoWithRegexMatching("/path/thing.thing", "/path", ".*\\.thing", null, "/thing.thing"); 236 pathInfoWithRegexMatching("/path///h.thing", "/path", ".*\\.thing", null, "/h.thing"); 237 pathInfoWithRegexMatching("/path///...//h.thing", "/path", ".*\\.thing", null, "/.../h.thing"); 238 pathInfoWithRegexMatching("/path/my/h.thing", "/path", ".*\\.thing", null, "/my/h.thing"); 239 240 // path 241 pathInfoWithRegexMatching( 242 "/path/test.com/com.test.MyServletModule", 243 "", 244 "/path/[^/]+/(.*)", 245 "com.test.MyServletModule", 246 "/path/test.com/com.test.MyServletModule"); 247 248 // Encoded URLs 249 pathInfoWithRegexMatching("/path/index%2B.html", "/path", "/(.)*", "/index+.html", ""); 250 pathInfoWithRegexMatching( 251 "/path/a%20file%20with%20spaces%20in%20name.html", 252 "/path", "/(.)*", "/a file with spaces in name.html", ""); 253 pathInfoWithRegexMatching( 254 "/path/Tam%C3%A1s%20nem%20m%C3%A1s.html", "/path", "/(.)*", "/Tamás nem más.html", ""); 255 } 256 pathInfoWithRegexMatching( final String requestUri, final String contextPath, String mapping, final String expectedPathInfo, final String servletPath)257 public final void pathInfoWithRegexMatching( 258 final String requestUri, 259 final String contextPath, 260 String mapping, 261 final String expectedPathInfo, 262 final String servletPath) 263 throws IOException, ServletException { 264 265 Injector injector = createMock(Injector.class); 266 Binding binding = createMock(Binding.class); 267 HttpServletRequest request = createMock(HttpServletRequest.class); 268 HttpServletResponse response = createMock(HttpServletResponse.class); 269 270 expect(binding.acceptScopingVisitor((BindingScopingVisitor) anyObject())).andReturn(true); 271 expect(injector.getBinding(Key.get(HttpServlet.class))).andReturn(binding); 272 273 final boolean[] run = new boolean[1]; 274 //get an instance of this servlet 275 expect(injector.getInstance(Key.get(HttpServlet.class))) 276 .andReturn( 277 new HttpServlet() { 278 279 @Override 280 protected void service( 281 HttpServletRequest servletRequest, HttpServletResponse httpServletResponse) 282 throws ServletException, IOException { 283 284 final String path = servletRequest.getPathInfo(); 285 286 if (null == expectedPathInfo) { 287 assertNull( 288 String.format("expected [%s] but was [%s]", expectedPathInfo, path), path); 289 } else { 290 assertEquals( 291 String.format("expected [%s] but was [%s]", expectedPathInfo, path), 292 expectedPathInfo, 293 path); 294 } 295 296 //assert memoizer 297 //noinspection StringEquality 298 assertSame("memo field did not work", path, servletRequest.getPathInfo()); 299 300 run[0] = true; 301 } 302 }); 303 304 expect(request.getRequestURI()).andReturn(requestUri); 305 306 expect(request.getServletPath()).andReturn(servletPath).anyTimes(); 307 308 expect(request.getContextPath()).andReturn(contextPath); 309 310 expect(request.getAttribute(REQUEST_DISPATCHER_REQUEST)).andReturn(null); 311 312 replay(injector, binding, request); 313 314 ServletDefinition servletDefinition = 315 new ServletDefinition( 316 Key.get(HttpServlet.class), 317 UriPatternType.get(UriPatternType.REGEX, mapping), 318 new HashMap<String, String>(), 319 null); 320 321 servletDefinition.init(null, injector, Sets.<HttpServlet>newIdentityHashSet()); 322 servletDefinition.doService(request, response); 323 324 assertTrue("Servlet did not run!", run[0]); 325 326 verify(injector, binding, request); 327 } 328 } 329