|
1 | 1 | /*
|
2 |
| - * Copyright 2002-2012 the original author or authors. |
| 2 | + * Copyright 2002-2014 the original author or authors. |
3 | 3 | *
|
4 | 4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
5 | 5 | * you may not use this file except in compliance with the License.
|
|
16 | 16 |
|
17 | 17 | package org.springframework.web.servlet.resource;
|
18 | 18 |
|
| 19 | +import static org.junit.Assert.assertEquals; |
| 20 | +import static org.junit.Assert.assertSame; |
| 21 | +import static org.junit.Assert.assertTrue; |
| 22 | + |
19 | 23 | import java.util.ArrayList;
|
20 | 24 | import java.util.Arrays;
|
21 | 25 | import java.util.List;
|
|
26 | 30 | import org.junit.Test;
|
27 | 31 | import org.springframework.core.io.ClassPathResource;
|
28 | 32 | import org.springframework.core.io.Resource;
|
| 33 | +import org.springframework.core.io.UrlResource; |
29 | 34 | import org.springframework.mock.web.test.MockHttpServletRequest;
|
30 | 35 | import org.springframework.mock.web.test.MockHttpServletResponse;
|
31 | 36 | import org.springframework.mock.web.test.MockServletContext;
|
32 | 37 | import org.springframework.web.HttpRequestMethodNotSupportedException;
|
33 | 38 | import org.springframework.web.servlet.HandlerMapping;
|
34 | 39 |
|
35 |
| -import static org.junit.Assert.*; |
36 |
| - |
37 | 40 | /**
|
38 | 41 | * @author Keith Donald
|
39 | 42 | * @author Jeremy Grelle
|
@@ -124,28 +127,76 @@ public void getResourceFromSubDirectoryOfAlternatePath() throws Exception {
|
124 | 127 | assertEquals("function foo() { console.log(\"hello world\"); }", response.getContentAsString());
|
125 | 128 | }
|
126 | 129 |
|
| 130 | + |
127 | 131 | @Test
|
128 |
| - public void getResourceViaDirectoryTraversal() throws Exception { |
| 132 | + public void invalidPath() throws Exception { |
129 | 133 | MockHttpServletRequest request = new MockHttpServletRequest();
|
130 | 134 | request.setMethod("GET");
|
131 |
| - |
132 |
| - request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "../testsecret/secret.txt"); |
133 | 135 | MockHttpServletResponse response = new MockHttpServletResponse();
|
134 |
| - handler.handleRequest(request, response); |
135 |
| - assertEquals(404, response.getStatus()); |
136 | 136 |
|
137 |
| - request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "test/../../testsecret/secret.txt"); |
| 137 | + Resource location = new ClassPathResource("test/", getClass()); |
| 138 | + this.handler.setLocations(Arrays.asList(location)); |
| 139 | + |
| 140 | + testInvalidPath(location, "../testsecret/secret.txt", request, response); |
| 141 | + testInvalidPath(location, "test/../../testsecret/secret.txt", request, response); |
| 142 | + testInvalidPath(location, ":/../../testsecret/secret.txt", request, response); |
| 143 | + |
| 144 | + location = new UrlResource(getClass().getResource("./test/")); |
| 145 | + this.handler.setLocations(Arrays.asList(location)); |
| 146 | + Resource secretResource = new UrlResource(getClass().getResource("testsecret/secret.txt")); |
| 147 | + String secretPath = secretResource.getURL().getPath(); |
| 148 | + |
| 149 | + testInvalidPath(location, "file:" + secretPath, request, response); |
| 150 | + testInvalidPath(location, "/file:" + secretPath, request, response); |
| 151 | + testInvalidPath(location, "url:" + secretPath, request, response); |
| 152 | + testInvalidPath(location, "/url:" + secretPath, request, response); |
| 153 | + testInvalidPath(location, "/" + secretPath, request, response); |
| 154 | + testInvalidPath(location, "////../.." + secretPath, request, response); |
| 155 | + testInvalidPath(location, "/%2E%2E/testsecret/secret.txt", request, response); |
| 156 | + testInvalidPath(location, "/%2e%2e/testsecret/secret.txt", request, response); |
| 157 | + testInvalidPath(location, " " + secretPath, request, response); |
| 158 | + testInvalidPath(location, "/ " + secretPath, request, response); |
| 159 | + testInvalidPath(location, "url:" + secretPath, request, response); |
| 160 | + } |
| 161 | + |
| 162 | + @Test |
| 163 | + public void ignoreInvalidEscapeSequence() throws Exception { |
| 164 | + MockHttpServletRequest request = new MockHttpServletRequest(); |
| 165 | + request.setMethod("GET"); |
| 166 | + MockHttpServletResponse response = new MockHttpServletResponse(); |
| 167 | + request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "/%foo%/bar.txt"); |
138 | 168 | response = new MockHttpServletResponse();
|
139 |
| - handler.handleRequest(request, response); |
| 169 | + this.handler.handleRequest(request, response); |
140 | 170 | assertEquals(404, response.getStatus());
|
| 171 | + } |
141 | 172 |
|
142 |
| - handler.setLocations(Arrays.<Resource>asList(new ClassPathResource("testsecret/", getClass()))); |
143 |
| - request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "secret.txt"); |
144 |
| - response = new MockHttpServletResponse(); |
145 |
| - handler.handleRequest(request, response); |
146 |
| - assertEquals(200, response.getStatus()); |
147 |
| - assertEquals("text/plain", response.getContentType()); |
148 |
| - assertEquals("big secret", response.getContentAsString()); |
| 173 | + @Test |
| 174 | + public void processPath() throws Exception { |
| 175 | + assertSame("/foo/bar", this.handler.processPath("/foo/bar")); |
| 176 | + assertSame("foo/bar", this.handler.processPath("foo/bar")); |
| 177 | + |
| 178 | + // leading whitespace control characters (00-1F) |
| 179 | + assertEquals("/foo/bar", this.handler.processPath(" /foo/bar")); |
| 180 | + assertEquals("/foo/bar", this.handler.processPath((char) 1 + "/foo/bar")); |
| 181 | + assertEquals("/foo/bar", this.handler.processPath((char) 31 + "/foo/bar")); |
| 182 | + assertEquals("foo/bar", this.handler.processPath(" foo/bar")); |
| 183 | + assertEquals("foo/bar", this.handler.processPath((char) 31 + "foo/bar")); |
| 184 | + |
| 185 | + // leading control character 0x7F (DEL) |
| 186 | + assertEquals("/foo/bar", this.handler.processPath((char) 127 + "/foo/bar")); |
| 187 | + assertEquals("/foo/bar", this.handler.processPath((char) 127 + "/foo/bar")); |
| 188 | + |
| 189 | + // leading control and '/' characters |
| 190 | + assertEquals("/foo/bar", this.handler.processPath(" / foo/bar")); |
| 191 | + assertEquals("/foo/bar", this.handler.processPath(" / / foo/bar")); |
| 192 | + assertEquals("/foo/bar", this.handler.processPath(" // /// //// foo/bar")); |
| 193 | + assertEquals("/foo/bar", this.handler.processPath((char) 1 + " / " + (char) 127 + " // foo/bar")); |
| 194 | + |
| 195 | + // root ot empty path |
| 196 | + assertEquals("", this.handler.processPath(" ")); |
| 197 | + assertEquals("/", this.handler.processPath("/")); |
| 198 | + assertEquals("/", this.handler.processPath("///")); |
| 199 | + assertEquals("/", this.handler.processPath("/ / / ")); |
149 | 200 | }
|
150 | 201 |
|
151 | 202 | @Test
|
@@ -219,6 +270,16 @@ public void resourceNotFound() throws Exception {
|
219 | 270 | assertEquals(404, response.getStatus());
|
220 | 271 | }
|
221 | 272 |
|
| 273 | + private void testInvalidPath(Resource location, String requestPath, |
| 274 | + MockHttpServletRequest request, MockHttpServletResponse response) throws Exception { |
| 275 | + |
| 276 | + request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, requestPath); |
| 277 | + response = new MockHttpServletResponse(); |
| 278 | + this.handler.handleRequest(request, response); |
| 279 | + assertTrue(location.createRelative(requestPath).exists()); |
| 280 | + assertEquals(404, response.getStatus()); |
| 281 | + } |
| 282 | + |
222 | 283 |
|
223 | 284 | private static class TestServletContext extends MockServletContext {
|
224 | 285 |
|
|
0 commit comments