diff options
5 files changed, 172 insertions, 3 deletions
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/AbstractHttpTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/AbstractHttpTest.java index eb464180d6..bbd96459ec 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/AbstractHttpTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/AbstractHttpTest.java @@ -30,6 +30,9 @@ import java.net.Socket; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; +import java.util.HashSet; +import java.util.Set; + import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -47,6 +50,8 @@ import org.junit.Rule; public abstract class AbstractHttpTest { + private final static Set<String> __noBodyCodes = new HashSet<>(Arrays.asList(new String[]{"100","101","102","204","304"})); + @Rule public TestTracker tracker = new TestTracker(); @@ -93,8 +98,10 @@ public abstract class AbstractHttpTest writer.flush(); SimpleHttpResponse response = httpParser.readResponse(reader); - if ("HTTP/1.1".equals(httpVersion) && response.getHeaders().get("content-length") == null && response - .getHeaders().get("transfer-encoding") == null) + if ("HTTP/1.1".equals(httpVersion) + && response.getHeaders().get("content-length") == null + && response.getHeaders().get("transfer-encoding") == null + && !__noBodyCodes.contains(response.getCode())) assertThat("If HTTP/1.1 response doesn't contain transfer-encoding or content-length headers, " + "it should contain connection:close", response.getHeaders().get("connection"), is("close")); return response; diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java index 7da9552ccb..f48f31000b 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java @@ -30,6 +30,7 @@ import static org.junit.Assert.assertTrue; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; +import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -1536,6 +1537,71 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture } } + @Test + public void testWriteBodyAfterNoBodyResponse() throws Exception + { + configureServer(new WriteBodyAfterNoBodyResponseHandler()); + Socket client = newSocket(_serverURI.getHost(), _serverURI.getPort()); + final OutputStream out=client.getOutputStream(); + + out.write("GET / HTTP/1.1\r\nHost: test\r\n\r\n".getBytes()); + out.write("GET / HTTP/1.1\r\nHost: test\r\nConnection: close\r\n\r\n".getBytes()); + out.flush(); + + + BufferedReader in =new BufferedReader(new InputStreamReader(client.getInputStream())); + + String line=in.readLine(); + assertThat(line, containsString(" 304 ")); + while (true) + { + line=in.readLine(); + if (line==null) + throw new EOFException(); + if (line.length()==0) + break; + + assertThat(line, not(containsString("Content-Length"))); + assertThat(line, not(containsString("Content-Type"))); + assertThat(line, not(containsString("Transfer-Encoding"))); + } + + line=in.readLine(); + assertThat(line, containsString(" 304 ")); + while (true) + { + line=in.readLine(); + if (line==null) + throw new EOFException(); + if (line.length()==0) + break; + + assertThat(line, not(containsString("Content-Length"))); + assertThat(line, not(containsString("Content-Type"))); + assertThat(line, not(containsString("Transfer-Encoding"))); + } + + do + { + line=in.readLine(); + } + while (line!=null); + + } + + private class WriteBodyAfterNoBodyResponseHandler extends AbstractHandler + { + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + baseRequest.setHandled(true); + response.setStatus(304); + response.getOutputStream().print("yuck"); + response.flushBuffer(); + } + } + + public class NoopHandler extends AbstractHandler { @Override diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java index da6dd7634c..af0bf9f466 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java @@ -62,6 +62,7 @@ import org.eclipse.jetty.server.handler.gzip.GzipHandler; import org.eclipse.jetty.server.session.SessionHandler; import org.eclipse.jetty.servlet.BaseHolder.Source; import org.eclipse.jetty.util.DecoratedObjectFactory; +import org.eclipse.jetty.util.DeprecationWarning; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.component.LifeCycle; @@ -90,7 +91,7 @@ public class ServletContextHandler extends ContextHandler public interface ServletContainerInitializerCaller extends LifeCycle {}; - protected final DecoratedObjectFactory _objFactory = new DecoratedObjectFactory(); + protected final DecoratedObjectFactory _objFactory; protected Class<? extends SecurityHandler> _defaultSecurityHandlerClass=org.eclipse.jetty.security.ConstraintSecurityHandler.class; protected SessionHandler _sessionHandler; protected SecurityHandler _securityHandler; @@ -150,6 +151,9 @@ public class ServletContextHandler extends ContextHandler _sessionHandler = sessionHandler; _securityHandler = securityHandler; _servletHandler = servletHandler; + + _objFactory = new DecoratedObjectFactory(); + _objFactory.addDecorator(new DeprecationWarning()); if (contextPath!=null) setContextPath(contextPath); diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java index 9b7faf7e51..0969eca2cf 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java @@ -27,6 +27,9 @@ import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + /* ------------------------------------------------------------ */ /** */ @@ -34,9 +37,12 @@ import javax.servlet.ServletResponse; @Deprecated public class GzipFilter implements Filter { + private static final Logger LOG = Log.getLogger(GzipFilter.class); + @Override public void init(FilterConfig filterConfig) throws ServletException { + LOG.warn("GzipFilter is deprecated. Use GzipHandler"); } @Override diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/DeprecationWarning.java b/jetty-util/src/main/java/org/eclipse/jetty/util/DeprecationWarning.java new file mode 100644 index 0000000000..bd00c928d5 --- /dev/null +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/DeprecationWarning.java @@ -0,0 +1,86 @@ +// +// ======================================================================== +// Copyright (c) 1995-2015 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.util; + +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + +public class DeprecationWarning implements Decorator +{ + private static final Logger LOG = Log.getLogger(DeprecationWarning.class); + + @Override + public <T> T decorate(T o) + { + if (o == null) + { + return null; + } + + Class<?> clazz = o.getClass(); + + try + { + Deprecated depr = clazz.getAnnotation(Deprecated.class); + if (depr != null) + { + LOG.warn("Using @Deprecated Class {}",clazz.getName()); + } + } + catch (Throwable t) + { + LOG.ignore(t); + } + + verifyIndirectTypes(clazz.getSuperclass(),clazz,"Class"); + for (Class<?> ifaceClazz : clazz.getInterfaces()) + { + verifyIndirectTypes(ifaceClazz,clazz,"Interface"); + } + + return o; + } + + private void verifyIndirectTypes(Class<?> superClazz, Class<?> clazz, String typeName) + { + try + { + // Report on super class deprecation too + while (superClazz != null && superClazz != Object.class) + { + Deprecated supDepr = superClazz.getAnnotation(Deprecated.class); + if (supDepr != null) + { + LOG.warn("Using indirect @Deprecated {} {} - (seen from {})",typeName,superClazz.getName(),clazz); + } + + superClazz = superClazz.getSuperclass(); + } + } + catch (Throwable t) + { + LOG.ignore(t); + } + } + + @Override + public void destroy(Object o) + { + } +} |