| // |
| // ======================================================================== |
| // Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. |
| // ------------------------------------------------------------------------ |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v1.0 |
| // and Apache License v2.0 which accompanies this distribution. |
| // |
| // The Eclipse Public License is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // |
| // The Apache License v2.0 is available at |
| // http://www.opensource.org/licenses/apache2.0.php |
| // |
| // You may elect to redistribute this code under either of these licenses. |
| // ======================================================================== |
| // |
| |
| package org.eclipse.jetty.servlets; |
| |
| import java.io.BufferedReader; |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.OutputStream; |
| import java.io.StringReader; |
| import java.nio.charset.StandardCharsets; |
| import java.nio.file.Files; |
| import java.nio.file.Path; |
| |
| import javax.servlet.ServletException; |
| import javax.servlet.http.HttpServlet; |
| import javax.servlet.http.HttpServletRequest; |
| import javax.servlet.http.HttpServletResponse; |
| |
| import org.eclipse.jetty.server.LocalConnector; |
| import org.eclipse.jetty.server.Server; |
| import org.eclipse.jetty.servlet.ServletContextHandler; |
| import org.eclipse.jetty.servlet.ServletHolder; |
| import org.eclipse.jetty.toolchain.test.MavenTestingUtils; |
| import org.eclipse.jetty.webapp.WebAppContext; |
| import org.junit.After; |
| import org.junit.Assert; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| public class ConcatServletTest |
| { |
| private Server server; |
| private LocalConnector connector; |
| |
| @Before |
| public void prepareServer() throws Exception |
| { |
| server = new Server(); |
| connector = new LocalConnector(server); |
| server.addConnector(connector); |
| } |
| |
| @After |
| public void destroy() throws Exception |
| { |
| if (server != null) |
| server.stop(); |
| } |
| |
| @Test |
| public void testConcatenation() throws Exception |
| { |
| String contextPath = ""; |
| ServletContextHandler context = new ServletContextHandler(server, contextPath); |
| server.setHandler(context); |
| String concatPath = "/concat"; |
| context.addServlet(ConcatServlet.class, concatPath); |
| ServletHolder resourceServletHolder = new ServletHolder(new HttpServlet() |
| { |
| @Override |
| protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException |
| { |
| String includedURI = (String)request.getAttribute("javax.servlet.include.request_uri"); |
| response.getOutputStream().println(includedURI); |
| } |
| }); |
| context.addServlet(resourceServletHolder, "/resource/*"); |
| server.start(); |
| |
| String resource1 = "/resource/one.js"; |
| String resource2 = "/resource/two.js"; |
| String uri = contextPath + concatPath + "?" + resource1 + "&" + resource2; |
| String request = "" + |
| "GET " + uri + " HTTP/1.1\r\n" + |
| "Host: localhost\r\n" + |
| "Connection: close\r\n" + |
| "\r\n"; |
| String response = connector.getResponses(request); |
| try (BufferedReader reader = new BufferedReader(new StringReader(response))) |
| { |
| while (true) |
| { |
| String line = reader.readLine(); |
| if (line == null) |
| Assert.fail(); |
| if (line.trim().isEmpty()) |
| break; |
| } |
| Assert.assertEquals(resource1, reader.readLine()); |
| Assert.assertEquals(resource2, reader.readLine()); |
| Assert.assertNull(reader.readLine()); |
| } |
| } |
| |
| @Test |
| public void testWEBINFResourceIsNotServed() throws Exception |
| { |
| File directoryFile = MavenTestingUtils.getTargetTestingDir(); |
| Path directoryPath = directoryFile.toPath(); |
| Path hiddenDirectory = directoryPath.resolve("WEB-INF"); |
| Files.createDirectories(hiddenDirectory); |
| Path hiddenResource = hiddenDirectory.resolve("one.js"); |
| try (OutputStream output = Files.newOutputStream(hiddenResource)) |
| { |
| output.write("function() {}".getBytes(StandardCharsets.UTF_8)); |
| } |
| |
| String contextPath = ""; |
| WebAppContext context = new WebAppContext(server, directoryPath.toString(), contextPath); |
| server.setHandler(context); |
| String concatPath = "/concat"; |
| context.addServlet(ConcatServlet.class, concatPath); |
| server.start(); |
| |
| // Verify that I can get the file programmatically, as required by the spec. |
| Assert.assertNotNull(context.getServletContext().getResource("/WEB-INF/one.js")); |
| |
| // Having a path segment and then ".." triggers a special case |
| // that the ConcatServlet must detect and avoid. |
| String uri = contextPath + concatPath + "?/trick/../WEB-INF/one.js"; |
| String request = "" + |
| "GET " + uri + " HTTP/1.1\r\n" + |
| "Host: localhost\r\n" + |
| "Connection: close\r\n" + |
| "\r\n"; |
| String response = connector.getResponses(request); |
| Assert.assertTrue(response.startsWith("HTTP/1.1 404 ")); |
| |
| // Make sure ConcatServlet behaves well if it's case insensitive. |
| uri = contextPath + concatPath + "?/trick/../web-inf/one.js"; |
| request = "" + |
| "GET " + uri + " HTTP/1.1\r\n" + |
| "Host: localhost\r\n" + |
| "Connection: close\r\n" + |
| "\r\n"; |
| response = connector.getResponses(request); |
| Assert.assertTrue(response.startsWith("HTTP/1.1 404 ")); |
| |
| // Make sure ConcatServlet behaves well if encoded. |
| uri = contextPath + concatPath + "?/trick/..%2FWEB-INF%2Fone.js"; |
| request = "" + |
| "GET " + uri + " HTTP/1.1\r\n" + |
| "Host: localhost\r\n" + |
| "Connection: close\r\n" + |
| "\r\n"; |
| response = connector.getResponses(request); |
| Assert.assertTrue(response.startsWith("HTTP/1.1 404 ")); |
| |
| // Make sure ConcatServlet cannot see file system files. |
| uri = contextPath + concatPath + "?/trick/../../" + directoryFile.getName(); |
| request = "" + |
| "GET " + uri + " HTTP/1.1\r\n" + |
| "Host: localhost\r\n" + |
| "Connection: close\r\n" + |
| "\r\n"; |
| response = connector.getResponses(request); |
| Assert.assertTrue(response.startsWith("HTTP/1.1 404 ")); |
| } |
| } |