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. 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 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. 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", "/*", "/Tams nem ms.html", ""); 140 } 141 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. 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", "/(.)*", "/Tams nem ms.html", ""); 240 } 241 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