diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/UncheckedPrintWriter.java b/jetty-io/src/main/java/org/eclipse/jetty/io/UncheckedPrintWriter.java index f114417e800..cfb05447a29 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/UncheckedPrintWriter.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/UncheckedPrintWriter.java @@ -35,7 +35,8 @@ public class UncheckedPrintWriter extends PrintWriter private static final Logger LOG = Log.getLogger(UncheckedPrintWriter.class); private boolean _autoFlush = false; - private boolean _throwUnchecked=true; + private IOException _ioException; + private boolean _isClosed = false; /* ------------------------------------------------------------ */ /** @@ -102,38 +103,45 @@ public class UncheckedPrintWriter extends PrintWriter this(new BufferedWriter(new OutputStreamWriter(out)),autoFlush); } + /* ------------------------------------------------------------ */ - private void setError(Throwable th) + public boolean checkError() { - setError(); - if (_throwUnchecked) - throw new RuntimeIOException(th); - LOG.debug(th); - } - - /* ------------------------------------------------------------ */ - /** Are unchecked exceptions thrown. - * @return True if {@link RuntimeIOException}s are thrown - */ - public boolean isUncheckedPrintWriter() - { - return _throwUnchecked; - } - - /* ------------------------------------------------------------ */ - /** Set if unchecked exceptions are thrown - * @param uncheckedPrintWriter True if {@link RuntimeIOException}s are to be thrown - */ - public void setUncheckedPrintWriter(boolean uncheckedPrintWriter) - { - _throwUnchecked = uncheckedPrintWriter; + return _ioException!=null || super.checkError(); } + /* ------------------------------------------------------------ */ + private void setError(Throwable th) + { + + super.setError(); + + if (th instanceof IOException) + _ioException=(IOException)th; + else + { + _ioException=new IOException(String.valueOf(th)); + _ioException.initCause(th); + } + + LOG.debug(th); + } + + + @Override + protected void setError() + { + setError(new IOException()); + } + /* ------------------------------------------------------------ */ /** Check to make sure that the stream has not been closed */ private void isOpen() throws IOException - { - if (super.out == null) + { + if (_ioException!=null) + throw new RuntimeIOException(_ioException); + + if (_isClosed) throw new IOException("Stream closed"); } @@ -170,6 +178,7 @@ public class UncheckedPrintWriter extends PrintWriter synchronized (lock) { out.close(); + _isClosed = true; } } catch (IOException ex) @@ -248,7 +257,7 @@ public class UncheckedPrintWriter extends PrintWriter */ @Override public void write(char buf[]) - { + { this.write(buf,0,buf.length); } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java index b589d22278b..6869768901f 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java @@ -356,7 +356,27 @@ public abstract class AbstractHttpConnection extends AbstractConnection if (_writer==null) { _writer=new OutputWriter(); - _printWriter=new UncheckedPrintWriter(_writer); + if (_server.isUncheckedPrintWriter()) + _printWriter=new UncheckedPrintWriter(_writer); + else + _printWriter = new PrintWriter(_writer) + { + public void close() + { + synchronized (lock) + { + try + { + out.close(); + } + catch (IOException e) + { + setError(); + } + } + } + }; + } _writer.setCharacterEncoding(encoding); return _printWriter; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java index e62fad56c79..98221fc2a65 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java @@ -76,6 +76,7 @@ public class Server extends HandlerWrapper implements Attributes private int _maxCookieVersion=1; private boolean _dumpAfterStart=false; private boolean _dumpBeforeStop=false; + private boolean _uncheckedPrintWriter=false; /* ------------------------------------------------------------ */ @@ -614,6 +615,20 @@ public class Server extends HandlerWrapper implements Attributes dumpThis(out); dump(out,indent,TypeUtil.asList(getHandlers()),getBeans(),TypeUtil.asList(_connectors)); } + + + /* ------------------------------------------------------------ */ + public boolean isUncheckedPrintWriter() + { + return _uncheckedPrintWriter; + } + + /* ------------------------------------------------------------ */ + public void setUncheckedPrintWriter(boolean unchecked) + { + _uncheckedPrintWriter=unchecked; + } + /* ------------------------------------------------------------ */ /* A handler that can be gracefully shutdown. 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 0e6d953c275..661fcde9a65 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 @@ -741,6 +741,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture IO.copy(is,bout); byte[] b=bout.toByteArray(); + System.err.println("OUTPUT: "+new String(b)); int i=0; while (b[i]!='Z') i++; diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerTest.java index 6b1dcfa28cb..5612d35c9f3 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerTest.java @@ -337,6 +337,7 @@ public class ContextHandlerTest public void testUncheckedPrintWriter() throws Exception { Server server = new Server(); + server.setUncheckedPrintWriter(true); LocalConnector connector = new LocalConnector(); server.setConnectors(new Connector[] { connector }); ContextHandler context = new ContextHandler("/"); @@ -422,7 +423,10 @@ public class ContextHandlerTest writer.write("Goodbye cruel world\n"); writer.close(); response.flushBuffer(); - writer.write("speaking from the dead"); + //writer.write("speaking from the dead"); + writer.write("give the printwriter a chance"); //should create an error + if (writer.checkError()) + writer.write("didn't take the chance, will throw now"); //write after an error } catch(Throwable th) {