Merge branch `jetty-9.4.x` into `jetty-10.0.x`
Signed-off-by: Joakim Erdfelt <joakim.erdfelt@gmail.com> # Conflicts: # VERSION.txt # aggregates/jetty-all-compact3/pom.xml # aggregates/jetty-all/pom.xml # apache-jsp/pom.xml # apache-jstl/pom.xml # build-resources/pom.xml # examples/async-rest/async-rest-jar/pom.xml # examples/async-rest/async-rest-webapp/pom.xml # examples/async-rest/pom.xml # examples/embedded/pom.xml # examples/pom.xml # jetty-alpn/jetty-alpn-client/pom.xml # jetty-alpn/jetty-alpn-conscrypt-client/pom.xml # jetty-alpn/jetty-alpn-conscrypt-server/pom.xml # jetty-alpn/jetty-alpn-java-client/pom.xml # jetty-alpn/jetty-alpn-java-server/pom.xml # jetty-alpn/jetty-alpn-openjdk8-client/pom.xml # jetty-alpn/jetty-alpn-openjdk8-server/pom.xml # jetty-alpn/jetty-alpn-server/pom.xml # jetty-alpn/pom.xml # jetty-annotations/pom.xml # jetty-ant/pom.xml # jetty-bom/pom.xml # jetty-cdi/pom.xml # jetty-client/pom.xml # jetty-continuation/pom.xml # jetty-deploy/pom.xml # jetty-distribution/pom.xml # jetty-documentation/pom.xml # jetty-fcgi/fcgi-client/pom.xml # jetty-fcgi/fcgi-server/pom.xml # jetty-fcgi/pom.xml # jetty-gcloud/jetty-gcloud-session-manager/pom.xml # jetty-gcloud/pom.xml # jetty-hazelcast/pom.xml # jetty-home/pom.xml # jetty-http-spi/pom.xml # jetty-http/pom.xml # jetty-http2/http2-alpn-tests/pom.xml # jetty-http2/http2-client/pom.xml # jetty-http2/http2-common/pom.xml # jetty-http2/http2-hpack/pom.xml # jetty-http2/http2-http-client-transport/pom.xml # jetty-http2/http2-server/pom.xml # jetty-http2/pom.xml # jetty-infinispan/infinispan-common/pom.xml # jetty-infinispan/infinispan-embedded-query/pom.xml # jetty-infinispan/infinispan-embedded/pom.xml # jetty-infinispan/infinispan-remote-query/pom.xml # jetty-infinispan/infinispan-remote/pom.xml # jetty-infinispan/pom.xml # jetty-io/pom.xml # jetty-jaas/pom.xml # jetty-jaspi/pom.xml # jetty-jmx/pom.xml # jetty-jndi/pom.xml # jetty-jspc-maven-plugin/pom.xml # jetty-maven-plugin/pom.xml # jetty-memcached/jetty-memcached-sessions/pom.xml # jetty-memcached/pom.xml # jetty-nosql/pom.xml # jetty-openid/pom.xml # jetty-osgi/jetty-osgi-alpn/pom.xml # jetty-osgi/jetty-osgi-boot-jsp/pom.xml # jetty-osgi/jetty-osgi-boot-warurl/pom.xml # jetty-osgi/jetty-osgi-boot/pom.xml # jetty-osgi/jetty-osgi-httpservice/pom.xml # jetty-osgi/pom.xml # jetty-osgi/test-jetty-osgi-context/pom.xml # jetty-osgi/test-jetty-osgi-fragment/pom.xml # jetty-osgi/test-jetty-osgi-server/pom.xml # jetty-osgi/test-jetty-osgi-webapp/pom.xml # jetty-osgi/test-jetty-osgi/pom.xml # jetty-plus/pom.xml # jetty-proxy/pom.xml # jetty-quickstart/pom.xml # jetty-rewrite/pom.xml # jetty-runner/pom.xml # jetty-security/pom.xml # jetty-server/pom.xml # jetty-server/src/test/java/org/eclipse/jetty/server/ErrorHandlerTest.java # jetty-servlet/pom.xml # jetty-servlets/pom.xml # jetty-spring/pom.xml # jetty-start/pom.xml # jetty-unixsocket/pom.xml # jetty-util-ajax/pom.xml # jetty-util/pom.xml # jetty-webapp/pom.xml # jetty-websocket/javax-websocket-client/pom.xml # jetty-websocket/javax-websocket-server/pom.xml # jetty-websocket/jetty-websocket-api/pom.xml # jetty-websocket/jetty-websocket-common/pom.xml # jetty-websocket/jetty-websocket-server/pom.xml # jetty-websocket/jetty-websocket-tests/pom.xml # jetty-websocket/pom.xml # jetty-websocket/websocket-core/pom.xml # jetty-websocket/websocket-servlet/pom.xml # jetty-xml/pom.xml # pom.xml # tests/jetty-jmh/pom.xml # tests/pom.xml # tests/test-continuation/pom.xml # tests/test-distribution/pom.xml # tests/test-http-client-transport/pom.xml # tests/test-integration/pom.xml # tests/test-jmx/jmx-webapp-it/pom.xml # tests/test-jmx/jmx-webapp/pom.xml # tests/test-jmx/pom.xml # tests/test-loginservice/pom.xml # tests/test-quickstart/pom.xml # tests/test-sessions/pom.xml # tests/test-sessions/test-file-sessions/pom.xml # tests/test-sessions/test-gcloud-sessions/pom.xml # tests/test-sessions/test-hazelcast-sessions/pom.xml # tests/test-sessions/test-infinispan-sessions/pom.xml # tests/test-sessions/test-jdbc-sessions/pom.xml # tests/test-sessions/test-memcached-sessions/pom.xml # tests/test-sessions/test-mongodb-sessions/pom.xml # tests/test-sessions/test-sessions-common/pom.xml # tests/test-webapps/pom.xml # tests/test-webapps/test-cdi-common-webapp/pom.xml # tests/test-webapps/test-felix-webapp/pom.xml # tests/test-webapps/test-http2-webapp/pom.xml # tests/test-webapps/test-jaas-webapp/pom.xml # tests/test-webapps/test-jetty-webapp/pom.xml # tests/test-webapps/test-jndi-webapp/pom.xml # tests/test-webapps/test-mock-resources/pom.xml # tests/test-webapps/test-owb-cdi-webapp/pom.xml # tests/test-webapps/test-proxy-webapp/pom.xml # tests/test-webapps/test-servlet-spec/pom.xml # tests/test-webapps/test-servlet-spec/test-container-initializer/pom.xml # tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml # tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml # tests/test-webapps/test-simple-webapp/pom.xml # tests/test-webapps/test-webapp-rfc2616/pom.xml # tests/test-webapps/test-weld-cdi-webapp/pom.xml
This commit is contained in:
commit
2777229867
|
@ -13,7 +13,7 @@ staleLabel: Stale
|
|||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has been a
|
||||
full year without activit. It will be closed if no further activity occurs.
|
||||
full year without activity. It will be closed if no further activity occurs.
|
||||
Thank you for your contributions.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: >
|
||||
|
|
|
@ -193,6 +193,12 @@ jetty-10.0.0-alpha0 - 11 July
|
|||
+ 3849 ClosedChannelException from jetty-test-webapp javax websocket chat
|
||||
example
|
||||
|
||||
jetty-9.4.24.v20191120 - 20 November 2019
|
||||
+ 3083 The ini-template for jetty.console-capture.dir does not match the
|
||||
default value
|
||||
+ 4128 OpenIdCredetials can't decode JWT ID token
|
||||
+ 4334 Better test ErrorHandler changes
|
||||
|
||||
jetty-9.4.23.v20191118 - 18 November 2019
|
||||
+ 1485 Add systemd service file
|
||||
+ 2266 Jetty maven plugin reload is triggered each time the
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.server.handler;
|
|||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
@ -474,24 +475,24 @@ public class ErrorHandler extends AbstractHandler
|
|||
writer.append(json.entrySet().stream()
|
||||
.map(e -> QuotedStringTokenizer.quote(e.getKey()) +
|
||||
":" +
|
||||
QuotedStringTokenizer.quote((e.getValue())))
|
||||
QuotedStringTokenizer.quote(StringUtil.sanitizeXmlString((e.getValue()))))
|
||||
.collect(Collectors.joining(",\n", "{\n", "\n}")));
|
||||
|
||||
|
||||
}
|
||||
|
||||
protected void writeErrorPageStacks(HttpServletRequest request, Writer writer)
|
||||
throws IOException
|
||||
{
|
||||
Throwable th = (Throwable)request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
|
||||
if (_showStacks && th != null)
|
||||
if (th != null)
|
||||
{
|
||||
PrintWriter pw = writer instanceof PrintWriter ? (PrintWriter)writer : new PrintWriter(writer);
|
||||
pw.write("<pre>");
|
||||
while (th != null)
|
||||
writer.write("<h3>Caused by:</h3><pre>");
|
||||
// You have to pre-generate and then use #write(writer, String)
|
||||
try (StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw))
|
||||
{
|
||||
th.printStackTrace(pw);
|
||||
th = th.getCause();
|
||||
pw.flush();
|
||||
write(writer, sw.getBuffer().toString()); // sanitize
|
||||
}
|
||||
writer.write("</pre>\n");
|
||||
}
|
||||
|
|
|
@ -19,8 +19,9 @@
|
|||
package org.eclipse.jetty.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
||||
import java.util.Set;
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletException;
|
||||
|
@ -28,30 +29,38 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.BadMessageException;
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.tools.HttpTester;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.util.ajax.JSON;
|
||||
import org.eclipse.jetty.util.log.StacklessLogging;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.anyOf;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class ErrorHandlerTest
|
||||
{
|
||||
static StacklessLogging stacklessLogging;
|
||||
static Server server;
|
||||
static LocalConnector connector;
|
||||
|
||||
@BeforeAll
|
||||
public static void before() throws Exception
|
||||
{
|
||||
stacklessLogging = new StacklessLogging(HttpChannel.class);
|
||||
server = new Server();
|
||||
connector = new LocalConnector(server);
|
||||
server.addConnector(connector);
|
||||
|
@ -64,7 +73,7 @@ public class ErrorHandlerTest
|
|||
if (baseRequest.getDispatcherType() == DispatcherType.ERROR)
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
response.sendError(((Integer)request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE)).intValue());
|
||||
response.sendError((Integer)request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -78,7 +87,40 @@ public class ErrorHandlerTest
|
|||
|
||||
if (target.startsWith("/badmessage/"))
|
||||
{
|
||||
throw new ServletException(new BadMessageException(Integer.parseInt(target.substring(12))));
|
||||
int code = Integer.parseInt(target.substring(target.lastIndexOf('/') + 1));
|
||||
throw new ServletException(new BadMessageException(code));
|
||||
}
|
||||
|
||||
// produce an exception with an JSON formatted cause message
|
||||
if (target.startsWith("/jsonmessage/"))
|
||||
{
|
||||
String message = "\"}, \"glossary\": {\n \"title\": \"example\"\n }\n {\"";
|
||||
throw new ServletException(new RuntimeException(message));
|
||||
}
|
||||
|
||||
// produce an exception with an XML cause message
|
||||
if (target.startsWith("/xmlmessage/"))
|
||||
{
|
||||
String message =
|
||||
"<!DOCTYPE glossary PUBLIC \"-//OASIS//DTD DocBook V3.1//EN\">\n" +
|
||||
" <glossary>\n" +
|
||||
" <title>example glossary</title>\n" +
|
||||
" </glossary>";
|
||||
throw new ServletException(new RuntimeException(message));
|
||||
}
|
||||
|
||||
// produce an exception with an HTML cause message
|
||||
if (target.startsWith("/htmlmessage/"))
|
||||
{
|
||||
String message = "<hr/><script>alert(42)</script>%3Cscript%3E";
|
||||
throw new ServletException(new RuntimeException(message));
|
||||
}
|
||||
|
||||
// produce an exception with a UTF-8 cause message
|
||||
if (target.startsWith("/utf8message/"))
|
||||
{
|
||||
String message = "Euro is € and \u20AC and %E2%82%AC";
|
||||
throw new ServletException(new RuntimeException(message));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -89,193 +131,238 @@ public class ErrorHandlerTest
|
|||
public static void after() throws Exception
|
||||
{
|
||||
server.stop();
|
||||
stacklessLogging.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test404NoAccept() throws Exception
|
||||
{
|
||||
String response = connector.getResponse(
|
||||
String rawResponse = connector.getResponse(
|
||||
"GET / HTTP/1.1\r\n" +
|
||||
"Host: Localhost\r\n" +
|
||||
"\r\n");
|
||||
|
||||
assertThat(response, startsWith("HTTP/1.1 404 "));
|
||||
assertThat(response, not(containsString("Content-Length: 0")));
|
||||
assertThat(response, containsString("Content-Type: text/html;charset=iso-8859-1"));
|
||||
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
|
||||
|
||||
assertThat("Response status code", response.getStatus(), is(404));
|
||||
assertThat("Response Content-Length", response.getField(HttpHeader.CONTENT_LENGTH).getIntValue(), greaterThan(0));
|
||||
assertThat("Response Content-Type", response.get(HttpHeader.CONTENT_TYPE), containsString("text/html;charset=ISO-8859-1"));
|
||||
|
||||
assertContent(response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test404EmptyAccept() throws Exception
|
||||
{
|
||||
String response = connector.getResponse(
|
||||
String rawResponse = connector.getResponse(
|
||||
"GET / HTTP/1.1\r\n" +
|
||||
"Accept: \r\n" +
|
||||
"Host: Localhost\r\n" +
|
||||
"\r\n");
|
||||
assertThat(response, startsWith("HTTP/1.1 404 "));
|
||||
assertThat(response, containsString("Content-Length: 0"));
|
||||
assertThat(response, not(containsString("Content-Type")));
|
||||
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
|
||||
|
||||
assertThat("Response status code", response.getStatus(), is(404));
|
||||
assertThat("Response Content-Length", response.getField(HttpHeader.CONTENT_LENGTH).getIntValue(), is(0));
|
||||
assertThat("Response Content-Type", response.getField(HttpHeader.CONTENT_TYPE), is(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test404UnAccept() throws Exception
|
||||
{
|
||||
String response = connector.getResponse(
|
||||
String rawResponse = connector.getResponse(
|
||||
"GET / HTTP/1.1\r\n" +
|
||||
"Accept: text/*;q=0\r\n" +
|
||||
"Host: Localhost\r\n" +
|
||||
"\r\n");
|
||||
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
|
||||
|
||||
assertThat(response, startsWith("HTTP/1.1 404 "));
|
||||
assertThat(response, containsString("Content-Length: 0"));
|
||||
assertThat(response, not(containsString("Content-Type")));
|
||||
assertThat("Response status code", response.getStatus(), is(404));
|
||||
assertThat("Response Content-Length", response.getField(HttpHeader.CONTENT_LENGTH).getIntValue(), is(0));
|
||||
assertThat("Response Content-Type", response.getField(HttpHeader.CONTENT_TYPE), is(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test404AllAccept() throws Exception
|
||||
{
|
||||
String response = connector.getResponse(
|
||||
String rawResponse = connector.getResponse(
|
||||
"GET / HTTP/1.1\r\n" +
|
||||
"Host: Localhost\r\n" +
|
||||
"Accept: */*\r\n" +
|
||||
"\r\n");
|
||||
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
|
||||
|
||||
assertThat(response, startsWith("HTTP/1.1 404 "));
|
||||
assertThat(response, not(containsString("Content-Length: 0")));
|
||||
assertThat(response, containsString("Content-Type: text/html;charset=iso-8859-1"));
|
||||
assertThat("Response status code", response.getStatus(), is(404));
|
||||
assertThat("Response Content-Length", response.getField(HttpHeader.CONTENT_LENGTH).getIntValue(), greaterThan(0));
|
||||
assertThat("Response Content-Type", response.get(HttpHeader.CONTENT_TYPE), containsString("text/html;charset=ISO-8859-1"));
|
||||
|
||||
assertContent(response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test404HtmlAccept() throws Exception
|
||||
{
|
||||
String response = connector.getResponse(
|
||||
String rawResponse = connector.getResponse(
|
||||
"GET / HTTP/1.1\r\n" +
|
||||
"Host: Localhost\r\n" +
|
||||
"Accept: text/html\r\n" +
|
||||
"\r\n");
|
||||
|
||||
assertThat(response, startsWith("HTTP/1.1 404 "));
|
||||
assertThat(response, not(containsString("Content-Length: 0")));
|
||||
assertThat(response, containsString("Content-Type: text/html;charset=iso-8859-1"));
|
||||
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
|
||||
|
||||
assertThat("Response status code", response.getStatus(), is(404));
|
||||
assertThat("Response Content-Length", response.getField(HttpHeader.CONTENT_LENGTH).getIntValue(), greaterThan(0));
|
||||
assertThat("Response Content-Type", response.get(HttpHeader.CONTENT_TYPE), containsString("text/html;charset=ISO-8859-1"));
|
||||
|
||||
assertContent(response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoreSpecificAccept() throws Exception
|
||||
{
|
||||
String response = connector.getResponse(
|
||||
String rawResponse = connector.getResponse(
|
||||
"GET / HTTP/1.1\r\n" +
|
||||
"Host: Localhost\r\n" +
|
||||
"Accept: text/html, some/other;specific=true\r\n" +
|
||||
"\r\n");
|
||||
|
||||
assertThat(response, startsWith("HTTP/1.1 404 "));
|
||||
assertThat(response, not(containsString("Content-Length: 0")));
|
||||
assertThat(response, containsString("Content-Type: text/html;charset=iso-8859-1"));
|
||||
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
|
||||
|
||||
assertThat("Response status code", response.getStatus(), is(404));
|
||||
assertThat("Response Content-Length", response.getField(HttpHeader.CONTENT_LENGTH).getIntValue(), greaterThan(0));
|
||||
assertThat("Response Content-Type", response.get(HttpHeader.CONTENT_TYPE), containsString("text/html;charset=ISO-8859-1"));
|
||||
|
||||
assertContent(response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test404HtmlAcceptAnyCharset() throws Exception
|
||||
{
|
||||
String response = connector.getResponse(
|
||||
String rawResponse = connector.getResponse(
|
||||
"GET / HTTP/1.1\r\n" +
|
||||
"Host: Localhost\r\n" +
|
||||
"Accept: text/html\r\n" +
|
||||
"Accept-Charset: *\r\n" +
|
||||
"\r\n");
|
||||
|
||||
assertThat(response, startsWith("HTTP/1.1 404 "));
|
||||
assertThat(response, not(containsString("Content-Length: 0")));
|
||||
assertThat(response, containsString("Content-Type: text/html;charset=utf-8"));
|
||||
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
|
||||
|
||||
assertThat("Response status code", response.getStatus(), is(404));
|
||||
assertThat("Response Content-Length", response.getField(HttpHeader.CONTENT_LENGTH).getIntValue(), greaterThan(0));
|
||||
assertThat("Response Content-Type", response.get(HttpHeader.CONTENT_TYPE), containsString("text/html;charset=UTF-8"));
|
||||
|
||||
assertContent(response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test404HtmlAcceptUtf8Charset() throws Exception
|
||||
{
|
||||
String response = connector.getResponse(
|
||||
String rawResponse = connector.getResponse(
|
||||
"GET / HTTP/1.1\r\n" +
|
||||
"Host: Localhost\r\n" +
|
||||
"Accept: text/html\r\n" +
|
||||
"Accept-Charset: utf-8\r\n" +
|
||||
"\r\n");
|
||||
|
||||
assertThat(response, startsWith("HTTP/1.1 404 "));
|
||||
assertThat(response, not(containsString("Content-Length: 0")));
|
||||
assertThat(response, containsString("Content-Type: text/html;charset=utf-8"));
|
||||
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
|
||||
|
||||
assertThat("Response status code", response.getStatus(), is(404));
|
||||
assertThat("Response Content-Length", response.getField(HttpHeader.CONTENT_LENGTH).getIntValue(), greaterThan(0));
|
||||
assertThat("Response Content-Type", response.get(HttpHeader.CONTENT_TYPE), containsString("text/html;charset=UTF-8"));
|
||||
|
||||
assertContent(response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test404HtmlAcceptNotUtf8Charset() throws Exception
|
||||
{
|
||||
String response = connector.getResponse(
|
||||
String rawResponse = connector.getResponse(
|
||||
"GET / HTTP/1.1\r\n" +
|
||||
"Host: Localhost\r\n" +
|
||||
"Accept: text/html\r\n" +
|
||||
"Accept-Charset: utf-8;q=0\r\n" +
|
||||
"\r\n");
|
||||
|
||||
assertThat(response, startsWith("HTTP/1.1 404 "));
|
||||
assertThat(response, not(containsString("Content-Length: 0")));
|
||||
assertThat(response, containsString("Content-Type: text/html;charset=iso-8859-1"));
|
||||
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
|
||||
|
||||
assertThat("Response status code", response.getStatus(), is(404));
|
||||
assertThat("Response Content-Length", response.getField(HttpHeader.CONTENT_LENGTH).getIntValue(), greaterThan(0));
|
||||
assertThat("Response Content-Type", response.get(HttpHeader.CONTENT_TYPE), containsString("text/html;charset=ISO-8859-1"));
|
||||
|
||||
assertContent(response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test404HtmlAcceptNotUtf8UnknownCharset() throws Exception
|
||||
{
|
||||
String response = connector.getResponse(
|
||||
String rawResponse = connector.getResponse(
|
||||
"GET / HTTP/1.1\r\n" +
|
||||
"Host: Localhost\r\n" +
|
||||
"Accept: text/html\r\n" +
|
||||
"Accept-Charset: utf-8;q=0,unknown\r\n" +
|
||||
"\r\n");
|
||||
|
||||
assertThat(response, startsWith("HTTP/1.1 404 "));
|
||||
assertThat(response, containsString("Content-Length: 0"));
|
||||
assertThat(response, not(containsString("Content-Type")));
|
||||
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
|
||||
|
||||
assertThat("Response status code", response.getStatus(), is(404));
|
||||
assertThat("Response Content-Length", response.getField(HttpHeader.CONTENT_LENGTH).getIntValue(), is(0));
|
||||
assertThat("Response Content-Type", response.getField(HttpHeader.CONTENT_TYPE), is(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test404HtmlAcceptUnknownUtf8Charset() throws Exception
|
||||
{
|
||||
String response = connector.getResponse(
|
||||
String rawResponse = connector.getResponse(
|
||||
"GET / HTTP/1.1\r\n" +
|
||||
"Host: Localhost\r\n" +
|
||||
"Accept: text/html\r\n" +
|
||||
"Accept-Charset: utf-8;q=0.1,unknown\r\n" +
|
||||
"\r\n");
|
||||
|
||||
assertThat(response, startsWith("HTTP/1.1 404 "));
|
||||
assertThat(response, not(containsString("Content-Length: 0")));
|
||||
assertThat(response, containsString("Content-Type: text/html;charset=utf-8"));
|
||||
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
|
||||
|
||||
assertThat("Response status code", response.getStatus(), is(404));
|
||||
assertThat("Response Content-Length", response.getField(HttpHeader.CONTENT_LENGTH).getIntValue(), greaterThan(0));
|
||||
assertThat("Response Content-Type", response.get(HttpHeader.CONTENT_TYPE), containsString("text/html;charset=UTF-8"));
|
||||
|
||||
assertContent(response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test404PreferHtml() throws Exception
|
||||
{
|
||||
String response = connector.getResponse(
|
||||
String rawResponse = connector.getResponse(
|
||||
"GET / HTTP/1.1\r\n" +
|
||||
"Host: Localhost\r\n" +
|
||||
"Accept: text/html;q=1.0,text/json;q=0.5,*/*\r\n" +
|
||||
"Accept-Charset: *\r\n" +
|
||||
"\r\n");
|
||||
|
||||
assertThat(response, startsWith("HTTP/1.1 404 "));
|
||||
assertThat(response, not(containsString("Content-Length: 0")));
|
||||
assertThat(response, containsString("Content-Type: text/html;charset=utf-8"));
|
||||
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
|
||||
|
||||
assertThat("Response status code", response.getStatus(), is(404));
|
||||
assertThat("Response Content-Length", response.getField(HttpHeader.CONTENT_LENGTH).getIntValue(), greaterThan(0));
|
||||
assertThat("Response Content-Type", response.get(HttpHeader.CONTENT_TYPE), containsString("text/html;charset=UTF-8"));
|
||||
|
||||
assertContent(response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test404PreferJson() throws Exception
|
||||
{
|
||||
String response = connector.getResponse(
|
||||
String rawResponse = connector.getResponse(
|
||||
"GET / HTTP/1.1\r\n" +
|
||||
"Host: Localhost\r\n" +
|
||||
"Accept: text/html;q=0.5,text/json;q=1.0,*/*\r\n" +
|
||||
"Accept-Charset: *\r\n" +
|
||||
"\r\n");
|
||||
|
||||
assertThat(response, startsWith("HTTP/1.1 404 "));
|
||||
assertThat(response, not(containsString("Content-Length: 0")));
|
||||
assertThat(response, containsString("Content-Type: text/json"));
|
||||
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
|
||||
|
||||
assertThat("Response status code", response.getStatus(), is(404));
|
||||
assertThat("Response Content-Length", response.getField(HttpHeader.CONTENT_LENGTH).getIntValue(), greaterThan(0));
|
||||
assertThat("Response Content-Type", response.get(HttpHeader.CONTENT_TYPE), containsString("text/json"));
|
||||
|
||||
assertContent(response);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -286,12 +373,14 @@ public class ErrorHandlerTest
|
|||
"Host: Localhost\r\n" +
|
||||
"Accept: text/plain\r\n" +
|
||||
"\r\n");
|
||||
|
||||
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
|
||||
|
||||
assertThat("Response status code", response.getStatus(), is(404));
|
||||
HttpField contentType = response.getField(HttpHeader.CONTENT_TYPE);
|
||||
assertThat("Response Content-Type", contentType, is(notNullValue()));
|
||||
assertThat("Response Content-Type value", contentType.getValue(), not(containsString("null")));
|
||||
assertThat("Response Content-Length", response.getField(HttpHeader.CONTENT_LENGTH).getIntValue(), greaterThan(0));
|
||||
assertThat("Response Content-Type", response.get(HttpHeader.CONTENT_TYPE), containsString("text/plain"));
|
||||
|
||||
assertContent(response);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -301,29 +390,173 @@ public class ErrorHandlerTest
|
|||
"GET /badmessage/444 HTTP/1.1\r\n" +
|
||||
"Host: Localhost\r\n" +
|
||||
"\r\n");
|
||||
|
||||
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
|
||||
|
||||
assertThat("Response status code", response.getStatus(), is(444));
|
||||
assertThat("Response Content-Length", response.getField(HttpHeader.CONTENT_LENGTH).getIntValue(), greaterThan(0));
|
||||
assertThat("Response Content-Type", response.get(HttpHeader.CONTENT_TYPE), containsString("text/html;charset=ISO-8859-1"));
|
||||
|
||||
assertContent(response);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"/jsonmessage/",
|
||||
"/xmlmessage/",
|
||||
"/htmlmessage/",
|
||||
"/utf8message/",
|
||||
})
|
||||
public void testComplexCauseMessageNoAcceptHeader(String path) throws Exception
|
||||
{
|
||||
String rawResponse = connector.getResponse(
|
||||
"GET " + path + " HTTP/1.1\r\n" +
|
||||
"Host: Localhost\r\n" +
|
||||
"\r\n");
|
||||
|
||||
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
|
||||
|
||||
assertThat("Response status code", response.getStatus(), is(500));
|
||||
assertThat("Response Content-Length", response.getField(HttpHeader.CONTENT_LENGTH).getIntValue(), greaterThan(0));
|
||||
assertThat("Response Content-Type", response.get(HttpHeader.CONTENT_TYPE), containsString("text/html;charset=ISO-8859-1"));
|
||||
|
||||
String content = assertContent(response);
|
||||
|
||||
if (path.startsWith("/utf8"))
|
||||
{
|
||||
// we are Not expecting UTF-8 output, look for mangled ISO-8859-1 version
|
||||
assertThat("content", content, containsString("Euro is &euro; and ? and %E2%82%AC"));
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"/jsonmessage/",
|
||||
"/xmlmessage/",
|
||||
"/htmlmessage/",
|
||||
"/utf8message/",
|
||||
})
|
||||
public void testComplexCauseMessageAcceptUtf8Header(String path) throws Exception
|
||||
{
|
||||
String rawResponse = connector.getResponse(
|
||||
"GET " + path + " HTTP/1.1\r\n" +
|
||||
"Host: Localhost\r\n" +
|
||||
"Accept: text/html\r\n" +
|
||||
"Accept-Charset: utf-8\r\n" +
|
||||
"\r\n");
|
||||
|
||||
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
|
||||
|
||||
assertThat("Response status code", response.getStatus(), is(500));
|
||||
assertThat("Response Content-Length", response.getField(HttpHeader.CONTENT_LENGTH).getIntValue(), greaterThan(0));
|
||||
assertThat("Response Content-Type", response.get(HttpHeader.CONTENT_TYPE), containsString("text/html;charset=UTF-8"));
|
||||
|
||||
String content = assertContent(response);
|
||||
|
||||
if (path.startsWith("/utf8"))
|
||||
{
|
||||
// we are Not expecting UTF-8 output, look for mangled ISO-8859-1 version
|
||||
assertThat("content", content, containsString("Euro is &euro; and \u20AC and %E2%82%AC"));
|
||||
}
|
||||
}
|
||||
|
||||
private String assertContent(HttpTester.Response response)
|
||||
{
|
||||
String contentType = response.get(HttpHeader.CONTENT_TYPE);
|
||||
String content = response.getContent();
|
||||
|
||||
if (contentType.contains("text/html"))
|
||||
{
|
||||
assertThat(content, not(containsString("<script>")));
|
||||
assertThat(content, not(containsString("<glossary>")));
|
||||
assertThat(content, not(containsString("<!DOCTYPE>")));
|
||||
assertThat(content, not(containsString("€")));
|
||||
}
|
||||
else if (contentType.contains("text/json"))
|
||||
{
|
||||
Map jo = (Map)JSON.parse(response.getContent());
|
||||
|
||||
Set<String> acceptableKeyNames = new HashSet<>();
|
||||
acceptableKeyNames.add("url");
|
||||
acceptableKeyNames.add("status");
|
||||
acceptableKeyNames.add("message");
|
||||
acceptableKeyNames.add("servlet");
|
||||
acceptableKeyNames.add("cause0");
|
||||
acceptableKeyNames.add("cause1");
|
||||
acceptableKeyNames.add("cause2");
|
||||
|
||||
for (Object key : jo.keySet())
|
||||
{
|
||||
String keyStr = (String)key;
|
||||
assertTrue(acceptableKeyNames.contains(keyStr), "Unexpected Key [" + keyStr + "]");
|
||||
|
||||
Object value = jo.get(key);
|
||||
assertThat("Unexpected value type (" + value.getClass().getName() + ")",
|
||||
value, instanceOf(String.class));
|
||||
}
|
||||
|
||||
assertThat("url field", jo.get("url"), is(notNullValue()));
|
||||
String expectedStatus = String.valueOf(response.getStatus());
|
||||
assertThat("status field", jo.get("status"), is(expectedStatus));
|
||||
String message = (String)jo.get("message");
|
||||
assertThat("message field", message, is(notNullValue()));
|
||||
assertThat("message field", message, anyOf(
|
||||
not(containsString("<")),
|
||||
not(containsString(">"))));
|
||||
}
|
||||
else if (contentType.contains("text/plain"))
|
||||
{
|
||||
assertThat(content, containsString("STATUS: " + response.getStatus()));
|
||||
}
|
||||
else
|
||||
{
|
||||
System.out.println("Not checked Content-Type: " + contentType);
|
||||
System.out.println(content);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJsonResponse() throws Exception
|
||||
{
|
||||
String rawResponse = connector.getResponse(
|
||||
"GET /badmessage/444 HTTP/1.1\r\n" +
|
||||
"Host: Localhost\r\n" +
|
||||
"Accept: text/json\r\n" +
|
||||
"\r\n");
|
||||
"GET /badmessage/444 HTTP/1.1\r\n" +
|
||||
"Host: Localhost\r\n" +
|
||||
"Accept: text/json\r\n" +
|
||||
"\r\n");
|
||||
|
||||
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
|
||||
|
||||
assertThat("Response status code", response.getStatus(), is(444));
|
||||
|
||||
System.out.println("response:" + response.getContent());
|
||||
assertContent(response);
|
||||
}
|
||||
|
||||
Map<Object,Object> jo = (Map) JSON.parse(response.getContent());
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"/jsonmessage/",
|
||||
"/xmlmessage/",
|
||||
"/htmlmessage/",
|
||||
"/utf8message/",
|
||||
})
|
||||
public void testJsonResponseWorse(String path) throws Exception
|
||||
{
|
||||
String rawResponse = connector.getResponse(
|
||||
"GET " + path + " HTTP/1.1\r\n" +
|
||||
"Host: Localhost\r\n" +
|
||||
"Accept: text/json\r\n" +
|
||||
"\r\n");
|
||||
|
||||
assertThat("url field null", jo.get("url"), is(notNullValue()));
|
||||
assertThat("status field null", jo.get("status"), is(notNullValue()));
|
||||
assertThat("message field null", jo.get("message"), is(notNullValue()));
|
||||
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
|
||||
assertThat("Response status code", response.getStatus(), is(500));
|
||||
|
||||
String content = assertContent(response);
|
||||
|
||||
if (path.startsWith("/utf8"))
|
||||
{
|
||||
// we are expecting UTF-8 output, look for it.
|
||||
assertThat("content", content, containsString("Euro is &euro; and \u20AC and %E2%82%AC"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ resources/
|
|||
|
||||
[ini-template]
|
||||
## Logging directory (relative to $jetty.base)
|
||||
# jetty.console-capture.dir=logs
|
||||
# jetty.console-capture.dir=./logs
|
||||
|
||||
## Whether to append to existing file
|
||||
# jetty.console-capture.append=true
|
||||
|
|
|
@ -945,7 +945,8 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
|||
}
|
||||
else if (b >= 'a' && b <= 'z' ||
|
||||
b >= 'A' && b <= 'Z' ||
|
||||
b >= '0' && b <= '9')
|
||||
b >= '0' && b <= '9' ||
|
||||
b == '-' || b == '.' || b == '_' || b == '~')
|
||||
{
|
||||
encoded[n++] = b;
|
||||
}
|
||||
|
|
3
pom.xml
3
pom.xml
|
@ -66,7 +66,7 @@
|
|||
<jackson-databind.version>2.9.9</jackson-databind.version>
|
||||
<localRepoPath>${project.build.directory}/local-repo</localRepoPath>
|
||||
<settingsPath>src/it/settings.xml</settingsPath>
|
||||
<surefire.rerunFailingTestsCount>3</surefire.rerunFailingTestsCount>
|
||||
<surefire.rerunFailingTestsCount>0</surefire.rerunFailingTestsCount>
|
||||
</properties>
|
||||
|
||||
<licenses>
|
||||
|
@ -1286,6 +1286,7 @@
|
|||
<id>ci</id>
|
||||
<properties>
|
||||
<settingsPath>${env.GLOBAL_MVN_SETTINGS}</settingsPath>
|
||||
<surefire.rerunFailingTestsCount>3</surefire.rerunFailingTestsCount>
|
||||
</properties>
|
||||
<modules>
|
||||
<module>aggregates/jetty-all</module>
|
||||
|
|
Loading…
Reference in New Issue