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