| // |
| // ======================================================================== |
| // 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.servlet; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.List; |
| import javax.servlet.ServletException; |
| import javax.servlet.ServletInputStream; |
| 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.hamcrest.Matcher; |
| import org.hamcrest.Matchers; |
| import org.junit.After; |
| import org.junit.Assert; |
| import org.junit.Test; |
| |
| public class DispatcherForwardTest |
| { |
| private Server server; |
| private LocalConnector connector; |
| private HttpServlet servlet1; |
| private HttpServlet servlet2; |
| private List<Exception> failures = new ArrayList<>(); |
| |
| public void prepare() throws Exception |
| { |
| server = new Server(); |
| connector = new LocalConnector(server); |
| server.addConnector(connector); |
| |
| ServletContextHandler context = new ServletContextHandler(server, "/"); |
| context.addServlet(new ServletHolder(servlet1), "/one"); |
| context.addServlet(new ServletHolder(servlet2), "/two"); |
| |
| server.start(); |
| } |
| |
| @After |
| public void dispose() throws Exception |
| { |
| for (Exception failure : failures) |
| throw failure; |
| server.stop(); |
| } |
| |
| // Replacement for Assert that allows to check failures after the response has been sent. |
| private <S> void checkThat(S item, Matcher<S> matcher) |
| { |
| if (!matcher.matches(item)) |
| failures.add(new Exception()); |
| } |
| |
| @Test |
| public void testQueryRetainedByForwardWithoutQuery() throws Exception |
| { |
| // 1. request /one?a=1 |
| // 1. forward /two |
| // 2. assert query => a=1 |
| // 1. assert query => a=1 |
| |
| final String query1 = "a=1"; |
| servlet1 = new HttpServlet() |
| { |
| @Override |
| protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException |
| { |
| checkThat(query1, Matchers.equalTo(req.getQueryString())); |
| |
| req.getRequestDispatcher("/two").forward(req, resp); |
| |
| checkThat(query1, Matchers.equalTo(req.getQueryString())); |
| checkThat("1", Matchers.equalTo(req.getParameter("a"))); |
| } |
| }; |
| servlet2 = new HttpServlet() |
| { |
| @Override |
| protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException |
| { |
| checkThat(query1, Matchers.equalTo(req.getQueryString())); |
| checkThat("1", Matchers.equalTo(req.getParameter("a"))); |
| } |
| }; |
| |
| prepare(); |
| |
| String request = "" + |
| "GET /one?" + query1 + " HTTP/1.1\r\n" + |
| "Host: localhost\r\n" + |
| "Connection: close\r\n" + |
| "\r\n"; |
| String response = connector.getResponses(request); |
| Assert.assertTrue(response, response.startsWith("HTTP/1.1 200")); |
| } |
| |
| @Test |
| public void testQueryReplacedByForwardWithQuery() throws Exception |
| { |
| // 1. request /one?a=1 |
| // 1. forward /two?a=2 |
| // 2. assert query => a=2 |
| // 1. assert query => a=1 |
| |
| final String query1 = "a=1&b=2"; |
| final String query2 = "a=3"; |
| final String query3 = "a=3&b=2"; |
| servlet1 = new HttpServlet() |
| { |
| @Override |
| protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException |
| { |
| checkThat(query1, Matchers.equalTo(req.getQueryString())); |
| |
| req.getRequestDispatcher("/two?" + query2).forward(req, resp); |
| |
| checkThat(query1, Matchers.equalTo(req.getQueryString())); |
| checkThat("1", Matchers.equalTo(req.getParameter("a"))); |
| checkThat("2", Matchers.equalTo(req.getParameter("b"))); |
| } |
| }; |
| servlet2 = new HttpServlet() |
| { |
| @Override |
| protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException |
| { |
| checkThat(query3, Matchers.equalTo(req.getQueryString())); |
| checkThat("3", Matchers.equalTo(req.getParameter("a"))); |
| checkThat("2", Matchers.equalTo(req.getParameter("b"))); |
| } |
| }; |
| |
| prepare(); |
| |
| String request = "" + |
| "GET /one?" + query1 + " HTTP/1.1\r\n" + |
| "Host: localhost\r\n" + |
| "Connection: close\r\n" + |
| "\r\n"; |
| String response = connector.getResponses(request); |
| Assert.assertTrue(response, response.startsWith("HTTP/1.1 200")); |
| } |
| |
| @Test |
| public void testQueryMergedByForwardWithQuery() throws Exception |
| { |
| // 1. request /one?a=1 |
| // 1. forward /two?b=2 |
| // 2. assert query => a=1&b=2 |
| // 1. assert query => a=1 |
| |
| final String query1 = "a=1"; |
| final String query2 = "b=2"; |
| final String query3 = "b=2&a=1"; |
| servlet1 = new HttpServlet() |
| { |
| @Override |
| protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException |
| { |
| checkThat(query1, Matchers.equalTo(req.getQueryString())); |
| |
| req.getRequestDispatcher("/two?" + query2).forward(req, resp); |
| |
| checkThat(query1, Matchers.equalTo(req.getQueryString())); |
| checkThat("1", Matchers.equalTo(req.getParameter("a"))); |
| } |
| }; |
| servlet2 = new HttpServlet() |
| { |
| @Override |
| protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException |
| { |
| checkThat(query3, Matchers.equalTo(req.getQueryString())); |
| checkThat("1", Matchers.equalTo(req.getParameter("a"))); |
| checkThat("2", Matchers.equalTo(req.getParameter("b"))); |
| } |
| }; |
| |
| prepare(); |
| |
| String request = "" + |
| "GET /one?" + query1 + " HTTP/1.1\r\n" + |
| "Host: localhost\r\n" + |
| "Connection: close\r\n" + |
| "\r\n"; |
| String response = connector.getResponses(request); |
| Assert.assertTrue(response, response.startsWith("HTTP/1.1 200")); |
| } |
| |
| @Test |
| public void testQueryAggregatesWithFormByForwardWithoutQuery() throws Exception |
| { |
| // 1. request /one?a=1 + content a=2 |
| // 1. forward /two |
| // 2. assert query => a=1 + params => a=1,2 |
| // 1. assert query => a=1 + params => a=1,2 |
| |
| final String query1 = "a=1"; |
| final String form = "a=2"; |
| servlet1 = new HttpServlet() |
| { |
| @Override |
| protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException |
| { |
| checkThat(query1, Matchers.equalTo(req.getQueryString())); |
| |
| req.getRequestDispatcher("/two").forward(req, resp); |
| |
| checkThat(query1, Matchers.equalTo(req.getQueryString())); |
| String[] values = req.getParameterValues("a"); |
| checkThat(values, Matchers.notNullValue()); |
| checkThat(2, Matchers.equalTo(values.length)); |
| checkThat(values, Matchers.arrayContainingInAnyOrder("1", "2")); |
| } |
| }; |
| servlet2 = new HttpServlet() |
| { |
| @Override |
| protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException |
| { |
| checkThat(query1, Matchers.equalTo(req.getQueryString())); |
| String[] values = req.getParameterValues("a"); |
| checkThat(values, Matchers.notNullValue()); |
| checkThat(2, Matchers.equalTo(values.length)); |
| checkThat(values, Matchers.arrayContainingInAnyOrder("1", "2")); |
| } |
| }; |
| |
| prepare(); |
| |
| String request = "" + |
| "POST /one?" + query1 + " HTTP/1.1\r\n" + |
| "Host: localhost\r\n" + |
| "Content-Type: application/x-www-form-urlencoded\r\n" + |
| "Content-Length: " + form.length() + "\r\n" + |
| "Connection: close\r\n" + |
| "\r\n" + |
| form; |
| String response = connector.getResponses(request); |
| Assert.assertTrue(response, response.startsWith("HTTP/1.1 200")); |
| } |
| |
| @Test |
| public void testQueryAggregatesWithFormReplacedByForwardWithQuery() throws Exception |
| { |
| // 1. request /one?a=1 + content a=2 |
| // 1. forward /two?a=3 |
| // 2. assert query => a=3 + params => a=3,2,1 |
| // 1. assert query => a=1 + params => a=1,2 |
| |
| final String query1 = "a=1"; |
| final String query2 = "a=3"; |
| final String form = "a=2"; |
| servlet1 = new HttpServlet() |
| { |
| @Override |
| protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException |
| { |
| checkThat(query1, Matchers.equalTo(req.getQueryString())); |
| |
| req.getRequestDispatcher("/two?" + query2).forward(req, resp); |
| |
| checkThat(query1, Matchers.equalTo(req.getQueryString())); |
| String[] values = req.getParameterValues("a"); |
| checkThat(values, Matchers.notNullValue()); |
| checkThat(2, Matchers.equalTo(values.length)); |
| checkThat(values, Matchers.arrayContainingInAnyOrder("1", "2")); |
| } |
| }; |
| servlet2 = new HttpServlet() |
| { |
| @Override |
| protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException |
| { |
| checkThat(query2, Matchers.equalTo(req.getQueryString())); |
| String[] values = req.getParameterValues("a"); |
| checkThat(values, Matchers.notNullValue()); |
| checkThat(3, Matchers.equalTo(values.length)); |
| checkThat(values, Matchers.arrayContainingInAnyOrder("3", "2", "1")); |
| } |
| }; |
| |
| prepare(); |
| |
| String request = "" + |
| "POST /one?" + query1 + " HTTP/1.1\r\n" + |
| "Host: localhost\r\n" + |
| "Content-Type: application/x-www-form-urlencoded\r\n" + |
| "Content-Length: " + form.length() + "\r\n" + |
| "Connection: close\r\n" + |
| "\r\n" + |
| form; |
| String response = connector.getResponses(request); |
| Assert.assertTrue(response, response.startsWith("HTTP/1.1 200")); |
| } |
| |
| @Test |
| public void testQueryAggregatesWithFormMergedByForwardWithQuery() throws Exception |
| { |
| // 1. request /one?a=1 + content b=2 |
| // 1. forward /two?c=3 |
| // 2. assert query => a=1&c=3 + params => a=1&b=2&c=3 |
| // 1. assert query => a=1 + params => a=1&b=2 |
| |
| final String query1 = "a=1"; |
| final String query2 = "c=3"; |
| final String query3 = "c=3&a=1"; |
| final String form = "b=2"; |
| servlet1 = new HttpServlet() |
| { |
| @Override |
| protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException |
| { |
| checkThat(query1, Matchers.equalTo(req.getQueryString())); |
| |
| req.getRequestDispatcher("/two?" + query2).forward(req, resp); |
| |
| checkThat(query1, Matchers.equalTo(req.getQueryString())); |
| checkThat("1", Matchers.equalTo(req.getParameter("a"))); |
| checkThat("2", Matchers.equalTo(req.getParameter("b"))); |
| checkThat(req.getParameter("c"), Matchers.nullValue()); |
| } |
| }; |
| servlet2 = new HttpServlet() |
| { |
| @Override |
| protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException |
| { |
| checkThat(query3, Matchers.equalTo(req.getQueryString())); |
| checkThat("1", Matchers.equalTo(req.getParameter("a"))); |
| checkThat("2", Matchers.equalTo(req.getParameter("b"))); |
| checkThat("3", Matchers.equalTo(req.getParameter("c"))); |
| } |
| }; |
| |
| prepare(); |
| |
| String request = "" + |
| "POST /one?" + query1 + " HTTP/1.1\r\n" + |
| "Host: localhost\r\n" + |
| "Content-Type: application/x-www-form-urlencoded\r\n" + |
| "Content-Length: " + form.length() + "\r\n" + |
| "Connection: close\r\n" + |
| "\r\n" + |
| form; |
| String response = connector.getResponses(request); |
| Assert.assertTrue(response, response.startsWith("HTTP/1.1 200")); |
| } |
| |
| @Test |
| public void testQueryAggregatesWithFormBeforeAndAfterForward() throws Exception |
| { |
| // 1. request /one?a=1 + content b=2 |
| // 1. assert params => a=1&b=2 |
| // 1. forward /two?c=3 |
| // 2. assert query => a=1&c=3 + params => a=1&b=2&c=3 |
| // 1. assert query => a=1 + params => a=1&b=2 |
| |
| final String query1 = "a=1"; |
| final String query2 = "c=3"; |
| final String query3 = "c=3&a=1"; |
| final String form = "b=2"; |
| servlet1 = new HttpServlet() |
| { |
| @Override |
| protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException |
| { |
| checkThat(query1, Matchers.equalTo(req.getQueryString())); |
| checkThat("1", Matchers.equalTo(req.getParameter("a"))); |
| checkThat("2", Matchers.equalTo(req.getParameter("b"))); |
| |
| req.getRequestDispatcher("/two?" + query2).forward(req, resp); |
| |
| checkThat(query1, Matchers.equalTo(req.getQueryString())); |
| checkThat("1", Matchers.equalTo(req.getParameter("a"))); |
| checkThat("2", Matchers.equalTo(req.getParameter("b"))); |
| checkThat(req.getParameter("c"), Matchers.nullValue()); |
| } |
| }; |
| servlet2 = new HttpServlet() |
| { |
| @Override |
| protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException |
| { |
| checkThat(query3, Matchers.equalTo(req.getQueryString())); |
| checkThat("1", Matchers.equalTo(req.getParameter("a"))); |
| checkThat("2", Matchers.equalTo(req.getParameter("b"))); |
| checkThat("3", Matchers.equalTo(req.getParameter("c"))); |
| } |
| }; |
| |
| prepare(); |
| |
| String request = "" + |
| "POST /one?" + query1 + " HTTP/1.1\r\n" + |
| "Host: localhost\r\n" + |
| "Content-Type: application/x-www-form-urlencoded\r\n" + |
| "Content-Length: " + form.length() + "\r\n" + |
| "Connection: close\r\n" + |
| "\r\n" + |
| form; |
| String response = connector.getResponses(request); |
| Assert.assertTrue(response, response.startsWith("HTTP/1.1 200")); |
| } |
| |
| @Test |
| public void testContentCanBeReadViaInputStreamAfterForwardWithoutQuery() throws Exception |
| { |
| final String query1 = "a=1"; |
| final String form = "c=3"; |
| servlet1 = new HttpServlet() |
| { |
| @Override |
| protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException |
| { |
| checkThat(query1, Matchers.equalTo(req.getQueryString())); |
| |
| req.getRequestDispatcher("/two").forward(req, resp); |
| |
| checkThat(query1, Matchers.equalTo(req.getQueryString())); |
| checkThat(req.getParameter("c"), Matchers.nullValue()); |
| } |
| }; |
| servlet2 = new HttpServlet() |
| { |
| @Override |
| protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException |
| { |
| checkThat(query1, Matchers.equalTo(req.getQueryString())); |
| ServletInputStream input = req.getInputStream(); |
| for (int i = 0; i < form.length(); ++i) |
| checkThat(form.charAt(i) & 0xFFFF, Matchers.equalTo(input.read())); |
| } |
| }; |
| |
| prepare(); |
| |
| String request = "" + |
| "POST /one?" + query1 + " HTTP/1.1\r\n" + |
| "Host: localhost\r\n" + |
| "Content-Type: application/x-www-form-urlencoded\r\n" + |
| "Content-Length: " + form.length() + "\r\n" + |
| "Connection: close\r\n" + |
| "\r\n" + |
| form; |
| String response = connector.getResponses(request); |
| Assert.assertTrue(response, response.startsWith("HTTP/1.1 200")); |
| } |
| |
| @Test |
| public void testContentCanBeReadViaInputStreamAfterForwardWithQuery() throws Exception |
| { |
| final String query1 = "a=1"; |
| final String query2 = "b=2"; |
| final String query3 = "b=2&a=1"; |
| final String form = "c=3"; |
| servlet1 = new HttpServlet() |
| { |
| @Override |
| protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException |
| { |
| checkThat(query1, Matchers.equalTo(req.getQueryString())); |
| |
| req.getRequestDispatcher("/two?" + query2).forward(req, resp); |
| |
| checkThat(query1, Matchers.equalTo(req.getQueryString())); |
| checkThat(req.getParameter("c"), Matchers.nullValue()); |
| } |
| }; |
| servlet2 = new HttpServlet() |
| { |
| @Override |
| protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException |
| { |
| checkThat(query3, Matchers.equalTo(req.getQueryString())); |
| ServletInputStream input = req.getInputStream(); |
| for (int i = 0; i < form.length(); ++i) |
| checkThat(form.charAt(i) & 0xFFFF, Matchers.equalTo(input.read())); |
| checkThat(-1, Matchers.equalTo(input.read())); |
| } |
| }; |
| |
| prepare(); |
| |
| String request = "" + |
| "POST /one?" + query1 + " HTTP/1.1\r\n" + |
| "Host: localhost\r\n" + |
| "Content-Type: application/x-www-form-urlencoded\r\n" + |
| "Content-Length: " + form.length() + "\r\n" + |
| "Connection: close\r\n" + |
| "\r\n" + |
| form; |
| String response = connector.getResponses(request); |
| Assert.assertTrue(response, response.startsWith("HTTP/1.1 200")); |
| } |
| |
| // TODO: add multipart tests |
| } |