From 2a5b120fc3f0f04b044c3024efde49d7b6a60380 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Fri, 6 May 2016 20:31:55 +1000 Subject: [PATCH] Issue #525 fix blockForContent spin abort request in bad request handling --- .../org/eclipse/jetty/server/HttpChannel.java | 1 + .../jetty/server/HttpChannelOverHttp.java | 1 + .../jetty/servlet/PostServletTest.java | 285 +++++++++--------- 3 files changed, 142 insertions(+), 145 deletions(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index 2c45153c917..af83928439a 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -641,6 +641,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor { // The bad message cannot be handled in the current state, so throw // to hopefull somebody that can handle + abort(e); throw new BadMessageException(status,reason); } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java index 11131494d68..121bd15c517 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java @@ -248,6 +248,7 @@ public class HttpChannelOverHttp extends HttpChannel implements HttpParser.Reque { // Need to call onRequest, so RequestLog can reports as much as possible onRequest(_metadata); + getRequest().getHttpInput().earlyEOF(); } catch (Exception e) { diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/PostServletTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/PostServletTest.java index 07fc9c5f375..db956a07d12 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/PostServletTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/PostServletTest.java @@ -1,145 +1,140 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 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 static org.hamcrest.Matchers.containsString; -import static org.junit.Assert.assertThat; - -import java.io.BufferedReader; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.concurrent.TimeUnit; - -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.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.log.StacklessLogging; -import org.junit.After; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - -public class PostServletTest -{ - private static final Logger LOG = Log.getLogger(PostServletTest.class); - - public static class BasicReadPostServlet extends HttpServlet - { - protected void doPost(HttpServletRequest request, HttpServletResponse response) - { - try - { - byte[] buffer = new byte[4096]; - - ServletInputStream in = request.getInputStream(); - - int l = in.read(buffer); - while (l>0) - { - // System.err.println("READ: "+new String(buffer,0,l,StandardCharsets.ISO_8859_1)); - l = in.read(buffer); - } - - } - catch (IOException e0) - { - LOG.warn(e0); - } - } - } - - private Server server; - private LocalConnector connector; - - @Before - public void startServer() throws Exception - { - server = new Server(); - connector = new LocalConnector(server); - server.addConnector(connector); - - ServletContextHandler context = new ServletContextHandler(); - context.setContextPath("/"); - context.addServlet(BasicReadPostServlet.class, "/post"); - - server.setHandler(context); - - server.start(); - } - - @After - public void stopServer() throws Exception - { - this.server.stop(); - } - - @Test - public void testGoodPost() throws Exception - { - StringBuilder req = new StringBuilder(); - req.append("POST /post HTTP/1.1\r\n"); - req.append("Host: localhost\r\n"); - req.append("Connection: close\r\n"); - req.append("Transfer-Encoding: chunked\r\n"); - req.append("\r\n"); - req.append("6\r\n"); - req.append("Hello "); - req.append("\r\n"); - req.append("6\r\n"); - req.append("World\n"); - req.append("\r\n"); - req.append("0\r\n"); - req.append("\r\n"); - - String resp = connector.getResponses(req.toString()); - - assertThat("resp", resp, containsString("HTTP/1.1 200 OK")); - } - - @Test - public void testBadPost() throws Exception - { - StringBuilder req = new StringBuilder(); - req.append("POST /post HTTP/1.1\r\n"); - req.append("Host: localhost\r\n"); - req.append("Connection: close\r\n"); - req.append("Transfer-Encoding: chunked\r\n"); - req.append("\r\n"); - req.append("6\r\n"); - req.append("Hello "); - req.append("\r\n"); - req.append("x\r\n"); - req.append("World\n"); - req.append("\r\n"); - req.append("0\r\n"); - req.append("\r\n"); - - try (StacklessLogging scope = new StacklessLogging(ServletHandler.class)) - { - String resp = connector.getResponses(req.toString()); - assertThat("resp", resp, containsString("HTTP/1.1 500 ")); - } - } -} +// +// ======================================================================== +// Copyright (c) 1995-2016 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 static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; +import static org.junit.Assert.assertThat; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +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.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.log.StacklessLogging; +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +public class PostServletTest +{ + private static final Logger LOG = Log.getLogger(PostServletTest.class); + + public static class BasicReadPostServlet extends HttpServlet + { + protected void doPost(HttpServletRequest request, HttpServletResponse response) + { + try + { + response.flushBuffer(); + request.getInputStream().read(); + } + catch (Exception e0) + { + try + { + // this read-call should fail immediately + request.getInputStream().read(); + } + catch (Exception e1) + { + LOG.warn(e1.toString()); + } + } + } + } + + private Server server; + private LocalConnector connector; + + @Before + public void startServer() throws Exception + { + server = new Server(); + connector = new LocalConnector(server); + server.addConnector(connector); + + ServletContextHandler context = new ServletContextHandler(); + context.setContextPath("/"); + context.addServlet(BasicReadPostServlet.class, "/post"); + + server.setHandler(context); + + server.start(); + } + + @After + public void stopServer() throws Exception + { + this.server.stop(); + } + + @Test + public void testGoodPost() throws Exception + { + StringBuilder req = new StringBuilder(); + req.append("POST /post HTTP/1.1\r\n"); + req.append("Host: localhost\r\n"); + req.append("Connection: close\r\n"); + req.append("Transfer-Encoding: chunked\r\n"); + req.append("\r\n"); + req.append("6\r\n"); + req.append("Hello "); + req.append("\r\n"); + req.append("6\r\n"); + req.append("World\n"); + req.append("\r\n"); + req.append("0\r\n"); + req.append("\r\n"); + + String resp = connector.getResponses(req.toString()); + + assertThat("resp", resp, containsString("HTTP/1.1 200 OK")); + } + + @Test + public void testBadPost() throws Exception + { + StringBuilder req = new StringBuilder(16*1024); + req.append("POST /post HTTP/1.1\r\n"); + req.append("Host: localhost\r\n"); + req.append("Transfer-Encoding: chunked\r\n"); + req.append("\r\n"); + // intentionally bad (not a valid chunked char here) + for (int i=1024;i-->0;) + req.append("xxxxxxxxxxxx"); + req.append("\r\n"); + req.append("\r\n"); + + try (StacklessLogging scope = new StacklessLogging(ServletHandler.class)) + { + String resp = connector.getResponses(req.toString()); + assertThat("resp", resp, containsString("HTTP/1.1 200 ")); + assertThat("resp", resp, containsString("chunked")); + assertThat("resp", resp, not(containsString("\r\n0\r\n"))); + } + } +} \ No newline at end of file